public SyntaxNode AddImports(
            Compilation compilation,
            SyntaxNode root,
            SyntaxNode?contextLocation,
            IEnumerable <SyntaxNode> newImports,
            SyntaxGenerator generator,
            CodeGenerationPreferences preferences,
            bool allowInHiddenRegions,
            CancellationToken cancellationToken)
        {
            contextLocation ??= root;

            var placeSystemNamespaceFirst = preferences.Options.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, compilation.Language);

            var globalImports   = GetGlobalImports(compilation, generator);
            var containers      = GetAllContainers(root, contextLocation);
            var filteredImports = newImports.Where(i => !HasExistingImport(i, containers, globalImports)).ToArray();

            var externAliases         = filteredImports.OfType <TExternSyntax>().ToArray();
            var usingDirectives       = filteredImports.OfType <TUsingOrAliasSyntax>().Where(IsSimpleUsing).ToArray();
            var staticUsingDirectives = filteredImports.OfType <TUsingOrAliasSyntax>().Where(IsStaticUsing).ToArray();
            var aliasDirectives       = filteredImports.OfType <TUsingOrAliasSyntax>().Where(IsAlias).ToArray();

            GetContainers(root, contextLocation, preferences,
                          out var externContainer, out var usingContainer, out var aliasContainer, out var staticUsingContainer);

            var newRoot = Rewrite(
                externAliases, usingDirectives, staticUsingDirectives, aliasDirectives,
                externContainer, usingContainer, staticUsingContainer, aliasContainer,
                placeSystemNamespaceFirst, allowInHiddenRegions, root, cancellationToken);

            return(newRoot);
        }
        private void GetContainers(SyntaxNode root, SyntaxNode contextLocation, CodeGenerationPreferences preferences, out SyntaxNode externContainer, out SyntaxNode usingContainer, out SyntaxNode staticUsingContainer, out SyntaxNode aliasContainer)
        {
            var applicableContainer = GetFirstApplicableContainer(contextLocation);
            var contextSpine        = applicableContainer.GetAncestorsOrThis <SyntaxNode>().ToImmutableArray();

            // The node we'll add to if we can't find a specific namespace with imports of
            // the type we're trying to add.  This will be the closest namespace with any
            // imports in it
            var fallbackNode = contextSpine.FirstOrDefault(HasAnyImports);

            // If there aren't any existing imports then make sure we honour the inside namespace preference
            // for using directings if it's set
            if (fallbackNode is null && PlaceImportsInsideNamespaces(preferences))
            {
                fallbackNode = contextSpine.OfType <TNamespaceDeclarationSyntax>().FirstOrDefault();
            }

            // If all else fails use the root
            if (fallbackNode is null)
            {
                fallbackNode = root;
            }

            // The specific container to add each type of import to.  We look for a container
            // that already has an import of the same type as the node we want to add to.
            // If we can find one, we add to that container.  If not, we call back to the
            // innermost node with any imports.
            externContainer      = contextSpine.FirstOrDefault(HasExterns) ?? fallbackNode;
            usingContainer       = contextSpine.FirstOrDefault(HasUsings) ?? fallbackNode;
            staticUsingContainer = contextSpine.FirstOrDefault(HasStaticUsings) ?? fallbackNode;
            aliasContainer       = contextSpine.FirstOrDefault(HasAliases) ?? fallbackNode;
        }
            private async Task <SyntaxNode> GetNewRootAsync(CancellationToken cancellationToken)
            {
                var semanticModel = await _document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                var preferences = await CodeGenerationPreferences.FromDocumentAsync(_document, cancellationToken).ConfigureAwait(false);

                if (_service.TryConvertToLocalDeclaration(_state.LocalType, _state.IdentifierToken, semanticModel, cancellationToken, out var newRoot))
                {
                    return(newRoot);
                }

                var syntaxFactory = _document.GetLanguageService <SyntaxGenerator>();
                var initializer   = _state.IsOnlyWrittenTo
                    ? null
                    : syntaxFactory.DefaultExpression(_state.LocalType);

                var type           = _state.LocalType;
                var localStatement = syntaxFactory.LocalDeclarationStatement(type, _state.IdentifierToken.ValueText, initializer);

                localStatement = localStatement.WithAdditionalAnnotations(Formatter.Annotation);

                var codeGenService = _document.GetLanguageService <ICodeGenerationService>();
                var root           = _state.IdentifierToken.GetAncestors <SyntaxNode>().Last();

                var options = preferences.GetOptions(
                    new CodeGenerationContext(beforeThisLocation: _state.IdentifierToken.GetLocation()));

                return(codeGenService.AddStatements(
                           root,
                           SpecializedCollections.SingletonEnumerable(localStatement),
                           options,
                           cancellationToken: cancellationToken));
            }
Esempio n. 4
0
        private async Task <Document> ExpandToFullPropertyAsync(
            Document document,
            SyntaxNode property,
            IPropertySymbol propertySymbol,
            SyntaxNode root,
            CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(document.DocumentState.ParseOptions);

            var generator     = SyntaxGenerator.GetGenerator(document);
            var codeGenerator = document.GetRequiredLanguageService <ICodeGenerationService>();
            var services      = document.Project.Solution.Workspace.Services;

            var preferences = (TCodeGenerationPreferences)await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false);

            // Create full property. If the auto property had an initial value
            // we need to remove it and later add it to the backing field
            var fieldName = await GetFieldNameAsync(document, propertySymbol, cancellationToken).ConfigureAwait(false);

            var(newGetAccessor, newSetAccessor) = GetNewAccessors(preferences, property, fieldName, generator);
            var fullProperty = generator
                               .WithAccessorDeclarations(
                GetPropertyWithoutInitializer(property),
                newSetAccessor == null
                        ? new SyntaxNode[] { newGetAccessor }
                        : new SyntaxNode[] { newGetAccessor, newSetAccessor })
                               .WithLeadingTrivia(property.GetLeadingTrivia());

            fullProperty = ConvertPropertyToExpressionBodyIfDesired(preferences, fullProperty);
            var editor = new SyntaxEditor(root, services);

            editor.ReplaceNode(property, fullProperty.WithAdditionalAnnotations(Formatter.Annotation));

            // add backing field, plus initializer if it exists
            var newField = CodeGenerationSymbolFactory.CreateFieldSymbol(
Esempio n. 5
0
 protected virtual (string description, bool hasExistingImport) GetDescription(
     Document document, CodeGenerationPreferences preferences, SyntaxNode node,
     SemanticModel semanticModel, CancellationToken cancellationToken)
 {
     return(provider.GetDescription(
                document, preferences, SymbolResult.Symbol, semanticModel, node, cancellationToken));
 }
Esempio n. 6
0
            protected override (string description, bool hasExistingImport) GetDescription(
                Document document, CodeGenerationPreferences preferences, SyntaxNode node,
                SemanticModel semanticModel, CancellationToken cancellationToken)
            {
                var(description, hasExistingImport) = base.GetDescription(document, preferences, node, semanticModel, cancellationToken);
                if (description == null)
                {
                    return(null, false);
                }

                return(string.Format(FeaturesResources.Add_reference_to_0, Path.GetFileName(_reference.FilePath)),
                       hasExistingImport);
            }
Esempio n. 7
0
            public sealed override async Task <AddImportFixData> TryGetFixDataAsync(
                Document document, SyntaxNode node,
                bool allowInHiddenRegions, CancellationToken cancellationToken)
            {
                var preferences = await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false);

                var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                var(description, hasExistingImport) = GetDescription(document, preferences, node, semanticModel, cancellationToken);
                if (description == null)
                {
                    return(null);
                }

                if (hasExistingImport && !ShouldAddWithExistingImport(document))
                {
                    return(null);
                }

                var isFuzzy = !SearchResult.DesiredNameMatchesSourceName(document);
                var tags    = GetTags(document);

                if (isFuzzy)
                {
                    // The name is going to change.  Make it clear in the description that this is
                    // going to happen.
                    description = $"{SearchResult.DesiredName} - {description}";

                    // if we were a fuzzy match, and we didn't have any glyph to show, then add the
                    // namespace-glyph to this item. This helps indicate that not only are we fixing
                    // the spelling of this name we are *also* adding a namespace.  This helps as we
                    // have gotten feedback in the past that the 'using/import' addition was
                    // unexpected.
                    if (tags.IsDefaultOrEmpty)
                    {
                        tags = WellKnownTagArrays.Namespace;
                    }
                }

                var textChanges = await GetTextChangesAsync(
                    document, node, allowInHiddenRegions, hasExistingImport, cancellationToken).ConfigureAwait(false);

                return(GetFixData(
                           document, textChanges, description,
                           tags, GetPriority(document)));
            }
Esempio n. 8
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var cancellationToken = context.CancellationToken;
            var document          = context.Document;
            var syntaxFacts       = document.GetRequiredLanguageService <ISyntaxFactsService>();
            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            // Innermost: We are looking for an IdentifierName. IdentifierName is sometimes at the same span as its parent (e.g. SimpleBaseTypeSyntax).
            var diagnosticNode = root.FindNode(context.Span, getInnermostNodeForTie: true);

            if (!syntaxFacts.IsIdentifierName(diagnosticNode))
            {
                return;
            }

            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var symbolInfo = semanticModel.GetSymbolInfo(diagnosticNode, cancellationToken);

            if (SymbolCandidatesContainsSupportedSymbols(symbolInfo))
            {
                var addImportService = document.GetRequiredLanguageService <IAddImportsService>();
                var syntaxGenerator  = document.GetRequiredLanguageService <SyntaxGenerator>();
                var codeGenerator    = document.GetRequiredLanguageService <ICodeGenerationService>();
                var compilation      = semanticModel.Compilation;
                var preferences      = await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false);

                var allowInHiddenRegions = document.CanAddImportsInHiddenRegions();
                var codeActionsBuilder   = ImmutableArray.CreateBuilder <CodeAction>(symbolInfo.CandidateSymbols.Length);
                foreach (var symbol in symbolInfo.CandidateSymbols.Cast <ITypeSymbol>())
                {
                    var typeName = symbol.Name;
                    var codeActionPreviewText = GetTextPreviewOfChange(typeName, symbol);
                    codeActionsBuilder.Add(new MyCodeAction(codeActionPreviewText, c =>
                    {
                        var aliasDirective = syntaxGenerator.AliasImportDeclaration(typeName, symbol);
                        var newRoot        = addImportService.AddImport(compilation, root, diagnosticNode, aliasDirective, syntaxGenerator, preferences, allowInHiddenRegions, cancellationToken);
                        return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                    }));
                }

                var groupingTitle      = string.Format(FeaturesResources.Alias_ambiguous_type_0, diagnosticNode.ToString());
                var groupingCodeAction = new CodeActionWithNestedActions(groupingTitle, codeActionsBuilder.ToImmutable(), isInlinable: true);
                context.RegisterCodeFix(groupingCodeAction, context.Diagnostics.First());
            }
        }
Esempio n. 9
0
            protected override (string description, bool hasExistingImport) GetDescription(
                Document document, CodeGenerationPreferences preferences, SyntaxNode node,
                SemanticModel semanticModel, CancellationToken cancellationToken)
            {
                var(description, hasExistingImport) = base.GetDescription(document, preferences, node, semanticModel, cancellationToken);
                if (description == null)
                {
                    return(null, false);
                }

                var project = document.Project;

                description = project.Id == _project.Id
                    ? description
                    : string.Format(FeaturesResources.Add_reference_to_0, _project.Name);

                return(description, hasExistingImport);
            }
Esempio n. 10
0
        internal override Document AddImports(
            Document document, CodeGenerationPreferences preferences, int position, XElement snippetNode,
            bool allowInHiddenRegions,
            CancellationToken cancellationToken)
        {
            var importsNode = snippetNode.Element(XName.Get("Imports", snippetNode.Name.NamespaceName));

            if (importsNode == null ||
                !importsNode.HasElements)
            {
                return(document);
            }

            var root            = document.GetRequiredSyntaxRootSynchronously(cancellationToken);
            var contextLocation = root.FindToken(position).GetRequiredParent();

            var newUsingDirectives = GetUsingDirectivesToAdd(contextLocation, snippetNode, importsNode);

            if (!newUsingDirectives.Any())
            {
                return(document);
            }

            // In Venus/Razor, inserting imports statements into the subject buffer does not work.
            // Instead, we add the imports through the contained language host.
            if (TryAddImportsToContainedDocument(document, newUsingDirectives.Where(u => u.Alias == null).Select(u => u.Name.ToString())))
            {
                return(document);
            }

            var addImportService = document.GetRequiredLanguageService <IAddImportsService>();
            var generator        = document.GetRequiredLanguageService <SyntaxGenerator>();
            var compilation      = document.Project.GetRequiredCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var newRoot          = addImportService.AddImports(compilation, root, contextLocation, newUsingDirectives, generator, preferences, allowInHiddenRegions, cancellationToken);

            var newDocument = document.WithSyntaxRoot(newRoot);

            var formattedDocument = Formatter.FormatAsync(newDocument, Formatter.Annotation, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);

            document.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken);

            return(formattedDocument);
        }
        protected override (string description, bool hasExistingImport) GetDescription(
            Document document,
            CodeGenerationPreferences preferences,
            INamespaceOrTypeSymbol namespaceOrTypeSymbol,
            SemanticModel semanticModel,
            SyntaxNode contextNode,
            CancellationToken cancellationToken)
        {
            var root = GetCompilationUnitSyntaxNode(contextNode, cancellationToken);

            // See if this is a reference to a type from a reference that has a specific alias
            // associated with it.  If that extern alias hasn't already been brought into scope
            // then add that one.
            var(externAlias, hasExistingExtern) = GetExternAliasDirective(
                namespaceOrTypeSymbol, semanticModel, contextNode);

            var(usingDirective, hasExistingUsing) = GetUsingDirective(
                document, (CSharpCodeGenerationPreferences)preferences, namespaceOrTypeSymbol, semanticModel, root, contextNode);

            var externAliasString    = externAlias != null ? $"extern alias {externAlias.Identifier.ValueText};" : null;
            var usingDirectiveString = usingDirective != null?GetUsingDirectiveString(namespaceOrTypeSymbol) : null;

            if (externAlias == null && usingDirective == null)
            {
                return(null, false);
            }

            if (externAlias != null && !hasExistingExtern)
            {
                return(externAliasString, false);
            }

            if (usingDirective != null && !hasExistingUsing)
            {
                return(usingDirectiveString, false);
            }

            return(externAlias != null
                ? (externAliasString, hasExistingExtern)
                : (usingDirectiveString, hasExistingUsing));
        }
Esempio n. 12
0
 protected abstract (string description, bool hasExistingImport) GetDescription(Document document, CodeGenerationPreferences preferences, INamespaceOrTypeSymbol symbol, SemanticModel semanticModel, SyntaxNode root, CancellationToken cancellationToken);
Esempio n. 13
0
 public static SyntaxNode AddImport(
     this IAddImportsService service, Compilation compilation, SyntaxNode root,
     SyntaxNode contextLocation, SyntaxNode newImport, SyntaxGenerator generator, CodeGenerationPreferences preferences,
     bool allowInHiddenRegions, CancellationToken cancellationToken)
 {
     return(service.AddImports(compilation, root, contextLocation,
                               SpecializedCollections.SingletonEnumerable(newImport), generator, preferences,
                               allowInHiddenRegions, cancellationToken));
 }
Esempio n. 14
0
        public SyntaxNode GetImportContainer(SyntaxNode root, SyntaxNode?contextLocation, SyntaxNode import, CodeGenerationPreferences preferences)
        {
            contextLocation ??= root;
            GetContainers(root, contextLocation, preferences,
                          out var externContainer, out var usingContainer, out var staticUsingContainer, out var aliasContainer);

            switch (import)
            {
            case TExternSyntax _:
                return(externContainer);

            case TUsingOrAliasSyntax u:
                if (IsAlias(u))
                {
                    return(aliasContainer);
                }

                if (IsStaticUsing(u))
                {
                    return(staticUsingContainer);
                }

                return(usingContainer);
            }

            throw new InvalidOperationException();
        }
Esempio n. 15
0
 protected abstract bool PlaceImportsInsideNamespaces(CodeGenerationPreferences preferences);
Esempio n. 16
0
        private async Task <Document> AddImportDirectivesFromSyntaxesAsync(
            Document document,
            CodeGenerationPreferences preferences,
            IEnumerable <SyntaxNode> syntaxNodes,
            IAddImportsService addImportsService,
            SyntaxGenerator generator,
            bool allowInHiddenRegions,
            CancellationToken cancellationToken)
        {
            using var _1 = ArrayBuilder <SyntaxNode> .GetInstance(out var importsToAdd);

            using var _2 = ArrayBuilder <SyntaxNode> .GetInstance(out var nodesToSimplify);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var nodesWithExplicitNamespaces = syntaxNodes
                                              .Select(n => (syntaxnode: n, namespaceSymbol: GetExplicitNamespaceSymbol(n, model)))
                                              .Where(x => x.namespaceSymbol != null);

            var addedSymbols = new HashSet <INamespaceSymbol>();

            foreach (var(node, namespaceSymbol) in nodesWithExplicitNamespaces)
            {
                cancellationToken.ThrowIfCancellationRequested();

                nodesToSimplify.Add(node);

                if (addedSymbols.Contains(namespaceSymbol))
                {
                    continue;
                }

                var namespaceSyntax = GenerateNamespaceImportDeclaration(namespaceSymbol, generator);
                if (addImportsService.HasExistingImport(model.Compilation, root, node, namespaceSyntax, generator))
                {
                    continue;
                }

                if (IsInsideNamespace(node, namespaceSymbol, model, cancellationToken))
                {
                    continue;
                }

                addedSymbols.Add(namespaceSymbol);
                importsToAdd.Add(namespaceSyntax);
            }

            if (nodesToSimplify.Count == 0)
            {
                return(document);
            }

            var annotation = new SyntaxAnnotation();

            root = root.ReplaceNodes(
                nodesToSimplify,
                (o, r) => r.WithAdditionalAnnotations(Simplifier.Annotation, annotation));

            var first = root.DescendantNodesAndSelf().First(x => x.HasAnnotation(annotation));
            var last  = root.DescendantNodesAndSelf().Last(x => x.HasAnnotation(annotation));

            var context = first.GetCommonRoot(last);

            root = addImportsService.AddImports(
                model.Compilation, root, context, importsToAdd, generator, preferences,
                allowInHiddenRegions, cancellationToken);

            return(document.WithSyntaxRoot(root));
        }
Esempio n. 17
0
        private async Task <Document> AddImportDirectivesFromSymbolAnnotationsAsync(
            Document document,
            CodeGenerationPreferences preferences,
            IEnumerable <SyntaxNode> syntaxNodes,
            IAddImportsService addImportsService,
            SyntaxGenerator generator,
            bool allowInHiddenRegions,
            CancellationToken cancellationToken)
        {
            using var _ = PooledDictionary <INamespaceSymbol, SyntaxNode> .GetInstance(out var importToSyntax);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode?first = null, last = null;
            var        annotatedNodes = syntaxNodes.Where(x => x.HasAnnotations(SymbolAnnotation.Kind));

            foreach (var annotatedNode in annotatedNodes)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (annotatedNode.GetAnnotations(DoNotAddImportsAnnotation.Kind).Any())
                {
                    continue;
                }

                var annotations = annotatedNode.GetAnnotations(SymbolAnnotation.Kind);
                foreach (var annotation in annotations)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    foreach (var namedType in SymbolAnnotation.GetSymbols(annotation, model.Compilation).OfType <INamedTypeSymbol>())
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        if (namedType.OriginalDefinition.IsSpecialType() || namedType.IsNullable() || namedType.IsTupleType)
                        {
                            continue;
                        }

                        var namespaceSymbol = namedType.ContainingNamespace;
                        if (namespaceSymbol is null || namespaceSymbol.IsGlobalNamespace)
                        {
                            continue;
                        }

                        first ??= annotatedNode;
                        last = annotatedNode;

                        if (importToSyntax.ContainsKey(namespaceSymbol))
                        {
                            continue;
                        }

                        var namespaceSyntax = GenerateNamespaceImportDeclaration(namespaceSymbol, generator);
                        if (addImportsService.HasExistingImport(model.Compilation, root, annotatedNode, namespaceSyntax, generator))
                        {
                            continue;
                        }

                        if (IsInsideNamespace(annotatedNode, namespaceSymbol, model, cancellationToken))
                        {
                            continue;
                        }

                        importToSyntax[namespaceSymbol] = namespaceSyntax;
                    }
                }
            }

            if (first == null || last == null || importToSyntax.Count == 0)
            {
                return(document);
            }

            var context = first.GetCommonRoot(last);

            // Find the namespace/compilation-unit we'll be adding all these imports to.
            var importContainer = addImportsService.GetImportContainer(root, context, importToSyntax.First().Value, preferences);

            // Now remove any imports we think can cause conflicts in that container.
            var safeImportsToAdd = GetSafeToAddImports(importToSyntax.Keys.ToImmutableArray(), importContainer, model, cancellationToken);

            var importsToAdd = importToSyntax.Where(kvp => safeImportsToAdd.Contains(kvp.Key)).Select(kvp => kvp.Value).ToImmutableArray();

            if (importsToAdd.Length == 0)
            {
                return(document);
            }

            root = addImportsService.AddImports(
                model.Compilation, root, context, importsToAdd, generator, preferences,
                allowInHiddenRegions, cancellationToken);
            return(document.WithSyntaxRoot(root));
        }
Esempio n. 18
0
 protected override bool PlaceImportsInsideNamespaces(CodeGenerationPreferences preferences)
 {
     return(preferences.Options.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement).Value == AddImportPlacement.InsideNamespace);
 }
        public override async Task <CompletionChange> GetChangeAsync(
            Document document, CompletionItem completionItem, char?commitKey, CancellationToken cancellationToken)
        {
            var containingNamespace          = ImportCompletionItem.GetContainingNamespace(completionItem);
            var provideParenthesisCompletion = await ShouldProvideParenthesisCompletionAsync(
                document,
                completionItem,
                commitKey,
                cancellationToken).ConfigureAwait(false);

            var insertText = completionItem.DisplayText;

            if (provideParenthesisCompletion)
            {
                insertText += "()";
                CompletionProvidersLogger.LogCustomizedCommitToAddParenthesis(commitKey);
            }

            if (await ShouldCompleteWithFullyQualifyTypeName().ConfigureAwait(false))
            {
                var completionText = $"{containingNamespace}.{insertText}";
                return(CompletionChange.Create(new TextChange(completionItem.Span, completionText)));
            }

            // Find context node so we can use it to decide where to insert using/imports.
            var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var addImportContextNode = root.FindToken(completionItem.Span.Start, findInsideTrivia: true).Parent;

            // Add required using/imports directive.
            var addImportService = document.GetRequiredLanguageService <IAddImportsService>();
            var generator        = document.GetRequiredLanguageService <SyntaxGenerator>();
            var preferences      = await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false);

            var allowInHiddenRegions = document.CanAddImportsInHiddenRegions();
            var importNode           = CreateImport(document, containingNamespace);

            var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);

            var rootWithImport     = addImportService.AddImport(compilation, root, addImportContextNode !, importNode, generator, preferences, allowInHiddenRegions, cancellationToken);
            var documentWithImport = document.WithSyntaxRoot(rootWithImport);
            // This only formats the annotated import we just added, not the entire document.
            var formattedDocumentWithImport = await Formatter.FormatAsync(documentWithImport, Formatter.Annotation, cancellationToken : cancellationToken).ConfigureAwait(false);

            using var _ = ArrayBuilder <TextChange> .GetInstance(out var builder);

            // Get text change for add import
            var importChanges = await formattedDocumentWithImport.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);

            builder.AddRange(importChanges);

            // Create text change for complete type name.
            //
            // Note: Don't try to obtain TextChange for completed type name by replacing the text directly,
            //       then use Document.GetTextChangesAsync on document created from the changed text. This is
            //       because it will do a diff and return TextChanges with minimum span instead of actual
            //       replacement span.
            //
            //       For example: If I'm typing "asd", the completion provider could be triggered after "a"
            //       is typed. Then if I selected type "AsnEncodedData" to commit, by using the approach described
            //       above, we will get a TextChange of "AsnEncodedDat" with 0 length span, instead of a change of
            //       the full display text with a span of length 1. This will later mess up span-tracking and end up
            //       with "AsnEncodedDatasd" in the code.
            builder.Add(new TextChange(completionItem.Span, insertText));

            // Then get the combined change
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var newText = text.WithChanges(builder);

            var changes = builder.ToImmutable();
            var change  = Utilities.Collapse(newText, changes);

            return(CompletionChange.Create(change, changes));

            async Task <bool> ShouldCompleteWithFullyQualifyTypeName()
            {
                if (!IsAddingImportsSupported(document))
                {
                    return(true);
                }

                // We might need to qualify unimported types to use them in an import directive, because they only affect members of the containing
                // import container (e.g. namespace/class/etc. declarations).
                //
                // For example, `List` and `StringBuilder` both need to be fully qualified below:
                //
                //      using CollectionOfStringBuilders = System.Collections.Generic.List<System.Text.StringBuilder>;
                //
                // However, if we are typing in an C# using directive that is inside a nested import container (i.e. inside a namespace declaration block),
                // then we can add an using in the outer import container instead (this is not allowed in VB).
                //
                // For example:
                //
                //      using System.Collections.Generic;
                //      using System.Text;
                //
                //      namespace Foo
                //      {
                //          using CollectionOfStringBuilders = List<StringBuilder>;
                //      }
                //
                // Here we will always choose to qualify the unimported type, just to be consistent and keeps things simple.
                return(await IsInImportsDirectiveAsync(document, completionItem.Span.Start, cancellationToken).ConfigureAwait(false));
            }
        }