예제 #1
0
        internal static bool TryGetRegisteredName(InvocationExpressionSyntax invocation, SemanticModel semanticModel, CancellationToken cancellationToken, out ArgumentSyntax nameArg, out string registeredName)
        {
            nameArg        = null;
            registeredName = null;
            if (invocation == null)
            {
                return(false);
            }

            if (TryGetRegisterCall(invocation, semanticModel, cancellationToken, out var method) ||
                TryGetRegisterReadOnlyCall(invocation, semanticModel, cancellationToken, out method) ||
                TryGetRegisterAttachedCall(invocation, semanticModel, cancellationToken, out method) ||
                TryGetRegisterAttachedReadOnlyCall(invocation, semanticModel, cancellationToken, out method))
            {
                return(method.TryFindParameter("name", out var parameter) &&
                       invocation.TryFindArgument(parameter, out nameArg) &&
                       nameArg.TryGetStringValue(semanticModel, cancellationToken, out registeredName));
            }

            if (invocation.Expression is MemberAccessExpressionSyntax memberAccess &&
                (TryGetAddOwnerCall(invocation, semanticModel, cancellationToken, out _) ||
                 TryGetOverrideMetadataCall(invocation, semanticModel, cancellationToken, out _)))
            {
                if (semanticModel.TryGetSymbol(memberAccess.Expression, cancellationToken, out var symbol) &&
                    BackingFieldOrProperty.TryCreateForDependencyProperty(symbol, out var fieldOrProperty))
                {
                    return(TryGetRegisteredName(fieldOrProperty, semanticModel, cancellationToken, out nameArg, out registeredName));
                }

                return(false);
            }

            return(false);
        }
예제 #2
0
        internal static bool TryGetPropertyByName(BackingFieldOrProperty fieldOrProperty, out IPropertySymbol property)
        {
            property = null;
            if (IsPotentialDependencyPropertyBackingField(fieldOrProperty) ||
                IsPotentialDependencyPropertyKeyBackingField(fieldOrProperty))
            {
                var suffix = IsPotentialDependencyPropertyBackingField(fieldOrProperty)
                                 ? "Property"
                                 : "PropertyKey";

                foreach (var symbol in fieldOrProperty.ContainingType.GetMembers())
                {
                    if (symbol is IPropertySymbol candidate)
                    {
                        if (!fieldOrProperty.Name.IsParts(candidate.Name, suffix))
                        {
                            continue;
                        }

                        if (property != null)
                        {
                            property = null;
                            return(false);
                        }

                        property = candidate;
                    }
                }
            }

            return(property != null);
        }
예제 #3
0
        internal static bool TryGetRegisteredType(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out ITypeSymbol result)
        {
            result = null;
            if (TryGetRegisterInvocationRecursive(backing, semanticModel, cancellationToken, out var invocation, out _))
            {
                return(invocation.TryGetArgumentAtIndex(1, out var typeArg) &&
                       typeArg.Expression is TypeOfExpressionSyntax typeOf &&
                       TypeOf.TryGetType(typeOf, backing.ContainingType, semanticModel, cancellationToken, out result));
            }

            if (TryGetDependencyAddOwnerSourceField(backing, semanticModel, cancellationToken, out var source) &&
                !source.Symbol.Equals(backing.Symbol))
            {
                return(TryGetRegisteredType(source, semanticModel, cancellationToken, out result));
            }

            if (backing.Symbol.Locations.All(x => !x.IsInSource) &&
                TryGetPropertyByName(backing, out var property))
            {
                result = property.Type;
                return(true);
            }

            return(false);
        }
예제 #4
0
        internal static bool TryGetDependencyPropertyKeyFieldOrProperty(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty result)
        {
            result = default;
            if (backing.TryGetAssignedValue(cancellationToken, out var value) &&
                semanticModel.TryGetSymbol(value, cancellationToken, out ISymbol symbol))
            {
                if (symbol is IMethodSymbol method)
                {
                    return(method == KnownSymbols.DependencyProperty.AddOwner &&
                           value is InvocationExpressionSyntax invocation &&
                           invocation.Expression is MemberAccessExpressionSyntax member &&
                           semanticModel.TryGetSymbol(member.Expression, cancellationToken, out ISymbol candidate) &&
                           BackingFieldOrProperty.TryCreateForDependencyProperty(candidate, out result) &&
                           TryGetDependencyPropertyKeyFieldOrProperty(result, semanticModel, cancellationToken, out result));
                }
                else
                {
                    return(symbol is IPropertySymbol property &&
                           property == KnownSymbols.DependencyPropertyKey.DependencyProperty &&
                           value is MemberAccessExpressionSyntax memberAccess &&
                           semanticModel.TryGetSymbol(memberAccess.Expression, cancellationToken, out ISymbol candidate) &&
                           BackingFieldOrProperty.TryCreateForDependencyProperty(candidate, out result));
                }
            }

            return(false);
        }
예제 #5
0
        internal static bool IsAttachedGet(MethodDeclarationSyntax method, SemanticModel semanticModel, CancellationToken cancellationToken, out InvocationExpressionSyntax call, out BackingFieldOrProperty getField)
        {
            call     = null;
            getField = default(BackingFieldOrProperty);
            if (method == null ||
                method.ParameterList.Parameters.Count != 1 ||
                method.ReturnType.IsVoid() ||
                !method.Modifiers.Any(SyntaxKind.StaticKeyword))
            {
                return(false);
            }

            using (var walker = ClrGetterWalker.Borrow(semanticModel, cancellationToken, method))
            {
                call = walker.GetValue;
                var memberAccess = walker.GetValue?.Expression as MemberAccessExpressionSyntax;
                var member       = memberAccess?.Expression as IdentifierNameSyntax;
                if (memberAccess == null ||
                    member == null ||
                    !memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression))
                {
                    return(false);
                }

                if (method.ParameterList.Parameters[0].Identifier.ValueText != member.Identifier.ValueText)
                {
                    return(false);
                }

                return(BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(walker.Property.Expression, cancellationToken), out getField));
            }
        }
예제 #6
0
        internal static bool TryGetRegisteredName(InvocationExpressionSyntax invocation, SemanticModel semanticModel, CancellationToken cancellationToken, out string registeredName)
        {
            registeredName = null;
            if (invocation == null)
            {
                return(false);
            }

            if (TryGetRegisterCall(invocation, semanticModel, cancellationToken, out _) ||
                TryGetRegisterReadOnlyCall(invocation, semanticModel, cancellationToken, out _) ||
                TryGetRegisterAttachedCall(invocation, semanticModel, cancellationToken, out _) ||
                TryGetRegisterAttachedReadOnlyCall(invocation, semanticModel, cancellationToken, out _))
            {
                return(invocation.TryGetArgumentAtIndex(0, out var nameArg) &&
                       nameArg.TryGetStringValue(semanticModel, cancellationToken, out registeredName));
            }

            if (invocation.Expression is MemberAccessExpressionSyntax memberAccess &&
                (TryGetAddOwnerCall(invocation, semanticModel, cancellationToken, out _) ||
                 TryGetOverrideMetadataCall(invocation, semanticModel, cancellationToken, out _)))
            {
                if (BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(memberAccess.Expression, cancellationToken), out var fieldOrProperty))
                {
                    return(TryGetRegisteredName(fieldOrProperty, semanticModel, cancellationToken, out registeredName));
                }

                return(false);
            }

            return(false);
        }
예제 #7
0
        internal static bool TryGetRegisteredName(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out ArgumentSyntax nameArg, out string result)
        {
            nameArg = null;
            result  = null;
            if (TryGetRegisterInvocationRecursive(backing, semanticModel, cancellationToken, out var invocation, out var method))
            {
                return(method.TryFindParameter("name", out var parameter) &&
                       invocation.TryFindArgument(parameter, out nameArg) &&
                       nameArg.TryGetStringValue(semanticModel, cancellationToken, out result));
            }

            if (TryGetDependencyAddOwnerSourceField(backing, semanticModel, cancellationToken, out var source) &&
                !source.Symbol.Equals(backing.Symbol))
            {
                return(TryGetRegisteredName(source, semanticModel, cancellationToken, out nameArg, out result));
            }

            if (backing.Symbol.Locations.All(x => !x.IsInSource) &&
                TryGetPropertyByName(backing, out var property))
            {
                result = property.Name;
                return(true);
            }

            return(false);
        }
예제 #8
0
        /// <summary>
        /// Get the backing fields for the <paramref name="propertyDeclaration"/> these are different for readonly dependency properties where the setter returns the DependencyPropertyKey field.
        /// </summary>
        internal static bool TryGetBackingFields(PropertyDeclarationSyntax propertyDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty getField, out BackingFieldOrProperty setField)
        {
            getField = default;
            setField = default;
            if (propertyDeclaration.TryGetGetter(out var getAccessor) &&
                propertyDeclaration.TryGetSetter(out var setAccessor))
            {
                using (var getterWalker = ClrGetterWalker.Borrow(semanticModel, cancellationToken, getAccessor))
                {
                    using (var setterWalker = ClrSetterWalker.Borrow(semanticModel, cancellationToken, setAccessor))
                    {
                        if (getterWalker.HasError ||
                            setterWalker.HasError)
                        {
                            return(false);
                        }

                        if (getterWalker.IsSuccess &&
                            BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(getterWalker.Property.Expression, cancellationToken), out getField) &&
                            setterWalker.IsSuccess &&
                            BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(setterWalker.Property.Expression, cancellationToken), out setField))
                        {
                            return(true);
                        }

                        var property = semanticModel.GetSymbolSafe(propertyDeclaration, cancellationToken) as IPropertySymbol;
                        return(TryGetBackingFieldsByName(property, semanticModel.Compilation, out getField, out setField));
                    }
                }
            }

            return(false);
        }
예제 #9
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (context.IsExcludedFromAnalysis())
            {
                return;
            }

            if (context.Node is InvocationExpressionSyntax invocation &&
                context.ContainingSymbol.IsStatic)
            {
                if (invocation.TryGetArgumentAtIndex(2, out var argument) &&
                    (DependencyProperty.TryGetRegisterCall(invocation, context.SemanticModel, context.CancellationToken, out _) ||
                     DependencyProperty.TryGetRegisterReadOnlyCall(invocation, context.SemanticModel, context.CancellationToken, out _) ||
                     DependencyProperty.TryGetRegisterAttachedCall(invocation, context.SemanticModel, context.CancellationToken, out _) ||
                     DependencyProperty.TryGetRegisterAttachedReadOnlyCall(invocation, context.SemanticModel, context.CancellationToken, out _)))
                {
                    HandleArgument(context, argument);
                }
                else if (invocation.TryGetArgumentAtIndex(0, out argument))
                {
                    if (DependencyProperty.TryGetAddOwnerCall(invocation, context.SemanticModel, context.CancellationToken, out _))
                    {
                        HandleArgument(context, argument);
                    }
                    else if (DependencyProperty.TryGetOverrideMetadataCall(invocation, context.SemanticModel, context.CancellationToken, out _) &&
                             invocation.Expression is MemberAccessExpressionSyntax memberAccess &&
                             BackingFieldOrProperty.TryCreateForDependencyProperty(context.SemanticModel.GetSymbolSafe(memberAccess.Expression, context.CancellationToken), out var fieldOrProperty) &&
                             context.ContainingSymbol.ContainingType.IsAssignableTo(fieldOrProperty.ContainingType, context.Compilation))
                    {
                        HandleArgument(context, argument);
                    }
                }
            }
        }
예제 #10
0
 private ClrProperty(BackingFieldOrProperty backingGet, BackingFieldOrProperty backingSet, InvocationExpressionSyntax?getValue, InvocationExpressionSyntax?setValue)
 {
     this.BackingGet = backingGet;
     this.BackingSet = backingSet;
     this.GetValue   = getValue;
     this.SetValue   = setValue;
 }
예제 #11
0
        /// <inheritdoc/>
        protected override async Task RegisterCodeFixesAsync(DocumentEditorCodeFixContext context)
        {
            var document   = context.Document;
            var syntaxRoot = await document.GetSyntaxRootAsync(context.CancellationToken)
                             .ConfigureAwait(false);

            var semanticModel = await document.GetSemanticModelAsync(context.CancellationToken)
                                .ConfigureAwait(false);

            foreach (var diagnostic in context.Diagnostics)
            {
                var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start);
                if (string.IsNullOrEmpty(token.ValueText))
                {
                    continue;
                }

                if (syntaxRoot.TryFindNodeOrAncestor(diagnostic, out MemberDeclarationSyntax member) &&
                    semanticModel.TryGetSymbol(member, context.CancellationToken, out ISymbol symbol) &&
                    BackingFieldOrProperty.TryCreateForDependencyProperty(symbol, out var fieldOrProperty) &&
                    DependencyProperty.TryGetRegisteredName(fieldOrProperty, semanticModel, context.CancellationToken, out var name))
                {
                    context.RegisterCodeFix(
                        "Add standard documentation.",
                        (editor, _) => editor.ReplaceNode(member, x => x.WithDocumentationText($"/// <summary>Identifies the <see cref=\"{name}\"/> dependency property.</summary>")),
                        this.GetType(),
                        diagnostic);
                }
            }
        }
예제 #12
0
        internal static bool IsAttachedSet(MethodDeclarationSyntax method, SemanticModel semanticModel, CancellationToken cancellationToken, out InvocationExpressionSyntax setValueCall, out BackingFieldOrProperty setField)
        {
            setValueCall = null;
            setField     = default(BackingFieldOrProperty);
            if (method == null ||
                method.ParameterList.Parameters.Count != 2 ||
                !method.ReturnType.IsVoid() ||
                !method.Modifiers.Any(SyntaxKind.StaticKeyword))
            {
                return(false);
            }

            using (var walker = ClrSetterWalker.Borrow(semanticModel, cancellationToken, method))
            {
                if (!walker.IsSuccess)
                {
                    return(false);
                }

                setValueCall = walker.SetValue ?? walker.SetCurrentValue;
                if (setValueCall.Expression is MemberAccessExpressionSyntax memberAccess &&
                    memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression) &&
                    memberAccess.Expression is IdentifierNameSyntax member)
                {
                    if (method.ParameterList.Parameters[0].Identifier.ValueText != member.Identifier.ValueText)
                    {
                        return(false);
                    }

                    if (setValueCall.TryGetArgumentAtIndex(1, out var arg) &&
                        method.ParameterList.Parameters.TryElementAt(1, out var parameter))
                    {
                        if (arg.Expression is IdentifierNameSyntax argIdentifier &&
                            argIdentifier.Identifier.ValueText == parameter.Identifier.ValueText)
                        {
                            return(BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(walker.Property.Expression, cancellationToken), out setField));
                        }

                        if (arg.Expression is InvocationExpressionSyntax invocation &&
                            invocation.TrySingleArgument(out var nestedArg) &&
                            nestedArg.Expression is IdentifierNameSyntax nestedArgId &&
                            nestedArgId.Identifier.ValueText == parameter.Identifier.ValueText)
                        {
                            return(BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(walker.Property.Expression, cancellationToken), out setField));
                        }

                        if (arg.Expression is ConditionalExpressionSyntax ternary &&
                            ternary.Condition is IdentifierNameSyntax conditionIdentifier &&
                            conditionIdentifier.Identifier.ValueText == parameter.Identifier.ValueText)
                        {
                            return(BackingFieldOrProperty.TryCreateForDependencyProperty(semanticModel.GetSymbolSafe(walker.Property.Expression, cancellationToken), out setField));
                        }
                    }
                }

                return(false);
            }
        }
        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))]"),
예제 #14
0
        internal static bool TryCreateCandidate(ISymbol symbol, out BackingFieldOrProperty result)
        {
            if (symbol != null &&
                FieldOrProperty.TryCreate(symbol, out var fieldOrProperty) &&
                fieldOrProperty.Type.IsEither(KnownSymbol.DependencyProperty, KnownSymbol.DependencyPropertyKey))
            {
                result = new BackingFieldOrProperty(fieldOrProperty);
                return(true);
            }

            result = default(BackingFieldOrProperty);
            return(false);
        }
예제 #15
0
 internal static bool TryGetDependencyPropertyKeyFieldOrProperty(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty result)
 {
     result = default;
     if (backing.TryGetAssignedValue(cancellationToken, out var value) &&
         semanticModel.TryGetSymbol(value, cancellationToken, out var symbol))
     {
         if (symbol is IMethodSymbol method)
         {
             return(method == KnownSymbols.DependencyProperty.AddOwner &&
                    value is InvocationExpressionSyntax {
                 Expression : MemberAccessExpressionSyntax {
                     Expression : { } expression
                 }
             } &&
예제 #16
0
        internal static bool TryGetRegisterInvocationRecursive(BackingFieldOrProperty fieldOrProperty, SemanticModel semanticModel, CancellationToken cancellationToken, out InvocationExpressionSyntax result, out IMethodSymbol symbol)
        {
            if (TryGetDependencyPropertyKeyFieldOrProperty(fieldOrProperty, semanticModel, cancellationToken, out var keyField))
            {
                return(TryGetRegisterInvocationRecursive(keyField, semanticModel, cancellationToken, out result, out symbol));
            }

            if (TryGetDependencyAddOwnerSourceField(fieldOrProperty, semanticModel, cancellationToken, out var addOwnerSource))
            {
                return(TryGetRegisterInvocationRecursive(addOwnerSource, semanticModel, cancellationToken, out result, out symbol));
            }

            return(TryGetRegisterInvocation(fieldOrProperty, semanticModel, cancellationToken, out result, out symbol));
        }
예제 #17
0
        internal static bool TryGetDependencyAddOwnerSourceField(BackingFieldOrProperty fieldOrProperty, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty result)
        {
            result = default;
            if (fieldOrProperty.TryGetAssignedValue(cancellationToken, out var value) &&
                value is InvocationExpressionSyntax invocation &&
                semanticModel.TryGetSymbol(invocation, KnownSymbols.DependencyProperty.AddOwner, cancellationToken, out _))
            {
                var addOwner = (MemberAccessExpressionSyntax)invocation.Expression;
                return(BackingFieldOrProperty.TryCreateForDependencyProperty(
                           semanticModel.GetSymbolSafe(addOwner.Expression, cancellationToken),
                           out result));
            }

            return(false);
        }
예제 #18
0
 private static void Handle(SyntaxNodeAnalysisContext context)
 {
     if (!context.IsExcludedFromAnalysis() &&
         context.Node is InvocationExpressionSyntax invocation &&
         DependencyProperty.TryGetOverrideMetadataCall(invocation, context.SemanticModel, context.CancellationToken, out var method) &&
         invocation.Expression is MemberAccessExpressionSyntax memberAccess &&
         context.SemanticModel.TryGetSymbol(memberAccess.Expression, context.CancellationToken, out ISymbol candidate) &&
         BackingFieldOrProperty.TryCreateForDependencyProperty(candidate, out var fieldOrProperty) &&
         method.TryFindParameter(KnownSymbols.PropertyMetadata, out var parameter) &&
         invocation.TryFindArgument(parameter, out var metadataArg))
     {
         if (fieldOrProperty.TryGetAssignedValue(context.CancellationToken, out var value) &&
             value is InvocationExpressionSyntax registerInvocation)
         {
             if (DependencyProperty.TryGetRegisterCall(registerInvocation, context.SemanticModel, context.CancellationToken, out var registerMethod) ||
                 DependencyProperty.TryGetRegisterReadOnlyCall(registerInvocation, context.SemanticModel, context.CancellationToken, out registerMethod) ||
                 DependencyProperty.TryGetRegisterAttachedCall(registerInvocation, context.SemanticModel, context.CancellationToken, out registerMethod) ||
                 DependencyProperty.TryGetRegisterAttachedReadOnlyCall(registerInvocation, context.SemanticModel, context.CancellationToken, out registerMethod))
             {
                 if (registerMethod.TryFindParameter(KnownSymbols.PropertyMetadata, out var registerParameter) &&
                     registerInvocation.TryFindArgument(registerParameter, out var registeredMetadataArg) &&
                     context.SemanticModel.TryGetType(metadataArg.Expression, context.CancellationToken, out var type) &&
                     context.SemanticModel.TryGetType(registeredMetadataArg.Expression, context.CancellationToken, out var registeredType) &&
                     !type.IsAssignableTo(registeredType, context.Compilation))
                 {
                     context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0017MetadataMustBeAssignable, metadataArg.GetLocation()));
                 }
             }
         }
         else if (fieldOrProperty.Symbol == KnownSymbols.FrameworkElement.DefaultStyleKeyProperty &&
                  metadataArg.Expression is ObjectCreationExpressionSyntax metadataCreation)
         {
             if (!context.SemanticModel.TryGetSymbol(metadataCreation, KnownSymbols.FrameworkPropertyMetadata, context.CancellationToken, out _))
             {
                 context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0017MetadataMustBeAssignable, metadataArg.GetLocation()));
             }
             else if (metadataCreation.TrySingleArgument(out var typeArg) &&
                      typeArg.Expression is TypeOfExpressionSyntax typeOf &&
                      typeOf.Type is IdentifierNameSyntax typeName &&
                      typeName.Identifier.ValueText != context.ContainingSymbol.ContainingType.MetadataName)
             {
                 context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0018DefaultStyleKeyPropertyOverrideMetadataArgument, typeArg.GetLocation()));
             }
         }
     }
 }
예제 #19
0
        private static void HandleInvocation(SyntaxNodeAnalysisContext context)
        {
            if (context.IsExcludedFromAnalysis())
            {
                return;
            }

            if (context.Node is InvocationExpressionSyntax invocation &&
                !IsInObjectInitializer(invocation) &&
                !IsInConstructor(invocation) &&
                DependencyObject.TryGetSetValueCall(invocation, context.SemanticModel, context.CancellationToken, out _))
            {
                var propertyArg = invocation.ArgumentList.Arguments[0];
                if (!BackingFieldOrProperty.TryCreateForDependencyProperty(context.SemanticModel.GetSymbolSafe(propertyArg.Expression, context.CancellationToken), out var propertyMember) ||
                    propertyMember.Type == KnownSymbol.DependencyPropertyKey)
                {
                    return;
                }

                if (propertyMember.Symbol is IFieldSymbol field &&
                    field == KnownSymbol.FrameworkElement.DataContextProperty)
                {
                    return;
                }

                var clrProperty = context.ContainingProperty();
                if (clrProperty.IsDependencyPropertyAccessor(context.SemanticModel, context.CancellationToken))
                {
                    return;
                }

                var clrMethod = context.ContainingSymbol as IMethodSymbol;
                if (ClrMethod.IsAttachedSet(clrMethod, context.SemanticModel, context.CancellationToken, out propertyMember))
                {
                    return;
                }

                if (IsCalleePotentiallyCreatedInScope(invocation.Expression as MemberAccessExpressionSyntax, context.SemanticModel, context.CancellationToken))
                {
                    return;
                }

                context.ReportDiagnostic(Diagnostic.Create(Descriptor, invocation.GetLocation(), propertyMember, invocation.ArgumentList.Arguments[1]));
            }
        }
예제 #20
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is InvocationExpressionSyntax invocation &&
                TryGetArgs(context, out var target, out var propertyArg, out var valueArg) &&
                context.SemanticModel.TryGetSymbol(propertyArg.Expression, context.CancellationToken, out var symbol) &&
                BackingFieldOrProperty.Match(symbol) is { } backing)
            {
                if (IsWrongType(backing, valueArg, context) is { } registeredType)
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            Descriptors.WPF0014SetValueMustUseRegisteredType,
                            valueArg.GetLocation(),
                            target.Name,
                            registeredType));
                }

                if (backing.Type == KnownSymbols.DependencyProperty &&
                    backing.FindKey(context.SemanticModel, context.CancellationToken) is { } keyField)
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            Descriptors.WPF0040SetUsingDependencyPropertyKey,
                            propertyArg.GetLocation(),
                            properties: ImmutableDictionary <string, string?> .Empty.Add(nameof(DependencyPropertyKeyType), keyField.Name),
                            propertyArg,
                            keyField.CreateArgument(context.SemanticModel, propertyArg.SpanStart)));
                }

                if (target == KnownSymbols.DependencyObject.SetCurrentValue &&
                    backing.Symbol is IFieldSymbol setField &&
                    (setField == KnownSymbols.FrameworkElement.DataContextProperty ||
                     setField.Name == "StyleProperty"))
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            Descriptors.WPF0043DoNotUseSetCurrentValue,
                            invocation.GetLocation(),
                            setField.Name,
                            invocation.ArgumentList.Arguments[1]));
                }
            }
        }
예제 #21
0
        private static void HandleInvocation(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is InvocationExpressionSyntax invocation &&
                !IsInConstructor(invocation) &&
                invocation.ArgumentList is ArgumentListSyntax argumentList &&
                argumentList.Arguments.Count == 2 &&
                argumentList.Arguments.TryElementAt(0, out var propertyArg) &&
                DependencyObject.TryGetSetValueCall(invocation, context.SemanticModel, context.CancellationToken, out _) &&
                BackingFieldOrProperty.TryCreateForDependencyProperty(context.SemanticModel.GetSymbolSafe(propertyArg.Expression, context.CancellationToken), out var backingFieldOrProperty) &&
                !IsCalleePotentiallyCreatedInScope(invocation.Expression as MemberAccessExpressionSyntax, context.SemanticModel, context.CancellationToken))
            {
                if (backingFieldOrProperty.Type == KnownSymbols.DependencyPropertyKey)
                {
                    return;
                }

                if (backingFieldOrProperty.Symbol is IFieldSymbol field &&
                    field == KnownSymbols.FrameworkElement.DataContextProperty)
                {
                    return;
                }

                var clrProperty = context.ContainingProperty();
                if (clrProperty.IsDependencyPropertyAccessor(context.SemanticModel, context.CancellationToken))
                {
                    return;
                }

                var clrMethod = context.ContainingSymbol as IMethodSymbol;
                if (ClrMethod.IsAttachedSet(clrMethod, context.SemanticModel, context.CancellationToken, out backingFieldOrProperty))
                {
                    return;
                }

                context.ReportDiagnostic(
                    Diagnostic.Create(
                        Descriptors.WPF0041SetMutableUsingSetCurrentValue,
                        invocation.GetLocation(),
                        backingFieldOrProperty,
                        invocation.ArgumentList.Arguments[1]));
            }
        }
예제 #22
0
        /// <summary>
        /// Get the backing fields for the <paramref name="property"/> these are different for readonly dependency properties where the setter returns the DependencyPropertyKey field.
        /// This method looks for fields that matches the name NameProperty and NamePropertyKey.
        /// </summary>
        private static bool TryGetBackingFieldsByName(IPropertySymbol property, Compilation compilation, out BackingFieldOrProperty getter, out BackingFieldOrProperty setter)
        {
            getter = default;
            setter = default;
            if (property == null ||
                !property.ContainingType.IsAssignableTo(KnownSymbols.DependencyObject, compilation))
            {
                return(false);
            }

            foreach (var member in property.ContainingType.GetMembers())
            {
                if (BackingFieldOrProperty.TryCreateForDependencyProperty(member, out var candidate))
                {
                    if (candidate.Name.IsParts(property.Name, "Property"))
                    {
                        if (!DependencyProperty.IsPotentialDependencyPropertyBackingField(candidate))
                        {
                            return(false);
                        }

                        getter = candidate;
                    }

                    if (candidate.Name.IsParts(property.Name, "PropertyKey"))
                    {
                        if (!DependencyProperty.IsPotentialDependencyPropertyKeyBackingField(candidate))
                        {
                            return(false);
                        }

                        setter = candidate;
                    }
                }
            }

            if (setter.Symbol == null)
            {
                setter = getter;
            }

            return(setter.Symbol != null);
        }
예제 #23
0
        internal static bool TryGetRegisterInvocation(BackingFieldOrProperty fieldOrProperty, SemanticModel semanticModel, CancellationToken cancellationToken, out InvocationExpressionSyntax result, out IMethodSymbol symbol)
        {
            symbol = null;
            result = null;
            if (fieldOrProperty.TryGetAssignedValue(cancellationToken, out var value) &&
                value is InvocationExpressionSyntax invocation)
            {
                if (TryGetRegisterCall(invocation, semanticModel, cancellationToken, out symbol) ||
                    TryGetRegisterReadOnlyCall(invocation, semanticModel, cancellationToken, out symbol) ||
                    TryGetRegisterAttachedCall(invocation, semanticModel, cancellationToken, out symbol) ||
                    TryGetRegisterAttachedReadOnlyCall(invocation, semanticModel, cancellationToken, out symbol))
                {
                    result = invocation;
                    return(true);
                }
            }

            return(false);
        }
예제 #24
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is InvocationExpressionSyntax invocation &&
                TryGetArgs(context, out var target, out var propertyArg, out var valueArg) &&
                context.SemanticModel.TryGetSymbol(propertyArg.Expression, context.CancellationToken, out ISymbol? symbol) &&
                BackingFieldOrProperty.TryCreateForDependencyProperty(symbol, out var fieldOrProperty))
            {
                if (IsWrongType(fieldOrProperty, valueArg, context, out var registeredType))
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            Descriptors.WPF0014SetValueMustUseRegisteredType,
                            valueArg.GetLocation(),
                            target.Name,
                            registeredType));
                }

                if (fieldOrProperty.Type == KnownSymbols.DependencyProperty &&
                    DependencyProperty.TryGetDependencyPropertyKeyFieldOrProperty(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var keyField))
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            Descriptors.WPF0040SetUsingDependencyPropertyKey,
                            propertyArg.GetLocation(),
                            propertyArg,
                            keyField.CreateArgument(context.SemanticModel, propertyArg.SpanStart)));
                }

                if (target == KnownSymbols.DependencyObject.SetCurrentValue &&
                    fieldOrProperty.Symbol is IFieldSymbol setField &&
                    setField == KnownSymbols.FrameworkElement.DataContextProperty)
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            Descriptors.WPF0043DoNotUseSetCurrentValueForDataContext,
                            invocation.GetLocation(),
                            setField.Name,
                            invocation.ArgumentList.Arguments[1]));
                }
            }
        }
예제 #25
0
        internal static bool TryGetDependencyProperty(ObjectCreationExpressionSyntax objectCreation, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty fieldOrProperty)
        {
            fieldOrProperty = default;
            var invocation = objectCreation.FirstAncestorOrSelf <InvocationExpressionSyntax>();

            if (invocation == null)
            {
                return(false);
            }

            if (DependencyProperty.TryGetRegisterCall(invocation, semanticModel, cancellationToken, out _) ||
                DependencyProperty.TryGetRegisterReadOnlyCall(invocation, semanticModel, cancellationToken, out _) ||
                DependencyProperty.TryGetRegisterAttachedCall(invocation, semanticModel, cancellationToken, out _) ||
                DependencyProperty.TryGetRegisterAttachedReadOnlyCall(invocation, semanticModel, cancellationToken, out _))
            {
                if (objectCreation.TryFirstAncestor <FieldDeclarationSyntax>(out var fieldDeclaration) &&
                    semanticModel.TryGetSymbol(fieldDeclaration, cancellationToken, out var field))
                {
                    return(BackingFieldOrProperty.TryCreateForDependencyProperty(field, out fieldOrProperty));
                }

                if (objectCreation.TryFirstAncestor <PropertyDeclarationSyntax>(out var propertyDeclaration) &&
                    semanticModel.TryGetSymbol(propertyDeclaration, cancellationToken, out var property))
                {
                    return(BackingFieldOrProperty.TryCreateForDependencyProperty(property, out fieldOrProperty));
                }

                return(false);
            }

            if (invocation.Expression is MemberAccessExpressionSyntax memberAccess &&
                (DependencyProperty.TryGetAddOwnerCall(invocation, semanticModel, cancellationToken, out _) ||
                 DependencyProperty.TryGetOverrideMetadataCall(invocation, semanticModel, cancellationToken, out _)) &&
                semanticModel.TryGetSymbol(memberAccess.Expression, cancellationToken, out ISymbol? candidate))
            {
                return(BackingFieldOrProperty.TryCreateForDependencyProperty(candidate, out fieldOrProperty));
            }

            return(false);
        }
예제 #26
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is MemberDeclarationSyntax memberDeclaration &&
                FieldOrProperty.TryCreate(context.ContainingSymbol, out var fieldOrProperty) &&
                fieldOrProperty.Type == KnownSymbol.RoutedEvent)
            {
                if (RoutedEvent.TryGetRegisteredName(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var registeredName) &&
                    !fieldOrProperty.Name.IsParts(registeredName, "Event"))
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            WPF0100BackingFieldShouldMatchRegisteredName.Descriptor,
                            FindIdentifier(context.Node).GetLocation(),
                            ImmutableDictionary <string, string> .Empty.Add("ExpectedName", registeredName + "Event"),
                            fieldOrProperty.Name,
                            registeredName));
                }

                if (RoutedEvent.TryGetRegisteredType(fieldOrProperty, context.SemanticModel, context.CancellationToken, out var typeArg, out var registeredOwnerType) &&
                    !Equals(registeredOwnerType, context.ContainingSymbol.ContainingType))
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            WPF0101RegisterContainingTypeAsOwner.Descriptor,
                            typeArg.GetLocation(),
                            fieldOrProperty.ContainingType.Name,
                            registeredName));
                }

                if (!fieldOrProperty.IsStaticReadOnly())
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            WPF0107BackingMemberShouldBeStaticReadonly.Descriptor,
                            BackingFieldOrProperty.FindIdentifier(memberDeclaration).GetLocation()));
                }
            }
        }
예제 #27
0
        /// <summary>
        /// Get the backing fields for the <paramref name="property"/> these are different for readonly dependency properties where the setter returns the DependencyPropertyKey field.
        /// </summary>
        private static bool TryGetBackingFields(IPropertySymbol property, SemanticModel semanticModel, CancellationToken cancellationToken, out BackingFieldOrProperty getField, out BackingFieldOrProperty setField)
        {
            getField = default;
            setField = default;

            if (property.IsPotentialClrProperty(semanticModel.Compilation) &&
                property.TrySingleDeclaration(cancellationToken, out PropertyDeclarationSyntax propertyDeclaration) &&
                TryGetBackingFields(propertyDeclaration, semanticModel, cancellationToken, out getField, out setField))
            {
                if (getField.ContainingType.IsGenericType)
                {
                    return(property.ContainingType.TryFindFirstMember(getField.Name, out var getMember) &&
                           BackingFieldOrProperty.TryCreateForDependencyProperty(getMember, out getField) &&
                           property.ContainingType.TryFindFirstMember(setField.Name, out var setMember) &&
                           BackingFieldOrProperty.TryCreateForDependencyProperty(setMember, out setField));
                }

                return(true);
            }

            return(false);
        }
예제 #28
0
        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);
        }
예제 #29
0
        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);
        }
예제 #30
0
        internal static bool TryGetRegisteredName(BackingFieldOrProperty backing, SemanticModel semanticModel, CancellationToken cancellationToken, out string result)
        {
            result = null;
            if (TryGetRegisterInvocationRecursive(backing, semanticModel, cancellationToken, out var invocation, out _))
            {
                return(invocation.TryGetArgumentAtIndex(0, out var arg) &&
                       arg.TryGetStringValue(semanticModel, cancellationToken, out result));
            }

            if (TryGetDependencyAddOwnerSourceField(backing, semanticModel, cancellationToken, out var source) &&
                !source.Symbol.Equals(backing.Symbol))
            {
                return(TryGetRegisteredName(source, semanticModel, cancellationToken, out result));
            }

            if (backing.Symbol.Locations.All(x => !x.IsInSource) &&
                TryGetPropertyByName(backing, out var property))
            {
                result = property.Name;
                return(true);
            }

            return(false);
        }