From 132c8c7a7ed3e812bb0831639e4d32a7bb780a02 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 22 May 2017 10:17:22 -0700 Subject: [PATCH] Implement consistent error story for directives. - Added error case that enforces whitespace in between directive tokens. - Upon encountering invalid directive tokens/states we bail out of parsing and log an appropriate error. - Raised directive parse errors to the IR layer. This is slightly hacky given the parsers limitations; we swap out the error sink temporarily to capture all directive parser errors and then shove the errors collected onto the directives chunk generator. - Added a `MalformedDiretiveIRNode` and corresponding pass to represent directives that are in an invalid state. Chose to not take the path of using the default `DirectiveIRNode.Diagnostics` member to enable users who are extending directives to only ever have to work with "valid" directives. If they want to work with malformed directives they can search the IR document for their malformed counterpart and handle it separately. - Updated existing test expectations - Removed some existing tests that were no longer valid (we don't call into user code if a directive is malformed). #1173 --- .../DefaultDirectiveSyntaxTreePass.cs | 26 +- .../DefaultRazorIRLoweringPhase.cs | 153 +++++- .../DefaultRazorTagHelperBinderPhase.cs | 72 +-- .../DirectiveRemovalIROptimizationPass.cs | 8 +- .../Intermediate/MalformedDirectiveIRNode.cs | 45 ++ .../Intermediate/RazorIRNodeVisitor.cs | 5 + .../Legacy/AddTagHelperChunkGenerator.cs | 8 +- .../Legacy/CSharpCodeParser.cs | 431 +++++++++-------- .../Legacy/DirectiveChunkGenerator.cs | 37 ++ .../Legacy/ParserContext.cs | 2 +- .../Legacy/RemoveTagHelperChunkGenerator.cs | 8 +- .../Legacy/TagHelperDirectiveDescriptor.cs | 3 + .../TagHelperPrefixDirectiveChunkGenerator.cs | 8 +- .../Properties/Resources.Designer.cs | 14 + .../Resources.resx | 3 + .../CodeGenerationIntegrationTest.cs | 19 +- .../PageDirectiveTest.cs | 19 +- ...IncompleteDirectives_DesignTime.codegen.cs | 3 +- .../IncompleteDirectives_DesignTime.ir.txt | 13 +- ...completeDirectives_DesignTime.mappings.txt | 2 +- .../IncompleteDirectives_Runtime.codegen.cs | 3 +- .../IncompleteDirectives_Runtime.ir.txt | 13 +- ...nvalidNamespaceAtEOF_DesignTime.codegen.cs | 3 +- .../InvalidNamespaceAtEOF_DesignTime.ir.txt | 5 +- .../InvalidNamespaceAtEOF_Runtime.codegen.cs | 3 +- .../InvalidNamespaceAtEOF_Runtime.ir.txt | 5 +- ...lformedPageDirective_DesignTime.codegen.cs | 8 +- .../MalformedPageDirective_DesignTime.ir.txt | 9 +- .../MalformedPageDirective_Runtime.codegen.cs | 8 +- .../MalformedPageDirective_Runtime.ir.txt | 9 +- .../DefaultRazorTagHelperBinderPhaseTest.cs | 123 ++--- .../Legacy/CSharpAutoCompleteTest.cs | 157 ++++--- .../Legacy/CSharpDirectivesTest.cs | 438 ++++++++++-------- .../Legacy/CSharpErrorTest.cs | 20 +- .../Legacy/CSharpSectionTest.cs | 307 +++++++----- .../Legacy/CSharpSpecialBlockTest.cs | 59 ++- .../Legacy/TestSpanBuilder.cs | 15 +- ...IncompleteDirectives_DesignTime.codegen.cs | 6 - .../IncompleteDirectives_DesignTime.ir.txt | 38 +- .../IncompleteDirectives_Runtime.codegen.cs | 6 - .../IncompleteDirectives_Runtime.ir.txt | 38 +- .../InlineBlocks_DesignTime.codegen.cs | 2 - .../InlineBlocks_DesignTime.ir.txt | 6 +- .../InlineBlocks_DesignTime.mappings.txt | 8 +- .../InlineBlocks_Runtime.codegen.cs | 2 - .../InlineBlocks_Runtime.ir.txt | 6 +- 46 files changed, 1337 insertions(+), 839 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Razor.Language/Intermediate/MalformedDirectiveIRNode.cs diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs index d05949477c..d41b998ca9 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs @@ -24,18 +24,8 @@ namespace Microsoft.AspNetCore.Razor.Language throw new ArgumentNullException(nameof(syntaxTree)); } - var errorSink = new ErrorSink(); var sectionVerifier = new NestedSectionVerifier(); - sectionVerifier.Verify(syntaxTree, errorSink); - - if (errorSink.Errors.Count > 0) - { - // Temporary code while we're still using legacy diagnostics in the SyntaxTree. - var errors = errorSink.Errors.Select(error => RazorDiagnostic.Create(error)); - - var combinedErrors = syntaxTree.Diagnostics.Concat(errors); - syntaxTree = RazorSyntaxTree.Create(syntaxTree.Root, syntaxTree.Source, combinedErrors, syntaxTree.Options); - } + sectionVerifier.Verify(syntaxTree); return syntaxTree; } @@ -43,11 +33,9 @@ namespace Microsoft.AspNetCore.Razor.Language private class NestedSectionVerifier : ParserVisitor { private int _nestedLevel; - private ErrorSink _errorSink; - public void Verify(RazorSyntaxTree tree, ErrorSink errorSink) + public void Verify(RazorSyntaxTree tree) { - _errorSink = errorSink; tree.Root.Accept(this); } @@ -57,10 +45,12 @@ namespace Microsoft.AspNetCore.Razor.Language { var directiveStart = block.Children.First(child => !child.IsBlock && ((Span)child).Kind == SpanKindInternal.Transition).Start; var errorLength = /* @ */ 1 + SectionDirective.Directive.Directive.Length; - _errorSink.OnError( - directiveStart, - LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS), - errorLength); + var error = RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS), + directiveStart, + errorLength)); + chunkGenerator.Diagnostics.Add(error); } _nestedLevel++; diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorIRLoweringPhase.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorIRLoweringPhase.cs index e43c086924..11d9b24ce6 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorIRLoweringPhase.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorIRLoweringPhase.cs @@ -131,12 +131,32 @@ namespace Microsoft.AspNetCore.Razor.Language public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunkGenerator, Span span) { - _builder.Push(new DirectiveIRNode() + RazorIRNode directiveNode; + if (IsMalformed(chunkGenerator.Diagnostics)) { - Name = CSharpCodeParser.AddTagHelperDirectiveDescriptor.Directive, - Descriptor = CSharpCodeParser.AddTagHelperDirectiveDescriptor, - Source = BuildSourceSpanFromNode(span), - }); + directiveNode = new MalformedDirectiveIRNode() + { + Name = CSharpCodeParser.AddTagHelperDirectiveDescriptor.Directive, + Descriptor = CSharpCodeParser.AddTagHelperDirectiveDescriptor, + Source = BuildSourceSpanFromNode(span), + }; + } + else + { + directiveNode = new DirectiveIRNode() + { + Name = CSharpCodeParser.AddTagHelperDirectiveDescriptor.Directive, + Descriptor = CSharpCodeParser.AddTagHelperDirectiveDescriptor, + Source = BuildSourceSpanFromNode(span), + }; + } + + for (var i = 0; i < chunkGenerator.Diagnostics.Count; i++) + { + directiveNode.Diagnostics.Add(chunkGenerator.Diagnostics[i]); + } + + _builder.Push(directiveNode); _builder.Add(new DirectiveTokenIRNode() { @@ -150,12 +170,32 @@ namespace Microsoft.AspNetCore.Razor.Language public override void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunkGenerator, Span span) { - _builder.Push(new DirectiveIRNode() + RazorIRNode directiveNode; + if (IsMalformed(chunkGenerator.Diagnostics)) { - Name = CSharpCodeParser.RemoveTagHelperDirectiveDescriptor.Directive, - Descriptor = CSharpCodeParser.RemoveTagHelperDirectiveDescriptor, - Source = BuildSourceSpanFromNode(span), - }); + directiveNode = new MalformedDirectiveIRNode() + { + Name = CSharpCodeParser.RemoveTagHelperDirectiveDescriptor.Directive, + Descriptor = CSharpCodeParser.RemoveTagHelperDirectiveDescriptor, + Source = BuildSourceSpanFromNode(span), + }; + } + else + { + directiveNode = new DirectiveIRNode() + { + Name = CSharpCodeParser.RemoveTagHelperDirectiveDescriptor.Directive, + Descriptor = CSharpCodeParser.RemoveTagHelperDirectiveDescriptor, + Source = BuildSourceSpanFromNode(span), + }; + } + + for (var i = 0; i < chunkGenerator.Diagnostics.Count; i++) + { + directiveNode.Diagnostics.Add(chunkGenerator.Diagnostics[i]); + } + + _builder.Push(directiveNode); _builder.Add(new DirectiveTokenIRNode() { @@ -169,12 +209,32 @@ namespace Microsoft.AspNetCore.Razor.Language public override void VisitTagHelperPrefixDirectiveSpan(TagHelperPrefixDirectiveChunkGenerator chunkGenerator, Span span) { - _builder.Push(new DirectiveIRNode() + RazorIRNode directiveNode; + if (IsMalformed(chunkGenerator.Diagnostics)) { - Name = CSharpCodeParser.TagHelperPrefixDirectiveDescriptor.Directive, - Descriptor = CSharpCodeParser.TagHelperPrefixDirectiveDescriptor, - Source = BuildSourceSpanFromNode(span), - }); + directiveNode = new MalformedDirectiveIRNode() + { + Name = CSharpCodeParser.TagHelperPrefixDirectiveDescriptor.Directive, + Descriptor = CSharpCodeParser.TagHelperPrefixDirectiveDescriptor, + Source = BuildSourceSpanFromNode(span), + }; + } + else + { + directiveNode = new DirectiveIRNode() + { + Name = CSharpCodeParser.TagHelperPrefixDirectiveDescriptor.Directive, + Descriptor = CSharpCodeParser.TagHelperPrefixDirectiveDescriptor, + Source = BuildSourceSpanFromNode(span), + }; + } + + for (var i = 0; i < chunkGenerator.Diagnostics.Count; i++) + { + directiveNode.Diagnostics.Add(chunkGenerator.Diagnostics[i]); + } + + _builder.Push(directiveNode); _builder.Add(new DirectiveTokenIRNode() { @@ -235,12 +295,32 @@ namespace Microsoft.AspNetCore.Razor.Language { _insideLineDirective = true; - _builder.Push(new DirectiveIRNode() + RazorIRNode directiveNode; + if (IsMalformed(chunkGenerator.Diagnostics)) { - Name = chunkGenerator.Descriptor.Directive, - Descriptor = chunkGenerator.Descriptor, - Source = BuildSourceSpanFromNode(block), - }); + directiveNode = new MalformedDirectiveIRNode() + { + Name = chunkGenerator.Descriptor.Directive, + Descriptor = chunkGenerator.Descriptor, + Source = BuildSourceSpanFromNode(block), + }; + } + else + { + directiveNode = new DirectiveIRNode() + { + Name = chunkGenerator.Descriptor.Directive, + Descriptor = chunkGenerator.Descriptor, + Source = BuildSourceSpanFromNode(block), + }; + } + + for (var i = 0; i < chunkGenerator.Diagnostics.Count; i++) + { + directiveNode.Diagnostics.Add(chunkGenerator.Diagnostics[i]); + } + + _builder.Push(directiveNode); base.VisitDirectiveBlock(chunkGenerator, block); @@ -274,12 +354,32 @@ namespace Microsoft.AspNetCore.Razor.Language public override void VisitDirectiveBlock(DirectiveChunkGenerator chunkGenerator, Block block) { - _builder.Push(new DirectiveIRNode() + RazorIRNode directiveNode; + if (IsMalformed(chunkGenerator.Diagnostics)) { - Name = chunkGenerator.Descriptor.Directive, - Descriptor = chunkGenerator.Descriptor, - Source = BuildSourceSpanFromNode(block), - }); + directiveNode = new MalformedDirectiveIRNode() + { + Name = chunkGenerator.Descriptor.Directive, + Descriptor = chunkGenerator.Descriptor, + Source = BuildSourceSpanFromNode(block), + }; + } + else + { + directiveNode = new DirectiveIRNode() + { + Name = chunkGenerator.Descriptor.Directive, + Descriptor = chunkGenerator.Descriptor, + Source = BuildSourceSpanFromNode(block), + }; + } + + for (var i = 0; i < chunkGenerator.Diagnostics.Count; i++) + { + directiveNode.Diagnostics.Add(chunkGenerator.Diagnostics[i]); + } + + _builder.Push(directiveNode); VisitDefault(block); @@ -675,5 +775,8 @@ namespace Microsoft.AspNetCore.Razor.Language } } } + + private static bool IsMalformed(List diagnostics) + => diagnostics.Count > 0 && diagnostics.Any(diagnostic => diagnostic.Severity == RazorDiagnosticSeverity.Error); } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs index 4970a761fe..f3892516ee 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs @@ -47,11 +47,10 @@ namespace Microsoft.AspNetCore.Razor.Language var errorList = new List(); var descriptors = feature.GetDescriptors(); - var errorSink = new ErrorSink(); var directives = visitor.Directives; - descriptors = ProcessDirectives(directives, descriptors, errorSink); + descriptors = ProcessDirectives(directives, descriptors); - var tagHelperPrefix = ProcessTagHelperPrefix(directives, codeDocument, errorSink); + var tagHelperPrefix = ProcessTagHelperPrefix(directives, codeDocument); var root = syntaxTree.Root; var context = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors); @@ -59,18 +58,14 @@ namespace Microsoft.AspNetCore.Razor.Language if (descriptors.Count == 0) { - if (errorSink.Errors.Count == 0 && errorList.Count == 0) - { - // No TagHelpers and errors, no op. - return; - } - } - else - { - var rewriter = new TagHelperParseTreeRewriter(tagHelperPrefix, descriptors); - root = rewriter.Rewrite(root, errorSink); + // No descriptors, no-op. + return; } + var errorSink = new ErrorSink(); + var rewriter = new TagHelperParseTreeRewriter(tagHelperPrefix, descriptors); + root = rewriter.Rewrite(root, errorSink); + // Temporary code while we're still using legacy diagnostics in the SyntaxTree. errorList.AddRange(errorSink.Errors.Select(error => RazorDiagnostic.Create(error))); @@ -83,7 +78,7 @@ namespace Microsoft.AspNetCore.Razor.Language } // Internal for testing - internal string ProcessTagHelperPrefix(List directives, RazorCodeDocument codeDocument, ErrorSink errorSink) + internal string ProcessTagHelperPrefix(List directives, RazorCodeDocument codeDocument) { // We only support a single prefix directive. TagHelperDirectiveDescriptor prefixDirective = null; @@ -97,7 +92,7 @@ namespace Microsoft.AspNetCore.Razor.Language } var prefix = prefixDirective?.DirectiveText; - if (prefix != null && !IsValidTagHelperPrefix(prefix, prefixDirective.Location, errorSink)) + if (prefix != null && !IsValidTagHelperPrefix(prefix, prefixDirective.Location, prefixDirective.Diagnostics)) { prefix = null; } @@ -112,8 +107,7 @@ namespace Microsoft.AspNetCore.Razor.Language internal IReadOnlyList ProcessDirectives( IReadOnlyList directives, - IReadOnlyList tagHelpers, - ErrorSink errorSink) + IReadOnlyList tagHelpers) { var matches = new HashSet(TagHelperDescriptorComparer.Default); @@ -126,7 +120,7 @@ namespace Microsoft.AspNetCore.Razor.Language { case TagHelperDirectiveType.AddTagHelper: - parsed = ParseAddOrRemoveDirective(directive, errorSink); + parsed = ParseAddOrRemoveDirective(directive); if (parsed == null) { // Skip this one, it's an error @@ -152,7 +146,7 @@ namespace Microsoft.AspNetCore.Razor.Language case TagHelperDirectiveType.RemoveTagHelper: - parsed = ParseAddOrRemoveDirective(directive, errorSink); + parsed = ParseAddOrRemoveDirective(directive); if (parsed == null) { // Skip this one, it's an error @@ -196,7 +190,7 @@ namespace Microsoft.AspNetCore.Razor.Language } // Internal for testing - internal ParsedDirective ParseAddOrRemoveDirective(TagHelperDirectiveDescriptor directive, ErrorSink errorSink) + internal ParsedDirective ParseAddOrRemoveDirective(TagHelperDirectiveDescriptor directive) { var text = directive.DirectiveText; var lookupStrings = text?.Split(new[] { ',' }); @@ -206,10 +200,12 @@ namespace Microsoft.AspNetCore.Razor.Language lookupStrings.Any(string.IsNullOrWhiteSpace) || lookupStrings.Length != 2) { - errorSink.OnError( - directive.Location, - Resources.FormatInvalidTagHelperLookupText(text), - Math.Max(text.Length, 1)); + directive.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + Resources.FormatInvalidTagHelperLookupText(text), + directive.Location, + Math.Max(text.Length, 1)))); return null; } @@ -238,20 +234,19 @@ namespace Microsoft.AspNetCore.Razor.Language internal bool IsValidTagHelperPrefix( string prefix, SourceLocation directiveLocation, - ErrorSink errorSink) + List diagnostics) { foreach (var character in prefix) { // Prefixes are correlated with tag names, tag names cannot have whitespace. if (char.IsWhiteSpace(character) || InvalidNonWhitespaceNameCharacters.Contains(character)) { - errorSink.OnError( - directiveLocation, - Resources.FormatInvalidTagHelperPrefixValue( - SyntaxConstants.CSharp.TagHelperPrefixKeyword, - character, - prefix), - prefix.Length); + diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + Resources.FormatInvalidTagHelperPrefixValue(SyntaxConstants.CSharp.TagHelperPrefixKeyword, character, prefix), + directiveLocation, + prefix.Length))); return false; } @@ -323,23 +318,27 @@ namespace Microsoft.AspNetCore.Razor.Language public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunkGenerator, Span span) { - Directives.Add(CreateDirective(span, chunkGenerator.LookupText, TagHelperDirectiveType.AddTagHelper)); + var directive = CreateDirective(span, chunkGenerator.LookupText, TagHelperDirectiveType.AddTagHelper, chunkGenerator.Diagnostics); + Directives.Add(directive); } public override void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunkGenerator, Span span) { - Directives.Add(CreateDirective(span, chunkGenerator.LookupText, TagHelperDirectiveType.RemoveTagHelper)); + var directive = CreateDirective(span, chunkGenerator.LookupText, TagHelperDirectiveType.RemoveTagHelper, chunkGenerator.Diagnostics); + Directives.Add(directive); } public override void VisitTagHelperPrefixDirectiveSpan(TagHelperPrefixDirectiveChunkGenerator chunkGenerator, Span span) { - Directives.Add(CreateDirective(span, chunkGenerator.Prefix, TagHelperDirectiveType.TagHelperPrefix)); + var directive = CreateDirective(span, chunkGenerator.Prefix, TagHelperDirectiveType.TagHelperPrefix, chunkGenerator.Diagnostics); + Directives.Add(directive); } private TagHelperDirectiveDescriptor CreateDirective( Span span, string directiveText, - TagHelperDirectiveType directiveType) + TagHelperDirectiveType directiveType, + List diagnostics) { directiveText = directiveText.Trim(); if (directiveText.Length >= 2 && @@ -375,6 +374,7 @@ namespace Microsoft.AspNetCore.Razor.Language DirectiveText = directiveText, Location = directiveStart, DirectiveType = directiveType, + Diagnostics = diagnostics, }; return directiveDescriptor; diff --git a/src/Microsoft.AspNetCore.Razor.Language/DirectiveRemovalIROptimizationPass.cs b/src/Microsoft.AspNetCore.Razor.Language/DirectiveRemovalIROptimizationPass.cs index 00a0935767..9902e01e78 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DirectiveRemovalIROptimizationPass.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DirectiveRemovalIROptimizationPass.cs @@ -15,19 +15,19 @@ namespace Microsoft.AspNetCore.Razor.Language var visitor = new Visitor(); visitor.VisitDocument(irDocument); - foreach (var (node, parent) in visitor.DirectiveNodes) + foreach (var nodeReference in visitor.DirectiveNodes) { - parent.Children.Remove(node); + nodeReference.Remove(); } } private class Visitor : RazorIRNodeWalker { - public IList<(DirectiveIRNode node, RazorIRNode parent)> DirectiveNodes { get; } = new List<(DirectiveIRNode node, RazorIRNode parent)>(); + public IList DirectiveNodes { get; } = new List(); public override void VisitDirective(DirectiveIRNode node) { - DirectiveNodes.Add((node, Parent)); + DirectiveNodes.Add(new RazorIRNodeReference(Parent, node)); } } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Intermediate/MalformedDirectiveIRNode.cs b/src/Microsoft.AspNetCore.Razor.Language/Intermediate/MalformedDirectiveIRNode.cs new file mode 100644 index 0000000000..4d21e4dcad --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/Intermediate/MalformedDirectiveIRNode.cs @@ -0,0 +1,45 @@ +// 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.Collections.Generic; +using System.Linq; + +namespace Microsoft.AspNetCore.Razor.Language.Intermediate +{ + public sealed class MalformedDirectiveIRNode : RazorIRNode + { + private RazorDiagnosticCollection _diagnostics; + + public override ItemCollection Annotations { get; } + + public override RazorDiagnosticCollection Diagnostics + { + get + { + if (_diagnostics == null) + { + _diagnostics = new DefaultDiagnosticCollection(); + } + + return _diagnostics; + } + } + + public override RazorIRNodeCollection Children { get; } = new DefaultIRNodeCollection(); + + public override SourceSpan? Source { get; set; } + + public override bool HasDiagnostics => _diagnostics != null && _diagnostics.Count > 0; + + public string Name { get; set; } + + public IEnumerable Tokens => Children.OfType(); + + public DirectiveDescriptor Descriptor { get; set; } + + public override void Accept(RazorIRNodeVisitor visitor) + { + visitor.VisitMalformedDirective(this); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Razor.Language/Intermediate/RazorIRNodeVisitor.cs b/src/Microsoft.AspNetCore.Razor.Language/Intermediate/RazorIRNodeVisitor.cs index ddb1e4d15b..8e9736370c 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Intermediate/RazorIRNodeVisitor.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Intermediate/RazorIRNodeVisitor.cs @@ -29,6 +29,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate VisitDefault(node); } + public virtual void VisitMalformedDirective(MalformedDirectiveIRNode node) + { + VisitDefault(node); + } + public virtual void VisitExtension(ExtensionIRNode node) { VisitDefault(node); diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/AddTagHelperChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/AddTagHelperChunkGenerator.cs index f682f87c87..92a43c2d50 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/AddTagHelperChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/AddTagHelperChunkGenerator.cs @@ -2,19 +2,24 @@ // 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.Linq; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Razor.Language.Legacy { internal class AddTagHelperChunkGenerator : SpanChunkGenerator { - public AddTagHelperChunkGenerator(string lookupText) + public AddTagHelperChunkGenerator(string lookupText, List diagnostics) { LookupText = lookupText; + Diagnostics = diagnostics; } public string LookupText { get; } + public List Diagnostics { get; } + public override void Accept(ParserVisitor visitor, Span span) { visitor.VisitAddTagHelperSpan(this, span); @@ -25,6 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { var other = obj as AddTagHelperChunkGenerator; return base.Equals(other) && + Enumerable.SequenceEqual(Diagnostics, other.Diagnostics) && string.Equals(LookupText, other.LookupText, StringComparison.Ordinal); } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs index 6d4d957b73..f85d6b2d46 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs @@ -91,11 +91,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { foreach (var directive in directives) { - _directiveParsers.Add(directive, () => - { - EnsureDirectiveIsAtStartOfLine(); - handler(); - }); + _directiveParsers.Add(directive, handler); Keywords.Add(directive); // These C# keywords are reserved for use in directives. It's an error to use them outside of @@ -1576,166 +1572,198 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy private void HandleDirective(DirectiveDescriptor descriptor) { - Context.Builder.CurrentBlock.Type = BlockKindInternal.Directive; - Context.Builder.CurrentBlock.ChunkGenerator = new DirectiveChunkGenerator(descriptor); AssertDirective(descriptor.Directive); - AcceptAndMoveNext(); - Output(SpanKindInternal.MetaCode, AcceptedCharactersInternal.None); + var directiveErrorSink = new ErrorSink(); + var savedErrorSink = Context.ErrorSink; + Context.ErrorSink = directiveErrorSink; - for (var i = 0; i < descriptor.Tokens.Count; i++) + var directiveChunkGenerator = new DirectiveChunkGenerator(descriptor); + try { - var tokenDescriptor = descriptor.Tokens[i]; - AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true)); + EnsureDirectiveIsAtStartOfLine(); - if (tokenDescriptor.Kind == DirectiveTokenKind.Member || - tokenDescriptor.Kind == DirectiveTokenKind.Namespace || - tokenDescriptor.Kind == DirectiveTokenKind.Type) + Context.Builder.CurrentBlock.Type = BlockKindInternal.Directive; + Context.Builder.CurrentBlock.ChunkGenerator = directiveChunkGenerator; + + AcceptAndMoveNext(); + Output(SpanKindInternal.MetaCode, AcceptedCharactersInternal.None); + + for (var i = 0; i < descriptor.Tokens.Count; i++) { - Span.ChunkGenerator = SpanChunkGenerator.Null; - Output(SpanKindInternal.Code, AcceptedCharactersInternal.WhiteSpace); - } - else - { - Span.ChunkGenerator = SpanChunkGenerator.Null; - Output(SpanKindInternal.Markup, AcceptedCharactersInternal.WhiteSpace); - } - - if (tokenDescriptor.Optional && (EndOfFile || At(CSharpSymbolType.NewLine))) - { - break; - } - else if (EndOfFile) - { - Context.ErrorSink.OnError( - CurrentStart, - LegacyResources.FormatUnexpectedEOFAfterDirective(descriptor.Directive, tokenDescriptor.Kind.ToString().ToLowerInvariant()), - length: 1); - return; - } - - switch (tokenDescriptor.Kind) - { - case DirectiveTokenKind.Type: - if (!NamespaceOrTypeName()) - { - Context.ErrorSink.OnError( - CurrentStart, - LegacyResources.FormatDirectiveExpectsTypeName(descriptor.Directive), - CurrentSymbol.Content.Length); - - return; - } - break; - - case DirectiveTokenKind.Namespace: - if (!QualifiedIdentifier(out var identifierLength)) - { - Context.ErrorSink.OnError( - CurrentStart, - LegacyResources.FormatDirectiveExpectsNamespace(descriptor.Directive), - identifierLength); - - return; - } - break; - - case DirectiveTokenKind.Member: - if (At(CSharpSymbolType.Identifier)) - { - AcceptAndMoveNext(); - } - else - { - Context.ErrorSink.OnError( - CurrentStart, - LegacyResources.FormatDirectiveExpectsIdentifier(descriptor.Directive), - CurrentSymbol.Content.Length); - return; - } - break; - - case DirectiveTokenKind.String: - if (At(CSharpSymbolType.StringLiteral) && CurrentSymbol.Errors.Count == 0) - { - AcceptAndMoveNext(); - } - else - { - Context.ErrorSink.OnError( - CurrentStart, - LegacyResources.FormatDirectiveExpectsQuotedStringLiteral(descriptor.Directive), - CurrentSymbol.Content.Length); - return; - } - break; - } - - Span.ChunkGenerator = new DirectiveTokenChunkGenerator(tokenDescriptor); - Span.EditHandler = new DirectiveTokenEditHandler(Language.TokenizeString); - Output(SpanKindInternal.Code, AcceptedCharactersInternal.NonWhiteSpace); - } - - AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true)); - Span.ChunkGenerator = SpanChunkGenerator.Null; - - switch (descriptor.Kind) - { - case DirectiveKind.SingleLine: - Optional(CSharpSymbolType.Semicolon); - AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true)); - - if (At(CSharpSymbolType.NewLine)) - { - AcceptAndMoveNext(); - } - else if (!EndOfFile) + if (!At(CSharpSymbolType.WhiteSpace) && + !At(CSharpSymbolType.NewLine) && + !EndOfFile) { Context.ErrorSink.OnError( CurrentStart, - LegacyResources.FormatUnexpectedDirectiveLiteral(descriptor.Directive, LegacyResources.ErrorComponent_Newline), - CurrentSymbol.Content.Length); + Resources.FormatDirectiveTokensMustBeSeparatedByWhitespace(descriptor.Directive), + length: CurrentSymbol.Content.Length); + return; } - Output(SpanKindInternal.MetaCode, AcceptedCharactersInternal.WhiteSpace); - break; - case DirectiveKind.RazorBlock: - AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: true)); - Output(SpanKindInternal.Markup, AcceptedCharactersInternal.AllWhiteSpace); + var tokenDescriptor = descriptor.Tokens[i]; + AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true)); - ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) => + if (tokenDescriptor.Kind == DirectiveTokenKind.Member || + tokenDescriptor.Kind == DirectiveTokenKind.Namespace || + tokenDescriptor.Kind == DirectiveTokenKind.Type) { - // When transitioning to the HTML parser we no longer want to act as if we're in a nested C# state. - // For instance, if
@hello.
is in a nested C# block we don't want the trailing '.' to be handled - // as C#; it should be handled as a period because it's wrapped in markup. - var wasNested = IsNested; - IsNested = false; + Span.ChunkGenerator = SpanChunkGenerator.Null; + Output(SpanKindInternal.Code, AcceptedCharactersInternal.WhiteSpace); + } + else + { + Span.ChunkGenerator = SpanChunkGenerator.Null; + Output(SpanKindInternal.Markup, AcceptedCharactersInternal.WhiteSpace); + } - using (PushSpanConfig()) + if (tokenDescriptor.Optional && (EndOfFile || At(CSharpSymbolType.NewLine))) + { + break; + } + else if (EndOfFile) + { + Context.ErrorSink.OnError( + CurrentStart, + LegacyResources.FormatUnexpectedEOFAfterDirective(descriptor.Directive, tokenDescriptor.Kind.ToString().ToLowerInvariant()), + length: 1); + return; + } + + switch (tokenDescriptor.Kind) + { + case DirectiveTokenKind.Type: + if (!NamespaceOrTypeName()) + { + Context.ErrorSink.OnError( + CurrentStart, + LegacyResources.FormatDirectiveExpectsTypeName(descriptor.Directive), + CurrentSymbol.Content.Length); + + return; + } + break; + + case DirectiveTokenKind.Namespace: + if (!QualifiedIdentifier(out var identifierLength)) + { + Context.ErrorSink.OnError( + CurrentStart, + LegacyResources.FormatDirectiveExpectsNamespace(descriptor.Directive), + identifierLength); + + return; + } + break; + + case DirectiveTokenKind.Member: + if (At(CSharpSymbolType.Identifier)) + { + AcceptAndMoveNext(); + } + else + { + Context.ErrorSink.OnError( + CurrentStart, + LegacyResources.FormatDirectiveExpectsIdentifier(descriptor.Directive), + CurrentSymbol.Content.Length); + return; + } + break; + + case DirectiveTokenKind.String: + if (At(CSharpSymbolType.StringLiteral) && CurrentSymbol.Errors.Count == 0) + { + AcceptAndMoveNext(); + } + else + { + Context.ErrorSink.OnError( + CurrentStart, + LegacyResources.FormatDirectiveExpectsQuotedStringLiteral(descriptor.Directive), + CurrentSymbol.Content.Length); + return; + } + break; + } + + Span.ChunkGenerator = new DirectiveTokenChunkGenerator(tokenDescriptor); + Span.EditHandler = new DirectiveTokenEditHandler(Language.TokenizeString); + Output(SpanKindInternal.Code, AcceptedCharactersInternal.NonWhiteSpace); + } + + AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true)); + Span.ChunkGenerator = SpanChunkGenerator.Null; + + switch (descriptor.Kind) + { + case DirectiveKind.SingleLine: + Optional(CSharpSymbolType.Semicolon); + AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true)); + + if (At(CSharpSymbolType.NewLine)) { - HtmlParser.ParseRazorBlock(Tuple.Create("{", "}"), caseSensitive: true); + AcceptAndMoveNext(); + } + else if (!EndOfFile) + { + Context.ErrorSink.OnError( + CurrentStart, + LegacyResources.FormatUnexpectedDirectiveLiteral(descriptor.Directive, LegacyResources.ErrorComponent_Newline), + CurrentSymbol.Content.Length); } - Span.Start = CurrentLocation; - Initialize(Span); + Output(SpanKindInternal.MetaCode, AcceptedCharactersInternal.WhiteSpace); + break; + case DirectiveKind.RazorBlock: + AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: true)); + Output(SpanKindInternal.Markup, AcceptedCharactersInternal.AllWhiteSpace); - IsNested = wasNested; + ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) => + { + // When transitioning to the HTML parser we no longer want to act as if we're in a nested C# state. + // For instance, if
@hello.
is in a nested C# block we don't want the trailing '.' to be handled + // as C#; it should be handled as a period because it's wrapped in markup. + var wasNested = IsNested; + IsNested = false; - NextToken(); - }); - break; - case DirectiveKind.CodeBlock: - AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: true)); - Output(SpanKindInternal.Markup, AcceptedCharactersInternal.AllWhiteSpace); + using (PushSpanConfig()) + { + HtmlParser.ParseRazorBlock(Tuple.Create("{", "}"), caseSensitive: true); + } - ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) => - { - NextToken(); - Balance(BalancingModes.NoErrorOnFailure, CSharpSymbolType.LeftBrace, CSharpSymbolType.RightBrace, startingBraceLocation); - Span.ChunkGenerator = new StatementChunkGenerator(); - Output(SpanKindInternal.Code); - }); - break; + Span.Start = CurrentLocation; + Initialize(Span); + + IsNested = wasNested; + + NextToken(); + }); + break; + case DirectiveKind.CodeBlock: + AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: true)); + Output(SpanKindInternal.Markup, AcceptedCharactersInternal.AllWhiteSpace); + + ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) => + { + NextToken(); + Balance(BalancingModes.NoErrorOnFailure, CSharpSymbolType.LeftBrace, CSharpSymbolType.RightBrace, startingBraceLocation); + Span.ChunkGenerator = new StatementChunkGenerator(); + Output(SpanKindInternal.Code); + }); + break; + } + } + finally + { + if (directiveErrorSink.Errors.Count > 0) + { + var directiveDiagnostics = directiveErrorSink.Errors.Select(error => RazorDiagnostic.Create(error)); + directiveChunkGenerator.Diagnostics.AddRange(directiveDiagnostics); + } + + Context.ErrorSink = savedErrorSink; } } @@ -1789,21 +1817,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { TagHelperDirective( SyntaxConstants.CSharp.TagHelperPrefixKeyword, - prefix => new TagHelperPrefixDirectiveChunkGenerator(prefix)); + (prefix, errors) => new TagHelperPrefixDirectiveChunkGenerator(prefix, errors)); } protected virtual void AddTagHelperDirective() { TagHelperDirective( SyntaxConstants.CSharp.AddTagHelperKeyword, - lookupText => new AddTagHelperChunkGenerator(lookupText)); + (lookupText, errors) => new AddTagHelperChunkGenerator(lookupText, errors)); } protected virtual void RemoveTagHelperDirective() { TagHelperDirective( SyntaxConstants.CSharp.RemoveTagHelperKeyword, - lookupText => new RemoveTagHelperChunkGenerator(lookupText)); + (lookupText, errors) => new RemoveTagHelperChunkGenerator(lookupText, errors)); } [Conditional("DEBUG")] @@ -1866,63 +1894,86 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Output(SpanKindInternal.Code, AcceptedCharactersInternal.AnyExceptNewline); } - private void TagHelperDirective(string keyword, Func chunkGeneratorFactory) + private void TagHelperDirective(string keyword, Func, ISpanChunkGenerator> chunkGeneratorFactory) { AssertDirective(keyword); - var keywordStartLocation = CurrentStart; - // Accept the directive name - AcceptAndMoveNext(); + var savedErrorSink = Context.ErrorSink; + var directiveErrorSink = new ErrorSink(); + Context.ErrorSink = directiveErrorSink; - // Set the block type - Context.Builder.CurrentBlock.Type = BlockKindInternal.Directive; - - var keywordLength = Span.End.AbsoluteIndex - Span.Start.AbsoluteIndex; - - var foundWhitespace = At(CSharpSymbolType.WhiteSpace); - AcceptWhile(CSharpSymbolType.WhiteSpace); - - // If we found whitespace then any content placed within the whitespace MAY cause a destructive change - // to the document. We can't accept it. - Output(SpanKindInternal.MetaCode, foundWhitespace ? AcceptedCharactersInternal.None : AcceptedCharactersInternal.AnyExceptNewline); - - ISpanChunkGenerator chunkGenerator; - if (EndOfFile || At(CSharpSymbolType.NewLine)) + string directiveValue = null; + try { - Context.ErrorSink.OnError( - keywordStartLocation, - LegacyResources.FormatParseError_DirectiveMustHaveValue(keyword), - keywordLength); + EnsureDirectiveIsAtStartOfLine(); - chunkGenerator = chunkGeneratorFactory(string.Empty); - } - else - { - // Need to grab the current location before we accept until the end of the line. - var startLocation = CurrentStart; + var keywordStartLocation = CurrentStart; - // Parse to the end of the line. Essentially accepts anything until end of line, comments, invalid code - // etc. - AcceptUntil(CSharpSymbolType.NewLine); + // Accept the directive name + AcceptAndMoveNext(); - // Pull out the value and remove whitespaces and optional quotes - var rawValue = string.Concat(Span.Symbols.Select(s => s.Content)).Trim(); + // Set the block type + Context.Builder.CurrentBlock.Type = BlockKindInternal.Directive; - var startsWithQuote = rawValue.StartsWith("\"", StringComparison.Ordinal); - var endsWithQuote = rawValue.EndsWith("\"", StringComparison.Ordinal); - if (startsWithQuote != endsWithQuote) + var keywordLength = Span.End.AbsoluteIndex - Span.Start.AbsoluteIndex; + + var foundWhitespace = At(CSharpSymbolType.WhiteSpace); + AcceptWhile(CSharpSymbolType.WhiteSpace); + + // If we found whitespace then any content placed within the whitespace MAY cause a destructive change + // to the document. We can't accept it. + Output(SpanKindInternal.MetaCode, foundWhitespace ? AcceptedCharactersInternal.None : AcceptedCharactersInternal.AnyExceptNewline); + + if (EndOfFile || At(CSharpSymbolType.NewLine)) { Context.ErrorSink.OnError( - startLocation, - LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(keyword), - rawValue.Length); + keywordStartLocation, + LegacyResources.FormatParseError_DirectiveMustHaveValue(keyword), + keywordLength); + + directiveValue = string.Empty; + } + else + { + // Need to grab the current location before we accept until the end of the line. + var startLocation = CurrentStart; + + // Parse to the end of the line. Essentially accepts anything until end of line, comments, invalid code + // etc. + AcceptUntil(CSharpSymbolType.NewLine); + + // Pull out the value and remove whitespaces and optional quotes + var rawValue = string.Concat(Span.Symbols.Select(s => s.Content)).Trim(); + + var startsWithQuote = rawValue.StartsWith("\"", StringComparison.Ordinal); + var endsWithQuote = rawValue.EndsWith("\"", StringComparison.Ordinal); + if (startsWithQuote != endsWithQuote) + { + Context.ErrorSink.OnError( + startLocation, + LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(keyword), + rawValue.Length); + } + + directiveValue = rawValue; + } + } + finally + { + List directiveErrors; + if (directiveErrorSink.Errors.Count > 0) + { + directiveErrors = directiveErrorSink.Errors.Select(RazorDiagnostic.Create).ToList(); + } + else + { + directiveErrors = new List(); } - chunkGenerator = chunkGeneratorFactory(rawValue); + Span.ChunkGenerator = chunkGeneratorFactory(directiveValue, directiveErrors); + Context.ErrorSink = savedErrorSink; } - Span.ChunkGenerator = chunkGenerator; - // Output the span and finish the block CompleteBlock(); Output(SpanKindInternal.Code, AcceptedCharactersInternal.AnyExceptNewline); diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/DirectiveChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/DirectiveChunkGenerator.cs index 4ed071400e..c584de9cc8 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/DirectiveChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/DirectiveChunkGenerator.cs @@ -2,6 +2,9 @@ // 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.Linq; +using System.Text; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Razor.Language.Legacy @@ -9,6 +12,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy internal class DirectiveChunkGenerator : ParentChunkGenerator { private static readonly Type Type = typeof(DirectiveChunkGenerator); + private List _diagnostics; public DirectiveChunkGenerator(DirectiveDescriptor descriptor) { @@ -17,6 +21,19 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy public DirectiveDescriptor Descriptor { get; } + public List Diagnostics + { + get + { + if (_diagnostics == null) + { + _diagnostics = new List(); + } + + return _diagnostics; + } + } + public override void Accept(ParserVisitor visitor, Block block) { visitor.VisitDirectiveBlock(this, block); @@ -26,6 +43,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { var other = obj as DirectiveChunkGenerator; return base.Equals(other) && + Enumerable.SequenceEqual(Diagnostics, other.Diagnostics) && DirectiveDescriptorComparer.Default.Equals(Descriptor, other.Descriptor); } @@ -37,5 +55,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return combiner.CombinedHash; } + + public override string ToString() + { + // This is used primarily at test time to show an identifiable representation of the chunk generator. + + var builder = new StringBuilder("Directive {"); + builder.Append(Descriptor.Directive); + builder.Append("}"); + + if (Diagnostics.Count > 0) + { + builder.Append(" ["); + var ids = string.Join(", ", Diagnostics.Select(diagnostic => diagnostic.Id)); + builder.Append(ids); + builder.Append("]"); + } + + return builder.ToString(); + } } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/ParserContext.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/ParserContext.cs index f12264df83..897504a300 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/ParserContext.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/ParserContext.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy public SyntaxTreeBuilder Builder { get; } - public ErrorSink ErrorSink { get; } + public ErrorSink ErrorSink { get; set; } public ITextDocument Source { get; } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/RemoveTagHelperChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/RemoveTagHelperChunkGenerator.cs index ac8df6da50..21bc2978e9 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/RemoveTagHelperChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/RemoveTagHelperChunkGenerator.cs @@ -2,19 +2,24 @@ // 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.Linq; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Razor.Language.Legacy { internal class RemoveTagHelperChunkGenerator : SpanChunkGenerator { - public RemoveTagHelperChunkGenerator(string lookupText) + public RemoveTagHelperChunkGenerator(string lookupText, List diagnostics) { LookupText = lookupText; + Diagnostics = diagnostics; } public string LookupText { get; } + public List Diagnostics { get; } + public override void Accept(ParserVisitor visitor, Span span) { visitor.VisitRemoveTagHelperSpan(this, span); @@ -25,6 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { var other = obj as RemoveTagHelperChunkGenerator; return base.Equals(other) && + Enumerable.SequenceEqual(Diagnostics, other.Diagnostics) && string.Equals(LookupText, other.LookupText, StringComparison.Ordinal); } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperDirectiveDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperDirectiveDescriptor.cs index b1fa4feeca..d5cb428fe3 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperDirectiveDescriptor.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperDirectiveDescriptor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; namespace Microsoft.AspNetCore.Razor.Language.Legacy { @@ -41,5 +42,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy /// The of this directive. /// public TagHelperDirectiveType DirectiveType { get; set; } + + public List Diagnostics { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperPrefixDirectiveChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperPrefixDirectiveChunkGenerator.cs index 1290988c8e..fae8d93ed8 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperPrefixDirectiveChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperPrefixDirectiveChunkGenerator.cs @@ -2,19 +2,24 @@ // 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.Linq; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Razor.Language.Legacy { internal class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator { - public TagHelperPrefixDirectiveChunkGenerator(string prefix) + public TagHelperPrefixDirectiveChunkGenerator(string prefix, List diagnostics) { Prefix = prefix; + Diagnostics = diagnostics; } public string Prefix { get; } + public List Diagnostics { get; } + public override void Accept(ParserVisitor visitor, Span span) { visitor.VisitTagHelperPrefixDirectiveSpan(this, span); @@ -25,6 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { var other = obj as TagHelperPrefixDirectiveChunkGenerator; return base.Equals(other) && + Enumerable.SequenceEqual(Diagnostics, other.Diagnostics) && string.Equals(Prefix, other.Prefix, StringComparison.Ordinal); } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Razor.Language/Properties/Resources.Designer.cs index 907fec1eeb..a041563555 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Properties/Resources.Designer.cs @@ -444,6 +444,20 @@ namespace Microsoft.AspNetCore.Razor.Language internal static string FormatDirectiveMustAppearAtStartOfLine(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("DirectiveMustAppearAtStartOfLine"), p0); + /// + /// The '{0}' directives value(s) must be separated by whitespace. + /// + internal static string DirectiveTokensMustBeSeparatedByWhitespace + { + get => GetString("DirectiveTokensMustBeSeparatedByWhitespace"); + } + + /// + /// The '{0}' directives value(s) must be separated by whitespace. + /// + internal static string FormatDirectiveTokensMustBeSeparatedByWhitespace(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("DirectiveTokensMustBeSeparatedByWhitespace"), p0); + /// /// The key must not be null. /// diff --git a/src/Microsoft.AspNetCore.Razor.Language/Resources.resx b/src/Microsoft.AspNetCore.Razor.Language/Resources.resx index 3f490ae2f9..5f1f9562d4 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Resources.resx +++ b/src/Microsoft.AspNetCore.Razor.Language/Resources.resx @@ -210,6 +210,9 @@ The '{0}` directive must appear at the start of the line. + + The '{0}' directives value(s) must be separated by whitespace. + The key must not be null. 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 c344a4f1f1..d8a93ef060 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs @@ -28,10 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.IntegrationTests public void InvalidNamespaceAtEOF_Runtime() { var references = CreateCompilationReferences(CurrentMvcShim); - RunRuntimeTest(references, expectedErrors: new[] - { - "Identifier expected" - }); + RunRuntimeTest(references); } [Fact] @@ -44,10 +41,7 @@ public class MyService }"; var compilationReferences = CreateCompilationReferences(CurrentMvcShim, appCode); - RunRuntimeTest(compilationReferences, expectedErrors: new[] - { - "Identifier expected" - }); + RunRuntimeTest(compilationReferences); } [Fact] @@ -267,7 +261,7 @@ public class AllTagHelper : {typeof(TagHelper).FullName} public void InvalidNamespaceAtEOF_DesignTime() { var references = CreateCompilationReferences(CurrentMvcShim); - RunDesignTimeTest(references, expectedErrors: new[] { "Identifier expected" }); + RunDesignTimeTest(references); } [Fact] @@ -281,12 +275,7 @@ public class MyService "; var references = CreateCompilationReferences(CurrentMvcShim, appCode); - RunDesignTimeTest( - references, - expectedErrors: new[] - { - "Identifier expected" - }); + RunDesignTimeTest(references); } [Fact] diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/PageDirectiveTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/PageDirectiveTest.cs index 428dd51f71..8380727b3c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/PageDirectiveTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/PageDirectiveTest.cs @@ -1,6 +1,7 @@ // 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 Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; using Xunit; @@ -9,24 +10,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { public class PageDirectiveTest { - [Fact] - public void TryGetPageDirective_CanHandleMalformedPageDirectives() - { - // Arrange - var content = "@page \""; - var sourceDocument = RazorSourceDocument.Create(content, "file"); - var codeDocument = RazorCodeDocument.Create(sourceDocument); - var engine = CreateEngine(); - var irDocument = CreateIRDocument(engine, codeDocument); - - // Act - var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective); - - // Assert - Assert.True(result); - Assert.Null(pageDirective.RouteTemplate); - } - [Fact] public void TryGetPageDirective_ReturnsFalse_IfPageDoesNotHaveDirective() { diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.codegen.cs index c5ce5a2371..aeeda90034 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.codegen.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.codegen.cs @@ -1,4 +1,5 @@ -namespace +[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_IncompleteDirectives_cshtml), null)] +namespace AspNetCore { #line hidden using TModel = global::System.Object; diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.ir.txt index a4e629b53d..968878a06f 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.ir.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.ir.txt @@ -1,5 +1,7 @@ Document - - NamespaceDeclaration - - + CSharpCode - + RazorIRToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_IncompleteDirectives_cshtml), null)] + NamespaceDeclaration - - AspNetCore UsingStatement - - TModel = global::System.Object UsingStatement - (1:0,1 [12] ) - System UsingStatement - (16:1,1 [32] ) - System.Collections.Generic @@ -29,20 +31,29 @@ Document - MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml) RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n + MalformedDirective - (102:4,0 [6] IncompleteDirectives.cshtml) HtmlContent - (108:4,6 [5] IncompleteDirectives.cshtml) RazorIRToken - (108:4,6 [5] IncompleteDirectives.cshtml) - Html - "\n\n + MalformedDirective - (113:6,0 [6] IncompleteDirectives.cshtml) HtmlContent - (119:6,6 [2] IncompleteDirectives.cshtml) RazorIRToken - (119:6,6 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (121:7,0 [7] IncompleteDirectives.cshtml) HtmlContent - (128:7,7 [4] IncompleteDirectives.cshtml) RazorIRToken - (128:7,7 [4] IncompleteDirectives.cshtml) - Html - \n\n + MalformedDirective - (132:9,0 [7] IncompleteDirectives.cshtml) HtmlContent - (139:9,7 [2] IncompleteDirectives.cshtml) RazorIRToken - (139:9,7 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (141:10,0 [8] IncompleteDirectives.cshtml) HtmlContent - (149:10,8 [2] IncompleteDirectives.cshtml) RazorIRToken - (149:10,8 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (151:11,0 [25] IncompleteDirectives.cshtml) + DirectiveToken - (159:11,8 [17] IncompleteDirectives.cshtml) - MyService HtmlContent - (176:11,25 [4] IncompleteDirectives.cshtml) RazorIRToken - (176:11,25 [4] IncompleteDirectives.cshtml) - Html - \n\n + MalformedDirective - (180:13,0 [10] IncompleteDirectives.cshtml) HtmlContent - (190:13,10 [2] IncompleteDirectives.cshtml) RazorIRToken - (190:13,10 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (192:14,0 [11] IncompleteDirectives.cshtml) HtmlContent - (203:14,11 [2] IncompleteDirectives.cshtml) RazorIRToken - (203:14,11 [2] IncompleteDirectives.cshtml) - Html - \n InjectDirective - diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.mappings.txt index da2d5f1fc3..23f8a7d6f5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.mappings.txt @@ -1,5 +1,5 @@ Source Location: (159:11,8 [17] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives.cshtml) |MyService| -Generated Location: (616:16,0 [17] ) +Generated Location: (833:17,0 [17] ) |MyService| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.codegen.cs index 99292e76b0..5488bac509 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.codegen.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.codegen.cs @@ -1,5 +1,6 @@ #pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "fec5cf763044f842fa2114e997bb07e0bf280cd6" -namespace +[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_IncompleteDirectives_cshtml), null)] +namespace AspNetCore { #line hidden using System; diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.ir.txt index 3727695b5e..8256aa1e47 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.ir.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.ir.txt @@ -1,5 +1,7 @@ Document - - NamespaceDeclaration - - + CSharpCode - + RazorIRToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_IncompleteDirectives_cshtml), null)] + NamespaceDeclaration - - AspNetCore UsingStatement - (1:0,1 [14] ) - System UsingStatement - (16:1,1 [34] ) - System.Collections.Generic UsingStatement - (51:2,1 [19] ) - System.Linq @@ -15,48 +17,57 @@ Document - RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n CSharpCode - RazorIRToken - - CSharp - EndContext(); + MalformedDirective - (102:4,0 [6] IncompleteDirectives.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(108, 5, true); HtmlContent - (108:4,6 [5] IncompleteDirectives.cshtml) RazorIRToken - (108:4,6 [5] IncompleteDirectives.cshtml) - Html - "\n\n CSharpCode - RazorIRToken - - CSharp - EndContext(); + MalformedDirective - (113:6,0 [6] IncompleteDirectives.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(119, 2, true); HtmlContent - (119:6,6 [2] IncompleteDirectives.cshtml) RazorIRToken - (119:6,6 [2] IncompleteDirectives.cshtml) - Html - \n CSharpCode - RazorIRToken - - CSharp - EndContext(); + MalformedDirective - (121:7,0 [7] IncompleteDirectives.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(128, 4, true); HtmlContent - (128:7,7 [4] IncompleteDirectives.cshtml) RazorIRToken - (128:7,7 [4] IncompleteDirectives.cshtml) - Html - \n\n CSharpCode - RazorIRToken - - CSharp - EndContext(); + MalformedDirective - (132:9,0 [7] IncompleteDirectives.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(139, 2, true); HtmlContent - (139:9,7 [2] IncompleteDirectives.cshtml) RazorIRToken - (139:9,7 [2] IncompleteDirectives.cshtml) - Html - \n CSharpCode - RazorIRToken - - CSharp - EndContext(); + MalformedDirective - (141:10,0 [8] IncompleteDirectives.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(149, 2, true); HtmlContent - (149:10,8 [2] IncompleteDirectives.cshtml) RazorIRToken - (149:10,8 [2] IncompleteDirectives.cshtml) - Html - \n CSharpCode - RazorIRToken - - CSharp - EndContext(); + MalformedDirective - (151:11,0 [25] IncompleteDirectives.cshtml) + DirectiveToken - (159:11,8 [17] IncompleteDirectives.cshtml) - MyService CSharpCode - RazorIRToken - - CSharp - BeginContext(176, 4, true); HtmlContent - (176:11,25 [4] IncompleteDirectives.cshtml) RazorIRToken - (176:11,25 [4] IncompleteDirectives.cshtml) - Html - \n\n CSharpCode - RazorIRToken - - CSharp - EndContext(); + MalformedDirective - (180:13,0 [10] IncompleteDirectives.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(190, 2, true); HtmlContent - (190:13,10 [2] IncompleteDirectives.cshtml) RazorIRToken - (190:13,10 [2] IncompleteDirectives.cshtml) - Html - \n CSharpCode - RazorIRToken - - CSharp - EndContext(); + MalformedDirective - (192:14,0 [11] IncompleteDirectives.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(203, 2, true); HtmlContent - (203:14,11 [2] IncompleteDirectives.cshtml) 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 index 0dd729a78d..e8fd02493b 100644 --- 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 @@ -1,4 +1,5 @@ -namespace +[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml))] +namespace AspNetCore { #line hidden using TModel = global::System.Object; 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 index 018ac0cb2c..4bd04cdb6d 100644 --- 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 @@ -1,5 +1,7 @@ Document - - NamespaceDeclaration - - + CSharpCode - + RazorIRToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml))] + NamespaceDeclaration - - AspNetCore UsingStatement - - TModel = global::System.Object UsingStatement - (1:0,1 [12] ) - System UsingStatement - (16:1,1 [32] ) - System.Collections.Generic @@ -26,6 +28,7 @@ Document - CSharpCode - RazorIRToken - - CSharp - private static System.Object __o = null; MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + MalformedDirective - (0:0,0 [11] InvalidNamespaceAtEOF.cshtml) HtmlContent - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) RazorIRToken - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) - Html - Test. InjectDirective - 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 index 0e8e0f2afd..8f1f15dd85 100644 --- 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 @@ -1,5 +1,6 @@ #pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "de132bd3e2a46a0d2ec953a168427c01e5829cde" -namespace +[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml))] +namespace AspNetCore { #line hidden using System; 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 index 28ffcc6237..9b586b65a0 100644 --- 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 @@ -1,5 +1,7 @@ Document - - NamespaceDeclaration - - + CSharpCode - + RazorIRToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml))] + NamespaceDeclaration - - AspNetCore UsingStatement - (1:0,1 [14] ) - System UsingStatement - (16:1,1 [34] ) - System.Collections.Generic UsingStatement - (51:2,1 [19] ) - System.Linq @@ -9,6 +11,7 @@ Document - 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 + MalformedDirective - (0:0,0 [11] InvalidNamespaceAtEOF.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(11, 5, true); HtmlContent - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.codegen.cs index 1cff6891cd..8f021837e1 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.codegen.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.codegen.cs @@ -1,4 +1,4 @@ -[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml), null)] +[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml))] namespace AspNetCore { #line hidden @@ -10,7 +10,7 @@ namespace AspNetCore using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; - public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.RazorPages.Page + public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage { #pragma warning disable 219 private void __RazorDirectiveTokenHelpers__() { @@ -31,8 +31,6 @@ namespace AspNetCore [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; } - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model; + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.ir.txt index 9ae80d1571..838720effa 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.ir.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_DesignTime.ir.txt @@ -1,6 +1,6 @@ Document - CSharpCode - - RazorIRToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml), null)] + RazorIRToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml))] NamespaceDeclaration - - AspNetCore UsingStatement - - TModel = global::System.Object UsingStatement - (1:0,1 [12] ) - System @@ -10,7 +10,7 @@ Document - 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_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.RazorPages.Page - + ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_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 @@ -28,6 +28,7 @@ Document - CSharpCode - RazorIRToken - - CSharp - private static System.Object __o = null; MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + MalformedDirective - (0:0,0 [6] MalformedPageDirective.cshtml) HtmlContent - (6:0,6 [49] MalformedPageDirective.cshtml) RazorIRToken - (6:0,6 [8] MalformedPageDirective.cshtml) - Html - "foo\n\n RazorIRToken - (14:2,0 [4] MalformedPageDirective.cshtml) - Html -

@@ -42,7 +43,3 @@ Document - InjectDirective - InjectDirective - InjectDirective - - CSharpCode - - RazorIRToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; - CSharpCode - - RazorIRToken - - CSharp - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model; diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.codegen.cs index ed46639a5d..faf92d5caf 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.codegen.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.codegen.cs @@ -1,5 +1,5 @@ #pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "5a9ff8440150c6746e4a8ba63bc633ea84930405" -[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml), null)] +[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml))] namespace AspNetCore { #line hidden @@ -10,7 +10,7 @@ namespace AspNetCore using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; - public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.RazorPages.Page + public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage { #pragma warning disable 1998 public async override global::System.Threading.Tasks.Task ExecuteAsync() @@ -29,8 +29,6 @@ namespace AspNetCore [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; } - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model; + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.ir.txt index 9d5a94fd61..fecda65a8c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.ir.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective_Runtime.ir.txt @@ -1,6 +1,6 @@ Document - CSharpCode - - RazorIRToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml), null)] + RazorIRToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(null, typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml))] NamespaceDeclaration - - AspNetCore UsingStatement - (1:0,1 [14] ) - System UsingStatement - (16:1,1 [34] ) - System.Collections.Generic @@ -9,8 +9,9 @@ Document - 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_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.RazorPages.Page - + ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage - MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + MalformedDirective - (0:0,0 [6] MalformedPageDirective.cshtml) CSharpCode - RazorIRToken - - CSharp - BeginContext(6, 49, true); HtmlContent - (6:0,6 [49] MalformedPageDirective.cshtml) @@ -29,7 +30,3 @@ Document - InjectDirective - InjectDirective - InjectDirective - - CSharpCode - - RazorIRToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; - CSharpCode - - RazorIRToken - - CSharp - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model; diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs index 8d1fa6f084..c264bbf92b 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Text; using Microsoft.AspNetCore.Razor.Language.Legacy; using Xunit; -using Moq; namespace Microsoft.AspNetCore.Razor.Language { @@ -39,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Language new SourceLocation(14 + Environment.NewLine.Length, 1, 14), length: 1)) }; - + var content = @" @@ -54,7 +53,9 @@ namespace Microsoft.AspNetCore.Razor.Language // Assert var rewrittenTree = codeDocument.GetSyntaxTree(); - Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); + var directiveValue = rewrittenTree.Root.Children.OfType().First().Children.Last() as Span; + var chunkGenerator = Assert.IsType(directiveValue.ChunkGenerator); + Assert.Equal(expectedDiagnostics, chunkGenerator.Diagnostics); } [Fact] @@ -98,7 +99,9 @@ namespace Microsoft.AspNetCore.Razor.Language // Assert var rewrittenTree = codeDocument.GetSyntaxTree(); - Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); + var directiveValue = rewrittenTree.Root.Children.OfType().First().Children.Last() as Span; + var chunkGenerator = Assert.IsType(directiveValue.ChunkGenerator); + Assert.Equal(expectedDiagnostics, chunkGenerator.Diagnostics); } [Fact] @@ -142,7 +145,9 @@ namespace Microsoft.AspNetCore.Razor.Language // Assert var rewrittenTree = codeDocument.GetSyntaxTree(); - Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); + var directiveValue = rewrittenTree.Root.Children.OfType().First().Children.Last() as Span; + var chunkGenerator = Assert.IsType(directiveValue.ChunkGenerator); + Assert.Equal(expectedDiagnostics, chunkGenerator.Diagnostics); } [Fact] @@ -464,7 +469,6 @@ namespace Microsoft.AspNetCore.Razor.Language public void ParseAddOrRemoveDirective_CalculatesAssemblyLocationInLookupText(string text, int assemblyLocation) { // Arrange - var errorSink = new ErrorSink(); var phase = new DefaultRazorTagHelperBinderPhase(); var directive = new TagHelperDirectiveDescriptor() @@ -472,15 +476,16 @@ namespace Microsoft.AspNetCore.Razor.Language DirectiveText = text, DirectiveType = TagHelperDirectiveType.AddTagHelper, Location = SourceLocation.Zero, + Diagnostics = new List(), }; var expected = new SourceLocation(assemblyLocation, 0, assemblyLocation); // Act - var result = phase.ParseAddOrRemoveDirective(directive, errorSink); + var result = phase.ParseAddOrRemoveDirective(directive); // Assert - Assert.Empty(errorSink.Errors); + Assert.Empty(directive.Diagnostics); Assert.Equal("foo", result.TypePattern); Assert.Equal("assemblyName", result.AssemblyName); Assert.Equal(expected, result.AssemblyNameLocation); @@ -505,7 +510,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = "th ", Location = directiveLocation1, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix + DirectiveType = TagHelperDirectiveType.TagHelperPrefix, + Diagnostics = new List(), }, }, new[] @@ -527,7 +533,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = "th\t", Location = directiveLocation1, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix + DirectiveType = TagHelperDirectiveType.TagHelperPrefix, + Diagnostics = new List(), } }, new[] @@ -549,7 +556,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = "th" + Environment.NewLine, Location = directiveLocation1, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix + DirectiveType = TagHelperDirectiveType.TagHelperPrefix, + Diagnostics = new List(), } }, new[] @@ -571,7 +579,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = " th ", Location = directiveLocation1, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix + DirectiveType = TagHelperDirectiveType.TagHelperPrefix, + Diagnostics = new List(), } }, new[] @@ -593,7 +602,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = "@", Location = directiveLocation1, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix + DirectiveType = TagHelperDirectiveType.TagHelperPrefix, + Diagnostics = new List(), } }, new[] @@ -615,7 +625,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = "t@h", Location = directiveLocation1, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix + DirectiveType = TagHelperDirectiveType.TagHelperPrefix, + Diagnostics = new List(), } }, new[] @@ -637,7 +648,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = "!", Location = directiveLocation1, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix + DirectiveType = TagHelperDirectiveType.TagHelperPrefix, + Diagnostics = new List(), } }, new[] @@ -659,7 +671,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = "!th", Location = directiveLocation1, - DirectiveType = TagHelperDirectiveType.TagHelperPrefix + DirectiveType = TagHelperDirectiveType.TagHelperPrefix, + Diagnostics = new List(), } }, new[] @@ -685,18 +698,18 @@ namespace Microsoft.AspNetCore.Razor.Language object expectedErrors) { // Arrange - var errorSink = new ErrorSink(); - + var expectedDiagnostics = ((IEnumerable)expectedErrors).Select(RazorDiagnostic.Create); + var tagHelperDirectives = (IEnumerable)directives; var phase = new DefaultRazorTagHelperBinderPhase(); // Act - foreach (var directive in ((IEnumerable)directives)) + foreach (var directive in tagHelperDirectives) { - Assert.False(phase.IsValidTagHelperPrefix(directive.DirectiveText, directive.Location, errorSink)); + Assert.False(phase.IsValidTagHelperPrefix(directive.DirectiveText, directive.Location, directive.Diagnostics)); } // Assert - Assert.Equal(((IEnumerable)expectedErrors).ToArray(), errorSink.Errors.ToArray()); + Assert.Equal(expectedDiagnostics, tagHelperDirectives.SelectMany(directive => directive.Diagnostics)); } private static string AssemblyA => "TestAssembly"; @@ -836,15 +849,15 @@ namespace Microsoft.AspNetCore.Razor.Language string expectedPrefix) { // Arrange - var errorSink = new ErrorSink(); var phase = new DefaultRazorTagHelperBinderPhase(); var document = RazorCodeDocument.Create(new StringSourceDocument("Test content", encoding: Encoding.UTF8, filePath: "TestFile")); + var tagHelperDirectives = (IEnumerable)directiveDescriptors; // Act - var prefix = phase.ProcessTagHelperPrefix(((IEnumerable)directiveDescriptors).ToList(), document, errorSink); + var prefix = phase.ProcessTagHelperPrefix(((IEnumerable)directiveDescriptors).ToList(), document); // Assert - Assert.Empty(errorSink.Errors); + Assert.Empty(tagHelperDirectives.SelectMany(directive => directive.Diagnostics)); Assert.Equal(expectedPrefix, prefix); } @@ -1056,20 +1069,17 @@ namespace Microsoft.AspNetCore.Razor.Language object expectedDescriptors) { // Arrange - var errorSink = new ErrorSink(); - var phase = new DefaultRazorTagHelperBinderPhase(); - + var tagHelperDirectives = (IEnumerable)directiveDescriptors; var expected = (IEnumerable)expectedDescriptors; // Act var results = phase.ProcessDirectives( - new List((IEnumerable)directiveDescriptors), - new List((IEnumerable)tagHelpers), - errorSink); + new List(tagHelperDirectives), + new List((IEnumerable)tagHelpers)); // Assert - Assert.Empty(errorSink.Errors); + Assert.Empty(tagHelperDirectives.SelectMany(directive => directive.Diagnostics)); Assert.Equal(expected.Count(), results.Count()); foreach (var expectedDescriptor in expected) @@ -1224,15 +1234,13 @@ namespace Microsoft.AspNetCore.Razor.Language object directiveDescriptors) { // Arrange - var errorSink = new ErrorSink(); - + var tagHelperDirectives = (IEnumerable)directiveDescriptors; var phase = new DefaultRazorTagHelperBinderPhase(); // Act var results = phase.ProcessDirectives( - new List((IEnumerable)directiveDescriptors), - new List((IEnumerable)tagHelpers), - errorSink); + new List(tagHelperDirectives), + new List((IEnumerable)tagHelpers)); // Assert Assert.Empty(results); @@ -1264,26 +1272,24 @@ namespace Microsoft.AspNetCore.Razor.Language public void ProcessDirectives_IgnoresSpaces(string directiveText) { // Arrange - var errorSink = new ErrorSink(); var phase = new DefaultRazorTagHelperBinderPhase(); - var directives = new[] { - new TagHelperDirectiveDescriptor() - { - DirectiveText = directiveText, - DirectiveType = TagHelperDirectiveType.AddTagHelper, - } - }; + new TagHelperDirectiveDescriptor() + { + DirectiveText = directiveText, + DirectiveType = TagHelperDirectiveType.AddTagHelper, + Diagnostics = new List(), + } + }; // Act var results = phase.ProcessDirectives( directives, - new[] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor }, - errorSink); + new[] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor }); // Assert - Assert.Empty(errorSink.Errors); + Assert.Empty(directives[0].Diagnostics); var single = Assert.Single(results); Assert.Equal(Valid_PlainTagHelperDescriptor, single, TagHelperDescriptorComparer.Default); @@ -1305,7 +1311,6 @@ namespace Microsoft.AspNetCore.Razor.Language public void DescriptorResolver_CreatesErrorIfInvalidLookupText_DoesNotThrow(string directiveText, int errorLength) { // Arrange - var errorSink = new ErrorSink(); var phase = new DefaultRazorTagHelperBinderPhase(); var directive = new TagHelperDirectiveDescriptor() @@ -1313,6 +1318,7 @@ namespace Microsoft.AspNetCore.Razor.Language DirectiveText = directiveText, DirectiveType = TagHelperDirectiveType.AddTagHelper, Location = new SourceLocation(1, 2, 3), + Diagnostics = new List(), }; var expectedErrorMessage = string.Format( @@ -1320,16 +1326,21 @@ namespace Microsoft.AspNetCore.Razor.Language "format is: \"typeName, assemblyName\".", directiveText); + var expectedError = RazorDiagnostic.Create( + new RazorError( + expectedErrorMessage, + new SourceLocation(1, 2, 3), + errorLength)); + + // Act - var result = phase.ParseAddOrRemoveDirective(directive, errorSink); + var result = phase.ParseAddOrRemoveDirective(directive); // Assert Assert.Null(result); - var error = Assert.Single(errorSink.Errors); - Assert.Equal(errorLength, error.Length); - Assert.Equal(new SourceLocation(1, 2, 3), error.Location); - Assert.Equal(expectedErrorMessage, error.Message); + var error = Assert.Single(directive.Diagnostics); + Assert.Equal(expectedError, error); } private static TagHelperDescriptor CreatePrefixedValidPlainDescriptor(string prefix) @@ -1367,7 +1378,8 @@ namespace Microsoft.AspNetCore.Razor.Language { DirectiveText = directiveText, Location = SourceLocation.Zero, - DirectiveType = directiveType + DirectiveType = directiveType, + Diagnostics = new List(), }; } @@ -1404,7 +1416,8 @@ namespace Microsoft.AspNetCore.Razor.Language { foreach (var ruleBuilder in ruleBuilders) { - builder.TagMatchingRule(innerRuleBuilder => { + builder.TagMatchingRule(innerRuleBuilder => + { innerRuleBuilder.RequireTagName(tagName); ruleBuilder(innerRuleBuilder); }); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs index c5cd5ec692..9f0e9f1fba 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpAutoCompleteTest.cs @@ -13,25 +13,42 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void FunctionsDirectiveAutoCompleteAtEOF() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(FunctionsDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(FunctionsDirective.Directive.Directive, "}", "{"), + new SourceLocation(10, 0, 10), + length: 1))); + + // Act & Assert ParseBlockTest( "@functions{", - new[] { FunctionsDirective.Directive, }, - new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), + new[] { FunctionsDirective.Directive }, + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), - Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None)), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(FunctionsDirective.Directive.Directive, "}", "{"), - new SourceLocation(10, 0, 10), - length: 1)); + Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None))); } [Fact] public void SectionDirectiveAutoCompleteAtEOF() { - ParseBlockTest("@section Header {", - new[] { SectionDirective.Directive, }, - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), + new SourceLocation(16, 0, 16), + length: 1))); + + // Act & Assert + ParseBlockTest( + "@section Header {", + new[] { SectionDirective.Directive }, + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -40,55 +57,67 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( - Factory.EmptyHtml())), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), - new SourceLocation(16, 0, 16), - length: 1)); + Factory.EmptyHtml()))); } [Fact] public void VerbatimBlockAutoCompleteAtEOF() { ParseBlockTest("@{", - new StatementBlock( - Factory.CodeTransition(), - Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None), - Factory.EmptyCSharp() - .AsStatement() - .With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }) - ), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF( - LegacyResources.BlockName_Code, "}", "{"), - new SourceLocation(1, 0, 1), - length: 1)); + new StatementBlock( + Factory.CodeTransition(), + Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None), + Factory.EmptyCSharp() + .AsStatement() + .With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }) + ), + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF( + LegacyResources.BlockName_Code, "}", "{"), + new SourceLocation(1, 0, 1), + length: 1)); } [Fact] public void FunctionsDirectiveAutoCompleteAtStartOfFile() { - ParseBlockTest( - "@functions{" + Environment.NewLine + "foo", - new[] { FunctionsDirective.Directive, }, - new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), - Factory.CodeTransition(), - Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), - Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), - Factory.Code(Environment.NewLine + "foo").AsStatement()), + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(FunctionsDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( new RazorError( LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"), new SourceLocation(10, 0, 10), - length: 1)); + length: 1))); + + // Act & Assert + ParseBlockTest( + "@functions{" + Environment.NewLine + "foo", + new[] { FunctionsDirective.Directive }, + new DirectiveBlock(chunkGenerator, + Factory.CodeTransition(), + Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), + Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), + Factory.Code(Environment.NewLine + "foo").AsStatement())); } [Fact] public void SectionDirectiveAutoCompleteAtStartOfFile() { - ParseBlockTest("@section Header {" + Environment.NewLine - + "

Foo

", - new[] { SectionDirective.Directive, }, - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), + new SourceLocation(16, 0, 16), + length: 1))); + + // Act & Assert + ParseBlockTest( + "@section Header {" + Environment.NewLine + "

Foo

", + new[] { SectionDirective.Directive }, + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -101,37 +130,33 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Markup("

")), Factory.Markup("Foo"), new MarkupTagBlock( - Factory.Markup("

")))), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), - new SourceLocation(16, 0, 16), - length: 1)); + Factory.Markup("

"))))); } [Fact] public void VerbatimBlockAutoCompleteAtStartOfFile() { - ParseBlockTest("@{" + Environment.NewLine - + "

", - new StatementBlock( - Factory.CodeTransition(), - Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None), - Factory.Code(Environment.NewLine) - .AsStatement() - .With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }), - new MarkupBlock( - new MarkupTagBlock( - Factory.Markup("

").Accepts(AcceptedCharactersInternal.None)), - new MarkupTagBlock( - Factory.Markup("

").Accepts(AcceptedCharactersInternal.None))), - Factory.Span(SpanKindInternal.Code, new CSharpSymbol(string.Empty, CSharpSymbolType.Unknown)) - .With(new StatementChunkGenerator()) - ), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF( - LegacyResources.BlockName_Code, "}", "{"), - new SourceLocation(1, 0, 1), - length: 1)); + ParseBlockTest( + "@{" + Environment.NewLine + "

", + new StatementBlock( + Factory.CodeTransition(), + Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None), + Factory.Code(Environment.NewLine) + .AsStatement() + .With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }), + new MarkupBlock( + new MarkupTagBlock( + Factory.Markup("

").Accepts(AcceptedCharactersInternal.None)), + new MarkupTagBlock( + Factory.Markup("

").Accepts(AcceptedCharactersInternal.None))), + Factory.Span(SpanKindInternal.Code, new CSharpSymbol(string.Empty, CSharpSymbolType.Unknown)) + .With(new StatementChunkGenerator()) + ), + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF( + LegacyResources.BlockName_Code, "}", "{"), + new SourceLocation(1, 0, 1), + length: 1)); } } } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs index 903ecd7033..4c48b7a8de 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs @@ -11,6 +11,32 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { public class CSharpDirectivesTest : CsHtmlCodeParserTestBase { + [Fact] + public void DirectiveDescriptor_TokensMustBeSeparatedBySpace() + { + // Arrange + var descriptor = DirectiveDescriptor.CreateDirective( + "custom", + DirectiveKind.SingleLine, + b => b.AddStringToken().AddStringToken()); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + Resources.FormatDirectiveTokensMustBeSeparatedByWhitespace("custom"), + 17, 0, 17, 9))); + + // Act & Assert + ParseCodeBlockTest( + "@custom \"string1\"\"string2\"", + new[] { descriptor }, + new DirectiveBlock(chunkGenerator, + Factory.CodeTransition(), + Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), + Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), + Factory.Span(SpanKindInternal.Code, "\"string1\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); + } + [Fact] public void DirectiveDescriptor_CanHandleEOFIncompleteNamespaceTokens() { @@ -19,19 +45,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsNamespace("custom"), + 8, 0, 8, 7))); // Act & Assert ParseCodeBlockTest( "@custom System.", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), - new RazorError( - LegacyResources.FormatDirectiveExpectsNamespace("custom"), - 8, 0, 8, 7)); + Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -42,19 +70,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsNamespace("custom"), + 8, 0, 8, 7))); // Act & Assert ParseCodeBlockTest( "@custom System<", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), - new RazorError( - LegacyResources.FormatDirectiveExpectsNamespace("custom"), - 8, 0, 8, 7)); + Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] public void DirectiveDescriptor_CanHandleIncompleteNamespaceTokens() @@ -64,19 +94,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsNamespace("custom"), + 8, 0, 8, 7))); // Act & Assert ParseCodeBlockTest( "@custom System." + Environment.NewLine, new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), - new RazorError( - LegacyResources.FormatDirectiveExpectsNamespace("custom"), - 8, 0, 8, 7)); + Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -87,19 +119,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsNamespace("custom"), + 8, 0, 8, 7))); // Act & Assert ParseCodeBlockTest( "@custom System<" + Environment.NewLine, new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), - new RazorError( - LegacyResources.FormatDirectiveExpectsNamespace("custom"), - 8, 0, 8, 7)); + Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -154,13 +188,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"*, Foo\"") - .AsAddTagHelper("\"*, Foo\"")), + .AsAddTagHelper( + "\"*, Foo\"", + new RazorError(Resources.FormatDirectiveMustAppearAtStartOfLine("addTagHelper"), new SourceLocation(4, 0, 4), 12))), Factory.Code(Environment.NewLine).AsStatement(), - Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), - new RazorError( - Resources.FormatDirectiveMustAppearAtStartOfLine("addTagHelper"), - new SourceLocation(4, 0, 4), - 12)); + Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None))); } [Fact] @@ -171,6 +203,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddTypeToken()); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + Resources.FormatDirectiveMustAppearAtStartOfLine("custom"), + new SourceLocation(4, 0, 4), + 6))); // Act & Assert ParseCodeBlockTest( @@ -181,19 +220,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Code(" ") .AsStatement() .AutoCompleteWith(autoCompleteString: null, atEndOfSpan: false), - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.MetaCode(Environment.NewLine).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.EmptyCSharp().AsStatement(), - Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), - new RazorError( - Resources.FormatDirectiveMustAppearAtStartOfLine("custom"), - new SourceLocation(4, 0, 4), - 6)); + Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None))); } [Fact] @@ -309,21 +343,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); - - var expectedError = new RazorError( - LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), - new SourceLocation(8, 0, 8), - length: 7); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), + new SourceLocation(8, 0, 8), + length: 7))); // Act & Assert ParseCodeBlockTest( "@custom AString", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedError); + Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -334,21 +369,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); - - var expectedError = new RazorError( - LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), - new SourceLocation(8, 0, 8), - length: 1); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), + new SourceLocation(8, 0, 8), + length: 1))); // Act & Assert ParseCodeBlockTest( "@custom {foo?}", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedError); + Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -359,21 +395,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); - - var expectedError = new RazorError( - LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), - new SourceLocation(8, 0, 8), - length: 9); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), + new SourceLocation(8, 0, 8), + length: 9))); // Act & Assert ParseCodeBlockTest( "@custom 'AString'", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedError); + Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -384,22 +421,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); - - var expectedError = new RazorError( - LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), - new SourceLocation(8, 0, 8), - length: 7); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), + new SourceLocation(8, 0, 8), + length: 7))); // Act & Assert ParseCodeBlockTest( "@custom AString\"", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), - expectedError); + Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -526,22 +563,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddMemberToken()); - - var expectedErorr = new RazorError( - LegacyResources.FormatDirectiveExpectsIdentifier("custom"), - new SourceLocation(8, 0, 8), - length: 1); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsIdentifier("custom"), + new SourceLocation(8, 0, 8), + length: 1))); // Act & Assert ParseCodeBlockTest( "@custom -Some_Member", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), - expectedErorr); + Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -574,25 +611,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); - - var expectedErorr = new RazorError( - LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "line break"), - new SourceLocation(16, 0, 16), - length: 7); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "line break"), + new SourceLocation(16, 0, 16), + length: 7))); // Act & Assert ParseCodeBlockTest( "@custom \"hello\" \"world\"", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), - Factory.MetaCode(" ").Accepts(AcceptedCharactersInternal.WhiteSpace)), - expectedErorr); + Factory.MetaCode(" ").Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -603,25 +640,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.CodeBlock, b => b.AddStringToken()); - - var expectedErorr = new RazorError( - LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "{"), - new SourceLocation(16, 0, 16), - length: 5); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "{"), + new SourceLocation(16, 0, 16), + length: 5))); // Act & Assert ParseCodeBlockTest( "@custom \"Hello\" World { foo(); bar(); }", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), - Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), - expectedErorr); + Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace))); } [Fact] @@ -632,23 +669,23 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.CodeBlock, b => b.AddStringToken()); - - var expectedErorr = new RazorError( - LegacyResources.FormatUnexpectedEOFAfterDirective("custom", "{"), - new SourceLocation(15, 0, 15), - length: 1); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatUnexpectedEOFAfterDirective("custom", "{"), + new SourceLocation(15, 0, 15), + length: 1))); // Act & Assert ParseCodeBlockTest( "@custom \"Hello\"", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), - Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0])), - expectedErorr); + Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] @@ -659,18 +696,19 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "custom", DirectiveKind.CodeBlock, b => b.AddStringToken()); - - var expectedErorr = new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("custom", "}", "{"), - new SourceLocation(16, 0, 16), - length: 1); + var chunkGenerator = new DirectiveChunkGenerator(descriptor); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("custom", "}", "{"), + new SourceLocation(16, 0, 16), + length: 1))); // Act & Assert ParseCodeBlockTest( "@custom \"Hello\" {", new[] { descriptor }, - new DirectiveBlock( - new DirectiveChunkGenerator(descriptor), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -678,8 +716,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{") .AutoCompleteWith("}", atEndOfSpan: true) - .Accepts(AcceptedCharactersInternal.None)), - expectedErorr); + .Accepts(AcceptedCharactersInternal.None))); } [Fact] @@ -724,6 +761,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void TagHelperPrefixDirective_RequiresValue() { + // Arrange + var expectedError = new RazorError( + LegacyResources.FormatParseError_DirectiveMustHaveValue(SyntaxConstants.CSharp.TagHelperPrefixKeyword), + absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15); + + // Act & Assert ParseBlockTest("@tagHelperPrefix ", new DirectiveBlock( Factory.CodeTransition(), @@ -731,17 +774,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.EmptyCSharp() - .AsTagHelperPrefixDirective(string.Empty) - .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), - new RazorError( - LegacyResources.FormatParseError_DirectiveMustHaveValue( - SyntaxConstants.CSharp.TagHelperPrefixKeyword), - absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15)); + .AsTagHelperPrefixDirective(string.Empty, expectedError) + .Accepts(AcceptedCharactersInternal.AnyExceptNewline))); } [Fact] public void TagHelperPrefixDirective_StartQuoteRequiresDoubleQuotesAroundValue() { + // Arrange + var expectedErrors = new[] + { + new RazorError( + LegacyResources.ParseError_Unterminated_String_Literal, + absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), + new RazorError( + LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(SyntaxConstants.CSharp.TagHelperPrefixKeyword), + absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4) + }; + + // Act & Assert ParseBlockTest("@tagHelperPrefix \"Foo", new DirectiveBlock( Factory.CodeTransition(), @@ -749,19 +800,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo") - .AsTagHelperPrefixDirective("\"Foo")), - new RazorError( - LegacyResources.ParseError_Unterminated_String_Literal, - absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), - new RazorError( - LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( - SyntaxConstants.CSharp.TagHelperPrefixKeyword), - absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4)); + .AsTagHelperPrefixDirective("\"Foo", expectedErrors))); } [Fact] public void TagHelperPrefixDirective_EndQuoteRequiresDoubleQuotesAroundValue() { + // Arrange + var expectedErrors = new[] + { + new RazorError( + LegacyResources.ParseError_Unterminated_String_Literal, + absoluteIndex: 23, lineIndex: 0, columnIndex: 23, length: 1), + new RazorError( + LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(SyntaxConstants.CSharp.TagHelperPrefixKeyword), + absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 7) + }; + + // Act & Assert ParseBlockTest("@tagHelperPrefix Foo \"", new DirectiveBlock( Factory.CodeTransition(), @@ -769,14 +825,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo \"") - .AsTagHelperPrefixDirective("Foo \"")), - new RazorError( - LegacyResources.ParseError_Unterminated_String_Literal, - absoluteIndex: 23, lineIndex: 0, columnIndex: 23, length: 1), - new RazorError( - LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( - SyntaxConstants.CSharp.TagHelperPrefixKeyword), - absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 7)); + .AsTagHelperPrefixDirective("Foo \"", expectedErrors))); } [Fact] @@ -831,57 +880,69 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void RemoveTagHelperDirective_RequiresValue() { + // Arrange + var expectedError = new RazorError( + LegacyResources.FormatParseError_DirectiveMustHaveValue(SyntaxConstants.CSharp.RemoveTagHelperKeyword), + absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15); + + // Act & Assert ParseBlockTest("@removeTagHelper ", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.EmptyCSharp() - .AsRemoveTagHelper(string.Empty) - .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), - new RazorError( - LegacyResources.FormatParseError_DirectiveMustHaveValue( - SyntaxConstants.CSharp.RemoveTagHelperKeyword), - absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15)); + .AsRemoveTagHelper(string.Empty, expectedError) + .Accepts(AcceptedCharactersInternal.AnyExceptNewline))); } [Fact] public void RemoveTagHelperDirective_StartQuoteRequiresDoubleQuotesAroundValue() { + // Arrange + var expectedErrors = new[] + { + new RazorError( + LegacyResources.ParseError_Unterminated_String_Literal, + absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), + new RazorError( + LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(SyntaxConstants.CSharp.RemoveTagHelperKeyword), + absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4) + }; + + // Act & Assert ParseBlockTest("@removeTagHelper \"Foo", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo") - .AsRemoveTagHelper("\"Foo")), - new RazorError( - LegacyResources.ParseError_Unterminated_String_Literal, - absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), - new RazorError( - LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( - SyntaxConstants.CSharp.RemoveTagHelperKeyword), - absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4)); + .AsRemoveTagHelper("\"Foo", expectedErrors))); } [Fact] public void RemoveTagHelperDirective_EndQuoteRequiresDoubleQuotesAroundValue() { + // Arrange + var expectedErrors = new[] + { + new RazorError( + LegacyResources.ParseError_Unterminated_String_Literal, + absoluteIndex: 20, lineIndex: 0, columnIndex: 20, length: 1), + new RazorError( + LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(SyntaxConstants.CSharp.RemoveTagHelperKeyword), + absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4) + }; + + // Act & Assert ParseBlockTest("@removeTagHelper Foo\"", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo\"") - .AsRemoveTagHelper("Foo\"") - .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), - new RazorError( - LegacyResources.ParseError_Unterminated_String_Literal, - absoluteIndex: 20, lineIndex: 0, columnIndex: 20, length: 1), - new RazorError( - LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( - SyntaxConstants.CSharp.RemoveTagHelperKeyword), - absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4)); + .AsRemoveTagHelper("Foo\"", expectedErrors) + .Accepts(AcceptedCharactersInternal.AnyExceptNewline))); } [Fact] @@ -935,56 +996,69 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void AddTagHelperDirectiveRequiresValue() { + // Arrange + var expectedError = new RazorError( + LegacyResources.FormatParseError_DirectiveMustHaveValue(SyntaxConstants.CSharp.AddTagHelperKeyword), + absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 12); + + // Act & Assert ParseBlockTest("@addTagHelper ", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.EmptyCSharp() - .AsAddTagHelper(string.Empty) - .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), - new RazorError( - LegacyResources.FormatParseError_DirectiveMustHaveValue(SyntaxConstants.CSharp.AddTagHelperKeyword), - absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 12)); + .AsAddTagHelper(string.Empty, expectedError) + .Accepts(AcceptedCharactersInternal.AnyExceptNewline))); } [Fact] public void AddTagHelperDirective_StartQuoteRequiresDoubleQuotesAroundValue() { + // Arrange + var expectedErrors = new[] + { + new RazorError( + LegacyResources.ParseError_Unterminated_String_Literal, + absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 1), + new RazorError( + LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(SyntaxConstants.CSharp.AddTagHelperKeyword), + absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 4) + }; + + // Act & Assert ParseBlockTest("@addTagHelper \"Foo", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo") - .AsAddTagHelper("\"Foo")), - new RazorError( - LegacyResources.ParseError_Unterminated_String_Literal, - absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 1), - new RazorError( - LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( - SyntaxConstants.CSharp.AddTagHelperKeyword), - absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 4)); + .AsAddTagHelper("\"Foo", expectedErrors))); } [Fact] public void AddTagHelperDirective_EndQuoteRequiresDoubleQuotesAroundValue() { + // Arrange + var expectedErrors = new[] + { + new RazorError( + LegacyResources.ParseError_Unterminated_String_Literal, + absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), + new RazorError( + LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(SyntaxConstants.CSharp.AddTagHelperKeyword), + absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 4) + }; + + // Act & Assert ParseBlockTest("@addTagHelper Foo\"", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo\"") - .AsAddTagHelper("Foo\"") - .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), - new RazorError( - LegacyResources.ParseError_Unterminated_String_Literal, - absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), - new RazorError( - LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( - SyntaxConstants.CSharp.AddTagHelperKeyword), - absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 4)); + .AsAddTagHelper("Foo\"", expectedErrors) + .Accepts(AcceptedCharactersInternal.AnyExceptNewline))); } [Fact] diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpErrorTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpErrorTest.cs index e131008c6b..d9be2f5e7b 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpErrorTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpErrorTest.cs @@ -299,18 +299,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseBlockReportsErrorIfClassBlockUnterminatedAtEOF() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(FunctionsDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", '}', '{'), + new SourceLocation(10, 0, 10), + length: 1))); + + // Act & Assert ParseBlockTest( "functions { var foo = bar; if(foo != null) { bar(); } ", - new[] { FunctionsDirective.Directive, }, - new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), + new[] { FunctionsDirective.Directive }, + new DirectiveBlock(chunkGenerator, Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), - Factory.Code(" var foo = bar; if(foo != null) { bar(); } ").AsStatement()), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", '}', '{'), - new SourceLocation(10, 0, 10), - length: 1)); + Factory.Code(" var foo = bar; if(foo != null) { bar(); } ").AsStatement())); } [Fact] diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs index e4ccd83029..4681038d84 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSectionTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using Microsoft.AspNetCore.Razor.Language.Extensions; using Xunit; @@ -12,59 +13,77 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockCapturesNewlineImmediatelyFollowing() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), + new SourceLocation(8, 0, 8), + length: Environment.NewLine.Length))); + + // Act & Assert ParseDocumentTest( "@section" + Environment.NewLine, - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None)), - Factory.Markup(Environment.NewLine)), - new RazorError( - LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), - new SourceLocation(8, 0, 8), - length: Environment.NewLine.Length)); + Factory.Markup(Environment.NewLine))); } [Fact] public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingOpenBrace() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"), + new SourceLocation(25 + Environment.NewLine.Length, 0, 25 + Environment.NewLine.Length), + length: 1))); + + // Act & Assert ParseDocumentTest( "@section Foo " + Environment.NewLine + " ", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]), Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine + " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), - Factory.EmptyHtml()), - new RazorError( - LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"), - new SourceLocation(25 + Environment.NewLine.Length, 0, 25 + Environment.NewLine.Length), - length: 1)); + Factory.EmptyHtml())); } [Fact] public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingName() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), + new SourceLocation(17, 0, 17), + length: Environment.NewLine.Length))); + + // Act & Assert ParseDocumentTest( "@section " + Environment.NewLine + " ", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), - Factory.Markup(Environment.NewLine + " ")), - new RazorError( - LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), - new SourceLocation(17, 0, 17), - length: Environment.NewLine.Length)); + Factory.Markup(Environment.NewLine + " "))); } [Fact] @@ -72,7 +91,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { ParseDocumentTest( "@Section foo", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new ExpressionBlock( @@ -86,12 +105,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfKeywordNotFollowedByIdentifierStartCharacter() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), + new SourceLocation(9, 0, 9), + length: 1))); + + // Act & Assert ParseDocumentTest( "@section 9 {

Foo

}", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), @@ -101,22 +130,28 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Markup("Foo"), new MarkupTagBlock( Factory.Markup("

")), - Factory.Markup(" }")), - new RazorError( - LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive), - new SourceLocation(9, 0, 9), - length: 1)); + Factory.Markup(" }"))); } [Fact] public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfNameNotFollowedByOpenBrace() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatUnexpectedDirectiveLiteral(SectionDirective.Directive.Directive, "{"), + new SourceLocation(12, 0, 12), + length: 1))); + + // Act & Assert ParseDocumentTest( "@section foo-bar {

Foo

}", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -127,19 +162,31 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Markup("Foo"), new MarkupTagBlock( Factory.Markup("

")), - Factory.Markup(" }")), - new RazorError( - LegacyResources.FormatUnexpectedDirectiveLiteral(SectionDirective.Directive.Directive, "{"), - new SourceLocation(12, 0, 12), - length: 1)); + Factory.Markup(" }"))); } [Fact] public void ParserOutputsErrorOnNestedSections() { + // Arrange + var erroredChunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + erroredChunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + Resources.FormatDirectiveMustAppearAtStartOfLine("section"), + new SourceLocation(16, 0, 16), + 7))); + erroredChunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS), + new SourceLocation(15, 0, 15), + 8))); + + // Act & Assert ParseDocumentTest( "@section foo { @section bar {

Foo

} }", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -151,7 +198,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( Factory.Markup(" "), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(erroredChunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -169,26 +216,28 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), Factory.Markup(" ")), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), - Factory.EmptyHtml()), - new RazorError( - Resources.FormatDirectiveMustAppearAtStartOfLine("section"), - new SourceLocation(16, 0, 16), - 7), - new RazorError( - LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS), - new SourceLocation(15, 0, 15), - 8)); + Factory.EmptyHtml())); } [Fact] public void ParseSectionBlockHandlesEOFAfterOpenBrace() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(SectionDirective.Directive.Directive, "}", "{"), + new SourceLocation(13, 0, 13), + length: 1))); + + // Act & Assert ParseDocumentTest( "@section foo {", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -196,11 +245,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( - Factory.EmptyHtml()))), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(SectionDirective.Directive.Directive, "}", "{"), - new SourceLocation(13, 0, 13), - length: 1)); + Factory.EmptyHtml())))); } [Theory] @@ -210,12 +255,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [InlineData(" \n abc")] public void ParseSectionBlockHandlesEOFAfterOpenContent(string postStartBrace) { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), + new SourceLocation(13, 0, 13), + length: 1))); + + // Act & Assert ParseDocumentTest( "@section foo {" + postStartBrace, - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -223,22 +278,28 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( - Factory.Markup(postStartBrace)))), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), - new SourceLocation(13, 0, 13), - length: 1)); + Factory.Markup(postStartBrace))))); } [Fact] public void ParseSectionBlockHandlesUnterminatedSection() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), + new SourceLocation(13, 0, 13), + length: 1))); + + // Act & Assert ParseDocumentTest( "@section foo {

Foo{}

", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -252,27 +313,33 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy // Need to provide the markup span as fragments, since the parser will split the {} into separate symbols. Factory.Markup("Foo", "{", "}"), new MarkupTagBlock( - Factory.Markup("

"))))), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), - new SourceLocation(13, 0, 13), - length: 1)); + Factory.Markup("

")))))); } [Fact] public void ParseSectionBlockHandlesUnterminatedSectionWithNestedIf() { + // Arrange var newLine = Environment.NewLine; + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), + new SourceLocation(13 + newLine.Length, 1, 0), + length: 1))); var spaces = " "; + + // Act & Assert ParseDocumentTest( string.Format( "@section Test{0}{{{0}{1}@if(true){0}{1}{{{0}{1}{1}

Hello World

{0}{1}}}", newLine, spaces), - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -291,47 +358,52 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy Factory.Markup("Hello World"), BlockFactory.MarkupTagBlock("

", AcceptedCharactersInternal.None), Factory.Markup(newLine).Accepts(AcceptedCharactersInternal.None)), - Factory.Code($"{spaces}}}").AsStatement())))), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"), - new SourceLocation(13 + newLine.Length, 1, 0), - length: 1)); + Factory.Code($"{spaces}}}").AsStatement()))))); } [Fact] public void ParseSectionBlockReportsErrorAndAcceptsWhitespaceToEndOfLineIfSectionNotFollowedByOpenBrace() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"), + new SourceLocation(18 + Environment.NewLine.Length, 0, 18 + Environment.NewLine.Length), + length: 1))); + + // Act & Assert ParseDocumentTest( "@section foo " + Environment.NewLine, - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), - new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), + new DirectiveBlock(chunkGenerator, Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]), Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine, markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), - Factory.EmptyHtml()), - new RazorError( - LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"), - new SourceLocation(18 + Environment.NewLine.Length, 0, 18 + Environment.NewLine.Length), - length: 1)); + Factory.EmptyHtml())); } [Fact] public void ParseSectionBlockAcceptsOpenBraceMultipleLinesBelowSectionName() { - ParseDocumentTest("@section foo " + Environment.NewLine - + Environment.NewLine - + Environment.NewLine - + Environment.NewLine - + Environment.NewLine - + Environment.NewLine - + "{" + Environment.NewLine - + "

Foo

" + Environment.NewLine - + "}", - new[] { SectionDirective.Directive, }, + // Act & Assert + ParseDocumentTest( + "@section foo " + + Environment.NewLine + + Environment.NewLine + + Environment.NewLine + + Environment.NewLine + + Environment.NewLine + + Environment.NewLine + + "{" + Environment.NewLine + + "

Foo

" + Environment.NewLine + + "}", + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -356,9 +428,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockParsesNamedSectionCorrectly() { + // Act & Assert ParseDocumentTest( "@section foo {

Foo

}", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -383,9 +456,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockDoesNotRequireSpaceBetweenSectionNameAndOpenBrace() { + // Act & Assert ParseDocumentTest( "@section foo{

Foo

}", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -409,9 +483,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockBalancesBraces() { + // Act & Assert ParseDocumentTest( "@section foo { }", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -436,9 +511,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockAllowsBracesInCSharpExpression() { + // Act & Assert ParseDocumentTest( "@section foo { I really want to render a close brace, so here I go: @(\"}\") }", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -463,11 +539,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void SectionIsCorrectlyTerminatedWhenCloseBraceImmediatelyFollowsCodeBlock() { - ParseDocumentTest("@section Foo {" + Environment.NewLine - + "@if(true) {" + Environment.NewLine - + "}" + Environment.NewLine - + "}", - new[] { SectionDirective.Directive, }, + // Act & Assert + ParseDocumentTest( + "@section Foo {" + Environment.NewLine + + "@if(true) {" + Environment.NewLine + + "}" + Environment.NewLine + + "}", + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -490,10 +568,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void SectionIsCorrectlyTerminatedWhenCloseBraceImmediatelyFollowsCodeBlockNoWhitespace() { - ParseDocumentTest("@section Foo {" + Environment.NewLine - + "@if(true) {" + Environment.NewLine - + "}}", - new[] { SectionDirective.Directive, }, + // Act & Assert + ParseDocumentTest( + "@section Foo {" + Environment.NewLine + + "@if(true) {" + Environment.NewLine + + "}}", + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -516,9 +596,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockCorrectlyTerminatesWhenCloseBraceImmediatelyFollowsMarkup() { + // Act & Assert ParseDocumentTest( "@section foo {something}", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -537,9 +618,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockParsesComment() { + // Act & Assert ParseDocumentTest( "@section s {}", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -560,9 +642,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockParsesCommentWithDelimiters() { + // Act & Assert ParseDocumentTest( "@section s {}", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -581,9 +664,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockCommentRecoversFromUnclosedTag() { + // Act & Assert ParseDocumentTest( "@section s {" + Environment.NewLine + " \" '-->}", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -605,9 +689,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseSectionBlockParsesXmlProcessingInstruction() { + // Act & Assert ParseDocumentTest( "@section s { }", - new[] { SectionDirective.Directive, }, + new[] { SectionDirective.Directive }, new MarkupBlock( Factory.EmptyHtml(), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), @@ -698,7 +783,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { FixupSpans = true; - ParseDocumentTest(input, new[] { SectionDirective.Directive, }, (Block)expected); + ParseDocumentTest(input, new[] { SectionDirective.Directive }, (Block)expected); } } } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs index fbbfa9e2fc..650c12d506 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpSpecialBlockTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using Microsoft.AspNetCore.Razor.Language.Extensions; using Xunit; @@ -12,14 +13,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(InheritsDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatUnexpectedEOFAfterDirective(InheritsDirective.Directive.Directive, "type"), + new SourceLocation(8, 0, 8), 1))); + + // Act & Assert ParseBlockTest( "inherits", - new[] { InheritsDirective.Directive, }, - new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), - Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None)), - new RazorError( - LegacyResources.FormatUnexpectedEOFAfterDirective(InheritsDirective.Directive.Directive, "type"), - new SourceLocation(8, 0, 8), 1)); + new[] { InheritsDirective.Directive }, + new DirectiveBlock(chunkGenerator, + Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None))); } [Fact] @@ -27,7 +34,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { ParseBlockTest( "inherits Foo.Bar, string, int>.Baz", - new[] { InheritsDirective.Directive, }, + new[] { InheritsDirective.Directive }, new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), @@ -37,13 +44,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(InheritsDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatDirectiveExpectsTypeName(InheritsDirective.Directive.Directive), + 24, 0, 24, Environment.NewLine.Length))); + + // Act & Assert ParseBlockTest( "inherits " + Environment.NewLine + "foo", - new[] { InheritsDirective.Directive, }, - new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), + new[] { InheritsDirective.Directive }, + new DirectiveBlock(chunkGenerator, Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), - Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), - new RazorError(LegacyResources.FormatDirectiveExpectsTypeName(InheritsDirective.Directive.Directive), 24, 0, 24, Environment.NewLine.Length)); + Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] @@ -146,7 +161,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy const string code = " foo(); \"bar}baz\" "; ParseBlockTest( "functions {" + code + "} zoop", - new[] { FunctionsDirective.Directive, }, + new[] { FunctionsDirective.Directive }, new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), @@ -158,18 +173,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Fact] public void ParseBlockDoesNoErrorRecoveryForFunctionsBlock() { + // Arrange + var chunkGenerator = new DirectiveChunkGenerator(FunctionsDirective.Directive); + chunkGenerator.Diagnostics.Add( + RazorDiagnostic.Create( + new RazorError( + LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"), + new SourceLocation(10, 0, 10), + length: 1))); + + // Act & Assert ParseBlockTest( "functions { { { { { } zoop", - new[] { FunctionsDirective.Directive, }, - new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), + new[] { FunctionsDirective.Directive }, + new DirectiveBlock(chunkGenerator, Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), - Factory.Code(" { { { { } zoop").AsStatement()), - new RazorError( - LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"), - new SourceLocation(10, 0, 10), - length: 1)); + Factory.Code(" { { { { } zoop").AsStatement())); } [Fact] diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TestSpanBuilder.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TestSpanBuilder.cs index 213883c0ff..dc0e19f801 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TestSpanBuilder.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TestSpanBuilder.cs @@ -334,24 +334,27 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy return _self.With(SpanChunkGenerator.Null); } - public SpanConstructor AsAddTagHelper(string lookupText) + public SpanConstructor AsAddTagHelper(string lookupText, params RazorError[] legacyErrors) { + var diagnostics = legacyErrors.Select(error => RazorDiagnostic.Create(error)).ToList(); return _self - .With(new AddTagHelperChunkGenerator(lookupText)) + .With(new AddTagHelperChunkGenerator(lookupText, diagnostics)) .Accepts(AcceptedCharactersInternal.AnyExceptNewline); } - public SpanConstructor AsRemoveTagHelper(string lookupText) + public SpanConstructor AsRemoveTagHelper(string lookupText, params RazorError[] legacyErrors) { + var diagnostics = legacyErrors.Select(error => RazorDiagnostic.Create(error)).ToList(); return _self - .With(new RemoveTagHelperChunkGenerator(lookupText)) + .With(new RemoveTagHelperChunkGenerator(lookupText, diagnostics)) .Accepts(AcceptedCharactersInternal.AnyExceptNewline); } - public SpanConstructor AsTagHelperPrefixDirective(string prefix) + public SpanConstructor AsTagHelperPrefixDirective(string prefix, params RazorError[] legacyErrors) { + var diagnostics = legacyErrors.Select(error => RazorDiagnostic.Create(error)).ToList(); return _self - .With(new TagHelperPrefixDirectiveChunkGenerator(prefix)) + .With(new TagHelperPrefixDirectiveChunkGenerator(prefix, diagnostics)) .Accepts(AcceptedCharactersInternal.AnyExceptNewline); } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.codegen.cs index b605e8dbdc..f47b579ee3 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.codegen.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.codegen.cs @@ -47,12 +47,6 @@ global::System.Object __typeHelper = "; #pragma warning disable 1998 public async System.Threading.Tasks.Task ExecuteAsync() { - DefineSection("", async (__razor_section_writer) => { - }); - DefineSection("", async (__razor_section_writer) => { - }); - DefineSection("", async (__razor_section_writer) => { - }); } #pragma warning restore 1998 } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.ir.txt index 0563488222..e2b03c6e98 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.ir.txt +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_DesignTime.ir.txt @@ -16,43 +16,57 @@ Document - MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml) RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n + MalformedDirective - (100:2,13 [0] IncompleteDirectives.cshtml) + DirectiveToken - (100:2,13 [0] IncompleteDirectives.cshtml) - HtmlContent - (100:2,13 [2] IncompleteDirectives.cshtml) RazorIRToken - (100:2,13 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (116:3,14 [0] IncompleteDirectives.cshtml) + DirectiveToken - (116:3,14 [0] IncompleteDirectives.cshtml) - HtmlContent - (116:3,14 [2] IncompleteDirectives.cshtml) RazorIRToken - (116:3,14 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (132:4,14 [1] IncompleteDirectives.cshtml) + DirectiveToken - (132:4,14 [1] IncompleteDirectives.cshtml) - " HtmlContent - (133:4,15 [4] IncompleteDirectives.cshtml) RazorIRToken - (133:4,15 [4] IncompleteDirectives.cshtml) - Html - \n\n + MalformedDirective - (153:6,16 [0] IncompleteDirectives.cshtml) + DirectiveToken - (153:6,16 [0] IncompleteDirectives.cshtml) - HtmlContent - (153:6,16 [2] IncompleteDirectives.cshtml) RazorIRToken - (153:6,16 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (172:7,17 [0] IncompleteDirectives.cshtml) + DirectiveToken - (172:7,17 [0] IncompleteDirectives.cshtml) - HtmlContent - (172:7,17 [2] IncompleteDirectives.cshtml) RazorIRToken - (172:7,17 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (191:8,17 [1] IncompleteDirectives.cshtml) + DirectiveToken - (191:8,17 [1] IncompleteDirectives.cshtml) - " HtmlContent - (192:8,18 [4] IncompleteDirectives.cshtml) RazorIRToken - (192:8,18 [4] IncompleteDirectives.cshtml) - Html - \n\n + MalformedDirective - (212:10,16 [0] IncompleteDirectives.cshtml) + DirectiveToken - (212:10,16 [0] IncompleteDirectives.cshtml) - HtmlContent - (212:10,16 [2] IncompleteDirectives.cshtml) RazorIRToken - (212:10,16 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (231:11,17 [0] IncompleteDirectives.cshtml) + DirectiveToken - (231:11,17 [0] IncompleteDirectives.cshtml) - HtmlContent - (231:11,17 [2] IncompleteDirectives.cshtml) RazorIRToken - (231:11,17 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (250:12,17 [1] IncompleteDirectives.cshtml) + DirectiveToken - (250:12,17 [1] IncompleteDirectives.cshtml) - " HtmlContent - (251:12,18 [4] IncompleteDirectives.cshtml) RazorIRToken - (251:12,18 [4] IncompleteDirectives.cshtml) - Html - \n\n + MalformedDirective - (255:14,0 [9] IncompleteDirectives.cshtml) HtmlContent - (264:14,9 [2] IncompleteDirectives.cshtml) RazorIRToken - (264:14,9 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (266:15,0 [10] IncompleteDirectives.cshtml) HtmlContent - (276:15,10 [4] IncompleteDirectives.cshtml) RazorIRToken - (276:15,10 [4] IncompleteDirectives.cshtml) - Html - \n\n - CSharpCode - - RazorIRToken - - CSharp - DefineSection("", async (__razor_section_writer) => { - CSharpCode - - RazorIRToken - - CSharp - }); + MalformedDirective - (280:17,0 [12] IncompleteDirectives.cshtml) + MalformedDirective - (292:18,0 [15] IncompleteDirectives.cshtml) + MalformedDirective - (307:20,0 [8] IncompleteDirectives.cshtml) HtmlContent - (315:20,8 [2] IncompleteDirectives.cshtml) RazorIRToken - (315:20,8 [2] IncompleteDirectives.cshtml) - Html - \n - CSharpCode - - RazorIRToken - - CSharp - DefineSection("", async (__razor_section_writer) => { - CSharpCode - - RazorIRToken - - CSharp - }); + MalformedDirective - (317:21,0 [9] IncompleteDirectives.cshtml) HtmlContent - (326:21,9 [4] IncompleteDirectives.cshtml) RazorIRToken - (326:21,9 [4] IncompleteDirectives.cshtml) - Html - \n\n - CSharpCode - - RazorIRToken - - CSharp - DefineSection("", async (__razor_section_writer) => { - CSharpCode - - RazorIRToken - - CSharp - }); + MalformedDirective - (330:23,0 [9] IncompleteDirectives.cshtml) HtmlContent - (339:23,9 [3] IncompleteDirectives.cshtml) RazorIRToken - (339:23,9 [3] IncompleteDirectives.cshtml) - Html - {\n + MalformedDirective - (342:24,0 [12] IncompleteDirectives.cshtml) diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.codegen.cs index 4da141abdd..4dd2fdebf7 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.codegen.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.codegen.cs @@ -13,14 +13,8 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestFiles WriteLiteral("\r\n"); WriteLiteral("\r\n"); WriteLiteral("\r\n\r\n"); - DefineSection("", async () => { - }); WriteLiteral("\r\n"); - DefineSection("", async () => { - }); WriteLiteral("\r\n\r\n"); - DefineSection("", async () => { - }); WriteLiteral("{\r\n"); } #pragma warning restore 1998 diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.ir.txt b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.ir.txt index cc812008b8..48b9d2d802 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.ir.txt +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives_Runtime.ir.txt @@ -4,31 +4,45 @@ Document - MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml) RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n + MalformedDirective - (100:2,13 [2] IncompleteDirectives.cshtml) + DirectiveToken - (100:2,13 [2] IncompleteDirectives.cshtml) - + MalformedDirective - (116:3,14 [2] IncompleteDirectives.cshtml) + DirectiveToken - (116:3,14 [2] IncompleteDirectives.cshtml) - + MalformedDirective - (132:4,14 [3] IncompleteDirectives.cshtml) + DirectiveToken - (132:4,14 [3] IncompleteDirectives.cshtml) - " HtmlContent - (135:5,0 [2] IncompleteDirectives.cshtml) RazorIRToken - (135:5,0 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (153:6,16 [2] IncompleteDirectives.cshtml) + DirectiveToken - (153:6,16 [2] IncompleteDirectives.cshtml) - + MalformedDirective - (172:7,17 [2] IncompleteDirectives.cshtml) + DirectiveToken - (172:7,17 [2] IncompleteDirectives.cshtml) - + MalformedDirective - (191:8,17 [3] IncompleteDirectives.cshtml) + DirectiveToken - (191:8,17 [3] IncompleteDirectives.cshtml) - " HtmlContent - (194:9,0 [2] IncompleteDirectives.cshtml) RazorIRToken - (194:9,0 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (212:10,16 [2] IncompleteDirectives.cshtml) + DirectiveToken - (212:10,16 [2] IncompleteDirectives.cshtml) - + MalformedDirective - (231:11,17 [2] IncompleteDirectives.cshtml) + DirectiveToken - (231:11,17 [2] IncompleteDirectives.cshtml) - + MalformedDirective - (250:12,17 [3] IncompleteDirectives.cshtml) + DirectiveToken - (250:12,17 [3] IncompleteDirectives.cshtml) - " HtmlContent - (253:13,0 [2] IncompleteDirectives.cshtml) RazorIRToken - (253:13,0 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (255:14,0 [9] IncompleteDirectives.cshtml) HtmlContent - (264:14,9 [2] IncompleteDirectives.cshtml) RazorIRToken - (264:14,9 [2] IncompleteDirectives.cshtml) - Html - \n + MalformedDirective - (266:15,0 [10] IncompleteDirectives.cshtml) HtmlContent - (276:15,10 [4] IncompleteDirectives.cshtml) RazorIRToken - (276:15,10 [4] IncompleteDirectives.cshtml) - Html - \n\n - CSharpCode - - RazorIRToken - - CSharp - DefineSection("", async () => { - CSharpCode - - RazorIRToken - - CSharp - }); + MalformedDirective - (280:17,0 [12] IncompleteDirectives.cshtml) + MalformedDirective - (292:18,0 [15] IncompleteDirectives.cshtml) + MalformedDirective - (307:20,0 [8] IncompleteDirectives.cshtml) HtmlContent - (315:20,8 [2] IncompleteDirectives.cshtml) RazorIRToken - (315:20,8 [2] IncompleteDirectives.cshtml) - Html - \n - CSharpCode - - RazorIRToken - - CSharp - DefineSection("", async () => { - CSharpCode - - RazorIRToken - - CSharp - }); + MalformedDirective - (317:21,0 [9] IncompleteDirectives.cshtml) HtmlContent - (326:21,9 [4] IncompleteDirectives.cshtml) RazorIRToken - (326:21,9 [4] IncompleteDirectives.cshtml) - Html - \n\n - CSharpCode - - RazorIRToken - - CSharp - DefineSection("", async () => { - CSharpCode - - RazorIRToken - - CSharp - }); + MalformedDirective - (330:23,0 [9] IncompleteDirectives.cshtml) HtmlContent - (339:23,9 [3] IncompleteDirectives.cshtml) RazorIRToken - (339:23,9 [3] IncompleteDirectives.cshtml) - Html - {\n + MalformedDirective - (342:24,0 [12] IncompleteDirectives.cshtml) diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_DesignTime.codegen.cs index fc786858d9..5b223d7551 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_DesignTime.codegen.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_DesignTime.codegen.cs @@ -15,8 +15,6 @@ global::System.Object Link = null; #pragma warning disable 1998 public async System.Threading.Tasks.Task ExecuteAsync() { - DefineSection("Link", async (__razor_section_writer) => { - }); #line 2 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml" if(link != null) { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_DesignTime.ir.txt index 51b2e8e318..b892f5ff97 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_DesignTime.ir.txt +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_DesignTime.ir.txt @@ -6,10 +6,8 @@ Document - CSharpCode - RazorIRToken - - CSharp - private static System.Object __o = null; MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync - CSharpCode - - RazorIRToken - - CSharp - DefineSection("Link", async (__razor_section_writer) => { - CSharpCode - - RazorIRToken - - CSharp - }); + MalformedDirective - (0:0,0 [13] InlineBlocks.cshtml) + DirectiveToken - (9:0,9 [4] InlineBlocks.cshtml) - Link HtmlContent - (13:0,13 [23] InlineBlocks.cshtml) RazorIRToken - (13:0,13 [21] InlineBlocks.cshtml) - Html - (string link) {\n RazorIRToken - (34:1,4 [2] InlineBlocks.cshtml) - Html - { - }); WriteLiteral("(string link) {\r\n { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_Runtime.ir.txt b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_Runtime.ir.txt index ce46ba6278..e0b73fa873 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_Runtime.ir.txt +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks_Runtime.ir.txt @@ -2,10 +2,8 @@ Document - NamespaceDeclaration - - Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestFiles ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InlineBlocks_Runtime - - MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync - CSharpCode - - RazorIRToken - - CSharp - DefineSection("Link", async () => { - CSharpCode - - RazorIRToken - - CSharp - }); + MalformedDirective - (0:0,0 [13] InlineBlocks.cshtml) + DirectiveToken - (9:0,9 [4] InlineBlocks.cshtml) - Link HtmlContent - (13:0,13 [23] InlineBlocks.cshtml) RazorIRToken - (13:0,13 [21] InlineBlocks.cshtml) - Html - (string link) {\n RazorIRToken - (34:1,4 [2] InlineBlocks.cshtml) - Html -