private static void ReportSessionWideTelemetry() { SolutionLogger.ReportTelemetry(); AsyncCompletionLogger.ReportTelemetry(); CompletionProvidersLogger.ReportTelemetry(); ChangeSignatureLogger.ReportTelemetry(); }
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; } } }
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();
protected override void LogCommit() => CompletionProvidersLogger.LogCommitOfTypeImportCompletionItem();