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

Cache classification services #73635

Merged
merged 6 commits into from
May 22, 2024
Merged
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 @@ -17,6 +17,7 @@
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Utilities;
using Roslyn.LanguageServer.Protocol;
using Roslyn.Utilities;

Expand All @@ -34,6 +35,12 @@ internal partial class SyntacticClassificationTaggerProvider
/// </summary>
internal sealed partial class TagComputer
{
private sealed record CachedServices(
Workspace Workspace,
IContentType ContentType,
SolutionServices SolutionServices,
IClassificationService ClassificationService);

private static readonly object s_uniqueKey = new();

private readonly SyntacticClassificationTaggerProvider _taggerProvider;
Expand All @@ -56,6 +63,13 @@ internal sealed partial class TagComputer

private Workspace? _workspace;

/// <summary>
/// Cached values for the last services we computed for a particular <see cref="Workspace"/> and <see
/// cref="IContentType"/>. These rarely change, and are expensive enough to show up in very hot scenarios (like
/// scrolling) where we are going to be called in at a very high volume.
/// </summary>
private CachedServices? _lastCachedServices;

// The latest data about the document being classified that we've cached. objects can
// be accessed from both threads, and must be obtained when this lock is held.
//
Expand Down Expand Up @@ -119,13 +133,25 @@ private void DisconnectTagComputer()

private (SolutionServices solutionServices, IClassificationService classificationService)? TryGetClassificationService(ITextSnapshot snapshot)
{
if (_workspace?.Services.SolutionServices is not { } solutionServices)
return null;
var workspace = _workspace;
var contentType = snapshot.ContentType;
var lastCachedServices = _lastCachedServices;

if (solutionServices.GetProjectServices(snapshot.ContentType)?.GetService<IClassificationService>() is not { } classificationService)
return null;
if (lastCachedServices is null ||
lastCachedServices.Workspace != workspace ||
lastCachedServices.ContentType != contentType)
{
if (workspace?.Services.SolutionServices is not { } solutionServices)
return null;

if (solutionServices.GetProjectServices(contentType)?.GetService<IClassificationService>() is not { } classificationService)
return null;

lastCachedServices = new(workspace, contentType, solutionServices, classificationService);
_lastCachedServices = lastCachedServices;
}

return (solutionServices, classificationService);
return (lastCachedServices.SolutionServices, lastCachedServices.ClassificationService);
}

#region Workspace Hookup
Expand Down Expand Up @@ -206,6 +232,7 @@ private void ConnectToWorkspace(Workspace workspace)
public void DisconnectFromWorkspace()
{
_taggerProvider._threadingContext.ThrowIfNotOnUIThread();
_lastCachedServices = null;

lock (_gate)
{
Expand Down
Loading