From 14eece92e3db5e20916afe594d98149dade26144 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 22 May 2024 13:24:01 -0700 Subject: [PATCH 1/8] Squeeze perf --- .../Core/Classification/TotalClassificationTaggerProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs index 89800c1090014..6a45dcf8d7429 100644 --- a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs @@ -77,7 +77,7 @@ internal sealed class TotalClassificationAggregateTagger( EfficientTagger embeddedTagger) : AbstractAggregateTagger([syntacticTagger, semanticTagger, embeddedTagger]) { - private static readonly Comparison> s_spanComparison = static (s1, s2) => s1.Span.Start - s2.Span.Start; + private static readonly Comparison> s_spanComparison = static (s1, s2) => s1.Span.Start.Position - s2.Span.Start.Position; public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> totalTags) { From c5a38ade732fddc502c901a071c6a20542e9410b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 22 May 2024 13:39:46 -0700 Subject: [PATCH 2/8] Move to tag spans --- ...assificationBufferTaggerProvider.Tagger.cs | 8 ++-- ...lassificationTaggerProvider.TagComputer.cs | 4 +- ...cticClassificationTaggerProvider.Tagger.cs | 2 +- .../TotalClassificationTaggerProvider.cs | 47 +++++++++++-------- .../Tagging/Utilities/TagSpanIntervalTree.cs | 18 +++---- ...ousTaggerProvider.TagSource_ProduceTags.cs | 2 +- ...stractAsynchronousTaggerProvider.Tagger.cs | 2 +- .../Core/Tagging/AggregateTagger.cs | 2 +- .../Core/Tagging/EfficientTagger.cs | 4 +- 9 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs b/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs index 3dc766d03b57f..d508117fcfcda 100644 --- a/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs +++ b/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs @@ -90,7 +90,7 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC } private static IEnumerable> GetIntersectingTags(NormalizedSnapshotSpanCollection spans, TagSpanIntervalTree cachedTags) - => SegmentedListPool>.ComputeList( + => SegmentedListPool>.ComputeList( static (args, tags) => args.cachedTags.AddIntersectingTagSpans(args.spans, tags), (cachedTags, spans)); @@ -138,7 +138,7 @@ private IEnumerable> ComputeAndCacheAllTags( var options = _globalOptions.GetClassificationOptions(document.Project.Language); // Final list of tags to produce, containing syntax/semantic/embedded classification tags. - using var _ = SegmentedListPool.GetPooledList>(out var mergedTags); + using var _ = SegmentedListPool.GetPooledList>(out var mergedTags); _owner._threadingContext.JoinableTaskFactory.Run(async () => { @@ -166,7 +166,7 @@ await TotalClassificationAggregateTagger.AddTagsAsync( return GetIntersectingTags(spans, cachedTags); - Func>, VoidResult, Task> GetTaggingFunction( + Func>, VoidResult, Task> GetTaggingFunction( bool requireSingleSpan, Func, Task> addTagsAsync) { Contract.ThrowIfTrue(requireSingleSpan && spans.Count != 1, "We should only be asking for a single span"); @@ -175,7 +175,7 @@ Func> result, + SegmentedList> result, Func, Task> addAsync) { // temp buffer we can use across all our classification calls. Should be cleared between each call. diff --git a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs index 3ae79201c33a4..14e1bc4e972df 100644 --- a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs +++ b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs @@ -392,7 +392,7 @@ async ValueTask ComputeChangedSpanAsync() return _lastProcessedData; } - public void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags) + public void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags) { _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); @@ -400,7 +400,7 @@ public void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags) + private void AddTagsWorker(NormalizedSnapshotSpanCollection spans, SegmentedList> tags) { _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); if (spans.Count == 0 || _workspace == null) diff --git a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.Tagger.cs b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.Tagger.cs index 5e0cff8f50880..b22ede5812c80 100644 --- a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.Tagger.cs +++ b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.Tagger.cs @@ -24,7 +24,7 @@ public Tagger(TagComputer tagComputer) public override void AddTags( NormalizedSnapshotSpanCollection spans, - SegmentedList> tags) + SegmentedList> tags) { var tagComputer = _tagComputer ?? throw new ObjectDisposedException(GetType().FullName); tagComputer.AddTags(spans, tags); diff --git a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs index 6a45dcf8d7429..3632a0d98b6e1 100644 --- a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -77,9 +78,9 @@ internal sealed class TotalClassificationAggregateTagger( EfficientTagger embeddedTagger) : AbstractAggregateTagger([syntacticTagger, semanticTagger, embeddedTagger]) { - private static readonly Comparison> s_spanComparison = static (s1, s2) => s1.Span.Start.Position - s2.Span.Start.Position; + private static readonly IComparer> s_spanComparer = new TagSpanComparer(); - public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> totalTags) + public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> totalTags) { // Everything we pass in is synchronous, so we should immediately get a completed task back out. AddTagsAsync( @@ -105,10 +106,10 @@ public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedLi public static async Task AddTagsAsync( NormalizedSnapshotSpanCollection spans, - SegmentedList> totalTags, - Func>, TArg, Task> addSyntacticSpansAsync, - Func>, TArg, Task> addSemanticSpansAsync, - Func>, TArg, Task> addEmbeddedSpansAsync, + SegmentedList> totalTags, + Func>, TArg, Task> addSyntacticSpansAsync, + Func>, TArg, Task> addSemanticSpansAsync, + Func>, TArg, Task> addEmbeddedSpansAsync, TArg arg) { // First, get all the syntactic tags. While they are generally overridden by semantic tags (since semantics @@ -116,15 +117,15 @@ public static async Task AddTagsAsync( // tags like 'Comments' and 'Excluded Code'. In those cases we want the classification to 'snap' instantly to // the syntactic state, and we do not want things like semantic classifications showing up over that. - using var _1 = SegmentedListPool.GetPooledList>(out var stringLiterals); - using var _2 = SegmentedListPool.GetPooledList>(out var syntacticSpans); - using var _3 = SegmentedListPool.GetPooledList>(out var semanticSpans); + using var _1 = SegmentedListPool.GetPooledList>(out var stringLiterals); + using var _2 = SegmentedListPool.GetPooledList>(out var syntacticSpans); + using var _3 = SegmentedListPool.GetPooledList>(out var semanticSpans); await addSyntacticSpansAsync(spans, syntacticSpans, arg).ConfigureAwait(false); await addSemanticSpansAsync(spans, semanticSpans, arg).ConfigureAwait(false); - syntacticSpans.Sort(s_spanComparison); - semanticSpans.Sort(s_spanComparison); + syntacticSpans.Sort(s_spanComparer); + semanticSpans.Sort(s_spanComparer); using var syntacticEnumerator = syntacticSpans.GetEnumerator(); using var semanticEnumerator = semanticSpans.GetEnumerator(); @@ -231,7 +232,7 @@ async Task AddEmbeddedClassificationsAsync() return; // Only need to ask for the spans that overlapped the string literals. - using var _1 = SegmentedListPool.GetPooledList>(out var embeddedClassifications); + using var _1 = SegmentedListPool.GetPooledList>(out var embeddedClassifications); var stringLiteralSpansFull = new NormalizedSnapshotSpanCollection(stringLiterals.Select(s => s.Span)); @@ -250,14 +251,14 @@ async Task AddEmbeddedClassificationsAsync() } // ClassifierHelper.MergeParts requires these to be sorted. - stringLiterals.Sort(s_spanComparison); - embeddedClassifications.Sort(s_spanComparison); + stringLiterals.Sort(s_spanComparer); + embeddedClassifications.Sort(s_spanComparer); // Call into the helper to merge the string literals and embedded classifications into the final result. // The helper will add all the embedded classifications first, then add string literal classifications // in the the space between the embedded classifications that were originally classified as a string // literal. - ClassifierHelper.MergeParts, ClassificationTagSpanIntervalIntrospector>( + ClassifierHelper.MergeParts, ClassificationTagSpanIntervalIntrospector>( stringLiterals, embeddedClassifications, totalTags, @@ -265,19 +266,25 @@ async Task AddEmbeddedClassificationsAsync() static (original, final) => new TagSpan(new SnapshotSpan(original.Span.Snapshot, final.ToSpan()), original.Tag)); } - ITagSpan? GetNextSyntacticSpan() + TagSpan? GetNextSyntacticSpan() => syntacticEnumerator.MoveNext() ? syntacticEnumerator.Current : null; - ITagSpan? GetNextSemanticSpan() + TagSpan? GetNextSemanticSpan() => semanticEnumerator.MoveNext() ? semanticEnumerator.Current : null; } - private readonly struct ClassificationTagSpanIntervalIntrospector : IIntervalIntrospector> + private sealed class TagSpanComparer : IComparer> { - public int GetStart(ITagSpan value) + public int Compare(TagSpan? x, TagSpan? y) + => x!.Span.Start.Position - y!.Span.Start.Position; + } + + private readonly struct ClassificationTagSpanIntervalIntrospector : IIntervalIntrospector> + { + public int GetStart(TagSpan value) => value.Span.Start; - public int GetLength(ITagSpan value) + public int GetLength(TagSpan value) => value.Span.Length; } } diff --git a/src/EditorFeatures/Core/Shared/Tagging/Utilities/TagSpanIntervalTree.cs b/src/EditorFeatures/Core/Shared/Tagging/Utilities/TagSpanIntervalTree.cs index fa6fae448e9e2..28cf058ccddda 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/Utilities/TagSpanIntervalTree.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/Utilities/TagSpanIntervalTree.cs @@ -51,8 +51,8 @@ public bool HasSpanThatContains(SnapshotPoint point) return _tree.HasIntervalThatContains(point.Position, length: 0, new IntervalIntrospector(snapshot)); } - public IList> GetIntersectingSpans(SnapshotSpan snapshotSpan) - => SegmentedListPool>.ComputeList( + public IList> GetIntersectingSpans(SnapshotSpan snapshotSpan) + => SegmentedListPool>.ComputeList( static (args, tags) => args.@this.AppendIntersectingSpansInSortedOrder(args.snapshotSpan, tags), (@this: this, snapshotSpan)); @@ -61,7 +61,7 @@ public IList> GetIntersectingSpans(SnapshotSpan snapshotSpan) /// . Note the sorted chunk of items are appended to . This /// means that may not be sorted if there were already items in them. /// - private void AppendIntersectingSpansInSortedOrder(SnapshotSpan snapshotSpan, SegmentedList> result) + private void AppendIntersectingSpansInSortedOrder(SnapshotSpan snapshotSpan, SegmentedList> result) { var snapshot = snapshotSpan.Snapshot; Debug.Assert(snapshot.TextBuffer == _textBuffer); @@ -80,14 +80,14 @@ public IEnumerable> GetSpans(ITextSnapshot snapshot) public bool IsEmpty() => _tree.IsEmpty(); - public void AddIntersectingTagSpans(NormalizedSnapshotSpanCollection requestedSpans, SegmentedList> tags) + public void AddIntersectingTagSpans(NormalizedSnapshotSpanCollection requestedSpans, SegmentedList> tags) { AddIntersectingTagSpansWorker(requestedSpans, tags); DebugVerifyTags(requestedSpans, tags); } [Conditional("DEBUG")] - private static void DebugVerifyTags(NormalizedSnapshotSpanCollection requestedSpans, SegmentedList> tags) + private static void DebugVerifyTags(NormalizedSnapshotSpanCollection requestedSpans, SegmentedList> tags) { if (tags == null) { @@ -107,7 +107,7 @@ private static void DebugVerifyTags(NormalizedSnapshotSpanCollection requestedSp private void AddIntersectingTagSpansWorker( NormalizedSnapshotSpanCollection requestedSpans, - SegmentedList> tags) + SegmentedList> tags) { const int MaxNumberOfRequestedSpans = 100; @@ -123,20 +123,20 @@ private void AddIntersectingTagSpansWorker( private void AddTagsForSmallNumberOfSpans( NormalizedSnapshotSpanCollection requestedSpans, - SegmentedList> tags) + SegmentedList> tags) { foreach (var span in requestedSpans) AppendIntersectingSpansInSortedOrder(span, tags); } - private void AddTagsForLargeNumberOfSpans(NormalizedSnapshotSpanCollection requestedSpans, SegmentedList> tags) + private void AddTagsForLargeNumberOfSpans(NormalizedSnapshotSpanCollection requestedSpans, SegmentedList> tags) { // we are asked with bunch of spans. rather than asking same question again and again, ask once with big span // which will return superset of what we want. and then filter them out in O(m+n) cost. // m == number of requested spans, n = number of returned spans var mergedSpan = new SnapshotSpan(requestedSpans[0].Start, requestedSpans[^1].End); - using var _1 = SegmentedListPool.GetPooledList>(out var tempList); + using var _1 = SegmentedListPool.GetPooledList>(out var tempList); AppendIntersectingSpansInSortedOrder(mergedSpan, tempList); if (tempList.Count == 0) diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs index f9d653b11ab5b..c40775baecbff 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs @@ -637,7 +637,7 @@ private DiffResult ComputeDifference( return tags; } - public void AddTags(NormalizedSnapshotSpanCollection requestedSpans, SegmentedList> tags) + public void AddTags(NormalizedSnapshotSpanCollection requestedSpans, SegmentedList> tags) { _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.Tagger.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.Tagger.cs index ee29cefc34951..28112e94b794a 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.Tagger.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.Tagger.cs @@ -35,7 +35,7 @@ public override event EventHandler? TagsChanged public override void Dispose() => _tagSource.OnTaggerDisposed(this); - public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags) + public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags) => _tagSource.AddTags(spans, tags); } } diff --git a/src/EditorFeatures/Core/Tagging/AggregateTagger.cs b/src/EditorFeatures/Core/Tagging/AggregateTagger.cs index 30254fec583ea..cda1c691cb139 100644 --- a/src/EditorFeatures/Core/Tagging/AggregateTagger.cs +++ b/src/EditorFeatures/Core/Tagging/AggregateTagger.cs @@ -56,7 +56,7 @@ internal sealed class SimpleAggregateTagger(ImmutableArray(taggers) where TTag : ITag { - public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags) + public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags) { foreach (var tagger in this.Taggers) tagger.AddTags(spans, tags); diff --git a/src/EditorFeatures/Core/Tagging/EfficientTagger.cs b/src/EditorFeatures/Core/Tagging/EfficientTagger.cs index 2b73738b90f79..09277d30982cd 100644 --- a/src/EditorFeatures/Core/Tagging/EfficientTagger.cs +++ b/src/EditorFeatures/Core/Tagging/EfficientTagger.cs @@ -22,7 +22,7 @@ internal abstract class EfficientTagger : ITagger, IDisposable where /// /// Produce the set of tags with the requested , adding those tags to . /// - public abstract void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags); + public abstract void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> tags); public abstract void Dispose(); @@ -30,7 +30,7 @@ internal abstract class EfficientTagger : ITagger, IDisposable where /// Default impl of the core interface. Forces an allocation. /// public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) - => SegmentedListPool>.ComputeList( + => SegmentedListPool>.ComputeList( static (args, tags) => args.@this.AddTags(args.spans, tags), (@this: this, spans)); From 5862e0187958d8b69753d2aa45d6f2adb5062fc3 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 22 May 2024 13:51:51 -0700 Subject: [PATCH 3/8] no alloc --- src/Dependencies/Collections/SegmentedArray.cs | 16 ++++++++++++++++ src/Dependencies/Collections/SegmentedList`1.cs | 2 +- .../TotalClassificationTaggerProvider.cs | 10 +++++----- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Dependencies/Collections/SegmentedArray.cs b/src/Dependencies/Collections/SegmentedArray.cs index 41b2fd7b96f47..da9c20f4c032f 100644 --- a/src/Dependencies/Collections/SegmentedArray.cs +++ b/src/Dependencies/Collections/SegmentedArray.cs @@ -394,6 +394,22 @@ public static void Sort(SegmentedArray array, int index, int length, IComp } } + public static void Sort(SegmentedArray array, int index, int length, Comparison comparison) + { + if (index < 0) + ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); + if (length < 0) + ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); + if (array.Length - index < length) + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); + + if (length > 1) + { + var segment = new SegmentedArraySegment(array, index, length); + SegmentedArraySortHelper.Sort(segment, comparison); + } + } + public static void Sort(SegmentedArray array, Comparison comparison) { if (comparison is null) diff --git a/src/Dependencies/Collections/SegmentedList`1.cs b/src/Dependencies/Collections/SegmentedList`1.cs index bf2bef8821287..ad4318528630a 100644 --- a/src/Dependencies/Collections/SegmentedList`1.cs +++ b/src/Dependencies/Collections/SegmentedList`1.cs @@ -1198,7 +1198,7 @@ public void Sort(Comparison comparison) if (_size > 1) { - SegmentedArray.Sort(_items, 0, _size, Comparer.Create(comparison)); + SegmentedArray.Sort(_items, 0, _size, comparison); } _version++; } diff --git a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs index 3632a0d98b6e1..f43e490e61595 100644 --- a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs @@ -78,7 +78,7 @@ internal sealed class TotalClassificationAggregateTagger( EfficientTagger embeddedTagger) : AbstractAggregateTagger([syntacticTagger, semanticTagger, embeddedTagger]) { - private static readonly IComparer> s_spanComparer = new TagSpanComparer(); + private static readonly Comparison> s_spanComparison = static (s1, s2) => s1.Span.Start.Position - s2.Span.Start.Position; public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> totalTags) { @@ -124,8 +124,8 @@ public static async Task AddTagsAsync( await addSyntacticSpansAsync(spans, syntacticSpans, arg).ConfigureAwait(false); await addSemanticSpansAsync(spans, semanticSpans, arg).ConfigureAwait(false); - syntacticSpans.Sort(s_spanComparer); - semanticSpans.Sort(s_spanComparer); + syntacticSpans.Sort(s_spanComparison); + semanticSpans.Sort(s_spanComparison); using var syntacticEnumerator = syntacticSpans.GetEnumerator(); using var semanticEnumerator = semanticSpans.GetEnumerator(); @@ -251,8 +251,8 @@ async Task AddEmbeddedClassificationsAsync() } // ClassifierHelper.MergeParts requires these to be sorted. - stringLiterals.Sort(s_spanComparer); - embeddedClassifications.Sort(s_spanComparer); + stringLiterals.Sort(s_spanComparison); + embeddedClassifications.Sort(s_spanComparison); // Call into the helper to merge the string literals and embedded classifications into the final result. // The helper will add all the embedded classifications first, then add string literal classifications From 316f0a60b0ef0b1ed1271ccb51d1ad26f9f74c36 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 22 May 2024 13:59:04 -0700 Subject: [PATCH 4/8] Remove suppresion --- src/Dependencies/Collections/Internal/ArraySortHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dependencies/Collections/Internal/ArraySortHelper.cs b/src/Dependencies/Collections/Internal/ArraySortHelper.cs index 7c12f6f76a234..16e14d6b08eb4 100644 --- a/src/Dependencies/Collections/Internal/ArraySortHelper.cs +++ b/src/Dependencies/Collections/Internal/ArraySortHelper.cs @@ -67,7 +67,7 @@ internal static void Sort(SegmentedArraySegment keys, Comparison comparer) // Add a try block here to detect bogus comparisons try { - IntrospectiveSort(keys, comparer!); + IntrospectiveSort(keys, comparer); } catch (IndexOutOfRangeException) { From 3a08e9ec94247dc21c4994b91bbde13d3a585c8f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 22 May 2024 14:03:49 -0700 Subject: [PATCH 5/8] no interface --- .../Core/Classification/TotalClassificationTaggerProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs index f43e490e61595..9ebae388001c6 100644 --- a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs @@ -78,7 +78,7 @@ internal sealed class TotalClassificationAggregateTagger( EfficientTagger embeddedTagger) : AbstractAggregateTagger([syntacticTagger, semanticTagger, embeddedTagger]) { - private static readonly Comparison> s_spanComparison = static (s1, s2) => s1.Span.Start.Position - s2.Span.Start.Position; + private static readonly Comparison> s_spanComparison = static (s1, s2) => s1.Span.Start.Position - s2.Span.Start.Position; public override void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList> totalTags) { From 79831fcd019c8d28cf426ed64179e1a6325a24c0 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 22 May 2024 14:04:04 -0700 Subject: [PATCH 6/8] Simplify --- .../Classification/TotalClassificationTaggerProvider.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs index 9ebae388001c6..1b918a7ae3274 100644 --- a/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/TotalClassificationTaggerProvider.cs @@ -273,12 +273,6 @@ async Task AddEmbeddedClassificationsAsync() => semanticEnumerator.MoveNext() ? semanticEnumerator.Current : null; } - private sealed class TagSpanComparer : IComparer> - { - public int Compare(TagSpan? x, TagSpan? y) - => x!.Span.Start.Position - y!.Span.Start.Position; - } - private readonly struct ClassificationTagSpanIntervalIntrospector : IIntervalIntrospector> { public int GetStart(TagSpan value) From f6f7d32267800601fa410f525b8b4f31f51fcf04 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 22 May 2024 14:20:11 -0700 Subject: [PATCH 7/8] Add back --- src/Dependencies/Collections/Internal/ArraySortHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dependencies/Collections/Internal/ArraySortHelper.cs b/src/Dependencies/Collections/Internal/ArraySortHelper.cs index 16e14d6b08eb4..7c12f6f76a234 100644 --- a/src/Dependencies/Collections/Internal/ArraySortHelper.cs +++ b/src/Dependencies/Collections/Internal/ArraySortHelper.cs @@ -67,7 +67,7 @@ internal static void Sort(SegmentedArraySegment keys, Comparison comparer) // Add a try block here to detect bogus comparisons try { - IntrospectiveSort(keys, comparer); + IntrospectiveSort(keys, comparer!); } catch (IndexOutOfRangeException) { From 1eba0d9340b5dc81ceda4547b988d9c6350a3936 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 22 May 2024 14:41:25 -0700 Subject: [PATCH 8/8] prevent service fetch --- .../Classification/CSharpClassificationService.cs | 11 ++++------- .../CSharpSyntaxClassificationService.cs | 2 +- .../Classification/AbstractClassificationService.cs | 7 ++++--- .../AbstractSyntaxClassificationService.cs | 4 ---- .../VisualBasicSyntaxClassificationService.vb | 3 +-- .../VisualBasicClassificationService.vb | 3 ++- 6 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/Workspaces/CSharp/Portable/Classification/CSharpClassificationService.cs b/src/Workspaces/CSharp/Portable/Classification/CSharpClassificationService.cs index 2e344537430f3..7e503a5f28c9c 100644 --- a/src/Workspaces/CSharp/Portable/Classification/CSharpClassificationService.cs +++ b/src/Workspaces/CSharp/Portable/Classification/CSharpClassificationService.cs @@ -13,14 +13,11 @@ namespace Microsoft.CodeAnalysis.CSharp.Classification; [ExportLanguageService(typeof(IClassificationService), LanguageNames.CSharp), Shared] -internal class CSharpEditorClassificationService : AbstractClassificationService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpEditorClassificationService( + CSharpSyntaxClassificationService syntaxClassificationService) : AbstractClassificationService(syntaxClassificationService) { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpEditorClassificationService() - { - } - public override void AddLexicalClassifications(SourceText text, TextSpan textSpan, SegmentedList result, CancellationToken cancellationToken) => ClassificationHelpers.AddLexicalClassifications(text, textSpan, result, cancellationToken); diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs index 652869837a59a..292ca3086181a 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Classification; -[ExportLanguageService(typeof(ISyntaxClassificationService), LanguageNames.CSharp), Shared] +[ExportLanguageService(typeof(ISyntaxClassificationService), LanguageNames.CSharp), Export, Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] internal sealed class CSharpSyntaxClassificationService() : AbstractSyntaxClassificationService diff --git a/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs b/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs index 176d0ebd7aac7..14cd1e3f60f47 100644 --- a/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs +++ b/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs @@ -20,8 +20,10 @@ namespace Microsoft.CodeAnalysis.Classification; -internal abstract class AbstractClassificationService : IClassificationService +internal abstract class AbstractClassificationService(ISyntaxClassificationService syntaxClassificationService) : IClassificationService { + private readonly ISyntaxClassificationService _syntaxClassificationService = syntaxClassificationService; + public abstract void AddLexicalClassifications(SourceText text, TextSpan textSpan, SegmentedList result, CancellationToken cancellationToken); public abstract ClassifiedSpan AdjustStaleClassification(SourceText text, ClassifiedSpan classifiedSpan); @@ -192,8 +194,7 @@ public void AddSyntacticClassifications( if (root is null) return; - var classificationService = services.GetLanguageServices(root.Language).GetRequiredService(); - classificationService.AddSyntacticClassifications(root, textSpans, result, cancellationToken); + _syntaxClassificationService.AddSyntacticClassifications(root, textSpans, result, cancellationToken); } /// diff --git a/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs b/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs index 9738e97735b8c..2a0f06553b0dd 100644 --- a/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs +++ b/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs @@ -16,10 +16,6 @@ namespace Microsoft.CodeAnalysis.Classification; internal abstract partial class AbstractSyntaxClassificationService : ISyntaxClassificationService { - protected AbstractSyntaxClassificationService() - { - } - public abstract void AddLexicalClassifications(SourceText text, TextSpan textSpan, SegmentedList result, CancellationToken cancellationToken); public abstract void AddSyntacticClassifications(SyntaxNode root, ImmutableArray textSpans, SegmentedList result, CancellationToken cancellationToken); diff --git a/src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/VisualBasicSyntaxClassificationService.vb b/src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/VisualBasicSyntaxClassificationService.vb index 782b05a7eeff9..c6ba62e937e5c 100644 --- a/src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/VisualBasicSyntaxClassificationService.vb +++ b/src/Workspaces/VisualBasic/Portable/Classification/SyntaxClassification/VisualBasicSyntaxClassificationService.vb @@ -9,12 +9,11 @@ Imports Microsoft.CodeAnalysis.Classification Imports Microsoft.CodeAnalysis.Classification.Classifiers Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Classification.Classifiers Namespace Microsoft.CodeAnalysis.VisualBasic.Classification - + Partial Friend Class VisualBasicSyntaxClassificationService Inherits AbstractSyntaxClassificationService diff --git a/src/Workspaces/VisualBasic/Portable/Classification/VisualBasicClassificationService.vb b/src/Workspaces/VisualBasic/Portable/Classification/VisualBasicClassificationService.vb index fa6dc0e3b2f12..ba3993d0349b4 100644 --- a/src/Workspaces/VisualBasic/Portable/Classification/VisualBasicClassificationService.vb +++ b/src/Workspaces/VisualBasic/Portable/Classification/VisualBasicClassificationService.vb @@ -16,7 +16,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification - Public Sub New() + Public Sub New(syntaxClassificationService As VisualBasicSyntaxClassificationService) + MyBase.New(syntaxClassificationService) End Sub Public Overrides Sub AddLexicalClassifications(text As SourceText, textSpan As TextSpan, result As SegmentedList(Of ClassifiedSpan), cancellationToken As CancellationToken)