Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move over to IDE using TagSpan uniformly #73713

Merged
merged 4 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ public async Task ErrorTagGeneratedForErrorInSourceGeneratedDocument()
Assert.Equal(PredefinedErrorTypeNames.SyntaxError, firstSpan.Tag.ErrorType);
}

private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansAsync(string content)
private static async Task<ImmutableArray<TagSpan<InlineDiagnosticsTag>>> GetTagSpansAsync(string content)
{
using var workspace = EditorTestWorkspace.CreateCSharp(content, composition: SquiggleUtilities.WpfCompositionWithSolutionCrawler);
return await GetTagSpansAsync(workspace);
}

private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansInSourceGeneratedDocumentAsync(string content)
private static async Task<ImmutableArray<TagSpan<InlineDiagnosticsTag>>> GetTagSpansInSourceGeneratedDocumentAsync(string content)
{
using var workspace = EditorTestWorkspace.CreateCSharp(
files: [],
Expand All @@ -50,7 +50,7 @@ private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTag
return await GetTagSpansAsync(workspace);
}

private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansAsync(EditorTestWorkspace workspace)
private static async Task<ImmutableArray<TagSpan<InlineDiagnosticsTag>>> GetTagSpansAsync(EditorTestWorkspace workspace)
{
workspace.GlobalOptions.SetGlobalOption(InlineDiagnosticsOptionsStorage.EnableInlineDiagnostics, LanguageNames.CSharp, true);
return await TestDiagnosticTagProducer<InlineDiagnosticsTaggerProvider, InlineDiagnosticsTag>.GetTagSpansAsync(workspace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class InteractiveBraceHighlightingTests
private static IEnumerable<T> Enumerable<T>(params T[] array)
=> array;

private static async Task<IEnumerable<ITagSpan<BraceHighlightTag>>> ProduceTagsAsync(
private static async Task<IEnumerable<TagSpan<BraceHighlightTag>>> ProduceTagsAsync(
EditorTestWorkspace workspace,
ITextBuffer buffer,
int position)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,10 @@ SingleDiagnosticKindPullTaggerProvider CreateDiagnosticsTaggerProvider(Diagnosti
protected virtual ImmutableArray<DiagnosticDataLocation> GetLocationsToTag(DiagnosticData diagnosticData)
=> diagnosticData.DataLocation is not null ? [diagnosticData.DataLocation] : [];

public ITagger<T>? CreateTagger<T>(ITextBuffer buffer) where T : ITag
ITagger<T>? ITaggerProvider.CreateTagger<T>(ITextBuffer buffer)
{
using var taggers = TemporaryArray<EfficientTagger<TTag>>.Empty;
foreach (var taggerProvider in _diagnosticsTaggerProviders)
{
var innerTagger = taggerProvider.CreateTagger(buffer);
if (innerTagger != null)
taggers.Add(innerTagger);
}
var tagger = CreateTagger<T>(buffer);

var tagger = new SimpleAggregateTagger<TTag>(taggers.ToImmutableAndClear());
if (tagger is not ITagger<T> genericTagger)
{
tagger.Dispose();
Expand All @@ -97,7 +90,20 @@ protected virtual ImmutableArray<DiagnosticDataLocation> GetLocationsToTag(Diagn
return genericTagger;
}

protected ITagSpan<TTag>? CreateTagSpan(Workspace workspace, SnapshotSpan span, DiagnosticData data)
public SimpleAggregateTagger<TTag> CreateTagger<T>(ITextBuffer buffer) where T : ITag
{
using var taggers = TemporaryArray<EfficientTagger<TTag>>.Empty;
foreach (var taggerProvider in _diagnosticsTaggerProviders)
{
var innerTagger = taggerProvider.CreateTagger(buffer);
if (innerTagger != null)
taggers.Add(innerTagger);
}

return new SimpleAggregateTagger<TTag>(taggers.ToImmutableAndClear());
}

protected TagSpan<TTag>? CreateTagSpan(Workspace workspace, SnapshotSpan span, DiagnosticData data)
{
var errorTag = CreateTag(workspace, data);
if (errorTag == null)
Expand Down
13 changes: 7 additions & 6 deletions src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal sealed class InlineHintsTagger : ITagger<IntraTextAdornmentTag>, IDispo
/// <summary>
/// stores the parameter hint tags in a global location
/// </summary>
private readonly List<(IMappingTagSpan<InlineHintDataTag> mappingTagSpan, ITagSpan<IntraTextAdornmentTag>? tagSpan)> _cache = [];
private readonly List<(IMappingTagSpan<InlineHintDataTag> mappingTagSpan, TagSpan<IntraTextAdornmentTag>? tagSpan)> _cache = [];

/// <summary>
/// Stores the snapshot associated with the cached tags in <see cref="_cache" />
Expand Down Expand Up @@ -133,14 +133,15 @@ private void InvalidateCache()
_cache.Clear();
}

public IEnumerable<ITagSpan<IntraTextAdornmentTag>> GetTags(NormalizedSnapshotSpanCollection spans)
IEnumerable<ITagSpan<IntraTextAdornmentTag>> ITagger<IntraTextAdornmentTag>.GetTags(NormalizedSnapshotSpanCollection spans)
=> GetTags(spans);

public IReadOnlyList<TagSpan<IntraTextAdornmentTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
try
{
if (spans.Count == 0)
{
return Array.Empty<ITagSpan<IntraTextAdornmentTag>>();
}
return [];

var snapshot = spans[0].Snapshot;
if (snapshot != _cacheSnapshot)
Expand Down Expand Up @@ -169,7 +170,7 @@ public IEnumerable<ITagSpan<IntraTextAdornmentTag>> GetTags(NormalizedSnapshotSp
var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();
var classify = document != null && _taggerProvider.EditorOptionsService.GlobalOptions.GetOption(InlineHintsViewOptionsStorage.ColorHints, document.Project.Language);

var selectedSpans = new List<ITagSpan<IntraTextAdornmentTag>>();
var selectedSpans = new List<TagSpan<IntraTextAdornmentTag>>();
for (var i = 0; i < _cache.Count; i++)
{
var tagSpans = _cache[i].mappingTagSpan.Span.GetSpans(snapshot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ public Tagger(ITextBuffer buffer, object key, TTag tagInstance)
_tagInstance = tagInstance;
}

public IEnumerable<ITagSpan<TTag>> GetTags(NormalizedSnapshotSpanCollection spans)
IEnumerable<ITagSpan<TTag>> ITagger<TTag>.GetTags(NormalizedSnapshotSpanCollection spans)
=> GetTags(spans);

public IEnumerable<TagSpan<TTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (_buffer.Properties.TryGetProperty(_key, out NormalizedSnapshotSpanCollection matchingSpans))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ public Tagger(ClassificationTypeMap typeMap, ITextBuffer buffer)
/// </summary>
event EventHandler<SnapshotSpanEventArgs> ITagger<IClassificationTag>.TagsChanged { add { } remove { } }

public IEnumerable<ITagSpan<IClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
IEnumerable<ITagSpan<IClassificationTag>> ITagger<IClassificationTag>.GetTags(NormalizedSnapshotSpanCollection spans)
=> GetTags(spans);

public IEnumerable<TagSpan<IClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (!_buffer.Properties.TryGetProperty(PredefinedPreviewTaggerKeys.StaticClassificationSpansKey, out ImmutableArray<ClassifiedSpan> classifiedSpans))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,15 @@ public IEnumerable<ITagSpan<IClassificationTag>> GetTags(NormalizedSnapshotSpanC
return [];
}

private static IEnumerable<ITagSpan<IClassificationTag>> GetIntersectingTags(NormalizedSnapshotSpanCollection spans, TagSpanIntervalTree<IClassificationTag> cachedTags)
private static IReadOnlyList<TagSpan<IClassificationTag>> GetIntersectingTags(NormalizedSnapshotSpanCollection spans, TagSpanIntervalTree<IClassificationTag> cachedTags)
=> SegmentedListPool<TagSpan<IClassificationTag>>.ComputeList(
static (args, tags) => args.cachedTags.AddIntersectingTagSpans(args.spans, tags),
(cachedTags, spans));

public IEnumerable<ITagSpan<IClassificationTag>> GetAllTags(NormalizedSnapshotSpanCollection spans, CancellationToken cancellationToken)
IEnumerable<ITagSpan<IClassificationTag>> IAccurateTagger<IClassificationTag>.GetAllTags(NormalizedSnapshotSpanCollection spans, CancellationToken cancellationToken)
=> GetAllTags(spans, cancellationToken);

public IEnumerable<TagSpan<IClassificationTag>> GetAllTags(NormalizedSnapshotSpanCollection spans, CancellationToken cancellationToken)
{
if (spans.Count == 0)
return [];
Expand Down Expand Up @@ -125,7 +128,7 @@ public IEnumerable<ITagSpan<IClassificationTag>> GetAllTags(NormalizedSnapshotSp
}
}

private IEnumerable<ITagSpan<IClassificationTag>> ComputeAndCacheAllTags(
private IEnumerable<TagSpan<IClassificationTag>> ComputeAndCacheAllTags(
NormalizedSnapshotSpanCollection spans,
ITextSnapshot snapshot,
Document document,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ public void Dispose()

public event EventHandler<SnapshotSpanEventArgs> TagsChanged;

public IEnumerable<ITagSpan<T>> GetTags(NormalizedSnapshotSpanCollection spans)
IEnumerable<ITagSpan<T>> ITagger<T>.GetTags(NormalizedSnapshotSpanCollection spans)
=> GetTags(spans);

public IEnumerable<TagSpan<T>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (_renameService.ActiveSession == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public IEnumerable<ITagSpan<RenameTrackingTag>> GetTags(NormalizedSnapshotSpanCo
IEnumerable<ITagSpan<IErrorTag>> ITagger<IErrorTag>.GetTags(NormalizedSnapshotSpanCollection spans)
=> GetTags(spans, new ErrorTag(PredefinedErrorTypeNames.Suggestion));

private IEnumerable<ITagSpan<T>> GetTags<T>(NormalizedSnapshotSpanCollection spans, T tag) where T : ITag
private IEnumerable<TagSpan<T>> GetTags<T>(NormalizedSnapshotSpanCollection spans, T tag) where T : ITag
{
if (!_stateMachine.GlobalOptions.GetOption(RenameTrackingOptionsStorage.RenameTracking))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ internal partial class TagSpanIntervalTree<TTag>
private readonly struct IntervalIntrospector(
ITextSnapshot snapshot,
SpanTrackingMode trackingMode)
: IIntervalIntrospector<ITagSpan<TTag>>
: IIntervalIntrospector<TagSpan<TTag>>
{
public TextSpan GetSpan(ITagSpan<TTag> value)
public TextSpan GetSpan(TagSpan<TTag> value)
=> GetTranslatedSpan(value, snapshot, trackingMode).Span.ToTextSpan();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Tagging;
internal sealed partial class TagSpanIntervalTree<TTag>(
ITextBuffer textBuffer,
SpanTrackingMode trackingMode,
IEnumerable<ITagSpan<TTag>>? values1 = null,
IEnumerable<ITagSpan<TTag>>? values2 = null) where TTag : ITag
IEnumerable<TagSpan<TTag>>? values1 = null,
IEnumerable<TagSpan<TTag>>? values2 = null) where TTag : ITag
{
private readonly ITextBuffer _textBuffer = textBuffer;
private readonly SpanTrackingMode _spanTrackingMode = trackingMode;
private readonly IntervalTree<ITagSpan<TTag>> _tree = IntervalTree.Create(
private readonly IntervalTree<TagSpan<TTag>> _tree = IntervalTree.Create(
new IntervalIntrospector(textBuffer.CurrentSnapshot, trackingMode),
values1, values2);

private static SnapshotSpan GetTranslatedSpan(
ITagSpan<TTag> originalTagSpan, ITextSnapshot textSnapshot, SpanTrackingMode trackingMode)
TagSpan<TTag> originalTagSpan, ITextSnapshot textSnapshot, SpanTrackingMode trackingMode)
{
var localSpan = originalTagSpan.Span;

Expand All @@ -43,13 +43,13 @@ private static SnapshotSpan GetTranslatedSpan(
: localSpan.TranslateTo(textSnapshot, trackingMode);
}

private ITagSpan<TTag> GetTranslatedITagSpan(ITagSpan<TTag> originalTagSpan, ITextSnapshot textSnapshot)
private TagSpan<TTag> GetTranslatedITagSpan(TagSpan<TTag> originalTagSpan, ITextSnapshot textSnapshot)
// Avoid reallocating in the case where we're on the same snapshot.
=> originalTagSpan.Span.Snapshot == textSnapshot
? originalTagSpan
: GetTranslatedTagSpan(originalTagSpan, textSnapshot, _spanTrackingMode);

private static TagSpan<TTag> GetTranslatedTagSpan(ITagSpan<TTag> originalTagSpan, ITextSnapshot textSnapshot, SpanTrackingMode trackingMode)
private static TagSpan<TTag> GetTranslatedTagSpan(TagSpan<TTag> originalTagSpan, ITextSnapshot textSnapshot, SpanTrackingMode trackingMode)
// Avoid reallocating in the case where we're on the same snapshot.
=> originalTagSpan is TagSpan<TTag> tagSpan && tagSpan.Span.Snapshot == textSnapshot
? tagSpan
Expand All @@ -67,7 +67,7 @@ public bool HasSpanThatContains(SnapshotPoint point)
return _tree.HasIntervalThatContains(point.Position, length: 0, new IntervalIntrospector(snapshot, _spanTrackingMode));
}

public IList<TagSpan<TTag>> GetIntersectingSpans(SnapshotSpan snapshotSpan)
public IReadOnlyList<TagSpan<TTag>> GetIntersectingSpans(SnapshotSpan snapshotSpan)
=> SegmentedListPool<TagSpan<TTag>>.ComputeList(
static (args, tags) => [email protected](args.snapshotSpan, tags),
(@this: this, snapshotSpan));
Expand All @@ -82,7 +82,7 @@ private void AppendIntersectingSpansInSortedOrder(SnapshotSpan snapshotSpan, Seg
var snapshot = snapshotSpan.Snapshot;
Debug.Assert(snapshot.TextBuffer == _textBuffer);

using var intersectingIntervals = TemporaryArray<ITagSpan<TTag>>.Empty;
using var intersectingIntervals = TemporaryArray<TagSpan<TTag>>.Empty;
_tree.FillWithIntervalsThatIntersectWith(
snapshotSpan.Start, snapshotSpan.Length,
ref intersectingIntervals.AsRef(),
Expand All @@ -92,14 +92,14 @@ ref intersectingIntervals.AsRef(),
result.Add(GetTranslatedTagSpan(tagSpan, snapshot, _spanTrackingMode));
}

public IEnumerable<ITagSpan<TTag>> GetSpans(ITextSnapshot snapshot)
public IEnumerable<TagSpan<TTag>> GetSpans(ITextSnapshot snapshot)
=> _tree.Select(tn => GetTranslatedITagSpan(tn, snapshot));

/// <summary>
/// Adds all the tag spans in <see langword="this"/> to <paramref name="tagSpans"/>, translating them to the given
/// location <paramref name="textSnapshot"/> based on <see cref="_spanTrackingMode"/>.
/// </summary>
public void AddAllSpans(ITextSnapshot textSnapshot, HashSet<ITagSpan<TTag>> tagSpans)
public void AddAllSpans(ITextSnapshot textSnapshot, HashSet<TagSpan<TTag>> tagSpans)
{
foreach (var tagSpan in _tree)
tagSpans.Add(GetTranslatedITagSpan(tagSpan, textSnapshot));
Expand All @@ -110,9 +110,9 @@ public void AddAllSpans(ITextSnapshot textSnapshot, HashSet<ITagSpan<TTag>> tagS
/// the spans in <paramref name="snapshotSpansToRemove"/>.
/// </summary>
public void RemoveIntersectingTagSpans(
ArrayBuilder<SnapshotSpan> snapshotSpansToRemove, HashSet<ITagSpan<TTag>> tagSpans)
ArrayBuilder<SnapshotSpan> snapshotSpansToRemove, HashSet<TagSpan<TTag>> tagSpans)
{
using var buffer = TemporaryArray<ITagSpan<TTag>>.Empty;
using var buffer = TemporaryArray<TagSpan<TTag>>.Empty;

foreach (var snapshotSpan in snapshotSpansToRemove)
{
Expand Down Expand Up @@ -202,7 +202,7 @@ private void AddTagsForLargeNumberOfSpans(NormalizedSnapshotSpanCollection reque
if (!enumerator.MoveNext())
return;

using var _2 = PooledHashSet<ITagSpan<TTag>>.GetInstance(out var hashSet);
using var _2 = PooledHashSet<TagSpan<TTag>>.GetInstance(out var hashSet);

var requestIndex = 0;
while (true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public TagSource(
_dataSource = dataSource;
_asyncListener = asyncListener;
_nonFrozenComputationCancellationSeries = new(_disposalTokenSource.Token);
_tagSpanSetPool = new ObjectPool<HashSet<ITagSpan<TTag>>>(() => new HashSet<ITagSpan<TTag>>(this), trimOnFree: false);
_tagSpanSetPool = new ObjectPool<HashSet<TagSpan<TTag>>>(() => new HashSet<TagSpan<TTag>>(this), trimOnFree: false);

_workspaceRegistration = Workspace.GetWorkspaceRegistration(subjectBuffer.AsTextContainer());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ namespace Microsoft.CodeAnalysis.Editor.Tagging;

internal abstract partial class AbstractAsynchronousTaggerProvider<TTag>
{
private partial class TagSource : IEqualityComparer<ITagSpan<TTag>>
private partial class TagSource : IEqualityComparer<TagSpan<TTag>>
{
private readonly ObjectPool<HashSet<ITagSpan<TTag>>> _tagSpanSetPool;
private readonly ObjectPool<HashSet<TagSpan<TTag>>> _tagSpanSetPool;

public bool Equals(ITagSpan<TTag>? x, ITagSpan<TTag>? y)
public bool Equals(TagSpan<TTag>? x, TagSpan<TTag>? y)
{
if (x == y)
return true;
Expand All @@ -28,10 +28,10 @@ public bool Equals(ITagSpan<TTag>? x, ITagSpan<TTag>? y)
/// <summary>
/// For the purposes of hashing, just hash spans. This will prevent most collisions. And the rare
/// collision of two tag spans with the same span will be handled by checking if their tags are the same
/// through <see cref="Equals(ITagSpan{TTag}, ITagSpan{TTag})"/>. This prevents us from having to
/// through <see cref="Equals(TagSpan{TTag}, TagSpan{TTag})"/>. This prevents us from having to
/// define a suitable hashing strategy for all our tags.
/// </summary>
public int GetHashCode(ITagSpan<TTag> obj)
public int GetHashCode(TagSpan<TTag> obj)
=> obj.Span.Span.GetHashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ private ImmutableDictionary<ITextBuffer, TagSpanIntervalTree<TTag>> ComputeNewTa
foreach (var spanToTag in context.SpansToTag)
buffersToTag.Add(spanToTag.SnapshotSpan.Snapshot.TextBuffer);

using var _2 = ArrayBuilder<ITagSpan<TTag>>.GetInstance(out var newTagsInBuffer);
using var _2 = ArrayBuilder<TagSpan<TTag>>.GetInstance(out var newTagsInBuffer);
using var _3 = ArrayBuilder<SnapshotSpan>.GetInstance(out var spansToInvalidateInBuffer);

var newTagTrees = ImmutableDictionary.CreateBuilder<ITextBuffer, TagSpanIntervalTree<TTag>>();
Expand Down Expand Up @@ -427,7 +427,7 @@ private ImmutableDictionary<ITextBuffer, TagSpanIntervalTree<TTag>> ComputeNewTa
private TagSpanIntervalTree<TTag>? ComputeNewTagTree(
ImmutableDictionary<ITextBuffer, TagSpanIntervalTree<TTag>> oldTagTrees,
ITextBuffer textBuffer,
ArrayBuilder<ITagSpan<TTag>> newTags,
ArrayBuilder<TagSpan<TTag>> newTags,
ArrayBuilder<SnapshotSpan> spansToInvalidate)
{
var noNewTags = newTags.IsEmpty;
Expand Down Expand Up @@ -469,7 +469,7 @@ private ImmutableDictionary<ITextBuffer, TagSpanIntervalTree<TTag>> ComputeNewTa
private static void AddNonIntersectingTagSpans(
ArrayBuilder<SnapshotSpan> spansToInvalidate,
TagSpanIntervalTree<TTag> oldTagTree,
HashSet<ITagSpan<TTag>> nonIntersectingTagSpans)
HashSet<TagSpan<TTag>> nonIntersectingTagSpans)
{
var firstSpanToInvalidate = spansToInvalidate.First();
var snapshot = firstSpanToInvalidate.Snapshot;
Expand Down Expand Up @@ -611,7 +611,7 @@ private DiffResult ComputeDifference(

return new DiffResult(new(added), new(removed));

static ITagSpan<TTag>? NextOrNull(IEnumerator<ITagSpan<TTag>> enumerator)
static TagSpan<TTag>? NextOrNull(IEnumerator<TagSpan<TTag>> enumerator)
=> enumerator.MoveNext() ? enumerator.Current : null;
}

Expand Down
Loading
Loading