示例#1
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out ArgumentSyntax argument))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.OptimizeStringBuilderAppendCall:
                {
                    MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo((InvocationExpressionSyntax)argument.Parent.Parent);

                    CodeAction codeAction = CodeAction.Create(
                        $"Optimize '{invocationInfo.NameText}' call",
                        cancellationToken => OptimizeStringBuilderAppendCallRefactoring.RefactorAsync(context.Document, argument, invocationInfo, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public static void Analyze(SyntaxNodeAnalysisContext context, MemberInvocationExpressionInfo invocationInfo)
        {
            ExpressionSyntax expression = invocationInfo.InvocationExpression.WalkUpParentheses();

            SyntaxNode parent = expression.Parent;

            SyntaxKind kind = parent.Kind();

            if (kind == SyntaxKind.SimpleMemberAccessExpression)
            {
                MemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.MemberInvocationExpressionInfo(parent.Parent);

                if (!invocationInfo2.Success)
                {
                    return;
                }

                Analyze(context, invocationInfo, invocationInfo2);
            }
            else if (kind == SyntaxKind.Argument)
            {
                Analyze(context, invocationInfo, (ArgumentSyntax)parent);
            }
            else if (kind == SyntaxKind.EqualsExpression ||
                     kind == SyntaxKind.NotEqualsExpression)
            {
                Analyze(context, invocationInfo, expression, (BinaryExpressionSyntax)parent);
            }
        }
        public static void Analyze(SyntaxNodeAnalysisContext context, MemberInvocationExpressionInfo invocationInfo)
        {
            ExpressionSyntax expression = invocationInfo.Expression;

            if (expression.IsKind(SyntaxKind.InvocationExpression))
            {
                MemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.MemberInvocationExpressionInfo((InvocationExpressionSyntax)expression);

                if (invocationInfo2.Success)
                {
                    switch (invocationInfo2.NameText)
                    {
                    case "OrderBy":
                    case "OrderByDescending":
                    {
                        if (IsLinqExtensionOfIEnumerableOfT(context, invocationInfo.InvocationExpression) &&
                            IsLinqExtensionOfIEnumerableOfT(context, invocationInfo2.InvocationExpression))
                        {
                            context.ReportDiagnostic(
                                DiagnosticDescriptors.CallThenByInsteadOfOrderBy,
                                invocationInfo.Name,
                                (invocationInfo.NameText == "OrderByDescending") ? "Descending" : null);
                        }

                        break;
                    }
                    }
                }
            }
        }
        public static async Task <Document> RefactorAsync(
            Document document,
            InvocationExpressionSyntax invocationExpression,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            MemberDeclarationSyntax memberDeclaration = invocationExpression.FirstAncestor <MemberDeclarationSyntax>();

            Debug.Assert(memberDeclaration != null, "");

            if (memberDeclaration != null)
            {
                BaseTypeDeclarationSyntax typeDeclaration = memberDeclaration.FirstAncestor <BaseTypeDeclarationSyntax>();

                Debug.Assert(typeDeclaration != null, "");

                if (typeDeclaration != null)
                {
                    MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocationExpression);

                    string fieldName = NameGenerator.Default.EnsureUniqueLocalName("_regex", semanticModel, invocationExpression.SpanStart, cancellationToken: cancellationToken);

                    MemberAccessExpressionSyntax newMemberAccess = invocationInfo.MemberAccessExpression.WithExpression(IdentifierName(Identifier(fieldName).WithRenameAnnotation()));

                    ArgumentListPair pair = RewriteArgumentLists(invocationInfo.ArgumentList, semanticModel, cancellationToken);

                    InvocationExpressionSyntax newInvocationExpression = invocationExpression
                                                                         .WithExpression(newMemberAccess)
                                                                         .WithArgumentList(pair.ArgumentList1);

                    MemberDeclarationSyntax newTypeDeclaration = typeDeclaration.ReplaceNode(invocationExpression, newInvocationExpression);

                    TypeSyntax regexType = semanticModel.GetTypeByMetadataName(MetadataNames.System_Text_RegularExpressions_Regex).ToMinimalTypeSyntax(semanticModel, typeDeclaration.SpanStart);

                    FieldDeclarationSyntax fieldDeclaration = FieldDeclaration(
                        (ShouldBeStatic(memberDeclaration, semanticModel, cancellationToken))
                            ? Modifiers.PrivateStaticReadOnly()
                            : Modifiers.PrivateReadOnly(),
                        regexType,
                        Identifier(fieldName),
                        EqualsValueClause(
                            ObjectCreationExpression(regexType, pair.ArgumentList2)));

                    SyntaxList <MemberDeclarationSyntax> newMembers = newTypeDeclaration
                                                                      .GetMembers()
                                                                      .InsertMember(fieldDeclaration, MemberDeclarationComparer.ByKind);

                    newTypeDeclaration = newTypeDeclaration.WithMembers(newMembers);

                    return(await document.ReplaceNodeAsync(typeDeclaration, newTypeDeclaration, cancellationToken).ConfigureAwait(false));
                }
            }

            return(document);
        }
示例#5
0
        private static bool IsFixable(InvocationExpressionSyntax invocationExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocationExpression);

            if (!invocationInfo.Success)
            {
                return(false);
            }

            if (!semanticModel.TryGetMethodInfo(invocationInfo.InvocationExpression, out MethodInfo methodInfo, cancellationToken))
            {
                return(false);
            }

            if (!methodInfo.IsContainingType(SpecialType.System_String))
            {
                return(false);
            }

            if (!methodInfo.IsReturnType(SpecialType.System_String))
            {
                return(false);
            }

            switch (methodInfo.Name)
            {
            case "Substring":
            {
                if (methodInfo.HasParameters(SpecialType.System_Int32, SpecialType.System_Int32))
                {
                    return(true);
                }

                break;
            }

            case "Remove":
            {
                if (methodInfo.HasParameter(SpecialType.System_Int32))
                {
                    return(true);
                }

                break;
            }

            case "Format":
            {
                return(true);
            }
            }

            return(false);
        }
        private string GetTextToAppend(ExpressionStatementSyntax expressionStatement)
        {
            MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(GetInvocationExpression(expressionStatement));

            MemberInvocationExpressionInfo firstMemberInvocation = WalkDownMethodChain(invocationInfo);

            InvocationExpressionSyntax invocationExpression = invocationInfo.InvocationExpression;

            return(invocationExpression
                   .ToString()
                   .Substring(firstMemberInvocation.OperatorToken.SpanStart - invocationExpression.SpanStart));
        }
示例#7
0
        internal static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocationExpression = (InvocationExpressionSyntax)context.Node;

            if (!invocationExpression.ContainsDiagnostics &&
                !invocationExpression.SpanContainsDirectives())
            {
                MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocationExpression);
                if (invocationInfo.Success &&
                    invocationInfo.NameText == "Any")
                {
                    ArgumentSyntax argument1 = invocationInfo.Arguments.SingleOrDefault(shouldthrow: false);

                    if (argument1 != null)
                    {
                        MemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.MemberInvocationExpressionInfo(invocationInfo.Expression);
                        if (invocationInfo2.Success &&
                            invocationInfo2.NameText == "Where")
                        {
                            ArgumentSyntax argument2 = invocationInfo2.Arguments.SingleOrDefault(shouldthrow: false);

                            if (argument2 != null)
                            {
                                SemanticModel     semanticModel     = context.SemanticModel;
                                CancellationToken cancellationToken = context.CancellationToken;

                                if (semanticModel.TryGetExtensionMethodInfo(invocationExpression, out MethodInfo methodInfo, ExtensionMethodKind.None, cancellationToken) &&
                                    methodInfo.IsLinqExtensionOfIEnumerableOfTWithPredicate("Any") &&
                                    semanticModel.TryGetExtensionMethodInfo(invocationInfo2.InvocationExpression, out MethodInfo methodInfo2, ExtensionMethodKind.None, cancellationToken) &&
                                    methodInfo2.IsLinqWhere(allowImmutableArrayExtension: true))
                                {
                                    SingleParameterLambdaExpressionInfo lambda = SyntaxInfo.SingleParameterLambdaExpressionInfo(argument1.Expression);
                                    if (lambda.Success &&
                                        lambda.Body is ExpressionSyntax)
                                    {
                                        SingleParameterLambdaExpressionInfo lambda2 = SyntaxInfo.SingleParameterLambdaExpressionInfo(argument2.Expression);
                                        if (lambda2.Success &&
                                            lambda2.Body is ExpressionSyntax &&
                                            lambda.ParameterName.Equals(lambda2.ParameterName, StringComparison.Ordinal))
                                        {
                                            context.ReportDiagnostic(
                                                DiagnosticDescriptors.SimplifyLinqMethodChain,
                                                Location.Create(context.SyntaxTree(), TextSpan.FromBounds(invocationInfo2.Name.SpanStart, invocationExpression.Span.End)));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        protected static MemberInvocationExpressionInfo WalkDownMethodChain(MemberInvocationExpressionInfo invocationInfo)
        {
            while (true)
            {
                MemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.MemberInvocationExpressionInfo(invocationInfo.Expression);

                if (invocationInfo2.Success)
                {
                    invocationInfo = invocationInfo2;
                }
                else
                {
                    break;
                }
            }

            return(invocationInfo);
        }
        private static bool TryCreateCaseChangingInvocation(ExpressionSyntax expression, out MemberInvocationExpressionInfo invocationInfo)
        {
            invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(expression);

            if (invocationInfo.Success &&
                !invocationInfo.Arguments.Any())
            {
                string name = invocationInfo.NameText;

                return(name == "ToLower" ||
                       name == "ToLowerInvariant" ||
                       name == "ToUpper" ||
                       name == "ToUpperInvariant");
            }

            invocationInfo = default(MemberInvocationExpressionInfo);
            return(false);
        }
        private static void Analyze(
            SyntaxNodeAnalysisContext context,
            MemberInvocationExpressionInfo invocationInfo,
            ArgumentSyntax argument)
        {
            if (!(argument.Parent is ArgumentListSyntax argumentList))
            {
                return;
            }

            SeparatedSyntaxList <ArgumentSyntax> arguments = argumentList.Arguments;

            if (arguments.Count != 2)
            {
                return;
            }

            MemberInvocationExpressionInfo equalsInvocation = SyntaxInfo.MemberInvocationExpressionInfo(argumentList.Parent);

            if (!equalsInvocation.Success)
            {
                return;
            }

            if (equalsInvocation.NameText != "Equals")
            {
                return;
            }

            if (!IsFixable(context, invocationInfo, argument, arguments))
            {
                return;
            }

            if (!context.SemanticModel.TryGetMethodInfo(equalsInvocation.InvocationExpression, out MethodInfo info, context.CancellationToken) ||
                !info.IsPublicStaticStringMethod("Equals") ||
                !info.ReturnsBoolean ||
                !info.HasParameters(SpecialType.System_String, SpecialType.System_String))
            {
                return;
            }

            ReportDiagnostic(context, equalsInvocation);
        }
        protected override bool IsFixableStatement(
            StatementSyntax statement,
            string name,
            ITypeSymbol typeSymbol,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if (statement.SpanOrLeadingTriviaContainsDirectives())
            {
                return(false);
            }

            if (!(statement is ExpressionStatementSyntax expressionStatement))
            {
                return(false);
            }

            MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(expressionStatement.Expression);

            if (!invocationInfo.Success)
            {
                return(false);
            }

            if (!(WalkDownMethodChain(invocationInfo).Expression is IdentifierNameSyntax identifierName))
            {
                return(false);
            }

            if (name != identifierName.Identifier.ValueText)
            {
                return(false);
            }

            if (!semanticModel.TryGetMethodInfo(invocationInfo.InvocationExpression, out MethodInfo methodInfo, cancellationToken))
            {
                return(false);
            }

            return(!methodInfo.IsStatic &&
                   methodInfo.ContainingType?.Equals(typeSymbol) == true &&
                   methodInfo.ReturnType.Equals(typeSymbol));
        }
        private static InvocationExpressionSyntax CreateInvocationExpression(
            InvocationExpressionSyntax innerInvocationExpression,
            InvocationExpressionSyntax outerInvocationExpression)
        {
            MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(innerInvocationExpression);

            switch (invocationInfo.NameText)
            {
            case "Substring":
            {
                SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments;

                ArgumentListSyntax argumentList = ArgumentList(
                    Argument(invocationInfo.Expression),
                    arguments[0],
                    arguments[1]
                    );

                return(CreateNewInvocationExpression(outerInvocationExpression, "Append", argumentList));
            }

            case "Remove":
            {
                SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments;

                ArgumentListSyntax argumentList = ArgumentList(
                    Argument(invocationInfo.Expression),
                    Argument(NumericLiteralExpression(0)),
                    arguments[0]
                    );

                return(CreateNewInvocationExpression(outerInvocationExpression, "Append", argumentList));
            }

            case "Format":
            {
                return(CreateNewInvocationExpression(outerInvocationExpression, "AppendFormat", invocationInfo.ArgumentList));
            }
            }

            Debug.Fail(innerInvocationExpression.ToString());
            return(outerInvocationExpression);
        }
示例#13
0
        public static Task <Document> RefactorAsync(
            Document document,
            MemberInvocationExpressionInfo invocationInfo,
            CancellationToken cancellationToken)
        {
            MemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.MemberInvocationExpressionInfo(invocationInfo.Expression);

            SyntaxTriviaList trivia = invocationInfo2.InvocationExpression
                                      .GetTrailingTrivia()
                                      .EmptyIfWhitespace()
                                      .AddRange(invocationInfo.InvocationExpression.GetTrailingTrivia());

            InvocationExpressionSyntax newNode = invocationInfo2
                                                 .WithName("AppendLine")
                                                 .InvocationExpression
                                                 .WithTrailingTrivia(trivia);

            return(document.ReplaceNodeAsync(invocationInfo.InvocationExpression, newNode, cancellationToken));
        }
示例#14
0
        public static Task <Document> RefactorAsync(
            Document document,
            InvocationExpressionSyntax invocationExpression,
            CancellationToken cancellationToken)
        {
            MemberInvocationExpressionInfo invocationInfo  = SyntaxInfo.MemberInvocationExpressionInfo(invocationExpression);
            MemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.MemberInvocationExpressionInfo(invocationInfo.Expression);

            SingleParameterLambdaExpressionInfo lambda  = SyntaxInfo.SingleParameterLambdaExpressionInfo((LambdaExpressionSyntax)invocationInfo.Arguments.First().Expression);
            SingleParameterLambdaExpressionInfo lambda2 = SyntaxInfo.SingleParameterLambdaExpressionInfo((LambdaExpressionSyntax)invocationInfo2.Arguments.First().Expression);

            BinaryExpressionSyntax logicalAnd = CSharpFactory.LogicalAndExpression(
                ((ExpressionSyntax)lambda2.Body).Parenthesize(),
                ((ExpressionSyntax)lambda.Body).Parenthesize());

            InvocationExpressionSyntax newNode = invocationInfo2.InvocationExpression
                                                 .ReplaceNode(invocationInfo2.Name, invocationInfo.Name.WithTriviaFrom(invocationInfo2.Name))
                                                 .WithArgumentList(invocationInfo2.ArgumentList.ReplaceNode((ExpressionSyntax)lambda2.Body, logicalAnd));

            return(document.ReplaceNodeAsync(invocationExpression, newNode, cancellationToken));
        }
示例#15
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    getInnermostNodeForTie: false,
                    predicate: f => f.IsKind(SyntaxKind.Argument, SyntaxKind.InvocationExpression)))
            {
                return;
            }

            Diagnostic diagnostic = context.Diagnostics[0];

            if (node is ArgumentSyntax argument)
            {
                MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo((InvocationExpressionSyntax)argument.Parent.Parent);

                CodeAction codeAction = CodeAction.Create(
                    $"Optimize '{invocationInfo.NameText}' call",
                    cancellationToken => OptimizeStringBuilderAppendCallRefactoring.RefactorAsync(context.Document, argument, invocationInfo, cancellationToken),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
            else if (node is InvocationExpressionSyntax invocationExpression)
            {
                MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocationExpression);

                CodeAction codeAction = CodeAction.Create(
                    $"Optimize '{invocationInfo.NameText}' call",
                    cancellationToken => OptimizeStringBuilderAppendCallRefactoring.RefactorAsync(context.Document, invocationInfo, cancellationToken),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
        }
        private static bool IsConfiguredTaskAwaitableOfT(
            ExpressionSyntax expression,
            INamedTypeSymbol expressionTypeSymbol,
            SemanticModel semanticModel)
        {
            MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(expression);

            if (!invocationInfo.Success)
            {
                return(false);
            }

            if (invocationInfo.Arguments.Count != 1)
            {
                return(false);
            }

            if (invocationInfo.NameText != "ConfigureAwait")
            {
                return(false);
            }

            return(expressionTypeSymbol.ConstructedFrom.Equals(semanticModel.GetTypeByMetadataName(MetadataNames.System_Runtime_CompilerServices_ConfiguredTaskAwaitable_T)));
        }
示例#17
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out InvocationExpressionSyntax invocation))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.SimplifyLinqMethodChain:
                {
                    var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression;

                    string name = memberAccess.Name.Identifier.ValueText;

                    if (name == "Cast")
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Simplify method chain",
                            cancellationToken => CallOfTypeInsteadOfWhereAndCastRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else if (name == "Any" &&
                             invocation.ArgumentList.Arguments.Count == 1)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Simplify method chain",
                            cancellationToken => CombineEnumerableWhereAndAnyRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Simplify method chain",
                            cancellationToken => SimplifyLinqMethodChainRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case DiagnosticIdentifiers.CombineEnumerableWhereMethodChain:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Combine 'Where' method chain",
                        cancellationToken => CombineEnumerableWhereMethodChainRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseCountOrLengthPropertyInsteadOfAnyMethod:
                {
                    string propertyName = diagnostic.Properties["PropertyName"];

                    CodeAction codeAction = CodeAction.Create(
                        $"Use '{propertyName}' property instead of calling 'Any'",
                        cancellationToken => UseCountOrLengthPropertyInsteadOfAnyMethodRefactoring.RefactorAsync(context.Document, invocation, propertyName, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseCountOrLengthPropertyInsteadOfCountMethod:
                {
                    string propertyName = diagnostic.Properties["PropertyName"];

                    CodeAction codeAction = CodeAction.Create(
                        $"Use '{propertyName}' property instead of calling 'Count'",
                        cancellationToken => UseCountOrLengthPropertyInsteadOfCountMethodRefactoring.RefactorAsync(context.Document, invocation, diagnostic.Properties["PropertyName"], cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseBitwiseOperationInsteadOfCallingHasFlag:
                {
                    CodeAction codeAction = CodeAction.Create(
                        UseBitwiseOperationInsteadOfCallingHasFlagRefactoring.Title,
                        cancellationToken => UseBitwiseOperationInsteadOfCallingHasFlagRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantToStringCall:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'ToString' call",
                        cancellationToken => RemoveRedundantCallRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallCastInsteadOfSelect:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Cast' instead of 'Select'",
                        cancellationToken => CallCastInsteadOfSelectRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantStringToCharArrayCall:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'ToCharArray' call",
                        cancellationToken => RemoveRedundantCallRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallFindInsteadOfFirstOrDefault:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Find' instead of 'FirstOrDefault'",
                        cancellationToken => CallFindInsteadOfFirstOrDefaultRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseElementAccessInsteadOfElementAt:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use [] instead of calling 'ElementAt'",
                        cancellationToken => UseElementAccessInsteadOfElementAtRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseElementAccessInsteadOfFirst:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use [] instead of calling 'First'",
                        cancellationToken => UseElementAccessInsteadOfFirstRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallStringConcatInsteadOfStringJoin:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Concat' instead of 'Join'",
                        cancellationToken => CallStringConcatInsteadOfStringJoinRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallDebugFailInsteadOfDebugAssert:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Fail' instead of 'Assert'",
                        cancellationToken => CallDebugFailInsteadOfDebugAssertRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallExtensionMethodAsInstanceMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        CallExtensionMethodAsInstanceMethodRefactoring.Title,
                        cancellationToken => CallExtensionMethodAsInstanceMethodRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallThenByInsteadOfOrderBy:
                {
                    MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocation);

                    string oldName = invocationInfo.NameText;

                    string newName = (string.Equals(oldName, "OrderBy", StringComparison.Ordinal))
                                ? "ThenBy"
                                : "ThenByDescending";

                    CodeAction codeAction = CodeAction.Create(
                        $"Call '{newName}' instead of '{oldName}'",
                        cancellationToken => CallThenByInsteadOfOrderByRefactoring.RefactorAsync(context.Document, invocation, newName, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public async Task <Document> RefactorAsync(
            Document document,
            ExpressionStatementSyntax expressionStatement,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            InvocationExpressionSyntax invocationExpression = GetInvocationExpression(expressionStatement);

            semanticModel.TryGetMethodInfo(invocationExpression, out MethodInfo methodInfo, cancellationToken);

            MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocationExpression);

            ITypeSymbol typeSymbol = methodInfo.ReturnType;

            string name = ((IdentifierNameSyntax)WalkDownMethodChain(invocationInfo).Expression).Identifier.ValueText;

            StatementsInfo statementsInfo = SyntaxInfo.StatementsInfo(expressionStatement);

            SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

            int index = statements.IndexOf(expressionStatement);

            string indentation = CSharpFormatter.GetIncreasedIndentation(expressionStatement, cancellationToken).ToString();

            var sb = new StringBuilder(invocationExpression.ToString());

            int j = index;

            while (j < statements.Count - 1)
            {
                StatementSyntax statement = statements[j + 1];

                if (!IsFixableStatement(statement, name, typeSymbol, semanticModel, cancellationToken))
                {
                    break;
                }

                sb.AppendLine();
                sb.Append(indentation);
                sb.Append(GetTextToAppend((ExpressionStatementSyntax)statement));

                j++;
            }

            StatementSyntax lastStatement = statements[j];

            SyntaxList <StatementSyntax> newStatements = statements;

            while (j > index)
            {
                newStatements = newStatements.RemoveAt(j);
                j--;
            }

            ExpressionSyntax newInvocationExpression = SyntaxFactory.ParseExpression(sb.ToString());

            SyntaxTriviaList trailingTrivia = statementsInfo
                                              .Node
                                              .DescendantTrivia(TextSpan.FromBounds(invocationExpression.Span.End, lastStatement.Span.End))
                                              .ToSyntaxTriviaList()
                                              .EmptyIfWhitespace()
                                              .AddRange(lastStatement.GetTrailingTrivia());

            ExpressionStatementSyntax newExpressionStatement = expressionStatement
                                                               .ReplaceNode(invocationExpression, newInvocationExpression)
                                                               .WithLeadingTrivia(expressionStatement.GetLeadingTrivia())
                                                               .WithTrailingTrivia(trailingTrivia)
                                                               .WithFormatterAndSimplifierAnnotations();

            newStatements = newStatements.ReplaceAt(index, newExpressionStatement);

            return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false));
        }
示例#19
0
        private void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocation = (InvocationExpressionSyntax)context.Node;

            ExpressionSyntax expression = invocation.Expression;

            if (expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true)
            {
                var memberAccess = (MemberAccessExpressionSyntax)expression;

                ArgumentListSyntax argumentList = invocation.ArgumentList;

                if (argumentList?.IsMissing == false)
                {
                    int argumentCount = argumentList.Arguments.Count;

                    string methodName = memberAccess.Name?.Identifier.ValueText;

                    if (argumentCount == 0)
                    {
                        switch (methodName)
                        {
                        case "Any":
                        {
                            SimplifyLinqMethodChainRefactoring.Analyze(context, invocation, memberAccess, methodName);
                            break;
                        }

                        case "Cast":
                        {
                            CallOfTypeInsteadOfWhereAndCastRefactoring.Analyze(context, invocation);
                            break;
                        }

                        case "Count":
                        case "First":
                        case "FirstOrDefault":
                        case "Last":
                        case "LastOrDefault":
                        case "LongCount":
                        case "Single":
                        case "SingleOrDefault":
                        {
                            SimplifyLinqMethodChainRefactoring.Analyze(context, invocation, memberAccess, methodName);
                            break;
                        }
                        }
                    }
                    else if (argumentCount == 1)
                    {
                        switch (methodName)
                        {
                        case "FirstOrDefault":
                        {
                            CallFindInsteadOfFirstOrDefaultRefactoring.Analyze(context, invocation, memberAccess);
                            break;
                        }

                        case "Where":
                        {
                            CombineEnumerableWhereMethodChainRefactoring.Analyze(context, invocation, memberAccess);
                            break;
                        }
                        }
                    }
                }
            }

            if (UseBitwiseOperationInsteadOfCallingHasFlagRefactoring.CanRefactor(invocation, context.SemanticModel, context.CancellationToken) &&
                !invocation.SpanContainsDirectives())
            {
                context.ReportDiagnostic(DiagnosticDescriptors.UseBitwiseOperationInsteadOfCallingHasFlag, invocation);
            }

            RemoveRedundantStringToCharArrayCallRefactoring.Analyze(context, invocation);

            CombineEnumerableWhereAndAnyRefactoring.AnalyzeInvocationExpression(context);

            if (!invocation.ContainsDiagnostics)
            {
                if (!invocation.SpanContainsDirectives())
                {
                    CallExtensionMethodAsInstanceMethodAnalysis analysis = CallExtensionMethodAsInstanceMethodRefactoring.Analyze(invocation, context.SemanticModel, allowAnyExpression: false, cancellationToken: context.CancellationToken);

                    if (analysis.Success &&
                        context.SemanticModel
                        .GetEnclosingNamedType(analysis.InvocationExpression.SpanStart, context.CancellationToken)?
                        .Equals(analysis.MethodSymbol.ContainingType) == false)
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.CallExtensionMethodAsInstanceMethod, invocation);
                    }
                }

                MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocation);

                if (invocationInfo.Success)
                {
                    if (!invocation.SpanContainsDirectives())
                    {
                        UseRegexInstanceInsteadOfStaticMethodRefactoring.Analyze(context, invocationInfo);
                    }

                    string methodName = invocationInfo.NameText;

                    AvoidNullReferenceExceptionRefactoring.Analyze(context, invocationInfo);

                    int argumentCount = invocationInfo.Arguments.Count;

                    switch (argumentCount)
                    {
                    case 0:
                        {
                            switch (methodName)
                            {
                            case "Any":
                            {
                                UseCountOrLengthPropertyInsteadOfAnyMethodRefactoring.Analyze(context, invocationInfo);
                                break;
                            }

                            case "Cast":
                            {
                                RemoveRedundantCastRefactoring.Analyze(context, invocationInfo);
                                break;
                            }

                            case "Count":
                            {
                                UseInsteadOfCountMethodRefactoring.Analyze(context, invocationInfo);
                                break;
                            }

                            case "First":
                            {
                                if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) &&
                                    UseElementAccessInsteadOfFirstRefactoring.CanRefactor(invocationInfo, context.SemanticModel, context.CancellationToken))
                                {
                                    context.ReportDiagnostic(DiagnosticDescriptors.UseElementAccessInsteadOfFirst, invocationInfo.Name);
                                }

                                break;
                            }

                            case "ToString":
                            {
                                RemoveRedundantToStringCallRefactoring.Analyze(context, invocationInfo);
                                UseNameOfOperatorRefactoring.Analyze(context, invocationInfo);
                                break;
                            }

                            case "ToLower":
                            case "ToLowerInvariant":
                            case "ToUpper":
                            case "ToUpperInvariant":
                            {
                                UseStringComparisonRefactoring.Analyze(context, invocationInfo);
                                break;
                            }
                            }

                            break;
                        }

                    case 1:
                    {
                        switch (methodName)
                        {
                        case "All":
                        case "Any":
                        {
                            SimplifyLogicalNegationRefactoring.Analyze(context, invocationInfo);
                            break;
                        }

                        case "ElementAt":
                        {
                            if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) &&
                                UseElementAccessInsteadOfElementAtRefactoring.CanRefactor(invocationInfo, context.SemanticModel, context.CancellationToken))
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.UseElementAccessInsteadOfElementAt, invocationInfo.Name);
                            }

                            break;
                        }
                        }

                        break;
                    }
                    }

                    switch (methodName)
                    {
                    case "Append":
                    case "AppendLine":
                    case "AppendFormat":
                    case "Insert":
                    {
                        OptimizeStringBuilderAppendCallRefactoring.Analyze(context, invocationInfo);
                        break;
                    }

                    case "Select":
                    {
                        if (argumentCount == 1 ||
                            argumentCount == 2)
                        {
                            CallCastInsteadOfSelectRefactoring.Analyze(context, invocationInfo);
                        }

                        break;
                    }

                    case "OrderBy":
                    case "OrderByDescending":
                    {
                        if (argumentCount == 1 ||
                            argumentCount == 2 ||
                            argumentCount == 3)
                        {
                            CallThenByInsteadOfOrderByRefactoring.Analyze(context, invocationInfo);
                        }

                        break;
                    }
                    }

                    if (UseMethodChainingRefactoring.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression);
                    }
                }
            }
        }
示例#20
0
        public static void Analyze(SyntaxNodeAnalysisContext context, MemberInvocationExpressionInfo invocationInfo)
        {
            INamedTypeSymbol stringBuilderSymbol = context.GetTypeByMetadataName(MetadataNames.System_Text_StringBuilder);

            if (stringBuilderSymbol == null)
            {
                return;
            }

            InvocationExpressionSyntax invocationExpression = invocationInfo.InvocationExpression;

            if (!context.SemanticModel.TryGetMethodInfo(invocationExpression, out MethodInfo methodInfo, context.CancellationToken))
            {
                return;
            }

            if (methodInfo.IsExtensionMethod)
            {
                return;
            }

            if (methodInfo.ContainingType?.Equals(stringBuilderSymbol) != true)
            {
                return;
            }

            ImmutableArray <IParameterSymbol> parameters = methodInfo.Parameters;

            int parameterCount = parameters.Length;

            if (parameterCount == 0)
            {
                if (methodInfo.IsName("AppendLine"))
                {
                    MemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.MemberInvocationExpressionInfo(invocationInfo.Expression);

                    if (invocationInfo2.Success &&
                        invocationInfo2.NameText == "Append" &&
                        invocationInfo2.Arguments.Count == 1 &&
                        context.SemanticModel.TryGetMethodInfo(invocationInfo2.InvocationExpression, out MethodInfo methodInfo2, context.CancellationToken) &&
                        !methodInfo2.IsStatic &&
                        methodInfo2.ContainingType?.Equals(stringBuilderSymbol) == true &&
                        methodInfo2.HasParameter(SpecialType.System_String))
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, invocationInfo.Name, methodInfo.Name);
                    }
                }
            }
            else if (parameterCount == 1)
            {
                if (methodInfo.IsName("Append", "AppendLine"))
                {
                    ArgumentSyntax argument = invocationInfo.Arguments.SingleOrDefault(shouldThrow: false);

                    if (argument != null)
                    {
                        ExpressionSyntax expression = argument.Expression;

                        SyntaxKind expressionKind = expression.Kind();

                        switch (expressionKind)
                        {
                        case SyntaxKind.InterpolatedStringExpression:
                        {
                            context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name);
                            return;
                        }

                        case SyntaxKind.AddExpression:
                        {
                            StringConcatenationExpressionInfo concatenationInfo = SyntaxInfo.StringConcatenationExpressionInfo((BinaryExpressionSyntax)expression, context.SemanticModel, context.CancellationToken);
                            if (concatenationInfo.Success)
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name);
                                return;
                            }

                            break;
                        }

                        default:
                        {
                            if (expressionKind == SyntaxKind.InvocationExpression &&
                                IsFixable((InvocationExpressionSyntax)expression, context.SemanticModel, context.CancellationToken))
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodInfo.Name);
                                return;
                            }

                            if (methodInfo.IsName("Append") &&
                                parameterCount == 1 &&
                                parameters[0].Type.IsObject() &&
                                context.SemanticModel.GetTypeSymbol(argument.Expression, context.CancellationToken).IsValueType)
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.AvoidBoxingOfValueType, argument);
                                return;
                            }

                            break;
                        }
                        }
                    }
                }
            }
            else if (parameterCount == 2)
            {
                if (methodInfo.IsName("Insert") &&
                    parameters[0].Type.SpecialType == SpecialType.System_Int32 &&
                    parameters[1].Type.SpecialType == SpecialType.System_Object)
                {
                    SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments;

                    if (arguments.Count == 2 &&
                        context.SemanticModel
                        .GetTypeSymbol(arguments[1].Expression, context.CancellationToken)
                        .IsValueType)
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.AvoidBoxingOfValueType, arguments[1]);
                    }
                }
            }
        }
示例#21
0
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, InvocationExpressionSyntax invocation)
        {
            MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocation);

            if (!invocationInfo.Success)
            {
                return;
            }

            switch (invocationInfo.NameText)
            {
            case "First":
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (invocationInfo.Arguments.Any())
                {
                    break;
                }

                if (!UseElementAccessInsteadOfFirstRefactoring.CanRefactor(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'First'",
                    cancellationToken => UseElementAccessInsteadOfFirstRefactoring.RefactorAsync(context.Document, invocation, cancellationToken));

                break;
            }

            case "Last":
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (invocationInfo.Arguments.Any())
                {
                    break;
                }

                if (!UseElementAccessInsteadOfLastRefactoring.CanRefactor(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                string propertyName = CSharpUtility.GetCountOrLengthPropertyName(invocationInfo.Expression, semanticModel, context.CancellationToken);

                if (propertyName == null)
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'Last'",
                    cancellationToken => UseElementAccessInsteadOfLastRefactoring.RefactorAsync(context.Document, invocation, propertyName, cancellationToken));

                break;
            }

            case "ElementAt":
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (invocationInfo.Arguments.Count != 1)
                {
                    break;
                }

                if (!UseElementAccessInsteadOfElementAtRefactoring.CanRefactor(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'ElementAt'",
                    cancellationToken => UseElementAccessInsteadOfElementAtRefactoring.RefactorAsync(context.Document, invocation, cancellationToken));

                break;
            }
            }
        }
        public static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
        {
            var methodDeclaration = (MethodDeclarationSyntax)context.Node;

            if (methodDeclaration.ContainsDirectives)
            {
                return;
            }

            if (methodDeclaration.ContainsDiagnostics)
            {
                return;
            }

            SyntaxTokenList modifiers = methodDeclaration.Modifiers;

            if (!modifiers.Contains(SyntaxKind.OverrideKeyword))
            {
                return;
            }

            if (modifiers.ContainsAny(SyntaxKind.SealedKeyword, SyntaxKind.PartialKeyword))
            {
                return;
            }

            if (methodDeclaration.AttributeLists.Any())
            {
                return;
            }

            if (methodDeclaration.HasDocumentationComment())
            {
                return;
            }

            if (!methodDeclaration.DescendantTrivia(methodDeclaration.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                return;
            }

            ExpressionSyntax expression = GetMethodExpression(methodDeclaration);

            MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(expression);

            if (!invocationInfo.Success)
            {
                return;
            }

            if (!invocationInfo.Expression.IsKind(SyntaxKind.BaseExpression))
            {
                return;
            }

            IMethodSymbol methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken);

            IMethodSymbol overriddenMethod = methodSymbol?.OverriddenMethod;

            if (overriddenMethod == null)
            {
                return;
            }

            ISymbol symbol = context.SemanticModel.GetSymbol(invocationInfo.Name, context.CancellationToken);

            if (!overriddenMethod.Equals(symbol))
            {
                return;
            }

            if (!CheckParameters(methodDeclaration.ParameterList, invocationInfo.ArgumentList, context.SemanticModel, context.CancellationToken))
            {
                return;
            }

            if (!CheckDefaultValues(methodSymbol.Parameters, overriddenMethod.Parameters))
            {
                return;
            }

            context.ReportDiagnostic(
                DiagnosticDescriptors.RemoveRedundantOverridingMember,
                methodDeclaration,
                methodDeclaration.GetTitle());
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(
                                                SyntaxKind.EqualsExpression,
                                                SyntaxKind.NotEqualsExpression,
                                                SyntaxKind.InvocationExpression)))
            {
                return;
            }

            Diagnostic diagnostic = context.Diagnostics[0];

            switch (node.Kind())
            {
            case SyntaxKind.EqualsExpression:
            case SyntaxKind.NotEqualsExpression:
            {
                var binaryExpression = (BinaryExpressionSyntax)node;

                MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(binaryExpression.Left.WalkDownParentheses());

                if (!invocationInfo.Success)
                {
                    invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo((InvocationExpressionSyntax)binaryExpression.Right.WalkDownParentheses());
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                INamedTypeSymbol comparisonSymbol = semanticModel.GetTypeByMetadataName(MetadataNames.System_StringComparison);

                if (!invocationInfo.NameText.EndsWith("Invariant", StringComparison.Ordinal) ||
                    !RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "InvariantCultureIgnoreCase"))
                {
                    RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "OrdinalIgnoreCase");
                    RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "CurrentCultureIgnoreCase");
                }

                break;
            }

            case SyntaxKind.InvocationExpression:
            {
                var invocationExpression = (InvocationExpressionSyntax)node;

                MemberInvocationExpressionInfo invocationInfo = SyntaxInfo.MemberInvocationExpressionInfo(invocationExpression);

                SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments;

                InvocationExpressionSyntax invocationExpression2;

                if (arguments.Count == 1)
                {
                    invocationExpression2 = (InvocationExpressionSyntax)invocationInfo.Expression;
                }
                else
                {
                    invocationExpression2 = (arguments[0].Expression.WalkDownParentheses() as InvocationExpressionSyntax)
                                            ?? (InvocationExpressionSyntax)arguments[1].Expression.WalkDownParentheses();
                }

                MemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.MemberInvocationExpressionInfo(invocationExpression2);

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                INamedTypeSymbol comparisonSymbol = semanticModel.GetTypeByMetadataName(MetadataNames.System_StringComparison);

                if (!invocationInfo2.NameText.EndsWith("Invariant", StringComparison.Ordinal) ||
                    !RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "InvariantCultureIgnoreCase"))
                {
                    RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "OrdinalIgnoreCase");
                    RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "CurrentCultureIgnoreCase");
                }

                break;
            }
            }
        }
        private static void Analyze(
            SyntaxNodeAnalysisContext context,
            MemberInvocationExpressionInfo invocationInfo,
            MemberInvocationExpressionInfo invocationInfo2)
        {
            if (invocationInfo2.InvocationExpression.SpanContainsDirectives())
            {
                return;
            }

            string name2 = invocationInfo2.NameText;

            if (name2 != "Equals" &&
                name2 != "StartsWith" &&
                name2 != "EndsWith" &&
                name2 != "IndexOf" &&
                name2 != "LastIndexOf" &&
                name2 != "Contains")
            {
                return;
            }

            SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo2.Arguments;

            if (arguments.Count != 1)
            {
                return;
            }

            ExpressionSyntax argumentExpression = arguments[0].Expression.WalkDownParentheses();

            string name = invocationInfo.NameText;

            MemberInvocationExpressionInfo invocationInfo3;

            bool isStringLiteral = argumentExpression.IsKind(SyntaxKind.StringLiteralExpression);

            if (!isStringLiteral)
            {
                invocationInfo3 = SyntaxInfo.MemberInvocationExpressionInfo(argumentExpression);

                if (!invocationInfo3.Success)
                {
                    return;
                }

                string name3 = invocationInfo3.NameText;

                if (name != name3)
                {
                    return;
                }
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            if (!CheckSymbol(invocationInfo, semanticModel, cancellationToken))
            {
                return;
            }

            if (!(semanticModel.TryGetMethodInfo(invocationInfo2.InvocationExpression, out MethodInfo info, cancellationToken) &&
                  info.IsPublicInstanceStringMethod(name2) &&
                  info.ReturnType.SpecialType == ((name2.EndsWith("IndexOf", StringComparison.Ordinal)) ? SpecialType.System_Int32 : SpecialType.System_Boolean) &&
                  info.HasParameter(SpecialType.System_String)))
            {
                return;
            }

            if (!isStringLiteral &&
                !CheckSymbol(invocationInfo3, semanticModel, cancellationToken))
            {
                return;
            }

            ReportDiagnostic(context, invocationInfo2);
        }