예제 #1
0
 private static void ReportSessionWideTelemetry()
 {
     SolutionLogger.ReportTelemetry();
     AsyncCompletionLogger.ReportTelemetry();
     CompletionProvidersLogger.ReportTelemetry();
     ChangeSignatureLogger.ReportTelemetry();
 }
예제 #2
0
 private void ReportSessionWideTelemetry()
 {
     PersistedVersionStampLogger.ReportTelemetry();
     LinkedFileDiffMergingLogger.ReportTelemetry();
     SolutionLogger.ReportTelemetry();
     AsyncCompletionLogger.ReportTelemetry();
     CompletionProvidersLogger.ReportTelemetry();
 }
        protected override async Task AddCompletionItemsAsync(
            CompletionContext completionContext,
            SyntaxContext syntaxContext,
            HashSet <string> namespaceInScope,
            bool isExpandedCompletion,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Completion_ExtensionMethodImportCompletionProvider_GetCompletionItemsAsync, cancellationToken))
            {
                var syntaxFacts = completionContext.Document.GetRequiredLanguageService <ISyntaxFactsService>();
                if (TryGetReceiverTypeSymbol(syntaxContext, syntaxFacts, cancellationToken, out var receiverTypeSymbol))
                {
                    using var nestedTokenSource = new CancellationTokenSource();
                    using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(nestedTokenSource.Token, cancellationToken);
                    var inferredTypes = completionContext.CompletionOptions.TargetTypedCompletionFilter
                        ? syntaxContext.InferredTypes
                        : ImmutableArray <ITypeSymbol> .Empty;

                    var getItemsTask = Task.Run(() => ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsAsync(
                                                    completionContext.Document,
                                                    completionContext.Position,
                                                    receiverTypeSymbol,
                                                    namespaceInScope,
                                                    inferredTypes,
                                                    forceIndexCreation: isExpandedCompletion,
                                                    hideAdvancedMembers: completionContext.CompletionOptions.HideAdvancedMembers,
                                                    linkedTokenSource.Token));

                    var timeoutInMilliseconds = completionContext.CompletionOptions.TimeoutInMillisecondsForExtensionMethodImportCompletion;

                    // Timebox is enabled if timeout value is >= 0 and we are not triggered via expander
                    if (timeoutInMilliseconds >= 0 && !isExpandedCompletion)
                    {
                        // timeout == 0 means immediate timeout (for testing purpose)
                        if (timeoutInMilliseconds == 0 || await Task.WhenAny(getItemsTask, Task.Delay(timeoutInMilliseconds, linkedTokenSource.Token)).ConfigureAwait(false) != getItemsTask)
                        {
                            nestedTokenSource.Cancel();
                            CompletionProvidersLogger.LogExtensionMethodCompletionTimeoutCount();
                            return;
                        }
                    }

                    // Either the timebox is not enabled, so we need to wait until the operation for complete,
                    // or there's no timeout, and we now have all completion items ready.
                    var items = await getItemsTask.ConfigureAwait(false);

                    var receiverTypeKey = SymbolKey.CreateString(receiverTypeSymbol, cancellationToken);
                    completionContext.AddItems(items.Select(i => Convert(i, receiverTypeKey)));
                }
                else
                {
                    // If we can't get a valid receiver type, then we don't show expander as available.
                    // We need to set this explicitly here because we didn't do the (more expensive) symbol check inside
                    // `ShouldProvideCompletion` method above, which is intended for quick syntax based check.
                    completionContext.ExpandItemsAvailable = false;
                }
            }
        }
예제 #4
0
        protected override string GetInsertionText(CompletionItem item, char ch)
        {
            if (ch == ';')
            {
                CompletionProvidersLogger.LogCommitUsingSemicolonToAddParenthesis();
                var insertionText = SymbolCompletionItem.GetInsertionText(item);
                return(insertionText + "()");
            }

            return(base.GetInsertionText(item, ch));
        }
        public void Report()
        {
            CompletionProvidersLogger.LogExtensionMethodCompletionTicksDataPoint(TotalTicks);
            CompletionProvidersLogger.LogExtensionMethodCompletionMethodsProvidedDataPoint(TotalExtensionMethodsProvided);
            CompletionProvidersLogger.LogExtensionMethodCompletionGetSymbolsTicksDataPoint(GetSymbolsTicks);
            CompletionProvidersLogger.LogExtensionMethodCompletionCreateItemsTicksDataPoint(CreateItemsTicks);

            if (PartialResult)
            {
                CompletionProvidersLogger.LogExtensionMethodCompletionPartialResultCount();
            }
        }
        public static async Task <ImmutableArray <SerializableImportCompletionItem> > GetUnimportedExtensionMethodsAsync(
            Document document,
            int position,
            ITypeSymbol receiverTypeSymbol,
            ISet <string> namespaceInScope,
            bool forceIndexCreation,
            CancellationToken cancellationToken)
        {
            SerializableUnimportedExtensionMethods items;

            var ticks = Environment.TickCount;

            var project = document.Project;
            var client  = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false);

            if (client != null)
            {
                var receiverTypeSymbolKeyData = SymbolKey.CreateString(receiverTypeSymbol, cancellationToken);

                var result = await client.TryInvokeAsync <IRemoteExtensionMethodImportCompletionService, SerializableUnimportedExtensionMethods>(
                    project.Solution,
                    (service, solutionInfo, cancellationToken) => service.GetUnimportedExtensionMethodsAsync(
                        solutionInfo, document.Id, position, receiverTypeSymbolKeyData, namespaceInScope.ToImmutableArray(), forceIndexCreation, cancellationToken),
                    callbackTarget : null,
                    cancellationToken).ConfigureAwait(false);

                if (!result.HasValue)
                {
                    return(ImmutableArray <SerializableImportCompletionItem> .Empty);
                }

                items = result.Value;
            }
            else
            {
                items = await GetUnimportedExtensionMethodsInCurrentProcessAsync(document, position, receiverTypeSymbol, namespaceInScope, forceIndexCreation, cancellationToken).ConfigureAwait(false);
            }

            // report telemetry:
            var totalTicks = Environment.TickCount - ticks;

            CompletionProvidersLogger.LogExtensionMethodCompletionTicksDataPoint(totalTicks);
            CompletionProvidersLogger.LogExtensionMethodCompletionMethodsProvidedDataPoint(items.CompletionItems.Length);
            CompletionProvidersLogger.LogExtensionMethodCompletionGetSymbolsTicksDataPoint(items.GetSymbolsTicks);
            CompletionProvidersLogger.LogExtensionMethodCompletionCreateItemsTicksDataPoint(items.CreateItemsTicks);

            if (items.IsPartialResult)
            {
                CompletionProvidersLogger.LogExtensionMethodCompletionPartialResultCount();
            }

            return(items.CompletionItems);
        }
            public void Report()
            {
                var delta = Environment.TickCount - Tick;

                CompletionProvidersLogger.LogTypeImportCompletionTicksDataPoint(delta);
                CompletionProvidersLogger.LogTypeImportCompletionItemCountDataPoint(ItemsCount);
                CompletionProvidersLogger.LogTypeImportCompletionReferenceCountDataPoint(ReferenceCount);

                if (TimedOut)
                {
                    CompletionProvidersLogger.LogTypeImportCompletionTimeout();
                }
            }
 public void Report()
 {
     if (CacheMiss)
     {
         CompletionProvidersLogger.LogTypeImportCompletionCacheMiss();
     }
     else
     {
         var delta = Environment.TickCount - Tick;
         CompletionProvidersLogger.LogTypeImportCompletionTicksDataPoint(delta);
         CompletionProvidersLogger.LogTypeImportCompletionItemCountDataPoint(ItemsCount);
         CompletionProvidersLogger.LogTypeImportCompletionReferenceCountDataPoint(ReferenceCount);
     }
 }
        protected override async Task AddCompletionItemsAsync(
            CompletionContext completionContext,
            SyntaxContext syntaxContext,
            HashSet <string> namespaceInScope,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Completion_ExtensionMethodImportCompletionProvider_GetCompletionItemsAsync, cancellationToken))
            {
                var syntaxFacts = completionContext.Document.GetRequiredLanguageService <ISyntaxFactsService>();
                if (TryGetReceiverTypeSymbol(syntaxContext, syntaxFacts, cancellationToken, out var receiverTypeSymbol))
                {
                    var totalTime = SharedStopwatch.StartNew();

                    var inferredTypes = completionContext.CompletionOptions.TargetTypedCompletionFilter
                        ? syntaxContext.InferredTypes
                        : ImmutableArray <ITypeSymbol> .Empty;

                    var result = await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsAsync(
                        completionContext.Document,
                        completionContext.Position,
                        receiverTypeSymbol,
                        namespaceInScope,
                        inferredTypes,
                        forceCacheCreation : completionContext.CompletionOptions.ForceExpandedCompletionIndexCreation,
                        hideAdvancedMembers : completionContext.CompletionOptions.HideAdvancedMembers,
                        cancellationToken).ConfigureAwait(false);

                    if (result is null)
                    {
                        return;
                    }

                    var receiverTypeKey = SymbolKey.CreateString(receiverTypeSymbol, cancellationToken);
                    completionContext.AddItems(result.CompletionItems.Select(i => Convert(i, receiverTypeKey)));

                    // report telemetry:
                    CompletionProvidersLogger.LogExtensionMethodCompletionTicksDataPoint(
                        totalTime.Elapsed, result.GetSymbolsTime, result.CreateItemsTime, result.IsRemote);

                    if (result.IsPartialResult)
                    {
                        CompletionProvidersLogger.LogExtensionMethodCompletionPartialResultCount();
                    }
                }
            }
        }
        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 addImportsOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false);

            var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false);

            var importNode = CreateImport(document, containingNamespace);

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

            var rootWithImport     = addImportService.AddImport(compilation, root, addImportContextNode !, importNode, generator, addImportsOptions, 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, formattingOptions, 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));
            }
        }
 protected override void LogCommit()
 => CompletionProvidersLogger.LogCommitOfExtensionMethodImportCompletionItem();
예제 #12
0
 protected override void LogCommit()
 => CompletionProvidersLogger.LogCommitOfTypeImportCompletionItem();