private static bool IsDeclaredInTryStatementOrCatchClauseAndReferencedInFinallyClause(
            SyntaxNodeAnalysisContext context,
            StatementSyntax statement,
            ISymbol symbol)
        {
            SyntaxNode node = statement.Parent;

            while (node != null &&
                   node is not MemberDeclarationSyntax &&
                   !node.IsKind(SyntaxKind.FinallyClause))
            {
                if (node is TryStatementSyntax tryStatement)
                {
                    BlockSyntax block = tryStatement.Finally?.Block;

                    if (block != null)
                    {
                        ContainsLocalOrParameterReferenceWalker walker = null;

                        try
                        {
                            walker = ContainsLocalOrParameterReferenceWalker.GetInstance(symbol, context.SemanticModel, context.CancellationToken);

                            walker.VisitBlock(block);

                            if (walker.Result)
                            {
                                return(true);
                            }
                        }
                        finally
                        {
                            if (walker != null)
                            {
                                ContainsLocalOrParameterReferenceWalker.Free(walker);
                            }
                        }
                    }
                }

                node = node.Parent;
            }

            return(false);
        }
        private static bool IsLocalVariableReferenced(
            SyntaxNodeAnalysisContext context,
            SingleLocalDeclarationStatementInfo localInfo,
            SwitchStatementSyntax switchStatement)
        {
            ISymbol localSymbol = context.SemanticModel.GetDeclaredSymbol(localInfo.Declarator, context.CancellationToken);

            if (localSymbol.IsKind(SymbolKind.Local))
            {
                ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(localSymbol, context.SemanticModel, context.CancellationToken);

                walker.VisitList(switchStatement.Sections);

                if (!walker.Result)
                {
                    StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(switchStatement);

                    if (statementsInfo.Success)
                    {
                        int index = statementsInfo.IndexOf(switchStatement);

                        if (index < statementsInfo.Count - 1)
                        {
                            walker.VisitList(statementsInfo.Statements, index + 1);
                        }
                    }
                }

                bool isReferenced = walker.Result;

                ContainsLocalOrParameterReferenceWalker.Free(walker);

                return(isReferenced);
            }

            return(false);
        }
        public static void AnalyzeLocalDeclarationStatement(SyntaxNodeAnalysisContext context)
        {
            var localDeclarationStatement = (LocalDeclarationStatementSyntax)context.Node;

            if (localDeclarationStatement.ContainsDiagnostics)
            {
                return;
            }

            if (localDeclarationStatement.SpanOrTrailingTriviaContainsDirectives())
            {
                return;
            }

            SingleLocalDeclarationStatementInfo localDeclarationInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclarationStatement);

            if (!localDeclarationInfo.Success)
            {
                return;
            }

            ExpressionSyntax value = localDeclarationInfo.Value;

            if (value == null)
            {
                return;
            }

            SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(localDeclarationStatement).Statements;

            if (!statements.Any())
            {
                return;
            }

            int index = statements.IndexOf(localDeclarationStatement);

            if (index == statements.Count - 1)
            {
                return;
            }

            StatementSyntax nextStatement = statements[index + 1];

            if (nextStatement.ContainsDiagnostics)
            {
                return;
            }

            switch (nextStatement.Kind())
            {
            case SyntaxKind.ExpressionStatement:
            {
                Analyze(context, statements, localDeclarationInfo, index, (ExpressionStatementSyntax)nextStatement);
                break;
            }

            case SyntaxKind.LocalDeclarationStatement:
            {
                Analyze(context, statements, localDeclarationInfo, index, (LocalDeclarationStatementSyntax)nextStatement);
                break;
            }

            case SyntaxKind.ReturnStatement:
            {
                var returnStatement = (ReturnStatementSyntax)nextStatement;

                if (!returnStatement.SpanOrLeadingTriviaContainsDirectives())
                {
                    ExpressionSyntax expression = returnStatement.Expression;

                    if (expression?.Kind() == SyntaxKind.IdentifierName)
                    {
                        var identifierName = (IdentifierNameSyntax)expression;

                        if (string.Equals(localDeclarationInfo.IdentifierText, identifierName.Identifier.ValueText, StringComparison.Ordinal))
                        {
                            ReportDiagnostic(context, localDeclarationInfo, expression);
                        }
                    }
                }

                break;
            }

            case SyntaxKind.YieldReturnStatement:
            {
                var yieldStatement = (YieldStatementSyntax)nextStatement;

                if (index == statements.Count - 2 &&
                    !yieldStatement.SpanOrLeadingTriviaContainsDirectives())
                {
                    ExpressionSyntax expression = yieldStatement.Expression;

                    if (expression?.Kind() == SyntaxKind.IdentifierName)
                    {
                        var identifierName = (IdentifierNameSyntax)expression;

                        if (string.Equals(localDeclarationInfo.IdentifierText, identifierName.Identifier.ValueText, StringComparison.Ordinal))
                        {
                            ReportDiagnostic(context, localDeclarationInfo, expression);
                        }
                    }
                }

                break;
            }

            case SyntaxKind.ForEachStatement:
            {
                if (value.WalkDownParentheses().IsKind(SyntaxKind.AwaitExpression))
                {
                    return;
                }

                if (!value.IsSingleLine())
                {
                    return;
                }

                if (value.IsKind(SyntaxKind.ArrayInitializerExpression))
                {
                    return;
                }

                var forEachStatement = (ForEachStatementSyntax)nextStatement;

                ISymbol localSymbol = GetLocalSymbol(localDeclarationInfo, forEachStatement.Expression, context.SemanticModel, context.CancellationToken);

                if (localSymbol?.IsErrorType() != false)
                {
                    return;
                }

                ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(localSymbol, context.SemanticModel, context.CancellationToken);

                walker.Visit(forEachStatement.Statement);

                if (!walker.Result &&
                    index < statements.Count - 2)
                {
                    walker.VisitList(statements, index + 2);
                }

                if (ContainsLocalOrParameterReferenceWalker.GetResultAndFree(walker))
                {
                    return;
                }

                ReportDiagnostic(context, localDeclarationInfo, forEachStatement.Expression);

                break;
            }

            case SyntaxKind.SwitchStatement:
            {
                if (value.WalkDownParentheses().IsKind(SyntaxKind.AwaitExpression))
                {
                    return;
                }

                if (!value.IsSingleLine())
                {
                    return;
                }

                var switchStatement = (SwitchStatementSyntax)nextStatement;

                ISymbol localSymbol = GetLocalSymbol(localDeclarationInfo, switchStatement.Expression, context.SemanticModel, context.CancellationToken);

                if (localSymbol?.IsErrorType() != false)
                {
                    return;
                }

                ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(localSymbol, context.SemanticModel, context.CancellationToken);

                walker.VisitList(switchStatement.Sections);

                if (!walker.Result &&
                    index < statements.Count - 2)
                {
                    walker.VisitList(statements, index + 2);
                }

                if (ContainsLocalOrParameterReferenceWalker.GetResultAndFree(walker))
                {
                    return;
                }

                ReportDiagnostic(context, localDeclarationInfo, switchStatement.Expression);

                break;
            }
            }
        }
Exemplo n.º 4
0
        private static int FindLocalDeclarationStatementIndex(
            WhileStatementSyntax whileStatement,
            SyntaxList <StatementSyntax> statements,
            int startIndex,
            int count,
            bool mustBeReferencedInsideWhileStatement,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default)
        {
            int         resultIndex         = -1;
            int         whileStatementIndex = -1;
            ITypeSymbol typeSymbol          = null;

            for (int i = count - 1; i >= startIndex; i--)
            {
                StatementSyntax statement = statements[i];

                if (!(statement is LocalDeclarationStatementSyntax localDeclaration))
                {
                    return(resultIndex);
                }

                VariableDeclarationSyntax declaration = localDeclaration.Declaration;

                foreach (VariableDeclaratorSyntax variable in declaration.Variables)
                {
                    var symbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(variable, cancellationToken);

                    if (symbol == null)
                    {
                        continue;
                    }

                    if (symbol.Type.IsErrorType())
                    {
                        continue;
                    }

                    if (typeSymbol == null)
                    {
                        typeSymbol = symbol.Type;
                    }
                    else if (!SymbolEqualityComparer.Default.Equals(typeSymbol, symbol.Type))
                    {
                        return(resultIndex);
                    }

                    ContainsLocalOrParameterReferenceWalker walker = null;

                    try
                    {
                        walker = ContainsLocalOrParameterReferenceWalker.GetInstance(symbol, semanticModel, cancellationToken);

                        if (mustBeReferencedInsideWhileStatement)
                        {
                            walker.VisitWhileStatement(whileStatement);

                            if (!walker.Result)
                            {
                                ContainsLocalOrParameterReferenceWalker.Free(walker);
                                return(resultIndex);
                            }
                        }

                        walker.Result = false;

                        if (whileStatementIndex == -1)
                        {
                            whileStatementIndex = statements.IndexOf(whileStatement);
                        }

                        walker.VisitList(statements, whileStatementIndex + 1);

                        if (walker.Result)
                        {
                            return(resultIndex);
                        }
                    }
                    finally
                    {
                        if (walker != null)
                        {
                            ContainsLocalOrParameterReferenceWalker.Free(walker);
                        }
                    }

                    resultIndex = i;
                }
            }

            return(resultIndex);
        }
        private static void AnalyzeWhileStatement(SyntaxNodeAnalysisContext context)
        {
            var whileStatement = (WhileStatementSyntax)context.Node;

            ExpressionSyntax condition = whileStatement.Condition;

            if (condition.IsMissing)
            {
                return;
            }

            if (!condition.IsSingleLine())
            {
                return;
            }

            StatementSyntax statement = whileStatement.Statement;

            if (!(statement is BlockSyntax block))
            {
                return;
            }

            SyntaxList <StatementSyntax> innerStatements = block.Statements;

            if (innerStatements.Count <= 1)
            {
                return;
            }

            ExpressionSyntax incrementedExpression = GetIncrementedExpression(innerStatements.Last());

            if (!incrementedExpression.IsKind(SyntaxKind.IdentifierName))
            {
                return;
            }

            SyntaxList <StatementSyntax> outerStatements = SyntaxInfo.StatementListInfo(whileStatement).Statements;

            int index = outerStatements.IndexOf(whileStatement);

            if (index <= 0)
            {
                return;
            }

            SingleLocalDeclarationStatementInfo localInfo = GetLocalInfo(outerStatements[index - 1]);

            if (!localInfo.Success)
            {
                return;
            }

            if (index > 1)
            {
                SingleLocalDeclarationStatementInfo localInfo2 = GetLocalInfo(outerStatements[index - 2]);

                if (localInfo2.Success)
                {
                    ExpressionSyntax incrementedExpression2 = GetIncrementedExpression(innerStatements[innerStatements.Count - 2]);

                    if (incrementedExpression2 is IdentifierNameSyntax identifierName2 &&
                        string.Equals(localInfo2.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal))
                    {
                        return;
                    }
                }
            }

            var identifierName = (IdentifierNameSyntax)incrementedExpression;

            if (!string.Equals(localInfo.Identifier.ValueText, identifierName.Identifier.ValueText, StringComparison.Ordinal))
            {
                return;
            }

            if (ContainsContinueStatement())
            {
                return;
            }

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

            ISymbol symbol = semanticModel.GetDeclaredSymbol(localInfo.Declarator, cancellationToken);

            if (symbol?.Kind != SymbolKind.Local)
            {
                return;
            }

            if (IsLocalVariableReferencedAfterWhileStatement())
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseForStatementInsteadOfWhileStatement, whileStatement.WhileKeyword);

            bool ContainsContinueStatement()
            {
                ContainsContinueStatementWalker walker = ContainsContinueStatementWalker.GetInstance();

                walker.ContainsContinueStatement = false;

                bool containsContinueStatement = false;

                foreach (StatementSyntax innerStatement in innerStatements)
                {
                    walker.Visit(innerStatement);

                    if (walker.ContainsContinueStatement)
                    {
                        containsContinueStatement = true;
                        break;
                    }
                }

                ContainsContinueStatementWalker.Free(walker);

                return(containsContinueStatement);
            }

            bool IsLocalVariableReferencedAfterWhileStatement()
            {
                ContainsLocalOrParameterReferenceWalker walker = ContainsLocalOrParameterReferenceWalker.GetInstance(symbol, semanticModel, cancellationToken);

                walker.VisitList(outerStatements, index + 1);

                return(ContainsLocalOrParameterReferenceWalker.GetResultAndFree(walker));
            }
        }