-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Improvements to classification perf with large string literals. #72217
Changes from all commits
f792eef
9dcb066
bf04f79
71b4de6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,17 +106,20 @@ public void VisitTokens(SyntaxNode node) | |
private void ProcessToken(SyntaxToken token) | ||
{ | ||
_cancellationToken.ThrowIfCancellationRequested(); | ||
ProcessTriviaList(token.LeadingTrivia); | ||
|
||
// Directives need to be processes as they can contain strings, which then have escapes in them. | ||
if (token.ContainsDirectives) | ||
ProcessTriviaList(token.LeadingTrivia); | ||
|
||
ClassifyToken(token); | ||
ProcessTriviaList(token.TrailingTrivia); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we were also previous walking down into trailing trivia (which never has structure). we were also walking into all structure, even though we don't have any embedded-lang classification in structured-trivia except for the case of |
||
} | ||
|
||
private void ClassifyToken(SyntaxToken token) | ||
{ | ||
if (token.Span.IntersectsWith(_textSpan) && _owner.SyntaxTokenKinds.Contains(token.RawKind)) | ||
{ | ||
var context = new EmbeddedLanguageClassificationContext( | ||
_solutionServices, _project, _semanticModel, token, _options, _owner.Info.VirtualCharService, _result, _cancellationToken); | ||
_solutionServices, _project, _semanticModel, token, _textSpan, _options, _owner.Info.VirtualCharService, _result, _cancellationToken); | ||
|
||
var classifiers = _owner.GetServices(_semanticModel, token, _cancellationToken); | ||
foreach (var classifier in classifiers) | ||
|
@@ -146,7 +149,7 @@ private void ProcessTriviaList(SyntaxTriviaList triviaList) | |
|
||
private void ProcessTrivia(SyntaxTrivia trivia) | ||
{ | ||
if (trivia.HasStructure && trivia.FullSpan.IntersectsWith(_textSpan)) | ||
if (trivia.IsDirective && trivia.FullSpan.IntersectsWith(_textSpan)) | ||
VisitTokens(trivia.GetStructure()!); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,52 +8,63 @@ | |
using Microsoft.CodeAnalysis.Host; | ||
using Microsoft.CodeAnalysis.Text; | ||
|
||
namespace Microsoft.CodeAnalysis.Classification | ||
namespace Microsoft.CodeAnalysis.Classification; | ||
|
||
internal readonly struct EmbeddedLanguageClassificationContext | ||
{ | ||
internal readonly struct EmbeddedLanguageClassificationContext | ||
internal readonly SolutionServices SolutionServices; | ||
|
||
private readonly SegmentedList<ClassifiedSpan> _result; | ||
|
||
/// <summary> | ||
/// The portion of the string or character token to classify. | ||
/// </summary> | ||
private readonly TextSpan _spanToClassify; | ||
|
||
public Project Project { get; } | ||
|
||
/// <summary> | ||
/// The string or character token to classify. | ||
/// </summary> | ||
public SyntaxToken SyntaxToken { get; } | ||
|
||
/// <summary> | ||
/// SemanticModel that <see cref="SyntaxToken"/> is contained in. | ||
/// </summary> | ||
public SemanticModel SemanticModel { get; } | ||
|
||
public CancellationToken CancellationToken { get; } | ||
|
||
internal readonly ClassificationOptions Options; | ||
internal readonly IVirtualCharService VirtualCharService; | ||
|
||
internal EmbeddedLanguageClassificationContext( | ||
SolutionServices solutionServices, | ||
Project project, | ||
SemanticModel semanticModel, | ||
SyntaxToken syntaxToken, | ||
TextSpan spanToClassify, | ||
ClassificationOptions options, | ||
IVirtualCharService virtualCharService, | ||
SegmentedList<ClassifiedSpan> result, | ||
CancellationToken cancellationToken) | ||
{ | ||
SolutionServices = solutionServices; | ||
Project = project; | ||
SemanticModel = semanticModel; | ||
SyntaxToken = syntaxToken; | ||
_spanToClassify = spanToClassify; | ||
Options = options; | ||
VirtualCharService = virtualCharService; | ||
_result = result; | ||
CancellationToken = cancellationToken; | ||
} | ||
|
||
public void AddClassification(string classificationType, TextSpan span) | ||
{ | ||
internal readonly SolutionServices SolutionServices; | ||
|
||
private readonly SegmentedList<ClassifiedSpan> _result; | ||
|
||
public Project Project { get; } | ||
|
||
/// <summary> | ||
/// The string or character token to classify. | ||
/// </summary> | ||
public SyntaxToken SyntaxToken { get; } | ||
|
||
/// <summary> | ||
/// SemanticModel that <see cref="SyntaxToken"/> is contained in. | ||
/// </summary> | ||
public SemanticModel SemanticModel { get; } | ||
|
||
public CancellationToken CancellationToken { get; } | ||
|
||
internal readonly ClassificationOptions Options; | ||
internal readonly IVirtualCharService VirtualCharService; | ||
|
||
internal EmbeddedLanguageClassificationContext( | ||
SolutionServices solutionServices, | ||
Project project, | ||
SemanticModel semanticModel, | ||
SyntaxToken syntaxToken, | ||
ClassificationOptions options, | ||
IVirtualCharService virtualCharService, | ||
SegmentedList<ClassifiedSpan> result, | ||
CancellationToken cancellationToken) | ||
{ | ||
SolutionServices = solutionServices; | ||
Project = project; | ||
SemanticModel = semanticModel; | ||
SyntaxToken = syntaxToken; | ||
Options = options; | ||
VirtualCharService = virtualCharService; | ||
_result = result; | ||
CancellationToken = cancellationToken; | ||
} | ||
|
||
public void AddClassification(string classificationType, TextSpan span) | ||
=> _result.Add(new ClassifiedSpan(classificationType, span)); | ||
// Ignore characters that don't intersect with the requested span. That avoids potentially adding lots of | ||
// classifications for portions of a large string that are out of view. | ||
if (span.IntersectsWith(_spanToClassify)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note: in the case the user provided, while the string contains json, it's not a JsonTree. All we ahve are the embedded classifications for escapes like |
||
_result.Add(new ClassifiedSpan(classificationType, span)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
view with whitespace off.