Skip to content

Conversation

@chsienki
Copy link
Member

@chsienki chsienki commented Jun 6, 2025

Part of #76868

This removes the special casing in ProjectSystemProject for the razor compiler. Instead, we make use of the IAnalyzerAssemblyRedirector interface to provide a component via MEF that handles the redirection. That interface isn't public, so we expose an interface via the Razor EA that allows razor to provide the redirection.

This works for both VS and VS Code, which means it is no longer necessary to pass in the path the razor source generator in VS Code, nor to provide a HostDiagnosticAnalyzerProvider that passes the razor compiler to the project system.

The razor side is waiting on this PR to be able to make use of the new EA interface, but a dual insertion isn't strictly necessary. For the period when this goes in, but razor hasn't yet updated, there will be no redirection (the generator will load from the SDK instead), but things will still work. The plan is to get the razor side in before this change ships to any customers, so there shouldn't be any time where a publicly available build has no redirection.

There is also a small piece in the C# extension where we pass the razor source generator path. We need to keep the argument here until we update that codebase not to pass it.

- Remove the special casing for razor in projectsystemproject
- Remove HostDiagnosticAnalyzerProvider as it is no longer needed
- Add an EA redirector that razor can implement
- MEF import the redirectors where needed
- Remove RazorSourceGenerator option from language server
@chsienki chsienki force-pushed the razor_assembly_redirector branch from ad2e8df to bd3fb8f Compare June 9, 2025 20:44
@chsienki chsienki marked this pull request as ready for review June 13, 2025 18:10
@chsienki chsienki requested a review from a team as a code owner June 13, 2025 18:10
chsienki added 2 commits June 13, 2025 11:39
- The VS Code C# extension is still passing the argument and we error if we get an unrecognized option. We can remove this once we update the C# side.
@chsienki chsienki requested a review from a team as a code owner June 13, 2025 19:37
var sessionId = parseResult.GetValue(sessionIdOption);
var extensionAssemblyPaths = parseResult.GetValue(extensionAssemblyPathsOption) ?? [];
var devKitDependencyPath = parseResult.GetValue(devKitDependencyPathOption);
var razorSourceGenerator = parseResult.GetValue(razorSourceGeneratorOption);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is the option we need to keep as you say in the PR's description. Consider adding a comment near the option definition.

@jaredpar jaredpar self-assigned this Jun 17, 2025
[Export(typeof(IAnalyzerAssemblyRedirector)), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class RazorAnalyzerAssemblyRedirector([Import(AllowDefault = true)] RazorAnalyzerAssemblyRedirector.IRazorAnalyzerAssemblyRedirector? razorRedirector = null) : IAnalyzerAssemblyRedirector
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Line is getting a little long here and wrapping, consider breaking it up a bit.

Path.Combine(TempRoot.Root, "Dir", "File.dll")
}, environment.Workspace.CurrentSolution.Projects.Single().AnalyzerReferences.Select(Function(r) r.FullPath))
End Using
End Function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit worried about the drop in test coverage. Will we get this covered in the razor side of the change?

Copy link
Member Author

@chsienki chsienki Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This test is literally checking that if we pass "razorcompiler.dll" to the project system we redirect it. We no longer have that logic hard coded into the project system, so can't really test it.

I did start making a test with a TestRazorRedirector injected, but then all its really testing is the test redirector, so it doesn't actually provide any value.

Testing that redirection works in general is covered already by RedirectedAnalyzers_CSharp

Copy link
Member

@dibarbet dibarbet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one part got deleted that I don't think should be

await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken);
_visualStudioWorkspaceImpl.Services.GetRequiredService<VisualStudioMetadataReferenceManager>();

_visualStudioWorkspaceImpl.SubscribeExternalErrorDiagnosticUpdateSourceToSolutionBuildEvents();
Copy link
Member

@dibarbet dibarbet Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these should be deleted. This is for listening to build events for legacy project system build diagnostics so we can push them to the error list (long story).

I'm not sure about VisualStudioMetadataReferenceManager, but I also don't think it should necessarily be deleted either.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I hadn't realized that there was other stuff going on in that initializer other than getting the analyzer provider factory. I've restored the original logic and just removed the return for the provider.

Not sure if CreateAndAddToWorkspaceAsync needs to wait until the init task is finished so I've added it back just in case.

Copy link
Member

@jasonmalinowski jasonmalinowski Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't quite catch the history of this, but this final form looks correct. We do expect the other stuff to run before the first load of a project or otherwise I think metadata reference reading might fail in bad ways.


// HACK: Fetch this service to ensure it's still created on the UI thread; once this is
// moved off we'll need to fix up it's constructor to be free-threaded.
_threadingContext.JoinableTaskFactory.RunAsync(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tagging @jasonmalinowski - do we still need to ensure that CreateAndAddToWorkspace awaits the result of this? e..g for the VisualStudioMetadataReferenceManager part?

If we don't need to await, this should likely be tracked with a ReportNonFatal continuation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, you reviewed quicker than I could update the code and force pushed with the await also replaced.

@chsienki chsienki force-pushed the razor_assembly_redirector branch from e750196 to 420044c Compare June 17, 2025 21:34
@chsienki chsienki force-pushed the razor_assembly_redirector branch from 420044c to fe5a33a Compare June 17, 2025 21:37
@chsienki
Copy link
Member Author

Val build here https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequest/644653 passing since I restored the deleted code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants