Esempio n. 1
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);
        }
Esempio n. 2
0
        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()));
                    }
                }
Esempio n. 3
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.ContainingSymbol is INamedTypeSymbol type &&
                type.IsAssignableToEither(KnownSymbols.IValueConverter, KnownSymbols.IMultiValueConverter, context.Compilation) &&
                context.Node is ClassDeclarationSyntax classDeclaration &&
                !type.IsAbstract &&
                type.DeclaredAccessibility != Accessibility.Private &&
                type.DeclaredAccessibility != Accessibility.Protected)
            {
                if (!type.IsAssignableTo(KnownSymbols.MarkupExtension, context.Compilation))
                {
                    if (ValueConverter.TryGetDefaultFieldsOrProperties(type, context.Compilation, out var defaults))
                    {
                        foreach (var fieldOrProperty in defaults)
                        {
                            if (fieldOrProperty.TryGetAssignedValue(context.CancellationToken, out var assignedValue) &&
                                context.SemanticModel.TryGetType(assignedValue, context.CancellationToken, out var assignedType) &&
                                !Equals(assignedType, type))
                            {
                                context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0074DefaultMemberOfWrongType, assignedValue.GetLocation()));
                            }
                        }
                    }
                    else if (!Virtual.HasVirtualOrAbstractOrProtectedMembers(type) &&
                             !type.Constructors.TryFirst(x => x.Parameters.Length > 0, out _) &&
                             !Mutable.HasMutableInstanceMembers(type))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0070ConverterDoesNotHaveDefaultField, classDeclaration.Identifier.GetLocation()));
                    }
                }

                if (type.IsAssignableTo(KnownSymbols.IValueConverter, context.Compilation))
                {
                    if (Attribute.TryFind(classDeclaration, KnownSymbols.ValueConversionAttribute, context.SemanticModel, context.CancellationToken, out var attribute))
                    {
                        if (ValueConverter.TryGetConversionTypes(classDeclaration, context.SemanticModel, context.CancellationToken, out var sourceType, out var targetType))
                        {
                            if (sourceType != null &&
                                sourceType != QualifiedType.System.Object &&
                                attribute.TryFindArgument(0, "sourceType", out var arg) &&
                                arg.Expression is TypeOfExpressionSyntax sourceTypeOf &&
                                TypeOf.TryGetType(sourceTypeOf, type, context.SemanticModel, context.CancellationToken, out var argType) &&
                                !Equals(argType, sourceType))
                            {
                                context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0072ValueConversionMustUseCorrectTypes, arg.GetLocation(), sourceType));
                            }

                            if (attribute.TryFindArgument(1, "targetType", out arg) &&
                                arg.Expression is TypeOfExpressionSyntax targetTypeOf &&
                                TypeOf.TryGetType(targetTypeOf, type, context.SemanticModel, context.CancellationToken, out argType) &&
                                !Equals(argType, targetType))
                            {
                                context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0072ValueConversionMustUseCorrectTypes, arg.GetLocation(), targetType));
                            }
                        }
                    }
                    else
                    {
                        if (ValueConverter.TryGetConversionTypes(classDeclaration, context.SemanticModel, context.CancellationToken, out _, out _))
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0071ConverterDoesNotHaveAttribute, classDeclaration.Identifier.GetLocation()));
                        }
                        else
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptors.WPF0073ConverterDoesNotHaveAttributeUnknownTypes, classDeclaration.Identifier.GetLocation()));
                        }
                    }
                }
            }
        }
        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()));
                    }
                }