public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                       .ConfigureAwait(false);

            Diagnostic diagnostic     = context.Diagnostics.First();
            TextSpan   diagnosticSpan = diagnostic.Location.SourceSpan;

            var argumentListNode = root.FindNode(diagnosticSpan)
                                   .Ancestors()
                                   .OfType <ArgumentListSyntax>()
                                   .FirstOrDefault();

            var firstParameterIdentifier = argumentListNode.Arguments
                                           .First()
                                           .Expression as IdentifierNameSyntax;

            string firstParameterName = firstParameterIdentifier.Identifier.ValueText;
            string fixTitle           = $"Change second argument to {firstParameterName}";

            context.RegisterCodeFix(
                diagnostic: diagnostic,
                action: CodeAction.Create(
                    title: fixTitle,
                    equivalenceKey: fixTitle,
                    createChangedDocument: cancellationToken =>
                    AnalyzerHelpers.ChangeArgumentAsync(
                        context.Document,
                        argumentListNode,
                        firstParameterName,
                        cancellationToken)));
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                       .ConfigureAwait(false);

            Diagnostic diagnostic     = context.Diagnostics.First();
            TextSpan   diagnosticSpan = diagnostic.Location.SourceSpan;

            // Find the method that contains the EnsureArg call.
            var containingMethod = root.FindNode(diagnosticSpan)
                                   .Ancestors()
                                   .OfType <MemberDeclarationSyntax>()
                                   .FirstOrDefault();

            if (containingMethod == null)
            {
                return;
            }

            var argumentListNode = root.FindNode(diagnosticSpan)
                                   .Ancestors()
                                   .OfType <ArgumentListSyntax>()
                                   .FirstOrDefault();

            var methodParameters = AnalyzerHelpers.GetParameters(containingMethod);

            foreach (string parameterName in methodParameters)
            {
                string fixTitle = $"Change first argument to {parameterName}";

                context.RegisterCodeFix(
                    diagnostic: diagnostic,
                    action: CodeAction.Create(
                        title: fixTitle,
                        equivalenceKey: fixTitle,
                        createChangedDocument: cancellationToken =>
                        AnalyzerHelpers.ChangeArgumentAsync(
                            context.Document,
                            argumentListNode,
                            parameterName,
                            cancellationToken)));
            }
        }
Example #3
0
        private void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            if (!context.Node.IsKind(SyntaxKind.InvocationExpression))
            {
                return;
            }

            var invocationExpr = context.Node as InvocationExpressionSyntax;

            if (!IsNodeEnsureArgCall(context, invocationExpr))
            {
                return;
            }

            var argumentList = invocationExpr.ArgumentList as ArgumentListSyntax;

            if ((argumentList?.Arguments.Count ?? 0) < 1)
            {
                return;
            }

            var firstArgumentNameSyntax = argumentList.Arguments[0].Expression as IdentifierNameSyntax;

            if (firstArgumentNameSyntax == null)
            {
                return;
            }

            var methodDeclaration = context.Node
                                    .Ancestors()
                                    .OfType <MemberDeclarationSyntax>()
                                    .FirstOrDefault();

            string firstArgumentName = firstArgumentNameSyntax.Identifier.ValueText;

            if (methodDeclaration != null)
            {
                var methodParameters = AnalyzerHelpers.GetParameters(methodDeclaration);

                if (!methodParameters.Contains(firstArgumentName))
                {
                    var diagnostic =
                        Diagnostic.Create(
                            Rule1,
                            firstArgumentNameSyntax.GetLocation(),
                            firstArgumentName,
                            GetMethodName(methodDeclaration));

                    context.ReportDiagnostic(diagnostic);
                }
            }

            if (argumentList.Arguments.Count >= 2)
            {
                ExpressionSyntax secondArgument      = argumentList.Arguments[1].Expression;
                string           secondParameterText = null;
                Location         diagnosticLocation  = null;

                // String Literal e.g. Ensure.Arg(a, "b");
                if (secondArgument.IsKind(SyntaxKind.StringLiteralExpression))
                {
                    var stringLiteral = secondArgument as LiteralExpressionSyntax;

                    secondParameterText = stringLiteral.Token.ValueText;
                    diagnosticLocation  = stringLiteral.GetLocation();

                    if (secondParameterText == firstArgumentName)
                    {
                        var diagnostic =
                            Diagnostic.Create(
                                Rule3,
                                diagnosticLocation,
                                secondParameterText);

                        context.ReportDiagnostic(diagnostic);
                    }
                }

                // Detect if using nameof operator e.g. Ensure.Arg(a, nameof(b));
                if (secondArgument.IsKind(SyntaxKind.InvocationExpression))
                {
                    var invocationExpression = secondArgument as InvocationExpressionSyntax;

                    var nameOfIdentifier = invocationExpression.ChildNodes().FirstOrDefault() as IdentifierNameSyntax;

                    if (nameOfIdentifier.Identifier.ValueText == "nameof")
                    {
                        // Definitely nameof operater, keep digging to get to the identifier argument.
                        var nameOfIdentifierArgument = invocationExpression.DescendantNodes()
                                                       .OfType <ArgumentListSyntax>()
                                                       .FirstOrDefault()
                                                       ?.Arguments
                                                       .FirstOrDefault()
                                                       ?.Expression as IdentifierNameSyntax;

                        secondParameterText = nameOfIdentifierArgument?.Identifier.ValueText;
                        diagnosticLocation  = invocationExpression.GetLocation();
                    }
                }

                if (secondParameterText != firstArgumentName)
                {
                    var diagnostic =
                        Diagnostic.Create(
                            Rule2,
                            diagnosticLocation,
                            secondParameterText,
                            firstArgumentName);

                    context.ReportDiagnostic(diagnostic);
                }
            }

            var methodIdentifier = invocationExpr.Parent
                                   .ChildNodes()
                                   .OfType <IdentifierNameSyntax>()
                                   .FirstOrDefault();

            if (methodIdentifier == null)
            {
                var diagnostic = Diagnostic.Create(
                    Rule4,
                    invocationExpr.GetLocation());

                context.ReportDiagnostic(diagnostic);
            }
        }