public static Task <CompletionDescription> CreateDescriptionAsync( Workspace workspace, SemanticModel semanticModel, int position, IReadOnlyList <ISymbol> symbols, SupportedPlatformData supportedPlatforms, CancellationToken cancellationToken ) { // Lets try to find the first non-obsolete symbol (overload) and fall-back // to the first symbol if all are obsolete. var symbol = symbols.FirstOrDefault(s => !s.IsObsolete()) ?? symbols[0]; return(CreateDescriptionAsync( workspace, semanticModel, position, symbol, overloadCount: symbols.Count - 1, supportedPlatforms, cancellationToken )); }
public static CompletionItem CreateWithNameAndKind( string displayText, string displayTextSuffix, IReadOnlyList <ISymbol> symbols, CompletionItemRules rules, int contextPosition, string sortText = null, string insertionText = null, string filterText = null, string displayTextPrefix = null, string inlineDescription = null, Glyph?glyph = null, SupportedPlatformData supportedPlatforms = null, ImmutableDictionary <string, string> properties = null, ImmutableArray <string> tags = default, bool isComplexTextEdit = false ) { return(CreateWorker( displayText, displayTextSuffix, symbols, rules, contextPosition, s_addSymbolInfo, sortText, insertionText, filterText, supportedPlatforms, properties, tags, displayTextPrefix, inlineDescription, glyph, isComplexTextEdit )); }
/// <summary> /// Given a Symbol, creates the completion item for it. /// </summary> private CompletionItem CreateItem( CompletionContext completionContext, string displayText, string displayTextSuffix, string insertionText, List <ISymbol> symbols, SyntaxContext context, Dictionary <ISymbol, List <ProjectId> > invalidProjectMap, List <ProjectId> totalProjects, bool preselect) { Contract.ThrowIfNull(symbols); SupportedPlatformData supportedPlatformData = null; if (invalidProjectMap != null) { List <ProjectId> invalidProjects = null; foreach (var symbol in symbols) { if (invalidProjectMap.TryGetValue(symbol, out invalidProjects)) { break; } } if (invalidProjects != null) { supportedPlatformData = new SupportedPlatformData(invalidProjects, totalProjects, context.Workspace); } } return(CreateItem( completionContext, displayText, displayTextSuffix, insertionText, symbols, context, preselect, supportedPlatformData)); }
protected override CompletionItem CreateItem( string displayText, string displayTextSuffix, string insertionText, List <ISymbol> symbols, SyntaxContext context, bool preselect, SupportedPlatformData supportedPlatformData) { var rules = GetCompletionItemRules(symbols, context, preselect); var matchPriority = preselect ? ComputeSymbolMatchPriority(symbols[0]) : MatchPriority.Default; rules = rules.WithMatchPriority(matchPriority); if (preselect) { rules = rules.WithSelectionBehavior(PreselectedItemSelectionBehavior); } return(SymbolCompletionItem.CreateWithNameAndKind( displayText: displayText, displayTextSuffix: displayTextSuffix, symbols: symbols, rules: rules, contextPosition: context.Position, insertionText: insertionText, filterText: GetFilterText(symbols[0], displayText, context), supportedPlatforms: supportedPlatformData)); }
private static CompletionItem CreateWorker( string displayText, IReadOnlyList <ISymbol> symbols, CompletionItemRules rules, int contextPosition, Func <IReadOnlyList <ISymbol>, CompletionItem, CompletionItem> symbolEncoder, string sortText = null, string insertionText = null, string filterText = null, SupportedPlatformData supportedPlatforms = null, ImmutableDictionary <string, string> properties = null, ImmutableArray <string> tags = default) { var props = properties ?? ImmutableDictionary <string, string> .Empty; if (insertionText != null) { props = props.Add("InsertionText", insertionText); } props = props.Add("ContextPosition", contextPosition.ToString()); var firstSymbol = symbols[0]; var item = CommonCompletionItem.Create( displayText: displayText, rules: rules, filterText: filterText ?? (displayText.Length > 0 && displayText[0] == '@' ? displayText : firstSymbol.Name), sortText: sortText ?? firstSymbol.Name, glyph: firstSymbol.GetGlyph(), showsWarningIcon: supportedPlatforms != null, properties: props, tags: tags); item = WithSupportedPlatforms(item, supportedPlatforms); return(symbolEncoder(symbols, item)); }
private static SignatureHelpItem UpdateItem( SignatureHelpItem item, SupportedPlatformData platformData ) { var platformParts = platformData.ToDisplayParts().ToTaggedText(); if (platformParts.Length == 0) { return(item); } var startingNewLine = new List <TaggedText>(); startingNewLine.AddLineBreak(); var concatted = startingNewLine.Concat(platformParts); var updatedDescription = item.DescriptionParts.IsDefault ? concatted : item.DescriptionParts.Concat(concatted); item.DescriptionParts = updatedDescription.ToImmutableArrayOrEmpty(); return(item); }
public SymbolCompletionItem( CompletionListProvider completionProvider, string displayText, string insertionText, string filterText, TextSpan filterSpan, int position, List <ISymbol> symbols, string sortText, AbstractSyntaxContext context, Glyph glyph, bool preselect = false, SupportedPlatformData supportedPlatforms = null, CompletionItemRules rules = null) : base(completionProvider, displayText, filterSpan, descriptionFactory: null, glyph: glyph, sortText: sortText, filterText: filterText, preselect: preselect, showsWarningIcon: supportedPlatforms != null, rules: rules) { this.InsertionText = insertionText; this.Position = position; this.Symbols = symbols; this.Context = context; _supportedPlatforms = supportedPlatforms; }
public static Task <CompletionDescription> CreateDescriptionAsync( Workspace workspace, SemanticModel semanticModel, int position, IReadOnlyList <ISymbol> symbols, SupportedPlatformData supportedPlatforms, CancellationToken cancellationToken) { return(CreateDescriptionAsync(workspace, semanticModel, position, symbols[0], overloadCount: symbols.Count - 1, supportedPlatforms, cancellationToken)); }
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)); }
private static CompletionItem WithSupportedPlatforms(CompletionItem completionItem, SupportedPlatformData supportedPlatforms) { if (supportedPlatforms != null) { return(completionItem .AddProperty("InvalidProjects", string.Join(";", supportedPlatforms.InvalidProjects.Select(id => id.Id))) .AddProperty("CandidateProjects", string.Join(";", supportedPlatforms.CandidateProjects.Select(id => id.Id)))); } else { return(completionItem); } }
public static Func <CancellationToken, Task <CompletionDescription> > CreateDescriptionFactory( Workspace workspace, SemanticModel semanticModel, int position, IReadOnlyList <ISymbol> symbols, SupportedPlatformData supportedPlatforms) { return(c => CreateDescriptionAsync(workspace, semanticModel, position, symbols, supportedPlatforms: supportedPlatforms, cancellationToken: c)); }
private async Task <IDeferredQuickInfoContent> CreateContentAsync( Workspace workspace, SyntaxToken token, SemanticModel semanticModel, IEnumerable <ISymbol> symbols, SupportedPlatformData supportedPlatforms, CancellationToken cancellationToken) { var descriptionService = workspace.Services.GetLanguageServices(token.Language).GetService <ISymbolDisplayService>(); var sections = await descriptionService.ToDescriptionGroupsAsync(workspace, semanticModel, token.SpanStart, symbols.AsImmutable(), cancellationToken).ConfigureAwait(false); var mainDescriptionBuilder = new List <TaggedText>(); if (sections.ContainsKey(SymbolDescriptionGroups.MainDescription)) { mainDescriptionBuilder.AddRange(sections[SymbolDescriptionGroups.MainDescription]); } var typeParameterMapBuilder = new List <TaggedText>(); if (sections.ContainsKey(SymbolDescriptionGroups.TypeParameterMap)) { var parts = sections[SymbolDescriptionGroups.TypeParameterMap]; if (!parts.IsDefaultOrEmpty) { typeParameterMapBuilder.AddLineBreak(); typeParameterMapBuilder.AddRange(parts); } } var anonymousTypesBuilder = new List <TaggedText>(); if (sections.ContainsKey(SymbolDescriptionGroups.AnonymousTypes)) { var parts = sections[SymbolDescriptionGroups.AnonymousTypes]; if (!parts.IsDefaultOrEmpty) { anonymousTypesBuilder.AddLineBreak(); anonymousTypesBuilder.AddRange(parts); } } var usageTextBuilder = new List <TaggedText>(); if (sections.ContainsKey(SymbolDescriptionGroups.AwaitableUsageText)) { var parts = sections[SymbolDescriptionGroups.AwaitableUsageText]; if (!parts.IsDefaultOrEmpty) { usageTextBuilder.AddRange(parts); } } if (supportedPlatforms != null) { usageTextBuilder.AddRange(supportedPlatforms.ToDisplayParts().ToTaggedText()); } var exceptionsTextBuilder = new List <TaggedText>(); if (sections.ContainsKey(SymbolDescriptionGroups.Exceptions)) { var parts = sections[SymbolDescriptionGroups.Exceptions]; if (!parts.IsDefaultOrEmpty) { exceptionsTextBuilder.AddRange(parts); } } var formatter = workspace.Services.GetLanguageServices(semanticModel.Language).GetService <IDocumentationCommentFormattingService>(); var syntaxFactsService = workspace.Services.GetLanguageServices(semanticModel.Language).GetService <ISyntaxFactsService>(); var documentationContent = GetDocumentationContent(symbols, sections, semanticModel, token, formatter, syntaxFactsService, cancellationToken); var showWarningGlyph = supportedPlatforms != null && supportedPlatforms.HasValidAndInvalidProjects(); var showSymbolGlyph = true; if (workspace.Services.GetLanguageServices(semanticModel.Language).GetService <ISyntaxFactsService>().IsAwaitKeyword(token) && (symbols.First() as INamedTypeSymbol)?.SpecialType == SpecialType.System_Void) { documentationContent = _contentProvider.CreateDocumentationCommentDeferredContent(null); showSymbolGlyph = false; } return(_contentProvider.CreateQuickInfoDisplayDeferredContent( symbol: symbols.First(), showWarningGlyph: showWarningGlyph, showSymbolGlyph: showSymbolGlyph, mainDescription: mainDescriptionBuilder, documentation: documentationContent, typeParameterMap: typeParameterMapBuilder, anonymousTypes: anonymousTypesBuilder, usageText: usageTextBuilder, exceptionText: exceptionsTextBuilder)); }
protected virtual CompletionItem CreateItem(string displayText, string insertionText, int position, List <ISymbol> symbols, AbstractSyntaxContext context, TextSpan span, bool preselect, SupportedPlatformData supportedPlatformData) { return(SymbolCompletionItem.Create( displayText: displayText, insertionText: insertionText, filterText: GetFilterText(symbols[0], displayText, context), span: span, contextPosition: context.Position, descriptionPosition: position, symbols: symbols, supportedPlatforms: supportedPlatformData, preselect: preselect, rules: GetCompletionItemRules(symbols, context))); }
public static Func <CancellationToken, Task <ImmutableArray <SymbolDisplayPart> > > CreateDescriptionFactory( Workspace workspace, SemanticModel semanticModel, int position, IList <ISymbol> symbols, SupportedPlatformData supportedPlatforms) { return(c => CreateDescriptionAsync(workspace, semanticModel, position, symbols, supportedPlatforms: supportedPlatforms, cancellationToken: c)); }
protected virtual CompletionItem CreateItem(ValueTuple <string, string> displayAndInsertionText, int position, List <ISymbol> symbols, AbstractSyntaxContext context, TextSpan textChangeSpan, bool preselect, SupportedPlatformData supportedPlatformData) { return(new SymbolCompletionItem( this, displayAndInsertionText.Item1, displayAndInsertionText.Item2, GetFilterText(symbols[0], displayAndInsertionText.Item1, context), textChangeSpan, position, symbols, context, supportedPlatforms: supportedPlatformData, preselect: preselect)); }
protected override async Task <QuickInfoContent> BuildContentAsync( Document document, SyntaxToken token, CancellationToken cancellationToken) { var linkedDocumentIds = document.GetLinkedDocumentIds(); var modelAndSymbols = await this.BindTokenAsync(document, token, cancellationToken).ConfigureAwait(false); if (modelAndSymbols.Item2.Length == 0 && !linkedDocumentIds.Any()) { return(null); } if (!linkedDocumentIds.Any()) { return(await CreateContentAsync(document.Project.Solution.Workspace, token, modelAndSymbols.Item1, modelAndSymbols.Item2, supportedPlatforms : null, cancellationToken : cancellationToken).ConfigureAwait(false)); } // Linked files/shared projects: imagine the following when GOO is false // #if GOO // int x = 3; // #endif // var y = x$$; // // 'x' will bind as an error type, so we'll show incorrect information. // Instead, we need to find the head in which we get the best binding, // which in this case is the one with no errors. var candidateProjects = new List <ProjectId>() { document.Project.Id }; var invalidProjects = new List <ProjectId>(); var candidateResults = new List <Tuple <DocumentId, SemanticModel, ImmutableArray <ISymbol> > >(); candidateResults.Add(Tuple.Create(document.Id, modelAndSymbols.Item1, modelAndSymbols.Item2)); foreach (var link in linkedDocumentIds) { var linkedDocument = document.Project.Solution.GetDocument(link); var linkedToken = await FindTokenInLinkedDocument(token, document, linkedDocument, cancellationToken).ConfigureAwait(false); if (linkedToken != default) { // Not in an inactive region, so this file is a candidate. candidateProjects.Add(link.ProjectId); var linkedModelAndSymbols = await this.BindTokenAsync(linkedDocument, linkedToken, cancellationToken).ConfigureAwait(false); candidateResults.Add(Tuple.Create(link, linkedModelAndSymbols.Item1, linkedModelAndSymbols.Item2)); } } // Take the first result with no errors. var bestBinding = candidateResults.FirstOrDefault( c => c.Item3.Length > 0 && !ErrorVisitor.ContainsError(c.Item3.FirstOrDefault())); // Every file binds with errors. Take the first candidate, which is from the current file. if (bestBinding == null) { bestBinding = candidateResults.First(); } if (bestBinding.Item3 == null || !bestBinding.Item3.Any()) { return(null); } // We calculate the set of supported projects candidateResults.Remove(bestBinding); foreach (var candidate in candidateResults) { // Does the candidate have anything remotely equivalent? if (!candidate.Item3.Intersect(bestBinding.Item3, LinkedFilesSymbolEquivalenceComparer.Instance).Any()) { invalidProjects.Add(candidate.Item1.ProjectId); } } var supportedPlatforms = new SupportedPlatformData(invalidProjects, candidateProjects, document.Project.Solution.Workspace); return(await CreateContentAsync(document.Project.Solution.Workspace, token, bestBinding.Item2, bestBinding.Item3, supportedPlatforms, cancellationToken).ConfigureAwait(false)); }
protected override CompletionItem CreateItem(string displayText, string insertionText, int position, List <ISymbol> symbols, AbstractSyntaxContext context, TextSpan span, bool preselect, SupportedPlatformData supportedPlatformData) { return(SymbolCompletionItem.Create( displayText: displayText, insertionText: insertionText, filterText: GetFilterText(symbols[0], displayText, context), span: span, contextPosition: context.Position, descriptionPosition: position, symbols: symbols, supportedPlatforms: supportedPlatformData, matchPriority: MatchPriority.Preselect, // Always preselect tags: s_Tags, rules: GetCompletionItemRules(symbols, context))); }
public static async Task <CompletionDescription> CreateDescriptionAsync( Workspace workspace, SemanticModel semanticModel, int position, IReadOnlyList <ISymbol> symbols, SupportedPlatformData supportedPlatforms, CancellationToken cancellationToken) { var symbolDisplayService = workspace.Services.GetLanguageServices(semanticModel.Language).GetService <ISymbolDisplayService>(); var formatter = workspace.Services.GetLanguageServices(semanticModel.Language).GetService <IDocumentationCommentFormattingService>(); // TODO(cyrusn): Figure out a way to cancel this. var symbol = symbols[0]; var sections = await symbolDisplayService.ToDescriptionGroupsAsync(workspace, semanticModel, position, ImmutableArray.Create(symbol), cancellationToken).ConfigureAwait(false); if (!sections.ContainsKey(SymbolDescriptionGroups.MainDescription)) { return(CompletionDescription.Empty); } var textContentBuilder = new List <SymbolDisplayPart>(); textContentBuilder.AddRange(sections[SymbolDescriptionGroups.MainDescription]); switch (symbol.Kind) { case SymbolKind.Method: case SymbolKind.NamedType: if (symbols.Count > 1) { var overloadCount = symbols.Count - 1; var isGeneric = symbol.GetArity() > 0; textContentBuilder.AddSpace(); textContentBuilder.AddPunctuation("("); textContentBuilder.AddPunctuation("+"); textContentBuilder.AddText(NonBreakingSpaceString + overloadCount.ToString()); AddOverloadPart(textContentBuilder, overloadCount, isGeneric); textContentBuilder.AddPunctuation(")"); } break; } AddDocumentationPart(textContentBuilder, symbol, semanticModel, position, formatter, cancellationToken); if (sections.ContainsKey(SymbolDescriptionGroups.AwaitableUsageText)) { textContentBuilder.AddRange(sections[SymbolDescriptionGroups.AwaitableUsageText]); } if (sections.ContainsKey(SymbolDescriptionGroups.AnonymousTypes)) { var parts = sections[SymbolDescriptionGroups.AnonymousTypes]; if (!parts.IsDefaultOrEmpty) { textContentBuilder.AddLineBreak(); textContentBuilder.AddLineBreak(); textContentBuilder.AddRange(parts); } } if (supportedPlatforms != null) { textContentBuilder.AddLineBreak(); textContentBuilder.AddRange(supportedPlatforms.ToDisplayParts()); } return(CompletionDescription.Create(textContentBuilder.Select(p => new TaggedText(SymbolDisplayPartKindTags.GetTag(p.Kind), p.ToString())).ToImmutableArray())); }
private static Document FindAppropriateDocumentForDescriptionContext(Document document, SupportedPlatformData supportedPlatforms) { var contextDocument = document; if (supportedPlatforms != null && supportedPlatforms.InvalidProjects.Contains(document.Id.ProjectId)) { var contextId = document.GetLinkedDocumentIds().FirstOrDefault(id => !supportedPlatforms.InvalidProjects.Contains(id.ProjectId)); if (contextId != null) { contextDocument = document.Project.Solution.GetDocument(contextId); } } return(contextDocument); }