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)); }
public async Task <SignatureHelpItems> GetSignatureHelp(SignatureHelpTriggerInfo trigger, int position) { var document = GetCurrentDocument(); foreach (var provider in _signatureHelpProviders) { var items = await provider.GetItemsAsync(document, position, trigger, CancellationToken.None) .ConfigureAwait(false); if (items != null) { return(items); } } return(null); }
public void ComputeModel( ImmutableArray <ISignatureHelpProvider> providers, 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, providers, caretPosition, disconnectedBufferGraph, triggerInfo, cancellationToken)); }
void Start(SignatureHelpInfo info, SnapshotPoint triggerPosition, SignatureHelpTriggerInfo triggerInfo) { CancelFetchItems(); Debug.Assert(cancellationTokenSource == null); cancellationTokenSource = new CancellationTokenSource(); var cancellationTokenSourceTmp = cancellationTokenSource; StartAsync(info, triggerPosition, triggerInfo, cancellationTokenSource.Token) .ContinueWith(t => { var ex = t.Exception; // Free resources if (cancellationTokenSource == cancellationTokenSourceTmp) { CancelFetchItems(); } }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); }
private async Task TestSignatureHelpWorkerSharedAsync( string code, int cursorPosition, SourceCodeKind sourceCodeKind, Document document, TextSpan?textSpan, IEnumerable <SignatureHelpTestItem> expectedOrderedItemsOrNull = null, bool usePreviousCharAsTrigger = false) { var signatureHelpProvider = CreateSignatureHelpProvider(); var triggerInfo = new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.InvokeSignatureHelpCommand); if (usePreviousCharAsTrigger) { triggerInfo = new SignatureHelpTriggerInfo( SignatureHelpTriggerReason.TypeCharCommand, code.ElementAt(cursorPosition - 1)); if (!signatureHelpProvider.IsTriggerCharacter(triggerInfo.TriggerCharacter.Value)) { return; } } var items = await signatureHelpProvider.GetItemsAsync(document, cursorPosition, triggerInfo, CancellationToken.None); // If we're expecting 0 items, then there's no need to compare them if ((expectedOrderedItemsOrNull == null || !expectedOrderedItemsOrNull.Any()) && items == null) { return; } AssertEx.NotNull(items, "Signature help provider returned null for items. Did you forget $$ in the test or is the test otherwise malformed, e.g. quotes not escaped?"); // Verify the span if (textSpan != null) { Assert.Equal(textSpan, items.ApplicableSpan); } if (expectedOrderedItemsOrNull != null) { CompareAndAssertCollectionsAndCurrentParameter(expectedOrderedItemsOrNull, items); CompareSelectedIndex(expectedOrderedItemsOrNull, items.SelectedItemIndex); } }
private static async Task <(ISignatureHelpProvider provider, SignatureHelpItems items)> ComputeItemsAsync( ImmutableArray <ISignatureHelpProvider> providers, SnapshotPoint caretPosition, SignatureHelpTriggerInfo triggerInfo, SignatureHelpOptions options, 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, options, 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: // // 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 = currentItems; bestProvider = provider; } } } return(bestProvider, bestItems); } catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken, ErrorSeverity.Critical)) { return(null, null); } }
async Task StartAsync(SignatureHelpInfo info, SnapshotPoint triggerPosition, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { // This helps a little to speed up the code ProfileOptimizationHelper.StartProfile("roslyn-sighelp-" + info.SignatureHelpService.Language); var result = await info.SignatureHelpService.GetItemsAsync(info.Document, triggerPosition.Position, triggerInfo, cancellationToken); if (result == null) { Dispose(); return; } if (cancellationToken.IsCancellationRequested) { return; } StartSession(triggerPosition, result); }
protected override async Task <SignatureHelpItems?> GetItemsWorkerAsync( Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken ) { var root = await document .GetRequiredSyntaxRootAsync(cancellationToken) .ConfigureAwait(false); var semanticModel = await document .GetRequiredSemanticModelAsync(cancellationToken) .ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>(); var typeInferrer = document.GetRequiredLanguageService <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 )); }
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 .Where(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)), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); }
// TODO: Some of this is duplicated from Controller.Session_ComputeModel.cs private async Task <SignatureHelpItems> GetItemsAsync(LogicalDocument document, int position, CancellationToken cancellationToken) { var triggerInfo = new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.InvokeSignatureHelpCommand); var providers = _signatureHelpProviders .Where(x => x.Metadata.Language == document.Language) .Select(x => x.Value); ISignatureHelpProvider bestProvider = null; SignatureHelpItems bestItems = null; foreach (var provider in providers) { cancellationToken.ThrowIfCancellationRequested(); var currentItems = await provider.GetItemsAsync(document, position, triggerInfo, cancellationToken); if (currentItems != null && currentItems.ApplicableSpan.IntersectsWith(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(bestItems); }
protected abstract Task <SignatureHelpItems?> GetItemsAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken);
async Task InitializeAsync(ITextBuffer buffer, string code, MetadataReference[] refs, string languageName, ISynchronousTagger <IClassificationTag> tagger, CompilationOptions compilationOptions, ParseOptions parseOptions) { using (var workspace = new AdhocWorkspace(RoslynMefHostServices.DefaultServices)) { var documents = new List <DocumentInfo>(); var projectId = ProjectId.CreateNewId(); documents.Add(DocumentInfo.Create(DocumentId.CreateNewId(projectId), "main.cs", null, SourceCodeKind.Regular, TextLoader.From(buffer.AsTextContainer(), VersionStamp.Create()))); var projectInfo = ProjectInfo.Create(projectId, VersionStamp.Create(), "compilecodeproj", Guid.NewGuid().ToString(), languageName, compilationOptions: compilationOptions .WithOptimizationLevel(OptimizationLevel.Release) .WithPlatform(Platform.AnyCpu) .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default), parseOptions: parseOptions, documents: documents, metadataReferences: refs, isSubmission: false, hostObjectType: null); workspace.AddProject(projectInfo); foreach (var doc in documents) { workspace.OpenDocument(doc.Id); } buffer.Replace(new Span(0, buffer.CurrentSnapshot.Length), code); { // Initialize classification code paths var spans = new NormalizedSnapshotSpanCollection(new SnapshotSpan(buffer.CurrentSnapshot, 0, buffer.CurrentSnapshot.Length)); foreach (var tagSpan in tagger.GetTags(spans, CancellationToken.None)) { } } { // Initialize completion code paths var info = CompletionInfo.Create(buffer.CurrentSnapshot); Debug.Assert(info != null); if (info != null) { var completionTrigger = CompletionTrigger.Invoke; var completionList = await info.Value.CompletionService.GetCompletionsAsync(info.Value.Document, 0, completionTrigger); } } { // Initialize signature help code paths var info = SignatureHelpInfo.Create(buffer.CurrentSnapshot); Debug.Assert(info != null); if (info != null) { int sigHelpIndex = code.IndexOf("sighelp"); Debug.Assert(sigHelpIndex >= 0); var triggerInfo = new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.InvokeSignatureHelpCommand); var items = await info.Value.SignatureHelpService.GetItemsAsync(info.Value.Document, sigHelpIndex, triggerInfo); } } { // Initialize quick info code paths var info = QuickInfoState.Create(buffer.CurrentSnapshot); Debug.Assert(info != null); if (info != null) { int quickInfoIndex = code.IndexOf("Equals"); Debug.Assert(quickInfoIndex >= 0); var item = await info.Value.QuickInfoService.GetItemAsync(info.Value.Document, quickInfoIndex); } } } }
protected abstract Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken);
Task <SignatureHelpItems?> ISignatureHelpProvider.GetItemsAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, SignatureHelpOptions options, CancellationToken cancellationToken) => GetItemsAsync(document, position, triggerInfo, cancellationToken);
protected override async Task <SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (!TryGetElementAccessExpression(root, position, document.GetLanguageService <ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out var expression, out var openBrace)) { return(null); } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var expressionSymbol = semanticModel.GetSymbolInfo(expression, cancellationToken).GetAnySymbol(); // goo?[$$] if (expressionSymbol is INamedTypeSymbol namedType) { 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); } if (!TryGetIndexers(position, semanticModel, expression, cancellationToken, out var indexers, out var 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.WhereAsArray( 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)).ToList(), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken))); }
public async Task <SignatureHelpItems> GetItemsAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { // This provider is exported for all workspaces - so limit it to just our workspace. if (document.Project.Solution.Workspace.Kind != WorkspaceKind.AnyCodeRoslynWorkspace) { return(null); } var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient; if (lspClient == null) { return(null); } var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var textDocumentPositionParams = ProtocolConversions.PositionToTextDocumentPositionParams(position, text, document); var signatureHelp = await lspClient.RequestAsync(Methods.TextDocumentSignatureHelp.ToLSRequest(), textDocumentPositionParams, cancellationToken).ConfigureAwait(false); if (signatureHelp == null || signatureHelp.Signatures == null || signatureHelp.Signatures.Length <= 0) { return(null); } var items = new List <SignatureHelpItem>(); foreach (var signature in signatureHelp.Signatures) { items.Add(CreateSignatureHelpItem(signature)); } var linePosition = text.Lines.GetLinePosition(position); var applicableSpan = text.Lines.GetTextSpan(new CodeAnalysis.Text.LinePositionSpan(linePosition, linePosition)); return(new SignatureHelpItems(items, applicableSpan, signatureHelp.ActiveParameter, signatureHelp.ActiveParameter, null, signatureHelp.ActiveSignature)); }
public async Task <SignatureHelpItems> GetItemsAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var mappedTriggerReason = FSharpSignatureHelpTriggerReasonHelpers.ConvertFrom(triggerInfo.TriggerReason); var mappedTriggerInfo = new FSharpSignatureHelpTriggerInfo(mappedTriggerReason, triggerInfo.TriggerCharacter); var mappedSignatureHelpItems = await _provider.GetItemsAsync(document, position, mappedTriggerInfo, cancellationToken).ConfigureAwait(false); if (mappedSignatureHelpItems != null) { return(new SignatureHelpItems( mappedSignatureHelpItems.Items?.Select(x => new SignatureHelpItem( x.IsVariadic, x.DocumentationFactory, x.PrefixDisplayParts, x.SeparatorDisplayParts, x.SuffixDisplayParts, x.Parameters.Select(y => new SignatureHelpParameter( y.Name, y.IsOptional, y.DocumentationFactory, y.DisplayParts, y.PrefixDisplayParts, y.SuffixDisplayParts, y.SelectedDisplayParts)).ToList(), x.DescriptionParts)).ToList(), mappedSignatureHelpItems.ApplicableSpan, mappedSignatureHelpItems.ArgumentIndex, mappedSignatureHelpItems.ArgumentCount, mappedSignatureHelpItems.ArgumentName, mappedSignatureHelpItems.SelectedItemIndex)); } else { return(null); } }
protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetCSharpSyntaxRootAsync(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.GetCSharpSemanticModelAsync(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)); }
protected sealed override async Task <SignatureHelpItems> GetItemsWorkerAsync(LogicalDocument document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var sourceLocation = syntaxTree.MapRootFilePosition(position); var token = ((SyntaxNode)syntaxTree.Root).FindTokenOnLeft(sourceLocation); var node = token.Parent .AncestorsAndSelf() .OfType <TNode>() .FirstOrDefault(c => c.IsBetweenParentheses(sourceLocation)); if (node == null) { return(null); } var rootSpan = node.GetTextSpanRoot(); if (rootSpan == null) { return(null); } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (semanticModel == null) { return(null); } return(GetModel((SemanticModel)semanticModel, node, sourceLocation)); }
void IChainedCommandHandler <TypeCharCommandArgs> .ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CommandExecutionContext context) { AssertIsForeground(); var allProviders = GetProviders(); if (allProviders == null) { nextHandler(); return; } // Note: while we're doing this, we don't want to hear about buffer changes (since we // know they're going to happen). So we disconnect and reconnect to the event // afterwards. That way we can hear about changes to the buffer that don't happen // through us. this.TextView.TextBuffer.PostChanged -= OnTextViewBufferPostChanged; try { nextHandler(); } finally { this.TextView.TextBuffer.PostChanged += OnTextViewBufferPostChanged; } // We only want to process typechar if it is a normal typechar and no one else is // involved. i.e. if there was a typechar, but someone processed it and moved the caret // somewhere else then we don't want signature help. Also, if a character was typed but // something intercepted and placed different text into the editor, then we don't want // to proceed. // // Note: we do not want to pass along a text version here. It is expected that multiple // version changes may happen when we call 'nextHandler' and we will still want to // proceed. For example, if the user types "WriteL(", then that will involve two text // changes as completion commits that out to "WriteLine(". But we still want to provide // sig help in this case. if (this.TextView.TypeCharWasHandledStrangely(this.SubjectBuffer, args.TypedChar)) { // If we were computing anything, we stop. We only want to process a typechar // if it was a normal character. DismissSessionIfActive(); return; } // Separate the sig help providers into two buckets; one bucket for those that were triggered // by the typed character, and those that weren't. To keep our queries to a minimum, we first // check with the textually triggered providers. If none of those produced any sig help items // then we query the other providers to see if they can produce anything viable. This takes // care of cases where the filtered set of providers didn't provide anything but one of the // other providers could still be valid, but doesn't explicitly treat the typed character as // a trigger character. var(textuallyTriggeredProviders, untriggeredProviders) = FilterProviders(allProviders, args.TypedChar); var triggerInfo = new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.TypeCharCommand, args.TypedChar); if (!IsSessionActive) { // No computation at all. If this is not a trigger character, we just ignore it and // stay in this state. Otherwise, if it's a trigger character, start up a new // computation and start computing the model in the background. if (textuallyTriggeredProviders.Any()) { // First create the session that represents that we now have a potential // signature help list. Then tell it to start computing. StartSession(textuallyTriggeredProviders, triggerInfo); return; } else { // No need to do anything. Just stay in the state where we have no session. return; } } else { var computed = false; if (allProviders.Any(p => p.IsRetriggerCharacter(args.TypedChar))) { // The user typed a character that might close the scope of the current model. // In this case, we should requery all providers. // // e.g. Math.Max(Math.Min(1,2)$$ sessionOpt.ComputeModel(allProviders, new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.RetriggerCommand, triggerInfo.TriggerCharacter)); computed = true; } if (textuallyTriggeredProviders.Any()) { // The character typed was something like "(". It can both filter a list if // it was in a string like: Foo(bar, "( // // Or it can trigger a new list. Ask the computation to compute again. sessionOpt.ComputeModel( textuallyTriggeredProviders.Concat(untriggeredProviders), triggerInfo); computed = true; } if (!computed) { // A character was typed and we haven't updated our model; do so now. sessionOpt.ComputeModel(allProviders, new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.RetriggerCommand)); } } }
private static bool IsNonTypeCharRetrigger(SignatureHelpTriggerInfo triggerInfo) => triggerInfo.TriggerReason == SignatureHelpTriggerReason.RetriggerCommand && triggerInfo.TriggerCharacter == null;
public override System.Threading.Tasks.Task <CodeCompletion.ParameterHintingResult> HandleParameterCompletionAsync(CodeCompletion.CodeCompletionContext completionContext, SignatureHelpTriggerInfo triggerInfo, System.Threading.CancellationToken token) { return(completionTextEditorExtension.HandleParameterCompletionAsync(completionContext, triggerInfo, token)); }
public void ComputeModel( IList <ISignatureHelpProvider> providers, SignatureHelpTriggerInfo triggerInfo) { ComputeModel(providers, SpecializedCollections.EmptyList <ISignatureHelpProvider>(), triggerInfo); }
public void ComputeModel( IList<ISignatureHelpProvider> providers, SignatureHelpTriggerInfo triggerInfo) { ComputeModel(providers, SpecializedCollections.EmptyList<ISignatureHelpProvider>(), triggerInfo); }
protected override async Task <SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (!TryGetInitializerExpression(root, position, document.GetLanguageService <ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out var initializerExpression)) { return(null); } var addMethods = await CommonSignatureHelpUtilities.GetCollectionInitializerAddMethodsAsync( document, initializerExpression, cancellationToken).ConfigureAwait(false); if (addMethods.IsDefaultOrEmpty) { return(null); } var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(initializerExpression); var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); return(CreateCollectionInitializerSignatureHelpItems(addMethods.Select(s => ConvertMethodGroupMethod(document, s, initializerExpression.OpenBraceToken.SpanStart, semanticModel)).ToList(), 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); ConstructorInitializerSyntax constructorInitializer; if (!TryGetConstructorInitializer(root, position, document.GetLanguageService <ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out constructorInitializer)) { return(null); } var semanticModel = await document.GetCSharpSemanticModelAsync(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))); }
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; } }
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); }
public async Task <ParameterHintingResult> GetParameterDataProviderAsync(List <ISignatureHelpProvider> providers, Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken token = default(CancellationToken)) { var hintingData = new List <ParameterHintingData> (); SignatureHelpItems bestSignatureHelpItems = null; foreach (var provider in providers) { try { if (triggerInfo.TriggerReason == SignatureHelpTriggerReason.TypeCharCommand && !provider.IsTriggerCharacter(triggerInfo.TriggerCharacter.Value)) { continue; } if (triggerInfo.TriggerReason == SignatureHelpTriggerReason.RetriggerCommand && !provider.IsRetriggerCharacter(triggerInfo.TriggerCharacter.Value)) { continue; } var signatureHelpItems = await provider.GetItemsAsync(document, position, triggerInfo, token).ConfigureAwait(false); if (signatureHelpItems == null) { continue; } if (bestSignatureHelpItems == null) { bestSignatureHelpItems = signatureHelpItems; } else if (signatureHelpItems.ApplicableSpan.Start > bestSignatureHelpItems.ApplicableSpan.Start) { bestSignatureHelpItems = signatureHelpItems; } } catch (Exception e) { LoggingService.LogError("Error while getting items from parameter provider " + provider, e); } } if (bestSignatureHelpItems != null) { foreach (var item in bestSignatureHelpItems.Items) { hintingData.Add(new SignatureHelpParameterHintingData(item)); } var tree = await document.GetSyntaxTreeAsync(token); var tokenLeftOfPosition = tree.GetRoot(token).FindTokenOnLeftOfPosition(position); var syntaxNode = tokenLeftOfPosition.Parent; var node = syntaxNode?.FirstAncestorOrSelf <ArgumentListSyntax> (); return(new ParameterHintingResult(hintingData) { ApplicableSpan = bestSignatureHelpItems.ApplicableSpan, SelectedItemIndex = bestSignatureHelpItems.SelectedItemIndex, ParameterListStart = node != null ? node.SpanStart : bestSignatureHelpItems.ApplicableSpan.Start }); } return(ParameterHintingResult.Empty); }
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); } }
private static async Task <SignatureHelpState> GetArgumentStateAsync(int cursorPosition, Document document, ISignatureHelpProvider signatureHelpProvider, SignatureHelpTriggerInfo triggerInfo) { var items = await signatureHelpProvider.GetItemsAsync(document, cursorPosition, triggerInfo, CancellationToken.None); return(items == null ? null : new SignatureHelpState(items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, null)); }
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.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken: cancellationToken).Symbol; if (expectedSymbol == null) { finalItems.Add(item); continue; } var invalidProjectsForCurrentSymbol = candidateLinkedProjectsAndSymbolSets.Where(c => !c.Item2.Contains(expectedSymbol, LinkedFilesSymbolEquivalenceComparer.IgnoreAssembliesInstance)) .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; } }
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 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)), 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); 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 .Where(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)), textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken))); }
public async Task<SignatureHelpResult> GetItemsAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken = default(CancellationToken)) { var res = await ComputeItemsAsync(signatureHelpProviders, position, triggerInfo.ToSignatureHelpTriggerInfo(), document, cancellationToken).ConfigureAwait(false); return GetSignatureHelpResult(res, document); }