protected override bool IsFixable(StatementSyntax statement, 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), statement))
                return false;

            ContainsYieldWalker walker = ContainsYieldWalker.GetInstance();

            bool success = false;

            int index = statements.IndexOf(statement);

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

                success = walker.YieldStatement != null;

                if (success)
                    break;
            }

            ContainsYieldWalker.Free(walker);

            return success;
        }
Exemplo n.º 2
0
        private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
        {
            var methodDeclaration = (MethodDeclarationSyntax)context.Node;

            BlockSyntax body = methodDeclaration.Body;

            if (body == null)
            {
                return;
            }

            ParameterListSyntax parameterList = methodDeclaration.ParameterList;

            if (parameterList == null)
            {
                return;
            }

            if (!parameterList.Parameters.Any())
            {
                return;
            }

            SyntaxList <StatementSyntax> statements = body.Statements;

            int statementCount = statements.Count;

            int index = -1;

            for (int i = 0; i < statementCount; i++)
            {
                if (IsNullCheck(statements[i]))
                {
                    index++;
                }
                else
                {
                    break;
                }
            }

            if (index == -1)
            {
                return;
            }

            if (index == statementCount - 1)
            {
                return;
            }

            TextSpan span = TextSpan.FromBounds(statements[index + 1].SpanStart, statements.Last().Span.End);

            if (body.ContainsUnbalancedIfElseDirectives(span))
            {
                return;
            }

            context.CancellationToken.ThrowIfCancellationRequested();

            ContainsYieldWalker walker = ContainsYieldWalker.GetInstance();

            walker.VisitBlock(body);

            YieldStatementSyntax yieldStatement = walker.YieldStatement;

            ContainsYieldWalker.Free(walker);

            if (yieldStatement == null)
            {
                return;
            }

            if (yieldStatement.SpanStart < statements[index].Span.End)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context,
                                               DiagnosticDescriptors.ValidateArgumentsCorrectly,
                                               Location.Create(body.SyntaxTree, new TextSpan(statements[index + 1].SpanStart, 0)));
        }
        public static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
        {
            var methodDeclaration = (MethodDeclarationSyntax)context.Node;

            BlockSyntax body = methodDeclaration.Body;

            if (body == null)
            {
                return;
            }

            ParameterListSyntax parameterList = methodDeclaration.ParameterList;

            if (parameterList == null)
            {
                return;
            }

            if (parameterList.Parameters.Count == 0)
            {
                return;
            }

            SyntaxList <StatementSyntax> statements = body.Statements;

            int statementCount = statements.Count;

            if (statementCount == 0)
            {
                return;
            }

            if (!IsNullCheck(statements[0]))
            {
                return;
            }

            context.CancellationToken.ThrowIfCancellationRequested();

            ContainsYieldWalker walker = ContainsYieldWalker.Cache.GetInstance();

            walker.VisitBlock(body);

            YieldStatementSyntax yieldStatement = walker.YieldStatement;

            ContainsYieldWalker.Cache.Free(walker);

            if (yieldStatement == null)
            {
                return;
            }

            int index = 0;

            for (int i = 1; i < statementCount; i++)
            {
                if (IsNullCheck(statements[i]))
                {
                    index++;
                }
                else
                {
                    break;
                }
            }

            if (yieldStatement.SpanStart < statements[index].Span.End)
            {
                return;
            }

            context.ReportDiagnostic(
                DiagnosticDescriptors.ValidateArgumentsCorrectly,
                Location.Create(body.SyntaxTree, new TextSpan(statements[index + 1].SpanStart, 0)));
        }
Exemplo n.º 4
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AssignDefaultValueToOutParameter))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    predicate: f => f.IsKind(SyntaxKind.MethodDeclaration) || f is StatementSyntax))
            {
                return;
            }

            Diagnostic diagnostic = context.Diagnostics[0];

            StatementSyntax statement = null;

            if (!node.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement))
            {
                statement = (StatementSyntax)node;

                node = node.FirstAncestor(f => f.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement));

                Debug.Assert(node != null, "Containing method or local function not found.");

                if (node == null)
                {
                    return;
                }
            }

            SyntaxNode bodyOrExpressionBody = GetBodyOrExpressionBody(node);

            if (bodyOrExpressionBody == null)
            {
                return;
            }

            if (ContainsYieldWalker.ContainsYield(bodyOrExpressionBody))
            {
                return;
            }

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

            DataFlowAnalysis dataFlowAnalysis = AnalyzeDataFlow(bodyOrExpressionBody, semanticModel);

            // Flow analysis APIs do not work with local functions: https://github.com/dotnet/roslyn/issues/14214
            if (!dataFlowAnalysis.Succeeded)
            {
                return;
            }

            var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(node);

            ImmutableArray <IParameterSymbol> parameters = methodSymbol.Parameters;

            ImmutableArray <ISymbol> alwaysAssigned = dataFlowAnalysis.AlwaysAssigned;

            IParameterSymbol singleParameter = null;
            bool             isAny           = false;

            foreach (IParameterSymbol parameter in parameters)
            {
                if (parameter.RefKind == RefKind.Out &&
                    !alwaysAssigned.Contains(parameter))
                {
                    if (singleParameter == null)
                    {
                        singleParameter = parameter;
                        isAny           = true;
                    }
                    else
                    {
                        singleParameter = null;
                        break;
                    }
                }
            }

            Debug.Assert(isAny, "No unassigned 'out' parameter found.");

            if (!isAny)
            {
                return;
            }

            CodeAction codeAction = CodeAction.Create(
                (singleParameter != null)
                    ? $"Assign default value to parameter '{singleParameter.Name}'"
                    : "Assign default value to parameters",
                cancellationToken => RefactorAsync(context.Document, node, statement, bodyOrExpressionBody, parameters, alwaysAssigned, semanticModel, cancellationToken),
                base.GetEquivalenceKey(diagnostic));

            context.RegisterCodeFix(codeAction, diagnostic);
        }