Beispiel #1
0
        private static void RemoveExpression(DocumentEditor editor, ArgumentSyntax argument, IMethodSymbol invoker, bool usesUnderscoreNames, CancellationToken cancellationToken)
        {
            var invocation = argument.FirstAncestorOrSelf <InvocationExpressionSyntax>();

            if (PropertyChanged.TryGetInvokedPropertyChangedName(invocation, editor.SemanticModel, cancellationToken, out var name) == AnalysisResult.Yes)
            {
                var property = editor.SemanticModel.GetDeclaredSymbolSafe(argument.FirstAncestorOrSelf <PropertyDeclarationSyntax>(), cancellationToken);
                if (property?.Name == name)
                {
                    editor.ReplaceNode(
                        invocation,
                        SyntaxFactory.ParseExpression(Snippet.OnPropertyChanged(invoker, property?.Name, usesUnderscoreNames).TrimEnd(';'))
                        .WithSimplifiedNames()
                        .WithLeadingElasticLineFeed()
                        .WithTrailingElasticLineFeed()
                        .WithAdditionalAnnotations(Formatter.Annotation));
                }
                else
                {
                    editor.ReplaceNode(
                        invocation,
                        SyntaxFactory.ParseExpression(Snippet.OnOtherPropertyChanged(invoker, name, usesUnderscoreNames).TrimEnd(';'))
                        .WithSimplifiedNames()
                        .WithLeadingElasticLineFeed()
                        .WithTrailingElasticLineFeed()
                        .WithAdditionalAnnotations(Formatter.Annotation));
                }
            }
        }
        private static bool VariableIsNotUsedBeforePassedAsOutArgument(SemanticModel semanticModel, VariableDeclaratorSyntax variableDeclarator, ArgumentSyntax argument)
        {
            var firstStatement = variableDeclarator.FirstAncestorOrSelf <StatementSyntax>();
            var lastStatement  = argument.FirstAncestorOrSelf <StatementSyntax>().PrecedingSyblingOrSelf();


            DataFlowAnalysis dataFlow;

            try
            {
                // TODO-IG: Implement a proprietary data flow analysis that will work over statements that do not have same parent.
                //          The AnalyzeDataFlow() method will throw exception if the firstStatement and the lastStatement are
                //          not within the same immediate parent statement. We have to implement a data flow analysis that will
                //          accept statements that have a common root parent statement, but are not necessarily within the same
                //          immediate parent statement.
                dataFlow = semanticModel.AnalyzeDataFlow(firstStatement, lastStatement);
            }
            catch
            {
                // TODO-IG: Remove the try-catch block once the data flow analysis is implemented.
                //          At the moment, if the firstStatement and the lastStatement are not within the same immediate parent
                //          we will simply assume that the variable is used, although this must not actually be the case.
                //          Such cases will anyway appear rarely, so we can live with it so far.
                return(false);
            }

            var outVariableName = variableDeclarator.Identifier.ValueText;

            return(dataFlow.ReadInside.Union(dataFlow.WrittenInside).All(symbol => symbol.Name != outVariableName));
        }
Beispiel #3
0
        private static void ApplyFixGU0005(DocumentEditor editor, ArgumentSyntax nameArgument, CancellationToken cancellationToken)
        {
            var argumentListSyntax = nameArgument.FirstAncestorOrSelf <ArgumentListSyntax>();
            var arguments          = new ArgumentSyntax[argumentListSyntax.Arguments.Count];
            var method             = editor.SemanticModel.GetSymbolSafe(argumentListSyntax.Parent, cancellationToken) as IMethodSymbol;
            var messageIndex       = ParameterIndex(method, "message");
            var nameIndex          = ParameterIndex(method, "paramName");

            for (var i = 0; i < argumentListSyntax.Arguments.Count; i++)
            {
                if (i == messageIndex)
                {
                    arguments[nameIndex] = argumentListSyntax.Arguments[i];
                    continue;
                }

                if (i == nameIndex)
                {
                    arguments[messageIndex] = argumentListSyntax.Arguments[i];
                    continue;
                }

                arguments[i] = argumentListSyntax.Arguments[i];
            }

            var updated = argumentListSyntax.WithArguments(SyntaxFactory.SeparatedList(arguments, argumentListSyntax.Arguments.GetSeparators()));

            editor.ReplaceNode(argumentListSyntax, updated);
        }
Beispiel #4
0
        private static Task <Document> ApplyFixGU0005Async(CancellationToken cancellationToken, CodeFixContext context, SemanticModel semanticModel, ArgumentSyntax nameArgument)
        {
            var argumentListSyntax = nameArgument.FirstAncestorOrSelf <ArgumentListSyntax>();
            var arguments          = new ArgumentSyntax[argumentListSyntax.Arguments.Count];
            var method             = semanticModel.GetSymbolSafe(argumentListSyntax.Parent, cancellationToken) as IMethodSymbol;
            var messageIndex       = ParameterIndex(method, "message");
            var nameIndex          = ParameterIndex(method, "paramName");

            for (var i = 0; i < argumentListSyntax.Arguments.Count; i++)
            {
                if (i == messageIndex)
                {
                    arguments[nameIndex] = argumentListSyntax.Arguments[i];
                    continue;
                }

                if (i == nameIndex)
                {
                    arguments[messageIndex] = argumentListSyntax.Arguments[i];
                    continue;
                }

                arguments[i] = argumentListSyntax.Arguments[i];
            }

            var updated = argumentListSyntax.WithArguments(SyntaxFactory.SeparatedList(arguments, argumentListSyntax.Arguments.GetSeparators()));

            return(Task.FromResult(context.Document.WithSyntaxRoot(semanticModel.SyntaxTree.GetRoot().ReplaceNode(argumentListSyntax, updated))));
        }
Beispiel #5
0
        internal static bool TryGetRegisteredName(ArgumentSyntax callback, SemanticModel semanticModel, CancellationToken cancellationToken, out string registeredName)
        {
            registeredName = null;
            if (callback == null)
            {
                return(false);
            }

            var fieldDeclaration   = callback.FirstAncestorOrSelf <VariableDeclaratorSyntax>();
            var dependencyProperty = semanticModel.GetDeclaredSymbol(fieldDeclaration) as IFieldSymbol;

            return(DependencyProperty.TryGetRegisteredName(dependencyProperty, semanticModel, cancellationToken, out registeredName));
        }
Beispiel #6
0
        internal static bool TryGetRegisteredName(ArgumentSyntax callback, SemanticModel semanticModel, CancellationToken cancellationToken, out string registeredName)
        {
            registeredName = null;
            var invocation   = callback?.FirstAncestorOrSelf <InvocationExpressionSyntax>();
            var memberAccess = invocation?.Expression as MemberAccessExpressionSyntax;

            if (memberAccess == null)
            {
                return(false);
            }

            var method = semanticModel.GetSymbolSafe(invocation, cancellationToken) as IMethodSymbol;

            if (method == KnownSymbol.DependencyProperty.OverrideMetadata ||
                method == KnownSymbol.DependencyProperty.AddOwner)
            {
                var dependencyProperty = semanticModel.GetSymbolSafe(memberAccess.Expression, cancellationToken) as IFieldSymbol;
                if (dependencyProperty?.Type != KnownSymbol.DependencyProperty)
                {
                    return(false);
                }

                return(DependencyProperty.TryGetRegisteredName(dependencyProperty, semanticModel, cancellationToken, out registeredName));
            }

            if (method == KnownSymbol.DependencyProperty.Register ||
                method == KnownSymbol.DependencyProperty.RegisterReadOnly ||
                method == KnownSymbol.DependencyProperty.RegisterAttached ||
                method == KnownSymbol.DependencyProperty.RegisterAttachedReadOnly)
            {
                var fieldDeclaration = callback.FirstAncestorOrSelf <VariableDeclaratorSyntax>();
                if (fieldDeclaration == null)
                {
                    return(false);
                }

                var dependencyProperty = semanticModel.GetDeclaredSymbolSafe(fieldDeclaration, cancellationToken) as IFieldSymbol;
                if (dependencyProperty == null)
                {
                    return(false);
                }

                return(DependencyProperty.TryGetRegisteredName(dependencyProperty, semanticModel, cancellationToken, out registeredName));
            }

            return(false);
        }
        internal static int ArgumentIndex(ArgumentSyntax argument)
        {
            var argumentListExpression = argument.FirstAncestorOrSelf <ArgumentListSyntax>();

            if (argumentListExpression == null)
            {
                return(-1);
            }

            for (var i = 0; i < argumentListExpression.Arguments.Count; i++)
            {
                if (argumentListExpression.Arguments[i] == argument)
                {
                    return(i);
                }
            }

            return(-1);
        }
        internal static bool TryGetParameter(this ArgumentSyntax argument, SemanticModel semanticModel, CancellationToken cancellationToken, out IParameterSymbol result)
        {
            var invocation = (SyntaxNode)argument.FirstAncestor <InvocationExpressionSyntax>() ??
                             argument.FirstAncestor <ConstructorInitializerSyntax>();
            var method = (IMethodSymbol)semanticModel.GetSymbolSafe(invocation, cancellationToken);

            result = null;
            if (argument == null ||
                method?.Parameters == null)
            {
                return(false);
            }

            if (argument.NameColon == null)
            {
                var index = argument.FirstAncestorOrSelf <ArgumentListSyntax>()
                            .Arguments.IndexOf(argument);
                if (method.Parameters.TryElementAt(index, out result))
                {
                    return(true);
                }

                var temp = method.Parameters[method.Parameters.Length - 1];
                if (temp.IsParams)
                {
                    result = temp;
                    return(true);
                }

                return(false);
            }

            foreach (var candidate in method.Parameters)
            {
                if (candidate.Name == argument.NameColon.Name.Identifier.ValueText)
                {
                    result = candidate;
                    return(true);
                }
            }

            return(false);
        }
Beispiel #9
0
        public override void VisitArgument(ArgumentSyntax node)
        {
            if (this.visitedLocations.Add(node) &&
                (node.RefOrOutKeyword.IsKind(SyntaxKind.RefKeyword) ||
                 node.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword)))
            {
                var invocation = node.FirstAncestorOrSelf <InvocationExpressionSyntax>();
                var argSymbol  = this.semanticModel.GetSymbolSafe(node.Expression, this.cancellationToken);
                if (invocation != null &&
                    (SymbolComparer.Equals(this.CurrentSymbol, argSymbol) ||
                     this.refParameters.Contains(argSymbol as IParameterSymbol)))
                {
                    var method = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken);
                    if (method != null &&
                        method.DeclaringSyntaxReferences.Length > 0)
                    {
                        foreach (var reference in method.DeclaringSyntaxReferences)
                        {
                            var methodDeclaration = reference.GetSyntax(this.cancellationToken) as MethodDeclarationSyntax;
                            if (methodDeclaration.TryGetMatchingParameter(node, out var parameterSyntax))
                            {
                                var parameterSymbol = this.semanticModel.GetDeclaredSymbolSafe(parameterSyntax, this.cancellationToken);
                                if (parameterSymbol != null)
                                {
                                    if (node.RefOrOutKeyword.IsKind(SyntaxKind.RefKeyword))
                                    {
                                        this.refParameters.Add(parameterSymbol).IgnoreReturnValue();
                                    }

                                    if (node.RefOrOutKeyword.IsKind(SyntaxKind.OutKeyword))
                                    {
                                        this.values.Add(node.Expression);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            base.VisitArgument(node);
        }
        internal static bool TryGetMatchingParameter(this BaseMethodDeclarationSyntax method, ArgumentSyntax argument, out ParameterSyntax parameter)
        {
            parameter = null;
            if (argument == null ||
                method?.ParameterList == null)
            {
                return(false);
            }

            if (argument.NameColon == null)
            {
                var index = argument.FirstAncestorOrSelf <ArgumentListSyntax>()
                            .Arguments.IndexOf(argument);
                if (method.ParameterList.Parameters.TryElementAt(index, out parameter))
                {
                    return(true);
                }

                parameter = method.ParameterList.Parameters.Last();
                foreach (var modifier in parameter.Modifiers)
                {
                    if (modifier.IsKind(SyntaxKind.ParamsKeyword))
                    {
                        return(true);
                    }
                }

                parameter = null;
                return(false);
            }

            foreach (var candidate in method.ParameterList.Parameters)
            {
                if (candidate.Identifier.ValueText == argument.NameColon.Name.Identifier.ValueText)
                {
                    parameter = candidate;
                    return(true);
                }
            }

            return(false);
        }
Beispiel #11
0
        private static int?FindParameterIndexCorrespondingToIndex(IMethodSymbol method, ArgumentSyntax argument)
        {
            if (argument.NameColon == null)
            {
                var index = argument.FirstAncestorOrSelf <ArgumentListSyntax>()
                            .Arguments.IndexOf(argument);
                return(index);
            }

            for (int i = 0; i < method.Parameters.Length; ++i)
            {
                var candidate = method.Parameters[i];
                if (candidate.Name == argument.NameColon.Name.Identifier.ValueText)
                {
                    return(i);
                }
            }

            return(null);
        }
Beispiel #12
0
        internal static Result IsArgumentDisposedByReturnValue(ArgumentSyntax argument, SemanticModel semanticModel, CancellationToken cancellationToken, PooledHashSet <SyntaxNode> visited = null)
        {
            if (argument?.Parent is ArgumentListSyntax argumentList)
            {
                if (argumentList.Parent is InvocationExpressionSyntax invocation &&
                    semanticModel.GetSymbolSafe(invocation, cancellationToken) is IMethodSymbol method)
                {
                    if (method.ContainingType.DeclaringSyntaxReferences.Length == 0)
                    {
                        if (method == KnownSymbol.CompositeDisposable.Add)
                        {
                            return(Result.Yes);
                        }

                        return(method.ReturnsVoid ||
                               !IsAssignableTo(method.ReturnType)
                            ? Result.No
                            : Result.AssumeYes);
                    }

                    if (invocation.TryGetMatchingParameter(argument, semanticModel, cancellationToken, out var parameter))
                    {
                        return(CheckReturnValues(parameter, invocation, semanticModel, cancellationToken, visited));
                    }

                    return(Result.Unknown);
                }

                if (argumentList.Parent is ObjectCreationExpressionSyntax ||
                    argumentList.Parent is ConstructorInitializerSyntax)
                {
                    if (TryGetAssignedFieldOrProperty(argument, semanticModel, cancellationToken, out var member, out var ctor) &&
                        member != null)
                    {
                        var initializer = argument.FirstAncestorOrSelf <ConstructorInitializerSyntax>();
                        if (initializer != null)
                        {
                            if (semanticModel.GetDeclaredSymbolSafe(initializer.Parent, cancellationToken) is IMethodSymbol chainedCtor &&
                                chainedCtor.ContainingType != member.ContainingType)
                            {
                                if (TryGetDelRefMethod(chainedCtor.ContainingType, Search.TopLevel, out var disposeMethod))
                                {
                                    return(IsMemberDisposed(member, disposeMethod, semanticModel, cancellationToken)
                                        ? Result.Yes
                                        : Result.No);
                                }
                            }
                        }

                        return(IsMemberDisposed(member, ctor.ContainingType, semanticModel, cancellationToken));
                    }

                    if (ctor == null)
                    {
                        return(Result.AssumeYes);
                    }

                    if (ctor.ContainingType.DeclaringSyntaxReferences.Length == 0)
                    {
                        return(IsAssignableTo(ctor.ContainingType) ? Result.AssumeYes : Result.No);
                    }

                    return(Result.No);
                }
            }

            return(Result.Unknown);
        }
Beispiel #13
0
        private static bool OutArgumentCanBecomeOutVariableOrCanBeDiscarded(SemanticModel semanticModel, ArgumentSyntax outArgument, bool outArgumentCanBeDiscarded)
        {
            var enclosingStatement    = outArgument.LastAncestorOrSelf <StatementSyntax>(); // E.g. method body block.
            var outArgumentIdentifier = (IdentifierNameSyntax)outArgument.Expression;
            var outVariableName       = outArgumentIdentifier.Identifier.ValueText;

            // 1. The enclosing expression (method/constructor call) must correspond to the TEnclosingExpressionSyntax type.
            var enclosingExpression = GetEnclosingExpression();

            if (enclosingExpression == null)
            {
                return(false);
            }

            // 2. The out argument must be a local variable.
            var variableDeclarator = GetLocalVariableDeclaratorForOutArgument();

            if (variableDeclarator == null)
            {
                return(false);
            }

            // 3. If the local variable is initialized within the declaration, it means that it is used.
            if (variableDeclarator.Initializer != null)
            {
                return(false);
            }


            // 4. The local variable must not be used before it is passed to the method/constructor as an out argument.
            //    Also, if it is a requirement that the out argument can be discarded, it must not be used
            //    anywhere in code after the out argument.

            var localVariableSymbol = semanticModel.GetSymbolInfo(outArgumentIdentifier).Symbol;

            if (localVariableSymbol == null)
            {
                return(false);
            }
            var localVariableTextSpan = variableDeclarator.Identifier.Span;
            var outArgumentTextSpan   = outArgumentIdentifier.Span;

            // Find all the usages of the local variable within the enclosing e.g. method body block
            // that are different then its declaration and the usage in the out variable itself.
            // Those usage then appear either between the variable declaration and the out argument
            // or after the out argument.
            var usagesOfTheLocalVariable = enclosingStatement
                                           .DescendantNodes()
                                           .OfType <IdentifierNameSyntax>()
                                           .Where(identifier =>
                                                  identifier.Identifier.ValueText == outVariableName &&
                                                  identifier.Span != localVariableTextSpan && // It is not the declaration of the local variable itself.
                                                  identifier != outArgumentIdentifier &&      // It is not the out argument itself.
                                                  semanticModel.GetSymbolInfo(identifier).Symbol?.Equals(localVariableSymbol) == true
                                                  )
                                           .ToList();

            var(numberOfUsagesBeforeOutArgument, numberOfUsagesAfterOutArgument) = usagesOfTheLocalVariable
                                                                                   .CountMany
                                                                                   (
                identifier => identifier.Identifier.Span.IsBetween(localVariableTextSpan, outArgumentTextSpan),
                identifier => identifier.Identifier.Span.IsAfter(outArgumentTextSpan)
                                                                                   );

            var localVariableCouldBecomeOutVariableOrDiscarded =
                numberOfUsagesBeforeOutArgument == 0 &&
                (
                    outArgumentCanBeDiscarded && numberOfUsagesAfterOutArgument == 0
                    ||
                    !outArgumentCanBeDiscarded && numberOfUsagesAfterOutArgument > 0
                );

            if (!localVariableCouldBecomeOutVariableOrDiscarded)
            {
                return(false);
            }

            // 5. If turned into out variable, the local variable identifier still has the
            //    scope that contains all of the usages of that identifier that originally
            //    appear in the code after the out variable declaration.

            // If it can be discarded there is no usages after the out argument.
            // Thus, there cannot be any issues with the scope.
            if (outArgumentCanBeDiscarded && numberOfUsagesAfterOutArgument == 0)
            {
                return(true);
            }

            var outVariableScope = GetOutVariableScope();

            // If we have reached here, all the usages of the local variable are actually
            // after the out argument. We have to check that they are all in the scope
            // of the out variable.
            return(usagesOfTheLocalVariable
                   .All(identifier => outVariableScope.IsAnyAncestorOfOrSelf(identifier, enclosingStatement.Parent)));

            // The enclosing expression can be only a method or constructor call.
            // We have to additionally check for the case where we have them nested ;-)
            ExpressionSyntax GetEnclosingExpression()
            {
                var result = outArgument.FirstAncestorOrSelf <TEnclosingExpressionSyntax>();

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

                // Check the possibly nested calls. E.g. Method(out j, new Constructor(out i));
                var potentialOtherEnclosingExpression = typeof(TEnclosingExpressionSyntax) == typeof(InvocationExpressionSyntax)
                                                        ? (ExpressionSyntax)outArgument.FirstAncestorOrSelf <ObjectCreationExpressionSyntax>()
                                                        : outArgument.FirstAncestorOrSelf <InvocationExpressionSyntax>();

                if (potentialOtherEnclosingExpression == null)
                {
                    // No nesting, just return the result.
                    return(result);
                }

                // Nesting. Check that the invocation of the type TEnclosingExpressionSyntax comes first.
                return(potentialOtherEnclosingExpression.IsAncestorOfOrSelf(result, enclosingStatement)
                    ? result
                    : null);
            }

            // Why an array here and not a single StatementSyntax node?
            // We have rare cases like e.g. for loop incrementors
            // where we do not have a single syntax node that would enclose
            // the scope but rather a list of mutually "disconnected" nodes.
            SyntaxNode[] GetOutVariableScope()
            {
                var potentialIfStatement = GetPotentialEnclosingIfStatement();

                if (potentialIfStatement != null)
                {
                    return new SyntaxNode[] { potentialIfStatement.FirstAncestorOrSelf <BlockSyntax>() }
                }
                ;

                var potentialSwitchStatement = GetPotentialEnclosingSwitchStatement();

                if (potentialSwitchStatement != null)
                {
                    return new SyntaxNode[] { potentialSwitchStatement.FirstAncestorOrSelf <BlockSyntax>() }
                }
                ;

                var potentialSwitchSection = GetPotentialEnclosingSwitchSection();

                if (potentialSwitchSection != null)
                {
                    return new SyntaxNode[] { (SwitchStatementSyntax)potentialSwitchSection.Parent }
                }
                ;

                var potentialWhileStatement = GetPotentialEnclosingWhileStatement();

                if (potentialWhileStatement != null)
                {
                    return new SyntaxNode[] { potentialWhileStatement }
                }
                ;

                // If the method/constructor invocation is within the while part of
                // a do-while statement the declared variable will not be visible anywhere
                // else but within that while part. Also, if we are checking that that method/constructor
                // invocation as a candidate to have an out variable, we know already that the
                // out variable is not used anywhere else in the do-while body.
                // In other words, the returned do-while statement will not contain any access
                // to the local variable that we want to turn into out variable.
                // Also, if the out variable is declared in the while part of the do-while loop,
                // it will not be visible after the while loop.
                // In other words, its new scope will be just the while part which is effectively
                // a kind of a "empty" scope.
                // Also, we ignore the usages like Method(out x, out x);
                var potentialDoStatement = GetPotentialEnclosingDoStatement();

                if (potentialDoStatement != null)
                {
                    return(new SyntaxNode[0]);
                }

                var potentialForStatement = GetPotentialEnclosingForStatement();

                if (potentialForStatement != null)
                {
                    return new SyntaxNode[] { potentialForStatement }
                }
                ;

                var potentialForIncrementors = GetPotentialEnclosingForIncrementors();

                if (potentialForIncrementors != default)
                {
                    return(potentialForIncrementors.Cast <SyntaxNode>().ToArray());
                }

                var potentialForEachStatement = GetPotentialEnclosingForEachStatement();

                if (potentialForEachStatement != null)
                {
                    return new SyntaxNode[] { potentialForEachStatement }
                }
                ;

                var potentialAnonymousFunction = GetPotentialEnclosingAnonymousFunction();

                if (potentialAnonymousFunction != null)
                {
                    return new SyntaxNode[] { potentialAnonymousFunction.Body }
                }
                ;

                // If it is nothing of the above, the method/constructor is called within some
                // "regular" block.
                return(new SyntaxNode[] { enclosingExpression.FirstAncestorOrSelf <BlockSyntax>() });

                AnonymousFunctionExpressionSyntax GetPotentialEnclosingAnonymousFunction()
                {
                    var anonymousFunction = enclosingExpression.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>();

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

                    // Method/constructor invocation is within an anonymous delegate or lambda expression.
                    // But we have to make sure that it is not within a separate block within that
                    // anonymous delegate or lambda expression.
                    var block = enclosingExpression.FirstAncestorOrSelf <BlockSyntax>();

                    // Why enclosingStatement.Parent?
                    // Anonymous functions in general do not have to have a block.
                    // So the above search for the first enclosing block could return
                    // the enclosingStatement itself.
                    // So in general case we have to step one step out of it.
                    return(anonymousFunction.IsAncestorOfOrSelf(block, enclosingStatement.Parent)
                        ? null
                        : anonymousFunction);
                }

                ForEachStatementSyntax GetPotentialEnclosingForEachStatement()
                {
                    var forEachStatement = enclosingExpression.FirstAncestorOrSelf <ForEachStatementSyntax>();

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

                    return(forEachStatement.Expression.IsAncestorOfOrSelf(enclosingExpression, forEachStatement)
                        ? forEachStatement
                        : null);
                }

                SeparatedSyntaxList <ExpressionSyntax> GetPotentialEnclosingForIncrementors()
                {
                    // Is the method/constructor invocation a part of incrementors of a for loop?
                    var forStatement = enclosingExpression.FirstAncestorOrSelf <ForStatementSyntax>();

                    if (forStatement == null)
                    {
                        return(default);