public static IEnumerable<ReplaceAction> GetSimplifications(ForEachStatementSyntax forLoop, ISemanticModel model, Assumptions assume, CancellationToken cancellationToken = default(CancellationToken)) { var body = forLoop.Statement.Statements(); if (body.None()) yield break; var unconditionalStatements = body.Skip(1); var conditionalStatement = body.First() as IfStatementSyntax; if (conditionalStatement == null) yield break; var trueBranch = conditionalStatement.Statement.Statements().AppendUnlessJumps(unconditionalStatements).Block(); var falseBranch = conditionalStatement.ElseStatementOrEmptyBlock().Statements().AppendUnlessJumps(unconditionalStatements).Block(); var falseIsEmpty = falseBranch.HasSideEffects(model, assume) == false; var trueIsEmpty = trueBranch.HasSideEffects(model, assume) == false; if (falseIsEmpty == trueIsEmpty) yield break; var condition = falseIsEmpty ? conditionalStatement.Condition : conditionalStatement.Condition.Inverted(); var conditionalActions = falseIsEmpty ? trueBranch : falseBranch; var query = forLoop.Expression.Accessing("Where").Invoking(forLoop.Identifier.Lambdad(condition).Args1()); var forWhereDo = forLoop.WithExpression(query).WithStatement(conditionalActions); yield return new ReplaceAction( "Filter collection", forLoop, forWhereDo); }
private async Task <Document> ConvertVariableAssignmentToLINQ(Document document, VariableDeclaratorSyntax variableDeclarator, ForEachStatementSyntax foreachStatement, CancellationToken c) { var generator = SyntaxGenerator.GetGenerator(document); var oldVariableName = foreachStatement.Identifier.Text; var newVariableName = variableDeclarator.Identifier.Text; var oldVariables = variableDeclarator.Initializer.Value.DescendantNodesAndSelf().OfType <IdentifierNameSyntax>().Where(x => x.Identifier.Text == oldVariableName); var selectCall = generator.InvocationExpression( generator.MemberAccessExpression(foreachStatement.Expression, "Select"), generator.Argument( generator.ValueReturningLambdaExpression( new[] { generator.LambdaParameter("x") }, variableDeclarator.Initializer.Value.ReplaceNodes(oldVariables, (x, y) => generator.IdentifierName("x"))))); var root = await document.GetSyntaxRootAsync(c); Debug.WriteLine(variableDeclarator.Parent); var restOfForeachBody = foreachStatement.Statement .RemoveNode(variableDeclarator, SyntaxRemoveOptions.AddElasticMarker) .WithAdditionalAnnotations(Formatter.Annotation); var newFeStatement = foreachStatement .WithExpression((ExpressionSyntax)selectCall) .WithIdentifier(generator.IdentifierName(newVariableName).GetFirstToken()) .WithStatement(restOfForeachBody); var newRoot = root.ReplaceNode(foreachStatement, newFeStatement); var withEmptyVariableDeclarationsRemoved = new RemoveEmptyVariableDeclarationSyntax().Visit(newRoot); return(document.WithSyntaxRoot(withEmptyVariableDeclarationsRemoved)); }
private async Task <Document> ConvertIfContinueToLINQ(Document document, IfStatementSyntax ifStatement, ForEachStatementSyntax foreachStatement, CancellationToken c) { var generator = SyntaxGenerator.GetGenerator(document); var oldVariables = ifStatement.Condition.DescendantNodesAndSelf().OfType <IdentifierNameSyntax>().Where(x => x.Identifier.Text == foreachStatement.Identifier.Text); var whereCall = generator.InvocationExpression( generator.MemberAccessExpression(foreachStatement.Expression, "Where"), generator.Argument( generator.ValueReturningLambdaExpression( new[] { generator.LambdaParameter("x") }, generator.LogicalNotExpression( ifStatement.Condition.ReplaceNodes(oldVariables, (x, y) => generator.IdentifierName("x")))))); var root = await document.GetSyntaxRootAsync(c); var restOfForeachBody = foreachStatement.Statement .ReplaceNode(ifStatement, ifStatement.Else?.Statement) .WithAdditionalAnnotations(Formatter.Annotation); var newFeStatement = foreachStatement .WithExpression((ExpressionSyntax)whereCall) .WithStatement(restOfForeachBody); var newRoot = root.ReplaceNode(foreachStatement, newFeStatement); return(document.WithSyntaxRoot(newRoot)); }
public static IEnumerable<ReplaceAction> GetSimplifications(ForEachStatementSyntax forLoop, ISemanticModel model, Assumptions assume, CancellationToken cancellationToken = default(CancellationToken)) { // loop uses iterator once? var declaredSymbol = model.GetDeclaredSymbol(forLoop); var singleRead = forLoop.Statement.DescendantNodes() .OfType<SimpleNameSyntax>() .Where(e => model.GetSymbolInfo(e).Symbol == declaredSymbol) .SingleOrDefaultAllowMany(); if (singleRead == null) yield break; // safe iterator projection? var guaranteedProjectionPerIteration = forLoop.Statement.CompleteExecutionGuaranteesChildExecutedExactlyOnce(singleRead); var projection = singleRead.AncestorsAndSelf() .TakeWhile(e => !(e is StatementSyntax)) .OfType<ExpressionSyntax>() .TakeWhile(e => model.GetTypeInfo(e).Type.SpecialType != SpecialType.System_Void) .TakeWhile(e => guaranteedProjectionPerIteration == true || e.HasSideEffects(model, assume) == false) .LastOrDefault(); if (projection == null) yield break; if (projection.TryEvalAlternativeComparison(singleRead, model, assume) == true) yield break; // build replacement loop var projectedCollection = forLoop.Expression .Accessing("Select") .Invoking(forLoop.Identifier.Lambdad(projection).Args1()); var newBody = forLoop.Statement.ReplaceNode(projection, singleRead); var replacedLoop = forLoop.WithExpression(projectedCollection).WithStatement(newBody); // expose as code action/issue yield return new ReplaceAction( "Project collection", forLoop, replacedLoop); }
public override SyntaxNode VisitForEachStatement(ForEachStatementSyntax node) { if (node != this.ContainerOfStatementsOrFieldToReplace) { return(base.VisitForEachStatement(node)); } return(node.WithExpression(VisitNode(node.Expression)) .WithStatement(ReplaceStatementIfNeeded(node.Statement))); }