Skip to content

Commit af94f21

Browse files
chsienkiCopilot
authored andcommitted
Add failing test for ArgumentOutOfRangeException in tag helper resolution
When an orphan end tag (e.g. </input> without a matching start tag) immediately follows HTML text content and the tag name matches a legacy tag helper, DefaultTagHelperResolutionPhase throws ArgumentOutOfRangeException. Root cause: the legacy resolver's ConvertToPlainElement removes the wrapper at parent.Children[index], inserts the lowered HTML for the orphan end tag, then calls MergeAdjacentHtmlContent, which merges those tokens into the preceding text sibling and removes one item from parent.Children. The caller then indexes parent.Children[index] using the now-stale index. This is the same class of bug fixed by PR #83516, just in a different code path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8086386 commit af94f21

1 file changed

Lines changed: 39 additions & 0 deletions

File tree

src/Compiler/Microsoft.AspNetCore.Razor.Language/test/DefaultRazorTagHelperBinderPhaseTest.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,45 @@ public void Execute_CombinesErrorsOnRewritingErrors()
495495
Assert.Equal<RazorDiagnostic>([initialError, expectedRewritingError], outputTree.Diagnostics);
496496
}
497497

498+
[Theory]
499+
[InlineData("Hello</input>")]
500+
[InlineData("Hello</input")]
501+
[InlineData("text content</form>")]
502+
[InlineData("foo</p>")]
503+
public void Execute_OrphanEndTagAfterText_DoesNotThrow(string content)
504+
{
505+
var formTagHelper = CreateTagHelperDescriptor(
506+
tagName: "form",
507+
typeName: "TestFormTagHelper",
508+
assemblyName: "TestAssembly");
509+
var inputTagHelper = CreateTagHelperDescriptor(
510+
tagName: "input",
511+
typeName: "TestInputTagHelper",
512+
assemblyName: "TestAssembly");
513+
var pTagHelper = TagHelperDescriptorBuilder.CreateTagHelper("pTagHelper", "TestAssembly")
514+
.TagMatchingRuleDescriptor(rule =>
515+
rule
516+
.RequireTagName("p")
517+
.RequireAttributeDescriptor(attribute => attribute.Name("class")))
518+
.Build();
519+
520+
var projectEngine = RazorProjectEngine.Create(builder =>
521+
{
522+
builder.SetTagHelpers(formTagHelper, inputTagHelper, pTagHelper);
523+
});
524+
525+
var source = TestRazorSourceDocument.Create("@addTagHelper *, TestAssembly\r\n" + content, filePath: null);
526+
var codeDocument = projectEngine.CreateCodeDocument(source);
527+
var originalTree = RazorSyntaxTree.Parse(source);
528+
codeDocument = codeDocument.WithSyntaxTree(originalTree);
529+
530+
codeDocument = projectEngine.ExecutePhase<DefaultRazorTagHelperContextDiscoveryPhase>(codeDocument);
531+
codeDocument = projectEngine.ExecutePhase<DefaultRazorIntermediateNodeLoweringPhase>(codeDocument);
532+
codeDocument = projectEngine.ExecutePhase<DefaultTagHelperResolutionPhase>(codeDocument);
533+
534+
Assert.NotNull(codeDocument.GetDocumentNode());
535+
}
536+
498537
private static string AssemblyA => "TestAssembly";
499538

500539
private static string AssemblyB => "AnotherAssembly";

0 commit comments

Comments
 (0)