示例#1
0
        private static bool UsesValueAndMember(IfStatementSyntax ifStatement, SemanticModel semanticModel, CancellationToken cancellationToken, IParameterSymbol value, ISymbol member)
        {
            var usesValue  = false;
            var usesMember = false;

            using (var pooledIdentifierNames = IdentifierNameWalker.Create(ifStatement.Condition))
            {
                foreach (var identifierName in pooledIdentifierNames.Item.IdentifierNames)
                {
                    var symbol = semanticModel.GetSymbolSafe(identifierName, cancellationToken);
                    if (symbol == null)
                    {
                        continue;
                    }

                    if (symbol.Equals(value))
                    {
                        usesValue = true;
                    }

                    if (symbol.Equals(member))
                    {
                        usesMember = true;
                    }
                }
            }

            return(usesMember && usesValue);
        }
        /// <inheritdoc/>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                             .ConfigureAwait(false);

            var semanticModel = await context.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) ||
                    token.IsMissing)
                {
                    continue;
                }

                var ctor       = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf <ConstructorDeclarationSyntax>();
                var invocation = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf <InvocationExpressionSyntax>();

                if (ctor != null &&
                    invocation != null &&
                    invocation.Expression is MemberAccessExpressionSyntax memberAccess)
                {
                    var condition = memberAccess.Expression;
                    var symbol    = semanticModel.GetSymbolSafe(condition, context.CancellationToken);
                    if (symbol is IParameterSymbol parameter)
                    {
                        using (var pooled = IdentifierNameWalker.Create(ctor))
                        {
                            foreach (var name in pooled.Item.IdentifierNames)
                            {
                                if (name.Identifier.ValueText == parameter.Name)
                                {
                                    if (!condition.Contains(name))
                                    {
                                        return;
                                    }
                                }
                            }
                        }

                        if (ctor.ParameterList.Parameters.TryGetFirst(p => p.Identifier.ValueText == parameter.Name, out ParameterSyntax parameterSyntax))
                        {
                            context.RegisterCodeFix(
                                CodeAction.Create(
                                    "Inject negated.",
                                    cancellationToken => ApplyInjectNegatedFixAsync(cancellationToken, context, parameterSyntax, invocation),
                                    nameof(InjectNegatedCodeFix)),
                                diagnostic);
                            continue;
                        }
                    }
                }
            }
        }
        /// <inheritdoc/>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                             .ConfigureAwait(false);

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

                var assignment = syntaxRoot.FindNode(diagnostic.Location.SourceSpan)
                                 .FirstAncestorOrSelf <AssignmentExpressionSyntax>();
                if (assignment == null ||
                    assignment.Left == null ||
                    assignment.Right == null)
                {
                    continue;
                }

                if (assignment.Right is ParenthesizedLambdaExpressionSyntax lambda &&
                    lambda.Body != null)
                {
                    using (var pooled = IdentifierNameWalker.Create(lambda.Body))
                    {
                        var usesArg = false;
                        foreach (var name in pooled.Item.IdentifierNames)
                        {
                            if (name.Identifier.ValueText == lambda.ParameterList.Parameters[0]
                                .Identifier.ValueText)
                            {
                                return;
                            }

                            if (name.Identifier.ValueText == lambda.ParameterList.Parameters[1]
                                .Identifier.ValueText)
                            {
                                usesArg = true;
                            }
                        }

                        context.RegisterCodeFix(
                            CodeAction.Create(
                                "Observe.Event",
                                cancellationToken => ApplyObserveEventLamdaFixAsync(
                                    cancellationToken, context, assignment, usesArg),
                                nameof(EventSubscriptionToObserveFix)),
                            diagnostic);
                    }
                }

                if (assignment.Right is MemberAccessExpressionSyntax memberAccess)
                {
                    var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

                    if (semanticModel.GetSymbolSafe(memberAccess, context.CancellationToken) is IMethodSymbol method &&
                        method.DeclaredAccessibility == Accessibility.Private &&
                        method.DeclaringSyntaxReferences.Length == 1)
                    {
                        var methodDeclaration = (MethodDeclarationSyntax)method.DeclaringSyntaxReferences[0].GetSyntax(context.CancellationToken);
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                "Observe.Event",
                                cancellationToken => ApplyObserveEventMethodFixAsync(cancellationToken, context, assignment, methodDeclaration),
                                nameof(EventSubscriptionToObserveFix)),
                            diagnostic);
                    }
                }
            }
        }
        private static async Task <Document> ApplyObserveEventMethodFixAsync(
            CancellationToken cancellationToken,
            CodeFixContext context,
            AssignmentExpressionSyntax assignment,
            MethodDeclarationSyntax methodDeclaration)
        {
            var usesArg = false;

            if (methodDeclaration.ParameterList.Parameters.Any())
            {
                using (var pooled = IdentifierNameWalker.Create((SyntaxNode)methodDeclaration.Body ?? methodDeclaration.ExpressionBody))
                {
                    foreach (var name in pooled.Item.IdentifierNames)
                    {
                        if (name.Identifier.ValueText == methodDeclaration.ParameterList.Parameters[0].Identifier.ValueText)
                        {
                            if (methodDeclaration.ParameterList.Parameters.Count == 1)
                            {
                                usesArg = true;
                                continue;
                            }

                            return(context.Document);
                        }

                        if (methodDeclaration.ParameterList.Parameters.Count == 2 &&
                            name.Identifier.ValueText == methodDeclaration.ParameterList.Parameters[1]
                            .Identifier.ValueText)
                        {
                            usesArg = true;
                        }
                    }
                }
            }

            var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken)
                         .ConfigureAwait(false);

            var eventSymbol      = (IEventSymbol)editor.SemanticModel.GetSymbolSafe(assignment.Left, cancellationToken);
            var observeSubscribe = GetObservableFromEventString(eventSymbol)
                                   .Replace("HANDLERTYPE", eventSymbol.Type.ToDisplayString())
                                   .Replace("ARGTYPE", ArgType(eventSymbol))
                                   .Replace("LEFT", assignment.Left.ToString())
                                   .Replace("LAMBDA", Lambda(methodDeclaration, usesArg));

            editor.ReplaceNode(
                assignment,
                SyntaxFactory.ParseExpression(observeSubscribe)
                .WithLeadingTrivia(assignment.GetLeadingTrivia())
                .WithAdditionalAnnotations(Simplifier.Annotation));
            if (methodDeclaration.ParameterList.Parameters.Count == 2)
            {
                editor.RemoveNode(methodDeclaration.ParameterList.Parameters[0]);
            }

            if (!usesArg &&
                methodDeclaration.ParameterList.Parameters.Any())
            {
                editor.RemoveNode(methodDeclaration.ParameterList.Parameters.Last());
            }

            return(editor.GetChangedDocument());
        }
        private static void HandleAssignment(SyntaxNodeAnalysisContext context)
        {
            var assignment = (AssignmentExpressionSyntax)context.Node;

            if (assignment?.IsMissing != false ||
                assignment.FirstAncestorOrSelf <ConstructorDeclarationSyntax>() != null ||
                assignment.FirstAncestorOrSelf <InitializerExpressionSyntax>() != null)
            {
                return;
            }

            var block = assignment.FirstAncestorOrSelf <BlockSyntax>();

            if (block == null)
            {
                return;
            }

            var typeDeclaration = assignment.FirstAncestorOrSelf <TypeDeclarationSyntax>();
            var typeSymbol      = context.SemanticModel.GetDeclaredSymbolSafe(typeDeclaration, context.CancellationToken);

            if (!typeSymbol.Is(KnownSymbol.INotifyPropertyChanged))
            {
                return;
            }

            var field = context.SemanticModel.GetSymbolSafe(assignment.Left, context.CancellationToken) as IFieldSymbol;

            if (field == null || !typeSymbol.Equals(field.ContainingType))
            {
                return;
            }

            foreach (var member in typeDeclaration.Members)
            {
                var propertyDeclaration = member as PropertyDeclarationSyntax;
                if (propertyDeclaration == null)
                {
                    continue;
                }

                var property = context.SemanticModel.GetDeclaredSymbolSafe(propertyDeclaration, context.CancellationToken);
                var getter   = Getter(propertyDeclaration);
                if (getter == null || property == null || property.DeclaredAccessibility != Accessibility.Public)
                {
                    continue;
                }

                using (var pooled = IdentifierNameWalker.Create(getter))
                {
                    foreach (var identifierName in pooled.Item.IdentifierNames)
                    {
                        var component      = context.SemanticModel.GetSymbolSafe(identifierName, context.CancellationToken);
                        var componentField = component as IFieldSymbol;
                        if (componentField == null)
                        {
                            var propertySymbol = component as IPropertySymbol;
                            if (propertySymbol == null)
                            {
                                continue;
                            }

                            if (!Property.TryGetBackingField(propertySymbol, context.SemanticModel, context.CancellationToken, out componentField))
                            {
                                continue;
                            }
                        }

                        if (!field.Equals(componentField))
                        {
                            continue;
                        }

                        if (PropertyChanged.InvokesPropertyChangedFor(assignment, property, context.SemanticModel, context.CancellationToken) == PropertyChanged.InvokesPropertyChanged.No)
                        {
                            var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>(PropertyNameKey, property.Name), });
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, assignment.GetLocation(), properties, property.Name));
                        }
                    }
                }
            }
        }