Skip to content

Consume split Razor declarations through pre-compilation source output - #84670

Merged
chsienki merged 8 commits into
dotnet:features/sonicfrom
chsienki:sonic/decl-precomp-sg-consume
Jul 29, 2026
Merged

chsienki merged 8 commits into
dotnet:features/sonicfrom
chsienki:sonic/decl-precomp-sg-consume

Conversation

@chsienki

@chsienki chsienki commented Jul 29, 2026 •

Copy link
Copy Markdown
Member

Builds on the decl/impl split now in features/sonic (#84577, #84605).

What this does

Wires the resolution-independent declaration half of a splittable Razor component through RegisterPreCompilationSourceOutput, so tag-helper discovery runs over the real compilation instead of a separate declaration compilation parsed from generated text. This is the step that unlocks reusing the standard compilation's tag helpers.

Components the markup split can't partition (a header/arity directive like @inherits/@implements/@typeparam, or class-body markup it can't route) still go through the separate declaration engine. To keep their type resolvable in the pre-compilation compilation — so a split component that references one in C# (e.g. [Parameter] public Widget Child) doesn't bind to an error type and fail consumers with CS0246 — the split phase emits a bodiless type shell for them.

Commits

  1. Consume the split declaration through pre-compilation source output — the core rewire: fast/slow tag-helper discovery split, decl #pragma checksum suppression so markup-only edits keep discovery cached, set-based test matching.
  2. Strip the generated-code banner from files a delegated code action creates — cohost fix: generate-type-in-a-new-file no longer copies the // <auto-generated/> banner (from the decl's suppressed-checksum first line) onto authored .cs files.
  3. Emit a type-shell declaration for fallback components — the bodiless type shell (namespace / class / modifiers / type-parameter names only) so fallback types resolve without contributing a discoverable surface.
  4. Add decl-baseline files for fallback component code-generation tests — .decl.codegen.cs / .decl.ir.txt baselines.
  5. Distinguish a fallback type-shell declaration from a real declaration half — RazorCSharpDocument.IsStubDocument, so tooling (diagnostic translation) treats the member-less shell as absent; fixes dropped IDE0005 unused-usings for fallback components.
  6. Add a skipped test for the fallback nested-delegate limitation — a known gap (a delegate nested in a fallback binds to an error type → CS1503), tracked by Razor: split component referencing a fallback component's nested delegate/enum loses metadata (decl/impl split) #84646 and marked PROTOTYPE(sonic) so it can't reach main unfixed.

Testing

  • Razor SG unit suite: 218 passed / 1 skipped (net10.0).
  • Cohost pull-diagnostics: 19/19.
  • Each commit builds in isolation (bisect-safe).

Known follow-ups

Microsoft Reviewers: Open in CodeFlow

chsienki and others added 6 commits July 28, 2026 18:07
Emit the resolution-independent declaration half of a splittable Razor
component via RegisterPreCompilationSourceOutput so it lands in the
compilation that tag-helper discovery reads. Discovery runs over the real
compilation instead of a separate declaration compilation parsed from
generated text, which is the step that unlocks reusing the standard
compilation's tag helpers.

- A component the split can partition contributes its decl through the
  pre-compilation output; that decl is visible to tag-helper discovery and
  is compiled into the output as the decl partial alongside the impl partial.
- A component the split cannot partition has no main-run decl, so the
  separate declaration engine produces a discovery-only decl for it. Fast
  discovery covers the standard compilation (split decls plus user types);
  slow discovery runs only when something falls back, augmenting the
  compilation with the fallback decl trees and keeping just the fallback
  types. The two are merged, with fallback types excluded from fast
  discovery so a type that is also a compilation partial isn't discovered
  twice or with an incomplete partial-only descriptor.
- The decl half suppresses its #pragma checksum so a markup-only edit leaves
  the decl SourceText byte-identical: discovery stays cached and the decl
  stays out of the pre-compilation compilation delta. The impl half keeps
  its checksum for the debugger.
- Decl diagnostics flow through the implementation-time output, since the
  pre-compilation output runs before the compilation exists.

Tests match generated sources as a set rather than by position (decls and
impls arrive through separate outputs) and follow the renamed incremental
steps (DeclSources, FastTagHelpers).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c45f67d5-6fe0-4f6b-8c68-c268dc7c0621
…eates

Generate-type-in-a-new-file copies the triggering document's file banner into
the new file. Triggered from a Razor component's split declaration document --
whose first line is "// <auto-generated/>" because the decl suppresses its
#pragma checksum -- that puts the auto-generated banner on the user's new .cs
file, which is authored code, not generated.

The delegated C# code action resolver drops a leading auto-generated comment
from files the action creates, keeping authored files free of the marker while
leaving the generated documents themselves untouched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c45f67d5-6fe0-4f6b-8c68-c268dc7c0621
A component the markup split can't partition -- one with a header/arity
directive (@inherits/@implements/@typeparam) or class-body markup it can't
route -- has its tag-helper descriptor produced by the separate declaration
engine rather than read from the pre-compilation compilation. That
compilation therefore omits the fallback component's type, so a split
component that references it in C# (e.g. [Parameter] public Widget Child)
binds to an error type and records an unqualified name, which breaks
consumers with CS0246 when they don't import the fallback's namespace.

To make the type resolve, the split phase emits a bodiless type shell for
such a component: the namespace, class name, modifiers, and type-parameter
names only -- no base type, interfaces, members, or constraints. Routed
through pre-compilation output, it lets the fallback type (and its nested
types, which qualify from the resolved outer type) resolve, so references
record a fully-qualified name. Carrying no base, the shell is not a
component, so tag-helper discovery ignores it and the declaration engine
owns its complete descriptor; as a member-less partial it rejoins the
emitted impl cleanly.

A non-null FallbackComponentTypeName on the document node routes a component
to the declaration engine. It is a separate signal from the shell because an
unsplit component with a primary class also produces a (shell) declaration,
so a declaration's presence does not by itself distinguish a split component
from a fallback one. A component with no primary class or a suppressed body
carries the type name without a shell -- it has no distinct type to declare.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c45f67d5-6fe0-4f6b-8c68-c268dc7c0621
A fallback component emits a bodiless type-shell declaration document, so
each component code-generation integration test that exercises one gains a
declaration baseline (.decl.codegen.cs and .decl.ir.txt). The impl baselines
are unchanged; these files are produced via GenerateBaselines.ShouldGenerate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c45f67d5-6fe0-4f6b-8c68-c268dc7c0621
… half

A fallback component emits a bodiless "type shell" declaration document so
its type still resolves in the pre-compilation compilation. That shell is a
non-null RazorCSharpDocument that carries no members or using directives, so
tooling which treats any non-null declaration document as the component's
full declaration surface is misled by it.

Mark the shell with RazorCSharpDocument.IsStubDocument, threaded from the
split phase (DocumentIntermediateNode.IsStubDeclaration) through declaration
lowering. Diagnostic translation treats a stub as absent: unused-using
(IDE0005) diagnostics for a fallback component now come from the
implementation document unfiltered, instead of being filtered against the
shell's empty using set -- which dropped every genuinely-unused using.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c45f67d5-6fe0-4f6b-8c68-c268dc7c0621
The decl/impl split lowers a fallback component to a bodiless type shell in the
pre-compilation compilation, so a split component whose [Parameter] type is a
delegate nested in that fallback binds to an error type during discovery.
@bind-Value then lowers as an EventCallback and the consumer fails with CS1503.

Capture the scenario as a skipped test alongside the other @Bind coverage so the
gap stays discoverable and the eventual fix has a ready regression guard. Tracked
by dotnet#84646.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c45f67d5-6fe0-4f6b-8c68-c268dc7c0621
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@chsienki
chsienki marked this pull request as ready for review July 29, 2026 01:14
@chsienki
chsienki requested a review from a team as a code owner July 29, 2026 01:14
Copilot AI review requested due to automatic review settings July 29, 2026 01:14
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Wires Razor component declaration halves into the source generator’s pre-compilation output (so tag-helper discovery runs over the real compilation), adds a stub (“type shell”) decl document for fallback components so their types resolve during pre-compilation, and updates cohost diagnostics/code actions plus generator tests/baselines accordingly.

Changes:

  • Emit split component decl sources via RegisterPreCompilationSourceOutput and split tag-helper discovery into fast/slow paths (slow only for fallback components).
  • Introduce fallback component stub decl documents (RazorCSharpDocument.IsStubDocument) and adjust diagnostics translation/filtering behavior accordingly.
  • Update cohost C# code action resolution to strip the generated banner from newly-created authored .cs files; refresh/extend SG and integration test baselines for decl outputs.

Reviewed changes

Copilot reviewed 89 out of 89 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Razor/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.UnitTests/Endpoints/CohostDocumentPullDiagnosticsTest.cs Adds regression coverage for unused-usings on fallback components where the decl is a stub.
src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Diagnostics/RazorTranslateDiagnosticsService.cs Treats stub decl documents as “absent” to avoid dropping real impl diagnostics (notably unused-usings).
src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/CodeActions/CSharp/CSharpCodeActionResolver.cs Strips // <auto-generated/> banner from files created by delegated Roslyn code actions.
src/Razor/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.UnitTests/TestFiles/RazorSourceGeneratorComponentTests/Inject/Shared/Component1_razor.decl.g.cs New decl baseline output for a component (decl emitted separately from impl).
src/Razor/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.UnitTests/RazorSourceGeneratorTestsBase.cs Makes generated source verification order-independent; relaxes checksum trimming to support decl outputs without checksum.
src/Razor/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.UnitTests/RazorSourceGeneratorTests.cs Updates incremental-step tracking names/expectations for fast discovery and decl pre-comp output.
src/Razor/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.UnitTests/RazorSourceGeneratorTagHelperTests.cs Adjusts expected generated source counts when fallback components now produce stub decl + impl.
src/Razor/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.UnitTests/RazorSourceGeneratorComponentTests.cs Updates expected counts and adds a skipped regression test documenting a known fallback nested-delegate limitation.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.Helpers.cs Adds helper to strip generic arity from descriptor type names for fallback matching.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/SourceGenerators/RazorSourceGenerator.cs Rewires decl emission via pre-compilation output; introduces fast/slow tag-helper discovery and fallback filtering.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCSharpDocumentWriter.cs Threads a new isStubDocument flag into RazorCSharpDocument construction.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCSharpDocument.cs Adds IsStubDocument metadata to distinguish stub decl shells from real decl halves.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/DocumentIntermediateNode.cs Extends IR to carry fallback component type name and clarifies decl node semantics (full decl vs stub shell).
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorMarkupSplitPhase.cs Routes unsplittable components to fallback discovery and emits a stub decl shell for type resolution.
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorDeclCSharpLoweringPhase.cs Marks fallback decl outputs as stub documents for downstream tooling decisions.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/RenderMode_With_TypeInference/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/RenderMode_With_TypeInference/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/RenderMode_Directive_WithTypeParam_Razor9/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/RenderMode_Directive_WithTypeParam_Razor9/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/InjectDirective/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/InjectDirective/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/InheritsDirective/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/InheritsDirective/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/InheritsDirective_NullableReferenceType/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/InheritsDirective_NullableReferenceType/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/InheritsDirective_NullableReferenceType_NullableDisabled/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/InheritsDirective_NullableReferenceType_NullableDisabled/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeUsageWithInference/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeUsageWithInference/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeUsageWithGenericType/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeUsageWithGenericType/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeUsageWhitespace/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeUsageWhitespace/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeUsage/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeUsage/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeParamUsageWithImplicitExpression2/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeParamUsageWithImplicitExpression2/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeParamUsageWithImplicitExpression/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentTypeParamUsageWithImplicitExpression/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentMultipleTypeParamUsage/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentMultipleTypeParamUsage/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_InferredType_WithGetSet_Function/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_InferredType_WithGetSet_Function/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_InferredType_WithGetSet_EventCallback/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_InferredType_WithGetSet_EventCallback/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_InferredType_WithGetSet_Action/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_InferredType_WithGetSet_Action/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_InferredType_WithAfter_Action/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_InferredType_WithAfter_Action/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_ExplicitType_WithAfter_Action/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponentBindToGenericComponent_ExplicitType_WithAfter_Action/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponent_GenericEventCallbackWithGenericTypeParameter_NestedTypeInference/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponent_GenericEventCallbackWithGenericTypeParameter_NestedTypeInference/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponent_GenericEventCallbackWithGenericTypeParameter_NestedTypeExplicit/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericComponent_GenericEventCallbackWithGenericTypeParameter_NestedTypeExplicit/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericBindToGenericComponent_ExplicitType_WithGetSet_Function/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericBindToGenericComponent_ExplicitType_WithGetSet_Function/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericBindToGenericComponent_ExplicitType_WithGetSet_EventCallback/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericBindToGenericComponent_ExplicitType_WithGetSet_EventCallback/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericBindToGenericComponent_ExplicitType_WithGetSet_Action/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/GenericBindToGenericComponent_ExplicitType_WithGetSet_Action/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/FormName_Component_Generic/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/FormName_Component_Generic/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/FormName_Component_Generic_RazorLangVersion7/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/FormName_Component_Generic_RazorLangVersion7/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameterValueTupleGloballyQualifiedTypes/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameterValueTupleGloballyQualifiedTypes/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameterValueTuple/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameterValueTuple/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameterValueTuple_ExplicitGenericArguments/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameterValueTuple_ExplicitGenericArguments/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameters/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameters/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameters_WithSemicolon/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameters_WithSemicolon/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameters_Interconnected/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameters_Interconnected/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameterArray/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithTypeParameterArray/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithConstrainedTypeParameters/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithConstrainedTypeParameters/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithConstrainedTypeParameters_WithSemicolon/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/ComponentWithConstrainedTypeParameters_WithSemicolon/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/CanProduceLinePragmasForComponentWithRenderFragment_02/TestComponent.decl.ir.txt New decl IR baseline for stub decl output shape.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentCodeGenerationTest/CanProduceLinePragmasForComponentWithRenderFragment_02/TestComponent.decl.codegen.cs New decl codegen baseline for stub decl output shape.

The four-line comment between the test signature and the `=>` arrow was
indented one column too far, which the analyzer-enforced IDE0055 formatting
leg rejects even though a plain Debug build does not run it. Re-indent it to
the arrow continuation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c45f67d5-6fe0-4f6b-8c68-c268dc7c0621
Copilot AI review requested due to automatic review settings July 29, 2026 01:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 89 out of 89 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorMarkupSplitPhase.cs:56

  • RouteToFallbackDiscovery assumes primaryClass is non-null, but this method calls it even when FindPrimaryClass()/FindPrimaryMethod()/FindPrimaryNamespace() returned null. That will hit Debug.Assert and then throw NullReferenceException when computing FallbackComponentTypeName (primaryClass.Name) in release builds. Consider preserving the prior behavior (return codeDocument) when primaryClass is null, and only routing to fallback discovery when a primary class exists.
    src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/CodeActions/CSharp/CSharpCodeActionResolver.cs:148
  • TryRemoveLeadingAutoGeneratedComment won’t strip the banner if the inserted text starts with a UTF-8 BOM (\uFEFF). The generated decl sources in this PR start with "// ", and Roslyn’s new-file text may include the BOM too, so the StartsWith("//") check can fail and the banner won’t be removed.
    src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorMarkupSplitPhase.cs:113
  • This comment states that the type shell makes nested types resolve, but the shell only declares the outer partial class. Nested types declared in the fallback component’s Razor code are not present in the pre-compilation compilation, so references like Widget.MyHandler still bind as error types (see the skipped test added in this PR). Suggest adjusting the comment to avoid claiming nested-type resolution.

// document's file banner into the new file. When the trigger is a Razor component's generated
// C#, that banner is "// <auto-generated/>" -- correct for the generated document, but it must
// not be written onto the user's authored file, so it is stripped below.
var createdFileUris = new HashSet<DocumentUri>();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: Pool

return codeAction;
}

// Removes a leading "// <auto-generated/>" banner that Roslyn copied from a Razor component's

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's interesting that this started breaking now, but thanks for fixing regardless :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The decl half now suppresses its #pragma checksum which leaves // <auto-generated/> as the literal first line of the decl document, which lead to the need to strip it.

Three follow-up fixes in the component split and cohost code-action paths:

- The markup split routes a component with no classified primary class to
  fallback discovery, which dereferences the class name to build the discovery
  key; with Debug.Assert compiled out (Release) that is a NullReferenceException.
  Return the document unchanged when there is no primary class -- there is no
  component type to discover or to split.

- The delegated code-action banner strip matches "//" after TrimStart(), but
  TrimStart() does not treat a leading UTF-8 BOM (U+FEFF) as whitespace, so a
  BOM-prefixed generated banner would be left on the newly created file. Strip
  a leading BOM before the check.

- Use a pooled HashSet for the created-file URI set instead of allocating one.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c45f67d5-6fe0-4f6b-8c68-c268dc7c0621

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 89 out of 89 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/CodeActions/CSharp/CSharpCodeActionResolver.cs:139

  • RemoveGeneratedCodeBanner currently rewrites NewText for every edit in a newly-created file, regardless of where the edit applies. If Roslyn ever returns multiple edits for a create-file operation, this can end up stripping an "" comment that is not actually the file banner (i.e., not inserted at position 0,0). Consider restricting this to edits whose range starts at the beginning of the document (and ideally only insertion edits at 0,0).
    src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorMarkupSplitPhase.cs:123
  • The comment on BuildStubDeclDocument claims the shell makes nested types resolve, but the stub decl intentionally does not include nested type declarations. For nested types declared only in the fallback component’s implementation, they will still be absent from the pre-compilation compilation. The comment should be adjusted to avoid implying nested types are covered by the shell.
    src/Razor/src/Compiler/test/Microsoft.NET.Sdk.Razor.SourceGenerators.UnitTests/RazorSourceGeneratorTestsBase.cs:518
  • VerifyPageOutput’s set-based matching uses CollapseWhitespace, but AssertEx.AssertEqualToleratingWhitespaceDifferences uses a different normalization (NormalizeWhitespace trims each line, drops empty lines, and adds indentation based on braces). This can prevent a true match from being found when ordering differs, and then the fallback positional assertion compares against the wrong GeneratedSourceResult. The normalization used for matching should mirror AssertEx.NormalizeWhitespace semantics.
    src/Razor/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/CodeActions/CSharp/CSharpCodeActionResolver.cs:149
  • TryRemoveLeadingAutoGeneratedComment trims all leading whitespace before checking for "// <auto-generated...". That’s inconsistent with the comment (“banner at the very start”) and can make the check succeed even when the inserted text doesn’t start with "//". If the intent is just to handle a leading BOM, consider stripping only U+FEFF and otherwise requiring "//" at the start.

@chsienki
chsienki merged commit c65021c into dotnet:features/sonic Jul 29, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants