Exemple #1
0
        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));
        }
Exemple #2
0
        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)
 {
 }
Exemple #4
0
 public YieldReturnConverter(
     ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo,
     YieldStatementSyntax yieldReturnStatement,
     YieldStatementSyntax yieldBreakStatement
     ) : base(forEachInfo)
 {
     _yieldReturnStatement = yieldReturnStatement;
     _yieldBreakStatement  = yieldBreakStatement;
 }
Exemple #5
0
        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;
 }
Exemple #7
0
        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));
        }
Exemple #8
0
        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));
        }
Exemple #9
0
 protected override IConverter <ForEachStatementSyntax, StatementSyntax> CreateDefaultConverter(
     ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo)
 => new DefaultConverter(forEachInfo);
Exemple #10
0
        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);
        }
Exemple #11
0
 protected abstract void ConvertToForStatement(
     SemanticModel model, ForEachInfo info, SyntaxEditor editor, CancellationToken cancellationToken);
Exemple #12
0
 protected abstract bool ValidLocation(ForEachInfo foreachInfo);
Exemple #13
0
 public AbstractConverter(ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo)
 {
     ForEachInfo = forEachInfo;
 }
Exemple #14
0
        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();
        }
Exemple #15
0
 public DefaultConverter(ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo)
     : base(forEachInfo)
 {
 }
Exemple #16
0
 > CreateDefaultConverter(
 ForEachInfo <ForEachStatementSyntax, StatementSyntax> forEachInfo
 ) => new DefaultConverter(forEachInfo);