Ejemplo n.º 1
0
        protected override async Task FixAllAsync(
            Document document, ImmutableArray <Diagnostic> diagnostics,
            SyntaxEditor editor, CancellationToken cancellationToken)
        {
            // Fix-All for this feature is somewhat complicated.  As Collection-Initializers
            // could be arbitrarily nested, we have to make sure that any edits we make
            // to one Collection-Initializer are seen by any higher ones.  In order to do this
            // we actually process each object-creation-node, one at a time, rewriting
            // the tree for each node.  In order to do this effectively, we use the '.TrackNodes'
            // feature to keep track of all the object creation nodes as we make edits to
            // the tree.  If we didn't do this, then we wouldn't be able to find the
            // second object-creation-node after we make the edit for the first one.
            var workspace    = document.Project.Solution.Workspace;
            var syntaxFacts  = document.GetLanguageService <ISyntaxFactsService>();
            var originalRoot = editor.OriginalRoot;

            var originalObjectCreationNodes = new Stack <TObjectCreationExpressionSyntax>();

            foreach (var diagnostic in diagnostics)
            {
                var objectCreation = (TObjectCreationExpressionSyntax)originalRoot.FindNode(
                    diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true);
                originalObjectCreationNodes.Push(objectCreation);
            }

            // We're going to be continually editing this tree.  Track all the nodes we
            // care about so we can find them across each edit.
            document = document.WithSyntaxRoot(originalRoot.TrackNodes(originalObjectCreationNodes));
            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var currentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            while (originalObjectCreationNodes.Count > 0)
            {
                var originalObjectCreation = originalObjectCreationNodes.Pop();
                var objectCreation         = currentRoot.GetCurrentNodes(originalObjectCreation).Single();

                var matches = ObjectCreationExpressionAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclarationSyntax> .Analyze(
                    semanticModel, syntaxFacts, objectCreation, cancellationToken);

                if (matches == null || matches.Value.Length == 0)
                {
                    continue;
                }

                var statement    = objectCreation.FirstAncestorOrSelf <TStatementSyntax>();
                var newStatement = GetNewStatement(statement, objectCreation, matches.Value)
                                   .WithAdditionalAnnotations(Formatter.Annotation);

                var subEditor = new SyntaxEditor(currentRoot, workspace);

                subEditor.ReplaceNode(statement, newStatement);
                foreach (var match in matches)
                {
                    subEditor.RemoveNode(match, SyntaxRemoveOptions.KeepUnbalancedDirectives);
                }

                document      = document.WithSyntaxRoot(subEditor.GetChangedRoot());
                semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                currentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            }

            editor.ReplaceNode(originalRoot, currentRoot);
        }
        private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ienumerableType)
        {
            if (!AreCollectionInitializersSupported(context))
            {
                return;
            }

            var semanticModel            = context.SemanticModel;
            var objectCreationExpression = (TObjectCreationExpressionSyntax)context.Node;
            var language          = objectCreationExpression.Language;
            var syntaxTree        = objectCreationExpression.SyntaxTree;
            var cancellationToken = context.CancellationToken;

            var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var option = optionSet.GetOption(CodeStyleOptions.PreferCollectionInitializer, language);

            if (!option.Value)
            {
                // not point in analyzing if the option is off.
                return;
            }

            // Object creation can only be converted to collection initializer if it
            // implements the IEnumerable type.
            var objectType = context.SemanticModel.GetTypeInfo(objectCreationExpression, cancellationToken);

            if (objectType.Type == null || !objectType.Type.AllInterfaces.Contains(ienumerableType))
            {
                return;
            }

            var matches = ObjectCreationExpressionAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclarationSyntax> .Analyze(
                semanticModel, GetSyntaxFactsService(), objectCreationExpression, cancellationToken);

            if (matches == null || matches.Value.Length == 0)
            {
                return;
            }

            var containingStatement = objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>();
            var nodes       = ImmutableArray.Create <SyntaxNode>(containingStatement).AddRange(matches.Value);
            var syntaxFacts = GetSyntaxFactsService();

            if (syntaxFacts.ContainsInterleavedDirective(nodes, cancellationToken))
            {
                return;
            }

            var locations = ImmutableArray.Create(objectCreationExpression.GetLocation());

            var severity = option.Notification.Severity;

            context.ReportDiagnostic(DiagnosticHelper.Create(
                                         Descriptor,
                                         objectCreationExpression.GetLocation(),
                                         severity,
                                         additionalLocations: locations,
                                         properties: null));

            FadeOutCode(context, optionSet, matches.Value, locations);
        }