diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinderSyntaxTreePass.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs similarity index 97% rename from src/Microsoft.AspNetCore.Razor.Language/TagHelperBinderSyntaxTreePass.cs rename to src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs index 7bec85d595..3f00a2b062 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinderSyntaxTreePass.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs @@ -8,24 +8,23 @@ using Microsoft.AspNetCore.Razor.Language.Legacy; namespace Microsoft.AspNetCore.Razor.Language { - internal class TagHelperBinderSyntaxTreePass : IRazorSyntaxTreePass + internal class DefaultRazorTagHelperBinderPhase : RazorEnginePhaseBase, IRazorTagHelperBinderPhase { private static HashSet InvalidNonWhitespaceNameCharacters = new HashSet(new[] { '@', '!', '<', '/', '?', '[', '>', ']', '=', '"', '\'', '*' }); - public RazorEngine Engine { get; set; } - - public int Order => 150; - - public RazorSyntaxTree Execute(RazorCodeDocument codeDocument, RazorSyntaxTree syntaxTree) + protected override void ExecuteCore(RazorCodeDocument codeDocument) { + var syntaxTree = codeDocument.GetSyntaxTree(); + ThrowForMissingDependency(syntaxTree); + var resolver = Engine.Features.OfType().FirstOrDefault()?.Resolver; if (resolver == null) { // No resolver, nothing to do. - return syntaxTree; + return; } // We need to find directives in all of the *imports* as well as in the main razor file @@ -63,7 +62,7 @@ namespace Microsoft.AspNetCore.Razor.Language if (errorSink.Errors.Count == 0 && errorList.Count == 0) { // No TagHelpers and errors, no op. - return syntaxTree; + return; } } else @@ -80,7 +79,7 @@ namespace Microsoft.AspNetCore.Razor.Language var diagnostics = CombineErrors(syntaxTree.Diagnostics, errorList); var newSyntaxTree = RazorSyntaxTree.Create(root, syntaxTree.Source, diagnostics, syntaxTree.Options); - return newSyntaxTree; + codeDocument.SetSyntaxTree(newSyntaxTree); } // Internal for testing diff --git a/src/Microsoft.AspNetCore.Razor.Language/IRazorTagHelperBinderPhase.cs b/src/Microsoft.AspNetCore.Razor.Language/IRazorTagHelperBinderPhase.cs new file mode 100644 index 0000000000..1cea097fbd --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/IRazorTagHelperBinderPhase.cs @@ -0,0 +1,9 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Razor.Language +{ + public interface IRazorTagHelperBinderPhase : IRazorEnginePhase + { + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/RazorEngine.cs b/src/Microsoft.AspNetCore.Razor.Language/RazorEngine.cs index 8db56a7118..f55eb53d28 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/RazorEngine.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/RazorEngine.cs @@ -53,6 +53,7 @@ namespace Microsoft.AspNetCore.Razor.Language { builder.Phases.Add(new DefaultRazorParsingPhase()); builder.Phases.Add(new DefaultRazorSyntaxTreePhase()); + builder.Phases.Add(new DefaultRazorTagHelperBinderPhase()); builder.Phases.Add(new DefaultRazorIRLoweringPhase()); builder.Phases.Add(new DefaultRazorDocumentClassifierPhase()); builder.Phases.Add(new DefaultRazorDirectiveClassifierPhase()); @@ -66,7 +67,6 @@ namespace Microsoft.AspNetCore.Razor.Language // Syntax Tree passes builder.Features.Add(new DefaultDirectiveSyntaxTreePass()); builder.Features.Add(new HtmlNodeOptimizationPass()); - builder.Features.Add(new TagHelperBinderSyntaxTreePass()); // IR Passes builder.Features.Add(new DefaultDocumentClassifierPass()); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperBinderSyntaxTreePassTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs similarity index 94% rename from test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperBinderSyntaxTreePassTest.cs rename to test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs index 0d4b1b2cd8..c5238067ab 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperBinderSyntaxTreePassTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs @@ -3,15 +3,15 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; using Microsoft.AspNetCore.Razor.Language.Legacy; using Xunit; -using System.Linq; using Moq; -using System.Text; namespace Microsoft.AspNetCore.Razor.Language { - public class TagHelperBinderSyntaxTreePassTest + public class DefaultRazorTagHelperBinderPhaseTest { [Fact] public void Execute_CanHandleSingleLengthAddTagHelperDirective() @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Razor.Language builder.AddTagHelpers(new TagHelperDescriptor[0]); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -47,11 +47,13 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var rewrittenTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var rewrittenTree = codeDocument.GetSyntaxTree(); Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); } @@ -64,7 +66,7 @@ namespace Microsoft.AspNetCore.Razor.Language builder.AddTagHelpers(new TagHelperDescriptor[0]); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -89,11 +91,13 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var rewrittenTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var rewrittenTree = codeDocument.GetSyntaxTree(); Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); } @@ -106,7 +110,7 @@ namespace Microsoft.AspNetCore.Razor.Language builder.AddTagHelpers(new TagHelperDescriptor[0]); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -131,11 +135,13 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var rewrittenTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var rewrittenTree = codeDocument.GetSyntaxTree(); Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); } @@ -158,7 +164,7 @@ namespace Microsoft.AspNetCore.Razor.Language }); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -166,11 +172,13 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = CreateTestSourceDocument(); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var rewrittenTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var rewrittenTree = codeDocument.GetSyntaxTree(); Assert.Empty(rewrittenTree.Diagnostics); Assert.Equal(3, rewrittenTree.Root.Children.Count); var formTagHelper = Assert.IsType(rewrittenTree.Root.Children[2]); @@ -205,7 +213,7 @@ namespace Microsoft.AspNetCore.Razor.Language builder.AddTagHelpers(new[] { descriptor }); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -218,11 +226,13 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = TestRazorSourceDocument.Create(content); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var rewrittenTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var rewrittenTree = codeDocument.GetSyntaxTree(); Assert.Empty(rewrittenTree.Diagnostics); Assert.Equal(3, rewrittenTree.Root.Children.Count); @@ -256,7 +266,7 @@ namespace Microsoft.AspNetCore.Razor.Language builder.AddTagHelpers(new[] { descriptor }); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -269,11 +279,13 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = TestRazorSourceDocument.Create(content); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var rewrittenTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var rewrittenTree = codeDocument.GetSyntaxTree(); Assert.Empty(rewrittenTree.Diagnostics); Assert.Equal(3, rewrittenTree.Root.Children.Count); @@ -287,18 +299,20 @@ namespace Microsoft.AspNetCore.Razor.Language { // Arrange var engine = RazorEngine.Create(); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; var sourceDocument = CreateTestSourceDocument(); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var outputTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var outputTree = codeDocument.GetSyntaxTree(); Assert.Empty(outputTree.Diagnostics); Assert.Same(originalTree, outputTree); } @@ -311,18 +325,20 @@ namespace Microsoft.AspNetCore.Razor.Language { builder.Features.Add(Mock.Of()); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; var sourceDocument = CreateTestSourceDocument(); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var outputTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var outputTree = codeDocument.GetSyntaxTree(); Assert.Empty(outputTree.Diagnostics); Assert.Same(originalTree, outputTree); } @@ -336,7 +352,7 @@ namespace Microsoft.AspNetCore.Razor.Language builder.Features.Add(new TestTagHelperFeature()); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -345,11 +361,13 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = TestRazorSourceDocument.Create("Hello, world"); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var outputTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var outputTree = codeDocument.GetSyntaxTree(); Assert.Empty(outputTree.Diagnostics); Assert.Same(originalTree, outputTree); } @@ -363,7 +381,7 @@ namespace Microsoft.AspNetCore.Razor.Language builder.Features.Add(new TestTagHelperFeature()); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -372,9 +390,10 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = TestRazorSourceDocument.Create("Hello, world"); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var outputTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert var context = codeDocument.GetTagHelperContext(); @@ -393,7 +412,7 @@ namespace Microsoft.AspNetCore.Razor.Language builder.Features.Add(Mock.Of(f => f.Resolver == resolver)); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -408,11 +427,13 @@ namespace Microsoft.AspNetCore.Razor.Language originalTree.Source, new[] { initialError }, originalTree.Options); + codeDocument.SetSyntaxTree(erroredOriginalTree); // Act - var outputTree = pass.Execute(codeDocument, erroredOriginalTree); + phase.Execute(codeDocument); // Assert + var outputTree = codeDocument.GetSyntaxTree(); Assert.Empty(originalTree.Diagnostics); Assert.NotSame(erroredOriginalTree, outputTree); Assert.Equal(new[] { initialError, resolverError }, outputTree.Diagnostics); @@ -431,7 +452,7 @@ namespace Microsoft.AspNetCore.Razor.Language var descriptorError = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedTagNameNullOrWhitespace(); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -439,11 +460,13 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = CreateTestSourceDocument(); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); + codeDocument.SetSyntaxTree(originalTree); // Act - var outputTree = pass.Execute(codeDocument, originalTree); + phase.Execute(codeDocument); // Assert + var outputTree = codeDocument.GetSyntaxTree(); Assert.Empty(originalTree.Diagnostics); Assert.Equal(new[] { resolverError, descriptorError }, outputTree.Diagnostics); } @@ -467,7 +490,7 @@ namespace Microsoft.AspNetCore.Razor.Language }); }); - var pass = new TagHelperBinderSyntaxTreePass() + var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; @@ -490,11 +513,13 @@ namespace Microsoft.AspNetCore.Razor.Language length: 4)); var erroredOriginalTree = RazorSyntaxTree.Create(originalTree.Root, originalTree.Source, new[] { initialError }, originalTree.Options); + codeDocument.SetSyntaxTree(erroredOriginalTree); // Act - var outputTree = pass.Execute(codeDocument, erroredOriginalTree); + phase.Execute(codeDocument); // Assert + var outputTree = codeDocument.GetSyntaxTree(); Assert.Empty(originalTree.Diagnostics); Assert.NotSame(erroredOriginalTree, outputTree); Assert.Equal(new[] { initialError, expectedRewritingError }, outputTree.Diagnostics); @@ -511,7 +536,7 @@ namespace Microsoft.AspNetCore.Razor.Language { // Arrange var errorSink = new ErrorSink(); - var pass = new TagHelperBinderSyntaxTreePass(); + var phase = new DefaultRazorTagHelperBinderPhase(); var directive = new TagHelperDirectiveDescriptor() { @@ -523,7 +548,7 @@ namespace Microsoft.AspNetCore.Razor.Language var expected = new SourceLocation(assemblyLocation, 0, assemblyLocation); // Act - var result = pass.ParseAddOrRemoveDirective(directive, errorSink); + var result = phase.ParseAddOrRemoveDirective(directive, errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -733,12 +758,12 @@ namespace Microsoft.AspNetCore.Razor.Language // Arrange var errorSink = new ErrorSink(); - var pass = new TagHelperBinderSyntaxTreePass(); + var phase = new DefaultRazorTagHelperBinderPhase(); // Act foreach (var directive in ((IEnumerable)directives)) { - Assert.False(pass.IsValidTagHelperPrefix(directive.DirectiveText, directive.Location, errorSink)); + Assert.False(phase.IsValidTagHelperPrefix(directive.DirectiveText, directive.Location, errorSink)); } // Assert @@ -883,11 +908,11 @@ namespace Microsoft.AspNetCore.Razor.Language { // Arrange var errorSink = new ErrorSink(); - var pass = new TagHelperBinderSyntaxTreePass(); + var phase = new DefaultRazorTagHelperBinderPhase(); var document = RazorCodeDocument.Create(new DefaultRazorSourceDocument("Test content", encoding: Encoding.UTF8, fileName: "TestFile")); // Act - var prefix = pass.ProcessTagHelperPrefix(((IEnumerable)directiveDescriptors).ToList(), document, errorSink); + var prefix = phase.ProcessTagHelperPrefix(((IEnumerable)directiveDescriptors).ToList(), document, errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -1104,12 +1129,12 @@ namespace Microsoft.AspNetCore.Razor.Language // Arrange var errorSink = new ErrorSink(); - var pass = new TagHelperBinderSyntaxTreePass(); + var phase = new DefaultRazorTagHelperBinderPhase(); var expected = (IEnumerable)expectedDescriptors; // Act - var results = pass.ProcessDirectives( + var results = phase.ProcessDirectives( new List((IEnumerable)directiveDescriptors), new List((IEnumerable)tagHelpers), errorSink); @@ -1272,10 +1297,10 @@ namespace Microsoft.AspNetCore.Razor.Language // Arrange var errorSink = new ErrorSink(); - var pass = new TagHelperBinderSyntaxTreePass(); + var phase = new DefaultRazorTagHelperBinderPhase(); // Act - var results = pass.ProcessDirectives( + var results = phase.ProcessDirectives( new List((IEnumerable)directiveDescriptors), new List((IEnumerable)tagHelpers), errorSink); @@ -1311,7 +1336,7 @@ namespace Microsoft.AspNetCore.Razor.Language { // Arrange var errorSink = new ErrorSink(); - var pass = new TagHelperBinderSyntaxTreePass(); + var phase = new DefaultRazorTagHelperBinderPhase(); var directives = new[] { @@ -1323,7 +1348,7 @@ namespace Microsoft.AspNetCore.Razor.Language }; // Act - var results = pass.ProcessDirectives( + var results = phase.ProcessDirectives( directives, new[] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor }, errorSink); @@ -1352,7 +1377,7 @@ namespace Microsoft.AspNetCore.Razor.Language { // Arrange var errorSink = new ErrorSink(); - var pass = new TagHelperBinderSyntaxTreePass(); + var phase = new DefaultRazorTagHelperBinderPhase(); var directive = new TagHelperDirectiveDescriptor() { @@ -1367,7 +1392,7 @@ namespace Microsoft.AspNetCore.Razor.Language directiveText); // Act - var result = pass.ParseAddOrRemoveDirective(directive, errorSink); + var result = phase.ParseAddOrRemoveDirective(directive, errorSink); // Assert Assert.Null(result); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/RazorEngineTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/RazorEngineTest.cs index a8aa2cbc10..9782503112 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/RazorEngineTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/RazorEngineTest.cs @@ -151,7 +151,6 @@ namespace Microsoft.AspNetCore.Razor.Language feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), - feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), @@ -165,6 +164,7 @@ namespace Microsoft.AspNetCore.Razor.Language phases, phase => Assert.IsType(phase), phase => Assert.IsType(phase), + phase => Assert.IsType(phase), phase => Assert.IsType(phase), phase => Assert.IsType(phase), phase => Assert.IsType(phase), @@ -180,7 +180,6 @@ namespace Microsoft.AspNetCore.Razor.Language feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), - feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), feature => Assert.IsType(feature), @@ -195,6 +194,7 @@ namespace Microsoft.AspNetCore.Razor.Language phases, phase => Assert.IsType(phase), phase => Assert.IsType(phase), + phase => Assert.IsType(phase), phase => Assert.IsType(phase), phase => Assert.IsType(phase), phase => Assert.IsType(phase),