private void GetCompletionSources()

in src/Editor/Language/Impl/Language/AsyncCompletion/AsyncCompletionBroker.cs [334:437]


        private void GetCompletionSources(
            SnapshotPoint triggerLocation,
            Func<IContentType, ITextViewRoleSet, IReadOnlyList<Lazy<IAsyncCompletionSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>>> getImports,
            ITextSnapshot rootSnapshot,
            ITextView textView,
            IBufferGraph bufferGraph,
            CompletionTrigger trigger,
            CompletionSessionTelemetry telemetry,
            CancellationToken token,
            out List<(IAsyncCompletionSource Source, SnapshotPoint Point)> sourcesWithLocations,
            out SnapshotSpan applicableToSpan)
        {
            var sourcesWithData = MetadataUtilities<IAsyncCompletionSourceProvider, IOrderableContentTypeAndOptionalTextViewRoleMetadata>
                .GetBuffersAndImports(triggerLocation, rootSnapshot, textView.Roles, getImports);

            var applicableToSpanBuilder = default(SnapshotSpan);
            bool applicableToSpanExists = false;
            bool anySourceParticipates = false;
            bool anySourceExclusive = false;
            var sourcesWithLocationsBuilder = new List<(IAsyncCompletionSource, SnapshotPoint, CompletionParticipation)>();

            foreach (var (buffer, point, import) in sourcesWithData)
            {
                telemetry.UiStopwatch.Restart();

                var sourceProvider = GuardedOperations.InstantiateExtension(this, import);
                var source = GuardedOperations.CallExtensionPoint(
                    errorSource: sourceProvider,
                    call: () => sourceProvider.GetOrCreate(textView),
                    valueOnThrow: null);

                if (source == null)
                {
                    telemetry.UiStopwatch.Stop();
                    telemetry.RecordObtainingSourceSpan(source, telemetry.UiStopwatch.ElapsedMilliseconds);
                    continue;
                }

                // Iterate through all sources and add them to collection
                var startData = GuardedOperations.CallExtensionPoint(
                    errorSource: source,
                    call: () => source.InitializeCompletion(trigger, point, token),
                    valueOnThrow: CompletionStartData.DoesNotParticipateInCompletion);

                telemetry.UiStopwatch.Stop();
                telemetry.RecordObtainingSourceSpan(source, telemetry.UiStopwatch.ElapsedMilliseconds);

                if (!applicableToSpanExists && startData.ApplicableToSpan != default)
                {
                    applicableToSpanExists = true;
                    applicableToSpanBuilder = startData.ApplicableToSpan;
                }
                if (startData.Participation == CompletionParticipation.ProvidesItems)
                {
                    anySourceParticipates = true;
                }
                else if (startData.Participation == CompletionParticipation.ExclusivelyProvidesItems)
                {
                    anySourceParticipates = true;
                    anySourceExclusive = true;
                }
                sourcesWithLocationsBuilder.Add((source, point, startData.Participation));
            }

            // Map the applicable to span to the view's text snapshot and use it for completion,
            if (applicableToSpanExists)
            {
                if (rootSnapshot == textView.TextSnapshot)
                {
                    // Typical case; ApplicableToSpan is always defined on TextView.TextBuffer, so we will map up
                    var mappingSpan = bufferGraph.CreateMappingSpan(applicableToSpanBuilder, SpanTrackingMode.EdgeInclusive);
                    var spans = mappingSpan.GetSpans(textView.TextSnapshot);

                    if (spans.Count == 0)
                        throw new InvalidOperationException("Completion expects the Applicable To Span to be mappable to the view's TextBuffer.");
                    applicableToSpanBuilder = spans[0];
                }
                else
                {
                    // Edge case; in Roslyn's DebuggerTextView, TextView.TextSnapshot is below the root snapshot
                    // ApplicableToSpan is always defined on textView's TextBuffer, so we will to map down
                    var spans = MappingHelper.MapDownToBufferNoTrack(applicableToSpanBuilder, textView.TextBuffer);

                    if (spans.Count == 0)
                        throw new InvalidOperationException("Completion expects the Applicable To Span to be mappable to the view's TextBuffer.");
                    applicableToSpanBuilder = spans[0];
                }
            }

            // Copying temporary values because we can't access out&ref params in lambdas
            if (anySourceExclusive)
            {
                sourcesWithLocations = sourcesWithLocationsBuilder.Where(n => n.Item3 == CompletionParticipation.ExclusivelyProvidesItems).Select(n => (n.Item1, n.Item2)).ToList();
            }
            else if (anySourceParticipates)
            {
                sourcesWithLocations = sourcesWithLocationsBuilder.Where(n => n.Item3 == CompletionParticipation.ProvidesItems).Select(n => (n.Item1, n.Item2)).ToList();
            }
            else
            {
                sourcesWithLocations = new List<(IAsyncCompletionSource Source, SnapshotPoint Point)>();
            }
            applicableToSpan = applicableToSpanBuilder;
        }