public async Task <SignatureHelpItems?> GetItemsAsync(Document document, int position, SignatureHelpTriggerInfo trigger, CancellationToken cancellationToken)
        {
            Microsoft.CodeAnalysis.SignatureHelp.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, position, trigger.Inner, cancellationToken).ConfigureAwait(false);

                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;
                    }
                }
            }

            if (bestItems != null)
            {
                var items = new SignatureHelpItems(bestItems);
                if (items.SelectedItemIndex == null)
                {
                    var selection = DefaultSignatureHelpSelector.GetSelection(items.Items, null, false, items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, isCaseSensitive: true);
                    if (selection.SelectedItem != null)
                    {
                        items.SelectedItemIndex = items.Items.IndexOf(selection.SelectedItem);
                    }
                }

                return(items);
            }

            return(null);
        }
        SignatureHelpResult GetSignatureHelpResult(Tuple <ISignatureHelpProvider, SignatureHelpItems> res, Document document)
        {
            // Code is from the end of ComputeModelInBackgroundAsync()
            var items = res.Item2;

            if (items == null)
            {
                return(null);
            }
            var selectedItem       = GetSelectedItem(items, res.Item1);
            var syntaxFactsService = document?.Project?.LanguageServices?.GetService <Microsoft.CodeAnalysis.LanguageServices.ISyntaxFactsService>();
            var isCaseSensitive    = syntaxFactsService == null || syntaxFactsService.IsCaseSensitive;
            var selection          = DefaultSignatureHelpSelector.GetSelection(items.Items,
                                                                               selectedItem, items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, isCaseSensitive);

            return(new SignatureHelpResult(items, selection.SelectedItem, selection.SelectedParameter));
        }
            private async Task <Model> ComputeModelInBackgroundAsync(
                Model currentModel,
                ImmutableArray <ISignatureHelpProvider> providers,
                SnapshotPoint caretPosition,
                DisconnectedBufferGraph disconnectedBufferGraph,
                SignatureHelpTriggerInfo triggerInfo,
                CancellationToken cancellationToken)
            {
                try
                {
                    using (Logger.LogBlock(FunctionId.SignatureHelp_ModelComputation_ComputeModelInBackground, cancellationToken))
                    {
                        AssertIsBackground();
                        cancellationToken.ThrowIfCancellationRequested();

                        var document = Controller.DocumentProvider.GetDocument(caretPosition.Snapshot, cancellationToken);
                        if (document == null)
                        {
                            return(currentModel);
                        }

                        if (triggerInfo.TriggerReason == SignatureHelpTriggerReason.RetriggerCommand)
                        {
                            if (currentModel == null)
                            {
                                return(null);
                            }

                            if (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(provider, items) = await ComputeItemsAsync(
                            providers, caretPosition, triggerInfo,
                            document, cancellationToken).ConfigureAwait(false);

                        if (provider == null)
                        {
                            // No provider produced items. So we can't produce a model
                            return(null);
                        }

                        if (currentModel != null &&
                            currentModel.Provider == provider &&
                            currentModel.GetCurrentSpanInSubjectBuffer(disconnectedBufferGraph.SubjectBufferSnapshot).Span.Start == items.ApplicableSpan.Start &&
                            currentModel.Items.IndexOf(currentModel.SelectedItem) == items.SelectedItemIndex &&
                            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, out var userSelected);

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

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

                        return(model.WithSelectedItem(selection.SelectedItem, selection.UserSelected)
                               .WithSelectedParameter(selection.SelectedParameter));
                    }
                }
                catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }