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); }
private bool IsParameterReferencedIn(SyntaxNode searchArea) { return(DataFlowAnalysisHelper.IsIdentifierReferencedIn( _parameterName, _parameterSymbol, _semanticModel, searchArea)); }
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); }
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)); }
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); }