From 88a002a9186a01f1318b25434673128114094835 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 6 Aug 2019 14:39:00 -0700 Subject: [PATCH] Enable Component parameter delegates to not require @() at design time. - The core issue is that the Razor parser splits attribute values based on whitespace. Therefore, when it encounters `@onclick="() => Foo()"` it breaks it into three different tokens based on the spaces involved. This separation results in multiple adjacent classified spans for C# which is currently unsupported by WTE due to multiple seams overlapping. All that being said we have the opportunity to be smarter when generating attribute values that we feel can be simplified or collapsed; because of this in this PR I changed the `TagHelperBlockRewriter` phase to understand "simple" collapsible blocks and to then collapse them. In the future a goal would be to take a collapsing approach to all potential attributes and then to re-inspect each token individually at higher layers in order to decouple our TagHelper phases from what the parser initially parses. - Added an integration and parser test to validate the new functionality. Most of the testing is from the fact that no other tests had to change because of this (it doesn't break anything). - Added a new SyntaxNode method `GetTokens` that flattens a node into only its token representation. aspnet/AspNetCoredotnet/aspnetcore-tooling#11826 \n\nCommit migrated from https://github.com/dotnet/aspnetcore-tooling/commit/80f1bc76a448288670371ac294682afa601a421b --- .../src/Legacy/TagHelperBlockRewriter.cs | 42 ++++++++++++++ .../src/Syntax/SyntaxNode.cs | 29 ++++++++++ .../ComponentCodeGenerationTestBase.cs | 33 +++++++++++ .../test/Legacy/TagHelperBlockRewriterTest.cs | 6 ++ .../TestComponent.codegen.cs | 57 +++++++++++++++++++ .../TestComponent.ir.txt | 26 +++++++++ .../TestComponent.mappings.txt | 20 +++++++ .../TestComponent.codegen.cs | 42 ++++++++++++++ .../TestComponent.ir.txt | 17 ++++++ .../TestComponent.mappings.txt | 15 +++++ ...artNonStringTagHelperAttributes.cspans.txt | 1 + ...partNonStringTagHelperAttributes.stree.txt | 29 ++++++++++ ...artNonStringTagHelperAttributes.tspans.txt | 1 + 13 files changed, 318 insertions(+) create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.codegen.cs create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.ir.txt create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.mappings.txt create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.codegen.cs create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.ir.txt create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.mappings.txt create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.cspans.txt create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.stree.txt create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.tspans.txt diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs index d2dc97749d..9d47a0b97f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs @@ -521,6 +521,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy _tryParseResult = result; } + public override SyntaxNode VisitGenericBlock(GenericBlockSyntax node) + { + if (_tryParseResult.IsBoundNonStringAttribute && CanBeCollapsed(node)) + { + var tokens = node.GetTokens(); + var expression = SyntaxFactory.CSharpExpressionLiteral(tokens); + var rewrittenExpression = (CSharpExpressionLiteralSyntax)VisitCSharpExpressionLiteral(expression); + var newChildren = SyntaxListBuilder.Create(); + newChildren.Add(rewrittenExpression); + + return node.Update(newChildren); + } + + return base.VisitGenericBlock(node); + } + public override SyntaxNode VisitCSharpTransition(CSharpTransitionSyntax node) { if (!_tryParseResult.IsBoundNonStringAttribute) @@ -769,6 +785,32 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return value.WithSpanContext(node.GetSpanContext()); } + // Being collapsed represents that a block contains several identical looking markup literal attribute values. This can be the case + // when a user has written something like: @onclick="() => SomeMethod()" + // In that case there would be 3 children: + // - () + // - => + // - SomeMethod() + // There are 3 children because the Razor parser separates attribute values based on whitespace. + private static bool CanBeCollapsed(GenericBlockSyntax node) + { + if (node.Children.Count <= 1) + { + // The node is either already collapsed or has no children. + return false; + } + + for (var i = 0; i < node.Children.Count; i++) + { + if (node.Children[i].Kind != SyntaxKind.MarkupLiteralAttributeValue) + { + return false; + } + } + + return true; + } + private SyntaxNode ConfigureNonStringAttribute(SyntaxNode node) { var context = node.GetSpanContext(); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Syntax/SyntaxNode.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Syntax/SyntaxNode.cs index 2f58f13fe3..aacc0eb91e 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Syntax/SyntaxNode.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Syntax/SyntaxNode.cs @@ -224,6 +224,35 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax return ((SyntaxToken)GetFirstTerminal()); } + internal SyntaxList GetTokens() + { + var tokens = SyntaxListBuilder.Create(); + + AddTokens(this, tokens); + + return tokens; + + static void AddTokens(SyntaxNode current, SyntaxListBuilder tokens) + { + if (current.SlotCount == 0 && current is SyntaxToken token) + { + // Token + tokens.Add(token); + return; + } + + for (var i = 0; i < current.SlotCount; i++) + { + var child = current.GetNodeSlot(i); + + if (child != null) + { + AddTokens(child, tokens); + } + } + } + } + internal SyntaxToken GetLastToken() { return ((SyntaxToken)GetLastTerminal()); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs index cbd8737c16..b331afa4ca 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs @@ -2352,6 +2352,39 @@ namespace Test #region Event Handlers + [Fact] + public void Component_WithImplicitLambdaEventHandler() + { + // Arrange + AdditionalSyntaxTrees.Add(Parse(@" +using System; +using Microsoft.AspNetCore.Components; + +namespace Test +{ + public class MyComponent : ComponentBase + { + } +} +")); + + // Act + var generated = CompileToCSharp(@" + Increment()""/> + +@code { + private int counter; + private void Increment() { + counter++; + } +}"); + + // Assert + AssertDocumentNodeMatchesBaseline(generated.CodeDocument); + AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); + CompileToAssembly(generated); + } + [Fact] public void ChildComponent_WithLambdaEventHandler() { diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperBlockRewriterTest.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperBlockRewriterTest.cs index 7460142c23..c581a53c3c 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperBlockRewriterTest.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperBlockRewriterTest.cs @@ -423,6 +423,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy .Build() }; + [Fact] + public void UnderstandsMultipartNonStringTagHelperAttributes() + { + EvaluateData(CodeTagHelperAttributes_Descriptors, " 123)()\" />"); + } + [Fact] public void CreatesMarkupCodeSpansForNonStringTagHelperAttributes1() { diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.codegen.cs new file mode 100644 index 0000000000..5e7e2fe184 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.codegen.cs @@ -0,0 +1,57 @@ +// +#pragma warning disable 1591 +namespace Test +{ + #line hidden + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Components; + public class TestComponent : Microsoft.AspNetCore.Components.ComponentBase + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + } + #pragma warning restore 219 + #pragma warning disable 0414 + private static System.Object __o = null; + #pragma warning restore 0414 + #pragma warning disable 1998 + protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) + { + __o = Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, +#nullable restore +#line 1 "x:\dir\subdir\Test\TestComponent.cshtml" + () => Increment() + +#line default +#line hidden +#nullable disable + ); + builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((builder2) => { + } + )); +#nullable restore +#line 1 "x:\dir\subdir\Test\TestComponent.cshtml" +__o = typeof(MyComponent); + +#line default +#line hidden +#nullable disable + } + #pragma warning restore 1998 +#nullable restore +#line 3 "x:\dir\subdir\Test\TestComponent.cshtml" + + private int counter; + private void Increment() { + counter++; + } + +#line default +#line hidden +#nullable disable + } +} +#pragma warning restore 1591 diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.ir.txt new file mode 100644 index 0000000000..651d67138d --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.ir.txt @@ -0,0 +1,26 @@ +Document - + NamespaceDeclaration - - Test + UsingDirective - (3:1,1 [12] ) - System + UsingDirective - (18:2,1 [32] ) - System.Collections.Generic + UsingDirective - (53:3,1 [17] ) - System.Linq + UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks + UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components + ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - + DesignTimeDirective - + CSharpCode - + IntermediateToken - - CSharp - #pragma warning disable 0414 + CSharpCode - + IntermediateToken - - CSharp - private static System.Object __o = null; + CSharpCode - + IntermediateToken - - CSharp - #pragma warning restore 0414 + MethodDeclaration - - protected override - void - BuildRenderTree + Component - (0:0,0 [43] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent + ComponentAttribute - (23:0,23 [17] x:\dir\subdir\Test\TestComponent.cshtml) - onclick - AttributeStructure.DoubleQuotes + CSharpExpression - + IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, + IntermediateToken - (23:0,23 [17] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => Increment() + IntermediateToken - - CSharp - ) + HtmlContent - (43:0,43 [4] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (43:0,43 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n + CSharpCode - (54:2,7 [87] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (54:2,7 [87] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private int counter;\n private void Increment() {\n counter++;\n }\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.mappings.txt new file mode 100644 index 0000000000..6487d39922 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.mappings.txt @@ -0,0 +1,20 @@ +Source Location: (23:0,23 [17] x:\dir\subdir\Test\TestComponent.cshtml) +|() => Increment()| +Generated Location: (1002:25,23 [17] ) +|() => Increment()| + +Source Location: (54:2,7 [87] x:\dir\subdir\Test\TestComponent.cshtml) +| + private int counter; + private void Increment() { + counter++; + } +| +Generated Location: (1512:45,7 [87] ) +| + private int counter; + private void Increment() { + counter++; + } +| + diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.codegen.cs new file mode 100644 index 0000000000..ddcbeca415 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.codegen.cs @@ -0,0 +1,42 @@ +// +#pragma warning disable 1591 +namespace Test +{ + #line hidden + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Components; + public class TestComponent : Microsoft.AspNetCore.Components.ComponentBase + { + #pragma warning disable 1998 + protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) + { + builder.OpenComponent(0); + builder.AddAttribute(1, "onclick", Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, +#nullable restore +#line 1 "x:\dir\subdir\Test\TestComponent.cshtml" + () => Increment() + +#line default +#line hidden +#nullable disable + )); + builder.CloseComponent(); + } + #pragma warning restore 1998 +#nullable restore +#line 3 "x:\dir\subdir\Test\TestComponent.cshtml" + + private int counter; + private void Increment() { + counter++; + } + +#line default +#line hidden +#nullable disable + } +} +#pragma warning restore 1591 diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.ir.txt new file mode 100644 index 0000000000..b92548c14d --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.ir.txt @@ -0,0 +1,17 @@ +Document - + NamespaceDeclaration - - Test + UsingDirective - (3:1,1 [14] ) - System + UsingDirective - (18:2,1 [34] ) - System.Collections.Generic + UsingDirective - (53:3,1 [19] ) - System.Linq + UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks + UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components + ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - + MethodDeclaration - - protected override - void - BuildRenderTree + Component - (0:0,0 [43] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent + ComponentAttribute - (23:0,23 [17] x:\dir\subdir\Test\TestComponent.cshtml) - onclick - AttributeStructure.DoubleQuotes + CSharpExpression - + IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, + IntermediateToken - (23:0,23 [17] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => Increment() + IntermediateToken - - CSharp - ) + CSharpCode - (54:2,7 [87] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (54:2,7 [87] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n private int counter;\n private void Increment() {\n counter++;\n }\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.mappings.txt new file mode 100644 index 0000000000..e4a8581302 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/Component_WithImplicitLambdaEventHandler/TestComponent.mappings.txt @@ -0,0 +1,15 @@ +Source Location: (54:2,7 [87] x:\dir\subdir\Test\TestComponent.cshtml) +| + private int counter; + private void Increment() { + counter++; + } +| +Generated Location: (1071:30,7 [87] ) +| + private int counter; + private void Increment() { + counter++; + } +| + diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.cspans.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.cspans.txt new file mode 100644 index 0000000000..017c88aff0 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.cspans.txt @@ -0,0 +1 @@ +Code span at (13:0,13 [13] ) (Accepts:AnyExceptNewline) - Parent: Tag block at (0:0,0 [30] ) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.stree.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.stree.txt new file mode 100644 index 0000000000..51348bf9d0 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.stree.txt @@ -0,0 +1,29 @@ +RazorDocument - [0..30)::30 - [] + MarkupBlock - [0..30)::30 + MarkupTagHelperElement - [0..30)::30 - person[SelfClosing] - PersonTagHelper + MarkupTagHelperStartTag - [0..30)::30 - [] - Gen - SpanEditHandler;Accepts:Any + OpenAngle;[<]; + Text;[person]; + MarkupTagHelperAttribute - [7..27)::20 - age - DoubleQuotes - Bound - [ age="(() => 123)()"] + MarkupTextLiteral - [7..8)::1 - [ ] - Gen - SpanEditHandler;Accepts:Any + Whitespace;[ ]; + MarkupTextLiteral - [8..11)::3 - [age] - Gen - SpanEditHandler;Accepts:Any + Text;[age]; + Equals;[=]; + MarkupTextLiteral - [12..13)::1 - ["] - Gen - SpanEditHandler;Accepts:Any + DoubleQuote;["]; + MarkupTagHelperAttributeValue - [13..26)::13 + CSharpExpressionLiteral - [13..26)::13 - [(() => 123)()] - Gen - ImplicitExpressionEditHandler;Accepts:AnyExceptNewline;ImplicitExpression[ATD];K14 + Text;[(()]; + Whitespace;[ ]; + Equals;[=]; + CloseAngle;[>]; + Whitespace;[ ]; + Text;[123)()]; + MarkupTextLiteral - [26..27)::1 - ["] - Gen - SpanEditHandler;Accepts:Any + DoubleQuote;["]; + MarkupMiscAttributeContent - [27..28)::1 + MarkupTextLiteral - [27..28)::1 - [ ] - Gen - SpanEditHandler;Accepts:Any + Whitespace;[ ]; + ForwardSlash;[/]; + CloseAngle;[>]; diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.tspans.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.tspans.txt new file mode 100644 index 0000000000..6c93624813 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/ParserTests/TagHelperBlockRewriterTest/UnderstandsMultipartNonStringTagHelperAttributes.tspans.txt @@ -0,0 +1 @@ +TagHelper span at (0:0,0 [30] ) - PersonTagHelper