From 6a95002f0e2e7e58382087ec87a7e9128aba1577 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Thu, 26 Jan 2017 13:03:18 -0800 Subject: [PATCH] Fix lowering of taghelpers inside a section The IR lowering phase was attaching the 'tag helper fields' node to the builder instead of to the top-level node (document). This meant that things wouldn't be where we expect when the first tag helper occurrence is inside a directive block (section). Found this porting MVC to use the new Razor codebase. --- .../DefaultRazorIRLoweringPhase.cs | 26 +++++----- ...aultRazorIRLoweringPhaseIntegrationTest.cs | 51 +++++++++++++++++++ 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs index eb807681c3..99eae8977f 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution ThrowForMissingDependency(syntaxTree); var builder = RazorIRBuilder.Document(); + var document = (DocumentIRNode)builder.Current; var namespaces = new HashSet(); var i = 0; @@ -40,7 +41,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution var imports = codeDocument.GetImportSyntaxTrees(); if (imports != null) { - var importsVisitor = new ImportsVisitor(builder, namespaces); + var importsVisitor = new ImportsVisitor(document, builder, namespaces); for (var j = 0; j < imports.Count; j++) { @@ -51,24 +52,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution } } - var visitor = new MainSourceVisitor(builder, namespaces) + var visitor = new MainSourceVisitor(document, builder, namespaces) { Filename = syntaxTree.Source.Filename, }; visitor.VisitBlock(syntaxTree.Root); - - var irDocument = (DocumentIRNode)builder.Build(); - codeDocument.SetIRDocument(irDocument); + + codeDocument.SetIRDocument(document); } private class LoweringVisitor : ParserVisitor { protected readonly RazorIRBuilder _builder; + protected readonly DocumentIRNode _document; protected readonly HashSet _namespaces; - public LoweringVisitor(RazorIRBuilder builder, HashSet namespaces) + public LoweringVisitor(DocumentIRNode document, RazorIRBuilder builder, HashSet namespaces) { + _document = document; _builder = builder; _namespaces = namespaces; } @@ -146,8 +148,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution // this simple. private bool _insideLineDirective; - public ImportsVisitor(RazorIRBuilder builder, HashSet namespaces) - : base(builder, namespaces) + public ImportsVisitor(DocumentIRNode document, RazorIRBuilder builder, HashSet namespaces) + : base(document, builder, namespaces) { } @@ -182,8 +184,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution { private DeclareTagHelperFieldsIRNode _tagHelperFields; - public MainSourceVisitor(RazorIRBuilder builder, HashSet namespaces) - : base(builder, namespaces) + public MainSourceVisitor(DocumentIRNode document, RazorIRBuilder builder, HashSet namespaces) + : base(document, builder, namespaces) { } @@ -416,8 +418,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution { if (_tagHelperFields == null) { - _tagHelperFields = new DeclareTagHelperFieldsIRNode(); - _builder.Add(_tagHelperFields); + _tagHelperFields = new DeclareTagHelperFieldsIRNode() { Parent = _document, }; + _document.Children.Add(_tagHelperFields); } foreach (var descriptor in block.Descriptors) diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/DefaultRazorIRLoweringPhaseIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/DefaultRazorIRLoweringPhaseIntegrationTest.cs index e4cce08614..3ca28364e8 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/DefaultRazorIRLoweringPhaseIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/DefaultRazorIRLoweringPhaseIntegrationTest.cs @@ -194,6 +194,57 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate }); } + [Fact] + public void Lower_TagHelper_InSection() + { + // Arrange + var codeDocument = TestRazorCodeDocument.Create(@"@addTagHelper *, TestAssembly +@section test { + +}"); + var tagHelpers = new[] + { + new TagHelperDescriptor + { + TagName = "span", + TypeName = "SpanTagHelper", + AssemblyName = "TestAssembly", + } + }; + + // Act + var irDocument = Lower(codeDocument, tagHelpers: tagHelpers); + + // Assert + Children( + irDocument, + n => Checksum(n), + n => Using("System", n), + n => Using(typeof(Task).Namespace, n), + n => Directive( + "section", + n, + c1 => DirectiveToken(DirectiveTokenKind.Member, "test", c1), + c1 => Html(Environment.NewLine, c1), + c1 => + { + var tagHelperNode = Assert.IsType(c1); + Children( + tagHelperNode, + c2 => TagHelperStructure("span", TagMode.StartTagAndEndTag, c2), + c2 => Assert.IsType(c2), + c2 => TagHelperHtmlAttribute( + "val", + HtmlAttributeValueStyle.DoubleQuotes, + c2, + v => CSharpAttributeValue(string.Empty, "Hello", v), + v => LiteralAttributeValue(" ", "World", v)), + c2 => Assert.IsType(c2)); + }, + c1 => Html(Environment.NewLine, c1)), + n => TagHelperFieldDeclaration(n, "SpanTagHelper")); + } + [Fact] public void Lower_TagHelpersWithBoundAttribute() {