Index Razor views and Blazor components - #117
Open
grinidx wants to merge 1 commit into
Open
Conversation
Razor views (.cshtml) and Blazor components (.razor) never reach the compiler as files, the Razor source generator feeds them to it, so project.Documents does not see them and they are missing from the index. Enumerate the source generated documents as well, and follow the #line directives that the generator emits so that each occurrence is reported against the .cshtml or .razor file it was written in rather than against the generated C# under obj/, which usually does not exist on disk.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #61.
The problem
ScipProjectIndexeriteratesproject.Documents, which is the set of files the compiler reads from disk. Razor views (.cshtml) and Blazor components (.razor) never reach the compiler that way. The Razor source generator turns them into C# and hands them straight to the compilation, so they live behindProject.GetSourceGeneratedDocumentsAsyncand the indexer has never seen them.Measured on freshly scaffolded apps against
mainat 4788446:dotnet new webappdotnet new blazor.cshtml.razorindex.scipOn #61 the reply was "Razor templates don't seem to be supported, Blazor should be supported. If you have an example of it not working, please provide a reproducer." The second column is that reproducer: a stock
dotnet new blazoryields zero.razordocuments today. Steps to reproduce are in the linked write-up.That thread also said "We'll be happy to review a PR adding this feature", which is what this is.
Why the obvious fix is not enough
Adding the source-generated documents to the existing loop produces an index full of paths like
which do not exist on disk unless
EmitCompilerGeneratedFilesis set, are excluded the moment anyone passes--exclude '**/obj/**', and mix generated boilerplate in with the developer's code.What this does
IndexSourceGeneratedDocumentsenumerates the generated documents per project and, for each, usesSyntaxTree.GetLineMappingsto find which real files its#linedirectives point at. One SCIPDocumentis created per original file, and--include/--excludeare matched against that path.ScipDocumentIndexertakes an optionaloriginalFilePathand records only the occurrences whoseGetMappedLineSpan().Pathmatches it, so generated boilerplate is dropped and the developer's code keeps the line and column numbers it has in the.cshtml.LocationToRangealready calledGetMappedLineSpan, so the ranges were always correct once the document was.RemoveDuplicatescollapses identical occurrences, which is needed because_ViewImports.cshtmland_Imports.razorare folded into the generated file of every view that inherits them.Result on the same two apps: 6
.cshtmldocuments with 17 occurrences, and 11.razordocuments with 153 occurrences. The seventh.cshtml,_ValidationScriptsPartial.cshtml, contains no C#, so there is nothing in it to index. No measurable change in indexing time.Tests
A new snapshot fixture,
snapshots/input/razor, covering a Razor Page with@model,@functionsand inline expressions, a_ViewImports.cshtml, a Blazor component with@code, and an_Imports.razor, with expected output for net8.0, net9.0 and net10.0.SnapshotTestspreviously only compared expected-output files ending in.cs, so Razor snapshots would have been written and never asserted on.IsSnapshotFilewidens that to.cshtmland.razor.All existing snapshots are byte-identical after the change on all three target frameworks, and
dotnet format --verify-no-changesis clean.Provenance and licensing
This came out of vela, a local code index for .NET that reached the same conclusion independently and has been running the source-generated-document approach against a 375,608-line solution with 307 Razor views. The full working notes, including the measurements above and how to reproduce them, are at docs/upstream/scip-dotnet-razor.md.
The approach was reimplemented for this codebase rather than copied: vela is MIT, scip-dotnet is Apache 2.0, and this contribution is offered under Apache 2.0 on the inbound-equals-outbound terms in section 5 of that licence.
What has not been checked
Only exercised on Linux. The CI matrix also covers Windows and macOS, where the path comparison in
VisitOccurrenceusesStringComparison.Ordinalagainst a path Roslyn produced from a#linedirective Roslyn also produced. Both sides originate from the same string, so they should match, but that is reasoning rather than a measurement.No Razor Class Library and no MVC
Views/layout were tested. Razor Pages and Blazor were.