protected override async Task OnDefinitionFoundWorkerAsync(DefinitionItem definition)
            {
                var definitionBucket = GetOrCreateDefinitionBucket(definition);

                var entries = ArrayBuilder <Entry> .GetInstance();

                if (definition.SourceSpans.Length == 1)
                {
                    // If we only have a single location, then use the DisplayParts of the
                    // definition as what to show.  That way we show enough information for things
                    // methods.  i.e. we'll show "void TypeName.MethodName(args...)" allowing
                    // the user to see the type the method was created in.
                    var entry = await TryCreateEntryAsync(definitionBucket, definition).ConfigureAwait(false);

                    entries.AddIfNotNull(entry);
                }
                else if (definition.SourceSpans.Length == 0)
                {
                    // No source spans means metadata references.
                    // Display it for Go to Base and try to navigate to metadata.
                    entries.Add(new MetadataDefinitionItemEntry(this, definitionBucket));
                }
                else
                {
                    // If we have multiple spans (i.e. for partial types), then create a
                    // DocumentSpanEntry for each.  That way we can easily see the source
                    // code where each location is to help the user decide which they want
                    // to navigate to.
                    foreach (var sourceSpan in definition.SourceSpans)
                    {
                        var entry = await TryCreateDocumentSpanEntryAsync(
                            definitionBucket,
                            sourceSpan,
                            HighlightSpanKind.Definition,
                            symbolUsageInfo : SymbolUsageInfo.None,
                            additionalProperties : definition.DisplayableProperties)
                                    .ConfigureAwait(false);

                        entries.AddIfNotNull(entry);
                    }
                }

                if (entries.Count > 0)
                {
                    lock (Gate)
                    {
                        EntriesWhenGroupingByDefinition    = EntriesWhenGroupingByDefinition.AddRange(entries);
                        EntriesWhenNotGroupingByDefinition = EntriesWhenNotGroupingByDefinition.AddRange(entries);
                    }

                    NotifyChange();
                }

                entries.Free();
            }
            private async Task AddDeclarationEntriesAsync(DefinitionItem definition)
            {
                CancellationToken.ThrowIfCancellationRequested();

                // Don't do anything if we already have declaration entries for this definition
                // (i.e. another thread beat us to this).
                if (HasDeclarationEntries(definition))
                {
                    return;
                }

                var definitionBucket = GetOrCreateDefinitionBucket(definition);

                // We could do this inside the lock.  but that would mean async activity in a
                // lock, and I'd like to avoid that.  That does mean that we might do extra
                // work if multiple threads end up down this path.  But only one of them will
                // win when we access the lock below.
                var declarations = ArrayBuilder <Entry> .GetInstance();

                foreach (var declarationLocation in definition.SourceSpans)
                {
                    var definitionEntry = await CreateDocumentSpanEntryAsync(
                        definitionBucket, declarationLocation, HighlightSpanKind.Definition).ConfigureAwait(false);

                    if (definitionEntry != null)
                    {
                        declarations.Add(definitionEntry);
                    }
                }

                var changed = false;

                lock (Gate)
                {
                    // Do one final check to ensure that no other thread beat us here.
                    if (!HasDeclarationEntries(definition))
                    {
                        // We only include declaration entries in the entries we show when
                        // not grouping by definition.
                        EntriesWhenNotGroupingByDefinition = EntriesWhenNotGroupingByDefinition.AddRange(declarations);
                        CurrentVersionNumber++;
                        changed = true;
                    }
                }

                if (changed)
                {
                    // Let all our subscriptions know that we've updated.
                    NotifyChange();
                }

                declarations.Free();
            }
            private async Task AddDeclarationEntriesAsync(DefinitionItem definition, bool expandedByDefault, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                // Don't do anything if we already have declaration entries for this definition
                // (i.e. another thread beat us to this).
                if (HasDeclarationEntries(definition))
                {
                    return;
                }

                var definitionBucket = GetOrCreateDefinitionBucket(definition, expandedByDefault);

                // We could do this inside the lock.  but that would mean async activity in a
                // lock, and I'd like to avoid that.  That does mean that we might do extra
                // work if multiple threads end up down this path.  But only one of them will
                // win when we access the lock below.

                using var _1 = ArrayBuilder <Entry> .GetInstance(out var declarations);

                using var _2 = PooledHashSet <(string?filePath, TextSpan span)> .GetInstance(out var seenLocations);

                foreach (var declarationLocation in definition.SourceSpans)
                {
                    var definitionEntry = await TryCreateDocumentSpanEntryAsync(
                        definitionBucket, declarationLocation, HighlightSpanKind.Definition, SymbolUsageInfo.None,
                        additionalProperties : definition.DisplayableProperties, cancellationToken).ConfigureAwait(false);

                    declarations.AddIfNotNull(definitionEntry);
                }

                var changed = false;

                lock (Gate)
                {
                    // Do one final check to ensure that no other thread beat us here.
                    if (!HasDeclarationEntries(definition))
                    {
                        // We only include declaration entries in the entries we show when
                        // not grouping by definition.
                        EntriesWhenNotGroupingByDefinition = EntriesWhenNotGroupingByDefinition.AddRange(declarations);
                        CurrentVersionNumber++;
                        changed = true;
                    }
                }

                if (changed)
                {
                    // Let all our subscriptions know that we've updated.
                    NotifyChange();
                }
            }
            protected override async Task OnDefinitionFoundWorkerAsync(DefinitionItem definition)
            {
                var definitionBucket = GetOrCreateDefinitionBucket(definition);

                var entries = ArrayBuilder <Entry> .GetInstance();

                if (definition.SourceSpans.Length == 1)
                {
                    // If we only have a single location, then use the DisplayParts of the
                    // definition as what to show.  That way we show enough information for things
                    // methods.  i.e. we'll show "void TypeName.MethodName(args...)" allowing
                    // the user to see the type the method was created in.
                    var entry = await CreateEntryAsync(definitionBucket, definition).ConfigureAwait(false);

                    entries.Add(entry);
                }
                else
                {
                    // If we have multiple spans (i.e. for partial types), then create a
                    // DocumentSpanEntry for each.  That way we can easily see the source
                    // code where each location is to help the user decide which they want
                    // to navigate to.
                    foreach (var sourceSpan in definition.SourceSpans)
                    {
                        var entry = await CreateDocumentSpanEntryAsync(
                            definitionBucket, sourceSpan, isDefinitionLocation : true).ConfigureAwait(false);

                        entries.Add(entry);
                    }
                }

                if (entries.Count > 0)
                {
                    lock (Gate)
                    {
                        EntriesWhenGroupingByDefinition    = EntriesWhenGroupingByDefinition.AddRange(entries);
                        EntriesWhenNotGroupingByDefinition = EntriesWhenNotGroupingByDefinition.AddRange(entries);
                    }

                    NotifyChange();
                }

                entries.Free();
            }
Exemple #5
0
            private async Task AddDeclarationEntriesAsync(
                DefinitionItem definition,
                bool expandedByDefault
                )
            {
                CancellationToken.ThrowIfCancellationRequested();

                // Don't do anything if we already have declaration entries for this definition
                // (i.e. another thread beat us to this).
                if (HasDeclarationEntries(definition))
                {
                    return;
                }

                var definitionBucket = GetOrCreateDefinitionBucket(definition, expandedByDefault);

                // We could do this inside the lock.  but that would mean async activity in a
                // lock, and I'd like to avoid that.  That does mean that we might do extra
                // work if multiple threads end up down this path.  But only one of them will
                // win when we access the lock below.

                using var _1 = ArrayBuilder <Entry> .GetInstance(out var declarations);

                using var _2 = PooledHashSet <(string?filePath, TextSpan span)> .GetInstance(
                          out var seenLocations
                          );

                foreach (var declarationLocation in definition.SourceSpans)
                {
                    // Because of things like linked files, we may have a source symbol showing up in multiple
                    // different locations that are effectively at the exact same navigation location for the user.
                    // i.e. they're the same file/span.  Showing multiple entries for these is just noisy and
                    // gets worse and worse with shared projects and whatnot.  So, we collapse things down to
                    // only show a single entry for each unique file/span pair.  Note that we check filepath,
                    // not 'Document' as linked files will have unique Document instances in each project context
                    // they are linked into.
                    if (
                        !seenLocations.Add(
                            (declarationLocation.Document.FilePath, declarationLocation.SourceSpan)
                            )
                        )
                    {
                        continue;
                    }

                    var definitionEntry = await TryCreateDocumentSpanEntryAsync(
                        definitionBucket,
                        declarationLocation,
                        HighlightSpanKind.Definition,
                        SymbolUsageInfo.None,
                        additionalProperties : definition.DisplayableProperties
                        )
                                          .ConfigureAwait(false);

                    declarations.AddIfNotNull(definitionEntry);
                }

                var changed = false;

                lock (Gate)
                {
                    // Do one final check to ensure that no other thread beat us here.
                    if (!HasDeclarationEntries(definition))
                    {
                        // We only include declaration entries in the entries we show when
                        // not grouping by definition.
                        EntriesWhenNotGroupingByDefinition =
                            EntriesWhenNotGroupingByDefinition.AddRange(declarations);
                        CurrentVersionNumber++;
                        changed = true;
                    }
                }

                if (changed)
                {
                    // Let all our subscriptions know that we've updated.
                    NotifyChange();
                }
            }