Beispiel #1
0
 internal static bool IsLoop(this SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.ForStatement,
                SyntaxKind.ForEachStatement,
                SyntaxKind.WhileStatement,
                SyntaxKind.DoStatement));
 }
Beispiel #2
0
 /// <summary>
 /// Returns true if a syntax of the specified kind if local function or anonymous function.
 /// </summary>
 /// <param name="kind"></param>
 /// <returns></returns>
 public static bool IsFunction(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.SimpleLambdaExpression,
                SyntaxKind.ParenthesizedLambdaExpression,
                SyntaxKind.AnonymousMethodExpression,
                SyntaxKind.LocalFunctionStatement));
 }
Beispiel #3
0
 /// <summary>
 /// Returns true if a syntax of the specified kind is pre/post increment/decrement expression.
 /// </summary>
 /// <param name="kind"></param>
 /// <returns></returns>
 public static bool IsIncrementOrDecrementExpression(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.PreIncrementExpression,
                SyntaxKind.PreDecrementExpression,
                SyntaxKind.PostIncrementExpression,
                SyntaxKind.PostDecrementExpression));
 }
Beispiel #4
0
 /// <summary>
 /// Returns true if a syntax of the specified kind is a constraint.
 /// </summary>
 /// <param name="kind"></param>
 /// <returns></returns>
 public static bool IsConstraint(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.ClassConstraint,
                SyntaxKind.ConstructorConstraint,
                SyntaxKind.StructConstraint,
                SyntaxKind.TypeConstraint));
 }
Beispiel #5
0
 /// <summary>
 /// Returns true if a syntax of the specified kind is comment trivia.
 /// </summary>
 /// <param name="kind"></param>
 /// <returns></returns>
 public static bool IsCommentTrivia(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.SingleLineCommentTrivia,
                SyntaxKind.MultiLineCommentTrivia,
                SyntaxKind.SingleLineDocumentationCommentTrivia,
                SyntaxKind.MultiLineDocumentationCommentTrivia));
 }
 private static bool IsFormattableKind(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.LogicalAndExpression,
                SyntaxKind.LogicalOrExpression,
                SyntaxKind.BitwiseAndExpression,
                SyntaxKind.BitwiseOrExpression));
 }
Beispiel #7
0
 internal static bool IsNestedMethod(this SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.SimpleLambdaExpression,
                SyntaxKind.ParenthesizedLambdaExpression,
                SyntaxKind.AnonymousMethodExpression,
                SyntaxKind.LocalFunctionStatement));
 }
Beispiel #8
0
 internal static bool CanContainContinueStatement(this SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.WhileStatement,
                SyntaxKind.DoStatement,
                SyntaxKind.ForStatement,
                SyntaxKind.ForEachStatement));
 }
Beispiel #9
0
 /// <summary>
 /// Returns true if a syntax of the specified kind can have members.
 /// </summary>
 /// <param name="kind"></param>
 /// <returns></returns>
 public static bool CanHaveMembers(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.CompilationUnit,
                SyntaxKind.NamespaceDeclaration,
                SyntaxKind.ClassDeclaration,
                SyntaxKind.StructDeclaration,
                SyntaxKind.InterfaceDeclaration));
 }
Beispiel #10
0
 /// <summary>
 /// Returns true if a syntax of the specified kind is a for, foreach, while or do statement.
 /// </summary>
 /// <param name="kind"></param>
 public static bool IsIterationStatement(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.ForStatement,
                SyntaxKind.ForEachStatement,
                SyntaxKind.ForEachVariableStatement,
                SyntaxKind.WhileStatement,
                SyntaxKind.DoStatement));
 }
Beispiel #11
0
 public static bool CanCreate(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.MethodDeclaration,
                SyntaxKind.PropertyDeclaration,
                SyntaxKind.IndexerDeclaration,
                SyntaxKind.EventDeclaration,
                SyntaxKind.VariableDeclarator));
 }
 internal static bool IsJumpStatement(this SyntaxKind kind)
 {
     return kind.Is(
         SyntaxKind.BreakStatement,
         SyntaxKind.ContinueStatement,
         SyntaxKind.GotoCaseStatement,
         SyntaxKind.GotoDefaultStatement,
         SyntaxKind.ReturnStatement,
         SyntaxKind.ThrowStatement);
 }
Beispiel #13
0
        internal static SyntaxKind GetJumpKind(StatementSyntax statement)
        {
            switch (statement)
            {
            case BreakStatementSyntax _:
            {
                return(SyntaxKind.BreakStatement);
            }

            case ContinueStatementSyntax _:
            {
                return(SyntaxKind.ContinueStatement);
            }

            case ReturnStatementSyntax returnStatement:
            {
                ExpressionSyntax expression = returnStatement.Expression;

                if (expression == null)
                {
                    return(SyntaxKind.ReturnStatement);
                }

                SyntaxKind kind = expression.Kind();

                if (kind.Is(
                        SyntaxKind.NullLiteralExpression,
                        SyntaxKind.DefaultLiteralExpression,
                        SyntaxKind.TrueLiteralExpression,
                        SyntaxKind.FalseLiteralExpression))
                {
                    return(kind);
                }

                return(SyntaxKind.None);
            }

            case ThrowStatementSyntax throwStatement:
            {
                ExpressionSyntax expression = throwStatement.Expression;

                if (expression == null)
                {
                    return(SyntaxKind.ThrowStatement);
                }

                return(SyntaxKind.None);
            }

            default:
            {
                return(SyntaxKind.None);
            }
            }
        }
        public static void ComputeRefactorings(RefactoringContext context, SyntaxTrivia trivia)
        {
            SyntaxKind kind     = trivia.Kind();
            Document   document = context.Document;
            TextSpan   span     = context.Span;

            if (context.IsRootCompilationUnit &&
                trivia.FullSpan.Contains(span) &&
                CSharpFacts.IsCommentTrivia(kind))
            {
                if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveComment))
                {
                    context.RegisterRefactoring(
                        "Remove comment",
                        ct =>
                    {
                        SyntaxToken newToken = RemoveCommentHelper.GetReplacementToken(trivia).WithFormatterAnnotation();

                        return(document.ReplaceTokenAsync(trivia.Token, newToken, ct));
                    },
                        RefactoringIdentifiers.RemoveComment);
                }

                if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllComments))
                {
                    context.RegisterRefactoring(
                        "Remove all comments",
                        ct => document.RemoveCommentsAsync(CommentFilter.All, ct),
                        RefactoringIdentifiers.RemoveAllComments);
                }

                if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllCommentsExceptDocumentationComments) &&
                    kind.Is(SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia))
                {
                    context.RegisterRefactoring(
                        "Remove all comments (except documentation comments)",
                        ct => document.RemoveCommentsAsync(CommentFilter.NonDocumentation, ct),
                        RefactoringIdentifiers.RemoveAllCommentsExceptDocumentationComments);
                }

                if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllDocumentationComments) &&
                    SyntaxFacts.IsDocumentationCommentTrivia(kind))
                {
                    context.RegisterRefactoring(
                        "Remove all documentation comments",
                        ct => document.RemoveCommentsAsync(CommentFilter.Documentation, ct),
                        RefactoringIdentifiers.RemoveAllDocumentationComments);
                }
            }
        }
Beispiel #15
0
        protected override bool IsFixable(StatementSyntax statement, BlockSyntax block, SyntaxKind parentKind)
        {
            if (!parentKind.Is(
                    SyntaxKind.MethodDeclaration,
                    SyntaxKind.LocalFunctionStatement))
            {
                return(false);
            }

            TextSpan span = TextSpan.FromBounds(block.SpanStart, statement.FullSpan.Start);

            //XTODO: Walker
            return(block
                   .DescendantNodes(span, f => !f.IsNestedMethod())
                   .Any(f => f.Kind().IsYieldStatement()));
        }
        protected override bool IsFixable(StatementSyntax statement, BlockSyntax block, SyntaxKind parentKind)
        {
            if (!parentKind.Is(
                    SyntaxKind.MethodDeclaration,
                    SyntaxKind.LocalFunctionStatement))
            {
                return(false);
            }

            if (object.ReferenceEquals(block.Statements.SingleOrDefault(ignoreLocalFunctions: true, shouldThrow: false), statement))
            {
                return(false);
            }

            TextSpan span = TextSpan.FromBounds(block.SpanStart, statement.FullSpan.Start);

            return(block.ContainsYield(span));
        }
Beispiel #17
0
        public override void VisitYieldStatement(YieldStatementSyntax node)
        {
            SyntaxKind kind = node.Kind();

            Debug.Assert(kind.Is(SyntaxKind.YieldBreakStatement, SyntaxKind.YieldReturnStatement), kind.ToString());

            if (kind == SyntaxKind.YieldReturnStatement)
            {
                if (SearchForYieldReturn)
                {
                    YieldStatement = node;
                }
            }
            else if (kind == SyntaxKind.YieldBreakStatement)
            {
                if (SearchForYieldBreak)
                {
                    YieldStatement = node;
                }
            }
        }
        protected override bool IsFixable(StatementSyntax statement, StatementSyntax containingStatement, BlockSyntax block, SyntaxKind parentKind)
        {
            if (!parentKind.Is(
                    SyntaxKind.MethodDeclaration,
                    SyntaxKind.LocalFunctionStatement))
            {
                return(false);
            }

            SyntaxList <StatementSyntax> statements = block.Statements;

            if (object.ReferenceEquals(statements.SingleOrDefault(ignoreLocalFunctions: true, shouldThrow: false), containingStatement))
            {
                return(false);
            }

            ContainsYieldWalker walker = ContainsYieldWalker.GetInstance();

            bool success = false;

            int index = statements.IndexOf(containingStatement);

            for (int i = 0; i < index; i++)
            {
                walker.VisitStatement(statements[i]);

                success = walker.YieldStatement != null;

                if (success)
                {
                    break;
                }
            }

            ContainsYieldWalker.Free(walker);

            return(success);
        }
Beispiel #19
0
        protected override bool IsFixable(StatementSyntax statement, BlockSyntax block, SyntaxKind parentKind)
        {
            if (!parentKind.Is(
                    SyntaxKind.ConstructorDeclaration,
                    SyntaxKind.DestructorDeclaration,
                    SyntaxKind.MethodDeclaration,
                    SyntaxKind.SetAccessorDeclaration,
                    SyntaxKind.LocalFunctionStatement))
            {
                return(false);
            }

            if (parentKind == SyntaxKind.MethodDeclaration)
            {
                return(((MethodDeclarationSyntax)block.Parent).ReturnType?.IsVoid() == true);
            }

            if (parentKind == SyntaxKind.LocalFunctionStatement)
            {
                return(((LocalFunctionStatementSyntax)block.Parent).ReturnType?.IsVoid() == true);
            }

            return(true);
        }
Beispiel #20
0
 /// <summary>
 /// Returns true if a syntax of the specified kind is a lambda expression.
 /// </summary>
 /// <param name="kind"></param>
 public static bool IsLambdaExpression(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.SimpleLambdaExpression,
                SyntaxKind.ParenthesizedLambdaExpression));
 }
Beispiel #21
0
 /// <summary>
 /// Returns true if a syntax of the specified kind is true or false literal expression.
 /// </summary>
 /// <param name="kind"></param>
 public static bool IsBooleanLiteralExpression(SyntaxKind kind)
 {
     return(kind.Is(
                SyntaxKind.TrueLiteralExpression,
                SyntaxKind.FalseLiteralExpression));
 }
Beispiel #22
0
 /// <summary>
 /// Returns true if a syntax of the specified kind can have statements. It can be either <see cref="BlockSyntax"/> or <see cref="SwitchSectionSyntax"/>.
 /// </summary>
 /// <param name="kind"></param>
 public static bool CanHaveStatements(SyntaxKind kind)
 {
     return(kind.Is(SyntaxKind.Block, SyntaxKind.SwitchSection));
 }
Beispiel #23
0
        private Dictionary <SyntaxNode, object> GetReplacementMap(SyntaxNode node, Dictionary <ISymbol, string> symbolMap)
        {
            var replacementMap = new Dictionary <SyntaxNode, object>();

            foreach (SyntaxNode descendant in node.DescendantNodesAndSelf(node.Span))
            {
                SyntaxKind kind = descendant.Kind();

                if (kind == SyntaxKind.IdentifierName)
                {
                    var identifierName = (IdentifierNameSyntax)descendant;

                    ISymbol symbol = DeclarationSemanticModel.GetSymbol(identifierName, CancellationToken);

                    if (symbol != null)
                    {
                        if (symbol.IsParameter())
                        {
                            foreach (ParameterInfo parameterInfo in ParameterInfos)
                            {
                                if (parameterInfo.ParameterSymbol.OriginalDefinition.Equals(symbol))
                                {
                                    replacementMap.Add(identifierName, parameterInfo.Expression);
                                    break;
                                }
                            }
                        }
                        else if (symbol.IsTypeParameter())
                        {
                            var typeParameter = (ITypeParameterSymbol)symbol;

                            ImmutableArray <ITypeSymbol> typeArguments = MethodSymbol.TypeArguments;

                            if (typeArguments.Length > typeParameter.Ordinal)
                            {
                                replacementMap.Add(identifierName, typeArguments[typeParameter.Ordinal].ToMinimalTypeSyntax(DeclarationSemanticModel, identifierName.SpanStart));
                            }
                        }
                        else if (symbol.IsStatic &&
                                 !identifierName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))
                        {
                            INamedTypeSymbol containingType = symbol.ContainingType;

                            if (!InvocationEnclosingType
                                .BaseTypesAndSelf()
                                .Any(f => f.Equals(containingType)))
                            {
                                replacementMap.Add(identifierName, CSharpFactory.SimpleMemberAccessExpression(containingType.ToTypeSyntax().WithSimplifierAnnotation(), identifierName));
                            }
                        }

                        if (symbolMap != null &&
                            symbolMap.TryGetValue(symbol, out string name))
                        {
                            replacementMap.Add(identifierName, SyntaxFactory.IdentifierName(name));
                        }
                    }
                }
                else if (symbolMap != null)
                {
                    if (kind.Is(
                            SyntaxKind.VariableDeclarator,
                            SyntaxKind.SingleVariableDesignation,
                            SyntaxKind.Parameter,
                            SyntaxKind.TypeParameter,
                            SyntaxKind.ForEachStatement,
                            SyntaxKind.ForEachVariableStatement))
                    {
                        ISymbol symbol = DeclarationSemanticModel.GetDeclaredSymbol(descendant, CancellationToken);

                        Debug.Assert(symbol != null || (descendant as ForEachVariableStatementSyntax)?.Variable?.Kind() == SyntaxKind.TupleExpression, kind.ToString());

                        if (symbol != null &&
                            symbolMap.TryGetValue(symbol, out string name))
                        {
                            replacementMap.Add(descendant, name);
                        }
                    }
                }
            }

            return(replacementMap);
        }
Beispiel #24
0
        public static ImmutableArray <IfRefactoring> Analyze(
            IfStatementSyntax ifStatement,
            IfAnalysisOptions options,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!ifStatement.IsTopmostIf())
            {
                return(Empty);
            }

            ExpressionSyntax condition = ifStatement.Condition?.WalkDownParentheses();

            if (condition == null)
            {
                return(Empty);
            }

            ElseClauseSyntax elseClause = ifStatement.Else;

            if (elseClause != null)
            {
                if (!options.CheckSpanDirectives(ifStatement))
                {
                    return(Empty);
                }

                StatementSyntax statement1 = ifStatement.GetSingleStatementOrDefault();

                if (statement1 == null)
                {
                    return(Empty);
                }

                SyntaxKind kind1 = statement1.Kind();

                if (kind1.Is(
                        SyntaxKind.ExpressionStatement,
                        SyntaxKind.ReturnStatement,
                        SyntaxKind.YieldReturnStatement))
                {
                    StatementSyntax statement2 = elseClause.GetSingleStatementOrDefault();

                    if (statement2?.Kind() == kind1)
                    {
                        switch (kind1)
                        {
                        case SyntaxKind.ExpressionStatement:
                        {
                            return(Analyze(
                                       ifStatement,
                                       condition,
                                       (ExpressionStatementSyntax)statement1,
                                       (ExpressionStatementSyntax)statement2,
                                       options,
                                       semanticModel,
                                       cancellationToken));
                        }

                        case SyntaxKind.ReturnStatement:
                        {
                            return(Analyze(
                                       ifStatement,
                                       condition,
                                       ((ReturnStatementSyntax)statement1).Expression?.WalkDownParentheses(),
                                       ((ReturnStatementSyntax)statement2).Expression?.WalkDownParentheses(),
                                       options,
                                       isYield: false,
                                       semanticModel: semanticModel,
                                       cancellationToken: cancellationToken));
                        }

                        case SyntaxKind.YieldReturnStatement:
                        {
                            return(Analyze(
                                       ifStatement,
                                       condition,
                                       ((YieldStatementSyntax)statement1).Expression?.WalkDownParentheses(),
                                       ((YieldStatementSyntax)statement2).Expression?.WalkDownParentheses(),
                                       options,
                                       isYield: true,
                                       semanticModel: semanticModel,
                                       cancellationToken: cancellationToken));
                        }
                        }
                    }
                }
            }
            else if (ifStatement.NextStatementOrDefault() is ReturnStatementSyntax returnStatement)
            {
                return(Analyze(ifStatement, returnStatement, options, semanticModel, cancellationToken));
            }

            return(Empty);
        }
Beispiel #25
0
        public static void Analyze(SyntaxNodeAnalysisContext context, SimpleMemberInvocationExpressionInfo invocationInfo)
        {
            InvocationExpressionSyntax invocationExpression = invocationInfo.InvocationExpression;

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

            IMethodSymbol methodSymbol = semanticModel.GetReducedExtensionMethodInfo(invocationExpression, cancellationToken).Symbol;

            if (methodSymbol == null)
            {
                return;
            }

            if (!SymbolUtility.IsLinqExtensionOfIEnumerableOfTWithoutParameters(methodSymbol, "Count", semanticModel))
            {
                return;
            }

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

            if (propertyName != null)
            {
                context.ReportDiagnostic(
                    DiagnosticDescriptors.UseCountOrLengthPropertyInsteadOfCountMethod,
                    Location.Create(context.Node.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End)),
                    ImmutableDictionary.CreateRange(new KeyValuePair <string, string>[] { new KeyValuePair <string, string>("PropertyName", propertyName) }),
                    propertyName);
            }
            else
            {
                bool isFixable = false;

                SyntaxNode parent = invocationExpression.Parent;

                SyntaxKind kind = parent.Kind();

                if (kind.Is(
                        SyntaxKind.EqualsExpression,
                        SyntaxKind.NotEqualsExpression))
                {
                    var equalsExpression = (BinaryExpressionSyntax)parent;

                    if (equalsExpression.Left == invocationExpression)
                    {
                        if (equalsExpression.Right.IsNumericLiteralExpression("0"))
                        {
                            isFixable = true;
                        }
                    }
                    else if (equalsExpression.Left.IsNumericLiteralExpression("0"))
                    {
                        isFixable = true;
                    }
                }
                else if (kind.Is(
                             SyntaxKind.GreaterThanExpression,
                             SyntaxKind.GreaterThanOrEqualExpression,
                             SyntaxKind.LessThanExpression,
                             SyntaxKind.LessThanOrEqualExpression))
                {
                    isFixable = true;
                }

                if (isFixable)
                {
                    context.ReportDiagnostic(DiagnosticDescriptors.CallAnyInsteadOfCount, parent);
                }
            }
        }
Beispiel #26
0
        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.InvocationExpression,
                        SyntaxKind.EqualsExpression,
                        SyntaxKind.NotEqualsExpression,
                        SyntaxKind.IsPatternExpression,
                        SyntaxKind.ConditionalExpression)))
            {
                return;
            }

            Diagnostic        diagnostic        = context.Diagnostics[0];
            Document          document          = context.Document;
            CancellationToken cancellationToken = context.CancellationToken;

            SyntaxKind kind = node.Kind();

            if (kind == SyntaxKind.InvocationExpression)
            {
                var invocation = (InvocationExpressionSyntax)node;

                SimpleMemberInvocationExpressionInfo invocationInfo = SimpleMemberInvocationExpressionInfo(invocation);

                if (diagnostic.Properties.TryGetValue("Name", out string name) &&
                    name == "SimplifyLinqMethodChain")
                {
                    SimpleMemberInvocationExpressionInfo invocationInfo2 = SimpleMemberInvocationExpressionInfo(invocationInfo.Expression);

                    CodeAction codeAction = CodeAction.Create(
                        $"Combine '{invocationInfo2.NameText}' and '{invocationInfo.NameText}'",
                        ct => SimplifyLinqMethodChainAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "SimplifyLinqMethodChain"));

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

                switch (invocationInfo.NameText)
                {
                case "Cast":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'OfType' instead of 'Where' and 'Cast'",
                        ct => CallOfTypeInsteadOfWhereAndCastAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CallOfTypeInsteadOfWhereAndCast"));

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

                case "Any":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Combine 'Where' and 'Any'",
                        ct => CombineWhereAndAnyAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CombineWhereAndAny"));

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

                case "OfType":
                {
                    TypeSyntax typeArgument = ((GenericNameSyntax)invocationInfo.Name).TypeArgumentList.Arguments.Single();

                    SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    if (semanticModel.GetTypeSymbol(typeArgument, cancellationToken).IsValueType)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove redundant 'OfType' call",
                            ct =>
                            {
                                ExpressionSyntax newNode = invocationInfo.Expression.WithTrailingTrivia(invocation.GetTrailingTrivia());
                                return(document.ReplaceNodeAsync(invocation, newNode, ct));
                            },
                            GetEquivalenceKey(diagnostic, "RemoveRedundantOfTypeCall"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Where' instead of 'OfType'",
                            ct => CallWhereInsteadOfOfTypeAsync(document, invocationInfo, ct),
                            GetEquivalenceKey(diagnostic, "CallWhereInsteadOfOfType"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "Reverse":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'OrderByDescending",
                        ct => CallOrderByDescendingInsteadOfOrderByAndReverseAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CallOrderByDescendingInsteadOfOrderByAndReverse"));

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

                case "Select":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Cast' instead of 'Select'",
                        ct => CallCastInsteadOfSelectAsync(document, invocation, ct),
                        GetEquivalenceKey(diagnostic, "CallCastInsteadOfSelect"));

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

                case "FirstOrDefault":
                {
                    SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Find' instead of 'FirstOrDefault'",
                        ct => CallFindInsteadOfFirstOrDefaultAsync(document, invocationInfo, semanticModel, ct),
                        GetEquivalenceKey(diagnostic, "CallFindInsteadOfFirstOrDefault"));

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

                case "First":
                {
                    if (diagnostic.Properties.TryGetValue("MethodName", out string methodName) &&
                        methodName == "Peek")
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Peek' instead of 'First'",
                            ct => document.ReplaceNodeAsync(invocation, ChangeInvokedMethodName(invocation, "Peek"), ct),
                            GetEquivalenceKey(diagnostic, "CallPeekInsteadOfFirst"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Use [] instead of calling 'First'",
                            ct => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfFirstAsync(context.Document, invocation, ct),
                            GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfFirst"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "Count":
                {
                    if (diagnostic.Properties.TryGetValue("PropertyName", out string propertyName))
                    {
                        if (diagnostic.Properties.TryGetValue("MethodName", out string methodName) &&
                            methodName == "Sum")
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Call 'Sum'",
                                ct => CallSumInsteadOfSelectManyAndCountAsync(document, invocationInfo, propertyName, ct),
                                GetEquivalenceKey(diagnostic, "CallSumInsteadOfSelectManyAndCount"));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                        else
                        {
                            CodeAction codeAction = CodeAction.Create(
                                $"Use '{propertyName}' property instead of calling 'Count'",
                                ct => UseCountOrLengthPropertyInsteadOfCountMethodAsync(document, invocation, diagnostic.Properties["PropertyName"], ct),
                                GetEquivalenceKey(diagnostic, "UseCountOrLengthPropertyInsteadOfCountMethod"));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }
                    else if (invocation.Parent is BinaryExpressionSyntax binaryExpression)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Any' instead of 'Count'",
                            ct => CallAnyInsteadOfCountAsync(document, invocation, binaryExpression, ct),
                            GetEquivalenceKey(diagnostic, "CallAnyInsteadOfCount"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "ElementAt":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use [] instead of calling 'ElementAt'",
                        ct => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfElementAtAsync(document, invocation, ct),
                        GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfElementAt"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }
                }
            }
            else if (kind == SyntaxKind.ConditionalExpression)
            {
                CodeAction codeAction = CodeAction.Create(
                    "Call 'FirstOrDefault' instead of ?:",
                    ct => CallFirstOrDeafultInsteadOfConditionalExpressionAsync(document, (ConditionalExpressionSyntax)node, ct),
                    GetEquivalenceKey(diagnostic, "CallFirstOrDefaultInsteadOfConditionalExpression"));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
            else if (kind.Is(
                         SyntaxKind.EqualsExpression,
                         SyntaxKind.NotEqualsExpression,
                         SyntaxKind.IsPatternExpression))
            {
                CodeAction codeAction = CodeAction.Create(
                    "Call 'Any' instead of 'FirstOrDefault'",
                    ct => CallAnyInsteadOfFirstOrDefaultAsync(document, node, ct),
                    GetEquivalenceKey(diagnostic, "CallAnyInsteadOfFirstOrDefault"));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
        }
        private static ReduceIfNestingAnalysisResult AnalyzeCore(
            IfStatementSyntax ifStatement,
            SemanticModel semanticModel,
            SyntaxKind jumpKind,
            ReduceIfNestingOptions options,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement);

            if (!statementsInfo.Success)
            {
                return(Fail(ifStatement));
            }

            SyntaxNode node       = statementsInfo.Parent;
            SyntaxNode parent     = node.Parent;
            SyntaxKind parentKind = parent.Kind();

            SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

            if (statementsInfo.IsParentSwitchSection ||
                parentKind == SyntaxKind.SwitchSection)
            {
                SyntaxNode switchSection = (statementsInfo.IsParentSwitchSection) ? node : parent;

                if (!options.AllowSwitchSection())
                {
                    return(Fail(switchSection));
                }

                if (ifStatement != statements.LastButOneOrDefault())
                {
                    return(Fail(switchSection));
                }

                if (!IsFixableJumpStatement(statements.Last(), ref jumpKind))
                {
                    return(Fail(switchSection));
                }

                if (!options.AllowNestedFix() &&
                    IsNestedFix(switchSection.Parent, semanticModel, options, cancellationToken))
                {
                    return(Fail(switchSection));
                }

                return(Success(jumpKind, switchSection));
            }

            if (parentKind.Is(
                    SyntaxKind.ForStatement,
                    SyntaxKind.ForEachStatement,
                    SyntaxKind.DoStatement,
                    SyntaxKind.WhileStatement))
            {
                if (!options.AllowLoop())
                {
                    return(Fail(parent));
                }

                StatementSyntax lastStatement = statements.Last();

                if (ifStatement == lastStatement)
                {
                    jumpKind = SyntaxKind.ContinueStatement;
                }
                else
                {
                    if (ifStatement != statements.LastButOneOrDefault())
                    {
                        return(Fail(parent));
                    }

                    if (!IsFixableJumpStatement(lastStatement, ref jumpKind))
                    {
                        return(Fail(parent));
                    }
                }

                if (!options.AllowNestedFix() &&
                    IsNestedFix(parent.Parent, semanticModel, options, cancellationToken))
                {
                    return(Fail(parent));
                }

                return(Success(jumpKind, parent));
            }

            if (!IsFixable(ifStatement, statements, ref jumpKind))
            {
                return(Fail(node));
            }

            switch (parentKind)
            {
            case SyntaxKind.ConstructorDeclaration:
            case SyntaxKind.DestructorDeclaration:
            case SyntaxKind.SetAccessorDeclaration:
            case SyntaxKind.AddAccessorDeclaration:
            case SyntaxKind.RemoveAccessorDeclaration:
            {
                if (jumpKind == SyntaxKind.None)
                {
                    jumpKind = SyntaxKind.ReturnStatement;
                }
                else if (jumpKind != SyntaxKind.ReturnStatement)
                {
                    return(Fail(parent));
                }

                return(Success(jumpKind, parent));
            }

            case SyntaxKind.OperatorDeclaration:
            case SyntaxKind.ConversionOperatorDeclaration:
            case SyntaxKind.GetAccessorDeclaration:
            {
                if (jumpKind == SyntaxKind.None)
                {
                    return(Fail(parent));
                }

                return(Success(jumpKind, parent));
            }

            case SyntaxKind.MethodDeclaration:
            {
                var methodDeclaration = (MethodDeclarationSyntax)parent;

                if (jumpKind != SyntaxKind.None)
                {
                    return(Success(jumpKind, parent));
                }

                if (methodDeclaration.ReturnsVoid())
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (methodDeclaration.Modifiers.Contains(SyntaxKind.AsyncKeyword) &&
                    semanticModel
                    .GetDeclaredSymbol(methodDeclaration, cancellationToken)?
                    .ReturnType
                    .HasMetadataName(MetadataNames.System_Threading_Tasks_Task) == true)
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (semanticModel
                    .GetDeclaredSymbol(methodDeclaration, cancellationToken)?
                    .ReturnType
                    .OriginalDefinition
                    .IsIEnumerableOrIEnumerableOfT() == true &&
                    methodDeclaration.ContainsYield())
                {
                    return(Success(SyntaxKind.YieldBreakStatement, parent));
                }

                break;
            }

            case SyntaxKind.LocalFunctionStatement:
            {
                var localFunction = (LocalFunctionStatementSyntax)parent;

                if (jumpKind != SyntaxKind.None)
                {
                    return(Success(jumpKind, parent));
                }

                if (localFunction.ReturnsVoid())
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (localFunction.Modifiers.Contains(SyntaxKind.AsyncKeyword) &&
                    semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)?
                    .ReturnType
                    .HasMetadataName(MetadataNames.System_Threading_Tasks_Task) == true)
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (semanticModel.GetDeclaredSymbol(localFunction, cancellationToken)?
                    .ReturnType
                    .OriginalDefinition
                    .IsIEnumerableOrIEnumerableOfT() == true &&
                    localFunction.ContainsYield())
                {
                    return(Success(SyntaxKind.YieldBreakStatement, parent));
                }

                break;
            }

            case SyntaxKind.AnonymousMethodExpression:
            case SyntaxKind.SimpleLambdaExpression:
            case SyntaxKind.ParenthesizedLambdaExpression:
            {
                var anonymousFunction = (AnonymousFunctionExpressionSyntax)parent;

                if (jumpKind != SyntaxKind.None)
                {
                    return(Success(jumpKind, parent));
                }

                if (!(semanticModel.GetSymbol(anonymousFunction, cancellationToken) is IMethodSymbol methodSymbol))
                {
                    return(Fail(parent));
                }

                if (methodSymbol.ReturnsVoid)
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (anonymousFunction.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword &&
                    methodSymbol.ReturnType.HasMetadataName(MetadataNames.System_Threading_Tasks_Task))
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                break;
            }

            case SyntaxKind.IfStatement:
            {
                ifStatement = (IfStatementSyntax)parent;

                if (ifStatement.Parent is ElseClauseSyntax elseClause)
                {
                    if (ifStatement.Else != null)
                    {
                        return(Fail(parent));
                    }

                    if (!options.AllowIfInsideIfElse())
                    {
                        return(Fail(parent));
                    }

                    return(AnalyzeCore(ifStatement.GetTopmostIf(), semanticModel, jumpKind, options, cancellationToken));
                }
                else
                {
                    if (!IsFixable(ifStatement))
                    {
                        return(Fail(parent));
                    }

                    if (!options.AllowNestedFix())
                    {
                        return(Fail(parent));
                    }

                    return(AnalyzeCore(ifStatement, semanticModel, jumpKind, options, cancellationToken));
                }
            }

            case SyntaxKind.ElseClause:
            {
                if (!options.AllowIfInsideIfElse())
                {
                    return(Fail(parent));
                }

                var elseClause = (ElseClauseSyntax)parent;

                return(AnalyzeCore(elseClause.GetTopmostIf(), semanticModel, jumpKind, options, cancellationToken));
            }
            }

            return(Fail(parent));
        }
        public static void ComputeRefactoring(RefactoringContext context, ExpressionSyntax expression)
        {
            SyntaxNode parent = expression.Parent;

            if (parent == null)
            {
                return;
            }

            SyntaxKind kind = parent.Kind();

            if (!kind.Is(SyntaxKind.LogicalAndExpression, SyntaxKind.LogicalOrExpression))
            {
                return;
            }

            BinaryExpressionSyntax binaryExpression = GetCondition((BinaryExpressionSyntax)parent);

            if (binaryExpression == null)
            {
                return;
            }

            parent = binaryExpression.Parent;

            switch (parent?.Kind())
            {
            case SyntaxKind.IfStatement:
            {
                if (kind == SyntaxKind.LogicalAndExpression)
                {
                    ExtractConditionFromIfToNestedIfRefactoring refactoring = ExtractConditionFromIfToNestedIfRefactoring.Instance;

                    context.RegisterRefactoring(
                        refactoring.Title,
                        cancellationToken => refactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken));
                }
                else if (kind == SyntaxKind.LogicalOrExpression)
                {
                    StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo((StatementSyntax)parent);

                    if (statementsInfo.Success)
                    {
                        ExtractConditionFromIfToIfRefactoring refactoring = ExtractConditionFromIfToIfRefactoring.Instance;

                        context.RegisterRefactoring(
                            refactoring.Title,
                            cancellationToken => refactoring.RefactorAsync(context.Document, statementsInfo, binaryExpression, expression, cancellationToken));
                    }
                }

                break;
            }

            case SyntaxKind.WhileStatement:
            {
                if (kind == SyntaxKind.LogicalAndExpression)
                {
                    StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo((StatementSyntax)parent);

                    if (statementsInfo.Success)
                    {
                        ExtractConditionFromWhileToNestedIfRefactoring refactoring = ExtractConditionFromWhileToNestedIfRefactoring.Instance;

                        context.RegisterRefactoring(
                            refactoring.Title,
                            cancellationToken => refactoring.RefactorAsync(context.Document, (WhileStatementSyntax)parent, binaryExpression, expression, cancellationToken));
                    }
                }

                break;
            }
            }
        }
        internal static void ComputeRefactoring(RefactoringContext context, BinaryExpressionSelection binaryExpressionSelection)
        {
            BinaryExpressionSyntax binaryExpression = binaryExpressionSelection.BinaryExpression;

            SyntaxKind kind = binaryExpression.Kind();

            if (!kind.Is(SyntaxKind.LogicalAndExpression, SyntaxKind.LogicalOrExpression))
            {
                return;
            }

            BinaryExpressionSyntax condition = GetCondition(binaryExpression);

            if (condition == null)
            {
                return;
            }

            SyntaxNode parent = condition.Parent;

            switch (parent?.Kind())
            {
            case SyntaxKind.IfStatement:
            {
                if (kind == SyntaxKind.LogicalAndExpression)
                {
                    ExtractConditionFromIfToNestedIfRefactoring refactoring = ExtractConditionFromIfToNestedIfRefactoring.Instance;

                    context.RegisterRefactoring(
                        refactoring.Title,
                        cancellationToken => refactoring.RefactorAsync(context.Document, (IfStatementSyntax)parent, condition, binaryExpressionSelection, cancellationToken),
                        RefactoringIdentifiers.ExtractExpressionFromCondition);
                }
                else if (kind == SyntaxKind.LogicalOrExpression)
                {
                    StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo((StatementSyntax)parent);

                    if (statementsInfo.Success)
                    {
                        ExtractConditionFromIfToIfRefactoring refactoring = ExtractConditionFromIfToIfRefactoring.Instance;

                        context.RegisterRefactoring(
                            refactoring.Title,
                            cancellationToken => refactoring.RefactorAsync(context.Document, statementsInfo, condition, binaryExpressionSelection, cancellationToken),
                            RefactoringIdentifiers.ExtractExpressionFromCondition);
                    }
                }

                break;
            }

            case SyntaxKind.WhileStatement:
            {
                if (kind == SyntaxKind.LogicalAndExpression)
                {
                    ExtractConditionFromWhileToNestedIfRefactoring refactoring = ExtractConditionFromWhileToNestedIfRefactoring.Instance;

                    context.RegisterRefactoring(
                        refactoring.Title,
                        cancellationToken => refactoring.RefactorAsync(context.Document, (WhileStatementSyntax)parent, condition, binaryExpressionSelection, cancellationToken),
                        RefactoringIdentifiers.ExtractExpressionFromCondition);
                }

                break;
            }
            }
        }
Beispiel #30
0
        private Dictionary <SyntaxNode, object> GetReplacementMap(SyntaxNode node, Dictionary <ISymbol, string> symbolMap)
        {
            var replacementMap = new Dictionary <SyntaxNode, object>();

            foreach (SyntaxNode descendant in node.DescendantNodesAndSelf(node.Span))
            {
                SyntaxKind kind = descendant.Kind();

                if (kind == SyntaxKind.IdentifierName)
                {
                    var identifierName = (IdentifierNameSyntax)descendant;

                    ISymbol symbol = DeclarationSemanticModel.GetSymbol(identifierName, CancellationToken);

                    if (symbol != null)
                    {
                        if (symbol is IParameterSymbol parameterSymbol)
                        {
                            foreach (ParameterInfo parameterInfo in ParameterInfos)
                            {
                                if (ParameterEquals(parameterInfo, parameterSymbol))
                                {
                                    ExpressionSyntax expression = parameterInfo.Expression;

                                    if (expression == null &&
                                        parameterInfo.ParameterSymbol.HasExplicitDefaultValue)
                                    {
                                        expression = parameterInfo.ParameterSymbol.GetDefaultValueMinimalSyntax(InvocationSemanticModel, Node.SpanStart);
                                    }

                                    replacementMap.Add(identifierName, expression);
                                    break;
                                }
                            }
                        }
                        else if (symbol.Kind == SymbolKind.TypeParameter)
                        {
                            var typeParameter = (ITypeParameterSymbol)symbol;

                            ImmutableArray <ITypeSymbol> typeArguments = TypeArguments;

                            if (typeArguments.Length > typeParameter.Ordinal)
                            {
                                replacementMap.Add(identifierName, typeArguments[typeParameter.Ordinal].ToMinimalTypeSyntax(DeclarationSemanticModel, identifierName.SpanStart));
                            }
                        }
                        else if (symbol.IsStatic &&
                                 !identifierName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.QualifiedName))
                        {
                            INamedTypeSymbol containingType = symbol.ContainingType;

                            if (containingType != null)
                            {
                                if (!NodeEnclosingType
                                    .BaseTypesAndSelf()
                                    .Any(f => f.Equals(containingType)))
                                {
                                    replacementMap.Add(identifierName, CSharpFactory.SimpleMemberAccessExpression(containingType.ToTypeSyntax().WithSimplifierAnnotation(), identifierName));
                                }
                            }
                            else if (symbol is ITypeSymbol typeSymbol)
                            {
                                replacementMap.Add(identifierName, typeSymbol.ToMinimalTypeSyntax(InvocationSemanticModel, Node.SpanStart));
                            }
                        }

                        if (symbolMap != null &&
                            symbolMap.TryGetValue(symbol, out string name))
                        {
                            replacementMap.Add(identifierName, IdentifierName(name));
                        }
                    }
                }
                else if (symbolMap != null)
                {
                    if (kind.Is(
                            SyntaxKind.VariableDeclarator,
                            SyntaxKind.SingleVariableDesignation,
                            SyntaxKind.Parameter,
                            SyntaxKind.TypeParameter,
                            SyntaxKind.ForEachStatement,
                            SyntaxKind.ForEachVariableStatement))
                    {
                        ISymbol symbol = DeclarationSemanticModel.GetDeclaredSymbol(descendant, CancellationToken);

                        Debug.Assert(symbol != null || (descendant as ForEachVariableStatementSyntax)?.Variable?.Kind() == SyntaxKind.TupleExpression, kind.ToString());

                        if (symbol != null &&
                            symbolMap.TryGetValue(symbol, out string name))
                        {
                            replacementMap.Add(descendant, name);
                        }
                    }
                }
            }

            return(replacementMap);

            bool ParameterEquals(in ParameterInfo parameterInfo, IParameterSymbol parameterSymbol2)
            {
                IParameterSymbol parameterSymbol = parameterInfo.ParameterSymbol;

                if (parameterSymbol.ContainingSymbol is IMethodSymbol methodSymbol)
                {
                    if (parameterInfo.IsThis ||
                        methodSymbol.MethodKind == MethodKind.ReducedExtension)
                    {
                        int ordinal = parameterSymbol.Ordinal;

                        if (methodSymbol.MethodKind == MethodKind.ReducedExtension)
                        {
                            ordinal++;
                        }

                        return(ordinal == parameterSymbol2.Ordinal &&
                               string.Equals(parameterSymbol.Name, parameterSymbol2.Name, StringComparison.Ordinal));
                    }
                }

                return(parameterSymbol.OriginalDefinition.Equals(parameterSymbol2));
            }
        }