protected static SyntaxNode GetCollectionVariableName( SemanticModel model, SyntaxGenerator generator, ForEachInfo foreachInfo, SyntaxNode foreachCollectionExpression, CancellationToken cancellationToken ) { if (foreachInfo.RequireCollectionStatement) { return(generator.IdentifierName( CreateUniqueName( foreachInfo.SemanticFacts, model, foreachInfo.ForEachStatement, foreachInfo.CollectionNameSuggestion, cancellationToken ) )); } return(foreachCollectionExpression .WithoutTrivia() .WithAdditionalAnnotations(Formatter.Annotation)); }
protected void IntroduceCollectionStatement( SemanticModel model, ForEachInfo foreachInfo, SyntaxEditor editor, SyntaxNode type, SyntaxNode foreachCollectionExpression, SyntaxNode collectionVariable) { if (!foreachInfo.RequireCollectionStatement) { return; } // TODO: refactor introduce variable refactoring to real service and use that service here to introduce local variable var generator = editor.Generator; // attach rename annotation to control variable var collectionVariableToken = generator.Identifier(collectionVariable.ToString()).WithAdditionalAnnotations(RenameAnnotation.Create()); // this expression is from user code. don't simplify this. var expression = foreachCollectionExpression.WithoutAnnotations(SimplificationHelpers.DontSimplifyAnnotation); var collectionStatement = generator.LocalDeclarationStatement( type, collectionVariableToken, foreachInfo.RequireExplicitCastInterface ? generator.CastExpression(foreachInfo.ExplicitCastInterface, expression) : expression); // attach trivia to right place collectionStatement = collectionStatement.WithLeadingTrivia(foreachInfo.ForEachStatement.GetFirstToken().LeadingTrivia); editor.InsertBefore(foreachInfo.ForEachStatement, collectionStatement); }
public ToToListConverter( ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo, ExpressionSyntax selectExpression, ExpressionSyntax modifyingExpression, SyntaxTrivia[] trivia) : base(forEachInfo, selectExpression, modifyingExpression, trivia) { }
public YieldReturnConverter( ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo, YieldStatementSyntax yieldReturnStatement, YieldStatementSyntax yieldBreakStatement ) : base(forEachInfo) { _yieldReturnStatement = yieldReturnStatement; _yieldBreakStatement = yieldBreakStatement; }
private StatementSyntax CreateDefaultReplacementStatement( ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo, IEnumerable <SyntaxToken> identifiers, BlockSyntax block, bool convertToQuery) { var identifiersCount = identifiers.Count(); if (identifiersCount == 0) { // Generate foreach(var _ ... select new {}) return(SyntaxFactory.ForEachStatement( VarNameIdentifier, SyntaxFactory.Identifier("_"), CreateQueryExpressionOrLinqInvocation( SyntaxFactory.AnonymousObjectCreationExpression(), Enumerable.Empty <SyntaxToken>(), Enumerable.Empty <SyntaxToken>(), convertToQuery), block)); } else if (identifiersCount == 1) { // Generate foreach(var singleIdentifier from ... select singleIdentifier) return(SyntaxFactory.ForEachStatement( VarNameIdentifier, identifiers.Single(), CreateQueryExpressionOrLinqInvocation( SyntaxFactory.IdentifierName(identifiers.Single()), Enumerable.Empty <SyntaxToken>(), Enumerable.Empty <SyntaxToken>(), convertToQuery), block)); } else { var tupleForSelectExpression = SyntaxFactory.TupleExpression( SyntaxFactory.SeparatedList(identifiers.Select( identifier => SyntaxFactory.Argument(SyntaxFactory.IdentifierName(identifier))))); var declaration = SyntaxFactory.DeclarationExpression( VarNameIdentifier, SyntaxFactory.ParenthesizedVariableDesignation( SyntaxFactory.SeparatedList <VariableDesignationSyntax>(identifiers.Select( identifier => SyntaxFactory.SingleVariableDesignation(identifier))))); // Generate foreach(var (a,b) ... select (a, b)) return(SyntaxFactory.ForEachVariableStatement( declaration, CreateQueryExpressionOrLinqInvocation( tupleForSelectExpression, Enumerable.Empty <SyntaxToken>(), Enumerable.Empty <SyntaxToken>(), convertToQuery), block)); } }
public AbstractToMethodConverter( ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo, ExpressionSyntax selectExpression, ExpressionSyntax modifyingExpression, SyntaxTrivia[] trivia) : base(forEachInfo) { _selectExpression = selectExpression; _modifyingExpression = modifyingExpression; _trivia = trivia; }
protected override bool ValidLocation(ForEachInfo foreachInfo) { if (!foreachInfo.RequireCollectionStatement) { return(true); } // for now, we don't support converting in embedded statement if // new local declaration for collection is required. // we can support this by using Introduce local variable service // but the service is not currently written in a way that can be // easily reused here. return(foreachInfo.ForEachStatement.Parent.IsKind(SyntaxKind.Block)); }
private async Task <Document> ConvertForeachToForAsync( Document document, ForEachInfo foreachInfo, CancellationToken cancellationToken) { var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var workspace = document.Project.Solution.Workspace; var editor = new SyntaxEditor(model.SyntaxTree.GetRoot(cancellationToken), workspace); ConvertToForStatement(model, foreachInfo, editor, cancellationToken); var newRoot = editor.GetChangedRoot(); return(document.WithSyntaxRoot(newRoot)); }
protected override IConverter <ForEachStatementSyntax, StatementSyntax> CreateDefaultConverter( ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo) => new DefaultConverter(forEachInfo);
protected override bool TryBuildSpecificConverter( ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo, SemanticModel semanticModel, StatementSyntax statementCannotBeConverted, CancellationToken cancellationToken, out IConverter <ForEachStatementSyntax, StatementSyntax> converter) { switch (statementCannotBeConverted.Kind()) { case SyntaxKind.ExpressionStatement: var expresisonStatement = (ExpressionStatementSyntax)statementCannotBeConverted; var expression = expresisonStatement.Expression; switch (expression.Kind()) { case SyntaxKind.PostIncrementExpression: // Input: // foreach (var x in a) // { // ... // c++; // } // Output: // (from x in a ... select x).Count(); // Here we put SyntaxFactory.IdentifierName(forEachStatement.Identifier) ('x' in the example) // into the select clause. var postfixUnaryExpression = (PostfixUnaryExpressionSyntax)expression; var operand = postfixUnaryExpression.Operand; converter = new ToCountConverter( forEachInfo, selectExpression: SyntaxFactory.IdentifierName(forEachInfo.ForEachStatement.Identifier), modifyingExpression: operand, trivia: SyntaxNodeOrTokenExtensions.GetTrivia( operand, postfixUnaryExpression.OperatorToken, expresisonStatement.SemicolonToken)); return(true); case SyntaxKind.InvocationExpression: var invocationExpression = (InvocationExpressionSyntax)expression; // Check that there is 'list.Add(item)'. if (invocationExpression.Expression is MemberAccessExpressionSyntax memberAccessExpression && semanticModel.GetSymbolInfo(memberAccessExpression, cancellationToken).Symbol is IMethodSymbol methodSymbol && TypeSymbolOptIsList(methodSymbol.ContainingType, semanticModel) && methodSymbol.Name == nameof(IList.Add) && methodSymbol.Parameters.Length == 1 && invocationExpression.ArgumentList.Arguments.Count == 1) { // Input: // foreach (var x in a) // { // ... // list.Add(...); // } // Output: // (from x in a ... select x).ToList(); var selectExpression = invocationExpression.ArgumentList.Arguments.Single().Expression; converter = new ToToListConverter( forEachInfo, selectExpression, modifyingExpression: memberAccessExpression.Expression, trivia: SyntaxNodeOrTokenExtensions.GetTrivia( memberAccessExpression, invocationExpression.ArgumentList.OpenParenToken, invocationExpression.ArgumentList.CloseParenToken, expresisonStatement.SemicolonToken)); return(true); } break; } break; case SyntaxKind.YieldReturnStatement: var memberDeclarationSymbol = semanticModel.GetEnclosingSymbol( forEachInfo.ForEachStatement.SpanStart, cancellationToken); // Using Single() is valid even for partial methods. var memberDeclarationSyntax = memberDeclarationSymbol.DeclaringSyntaxReferences.Single().GetSyntax(); var yieldStatementsCount = memberDeclarationSyntax.DescendantNodes().OfType <YieldStatementSyntax>() // Exclude yield statements from nested local functions. .Where(statement => semanticModel.GetEnclosingSymbol( statement.SpanStart, cancellationToken) == memberDeclarationSymbol).Count(); if (forEachInfo.ForEachStatement.IsParentKind(SyntaxKind.Block) && forEachInfo.ForEachStatement.Parent.Parent == memberDeclarationSyntax) { // Check that // a. There are either just a single 'yield return' or 'yield return' with 'yield break' just after. // b. Those foreach and 'yield break' (if exists) are last statements in the method (do not count local function declaration statements). var statementsOnBlockWithForEach = ((BlockSyntax)forEachInfo.ForEachStatement.Parent).Statements .Where(statement => statement.Kind() != SyntaxKind.LocalFunctionStatement).ToArray(); var lastNonLocalFunctionStatement = statementsOnBlockWithForEach.Last(); if (yieldStatementsCount == 1 && lastNonLocalFunctionStatement == forEachInfo.ForEachStatement) { converter = new YieldReturnConverter( forEachInfo, (YieldStatementSyntax)statementCannotBeConverted, yieldBreakStatement: null); return(true); } // foreach() // { // yield return ...; // } // yield break; // end of member if (yieldStatementsCount == 2 && lastNonLocalFunctionStatement.Kind() == SyntaxKind.YieldBreakStatement && !lastNonLocalFunctionStatement.ContainsDirectives && statementsOnBlockWithForEach[statementsOnBlockWithForEach.Length - 2] == forEachInfo.ForEachStatement) { // This removes the yield break. converter = new YieldReturnConverter( forEachInfo, (YieldStatementSyntax)statementCannotBeConverted, yieldBreakStatement: (YieldStatementSyntax)lastNonLocalFunctionStatement); return(true); } } break; } converter = default; return(false); }
protected abstract void ConvertToForStatement( SemanticModel model, ForEachInfo info, SyntaxEditor editor, CancellationToken cancellationToken);
protected abstract bool ValidLocation(ForEachInfo foreachInfo);
public AbstractConverter(ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo) { ForEachInfo = forEachInfo; }
public static IEnumerator ForEachAsync <T>(string path, System.Action <T> action, System.Func <string, bool> isUsed = null, IEnumerator ator_end = null, ForEachInfo info = null) where T : AssetImporter { if (string.IsNullOrEmpty(path)) { Debug.Log("非法的目录:" + path); yield break; } if (path.EndsWith("/")) { path = path.Substring(0, path.Length - 1); } if (File.Exists(path)) { // 是个文件 T assetImporter = AssetImporter.GetAtPath(path) as T; if (assetImporter != null) { if (info != null) { info.total = 1; info.current = 0; } action(assetImporter); } } else { HashSet <string> guids = new HashSet <string>(AssetDatabase.FindAssets("", new string[] { path })); if (info != null) { info.total = guids.Count; info.current = -1; } List <string> ts = new List <string>(); foreach (string guid in guids) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); if (info != null) { info.current++; if ((info.current % 100) == 0) { yield return(0); } } if (assetPath == null) { continue; } if (isUsed != null && !isUsed(assetPath)) { continue; } T assetImporter = AssetImporter.GetAtPath(assetPath) as T; if (assetImporter != null) { action(assetImporter); yield return(0); } } } AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); if (ator_end != null) { while (ator_end.MoveNext()) { yield return(0); } } Resources.UnloadUnusedAssets(); System.GC.Collect(); }
public DefaultConverter(ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo) : base(forEachInfo) { }
> CreateDefaultConverter( ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo ) => new DefaultConverter(forEachInfo);