From 2e8c154fcb2952b9b42610258dd600883fda461f Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 31 May 2017 12:17:37 -0700 Subject: [PATCH 1/2] Make namespace tokens tolerant to EOF and invalid states. - Updated our `QualifiedIdentifier` to properly parse invalid namespaces. This is more consistent with how the rest of the system works; we consume tokens until we determine if we're in an invalid or valid state. If invalid, we log an error and put back all invalid tokens for the parser to treat as non-directive tokens. - Added unit tests to validate our extensible directive system can handle malformed namespace tokens at EOF and inline. - Added a code gen test for Razor.Extensions to prove we've fixed the underlying issue for our `@namespace` directive that crashed VS. #1393 --- .../Legacy/CSharpCodeParser.cs | 48 ++++++++-- .../CodeGenerationIntegrationTest.cs | 21 +++++ .../InvalidNamespaceAtEOF.cshtml | 1 + ...nvalidNamespaceAtEOF_DesignTime.codegen.cs | 35 +++++++ .../InvalidNamespaceAtEOF_DesignTime.ir.txt | 36 ++++++++ ...alidNamespaceAtEOF_DesignTime.mappings.txt | 0 .../InvalidNamespaceAtEOF_Runtime.codegen.cs | 33 +++++++ .../InvalidNamespaceAtEOF_Runtime.ir.txt | 23 +++++ .../Legacy/CSharpDirectivesTest.cs | 91 +++++++++++++++++++ 9 files changed, 280 insertions(+), 8 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF.cshtml create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.codegen.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.ir.txt create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.mappings.txt create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_Runtime.codegen.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_Runtime.ir.txt diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs index 7d46c3f7f6..b96181a9d1 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs @@ -909,21 +909,53 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy // qualified-identifier: // identifier // qualified-identifier . identifier - protected bool QualifiedIdentifier() + protected bool QualifiedIdentifier(out int identifierLength) { - if (At(CSharpSymbolType.Identifier)) + var currentIdentifierLength = 0; + var expectingDot = false; + var tokens = ReadWhile(token => { - AcceptAndMoveNext(); - - if (Optional(CSharpSymbolType.Dot)) + var type = token.Type; + if ((expectingDot && type == CSharpSymbolType.Dot) || + (!expectingDot && type == CSharpSymbolType.Identifier)) { - return QualifiedIdentifier(); + expectingDot = !expectingDot; + return true; + } + + if (type != CSharpSymbolType.WhiteSpace && + type != CSharpSymbolType.NewLine) + { + expectingDot = false; + currentIdentifierLength += token.Content.Length; + } + + return false; + }); + + identifierLength = currentIdentifierLength; + var validQualifiedIdentifier = expectingDot; + if (validQualifiedIdentifier) + { + foreach (var token in tokens) + { + identifierLength += token.Content.Length; + Accept(token); } return true; } else { + PutCurrentBack(); + + foreach (var token in tokens) + { + identifierLength += token.Content.Length; + PutBack(token); + } + + EnsureCurrent(); return false; } } @@ -1574,12 +1606,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy break; case DirectiveTokenKind.Namespace: - if (!QualifiedIdentifier()) + if (!QualifiedIdentifier(out var identifierLength)) { Context.ErrorSink.OnError( CurrentStart, LegacyResources.FormatDirectiveExpectsNamespace(descriptor.Name), - CurrentSymbol.Content.Length); + identifierLength); return; } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs index 8caacfaf94..9a60a1eb9e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs @@ -27,6 +27,16 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.IntegrationTests private static readonly RazorSourceDocument DefaultImports = MvcRazorTemplateEngine.GetDefaultImports(); #region Runtime + [Fact] + public void InvalidNamespaceAtEOF_Runtime() + { + var references = CreateCompilationReferences(CurrentMvcShim); + RunRuntimeTest(references, expectedErrors: new[] + { + "Identifier expected" + }); + } + [Fact] public void IncompleteDirectives_Runtime() { @@ -235,6 +245,17 @@ public class DivTagHelper : {typeof(TagHelper).FullName} #endregion #region DesignTime + [Fact] + public void InvalidNamespaceAtEOF_DesignTime() + { + var references = CreateCompilationReferences(CurrentMvcShim); + RunDesignTimeTest(references, + expectedErrors: new[] + { + "Identifier expected" + }); + } + [Fact] public void IncompleteDirectives_DesignTime() { diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF.cshtml b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF.cshtml new file mode 100644 index 0000000000..6dfb72bc31 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF.cshtml @@ -0,0 +1 @@ +@namespace Test. \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.codegen.cs new file mode 100644 index 0000000000..0dd729a78d --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.codegen.cs @@ -0,0 +1,35 @@ +namespace +{ + #line hidden + using TModel = global::System.Object; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + } + #pragma warning restore 219 + private static System.Object __o = null; + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + } + #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.ir.txt new file mode 100644 index 0000000000..6cf3ca93c9 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.ir.txt @@ -0,0 +1,36 @@ +Document - + Checksum - + NamespaceDeclaration - - + UsingStatement - - TModel = global::System.Object + UsingStatement - (1:0,1 [12] ) - System + UsingStatement - (16:1,1 [32] ) - System.Collections.Generic + UsingStatement - (51:2,1 [17] ) - System.Linq + UsingStatement - (71:3,1 [28] ) - System.Threading.Tasks + UsingStatement - (102:4,1 [30] ) - Microsoft.AspNetCore.Mvc + UsingStatement - (135:5,1 [40] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingStatement - (178:6,1 [43] ) - Microsoft.AspNetCore.Mvc.ViewFeatures + ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage - + DesignTimeDirective - + DirectiveToken - (231:7,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper + DirectiveToken - (294:7,71 [4] ) - Html + DirectiveToken - (308:8,8 [54] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper + DirectiveToken - (363:8,63 [4] ) - Json + DirectiveToken - (377:9,8 [53] ) - global::Microsoft.AspNetCore.Mvc.IViewComponentHelper + DirectiveToken - (431:9,62 [9] ) - Component + DirectiveToken - (450:10,8 [43] ) - global::Microsoft.AspNetCore.Mvc.IUrlHelper + DirectiveToken - (494:10,52 [3] ) - Url + DirectiveToken - (507:11,8 [70] ) - global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider + DirectiveToken - (578:11,79 [23] ) - ModelExpressionProvider + DirectiveToken - (617:12,14 [96] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (729:13,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (832:14,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor + CSharpStatement - + RazorIRToken - - CSharp - private static System.Object __o = null; + MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + HtmlContent - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) + RazorIRToken - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) - Html - Test. + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_DesignTime.mappings.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_Runtime.codegen.cs new file mode 100644 index 0000000000..0e8e0f2afd --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_Runtime.codegen.cs @@ -0,0 +1,33 @@ +#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "de132bd3e2a46a0d2ec953a168427c01e5829cde" +namespace +{ + #line hidden + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(11, 5, true); + WriteLiteral("Test."); + EndContext(); + } + #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_Runtime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_Runtime.ir.txt new file mode 100644 index 0000000000..637caafd8d --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF_Runtime.ir.txt @@ -0,0 +1,23 @@ +Document - + Checksum - + NamespaceDeclaration - - + UsingStatement - (1:0,1 [14] ) - System + UsingStatement - (16:1,1 [34] ) - System.Collections.Generic + UsingStatement - (51:2,1 [19] ) - System.Linq + UsingStatement - (71:3,1 [30] ) - System.Threading.Tasks + UsingStatement - (102:4,1 [32] ) - Microsoft.AspNetCore.Mvc + UsingStatement - (135:5,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingStatement - (178:6,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures + ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage - + MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + CSharpStatement - + RazorIRToken - - CSharp - BeginContext(11, 5, true); + HtmlContent - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) + RazorIRToken - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) - Html - Test. + CSharpStatement - + RazorIRToken - - CSharp - EndContext(); + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs index a11b339e4f..0daa079a41 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs @@ -10,6 +10,97 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { public class CSharpDirectivesTest : CsHtmlCodeParserTestBase { + [Fact] + public void DirectiveDescriptor_CanHandleEOFIncompleteNamespaceTokens() + { + // Arrange + var descriptor = DirectiveDescriptor.CreateDirective( + "custom", + DirectiveKind.SingleLine, + b => b.AddNamespaceToken()); + + // Act & Assert + ParseCodeBlockTest( + "@custom System.", + new[] { descriptor }, + new DirectiveBlock( + new DirectiveChunkGenerator(descriptor), + Factory.CodeTransition(), + Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), + Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace)), + new RazorError( + LegacyResources.FormatDirectiveExpectsNamespace("custom"), + 8, 0, 8, 7)); + } + + [Fact] + public void DirectiveDescriptor_CanHandleEOFInvalidNamespaceTokens() + { + // Arrange + var descriptor = DirectiveDescriptor.CreateDirective( + "custom", + DirectiveKind.SingleLine, + b => b.AddNamespaceToken()); + + // Act & Assert + ParseCodeBlockTest( + "@custom System<", + new[] { descriptor }, + new DirectiveBlock( + new DirectiveChunkGenerator(descriptor), + Factory.CodeTransition(), + Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), + Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace)), + new RazorError( + LegacyResources.FormatDirectiveExpectsNamespace("custom"), + 8, 0, 8, 7)); + } + [Fact] + public void DirectiveDescriptor_CanHandleIncompleteNamespaceTokens() + { + // Arrange + var descriptor = DirectiveDescriptor.CreateDirective( + "custom", + DirectiveKind.SingleLine, + b => b.AddNamespaceToken()); + + // Act & Assert + ParseCodeBlockTest( + "@custom System." + Environment.NewLine, + new[] { descriptor }, + new DirectiveBlock( + new DirectiveChunkGenerator(descriptor), + Factory.CodeTransition(), + Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), + Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace)), + new RazorError( + LegacyResources.FormatDirectiveExpectsNamespace("custom"), + 8, 0, 8, 7)); + } + + [Fact] + public void DirectiveDescriptor_CanHandleInvalidNamespaceTokens() + { + // Arrange + var descriptor = DirectiveDescriptor.CreateDirective( + "custom", + DirectiveKind.SingleLine, + b => b.AddNamespaceToken()); + + // Act & Assert + ParseCodeBlockTest( + "@custom System<" + Environment.NewLine, + new[] { descriptor }, + new DirectiveBlock( + new DirectiveChunkGenerator(descriptor), + Factory.CodeTransition(), + Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), + Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace)), + new RazorError( + LegacyResources.FormatDirectiveExpectsNamespace("custom"), + 8, 0, 8, 7)); + } + [Fact] public void DirectiveDescriptor_UnderstandsTypeTokens() { From 1f32a8322e3c8e9e8d6a79f6d3db33623de93e88 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 31 May 2017 16:37:45 -0700 Subject: [PATCH 2/2] Make invalid namespace tokens support IntelliSense. - Added a `DirectiveTokenEditHandler` to enable IntelliSense for invalid namespace tokens. - Added tests to verify new `DirectiveTokenEditHandler`. - Updated test expectations for `DirectiveTokenEditHandler`. #1393 --- .../DirectiveTokenEditHandler.cs | 49 ++++++++ .../Legacy/CSharpCodeParser.cs | 1 + .../CodeGenerationIntegrationTest.cs | 6 +- .../DirectiveTokenEditHandlerTest.cs | 66 +++++++++++ .../Legacy/CSharpAutoCompleteTest.cs | 7 +- .../Legacy/CSharpDirectivesTest.cs | 107 +++++------------- .../Legacy/CSharpSectionTest.cs | 92 ++++----------- .../Legacy/CSharpSpecialBlockTest.cs | 4 +- .../Legacy/HtmlDocumentTest.cs | 8 +- .../Legacy/HtmlToCodeSwitchTest.cs | 12 +- .../Legacy/TestSpanBuilder.cs | 8 ++ 11 files changed, 183 insertions(+), 177 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Razor.Language/DirectiveTokenEditHandler.cs create mode 100644 test/Microsoft.AspNetCore.Razor.Language.Test/DirectiveTokenEditHandlerTest.cs diff --git a/src/Microsoft.AspNetCore.Razor.Language/DirectiveTokenEditHandler.cs b/src/Microsoft.AspNetCore.Razor.Language/DirectiveTokenEditHandler.cs new file mode 100644 index 0000000000..a9bc3601b7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/DirectiveTokenEditHandler.cs @@ -0,0 +1,49 @@ +// 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. + +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.Language.Legacy; + +namespace Microsoft.AspNetCore.Razor.Language +{ + internal class DirectiveTokenEditHandler : SpanEditHandler + { + public DirectiveTokenEditHandler(Func> tokenizer) : base(tokenizer) + { + } + + protected override PartialParseResult CanAcceptChange(Span target, SourceChange change) + { + if (AcceptedCharacters == AcceptedCharacters.NonWhiteSpace) + { + var originalText = change.GetOriginalText(target); + var editedContent = change.GetEditedContent(target); + + if (!ContainsWhitespace(originalText) && !ContainsWhitespace(editedContent)) + { + // Did not modify whitespace, directive format should be the same. + // Return provisional so extensible IR/code gen pieces can see the full directive text + // once the user stops editing the document. + return PartialParseResult.Accepted | PartialParseResult.Provisional; + } + } + + return PartialParseResult.Rejected; + + } + + private static bool ContainsWhitespace(string content) + { + for (var i = 0; i < content.Length; i++) + { + if (char.IsWhiteSpace(content[i])) + { + return true; + } + } + + return false; + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs index b96181a9d1..91ce56bffe 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs @@ -1649,6 +1649,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } Span.ChunkGenerator = new DirectiveTokenChunkGenerator(tokenDescriptor); + Span.EditHandler = new DirectiveTokenEditHandler(Language.TokenizeString); Output(SpanKind.Code, AcceptedCharacters.NonWhiteSpace); } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs index 9a60a1eb9e..f0dcdcdbb5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs @@ -249,11 +249,7 @@ public class DivTagHelper : {typeof(TagHelper).FullName} public void InvalidNamespaceAtEOF_DesignTime() { var references = CreateCompilationReferences(CurrentMvcShim); - RunDesignTimeTest(references, - expectedErrors: new[] - { - "Identifier expected" - }); + RunDesignTimeTest(references, expectedErrors: new[] { "Identifier expected" }); } [Fact] diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DirectiveTokenEditHandlerTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DirectiveTokenEditHandlerTest.cs new file mode 100644 index 0000000000..f1d59030c7 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DirectiveTokenEditHandlerTest.cs @@ -0,0 +1,66 @@ +// 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. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.AspNetCore.Razor.Language.Legacy; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Language.Test +{ + public class DirectiveTokenEditHandlerTest + { + [Theory] + [InlineData(0, 4, "")] // "Namespace" + [InlineData(4, 0, "Other")] // "SomeOtherNamespace" + [InlineData(0, 4, "Other")] // "OtherNamespace" + public void CanAcceptChange_ProvisionallyAcceptsNonWhitespaceChanges(int index, int length, string newText) + { + // Arrange + var factory = new SpanFactory(); + var directiveTokenHandler = new TestDirectiveTokenEditHandler(); + var target = factory.Span(SpanKind.Code, "SomeNamespace", markup: false) + .With(directiveTokenHandler) + .Accepts(AcceptedCharacters.NonWhiteSpace); + var sourceChange = new SourceChange(index, length, newText); + + // Act + var result = directiveTokenHandler.CanAcceptChange(target, sourceChange); + + // Assert + Assert.Equal(PartialParseResult.Accepted | PartialParseResult.Provisional, result); + } + + [Theory] + [InlineData(4, 1, "")] // "SomeNamespace" + [InlineData(9, 0, " ")] // "Some Name space" + [InlineData(9, 5, " Space")] // "Some Name Space" + public void CanAcceptChange_RejectsWhitespaceChanges(int index, int length, string newText) + { + // Arrange + var factory = new SpanFactory(); + var directiveTokenHandler = new TestDirectiveTokenEditHandler(); + var target = factory.Span(SpanKind.Code, "Some Namespace", markup: false) + .With(directiveTokenHandler) + .Accepts(AcceptedCharacters.NonWhiteSpace); + var sourceChange = new SourceChange(index, length, newText); + + // Act + var result = directiveTokenHandler.CanAcceptChange(target, sourceChange); + + // Assert + Assert.Equal(PartialParseResult.Rejected, result); + } + + private class TestDirectiveTokenEditHandler : DirectiveTokenEditHandler + { + public TestDirectiveTokenEditHandler() : base(content => SpanConstructor.TestTokenizer(content)) + { + } + + public new PartialParseResult CanAcceptChange(Span target, SourceChange change) + => base.CanAcceptChange(target, change); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs index 011b3c8067..6a5cd0c02f 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs @@ -33,8 +33,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), Factory.Span(SpanKind.Code, "Header", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + .AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -87,9 +86,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Header", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Header", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs index 0daa079a41..cb32fa4f23 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs @@ -119,9 +119,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "System.Text.Encoding.ASCIIEncoding", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace))); + Factory.Span(SpanKind.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] @@ -142,9 +140,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Some_Member", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace))); + Factory.Span(SpanKind.Code, "Some_Member", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] @@ -165,9 +161,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "BaseNamespace", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace))); + Factory.Span(SpanKind.Code, "BaseNamespace", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] @@ -188,9 +182,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "BaseNamespace.Foo.Bar", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace))); + Factory.Span(SpanKind.Code, "BaseNamespace.Foo.Bar", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] @@ -211,9 +203,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"AString\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace))); + Factory.Span(SpanKind.Code, "\"AString\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] @@ -336,19 +326,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "System.Text.Encoding.ASCIIEncoding", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Some_Member", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[1])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "Some_Member", markup: false).AsDirectiveToken(descriptor.Tokens[1]), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"AString\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[2])) - .Accepts(AcceptedCharacters.NonWhiteSpace))); + Factory.Span(SpanKind.Code, "\"AString\"", markup: false).AsDirectiveToken(descriptor.Tokens[2]))); } [Fact] @@ -369,9 +353,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"Header\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "\"Header\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{") .AutoCompleteWith(null, atEndOfSpan: true) @@ -405,9 +387,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"Name\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "\"Name\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{") .AutoCompleteWith(null, atEndOfSpan: true) @@ -435,14 +415,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "System.Text.Encoding.ASCIIEncoding", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Some_Member", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[1])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "Some_Member", markup: false).AsDirectiveToken(descriptor.Tokens[1]), Factory.Span(SpanKind.Markup, " ", markup: false) .Accepts(AcceptedCharacters.WhiteSpace))); @@ -492,9 +468,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"hello\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "\"hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ; ", markup: false).Accepts(AcceptedCharacters.WhiteSpace))); } @@ -521,9 +495,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"hello\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "\"hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace)), expectedErorr); @@ -552,9 +524,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"Hello\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace)), expectedErorr); @@ -583,9 +553,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"Hello\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace)), + Factory.Span(SpanKind.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0])), expectedErorr); } @@ -612,9 +580,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"Hello\"", markup: false) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens[0])) - .Accepts(AcceptedCharacters.NonWhiteSpace), + Factory.Span(SpanKind.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{") .AutoCompleteWith("}", atEndOfSpan: true) @@ -935,9 +901,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "System.Web.WebPages.WebPage", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First())))); + Factory.Span(SpanKind.Code, "System.Web.WebPages.WebPage", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); } [Fact] @@ -948,9 +912,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "string[[]][]", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First())))); + Factory.Span(SpanKind.Code, "string[[]][]", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); } [Fact] @@ -962,8 +924,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), Factory.Span(SpanKind.Code, "System.Web.Mvc.WebViewPage>", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First())))); + .AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); } [Fact] @@ -975,8 +936,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), Factory.Span(SpanKind.Code, "string", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First())))); + .AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); } [Fact] @@ -1014,8 +974,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), Factory.Span(SpanKind.Code, "Header", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + .AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -1059,8 +1018,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy DirectiveKind.SingleLine, b => b.AddOptionalStringToken()); - var chunkGenerator = new DirectiveTokenChunkGenerator(descriptor.Tokens.First()); - // Act & Assert ParseCodeBlockTest( "@custom \"simple-value\"", @@ -1071,8 +1028,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), Factory.Span(SpanKind.Code, "\"simple-value\"", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(chunkGenerator))); + .AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] @@ -1084,8 +1040,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy DirectiveKind.SingleLine, b => b.AddOptionalStringToken()); - var chunkGenerator = new DirectiveTokenChunkGenerator(descriptor.Tokens.First()); - // Act & Assert ParseCodeBlockTest( "@custom \"{formaction}?/{id}?\"", @@ -1096,8 +1050,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), Factory.Span(SpanKind.Code, "\"{formaction}?/{id}?\"", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(chunkGenerator))); + .AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] @@ -1118,13 +1071,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Markup, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "\"{formaction}?/{id}?\"", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "\"{formaction}?/{id}?\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "System.String", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens.Last())))); + Factory.Span(SpanKind.Code, "System.String", markup: false).AsDirectiveToken(descriptor.Tokens.Last()))); } [Fact] @@ -1165,9 +1114,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("TestDirective").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", markup: false).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "PropertyName", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(descriptor.Tokens.First())))); + Factory.Span(SpanKind.Code, "PropertyName", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs index 3eb862d2a4..bf5c9248fb 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs @@ -35,9 +35,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " " + Environment.NewLine + " ", markup: false).Accepts(AcceptedCharacters.AllWhiteSpace)), Factory.EmptyHtml()), new RazorError( @@ -110,9 +108,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()))), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0])), Factory.Markup("-bar { "), new MarkupTagBlock( Factory.Markup("

")), @@ -136,9 +132,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -147,9 +141,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "bar", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "bar", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -180,9 +172,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -207,9 +197,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -230,9 +218,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -265,9 +251,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Test", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Test", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, Environment.NewLine, CSharpSymbolType.NewLine).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -299,9 +283,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " " + Environment.NewLine, markup: false).Accepts(AcceptedCharacters.AllWhiteSpace)), Factory.EmptyHtml()), new RazorError( @@ -328,9 +310,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " " + string.Format("{0}{0}{0}{0}{0}{0}", Environment.NewLine), markup: false).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -355,9 +335,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -382,9 +360,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( Factory.Markup(" "), @@ -408,9 +384,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -435,9 +409,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -465,9 +437,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -492,9 +462,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -517,9 +485,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -538,9 +504,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -561,9 +525,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -583,9 +545,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -608,9 +568,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -635,9 +593,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy factory.CodeTransition(), factory.MetaCode("section").Accepts(AcceptedCharacters.None), factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -662,9 +618,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy factory.CodeTransition(), factory.MetaCode("section").Accepts(AcceptedCharacters.None), factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + factory.Span(SpanKind.Code, "s", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs index 1e157145d1..b8db152812 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs @@ -27,9 +27,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), Factory.MetaCode("inherits").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Foo.Bar, string, int>.Baz", markup: false) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First())))); + Factory.Span(SpanKind.Code, "Foo.Bar, string, int>.Baz", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens[0]))); } [Fact] diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlDocumentTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlDocumentTest.cs index 00fe7ca003..a1c81a0903 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlDocumentTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlDocumentTest.cs @@ -113,9 +113,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -478,9 +476,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlToCodeSwitchTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlToCodeSwitchTest.cs index a2e8c23c9f..1086f37d0c 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlToCodeSwitchTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/HtmlToCodeSwitchTest.cs @@ -295,9 +295,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -398,9 +396,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( @@ -426,9 +422,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharacters.None), Factory.Span(SpanKind.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.WhiteSpace), - Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier) - .Accepts(AcceptedCharacters.NonWhiteSpace) - .With(new DirectiveTokenChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First())), + Factory.Span(SpanKind.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens[0]), Factory.Span(SpanKind.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharacters.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharacters.None), new MarkupBlock( diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TestSpanBuilder.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TestSpanBuilder.cs index 38419d279d..95f05e6a6d 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TestSpanBuilder.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TestSpanBuilder.cs @@ -153,6 +153,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy .Accepts(AcceptedCharacters.AnyExceptNewline); } + public static SpanConstructor AsDirectiveToken(this SpanConstructor self, DirectiveTokenDescriptor descriptor) + { + return self + .With(new DirectiveTokenChunkGenerator(descriptor)) + .With(new DirectiveTokenEditHandler((content) => SpanConstructor.TestTokenizer(content))) + .Accepts(AcceptedCharacters.NonWhiteSpace); + } + public static SourceLocation GetLocationAndAdvance(this SourceLocationTracker self, string content) { var ret = self.CurrentLocation;