private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is MemberDeclarationSyntax memberDeclaration) { if (BackingFieldOrProperty.TryCreateForDependencyProperty(context.ContainingSymbol, out var backing)) { if (DependencyProperty.TryGetRegisteredName(backing, context.SemanticModel, context.CancellationToken, out _, out var registeredName)) { if (backing.Type == KnownSymbols.DependencyProperty && !backing.Name.IsParts(registeredName, "Property")) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0001BackingFieldShouldMatchRegisteredName, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "Property"), backing.Name, registeredName)); } if (backing.Type == KnownSymbols.DependencyPropertyKey && !backing.Name.IsParts(registeredName, "PropertyKey")) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0002BackingFieldShouldMatchRegisteredName, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "PropertyKey"), backing.Name, registeredName)); } if (context.ContainingSymbol.ContainingType.TryFindProperty(registeredName, out _) && context.ContainingSymbol.DeclaredAccessibility.IsEither(Accessibility.Protected, Accessibility.Internal, Accessibility.Public)) { var summaryFormat = "<summary>Identifies the <see cref=\"{backing}\"/> dependency property.</summary>"; if (memberDeclaration.TryGetDocumentationComment(out var comment)) { if (comment.VerifySummary(summaryFormat, registeredName) is { } summaryError) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0060DocumentDependencyPropertyBackingMember, summaryError.Location, ImmutableDictionary <string, string> .Empty.Add(nameof(DocComment), summaryError.Text))); } } else { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0060DocumentDependencyPropertyBackingMember, backing.Symbol.Locations[0], ImmutableDictionary <string, string> .Empty.Add( nameof(DocComment), $"/// {DocComment.Format(summaryFormat, registeredName)}"))); } } if (DependencyProperty.TryGetRegisteredType(backing, context.SemanticModel, context.CancellationToken, out var type) && type.Is(KnownSymbols.Style) && !TryFindStyleTypedPropertyAttribute(memberDeclaration, registeredName, context.SemanticModel, context.CancellationToken) && backing.FieldOrProperty.Symbol.DeclaredAccessibility.IsEither(Accessibility.Public, Accessibility.Internal)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0176StyleTypedPropertyMissing, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation(), ImmutableDictionary <string, string> .Empty.Add( nameof(AttributeListSyntax), $"[StyleTypedProperty(Property = {(context.ContainingSymbol.ContainingType.TryFindProperty(registeredName, out _) ? $"nameof({registeredName})" : $"\"{registeredName}\"")}, StyleTargetType = typeof(TYPE))]"),
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 MemberDeclarationSyntax memberDeclaration && FieldOrProperty.TryCreate(context.ContainingSymbol, out var backing) && backing.Type == KnownSymbols.RoutedEvent) { if (RoutedEvent.TryGetRegisteredName(backing, context.SemanticModel, context.CancellationToken, out var nameArg, out var registeredName)) { if (!backing.Name.IsParts(registeredName, "Event")) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0100BackingFieldShouldMatchRegisteredName, backing.Symbol.Locations[0], ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "Event"), backing.Name, registeredName)); } if (backing.ContainingType.TryFindEvent(registeredName, out var eventSymbol)) { if (nameArg.Expression is LiteralExpressionSyntax) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0150UseNameofInsteadOfLiteral, nameArg.GetLocation(), ImmutableDictionary <string, string> .Empty.Add(nameof(IdentifierNameSyntax), eventSymbol.Name), eventSymbol.Name)); } else if (!nameArg.Expression.IsNameof()) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0151UseNameofInsteadOfConstant, nameArg.GetLocation(), ImmutableDictionary <string, string> .Empty.Add(nameof(IdentifierNameSyntax), eventSymbol.Name), eventSymbol.Name)); } } if (context.ContainingSymbol.ContainingType.TryFindEvent(registeredName, out _) && context.ContainingSymbol.DeclaredAccessibility.IsEither(Accessibility.Protected, Accessibility.Internal, Accessibility.Public)) { var summaryFormat = "<summary>Identifies the <see cref=\"{registered_name}\"/> routed event.</summary>"; if (memberDeclaration.TryGetDocumentationComment(out var comment)) { if (comment.VerifySummary(summaryFormat, registeredName) is { } summaryError) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0108DocumentRoutedEventBackingMember, summaryError.Location, ImmutableDictionary <string, string> .Empty.Add(nameof(DocComment), summaryError.Text))); } } else { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0108DocumentRoutedEventBackingMember, backing.Symbol.Locations[0], ImmutableDictionary <string, string> .Empty.Add( nameof(DocComment), $"/// {DocComment.Format(summaryFormat, registeredName)}"))); } } } if (RoutedEvent.TryGetRegisteredType(backing, context.SemanticModel, context.CancellationToken, out var typeArg, out var registeredOwnerType) && !Equals(registeredOwnerType, context.ContainingSymbol.ContainingType)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0101RegisterContainingTypeAsOwner, typeArg.GetLocation(), backing.ContainingType.Name, registeredName)); } if (!backing.IsStaticReadOnly()) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0107BackingMemberShouldBeStaticReadonly, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation())); } } }