Skip to content

Commit e23e91d

Browse files
committed
Separate out razor redirection:
- Razor is not going to be listed as an analyzer anymore - Add a version of the extension loading logic that loads the razor specified files in the razor VSIX - Add tests
1 parent 453c711 commit e23e91d

File tree

5 files changed

+44
-46
lines changed

5 files changed

+44
-46
lines changed

src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/HostDiagnosticAnalyzerProvider.cs

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,17 @@
88
using Microsoft.CodeAnalysis.Workspaces.ProjectSystem;
99

1010
namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace;
11-
internal sealed class HostDiagnosticAnalyzerProvider : IHostDiagnosticAnalyzerProvider
12-
{
13-
14-
private readonly ImmutableArray<(AnalyzerFileReference reference, string extensionId)> _analyzerReferences;
1511

16-
public HostDiagnosticAnalyzerProvider(string? razorSourceGenerator)
17-
{
18-
if (razorSourceGenerator == null || !File.Exists(razorSourceGenerator))
19-
{
20-
_analyzerReferences = [];
21-
}
22-
else
23-
{
24-
_analyzerReferences = [(
25-
new AnalyzerFileReference(razorSourceGenerator, new SimpleAnalyzerAssemblyLoader()),
26-
ProjectSystemProject.RazorVsixExtensionId
27-
)];
28-
}
29-
}
30-
31-
public ImmutableArray<(AnalyzerFileReference reference, string extensionId)> GetAnalyzerReferencesInExtensions()
32-
{
33-
return _analyzerReferences;
34-
}
12+
internal sealed class HostDiagnosticAnalyzerProvider(string? razorSourceGenerator) : IHostDiagnosticAnalyzerProvider
13+
{
14+
public ImmutableArray<(AnalyzerFileReference reference, string extensionId)> GetAnalyzerReferencesInExtensions() => [];
3515

36-
private sealed class SimpleAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader
16+
public ImmutableArray<(string path, string extensionId)> GetRazorReferencesInExtensions()
3717
{
38-
public void AddDependencyLocation(string fullPath)
39-
{
40-
// This method is used to add a path that should be probed for analyzer dependencies.
41-
// In this simple implementation, we do nothing.
42-
}
43-
44-
public Assembly LoadFromPath(string fullPath)
18+
if (razorSourceGenerator is not null)
4519
{
46-
// This method is used to load an analyzer assembly from the specified path.
47-
// In this simple implementation, we use Assembly.LoadFrom to load the assembly.
48-
return Assembly.LoadFrom(fullPath);
20+
return [(razorSourceGenerator, ProjectSystemProject.RazorVsixExtensionId)];
4921
}
22+
return [];
5023
}
5124
}

src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ internal sealed partial class VisualStudioDiagnosticAnalyzerProvider : IHostDiag
2222
{
2323
private const string AnalyzerContentTypeName = "Microsoft.VisualStudio.Analyzer";
2424

25+
private const string RazorContentTypeName = "Microsoft.VisualStudio.RazorAssembly";
26+
2527
/// <summary>
2628
/// Loader for VSIX-based analyzers.
2729
/// </summary>
@@ -31,6 +33,7 @@ internal sealed partial class VisualStudioDiagnosticAnalyzerProvider : IHostDiag
3133
private readonly Type _typeIExtensionContent;
3234

3335
private readonly Lazy<ImmutableArray<(AnalyzerFileReference reference, string extensionId)>> _lazyAnalyzerReferences;
36+
private readonly Lazy<ImmutableArray<(string path, string extensionId)>> _lazyRazorReferences;
3437

3538
// internal for testing
3639
internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type typeIExtensionContent)
@@ -40,24 +43,28 @@ internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type ty
4043

4144
_extensionManager = extensionManager;
4245
_typeIExtensionContent = typeIExtensionContent;
43-
_lazyAnalyzerReferences = new Lazy<ImmutableArray<(AnalyzerFileReference, string)>>(GetAnalyzerReferencesImpl);
46+
_lazyAnalyzerReferences = new Lazy<ImmutableArray<(AnalyzerFileReference, string)>>(() => GetExtensionContent(AnalyzerContentTypeName).SelectAsArray(c => (new AnalyzerFileReference(c.path, AnalyzerAssemblyLoader), c.extensionId)));
47+
_lazyRazorReferences = new Lazy<ImmutableArray<(string, string)>>(() => GetExtensionContent(RazorContentTypeName));
4448
}
4549

4650
public ImmutableArray<(AnalyzerFileReference reference, string extensionId)> GetAnalyzerReferencesInExtensions()
4751
=> _lazyAnalyzerReferences.Value;
4852

49-
private ImmutableArray<(AnalyzerFileReference reference, string extensionId)> GetAnalyzerReferencesImpl()
53+
public ImmutableArray<(string path, string extensionId)> GetRazorReferencesInExtensions()
54+
=> _lazyRazorReferences.Value;
55+
56+
private ImmutableArray<(string path, string extensionId)> GetExtensionContent(string contentTypeName)
5057
{
5158
try
5259
{
5360
// dynamic is weird. it can't see internal type with public interface even if callee is
5461
// implementation of the public interface in internal type. so we can't use dynamic here
55-
var _ = PooledDictionary<AnalyzerFileReference, string>.GetInstance(out var analyzePaths);
62+
var _ = PooledDictionary<string, string>.GetInstance(out var analyzePaths);
5663

57-
// var enabledExtensions = extensionManager.GetEnabledExtensions(AnalyzerContentTypeName);
64+
// var enabledExtensions = extensionManager.GetEnabledExtensions(contentTypeName);
5865
var extensionManagerType = _extensionManager.GetType();
5966
var extensionManager_GetEnabledExtensionsMethod = extensionManagerType.GetRuntimeMethod("GetEnabledExtensions", [typeof(string)]);
60-
var enabledExtensions = (IEnumerable<object>)extensionManager_GetEnabledExtensionsMethod.Invoke(_extensionManager, [AnalyzerContentTypeName]);
67+
var enabledExtensions = (IEnumerable<object>)extensionManager_GetEnabledExtensionsMethod.Invoke(_extensionManager, [contentTypeName]);
6168

6269
foreach (var extension in enabledExtensions)
6370
{
@@ -73,7 +80,7 @@ internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type ty
7380

7481
foreach (var content in extension_Content)
7582
{
76-
if (!ShouldInclude(content))
83+
if (!ShouldInclude(content, contentTypeName))
7784
{
7885
continue;
7986
}
@@ -85,7 +92,7 @@ internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type ty
8592
continue;
8693
}
8794

88-
analyzePaths.Add(new AnalyzerFileReference(assemblyPath, AnalyzerAssemblyLoader), identifier);
95+
analyzePaths.Add(assemblyPath, identifier);
8996
}
9097
}
9198

@@ -94,7 +101,7 @@ internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type ty
94101
GC.KeepAlive(enabledExtensions);
95102

96103
// Order for deterministic result.
97-
return analyzePaths.OrderBy((x, y) => string.CompareOrdinal(x.Key.FullPath, y.Key.FullPath)).SelectAsArray(entry => (entry.Key, entry.Value));
104+
return analyzePaths.OrderBy((x, y) => string.CompareOrdinal(x.Key, y.Key)).SelectAsArray(entry => (entry.Key, entry.Value));
98105
}
99106
catch (TargetInvocationException ex) when (ex.InnerException is InvalidOperationException)
100107
{
@@ -108,13 +115,13 @@ internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type ty
108115
}
109116
}
110117

111-
private static bool ShouldInclude(object content)
118+
private static bool ShouldInclude(object content, string contentTypeName)
112119
{
113120
// var content_ContentTypeName = content.ContentTypeName;
114121
var contentType = content.GetType();
115122
var contentType_ContentTypeNameProperty = contentType.GetRuntimeProperty("ContentTypeName");
116123
var content_ContentTypeName = contentType_ContentTypeNameProperty.GetValue(content) as string;
117124

118-
return string.Equals(content_ContentTypeName, AnalyzerContentTypeName, StringComparison.InvariantCultureIgnoreCase);
125+
return string.Equals(content_ContentTypeName, contentTypeName, StringComparison.InvariantCultureIgnoreCase);
119126
}
120127
}

src/VisualStudio/Core/Test/Diagnostics/VisualStudioDiagnosticAnalyzerProviderTests.vb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,21 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
6060
Assert.Equal("TestAnalyzer", analyzers(0).ToString)
6161
End Using
6262
End Sub
63+
64+
<Fact>
65+
Public Sub GetRazorReferencesInExtensions()
66+
Dim extensionManager = New VisualStudioDiagnosticAnalyzerProvider(
67+
New MockExtensionManager({({"razorPath1", "razorPath2"}, "RazorVsix")}, contentType:="Microsoft.VisualStudio.RazorAssembly"),
68+
GetType(MockExtensionManager.MockContent))
69+
70+
Dim references = extensionManager.GetRazorReferencesInExtensions()
71+
72+
AssertEx.SetEqual(
73+
{
74+
Path.Combine(TempRoot.Root, "InstallPath\razorPath1"),
75+
Path.Combine(TempRoot.Root, "InstallPath\razorPath2")
76+
},
77+
references.Select(Function(pathAndId) pathAndId.path))
78+
End Sub
6379
End Class
6480
End Namespace

src/Workspaces/Core/Portable/Workspace/ProjectSystem/IHostDiagnosticAnalyzerProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem;
1414
internal interface IHostDiagnosticAnalyzerProvider
1515
{
1616
ImmutableArray<(AnalyzerFileReference reference, string extensionId)> GetAnalyzerReferencesInExtensions();
17+
18+
ImmutableArray<(string path, string extensionId)> GetRazorReferencesInExtensions();
1719
}

src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,9 +1190,9 @@ private OneOrMany<string> GetMappedAnalyzerPaths(string fullPath)
11901190

11911191
private OneOrMany<string> GetMappedRazorSourceGenerator(string fullPath)
11921192
{
1193-
var vsixRazorAnalyzers = _hostInfo.HostDiagnosticAnalyzerProvider.GetAnalyzerReferencesInExtensions().SelectAsArray(
1193+
var vsixRazorAnalyzers = _hostInfo.HostDiagnosticAnalyzerProvider.GetRazorReferencesInExtensions().SelectAsArray(
11941194
predicate: item => item.extensionId == RazorVsixExtensionId,
1195-
selector: item => item.reference.FullPath);
1195+
selector: item => item.path);
11961196

11971197
if (!vsixRazorAnalyzers.IsEmpty)
11981198
{

0 commit comments

Comments
 (0)