protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); ObjectCreationExpressionSyntax objectCreationExpression; if (!TryGetObjectCreationExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out objectCreationExpression)) { return null; } var semanticModel = await document.GetSemanticModelForNodeAsync(objectCreationExpression, cancellationToken).ConfigureAwait(false); var type = semanticModel.GetTypeInfo(objectCreationExpression, cancellationToken).Type as INamedTypeSymbol; if (type == null) { return null; } var within = semanticModel.GetEnclosingNamedType(position, cancellationToken); if (within == null) { return null; } var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>(); var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>(); var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>(); var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(objectCreationExpression.ArgumentList); var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); return CreateSignatureHelpItems(type.TypeKind == TypeKind.Delegate ? GetDelegateTypeConstructors(objectCreationExpression, semanticModel, symbolDisplayService, anonymousTypeDisplayService, type, within, cancellationToken) : GetNormalTypeConstructors(document, objectCreationExpression, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, type, within, cancellationToken), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); }
protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); InvocationExpressionSyntax invocationExpression; if (!TryGetInvocationExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out invocationExpression)) { return null; } var semanticModel = await document.GetSemanticModelForNodeAsync(invocationExpression, cancellationToken).ConfigureAwait(false); var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); if (within == null) { return null; } // get the regular signature help items var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>(); var methodGroup = semanticModel.GetMemberGroup(invocationExpression.Expression, cancellationToken) .OfType<IMethodSymbol>() .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation); // try to bind to the actual method var symbolInfo = semanticModel.GetSymbolInfo(invocationExpression, cancellationToken); var matchedMethodSymbol = symbolInfo.Symbol as IMethodSymbol; // if the symbol could be bound, replace that item in the symbol list if (matchedMethodSymbol != null && matchedMethodSymbol.IsGenericMethod) { methodGroup = methodGroup.Select(m => matchedMethodSymbol.OriginalDefinition == m ? matchedMethodSymbol : m); } methodGroup = methodGroup.Sort(symbolDisplayService, semanticModel, invocationExpression.SpanStart); var expressionType = semanticModel.GetTypeInfo(invocationExpression.Expression, cancellationToken).Type as INamedTypeSymbol; var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>(); var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>(); var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(invocationExpression.ArgumentList); var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); if (methodGroup.Any()) { return CreateSignatureHelpItems( GetMethodGroupItems(invocationExpression, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, within, methodGroup, cancellationToken), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); } else if (expressionType != null && expressionType.TypeKind == TypeKind.Delegate) { return CreateSignatureHelpItems( GetDelegateInvokeItems(invocationExpression, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, within, expressionType, cancellationToken), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); } else { return null; } }
protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); ConstructorInitializerSyntax constructorInitializer; if (!TryGetConstructorInitializer(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out constructorInitializer)) { return null; } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var within = semanticModel.GetEnclosingNamedType(position, cancellationToken); if (within == null) { return null; } if (within.TypeKind != TypeKind.Struct && within.TypeKind != TypeKind.Class) { return null; } var type = constructorInitializer.Kind() == SyntaxKind.BaseConstructorInitializer ? within.BaseType : within; if (type == null) { return null; } var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>(); var accessibleConstructors = type.InstanceConstructors .Where(c => c.IsAccessibleWithin(within)) .Where(c => c.IsEditorBrowsable(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)) .Sort(symbolDisplayService, semanticModel, constructorInitializer.SpanStart); if (!accessibleConstructors.Any()) { return null; } var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>(); var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>(); var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(constructorInitializer.ArgumentList); var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); return CreateSignatureHelpItems(accessibleConstructors.Select(c => Convert(c, constructorInitializer.ArgumentList.OpenParenToken, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, cancellationToken)), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); }
public void ComputeModel( IList<ISignatureHelpProvider> matchedProviders, IList<ISignatureHelpProvider> unmatchedProviders, SignatureHelpTriggerInfo triggerInfo) { AssertIsForeground(); var caretPosition = Controller.TextView.GetCaretPoint(Controller.SubjectBuffer).Value; var disconnectedBufferGraph = new DisconnectedBufferGraph(Controller.SubjectBuffer, Controller.TextView.TextBuffer); // If we've already computed a model, then just use that. Otherwise, actually // compute a new model and send that along. Computation.ChainTaskAndNotifyControllerWhenFinished( (model, cancellationToken) => ComputeModelInBackgroundAsync(model, matchedProviders, unmatchedProviders, caretPosition, disconnectedBufferGraph, triggerInfo, cancellationToken)); }
/// <summary> /// Returns <code>null</code> if our work was preempted and we want to return the /// previous model we've computed. /// </summary> private async Task <(ISignatureHelpProvider provider, SignatureHelpItems items)> ComputeItemsAsync( ISignatureHelpProvider[] providers, int caretPosition, SIGHLP.SignatureHelpTriggerInfo triggerInfo, Document document, CancellationToken cancellationToken) { ISignatureHelpProvider bestProvider = null; SignatureHelpItems bestItems = null; // TODO(cyrusn): We're calling into extensions, we need to make ourselves resilient // to the extension crashing. foreach (var provider in providers) { // If this is a retrigger command, and another retrigger command has already // been issued then we can bail out immediately. //if (IsNonTypeCharRetrigger(triggerInfo) && // localRetriggerId != _retriggerId) { // return null; //} cancellationToken.ThrowIfCancellationRequested(); var currentItems = await provider.GetItemsAsync(document, caretPosition, triggerInfo, cancellationToken).ConfigureAwait(false); if (currentItems != null && currentItems.ApplicableSpan.IntersectsWith(caretPosition)) { // If another provider provides sig help items, then only take them if they // start after the last batch of items. i.e. we want the set of items that // conceptually are closer to where the caret position is. This way if you have: // // Goo(new Bar($$ // // Then invoking sig help will only show the items for "new Bar(" and not also // the items for "Goo(..." if (IsBetter(bestItems, currentItems.ApplicableSpan)) { bestItems = new SignatureHelpItems(currentItems); bestProvider = provider; } } } return(bestProvider, bestItems); }
protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); AttributeSyntax attribute; if (!TryGetAttributeExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out attribute)) { return null; } var semanticModel = await document.GetSemanticModelForNodeAsync(attribute, cancellationToken).ConfigureAwait(false); var attributeType = semanticModel.GetTypeInfo(attribute, cancellationToken).Type as INamedTypeSymbol; if (attributeType == null) { return null; } var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); if (within == null) { return null; } var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>(); var accessibleConstructors = attributeType.InstanceConstructors .WhereAsArray(c => c.IsAccessibleWithin(within)) .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation) .Sort(symbolDisplayService, semanticModel, attribute.SpanStart); if (!accessibleConstructors.Any()) { return null; } var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>(); var documentationCommentFormatter = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>(); var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(attribute.ArgumentList); var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); return CreateSignatureHelpItems(accessibleConstructors.Select(c => Convert(c, within, attribute, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormatter, cancellationToken)).ToList(), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); }
private async Task <Tuple <ISignatureHelpProvider, SignatureHelpItems> > ComputeItemsAsync( IList <ISignatureHelpProvider> providers, int caretPosition, SIGHLP.SignatureHelpTriggerInfo triggerInfo, Document document, CancellationToken cancellationToken) { ISignatureHelpProvider bestProvider = null; SignatureHelpItems bestItems = null; // TODO(cyrusn): We're calling into extensions, we need to make ourselves resilient // to the extension crashing. foreach (var provider in providers) { cancellationToken.ThrowIfCancellationRequested(); var currentItems = await provider.GetItemsAsync(document, caretPosition, triggerInfo, cancellationToken).ConfigureAwait(false); if (currentItems != null && currentItems.ApplicableSpan.IntersectsWith(caretPosition)) { // If another provider provides sig help items, then only take them if they // start after the last batch of items. i.e. we want the set of items that // conceptually are closer to where the caret position is. This way if you have: // // Foo(new Bar($$ // // Then invoking sig help will only show the items for "new Bar(" and not also // the items for "Foo(..." if (IsBetter(bestItems, currentItems.ApplicableSpan)) { bestItems = new SignatureHelpItems(currentItems); bestProvider = provider; } } } return(Tuple.Create(bestProvider, bestItems)); }
public async Task <SignatureHelpItems?> GetItemsAsync( Document document, int position, SignatureHelpTriggerInfo triggerInfo, SignatureHelpOptions options, CancellationToken cancellationToken) { var itemsForCurrentDocument = await GetItemsWorkerAsync(document, position, triggerInfo, options, cancellationToken).ConfigureAwait(false); if (itemsForCurrentDocument == null) { return(itemsForCurrentDocument); } var relatedDocuments = await FindActiveRelatedDocumentsAsync(position, document, cancellationToken).ConfigureAwait(false); if (relatedDocuments.IsEmpty) { return(itemsForCurrentDocument); } var totalProjects = relatedDocuments.Select(d => d.Project.Id).Concat(document.Project.Id); var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false); var compilation = semanticModel.Compilation; var finalItems = new List <SignatureHelpItem>(); foreach (var item in itemsForCurrentDocument.Items) { if (item is not SymbolKeySignatureHelpItem symbolKeyItem || symbolKeyItem.SymbolKey is not SymbolKey symbolKey || symbolKey.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken).Symbol is not ISymbol symbol) { finalItems.Add(item); continue; } // If the symbol is an instantiated generic method, ensure we use its original // definition for symbol key resolution in related compilations. if (symbol is IMethodSymbol methodSymbol && methodSymbol.IsGenericMethod && methodSymbol != methodSymbol.OriginalDefinition) { symbolKey = SymbolKey.Create(methodSymbol.OriginalDefinition, cancellationToken); } var invalidProjectsForCurrentSymbol = new List <ProjectId>(); foreach (var relatedDocument in relatedDocuments) { // Try to resolve symbolKey in each related compilation, // unresolvable key means the symbol is unavailable in the corresponding project. var relatedSemanticModel = await relatedDocument.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false); if (symbolKey.Resolve(relatedSemanticModel.Compilation, ignoreAssemblyKey: true, cancellationToken).Symbol == null) { invalidProjectsForCurrentSymbol.Add(relatedDocument.Project.Id); } } var platformData = new SupportedPlatformData(document.Project.Solution, invalidProjectsForCurrentSymbol, totalProjects); finalItems.Add(UpdateItem(item, platformData)); } return(new SignatureHelpItems( finalItems, itemsForCurrentDocument.ApplicableSpan, itemsForCurrentDocument.ArgumentIndex, itemsForCurrentDocument.ArgumentCount, itemsForCurrentDocument.ArgumentName, itemsForCurrentDocument.SelectedItemIndex)); }
protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); SyntaxToken genericIdentifier, lessThanToken; if (!TryGetGenericIdentifier(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out genericIdentifier, out lessThanToken)) { return null; } var simpleName = genericIdentifier.Parent as SimpleNameSyntax; if (simpleName == null) { return null; } var beforeDotExpression = simpleName.IsRightSideOfDot() ? simpleName.GetLeftSideOfDot() : null; var semanticModel = await document.GetSemanticModelForNodeAsync(simpleName, cancellationToken).ConfigureAwait(false); var leftSymbol = beforeDotExpression == null ? null : semanticModel.GetSymbolInfo(beforeDotExpression, cancellationToken).GetAnySymbol() as INamespaceOrTypeSymbol; var leftType = beforeDotExpression == null ? null : semanticModel.GetTypeInfo(beforeDotExpression, cancellationToken).Type as INamespaceOrTypeSymbol; var leftContainer = leftSymbol ?? leftType; var isBaseAccess = beforeDotExpression is BaseExpressionSyntax; var namespacesOrTypesOnly = SyntaxFacts.IsInNamespaceOrTypeContext(simpleName); var includeExtensions = leftSymbol == null && leftType != null; var name = genericIdentifier.ValueText; var symbols = isBaseAccess ? semanticModel.LookupBaseMembers(position, name) : namespacesOrTypesOnly ? semanticModel.LookupNamespacesAndTypes(position, leftContainer, name) : semanticModel.LookupSymbols(position, leftContainer, name, includeExtensions); var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); if (within == null) { return null; } var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>(); var accessibleSymbols = symbols.Where(s => s.GetArity() > 0) .Where(s => s is INamedTypeSymbol || s is IMethodSymbol) .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation) .Sort(symbolDisplayService, semanticModel, genericIdentifier.SpanStart); if (!accessibleSymbols.Any()) { return null; } var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>(); var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>(); var textSpan = GetTextSpan(genericIdentifier, lessThanToken); var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); return CreateSignatureHelpItems(accessibleSymbols.Select(s => Convert(s, lessThanToken, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, cancellationToken)).ToList(), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); }
protected async Task <List <Tuple <Document, IEnumerable <SignatureHelpItem> > > > GetItemsForRelatedDocuments(Document document, IEnumerable <DocumentId> relatedDocuments, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var supportedPlatforms = new List <Tuple <Document, IEnumerable <SignatureHelpItem> > >(); foreach (var relatedDocumentId in relatedDocuments) { var relatedDocument = document.Project.Solution.GetDocument(relatedDocumentId); var semanticModel = await relatedDocument.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false); var result = await GetItemsWorkerAsync(relatedDocument, position, triggerInfo, cancellationToken).ConfigureAwait(false); supportedPlatforms.Add(Tuple.Create(relatedDocument, result != null ? result.Items : SpecializedCollections.EmptyEnumerable <SignatureHelpItem>())); } return(supportedPlatforms); }
protected async Task<List<Tuple<Document, IEnumerable<SignatureHelpItem>>>> GetItemsForRelatedDocuments(Document document, IEnumerable<DocumentId> relatedDocuments, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var supportedPlatforms = new List<Tuple<Document, IEnumerable<SignatureHelpItem>>>(); foreach (var relatedDocumentId in relatedDocuments) { var relatedDocument = document.Project.Solution.GetDocument(relatedDocumentId); var semanticModel = await relatedDocument.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false); var result = await GetItemsWorkerAsync(relatedDocument, position, triggerInfo, cancellationToken).ConfigureAwait(false); supportedPlatforms.Add(Tuple.Create(relatedDocument, result != null ? result.Items : SpecializedCollections.EmptyEnumerable<SignatureHelpItem>())); } return supportedPlatforms; }
public async Task<SignatureHelpItems> GetItemsAsync( Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var itemsForCurrentDocument = await GetItemsWorkerAsync(document, position, triggerInfo, cancellationToken).ConfigureAwait(false); if (itemsForCurrentDocument == null) { return itemsForCurrentDocument; } var relatedDocuments = document.GetLinkedDocumentIds(); if (!relatedDocuments.Any()) { return itemsForCurrentDocument; } var relatedDocumentsAndItems = await GetItemsForRelatedDocuments(document, relatedDocuments, position, triggerInfo, cancellationToken).ConfigureAwait(false); var candidateLinkedProjectsAndSymbolSets = await ExtractSymbolsFromRelatedItems(position, relatedDocumentsAndItems, cancellationToken).ConfigureAwait(false); var totalProjects = candidateLinkedProjectsAndSymbolSets.Select(c => c.Item1).Concat(document.Project.Id); var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false); var compilation = semanticModel.Compilation; var finalItems = new List<SignatureHelpItem>(); foreach (var item in itemsForCurrentDocument.Items) { var symbolKey = ((SymbolKeySignatureHelpItem)item).SymbolKey; if (symbolKey == null) { finalItems.Add(item); continue; } var expectedSymbol = symbolKey.Value.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken: cancellationToken).Symbol; if (expectedSymbol == null) { finalItems.Add(item); continue; } var invalidProjectsForCurrentSymbol = candidateLinkedProjectsAndSymbolSets.Where(c => !c.Item2.Contains(expectedSymbol, LinkedFilesSymbolEquivalenceComparer.Instance)) .Select(c => c.Item1) .ToList(); var platformData = new SupportedPlatformData(invalidProjectsForCurrentSymbol, totalProjects, document.Project.Solution.Workspace); finalItems.Add(UpdateItem(item, platformData, expectedSymbol)); } return new SignatureHelpItems( finalItems, itemsForCurrentDocument.ApplicableSpan, itemsForCurrentDocument.ArgumentIndex, itemsForCurrentDocument.ArgumentCount, itemsForCurrentDocument.ArgumentName, itemsForCurrentDocument.SelectedItemIndex); }
private async Task<Model> ComputeModelInBackgroundAsync( Model currentModel, IList<ISignatureHelpProvider> matchedProviders, IList<ISignatureHelpProvider> unmatchedProviders, SnapshotPoint caretPosition, DisconnectedBufferGraph disconnectedBufferGraph, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { try { using (Logger.LogBlock(FunctionId.SignatureHelp_ModelComputation_ComputeModelInBackground, cancellationToken)) { AssertIsBackground(); cancellationToken.ThrowIfCancellationRequested(); var document = await Controller.DocumentProvider.GetDocumentAsync(caretPosition.Snapshot, cancellationToken).ConfigureAwait(false); if (document == null) { return currentModel; } if (triggerInfo.TriggerReason == SignatureHelpTriggerReason.RetriggerCommand) { if (currentModel == null || (triggerInfo.TriggerCharacter.HasValue && !currentModel.Provider.IsRetriggerCharacter(triggerInfo.TriggerCharacter.Value))) { return currentModel; } } // first try to query the providers that can trigger on the specified character var result = await ComputeItemsAsync(matchedProviders, caretPosition, triggerInfo, document, cancellationToken).ConfigureAwait(false); var provider = result.Item1; var items = result.Item2; if (provider == null) { // no match, so now query the other providers result = await ComputeItemsAsync(unmatchedProviders, caretPosition, triggerInfo, document, cancellationToken).ConfigureAwait(false); provider = result.Item1; items = result.Item2; if (provider == null) { // the other providers didn't produce items either, so we don't produce a model return null; } } if (currentModel != null && currentModel.Provider == provider && currentModel.GetCurrentSpanInSubjectBuffer(disconnectedBufferGraph.SubjectBufferSnapshot).Span.Start == items.ApplicableSpan.Start && currentModel.ArgumentIndex == items.ArgumentIndex && currentModel.ArgumentCount == items.ArgumentCount && currentModel.ArgumentName == items.ArgumentName) { // The new model is the same as the current model. Return the currentModel // so we keep the active selection. return currentModel; } var selectedItem = GetSelectedItem(currentModel, items, provider); var model = new Model(disconnectedBufferGraph, items.ApplicableSpan, provider, items.Items, selectedItem, items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, selectedParameter: 0); var syntaxFactsService = document.GetLanguageService<ISyntaxFactsService>(); var isCaseSensitive = syntaxFactsService == null || syntaxFactsService.IsCaseSensitive; var selection = DefaultSignatureHelpSelector.GetSelection(model.Items, model.SelectedItem, model.ArgumentIndex, model.ArgumentCount, model.ArgumentName, isCaseSensitive); return model.WithSelectedItem(selection.SelectedItem) .WithSelectedParameter(selection.SelectedParameter); } } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public void ComputeModel( IList<ISignatureHelpProvider> providers, SignatureHelpTriggerInfo triggerInfo) { ComputeModel(providers, SpecializedCollections.EmptyList<ISignatureHelpProvider>(), triggerInfo); }
private async Task<Tuple<ISignatureHelpProvider, SignatureHelpItems>> ComputeItemsAsync( IList<ISignatureHelpProvider> providers, SnapshotPoint caretPosition, SignatureHelpTriggerInfo triggerInfo, Document document, CancellationToken cancellationToken) { try { ISignatureHelpProvider bestProvider = null; SignatureHelpItems bestItems = null; // TODO(cyrusn): We're calling into extensions, we need to make ourselves resilient // to the extension crashing. foreach (var provider in providers) { cancellationToken.ThrowIfCancellationRequested(); var currentItems = await provider.GetItemsAsync(document, caretPosition, triggerInfo, cancellationToken).ConfigureAwait(false); if (currentItems != null && currentItems.ApplicableSpan.IntersectsWith(caretPosition.Position)) { // If another provider provides sig help items, then only take them if they // start after the last batch of items. i.e. we want the set of items that // conceptually are closer to where the caret position is. This way if you have: // // Foo(new Bar($$ // // Then invoking sig help will only show the items for "new Bar(" and not also // the items for "Foo(..." if (IsBetter(bestItems, currentItems.ApplicableSpan)) { bestItems = currentItems; bestProvider = provider; } } } return Tuple.Create(bestProvider, bestItems); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>(); var typeInferrer = document.Project.LanguageServices.GetService<ITypeInferenceService>(); var inferredTypes = FindNearestTupleConstructionWithInferrableType(root, semanticModel, position, triggerInfo, typeInferrer, syntaxFacts, cancellationToken, out var targetExpression); if (inferredTypes == null || !inferredTypes.Any()) { return null; } return CreateItems(position, root, syntaxFacts, targetExpression, semanticModel, inferredTypes, cancellationToken); }
IEnumerable<INamedTypeSymbol> FindNearestTupleConstructionWithInferrableType(SyntaxNode root, SemanticModel semanticModel, int position, SignatureHelpTriggerInfo triggerInfo, ITypeInferenceService typeInferrer, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken, out ExpressionSyntax targetExpression) { // Walk upward through TupleExpressionSyntax/ParenthsizedExpressionSyntax looking for a // place where we can infer a tuple type. ParenthesizedExpressionSyntax parenthesizedExpression = null; while (TryGetTupleExpression(triggerInfo.TriggerReason, root, position, syntaxFacts, cancellationToken, out var tupleExpression) || TryGetParenthesizedExpression(triggerInfo.TriggerReason, root, position, syntaxFacts, cancellationToken, out parenthesizedExpression)) { targetExpression = (ExpressionSyntax)tupleExpression ?? parenthesizedExpression; var inferredTypes = typeInferrer.InferTypes(semanticModel, targetExpression.SpanStart, cancellationToken); var tupleTypes = inferredTypes.Where(t => t.IsTupleType).OfType<INamedTypeSymbol>().ToList(); if (tupleTypes.Any()) { return tupleTypes; } position = targetExpression.GetFirstToken().SpanStart; } targetExpression = null; return null; }
protected abstract Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken);
protected abstract Task <SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken);
protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax expression; SyntaxToken openBrace; if (!TryGetElementAccessExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out expression, out openBrace)) { return null; } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var expressionSymbol = semanticModel.GetSymbolInfo(expression, cancellationToken).GetAnySymbol(); if (expressionSymbol is INamedTypeSymbol) { // foo?[$$] var namedType = (INamedTypeSymbol)expressionSymbol; if (namedType.ConstructedFrom.SpecialType == SpecialType.System_Nullable_T && expression.IsKind(SyntaxKind.NullableType) && expression.IsChildNode<ArrayTypeSyntax>(a => a.ElementType)) { // Speculatively bind the type part of the nullable as an expression var nullableTypeSyntax = (NullableTypeSyntax)expression; var speculativeBinding = semanticModel.GetSpeculativeSymbolInfo(position, nullableTypeSyntax.ElementType, SpeculativeBindingOption.BindAsExpression); expressionSymbol = speculativeBinding.GetAnySymbol(); expression = nullableTypeSyntax.ElementType; } } if (expressionSymbol != null && expressionSymbol is INamedTypeSymbol) { return null; } IEnumerable<IPropertySymbol> indexers; ITypeSymbol expressionType; if (!TryGetIndexers(position, semanticModel, expression, cancellationToken, out indexers, out expressionType) && !TryGetComIndexers(semanticModel, expression, cancellationToken, out indexers, out expressionType)) { return null; } var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); if (within == null) { return null; } var accessibleIndexers = indexers.Where(m => m.IsAccessibleWithin(within, throughTypeOpt: expressionType)); if (!accessibleIndexers.Any()) { return null; } var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>(); accessibleIndexers = accessibleIndexers.FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation) .Sort(symbolDisplayService, semanticModel, expression.SpanStart); var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>(); var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>(); var textSpan = GetTextSpan(expression, openBrace); var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>(); return CreateSignatureHelpItems(accessibleIndexers.Select(p => Convert(p, openBrace, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, cancellationToken)), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); }