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)) { var items = await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsAsync( completionContext.Document, completionContext.Position, receiverTypeSymbol, namespaceInScope, forceIndexCreation : isExpandedCompletion, cancellationToken).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; } } }
public async Task <Solution> EncapsulateFieldsAsync( Document document, ImmutableArray <IFieldSymbol> fields, bool updateReferences, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); using (Logger.LogBlock(FunctionId.Renamer_FindRenameLocationsAsync, cancellationToken)) { var solution = document.Project.Solution; var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { var fieldSymbolKeys = fields.SelectAsArray(f => SymbolKey.CreateString(f, cancellationToken)); var result = await client.TryInvokeAsync <IRemoteEncapsulateFieldService, ImmutableArray <(DocumentId, ImmutableArray <TextChange>)> >( solution, (service, solutionInfo, cancellationToken) => service.EncapsulateFieldsAsync(solutionInfo, document.Id, fieldSymbolKeys, updateReferences, cancellationToken), callbackTarget : null, cancellationToken).ConfigureAwait(false); if (!result.HasValue) { return(solution); } return(await RemoteUtilities.UpdateSolutionAsync( solution, result.Value, cancellationToken).ConfigureAwait(false)); } } return(await EncapsulateFieldsInCurrentProcessAsync( document, fields, updateReferences, cancellationToken).ConfigureAwait(false)); }
static SerializableImportCompletionItem CreateItem(IMethodSymbol methodSymbol, string containingNamespace, int additionalOverloadCount, CancellationToken cancellationToken) => new SerializableImportCompletionItem( SymbolKey.CreateString(methodSymbol, cancellationToken), methodSymbol.Name, methodSymbol.Arity, methodSymbol.GetGlyph(), containingNamespace, additionalOverloadCount);
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; } } }
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); }
private static ImmutableArray <SerializableImportCompletionItem> ConvertSymbolsToCompletionItems(ImmutableArray <IMethodSymbol> extentsionMethodSymbols, CancellationToken cancellationToken) { using var _1 = PooledDictionary <INamespaceSymbol, string> .GetInstance(out var namespaceNameCache); using var _2 = PooledDictionary <(string containingNamespace, string methodName, bool isGeneric), (IMethodSymbol bestSymbol, int overloadCount)> .GetInstance(out var overloadMap); // Aggregate overloads foreach (var symbol in extentsionMethodSymbols) { IMethodSymbol bestSymbol; int overloadCount; var containingNamespacename = GetFullyQualifiedNamespaceName(symbol.ContainingNamespace, namespaceNameCache); var overloadKey = (containingNamespacename, symbol.Name, isGeneric : symbol.Arity > 0); // Select the overload with minimum number of parameters to display if (overloadMap.TryGetValue(overloadKey, out var currentValue)) { bestSymbol = currentValue.bestSymbol.Parameters.Length > symbol.Parameters.Length ? symbol : currentValue.bestSymbol; overloadCount = currentValue.overloadCount + 1; } else { bestSymbol = symbol; overloadCount = 1; } overloadMap[overloadKey] = (bestSymbol, overloadCount); } // Then convert symbols into completion items using var _3 = ArrayBuilder <SerializableImportCompletionItem> .GetInstance(out var itemsBuilder); foreach (var((containingNamespace, _, _), (bestSymbol, overloadCount)) in overloadMap) { // To display the count of of additional overloads, we need to substract total by 1. var item = new SerializableImportCompletionItem( SymbolKey.CreateString(bestSymbol, cancellationToken), bestSymbol.Name, bestSymbol.Arity, bestSymbol.GetGlyph(), containingNamespace, additionalOverloadCount: overloadCount - 1); itemsBuilder.Add(item); } return(itemsBuilder.ToImmutable()); }
private static void GetItemsFromTypeContainsPotentialMatches( INamedTypeSymbol containerSymbol, string qualifiedNamespaceName, MultiDictionary <string, string> .ValueSet methodNames, ITypeSymbol receiverTypeSymbol, SemanticModel semanticModel, int position, StatisticCounter counter, ArrayBuilder <SerializableImportCompletionItem> builder) { counter.TotalTypesChecked++; if (containerSymbol == null || !containerSymbol.MightContainExtensionMethods || !IsSymbolAccessible(containerSymbol, position, semanticModel)) { return; } foreach (var methodName in methodNames) { var methodSymbols = containerSymbol.GetMembers(methodName).OfType <IMethodSymbol>(); foreach (var methodSymbol in methodSymbols) { counter.TotalExtensionMethodsChecked++; IMethodSymbol?reducedMethodSymbol = null; if (methodSymbol.IsExtensionMethod && IsSymbolAccessible(methodSymbol, position, semanticModel)) { reducedMethodSymbol = methodSymbol.ReduceExtensionMethod(receiverTypeSymbol); } if (reducedMethodSymbol != null) { var symbolKeyData = SymbolKey.CreateString(reducedMethodSymbol); builder.Add(new SerializableImportCompletionItem( symbolKeyData, reducedMethodSymbol.Name, reducedMethodSymbol.Arity, reducedMethodSymbol.GetGlyph(), qualifiedNamespaceName)); } } } }
public static bool TryCreate( ISymbol symbol, Project project, CancellationToken cancellationToken, out SerializableSymbolAndProjectId result) { if (!SymbolKey.CanCreate(symbol, cancellationToken)) { result = null; return(false); } result = new SerializableSymbolAndProjectId { SymbolKeyData = SymbolKey.CreateString(symbol, cancellationToken), ProjectId = project.Id, }; return(true); }
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 static async Task <ImmutableArray <SerializableImportCompletionItem> > GetUnimportedExtensionMethodsAsync( Document document, int position, ITypeSymbol receiverTypeSymbol, ISet <string> namespaceInScope, bool forceIndexCreation, CancellationToken cancellationToken) { async Task <(ImmutableArray <SerializableImportCompletionItem>, StatisticCounter)> GetItemsAsync() { var project = document.Project; var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); if (client != null) { var result = await client.TryRunRemoteAsync <(IList <SerializableImportCompletionItem> items, StatisticCounter counter)>( WellKnownServiceHubServices.CodeAnalysisService, nameof(IRemoteExtensionMethodImportCompletionService.GetUnimportedExtensionMethodsAsync), project.Solution, new object[] { document.Id, position, SymbolKey.CreateString(receiverTypeSymbol), namespaceInScope.ToArray(), forceIndexCreation }, callbackTarget : null, cancellationToken).ConfigureAwait(false); if (result.HasValue) { return(result.Value.items.ToImmutableArray(), result.Value.counter); } } return(await GetUnimportedExtensionMethodsInCurrentProcessAsync(document, position, receiverTypeSymbol, namespaceInScope, forceIndexCreation, cancellationToken).ConfigureAwait(false)); } var ticks = Environment.TickCount; var(items, counter) = await GetItemsAsync().ConfigureAwait(false); counter.TotalTicks = Environment.TickCount - ticks; counter.TotalExtensionMethodsProvided = items.Length; counter.Report(); return(items); }
public static async Task <(ImmutableArray <SerializableImportCompletionItem>, StatisticCounter)> GetUnimportedExtensionMethodsInRemoteProcessAsync( RemoteHostClient client, Document document, int position, ITypeSymbol receiverTypeSymbol, ISet <string> namespaceInScope, bool forceIndexCreation, CancellationToken cancellationToken) { var project = document.Project; var(serializableItems, counter) = await client.TryRunCodeAnalysisRemoteAsync <(IList <SerializableImportCompletionItem>, StatisticCounter)>( project.Solution, nameof(IRemoteExtensionMethodImportCompletionService.GetUnimportedExtensionMethodsAsync), new object[] { document.Id, position, SymbolKey.CreateString(receiverTypeSymbol), namespaceInScope.ToArray(), forceIndexCreation }, cancellationToken).ConfigureAwait(false); return(serializableItems.ToImmutableArray(), counter); }
private static void GetExtensionMethodItemsWorker( int position, SemanticModel semanticModel, ITypeSymbol receiverTypeSymbol, ImmutableArray <IMethodSymbol> matchingMethodSymbols, bool isSymbolFromCurrentCompilation, ArrayBuilder <SerializableImportCompletionItem> builder, Dictionary <INamespaceSymbol, string> stringCache) { foreach (var methodSymbol in matchingMethodSymbols) { // Symbols could be from a different compilation, // because we retrieved them on a per-assembly basis. // Need to find the matching one in current compilation // before any further checks is done. var methodSymbolInCurrentCompilation = isSymbolFromCurrentCompilation ? methodSymbol : SymbolFinder.FindSimilarSymbols(methodSymbol, semanticModel.Compilation).FirstOrDefault(); if (methodSymbolInCurrentCompilation == null || !semanticModel.IsAccessible(position, methodSymbolInCurrentCompilation)) { continue; } var reducedMethodSymbol = methodSymbolInCurrentCompilation.ReduceExtensionMethod(receiverTypeSymbol); if (reducedMethodSymbol != null) { var symbolKeyData = SymbolKey.CreateString(reducedMethodSymbol); builder.Add(new SerializableImportCompletionItem( symbolKeyData, reducedMethodSymbol.Name, reducedMethodSymbol.Arity, reducedMethodSymbol.GetGlyph(), GetFullyQualifiedNamespaceName(reducedMethodSymbol.ContainingNamespace, stringCache))); } } }
public static async Task <SerializableUnimportedExtensionMethods?> GetUnimportedExtensionMethodsAsync( Document document, int position, ITypeSymbol receiverTypeSymbol, ISet <string> namespaceInScope, ImmutableArray <ITypeSymbol> targetTypesSymbols, bool forceCacheCreation, bool hideAdvancedMembers, CancellationToken cancellationToken) { var project = document.Project; var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); if (client != null) { var receiverTypeSymbolKeyData = SymbolKey.CreateString(receiverTypeSymbol, cancellationToken); var targetTypesSymbolKeyData = targetTypesSymbols.SelectAsArray(s => SymbolKey.CreateString(s, cancellationToken)); // Call the project overload. Add-import-for-extension-method doesn't search outside of the current // project cone. var result = await client.TryInvokeAsync <IRemoteExtensionMethodImportCompletionService, SerializableUnimportedExtensionMethods?>( project, (service, solutionInfo, cancellationToken) => service.GetUnimportedExtensionMethodsAsync( solutionInfo, document.Id, position, receiverTypeSymbolKeyData, namespaceInScope.ToImmutableArray(), targetTypesSymbolKeyData, forceCacheCreation, hideAdvancedMembers, cancellationToken), cancellationToken).ConfigureAwait(false); return(result.HasValue ? result.Value : null); } else { return(await GetUnimportedExtensionMethodsInCurrentProcessAsync( document, position, receiverTypeSymbol, namespaceInScope, targetTypesSymbols, forceCacheCreation, hideAdvancedMembers, isRemote : false, cancellationToken) .ConfigureAwait(false)); } }
fields.Select(f => SymbolKey.CreateString(f, cancellationToken)).ToArray(),
private static ImmutableArray <SerializableImportCompletionItem> ConvertSymbolsToCompletionItems( Compilation compilation, ImmutableArray <IMethodSymbol> extentsionMethodSymbols, ImmutableArray <ITypeSymbol> targetTypeSymbols, CancellationToken cancellationToken) { Dictionary <ITypeSymbol, bool> typeConvertibilityCache = new(); using var _1 = PooledDictionary <INamespaceSymbol, string> .GetInstance(out var namespaceNameCache); using var _2 = PooledDictionary <(string containingNamespace, string methodName, bool isGeneric), (IMethodSymbol bestSymbol, int overloadCount, bool includeInTargetTypedCompletion)> .GetInstance(out var overloadMap); // Aggregate overloads foreach (var symbol in extentsionMethodSymbols) { cancellationToken.ThrowIfCancellationRequested(); IMethodSymbol bestSymbol; int overloadCount; var includeInTargetTypedCompletion = ShouldIncludeInTargetTypedCompletion(compilation, symbol, targetTypeSymbols, typeConvertibilityCache); var containingNamespacename = GetFullyQualifiedNamespaceName(symbol.ContainingNamespace, namespaceNameCache); var overloadKey = (containingNamespacename, symbol.Name, isGeneric : symbol.Arity > 0); // Select the overload convertible to any targeted type (if any) and with minimum number of parameters to display if (overloadMap.TryGetValue(overloadKey, out var currentValue)) { if (currentValue.includeInTargetTypedCompletion == includeInTargetTypedCompletion) { bestSymbol = currentValue.bestSymbol.Parameters.Length > symbol.Parameters.Length ? symbol : currentValue.bestSymbol; } else if (currentValue.includeInTargetTypedCompletion) { bestSymbol = currentValue.bestSymbol; } else { bestSymbol = symbol; } overloadCount = currentValue.overloadCount + 1; includeInTargetTypedCompletion = includeInTargetTypedCompletion || currentValue.includeInTargetTypedCompletion; } else { bestSymbol = symbol; overloadCount = 1; } overloadMap[overloadKey] = (bestSymbol, overloadCount, includeInTargetTypedCompletion); } // Then convert symbols into completion items using var _3 = ArrayBuilder <SerializableImportCompletionItem> .GetInstance(out var itemsBuilder); foreach (var((containingNamespace, _, _), (bestSymbol, overloadCount, includeInTargetTypedCompletion)) in overloadMap) { // To display the count of additional overloads, we need to subtract total by 1. var item = new SerializableImportCompletionItem( SymbolKey.CreateString(bestSymbol, cancellationToken), bestSymbol.Name, bestSymbol.Arity, bestSymbol.GetGlyph(), containingNamespace, additionalOverloadCount: overloadCount - 1, includeInTargetTypedCompletion); itemsBuilder.Add(item); } return(itemsBuilder.ToImmutable()); }
public static string EncodeSymbol(ISymbol symbol) { return(SymbolKey.CreateString(symbol)); }
public static string EncodeSymbol(ISymbol symbol) => SymbolKey.CreateString(symbol);