private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is MethodDeclarationSyntax methodDeclaration && context.ContainingSymbol is IMethodSymbol { IsStatic : true } method&& method.Parameters.TryElementAt(0, out var element) && element.Type.IsAssignableTo(KnownSymbols.DependencyObject, context.Compilation)) { if (ClrMethod.IsAttachedGet(methodDeclaration, context.SemanticModel, context.CancellationToken, out var getValueCall, out var backing)) { if (DependencyProperty.TryGetRegisteredName(backing, context.SemanticModel, context.CancellationToken, out _, out var registeredName)) { if (!method.Name.IsParts("Get", registeredName)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0004ClrMethodShouldMatchRegisteredName, methodDeclaration.Identifier.GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", "Get" + registeredName), method.Name, "Get" + registeredName)); } if (method.DeclaredAccessibility.IsEither(Accessibility.Protected, Accessibility.Internal, Accessibility.Public)) { var summaryFormat = "<summary>Helper for getting <see cref=\"{backing}\"/> from <paramref name=\"{element}\"/>.</summary>"; var paramFormat = "<param name=\"{element}\"><see cref=\"{element.type}\"/> to read <see cref=\"{backing}\"/> from.</param>"; var returnsFormat = "<returns>{registered_name} property value.</returns>"; if (methodDeclaration.TryGetDocumentationComment(out var comment)) { if (comment.VerifySummary(summaryFormat, backing.Symbol.Name, element.Name) is { } summaryError) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0061DocumentClrMethod, summaryError.Location, ImmutableDictionary <string, string> .Empty.Add(nameof(DocComment), summaryError.Text))); } if (comment.VerifyParameter(paramFormat, element, element.ToCrefType(), backing.Symbol.Name) is { } paramError) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0061DocumentClrMethod, paramError.Location, ImmutableDictionary <string, string> .Empty.Add(nameof(DocComment), paramError.Text))); } if (comment.VerifyReturns(returnsFormat, registeredName) is { } returnsError) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0061DocumentClrMethod, returnsError.Location, ImmutableDictionary <string, string> .Empty.Add(nameof(DocComment), returnsError.Text))); } } else { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0061DocumentClrMethod, methodDeclaration.Identifier.GetLocation(), ImmutableDictionary <string, string> .Empty.Add( nameof(DocComment), $"/// {DocComment.Format(summaryFormat, backing.Symbol.Name, element.Name)}\n" + $"/// {DocComment.Format(paramFormat, element.Name, element.ToCrefType(), backing.Name)}\n" + $"/// {DocComment.Format(returnsFormat, registeredName)}\n"))); } } } if (DependencyProperty.TryGetRegisteredType(backing, context.SemanticModel, context.CancellationToken, out var registeredType) && !Equals(method.ReturnType, registeredType)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0013ClrMethodMustMatchRegisteredType, methodDeclaration.ReturnType.GetLocation(), "Return type", registeredType)); } if (Gu.Roslyn.AnalyzerExtensions.Attribute.TryFind(methodDeclaration, KnownSymbols.AttachedPropertyBrowsableForTypeAttribute, context.SemanticModel, context.CancellationToken, out var attribute)) { if (attribute.TrySingleArgument(out var argument) && argument.Expression is TypeOfExpressionSyntax typeOf && TypeOf.TryGetType(typeOf, method.ContainingType, context.SemanticModel, context.CancellationToken, out var argumentType) && !argumentType.IsAssignableTo(element.Type, context.Compilation)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0034AttachedPropertyBrowsableForTypeAttributeArgument, argument.GetLocation(), element.Type.ToMinimalDisplayString( context.SemanticModel, argument.SpanStart))); } } else { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0033UseAttachedPropertyBrowsableForTypeAttribute, methodDeclaration.Identifier.GetLocation(), element.Type.ToMinimalDisplayString(context.SemanticModel, methodDeclaration.SpanStart))); } if (methodDeclaration.Body is { } body&& TryGetSideEffect(body, getValueCall, out var sideEffect)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0042AvoidSideEffectsInClrAccessors, sideEffect.GetLocation())); } }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is MethodDeclarationSyntax methodDeclaration && context.ContainingSymbol is IMethodSymbol method && method.IsStatic && method.Parameters.TryElementAt(0, out var parameter) && parameter.Type.IsAssignableTo(KnownSymbols.DependencyObject, context.Compilation)) { if (ClrMethod.IsAttachedGet(methodDeclaration, context.SemanticModel, context.CancellationToken, out var getValueCall, out var fieldOrProperty)) { if (DependencyProperty.TryGetRegisteredName(fieldOrProperty, context.SemanticModel, context.CancellationToken, out _, out var registeredName) && !method.Name.IsParts("Get", registeredName)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0004ClrMethodShouldMatchRegisteredName, methodDeclaration.Identifier.GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", "Get" + registeredName), method.Name, "Get" + registeredName)); } if (DependencyProperty.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var registeredType) && !Equals(method.ReturnType, registeredType)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0013ClrMethodMustMatchRegisteredType, methodDeclaration.ReturnType.GetLocation(), "Return type", registeredType)); } if (Attribute.TryFind(methodDeclaration, KnownSymbols.AttachedPropertyBrowsableForTypeAttribute, context.SemanticModel, context.CancellationToken, out var attribute)) { if (attribute.TrySingleArgument(out var argument) && argument.Expression is TypeOfExpressionSyntax typeOf && TypeOf.TryGetType(typeOf, method.ContainingType, context.SemanticModel, context.CancellationToken, out var argumentType) && !argumentType.IsAssignableTo(parameter.Type, context.Compilation)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0034AttachedPropertyBrowsableForTypeAttributeArgument, argument.GetLocation(), parameter.Type.ToMinimalDisplayString( context.SemanticModel, argument.SpanStart))); } } else { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0033UseAttachedPropertyBrowsableForTypeAttribute, methodDeclaration.Identifier.GetLocation(), parameter.Type.ToMinimalDisplayString(context.SemanticModel, methodDeclaration.SpanStart))); } if (methodDeclaration.Body is BlockSyntax body && body.Statements.TryFirst(x => !x.Contains(getValueCall), out var statement)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0042AvoidSideEffectsInClrAccessors, statement.GetLocation())); } if (method.DeclaredAccessibility.IsEither(Accessibility.Protected, Accessibility.Internal, Accessibility.Public) && !HasStandardText(methodDeclaration, fieldOrProperty, registeredName, out var location)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0061DocumentClrMethod, location)); } }