Skip to content

Fix RestrictChildren incorrectly flagging valid child tags - #84870

Merged
davidwengier merged 5 commits into
dotnet:mainfrom
davidwengier:investigate-sdk-feedback-3047155
Aug 13, 2026
Merged

davidwengier merged 5 commits into
dotnet:mainfrom
davidwengier:investigate-sdk-feedback-3047155

Conversation

@davidwengier

@davidwengier davidwengier commented Aug 12, 2026 •

Copy link
Copy Markdown
Member

Fixes dotnet/razor#13219

Microsoft Reviewers: Open in CodeFlow

davidwengier and others added 3 commits August 13, 2026 07:52
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cfc3366c-dc5a-4eed-8937-2c351f70533d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cfc3366c-dc5a-4eed-8937-2c351f70533d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cfc3366c-dc5a-4eed-8937-2c351f70533d
Copilot AI lite review requested due to automatic review settings August 12, 2026 22:24
@davidwengier
davidwengier requested a review from a team as a code owner August 12, 2026 22:24
@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

This pull request addresses dotnet/razor#13219 by adjusting how RestrictChildren/AllowedChildren constraints are validated during tag helper resolution so valid child tags aren’t incorrectly flagged after legacy resolution flattens unmatched elements into HTML content.

Changes:

  • Moves AllowedChildren validation earlier in DefaultTagHelperResolutionPhase (before unresolved children are resolved/flattened), and extends validation to understand UnresolvedElementIntermediateNode children.
  • Uses the TagHelperBinder during validation to recognize when a prefixed unresolved element would bind as a tag helper (so the prefix can be stripped for AllowedChildren comparisons).
  • Adds/extends integration tests to cover non-tag content and the reported regression scenario.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultTagHelperResolutionPhase.cs Validates AllowedChildren before child resolution and adds unresolved-element handling using the binder to preserve tag names for correct RestrictChildren behavior.
src/Razor/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorIntermediateNodeLoweringPhaseIntegrationTest.cs Adds integration coverage for RZ2009/RZ2010 and a WorkItem regression test ensuring allowed markup children don’t produce diagnostics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: cfc3366c-dc5a-4eed-8937-2c351f70533d
Copilot AI review requested due to automatic review settings August 12, 2026 23:14

// Assert
var diagnostic = Assert.Single(documentNode.GetAllDiagnostics());
Assert.Equal("RZ2010", diagnostic.Id);

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.

This used to report RZ2009 (invalid non-tag content), but now reports RZ2010 (invalid child tag) which seems more appropriate, since its the div that is wrong.

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 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultTagHelperResolutionPhase.cs:546

  • prefix + parentTagName is concatenated inside the per-child loop, creating a new string allocation each time we need to check whether a prefixed unresolved child would bind as a tag helper. Since parentTagName is constant for this validation pass, precompute the prefixed parent tag name once outside the loop and reuse it in the binder lookup to avoid repeated allocations in a hot compilation path.
                    binder.GetBinding(
                        childTagName,
                        unresolvedElement.AttributeData,
                        prefix + parentTagName,
                        parentIsTagHelper: true) != null)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cfc3366c-dc5a-4eed-8937-2c351f70533d
Copilot AI review requested due to automatic review settings August 13, 2026 02:02

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 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Razor/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultTagHelperResolutionPhase.cs:345

  • Allowed-children validation now runs (1) once before the reverse walk, and (2) per original UnresolvedElementIntermediateNode after ResolveElement. If ResolveElement resolves a StartTagOnly tag helper, it can promote parsed body content into parent.Children as new siblings (see the StartTagOnly promotion logic in ResolveElement). Those newly inserted siblings are added after the current index while this loop is iterating backwards, so they won’t be visited/validated here, and they also weren’t present during the initial ValidateAllowedChildren pre-pass. This can allow invalid direct children to slip through (or miss RZ2009/RZ2010) when StartTagOnly promotion occurs under an AllowedChildTags constraint.

Consider adding a validation step for any siblings inserted by StartTagOnly promotion (e.g., detect resolvedTagHelper.TagMode == TagMode.StartTagOnly and validate the promoted range), or restructure the logic so all final direct children are validated without reintroducing the original false-positive issue for flattened plain-HTML elements.

                var resolvedTagHelper = ResolveElement(
                    parent, i, elementNode, binder, prefix, usedHelpers, in context, tagHelperParent);

                if (allowedChildrenString != null)

@davidwengier
davidwengier merged commit f5aee94 into dotnet:main Aug 13, 2026
27 checks passed
@davidwengier
davidwengier deleted the investigate-sdk-feedback-3047155 branch August 13, 2026 21:46
@jjonescz jjonescz added this to the 18.11 milestone Aug 25, 2026
@davidwengier

Copy link
Copy Markdown
Member Author

/backport to release/10.0.4xx

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0.4xx (link to workflow run)

davidwengier added a commit that referenced this pull request Aug 27, 2026
…ild tags (#85060)

Backport of #84870 to release/10.0.4xx

/cc @davidwengier

## Customer Impact

Razor compiler errors in files that previously worked with earlier SDK
versions

## Regression

- [x] Yes
- [ ] No

Yes, this was a regression from the rewrite of tag helper resolution
into a two-stage approach, to separate resolution from lowering, in
dotnet/razor#12957

## Testing

Verified with specific regression tests. It was missed due to
historically low test coverage for the variety of Razor language/runtime
features.

## Risk

Low. The fix builds on previous work for another similar regression
caused by the same work, and is ultimately just a re-ordering of
diagnostic reporting, not a fundamental compiler change.

###### Microsoft Reviewers: [Open in
CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/dotnet/roslyn/pull/85060)
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.

Razor RZ2009 error for valid markup when using [RestrictChildren] after updating to 18.9.0

4 participants