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
                       ));
        }
Example #2
0
 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
                ));
 }
Example #3
0
        /// <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));
        }
Example #4
0
        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));
        }
Example #5
0
        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);
        }
Example #7
0
 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));
 }
Example #9
0
        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);
     }
 }
Example #11
0
 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));
 }
Example #12
0
        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));
        }
Example #13
0
 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)));
 }
Example #14
0
 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));
 }
Example #16
0
        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));
        }
Example #17
0
 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)));
 }
Example #18
0
        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);
        }