Example #1
0
        public static bool TryGetAction(
            ForEachStatementSyntax forEachStatement,
            SemanticModel semanticModel,
            out Func <SyntaxNode, SyntaxNode> action)
        {
            var collectionExpression = forEachStatement.Expression;

            var collectionType = semanticModel.GetTypeInfo(collectionExpression).Type;

            string lengthMemberName;

            bool hasLengthAndIndexer = DataFlowAnalysisHelper.HasLengthAndGetIndexer(
                collectionType,
                out lengthMemberName);

            if (!hasLengthAndIndexer)
            {
                action = null;
                return(false);
            }

            action = syntaxRoot =>
            {
                var forStatement = ConvertToFor(forEachStatement, semanticModel, lengthMemberName);

                var newRoot = syntaxRoot.ReplaceNode((SyntaxNode)forEachStatement, forStatement);

                return(newRoot.Format());
            };

            return(true);
        }
Example #2
0
 private bool IsParameterReferencedIn(SyntaxNode searchArea)
 {
     return(DataFlowAnalysisHelper.IsIdentifierReferencedIn(
                _parameterName,
                _parameterSymbol,
                _semanticModel,
                searchArea));
 }
Example #3
0
        private static ForEachStatementSyntax ConvertToForeach(
            ForStatementSyntax forStatement,
            SemanticModel semanticModel)
        {
            ExpressionSyntax collectionExpression;
            SimpleNameSyntax lengthMember;

            TryExtractCollectionInfo(
                (BinaryExpressionSyntax)forStatement.Condition,
                out collectionExpression,
                out lengthMember);

            var collectionType = semanticModel.GetTypeInfo(collectionExpression).Type;

            ITypeSymbol elementType = SymbolHelper.GetCollectionElementTypeSymbol(collectionType);

            string elementTypeName = elementType.ToMinimalDisplayString(semanticModel, forStatement.SpanStart);

            ISymbol collectionSymbol;
            string  collectionPartName;

            DataFlowAnalysisHelper.TryGetCollectionInfo(
                collectionExpression,
                semanticModel,
                out collectionPartName,
                out collectionSymbol);

            var iterationVarName = NameHelper.GetIterationVariableName(
                collectionPartName,
                elementType,
                forStatement.Statement.SpanStart,
                semanticModel);

            var iterationIdentifier = SyntaxFactory
                                      .IdentifierName(iterationVarName)
                                      .WithAdditionalAnnotations(RenameAnnotation.Create());

            var rewriter = new ForToForeachLoopBodyRewriter(
                iterationIdentifier,
                collectionPartName,
                collectionSymbol,
                semanticModel);

            var newBody = (StatementSyntax)forStatement.Statement.Accept(rewriter);

            var foreachStatement = SyntaxFactory.ForEachStatement(
                SyntaxFactory.ParseTypeName(elementTypeName),
                iterationIdentifier.Identifier.WithAdditionalAnnotations(RenameAnnotation.Create()),
                collectionExpression,
                newBody);

            foreachStatement = foreachStatement.WithTriviaFrom(forStatement);

            return(foreachStatement);
        }
Example #4
0
        private static InvocationExpressionSyntax SplitFunctionComposition(
            InvocationExpressionSyntax selectInvocation,
            SimpleLambdaExpressionSyntax projection,
            InvocationExpressionSyntax[] invocationStack,
            SemanticModel semanticModel)
        {
            var lambdaParameter = projection.Parameter;
            var parameterName   = lambdaParameter.Identifier.Text;
            var parameterSymbol = semanticModel.GetDeclaredSymbol(lambdaParameter);

            Func <InvocationExpressionSyntax, bool> isNeedToReplaceInvocation = i =>
                                                                                DataFlowAnalysisHelper.IsIdentifierReferencedIn(
                parameterName,
                parameterSymbol,
                semanticModel,
                i);

            var newSelectInvocation = ExtendedSyntaxFactory.MakeInvocationWithLambdaArgument(
                selectInvocation.Expression,
                lambdaParameter,
                invocationStack[0]);

            var invocationReplacer = new InvocationReplacer(
                isNeedToReplaceInvocation,
                SyntaxFactory.IdentifierName(parameterName));

            for (int i = 1; i < invocationStack.Length; ++i)
            {
                var innerInvocation = invocationStack[i];

                var processedInnerInvocation = ReplaceInvocationsInArguments(
                    innerInvocation,
                    invocationReplacer);

                var memberAccess = SyntaxFactory.MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    newSelectInvocation,
                    SyntaxFactory.IdentifierName(LinqHelper.SelectMethodName));

                newSelectInvocation = ExtendedSyntaxFactory.MakeInvocationWithLambdaArgument(
                    memberAccess,
                    lambdaParameter,
                    processedInnerInvocation);
            }

            return(newSelectInvocation.WithTriviaFrom(selectInvocation));
        }
Example #5
0
        private static bool IsConvertibleToForeach(ForStatementSyntax forStatement, SemanticModel semanticModel)
        {
            var declaration  = forStatement.Declaration;
            var initializers = forStatement.Initializers;
            var condition    = forStatement.Condition;
            var incrementors = forStatement.Incrementors;

            //
            // Initializers list must be empty;
            // Declaration must declare exactly one variable;
            // Condition must be "less than expression";
            // Incrementors list must have exactly one item which should be pre- or post-increment.
            //

            if (declaration == null ||
                initializers.Count != 0 ||
                condition == null || !condition.IsKind(SyntaxKind.LessThanExpression) ||
                declaration.Variables.Count != 1 ||
                incrementors.Count != 1 ||
                (!incrementors[0].IsKind(SyntaxKind.PreIncrementExpression) &&
                 !incrementors[0].IsKind(SyntaxKind.PostIncrementExpression)))
            {
                return(false);
            }

            //
            // Declarations must be of type System.Int32
            //

            var typeSymbol = semanticModel.GetSymbolInfo(declaration.Type).Symbol as INamedTypeSymbol;

            if (typeSymbol == null || typeSymbol.SpecialType != SpecialType.System_Int32)
            {
                return(false);
            }

            // Retrieve counter identifier
            var counterIdentifier = declaration.Variables[0].Identifier;

            //
            // Retrieve increment operand
            //

            ExpressionSyntax incrementOperand;

            if (incrementors[0].IsKind(SyntaxKind.PostIncrementExpression))
            {
                var postIncrement = (PostfixUnaryExpressionSyntax)incrementors[0];
                incrementOperand = postIncrement.Operand;
            }
            else
            {
                var preIncrement = (PrefixUnaryExpressionSyntax)incrementors[0];
                incrementOperand = preIncrement.Operand;
            }

            //
            // Increment operand must be identifier
            //

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

            //
            // Increment operand must be the same as declared variable
            //

            var incrementOperandIdentifier = (IdentifierNameSyntax)incrementOperand;

            if (incrementOperandIdentifier.Identifier.Text != counterIdentifier.Text)
            {
                return(false);
            }

            //
            // Retrieve less than expression
            //

            var lessThanCondition = (BinaryExpressionSyntax)condition;

            //
            // Left operand must be the same variable as declared variable
            //

            if (!lessThanCondition.Left.IsKind(SyntaxKind.IdentifierName))
            {
                return(false);
            }

            var conditionLeftOperand = (IdentifierNameSyntax)lessThanCondition.Left;

            if (conditionLeftOperand.Identifier.Text != counterIdentifier.Text)
            {
                return(false);
            }

            //
            // Process right operand.
            //

            ExpressionSyntax collectionExpression;
            SimpleNameSyntax lengthMember;

            if (!TryExtractCollectionInfo(lessThanCondition, out collectionExpression, out lengthMember))
            {
                return(false);
            }

            //
            // Collection member name must be "Length" or "Count"
            //

            var lengthMemberName = lengthMember.Identifier.Text;

            if (lengthMemberName != "Length" && lengthMemberName != "Count")
            {
                return(false);
            }

            var collectionType = semanticModel.GetTypeInfo(collectionExpression).Type;

            if (!SymbolHelper.IsCollection(collectionType))
            {
                return(false);
            }

            //if (collectionType.TypeKind != TypeKind.ArrayType
            //    && !collectionType.AllInterfaces.Any(i =>
            //            i.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) ==
            //            "global::System.Collections.IEnumerable"
            //       )
            //)
            //{
            //    return false;
            //}

            //
            // Body of the loop mustn't modify collection elements and counter
            //

            bool isLoopBodyOnlyReadsCurrentItem = DataFlowAnalysisHelper.IsLoopBodyReadsOnlyCurrentItem(
                forStatement.Statement,
                semanticModel,
                collectionExpression,
                counterIdentifier.Text);

            return(isLoopBodyOnlyReadsCurrentItem);
        }