private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && context.Node is MemberDeclarationSyntax memberDeclaration) { if (BackingFieldOrProperty.TryCreateForDependencyProperty(context.ContainingSymbol, out var backingMember)) { if (DependencyProperty.TryGetRegisteredName(backingMember, context.SemanticModel, context.CancellationToken, out _, out var registeredName)) { if (backingMember.Type == KnownSymbols.DependencyProperty && !backingMember.Name.IsParts(registeredName, "Property")) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0001BackingFieldShouldMatchRegisteredName, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "Property"), backingMember.Name, registeredName)); } if (backingMember.Type == KnownSymbols.DependencyPropertyKey && !backingMember.Name.IsParts(registeredName, "PropertyKey")) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0002BackingFieldShouldMatchRegisteredName, BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "PropertyKey"), backingMember.Name, registeredName)); } if (context.ContainingSymbol.ContainingType.TryFindProperty(registeredName, out _) && context.ContainingSymbol.DeclaredAccessibility.IsEither(Accessibility.Protected, Accessibility.Internal, Accessibility.Public) && !HasStandardText(memberDeclaration, registeredName, out var comment)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0060DocumentDependencyPropertyBackingMember, comment == null ? BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation() : comment.GetLocation(), properties: ImmutableDictionary <string, string> .Empty.Add(nameof(CrefParameterSyntax), registeredName))); } if (DependencyProperty.TryGetRegisteredType(backingMember, context.SemanticModel, context.CancellationToken, out var type) && type.Is(KnownSymbols.Style) && !TryFindStyleTypedPropertyAttribute(memberDeclaration, registeredName, context.SemanticModel, context.CancellationToken) && backingMember.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 bool IsWrongType(BackingFieldOrProperty fieldOrProperty, ArgumentSyntax argument, SyntaxNodeAnalysisContext context, [NotNullWhen(true)] out ITypeSymbol?registeredType) { if (DependencyProperty.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out registeredType) && !PropertyMetadata.IsValueValidForRegisteredType(argument.Expression, registeredType, context.SemanticModel, context.CancellationToken)) { if (context.SemanticModel.TryGetType(argument.Expression, context.CancellationToken, out var type)) { if (type == KnownSymbols.Object) { return(false); } if (registeredType.IsAssignableTo(KnownSymbols.Freezable, context.Compilation) && type.IsAssignableTo(KnownSymbols.Freezable, context.Compilation)) { return(false); } } return(true); } return(false); }
private static bool IsWrongType(BackingFieldOrProperty fieldOrProperty, ArgumentSyntax argument, SyntaxNodeAnalysisContext context, out ITypeSymbol registeredType) { if (DependencyProperty.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out registeredType) && !context.SemanticModel.IsRepresentationPreservingConversion(argument.Expression, registeredType, context.CancellationToken)) { if (context.SemanticModel.TryGetType(argument.Expression, context.CancellationToken, out var type)) { if (type == KnownSymbol.Object) { return(false); } if (registeredType.IsAssignableTo(KnownSymbol.Freezable, context.Compilation) && type.IsAssignableTo(KnownSymbol.Freezable, context.Compilation)) { return(false); } } return(true); } return(false); }
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 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)) { 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) && !HasStandardText(methodDeclaration, fieldOrProperty, registeredName, out var location)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0061DocumentClrMethod, location)); } } 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 { } 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 ObjectCreationExpressionSyntax objectCreation && context.ContainingSymbol.IsStatic && PropertyMetadata.TryGetConstructor(objectCreation, context.SemanticModel, context.CancellationToken, out _)) { if (PropertyMetadata.TryGetRegisteredName(objectCreation, context.SemanticModel, context.CancellationToken, out _, out var registeredName)) { if (PropertyMetadata.TryGetPropertyChangedCallback(objectCreation, context.SemanticModel, context.CancellationToken, out var propertyChangedCallback) && Callback.TryGetTarget(propertyChangedCallback, KnownSymbols.PropertyChangedCallback, context.SemanticModel, context.CancellationToken, out var callbackIdentifier, out var target)) { if (target.ContainingType.Equals(context.ContainingSymbol.ContainingType) && !target.Name.IsParts("On", registeredName, "Changed") && target.DeclaredAccessibility.IsEither(Accessibility.Private, Accessibility.Protected)) { using (var walker = InvocationWalker.InContainingClass(target, context.SemanticModel, context.CancellationToken)) { if (walker.IdentifierNames.Count == 1) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0005PropertyChangedCallbackShouldMatchRegisteredName, callbackIdentifier.GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", $"On{registeredName}Changed"), callbackIdentifier, $"On{registeredName}Changed")); } else if (target.Name.StartsWith("On") && target.Name.EndsWith("Changed")) { foreach (var identifierName in walker.IdentifierNames) { if (identifierName.TryFirstAncestor(out ArgumentSyntax argument) && argument != propertyChangedCallback && MatchesPropertyChangedCallbackName(argument, target, context)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0005PropertyChangedCallbackShouldMatchRegisteredName, callbackIdentifier.GetLocation(), callbackIdentifier, $"On{registeredName}Changed")); break; } } } } } if (target.TrySingleMethodDeclaration(context.CancellationToken, out var declaration) && Callback.IsSingleExpression(declaration)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0023ConvertToLambda, propertyChangedCallback.GetLocation())); } } if (PropertyMetadata.TryGetCoerceValueCallback(objectCreation, context.SemanticModel, context.CancellationToken, out var coerceValueCallback) && Callback.TryGetTarget(coerceValueCallback, KnownSymbols.CoerceValueCallback, context.SemanticModel, context.CancellationToken, out callbackIdentifier, out target)) { if (target.ContainingType.Equals(context.ContainingSymbol.ContainingType) && !target.Name.IsParts("Coerce", registeredName)) { using (var walker = InvocationWalker.InContainingClass(target, context.SemanticModel, context.CancellationToken)) { if (walker.IdentifierNames.Count == 1) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0006CoerceValueCallbackShouldMatchRegisteredName, callbackIdentifier.GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", $"Coerce{registeredName}"), callbackIdentifier, $"Coerce{registeredName}")); } else if (target.Name.StartsWith("Coerce")) { foreach (var identifierName in walker.IdentifierNames) { if (identifierName.TryFirstAncestor(out ArgumentSyntax argument) && argument != propertyChangedCallback && MatchesCoerceValueCallbackName(argument, target, context)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0006CoerceValueCallbackShouldMatchRegisteredName, callbackIdentifier.GetLocation(), callbackIdentifier, $"Coerce{registeredName}")); break; } } } } } if (target.TrySingleMethodDeclaration(context.CancellationToken, out var declaration) && Callback.IsSingleExpression(declaration)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0023ConvertToLambda, propertyChangedCallback.GetLocation())); } } } if (PropertyMetadata.TryGetDependencyProperty(objectCreation, context.SemanticModel, context.CancellationToken, out var fieldOrProperty) && DependencyProperty.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var registeredType) && PropertyMetadata.TryGetDefaultValue(objectCreation, context.SemanticModel, context.CancellationToken, out var defaultValueArg)) { if (!PropertyMetadata.IsValueValidForRegisteredType(defaultValueArg.Expression, registeredType, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic( Diagnostic.Create( Descriptors.WPF0010DefaultValueMustMatchRegisteredType, defaultValueArg.GetLocation(), fieldOrProperty.Symbol, registeredType)); } if (registeredType.IsReferenceType) { var defaultValue = defaultValueArg.Expression; if (defaultValue != null && !defaultValue.IsKind(SyntaxKind.NullLiteralExpression) && registeredType != KnownSymbols.FontFamily) { if (IsNonEmptyArrayCreation(defaultValue as ArrayCreationExpressionSyntax, context) || IsReferenceTypeCreation(defaultValue as ObjectCreationExpressionSyntax, context)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0016DefaultValueIsSharedReferenceType, defaultValueArg.GetLocation(), fieldOrProperty.Symbol)); } } } } } }
private static void Handle(SyntaxNodeAnalysisContext context) { if (!context.IsExcludedFromAnalysis() && !context.ContainingSymbol.IsStatic && context.ContainingSymbol is IPropertySymbol property && property.ContainingType.IsAssignableTo(KnownSymbol.DependencyObject, context.Compilation) && context.Node is PropertyDeclarationSyntax propertyDeclaration && PropertyDeclarationWalker.TryGetCalls(propertyDeclaration, out var getCall, out var setCall)) { if (setCall != null && propertyDeclaration.TryGetSetter(out var setter) && setter.Body != null && setter.Body.Statements.TryFirst(x => !x.Contains(setCall), out var statement)) { context.ReportDiagnostic(Diagnostic.Create(WPF0036AvoidSideEffectsInClrAccessors.Descriptor, statement.GetLocation())); } if (getCall != null && propertyDeclaration.TryGetGetter(out var getter) && getter.Body != null && getter.Body.Statements.TryFirst(x => !x.Contains(getCall), out statement)) { context.ReportDiagnostic(Diagnostic.Create(WPF0036AvoidSideEffectsInClrAccessors.Descriptor, statement.GetLocation())); } if (getCall.TryGetArgumentAtIndex(0, out var getArg) && getArg.Expression is IdentifierNameSyntax getIdentifier && setCall.TryGetArgumentAtIndex(0, out var setArg) && setArg.Expression is IdentifierNameSyntax setIdentifier && getIdentifier.Identifier.ValueText != setIdentifier.Identifier.ValueText && !setIdentifier.Identifier.ValueText.IsParts(getIdentifier.Identifier.ValueText, "Key")) { context.ReportDiagnostic( Diagnostic.Create( WPF0032ClrPropertyGetAndSetSameDependencyProperty.Descriptor, propertyDeclaration.GetLocation(), context.ContainingSymbol.Name)); } if (setCall.TryGetMethodName(out var setCallName) && setCallName != "SetValue") { //// ReSharper disable once PossibleNullReferenceException context.ReportDiagnostic( Diagnostic.Create( WPF0035ClrPropertyUseSetValueInSetter.Descriptor, setCall.GetLocation(), context.ContainingSymbol.Name)); } if (ClrProperty.TryGetRegisterField(propertyDeclaration, context.SemanticModel, context.CancellationToken, out var fieldOrProperty)) { if (DependencyProperty.TryGetRegisteredName(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var registeredName) && registeredName != property.Name) { context.ReportDiagnostic( Diagnostic.Create( WPF0003ClrPropertyShouldMatchRegisteredName.Descriptor, propertyDeclaration.Identifier.GetLocation(), ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName), property.Name, registeredName)); } if (DependencyProperty.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var registeredType) && !registeredType.Equals(property.Type)) { context.ReportDiagnostic( Diagnostic.Create( WPF0012ClrPropertyShouldMatchRegisteredType.Descriptor, propertyDeclaration.Type.GetLocation(), ImmutableDictionary <string, string> .Empty.Add(nameof(TypeSyntax), registeredType.ToMinimalDisplayString(context.SemanticModel, context.Node.SpanStart)), property, registeredType)); } } } }
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) { 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))]"),