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));
            }
예제 #5
0
        /// <summary>
        /// Returns <code>null</code> if our work was preempted and we want to return the
        /// previous model we've computed.
        /// </summary>
        private async Task <(ISignatureHelpProvider provider, SignatureHelpItems items)> ComputeItemsAsync(
            ISignatureHelpProvider[] providers,
            int caretPosition,
            SIGHLP.SignatureHelpTriggerInfo triggerInfo,
            Document document,
            CancellationToken cancellationToken)
        {
            ISignatureHelpProvider bestProvider = null;
            SignatureHelpItems     bestItems    = null;

            // TODO(cyrusn): We're calling into extensions, we need to make ourselves resilient
            // to the extension crashing.
            foreach (var provider in providers)
            {
                // If this is a retrigger command, and another retrigger command has already
                // been issued then we can bail out immediately.
                //if (IsNonTypeCharRetrigger(triggerInfo) &&
                //	localRetriggerId != _retriggerId) {
                //	return null;
                //}

                cancellationToken.ThrowIfCancellationRequested();

                var currentItems = await provider.GetItemsAsync(document, caretPosition, triggerInfo, cancellationToken).ConfigureAwait(false);

                if (currentItems != null && currentItems.ApplicableSpan.IntersectsWith(caretPosition))
                {
                    // If another provider provides sig help items, then only take them if they
                    // start after the last batch of items.  i.e. we want the set of items that
                    // conceptually are closer to where the caret position is.  This way if you have:
                    //
                    //  Goo(new Bar($$
                    //
                    // Then invoking sig help will only show the items for "new Bar(" and not also
                    // the items for "Goo(..."
                    if (IsBetter(bestItems, currentItems.ApplicableSpan))
                    {
                        bestItems    = new SignatureHelpItems(currentItems);
                        bestProvider = provider;
                    }
                }
            }

            return(bestProvider, bestItems);
        }
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            AttributeSyntax attribute;
            if (!TryGetAttributeExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out attribute))
            {
                return null;
            }

            var semanticModel = await document.GetSemanticModelForNodeAsync(attribute, cancellationToken).ConfigureAwait(false);
            var attributeType = semanticModel.GetTypeInfo(attribute, cancellationToken).Type as INamedTypeSymbol;
            if (attributeType == null)
            {
                return null;
            }

            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            var accessibleConstructors = attributeType.InstanceConstructors
                                                      .WhereAsArray(c => c.IsAccessibleWithin(within))
                                                      .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)
                                                      .Sort(symbolDisplayService, semanticModel, attribute.SpanStart);

            if (!accessibleConstructors.Any())
            {
                return null;
            }

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormatter = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();
            var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(attribute.ArgumentList);

            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
            return CreateSignatureHelpItems(accessibleConstructors.Select(c =>
                Convert(c, within, attribute, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormatter, cancellationToken)).ToList(),
                textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
        }
        private async Task <Tuple <ISignatureHelpProvider, SignatureHelpItems> > ComputeItemsAsync(
            IList <ISignatureHelpProvider> providers,
            int caretPosition,
            SIGHLP.SignatureHelpTriggerInfo triggerInfo,
            Document document,
            CancellationToken cancellationToken)
        {
            ISignatureHelpProvider bestProvider = null;
            SignatureHelpItems     bestItems    = null;

            // TODO(cyrusn): We're calling into extensions, we need to make ourselves resilient
            // to the extension crashing.
            foreach (var provider in providers)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var currentItems = await provider.GetItemsAsync(document, caretPosition, triggerInfo, cancellationToken).ConfigureAwait(false);

                if (currentItems != null && currentItems.ApplicableSpan.IntersectsWith(caretPosition))
                {
                    // If another provider provides sig help items, then only take them if they
                    // start after the last batch of items.  i.e. we want the set of items that
                    // conceptually are closer to where the caret position is.  This way if you have:
                    //
                    //  Foo(new Bar($$
                    //
                    // Then invoking sig help will only show the items for "new Bar(" and not also
                    // the items for "Foo(..."
                    if (IsBetter(bestItems, currentItems.ApplicableSpan))
                    {
                        bestItems    = new SignatureHelpItems(currentItems);
                        bestProvider = provider;
                    }
                }
            }

            return(Tuple.Create(bestProvider, bestItems));
        }
예제 #8
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));
        }
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxToken genericIdentifier, lessThanToken;
            if (!TryGetGenericIdentifier(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken,
                    out genericIdentifier, out lessThanToken))
            {
                return null;
            }

            var simpleName = genericIdentifier.Parent as SimpleNameSyntax;
            if (simpleName == null)
            {
                return null;
            }

            var beforeDotExpression = simpleName.IsRightSideOfDot() ? simpleName.GetLeftSideOfDot() : null;

            var semanticModel = await document.GetSemanticModelForNodeAsync(simpleName, cancellationToken).ConfigureAwait(false);

            var leftSymbol = beforeDotExpression == null
                ? null
                : semanticModel.GetSymbolInfo(beforeDotExpression, cancellationToken).GetAnySymbol() as INamespaceOrTypeSymbol;
            var leftType = beforeDotExpression == null
                ? null
                : semanticModel.GetTypeInfo(beforeDotExpression, cancellationToken).Type as INamespaceOrTypeSymbol;

            var leftContainer = leftSymbol ?? leftType;

            var isBaseAccess = beforeDotExpression is BaseExpressionSyntax;
            var namespacesOrTypesOnly = SyntaxFacts.IsInNamespaceOrTypeContext(simpleName);
            var includeExtensions = leftSymbol == null && leftType != null;
            var name = genericIdentifier.ValueText;
            var symbols = isBaseAccess
                ? semanticModel.LookupBaseMembers(position, name)
                : namespacesOrTypesOnly
                    ? semanticModel.LookupNamespacesAndTypes(position, leftContainer, name)
                    : semanticModel.LookupSymbols(position, leftContainer, name, includeExtensions);

            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            var accessibleSymbols =
                symbols.Where(s => s.GetArity() > 0)
                       .Where(s => s is INamedTypeSymbol || s is IMethodSymbol)
                       .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)
                       .Sort(symbolDisplayService, semanticModel, genericIdentifier.SpanStart);

            if (!accessibleSymbols.Any())
            {
                return null;
            }

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();
            var textSpan = GetTextSpan(genericIdentifier, lessThanToken);
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            return CreateSignatureHelpItems(accessibleSymbols.Select(s =>
                Convert(s, lessThanToken, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, cancellationToken)).ToList(),
                textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
        }
예제 #10
0
        protected async Task <List <Tuple <Document, IEnumerable <SignatureHelpItem> > > > GetItemsForRelatedDocuments(Document document, IEnumerable <DocumentId> relatedDocuments, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var supportedPlatforms = new List <Tuple <Document, IEnumerable <SignatureHelpItem> > >();

            foreach (var relatedDocumentId in relatedDocuments)
            {
                var relatedDocument = document.Project.Solution.GetDocument(relatedDocumentId);
                var semanticModel   = await relatedDocument.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false);

                var result = await GetItemsWorkerAsync(relatedDocument, position, triggerInfo, cancellationToken).ConfigureAwait(false);

                supportedPlatforms.Add(Tuple.Create(relatedDocument, result != null ? result.Items : SpecializedCollections.EmptyEnumerable <SignatureHelpItem>()));
            }

            return(supportedPlatforms);
        }
        protected async Task<List<Tuple<Document, IEnumerable<SignatureHelpItem>>>> GetItemsForRelatedDocuments(Document document, IEnumerable<DocumentId> relatedDocuments, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var supportedPlatforms = new List<Tuple<Document, IEnumerable<SignatureHelpItem>>>();
            foreach (var relatedDocumentId in relatedDocuments)
            {
                var relatedDocument = document.Project.Solution.GetDocument(relatedDocumentId);
                var semanticModel = await relatedDocument.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false);
                var result = await GetItemsWorkerAsync(relatedDocument, position, triggerInfo, cancellationToken).ConfigureAwait(false);

                supportedPlatforms.Add(Tuple.Create(relatedDocument, result != null ? result.Items : SpecializedCollections.EmptyEnumerable<SignatureHelpItem>()));
            }

            return supportedPlatforms;
        }
        public async Task<SignatureHelpItems> GetItemsAsync(
            Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var itemsForCurrentDocument = await GetItemsWorkerAsync(document, position, triggerInfo, cancellationToken).ConfigureAwait(false);
            if (itemsForCurrentDocument == null)
            {
                return itemsForCurrentDocument;
            }

            var relatedDocuments = document.GetLinkedDocumentIds();
            if (!relatedDocuments.Any())
            {
                return itemsForCurrentDocument;
            }

            var relatedDocumentsAndItems = await GetItemsForRelatedDocuments(document, relatedDocuments, position, triggerInfo, cancellationToken).ConfigureAwait(false);
            var candidateLinkedProjectsAndSymbolSets = await ExtractSymbolsFromRelatedItems(position, relatedDocumentsAndItems, cancellationToken).ConfigureAwait(false);

            var totalProjects = candidateLinkedProjectsAndSymbolSets.Select(c => c.Item1).Concat(document.Project.Id);

            var semanticModel = await document.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false);
            var compilation = semanticModel.Compilation;
            var finalItems = new List<SignatureHelpItem>();
            foreach (var item in itemsForCurrentDocument.Items)
            {
                var symbolKey = ((SymbolKeySignatureHelpItem)item).SymbolKey;
                if (symbolKey == null)
                {
                    finalItems.Add(item);
                    continue;
                }

                var expectedSymbol = symbolKey.Value.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken: cancellationToken).Symbol;
                if (expectedSymbol == null)
                {
                    finalItems.Add(item);
                    continue;
                }

                var invalidProjectsForCurrentSymbol = candidateLinkedProjectsAndSymbolSets.Where(c => !c.Item2.Contains(expectedSymbol, LinkedFilesSymbolEquivalenceComparer.Instance))
                                                                        .Select(c => c.Item1)
                                                                        .ToList();

                var platformData = new SupportedPlatformData(invalidProjectsForCurrentSymbol, totalProjects, document.Project.Solution.Workspace);
                finalItems.Add(UpdateItem(item, platformData, expectedSymbol));
            }

            return new SignatureHelpItems(
                finalItems, itemsForCurrentDocument.ApplicableSpan,
                itemsForCurrentDocument.ArgumentIndex,
                itemsForCurrentDocument.ArgumentCount,
                itemsForCurrentDocument.ArgumentName,
                itemsForCurrentDocument.SelectedItemIndex);
        }
            private async Task<Model> ComputeModelInBackgroundAsync(
                Model currentModel,
                IList<ISignatureHelpProvider> matchedProviders,
                IList<ISignatureHelpProvider> unmatchedProviders,
                SnapshotPoint caretPosition,
                DisconnectedBufferGraph disconnectedBufferGraph,
                SignatureHelpTriggerInfo triggerInfo,
                CancellationToken cancellationToken)
            {
                try
                {
                    using (Logger.LogBlock(FunctionId.SignatureHelp_ModelComputation_ComputeModelInBackground, cancellationToken))
                    {
                        AssertIsBackground();
                        cancellationToken.ThrowIfCancellationRequested();

                        var document = await Controller.DocumentProvider.GetDocumentAsync(caretPosition.Snapshot, cancellationToken).ConfigureAwait(false);
                        if (document == null)
                        {
                            return currentModel;
                        }

                        if (triggerInfo.TriggerReason == SignatureHelpTriggerReason.RetriggerCommand)
                        {
                            if (currentModel == null ||
                                (triggerInfo.TriggerCharacter.HasValue && !currentModel.Provider.IsRetriggerCharacter(triggerInfo.TriggerCharacter.Value)))
                            {
                                return currentModel;
                            }
                        }

                        // first try to query the providers that can trigger on the specified character
                        var result = await ComputeItemsAsync(matchedProviders, caretPosition, triggerInfo, document, cancellationToken).ConfigureAwait(false);
                        var provider = result.Item1;
                        var items = result.Item2;

                        if (provider == null)
                        {
                            // no match, so now query the other providers
                            result = await ComputeItemsAsync(unmatchedProviders, caretPosition, triggerInfo, document, cancellationToken).ConfigureAwait(false);
                            provider = result.Item1;
                            items = result.Item2;

                            if (provider == null)
                            {
                                // the other providers didn't produce items either, so we don't produce a model
                                return null;
                            }
                        }

                        if (currentModel != null &&
                            currentModel.Provider == provider &&
                            currentModel.GetCurrentSpanInSubjectBuffer(disconnectedBufferGraph.SubjectBufferSnapshot).Span.Start == items.ApplicableSpan.Start &&
                            currentModel.ArgumentIndex == items.ArgumentIndex &&
                            currentModel.ArgumentCount == items.ArgumentCount &&
                            currentModel.ArgumentName == items.ArgumentName)
                        {
                            // The new model is the same as the current model.  Return the currentModel
                            // so we keep the active selection.
                            return currentModel;
                        }

                        var selectedItem = GetSelectedItem(currentModel, items, provider);
                        var model = new Model(disconnectedBufferGraph, items.ApplicableSpan, provider,
                            items.Items, selectedItem, items.ArgumentIndex, items.ArgumentCount, items.ArgumentName,
                            selectedParameter: 0);

                        var syntaxFactsService = document.GetLanguageService<ISyntaxFactsService>();
                        var isCaseSensitive = syntaxFactsService == null || syntaxFactsService.IsCaseSensitive;
                        var selection = DefaultSignatureHelpSelector.GetSelection(model.Items,
                            model.SelectedItem, model.ArgumentIndex, model.ArgumentCount, model.ArgumentName, isCaseSensitive);

                        return model.WithSelectedItem(selection.SelectedItem)
                                    .WithSelectedParameter(selection.SelectedParameter);
                    }
                }
                catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }
 public void ComputeModel(
     IList<ISignatureHelpProvider> providers,
     SignatureHelpTriggerInfo triggerInfo)
 {
     ComputeModel(providers, SpecializedCollections.EmptyList<ISignatureHelpProvider>(), triggerInfo);
 }
            private async Task<Tuple<ISignatureHelpProvider, SignatureHelpItems>> ComputeItemsAsync(
                IList<ISignatureHelpProvider> providers,
                SnapshotPoint caretPosition,
                SignatureHelpTriggerInfo triggerInfo,
                Document document,
                CancellationToken cancellationToken)
            {
                try
                {
                    ISignatureHelpProvider bestProvider = null;
                    SignatureHelpItems bestItems = null;

                    // TODO(cyrusn): We're calling into extensions, we need to make ourselves resilient
                    // to the extension crashing.
                    foreach (var provider in providers)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        var currentItems = await provider.GetItemsAsync(document, caretPosition, triggerInfo, cancellationToken).ConfigureAwait(false);
                        if (currentItems != null && currentItems.ApplicableSpan.IntersectsWith(caretPosition.Position))
                        {
                            // If another provider provides sig help items, then only take them if they
                            // start after the last batch of items.  i.e. we want the set of items that
                            // conceptually are closer to where the caret position is.  This way if you have:
                            //
                            //  Foo(new Bar($$
                            //
                            // Then invoking sig help will only show the items for "new Bar(" and not also
                            // the items for "Foo(..."
                            if (IsBetter(bestItems, currentItems.ApplicableSpan))
                            {
                                bestItems = currentItems;
                                bestProvider = provider;
                            }
                        }
                    }

                    return Tuple.Create(bestProvider, bestItems);
                }
                catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
            var typeInferrer = document.Project.LanguageServices.GetService<ITypeInferenceService>();
            var inferredTypes = FindNearestTupleConstructionWithInferrableType(root, semanticModel, position, triggerInfo,
                typeInferrer, syntaxFacts, cancellationToken, out var targetExpression);

            if (inferredTypes == null || !inferredTypes.Any())
            {
                return null;
            }

            return CreateItems(position, root, syntaxFacts, targetExpression, semanticModel, inferredTypes, cancellationToken);
        }
        IEnumerable<INamedTypeSymbol> FindNearestTupleConstructionWithInferrableType(SyntaxNode root, SemanticModel semanticModel, int position, SignatureHelpTriggerInfo triggerInfo,
            ITypeInferenceService typeInferrer, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken, out ExpressionSyntax targetExpression)
        {
            // Walk upward through TupleExpressionSyntax/ParenthsizedExpressionSyntax looking for a 
            // place where we can infer a tuple type. 
            ParenthesizedExpressionSyntax parenthesizedExpression = null;
            while (TryGetTupleExpression(triggerInfo.TriggerReason, root, position, syntaxFacts, cancellationToken, out var tupleExpression) ||
                   TryGetParenthesizedExpression(triggerInfo.TriggerReason, root, position, syntaxFacts, cancellationToken, out parenthesizedExpression))
            {
                targetExpression = (ExpressionSyntax)tupleExpression ?? parenthesizedExpression;
                var inferredTypes = typeInferrer.InferTypes(semanticModel, targetExpression.SpanStart, cancellationToken);

                var tupleTypes = inferredTypes.Where(t => t.IsTupleType).OfType<INamedTypeSymbol>().ToList();
                if (tupleTypes.Any())
                {
                    return tupleTypes;
                }

                position = targetExpression.GetFirstToken().SpanStart;
            }

            targetExpression = null;
            return null;
        }
 protected abstract Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken);
예제 #19
0
 protected abstract Task <SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken);
        protected override async Task<SignatureHelpItems> GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            ExpressionSyntax expression;
            SyntaxToken openBrace;
            if (!TryGetElementAccessExpression(root, position, document.GetLanguageService<ISyntaxFactsService>(), triggerInfo.TriggerReason, cancellationToken, out expression, out openBrace))
            {
                return null;
            }

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
            var expressionSymbol = semanticModel.GetSymbolInfo(expression, cancellationToken).GetAnySymbol();
            if (expressionSymbol is INamedTypeSymbol)
            {
                // foo?[$$]
                var namedType = (INamedTypeSymbol)expressionSymbol;
                if (namedType.ConstructedFrom.SpecialType == SpecialType.System_Nullable_T &&
                    expression.IsKind(SyntaxKind.NullableType) &&
                    expression.IsChildNode<ArrayTypeSyntax>(a => a.ElementType))
                {
                    // Speculatively bind the type part of the nullable as an expression
                    var nullableTypeSyntax = (NullableTypeSyntax)expression;
                    var speculativeBinding = semanticModel.GetSpeculativeSymbolInfo(position, nullableTypeSyntax.ElementType, SpeculativeBindingOption.BindAsExpression);
                    expressionSymbol = speculativeBinding.GetAnySymbol();
                    expression = nullableTypeSyntax.ElementType;
                }
            }

            if (expressionSymbol != null && expressionSymbol is INamedTypeSymbol)
            {
                return null;
            }

            IEnumerable<IPropertySymbol> indexers;
            ITypeSymbol expressionType;

            if (!TryGetIndexers(position, semanticModel, expression, cancellationToken, out indexers, out expressionType) &&
                !TryGetComIndexers(semanticModel, expression, cancellationToken, out indexers, out expressionType))
            {
                return null;
            }

            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken);
            if (within == null)
            {
                return null;
            }

            var accessibleIndexers = indexers.Where(m => m.IsAccessibleWithin(within, throughTypeOpt: expressionType));
            if (!accessibleIndexers.Any())
            {
                return null;
            }

            var symbolDisplayService = document.Project.LanguageServices.GetService<ISymbolDisplayService>();
            accessibleIndexers = accessibleIndexers.FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)
                                                   .Sort(symbolDisplayService, semanticModel, expression.SpanStart);

            var anonymousTypeDisplayService = document.Project.LanguageServices.GetService<IAnonymousTypeDisplayService>();
            var documentationCommentFormattingService = document.Project.LanguageServices.GetService<IDocumentationCommentFormattingService>();
            var textSpan = GetTextSpan(expression, openBrace);
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();

            return CreateSignatureHelpItems(accessibleIndexers.Select(p =>
                Convert(p, openBrace, semanticModel, symbolDisplayService, anonymousTypeDisplayService, documentationCommentFormattingService, cancellationToken)),
                textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken));
        }