Skip to content

Commit 36542b2

Browse files
authored
Move down and interface-ize component search engine, and introduce IProjectCollectionResolver (#10706)
Started this for #10688 but saw that Go To Def used the same service, so figured @DustinCampbell would need to do the same thing, and thought it would be easier to put it up separately. (Unless of course you've already done this, or similar, Dustin in which case I can just abandon this, nbd)
2 parents 59e6260 + 0f56e69 commit 36542b2

File tree

15 files changed

+110
-47
lines changed

15 files changed

+110
-47
lines changed

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Microsoft.AspNetCore.Razor.PooledObjects;
1717
using Microsoft.AspNetCore.Razor.Utilities;
1818
using Microsoft.CodeAnalysis.Razor;
19+
using Microsoft.CodeAnalysis.Razor.Workspaces;
1920
using Microsoft.VisualStudio.Editor.Razor;
2021
using Microsoft.VisualStudio.LanguageServer.Protocol;
2122

@@ -157,7 +158,7 @@ private static async Task AddComponentAccessFromTagAsync(RazorCodeActionContext
157158
{
158159
// if fqn contains a generic typeparam, we should strip it out. Otherwise, replacing tag name will leave generic parameters in razor code, which are illegal
159160
// e.g. <Component /> -> <Component<T> />
160-
var fullyQualifiedName = DefaultRazorComponentSearchEngine.RemoveGenericContent(tagHelperPair.Short.Name.AsMemory()).ToString();
161+
var fullyQualifiedName = RazorComponentSearchEngine.RemoveGenericContent(tagHelperPair.Short.Name.AsMemory()).ToString();
161162

162163
// If the match was case insensitive, then see if we can work out a new tag name to use as part of adding a using statement
163164
TextDocumentEdit? additionalEdit = null;

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition;
2929

3030
[RazorLanguageServerEndpoint(Methods.TextDocumentDefinitionName)]
3131
internal sealed class DefinitionEndpoint(
32-
RazorComponentSearchEngine componentSearchEngine,
32+
IRazorComponentSearchEngine componentSearchEngine,
3333
IRazorDocumentMappingService documentMappingService,
3434
LanguageServerFeatureOptions languageServerFeatureOptions,
3535
IClientConnection clientConnection,
3636
ILoggerFactory loggerFactory)
3737
: AbstractRazorDelegatingEndpoint<TextDocumentPositionParams, DefinitionResult?>(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger<DefinitionEndpoint>()), ICapabilitiesProvider
3838
{
39-
private readonly RazorComponentSearchEngine _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine));
39+
private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine));
4040
private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService));
4141

4242
protected override bool PreferCSharpOverHtmlIfPossible => true;
@@ -73,7 +73,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V
7373
return default;
7474
}
7575

76-
var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(originTagDescriptor).ConfigureAwait(false);
76+
var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(documentContext.Snapshot, originTagDescriptor).ConfigureAwait(false);
7777
if (originComponentDocumentSnapshot is null)
7878
{
7979
Logger.LogInformation($"Origin TagHelper document snapshot is null.");

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ public static void AddDocumentManagementServices(this IServiceCollection service
226226
// Add project snapshot manager
227227
services.AddSingleton<IProjectEngineFactoryProvider, LspProjectEngineFactoryProvider>();
228228
services.AddSingleton<IProjectSnapshotManager, LspProjectSnapshotManager>();
229+
services.AddSingleton<IProjectCollectionResolver>(sp => (LspProjectSnapshotManager)sp.GetRequiredService<IProjectSnapshotManager>());
229230
}
230231

231232
public static void AddHandlerWithCapabilities<T>(this IServiceCollection services)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@
99
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
1010
using Microsoft.CodeAnalysis.Razor.Logging;
1111
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
12+
using Microsoft.CodeAnalysis.Razor.Workspaces;
1213

1314
namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
1415

1516
internal class LspProjectSnapshotManager(
1617
IProjectEngineFactoryProvider projectEngineFactoryProvider,
1718
ILoggerFactory loggerFactory)
18-
: ProjectSnapshotManager(projectEngineFactoryProvider, loggerFactory, initializer: AddMiscFilesProject)
19+
: ProjectSnapshotManager(projectEngineFactoryProvider, loggerFactory, initializer: AddMiscFilesProject), IProjectCollectionResolver
1920
{
2021
private static void AddMiscFilesProject(Updater updater)
2122
{
2223
updater.ProjectAdded(MiscFilesHostProject.Instance);
2324
}
25+
26+
public IEnumerable<IProjectSnapshot> EnumerateProjects(IDocumentSnapshot snapshot)
27+
{
28+
return GetProjects();
29+
}
2430
}

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,12 @@
2020
using Microsoft.AspNetCore.Razor.LanguageServer.LinkedEditingRange;
2121
using Microsoft.AspNetCore.Razor.LanguageServer.MapCode;
2222
using Microsoft.AspNetCore.Razor.LanguageServer.ProjectContexts;
23-
using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
2423
using Microsoft.AspNetCore.Razor.LanguageServer.Refactoring;
2524
using Microsoft.AspNetCore.Razor.LanguageServer.SignatureHelp;
2625
using Microsoft.AspNetCore.Razor.LanguageServer.WrapWithTag;
2726
using Microsoft.AspNetCore.Razor.Telemetry;
28-
using Microsoft.CodeAnalysis.Razor;
2927
using Microsoft.CodeAnalysis.Razor.FoldingRanges;
3028
using Microsoft.CodeAnalysis.Razor.Logging;
31-
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
3229
using Microsoft.CodeAnalysis.Razor.Workspaces;
3330
using Microsoft.CommonLanguageServerProtocol.Framework;
3431
using Microsoft.Extensions.DependencyInjection;
@@ -153,7 +150,7 @@ protected override ILspServices ConstructLspServices()
153150
}
154151

155152
// Other
156-
services.AddSingleton<RazorComponentSearchEngine, DefaultRazorComponentSearchEngine>();
153+
services.AddSingleton<IRazorComponentSearchEngine, RazorComponentSearchEngine>();
157154

158155
// Get the DefaultSession for telemetry. This is set by VS with
159156
// TelemetryService.SetDefaultSession and provides the correct

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring;
2727

2828
[RazorLanguageServerEndpoint(Methods.TextDocumentRenameName)]
2929
internal sealed class RenameEndpoint(
30-
RazorComponentSearchEngine componentSearchEngine,
31-
IProjectSnapshotManager projectManager,
30+
IRazorComponentSearchEngine componentSearchEngine,
31+
IProjectCollectionResolver projectResolver,
3232
LanguageServerFeatureOptions languageServerFeatureOptions,
3333
IRazorDocumentMappingService documentMappingService,
3434
IClientConnection clientConnection,
@@ -39,8 +39,8 @@ internal sealed class RenameEndpoint(
3939
clientConnection,
4040
loggerFactory.GetOrCreateLogger<RenameEndpoint>()), ICapabilitiesProvider
4141
{
42-
private readonly IProjectSnapshotManager _projectManager = projectManager;
43-
private readonly RazorComponentSearchEngine _componentSearchEngine = componentSearchEngine;
42+
private readonly IProjectCollectionResolver _projectResolver = projectResolver;
43+
private readonly IRazorComponentSearchEngine _componentSearchEngine = componentSearchEngine;
4444
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions;
4545
private readonly IRazorDocumentMappingService _documentMappingService = documentMappingService;
4646

@@ -117,7 +117,7 @@ protected override bool IsSupported()
117117
return null;
118118
}
119119

120-
var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(originTagHelpers.First()).ConfigureAwait(false);
120+
var originComponentDocumentSnapshot = await _componentSearchEngine.TryLocateComponentAsync(documentContext.Snapshot, originTagHelpers.First()).ConfigureAwait(false);
121121
if (originComponentDocumentSnapshot is null)
122122
{
123123
return null;
@@ -162,7 +162,7 @@ protected override bool IsSupported()
162162
using var documentSnapshots = new PooledArrayBuilder<IDocumentSnapshot?>();
163163
using var _ = StringHashSetPool.GetPooledObject(out var documentPaths);
164164

165-
var projects = _projectManager.GetProjects();
165+
var projects = _projectResolver.EnumerateProjects(skipDocumentContext.Snapshot);
166166

167167
foreach (var project in projects)
168168
{
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT license. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
6+
7+
namespace Microsoft.CodeAnalysis.Razor.Workspaces;
8+
9+
internal interface IProjectCollectionResolver
10+
{
11+
IEnumerable<IProjectSnapshot> EnumerateProjects(IDocumentSnapshot snapshot);
12+
}

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorComponentSearchEngine.cs renamed to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
using Microsoft.AspNetCore.Razor.Language;
66
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
77

8-
namespace Microsoft.AspNetCore.Razor.LanguageServer;
8+
namespace Microsoft.CodeAnalysis.Razor.Workspaces;
99

10-
internal abstract class RazorComponentSearchEngine
10+
internal interface IRazorComponentSearchEngine
1111
{
12-
public abstract Task<IDocumentSnapshot?> TryLocateComponentAsync(TagHelperDescriptor tagHelper);
12+
Task<IDocumentSnapshot?> TryLocateComponentAsync(IDocumentSnapshot contextSnapshot, TagHelperDescriptor tagHelper);
1313
}
Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
using Microsoft.CodeAnalysis.Razor.Logging;
88
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
99

10-
namespace Microsoft.AspNetCore.Razor.LanguageServer;
10+
namespace Microsoft.CodeAnalysis.Razor.Workspaces;
1111

12-
internal class DefaultRazorComponentSearchEngine(
13-
IProjectSnapshotManager projectManager,
12+
internal class RazorComponentSearchEngine(
13+
IProjectCollectionResolver projectCollectionResolver,
1414
ILoggerFactory loggerFactory)
15-
: RazorComponentSearchEngine
15+
: IRazorComponentSearchEngine
1616
{
17-
private readonly IProjectSnapshotManager _projectManager = projectManager;
18-
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<DefaultRazorComponentSearchEngine>();
17+
private readonly IProjectCollectionResolver _projectResolver = projectCollectionResolver;
18+
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<RazorComponentSearchEngine>();
1919

2020
/// <summary>Search for a component in a project based on its tag name and fully qualified name.</summary>
2121
/// <remarks>
@@ -24,10 +24,11 @@ internal class DefaultRazorComponentSearchEngine(
2424
/// component is present in has the same name as the assembly its corresponding tag helper is loaded from.
2525
/// Implicitly, this method inherits any assumptions made by TrySplitNamespaceAndType.
2626
/// </remarks>
27+
/// <param name="contextSnapshot">A document snapshot that provides context to enumerate project snapshots</param>
2728
/// <param name="tagHelper">A TagHelperDescriptor to find the corresponding Razor component for.</param>
2829
/// <returns>The corresponding DocumentSnapshot if found, null otherwise.</returns>
2930
/// <exception cref="ArgumentNullException">Thrown if <paramref name="tagHelper"/> is null.</exception>
30-
public override async Task<IDocumentSnapshot?> TryLocateComponentAsync(TagHelperDescriptor tagHelper)
31+
public async Task<IDocumentSnapshot?> TryLocateComponentAsync(IDocumentSnapshot contextSnapshot, TagHelperDescriptor tagHelper)
3132
{
3233
if (tagHelper is null)
3334
{
@@ -44,7 +45,7 @@ internal class DefaultRazorComponentSearchEngine(
4445

4546
var lookupSymbolName = RemoveGenericContent(typeName.AsMemory());
4647

47-
var projects = _projectManager.GetProjects();
48+
var projects = _projectResolver.EnumerateProjects(contextSnapshot);
4849

4950
foreach (var project in projects)
5051
{
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT license. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using System.Composition;
6+
using System.Diagnostics;
7+
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
8+
using Microsoft.CodeAnalysis.Razor.Workspaces;
9+
10+
namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem;
11+
12+
[Export(typeof(IProjectCollectionResolver)), Shared]
13+
[method: ImportingConstructor]
14+
internal class RemoteProjectCollectionResolver(ProjectSnapshotFactory projectSnapshotFactory) : IProjectCollectionResolver
15+
{
16+
public IEnumerable<IProjectSnapshot> EnumerateProjects(IDocumentSnapshot snapshot)
17+
{
18+
Debug.Assert(snapshot is RemoteDocumentSnapshot);
19+
20+
var projects = ((RemoteDocumentSnapshot)snapshot).TextDocument.Project.Solution.Projects;
21+
22+
foreach (var project in projects)
23+
{
24+
yield return projectSnapshotFactory.GetOrCreate(project);
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)