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
This commit is contained in:
N. Taylor Mullen 2017-05-22 10:17:22 -07:00
parent dd4e163173
commit 132c8c7a7e
46 changed files with 1337 additions and 839 deletions

View File

@ -24,18 +24,8 @@ namespace Microsoft.AspNetCore.Razor.Language
throw new ArgumentNullException(nameof(syntaxTree)); throw new ArgumentNullException(nameof(syntaxTree));
} }
var errorSink = new ErrorSink();
var sectionVerifier = new NestedSectionVerifier(); var sectionVerifier = new NestedSectionVerifier();
sectionVerifier.Verify(syntaxTree, errorSink); sectionVerifier.Verify(syntaxTree);
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);
}
return syntaxTree; return syntaxTree;
} }
@ -43,11 +33,9 @@ namespace Microsoft.AspNetCore.Razor.Language
private class NestedSectionVerifier : ParserVisitor private class NestedSectionVerifier : ParserVisitor
{ {
private int _nestedLevel; private int _nestedLevel;
private ErrorSink _errorSink;
public void Verify(RazorSyntaxTree tree, ErrorSink errorSink) public void Verify(RazorSyntaxTree tree)
{ {
_errorSink = errorSink;
tree.Root.Accept(this); 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 directiveStart = block.Children.First(child => !child.IsBlock && ((Span)child).Kind == SpanKindInternal.Transition).Start;
var errorLength = /* @ */ 1 + SectionDirective.Directive.Directive.Length; var errorLength = /* @ */ 1 + SectionDirective.Directive.Directive.Length;
_errorSink.OnError( var error = RazorDiagnostic.Create(
directiveStart, new RazorError(
LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS), LegacyResources.FormatParseError_Sections_Cannot_Be_Nested(LegacyResources.SectionExample_CS),
errorLength); directiveStart,
errorLength));
chunkGenerator.Diagnostics.Add(error);
} }
_nestedLevel++; _nestedLevel++;

View File

@ -131,12 +131,32 @@ namespace Microsoft.AspNetCore.Razor.Language
public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunkGenerator, Span span) public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunkGenerator, Span span)
{ {
_builder.Push(new DirectiveIRNode() RazorIRNode directiveNode;
if (IsMalformed(chunkGenerator.Diagnostics))
{ {
Name = CSharpCodeParser.AddTagHelperDirectiveDescriptor.Directive, directiveNode = new MalformedDirectiveIRNode()
Descriptor = CSharpCodeParser.AddTagHelperDirectiveDescriptor, {
Source = BuildSourceSpanFromNode(span), 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() _builder.Add(new DirectiveTokenIRNode()
{ {
@ -150,12 +170,32 @@ namespace Microsoft.AspNetCore.Razor.Language
public override void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunkGenerator, Span span) public override void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunkGenerator, Span span)
{ {
_builder.Push(new DirectiveIRNode() RazorIRNode directiveNode;
if (IsMalformed(chunkGenerator.Diagnostics))
{ {
Name = CSharpCodeParser.RemoveTagHelperDirectiveDescriptor.Directive, directiveNode = new MalformedDirectiveIRNode()
Descriptor = CSharpCodeParser.RemoveTagHelperDirectiveDescriptor, {
Source = BuildSourceSpanFromNode(span), 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() _builder.Add(new DirectiveTokenIRNode()
{ {
@ -169,12 +209,32 @@ namespace Microsoft.AspNetCore.Razor.Language
public override void VisitTagHelperPrefixDirectiveSpan(TagHelperPrefixDirectiveChunkGenerator chunkGenerator, Span span) public override void VisitTagHelperPrefixDirectiveSpan(TagHelperPrefixDirectiveChunkGenerator chunkGenerator, Span span)
{ {
_builder.Push(new DirectiveIRNode() RazorIRNode directiveNode;
if (IsMalformed(chunkGenerator.Diagnostics))
{ {
Name = CSharpCodeParser.TagHelperPrefixDirectiveDescriptor.Directive, directiveNode = new MalformedDirectiveIRNode()
Descriptor = CSharpCodeParser.TagHelperPrefixDirectiveDescriptor, {
Source = BuildSourceSpanFromNode(span), 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() _builder.Add(new DirectiveTokenIRNode()
{ {
@ -235,12 +295,32 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
_insideLineDirective = true; _insideLineDirective = true;
_builder.Push(new DirectiveIRNode() RazorIRNode directiveNode;
if (IsMalformed(chunkGenerator.Diagnostics))
{ {
Name = chunkGenerator.Descriptor.Directive, directiveNode = new MalformedDirectiveIRNode()
Descriptor = chunkGenerator.Descriptor, {
Source = BuildSourceSpanFromNode(block), 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); base.VisitDirectiveBlock(chunkGenerator, block);
@ -274,12 +354,32 @@ namespace Microsoft.AspNetCore.Razor.Language
public override void VisitDirectiveBlock(DirectiveChunkGenerator chunkGenerator, Block block) public override void VisitDirectiveBlock(DirectiveChunkGenerator chunkGenerator, Block block)
{ {
_builder.Push(new DirectiveIRNode() RazorIRNode directiveNode;
if (IsMalformed(chunkGenerator.Diagnostics))
{ {
Name = chunkGenerator.Descriptor.Directive, directiveNode = new MalformedDirectiveIRNode()
Descriptor = chunkGenerator.Descriptor, {
Source = BuildSourceSpanFromNode(block), 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); VisitDefault(block);
@ -675,5 +775,8 @@ namespace Microsoft.AspNetCore.Razor.Language
} }
} }
} }
private static bool IsMalformed(List<RazorDiagnostic> diagnostics)
=> diagnostics.Count > 0 && diagnostics.Any(diagnostic => diagnostic.Severity == RazorDiagnosticSeverity.Error);
} }
} }

View File

@ -47,11 +47,10 @@ namespace Microsoft.AspNetCore.Razor.Language
var errorList = new List<RazorDiagnostic>(); var errorList = new List<RazorDiagnostic>();
var descriptors = feature.GetDescriptors(); var descriptors = feature.GetDescriptors();
var errorSink = new ErrorSink();
var directives = visitor.Directives; 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 root = syntaxTree.Root;
var context = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors); var context = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors);
@ -59,18 +58,14 @@ namespace Microsoft.AspNetCore.Razor.Language
if (descriptors.Count == 0) if (descriptors.Count == 0)
{ {
if (errorSink.Errors.Count == 0 && errorList.Count == 0) // No descriptors, no-op.
{ return;
// No TagHelpers and errors, no op.
return;
}
}
else
{
var rewriter = new TagHelperParseTreeRewriter(tagHelperPrefix, descriptors);
root = rewriter.Rewrite(root, errorSink);
} }
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. // Temporary code while we're still using legacy diagnostics in the SyntaxTree.
errorList.AddRange(errorSink.Errors.Select(error => RazorDiagnostic.Create(error))); errorList.AddRange(errorSink.Errors.Select(error => RazorDiagnostic.Create(error)));
@ -83,7 +78,7 @@ namespace Microsoft.AspNetCore.Razor.Language
} }
// Internal for testing // Internal for testing
internal string ProcessTagHelperPrefix(List<TagHelperDirectiveDescriptor> directives, RazorCodeDocument codeDocument, ErrorSink errorSink) internal string ProcessTagHelperPrefix(List<TagHelperDirectiveDescriptor> directives, RazorCodeDocument codeDocument)
{ {
// We only support a single prefix directive. // We only support a single prefix directive.
TagHelperDirectiveDescriptor prefixDirective = null; TagHelperDirectiveDescriptor prefixDirective = null;
@ -97,7 +92,7 @@ namespace Microsoft.AspNetCore.Razor.Language
} }
var prefix = prefixDirective?.DirectiveText; var prefix = prefixDirective?.DirectiveText;
if (prefix != null && !IsValidTagHelperPrefix(prefix, prefixDirective.Location, errorSink)) if (prefix != null && !IsValidTagHelperPrefix(prefix, prefixDirective.Location, prefixDirective.Diagnostics))
{ {
prefix = null; prefix = null;
} }
@ -112,8 +107,7 @@ namespace Microsoft.AspNetCore.Razor.Language
internal IReadOnlyList<TagHelperDescriptor> ProcessDirectives( internal IReadOnlyList<TagHelperDescriptor> ProcessDirectives(
IReadOnlyList<TagHelperDirectiveDescriptor> directives, IReadOnlyList<TagHelperDirectiveDescriptor> directives,
IReadOnlyList<TagHelperDescriptor> tagHelpers, IReadOnlyList<TagHelperDescriptor> tagHelpers)
ErrorSink errorSink)
{ {
var matches = new HashSet<TagHelperDescriptor>(TagHelperDescriptorComparer.Default); var matches = new HashSet<TagHelperDescriptor>(TagHelperDescriptorComparer.Default);
@ -126,7 +120,7 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
case TagHelperDirectiveType.AddTagHelper: case TagHelperDirectiveType.AddTagHelper:
parsed = ParseAddOrRemoveDirective(directive, errorSink); parsed = ParseAddOrRemoveDirective(directive);
if (parsed == null) if (parsed == null)
{ {
// Skip this one, it's an error // Skip this one, it's an error
@ -152,7 +146,7 @@ namespace Microsoft.AspNetCore.Razor.Language
case TagHelperDirectiveType.RemoveTagHelper: case TagHelperDirectiveType.RemoveTagHelper:
parsed = ParseAddOrRemoveDirective(directive, errorSink); parsed = ParseAddOrRemoveDirective(directive);
if (parsed == null) if (parsed == null)
{ {
// Skip this one, it's an error // Skip this one, it's an error
@ -196,7 +190,7 @@ namespace Microsoft.AspNetCore.Razor.Language
} }
// Internal for testing // Internal for testing
internal ParsedDirective ParseAddOrRemoveDirective(TagHelperDirectiveDescriptor directive, ErrorSink errorSink) internal ParsedDirective ParseAddOrRemoveDirective(TagHelperDirectiveDescriptor directive)
{ {
var text = directive.DirectiveText; var text = directive.DirectiveText;
var lookupStrings = text?.Split(new[] { ',' }); var lookupStrings = text?.Split(new[] { ',' });
@ -206,10 +200,12 @@ namespace Microsoft.AspNetCore.Razor.Language
lookupStrings.Any(string.IsNullOrWhiteSpace) || lookupStrings.Any(string.IsNullOrWhiteSpace) ||
lookupStrings.Length != 2) lookupStrings.Length != 2)
{ {
errorSink.OnError( directive.Diagnostics.Add(
directive.Location, RazorDiagnostic.Create(
Resources.FormatInvalidTagHelperLookupText(text), new RazorError(
Math.Max(text.Length, 1)); Resources.FormatInvalidTagHelperLookupText(text),
directive.Location,
Math.Max(text.Length, 1))));
return null; return null;
} }
@ -238,20 +234,19 @@ namespace Microsoft.AspNetCore.Razor.Language
internal bool IsValidTagHelperPrefix( internal bool IsValidTagHelperPrefix(
string prefix, string prefix,
SourceLocation directiveLocation, SourceLocation directiveLocation,
ErrorSink errorSink) List<RazorDiagnostic> diagnostics)
{ {
foreach (var character in prefix) foreach (var character in prefix)
{ {
// Prefixes are correlated with tag names, tag names cannot have whitespace. // Prefixes are correlated with tag names, tag names cannot have whitespace.
if (char.IsWhiteSpace(character) || InvalidNonWhitespaceNameCharacters.Contains(character)) if (char.IsWhiteSpace(character) || InvalidNonWhitespaceNameCharacters.Contains(character))
{ {
errorSink.OnError( diagnostics.Add(
directiveLocation, RazorDiagnostic.Create(
Resources.FormatInvalidTagHelperPrefixValue( new RazorError(
SyntaxConstants.CSharp.TagHelperPrefixKeyword, Resources.FormatInvalidTagHelperPrefixValue(SyntaxConstants.CSharp.TagHelperPrefixKeyword, character, prefix),
character, directiveLocation,
prefix), prefix.Length)));
prefix.Length);
return false; return false;
} }
@ -323,23 +318,27 @@ namespace Microsoft.AspNetCore.Razor.Language
public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunkGenerator, Span span) 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) 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) 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( private TagHelperDirectiveDescriptor CreateDirective(
Span span, Span span,
string directiveText, string directiveText,
TagHelperDirectiveType directiveType) TagHelperDirectiveType directiveType,
List<RazorDiagnostic> diagnostics)
{ {
directiveText = directiveText.Trim(); directiveText = directiveText.Trim();
if (directiveText.Length >= 2 && if (directiveText.Length >= 2 &&
@ -375,6 +374,7 @@ namespace Microsoft.AspNetCore.Razor.Language
DirectiveText = directiveText, DirectiveText = directiveText,
Location = directiveStart, Location = directiveStart,
DirectiveType = directiveType, DirectiveType = directiveType,
Diagnostics = diagnostics,
}; };
return directiveDescriptor; return directiveDescriptor;

View File

@ -15,19 +15,19 @@ namespace Microsoft.AspNetCore.Razor.Language
var visitor = new Visitor(); var visitor = new Visitor();
visitor.VisitDocument(irDocument); 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 private class Visitor : RazorIRNodeWalker
{ {
public IList<(DirectiveIRNode node, RazorIRNode parent)> DirectiveNodes { get; } = new List<(DirectiveIRNode node, RazorIRNode parent)>(); public IList<RazorIRNodeReference> DirectiveNodes { get; } = new List<RazorIRNodeReference>();
public override void VisitDirective(DirectiveIRNode node) public override void VisitDirective(DirectiveIRNode node)
{ {
DirectiveNodes.Add((node, Parent)); DirectiveNodes.Add(new RazorIRNodeReference(Parent, node));
} }
} }
} }

View File

@ -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<DirectiveTokenIRNode> Tokens => Children.OfType<DirectiveTokenIRNode>();
public DirectiveDescriptor Descriptor { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
visitor.VisitMalformedDirective(this);
}
}
}

View File

@ -29,6 +29,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
VisitDefault(node); VisitDefault(node);
} }
public virtual void VisitMalformedDirective(MalformedDirectiveIRNode node)
{
VisitDefault(node);
}
public virtual void VisitExtension(ExtensionIRNode node) public virtual void VisitExtension(ExtensionIRNode node)
{ {
VisitDefault(node); VisitDefault(node);

View File

@ -2,19 +2,24 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
internal class AddTagHelperChunkGenerator : SpanChunkGenerator internal class AddTagHelperChunkGenerator : SpanChunkGenerator
{ {
public AddTagHelperChunkGenerator(string lookupText) public AddTagHelperChunkGenerator(string lookupText, List<RazorDiagnostic> diagnostics)
{ {
LookupText = lookupText; LookupText = lookupText;
Diagnostics = diagnostics;
} }
public string LookupText { get; } public string LookupText { get; }
public List<RazorDiagnostic> Diagnostics { get; }
public override void Accept(ParserVisitor visitor, Span span) public override void Accept(ParserVisitor visitor, Span span)
{ {
visitor.VisitAddTagHelperSpan(this, span); visitor.VisitAddTagHelperSpan(this, span);
@ -25,6 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
var other = obj as AddTagHelperChunkGenerator; var other = obj as AddTagHelperChunkGenerator;
return base.Equals(other) && return base.Equals(other) &&
Enumerable.SequenceEqual(Diagnostics, other.Diagnostics) &&
string.Equals(LookupText, other.LookupText, StringComparison.Ordinal); string.Equals(LookupText, other.LookupText, StringComparison.Ordinal);
} }

View File

@ -91,11 +91,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
foreach (var directive in directives) foreach (var directive in directives)
{ {
_directiveParsers.Add(directive, () => _directiveParsers.Add(directive, handler);
{
EnsureDirectiveIsAtStartOfLine();
handler();
});
Keywords.Add(directive); Keywords.Add(directive);
// These C# keywords are reserved for use in directives. It's an error to use them outside of // 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) private void HandleDirective(DirectiveDescriptor descriptor)
{ {
Context.Builder.CurrentBlock.Type = BlockKindInternal.Directive;
Context.Builder.CurrentBlock.ChunkGenerator = new DirectiveChunkGenerator(descriptor);
AssertDirective(descriptor.Directive); AssertDirective(descriptor.Directive);
AcceptAndMoveNext(); var directiveErrorSink = new ErrorSink();
Output(SpanKindInternal.MetaCode, AcceptedCharactersInternal.None); 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]; EnsureDirectiveIsAtStartOfLine();
AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true));
if (tokenDescriptor.Kind == DirectiveTokenKind.Member || Context.Builder.CurrentBlock.Type = BlockKindInternal.Directive;
tokenDescriptor.Kind == DirectiveTokenKind.Namespace || Context.Builder.CurrentBlock.ChunkGenerator = directiveChunkGenerator;
tokenDescriptor.Kind == DirectiveTokenKind.Type)
AcceptAndMoveNext();
Output(SpanKindInternal.MetaCode, AcceptedCharactersInternal.None);
for (var i = 0; i < descriptor.Tokens.Count; i++)
{ {
Span.ChunkGenerator = SpanChunkGenerator.Null; if (!At(CSharpSymbolType.WhiteSpace) &&
Output(SpanKindInternal.Code, AcceptedCharactersInternal.WhiteSpace); !At(CSharpSymbolType.NewLine) &&
} !EndOfFile)
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)
{ {
Context.ErrorSink.OnError( Context.ErrorSink.OnError(
CurrentStart, CurrentStart,
LegacyResources.FormatUnexpectedDirectiveLiteral(descriptor.Directive, LegacyResources.ErrorComponent_Newline), Resources.FormatDirectiveTokensMustBeSeparatedByWhitespace(descriptor.Directive),
CurrentSymbol.Content.Length); length: CurrentSymbol.Content.Length);
return;
} }
Output(SpanKindInternal.MetaCode, AcceptedCharactersInternal.WhiteSpace); var tokenDescriptor = descriptor.Tokens[i];
break; AcceptWhile(IsSpacingToken(includeNewLines: false, includeComments: true));
case DirectiveKind.RazorBlock:
AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: true));
Output(SpanKindInternal.Markup, AcceptedCharactersInternal.AllWhiteSpace);
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. Span.ChunkGenerator = SpanChunkGenerator.Null;
// For instance, if <div>@hello.</div> is in a nested C# block we don't want the trailing '.' to be handled Output(SpanKindInternal.Code, AcceptedCharactersInternal.WhiteSpace);
// as C#; it should be handled as a period because it's wrapped in markup. }
var wasNested = IsNested; else
IsNested = false; {
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; Output(SpanKindInternal.MetaCode, AcceptedCharactersInternal.WhiteSpace);
Initialize(Span); 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 <div>@hello.</div> 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(); using (PushSpanConfig())
}); {
break; HtmlParser.ParseRazorBlock(Tuple.Create("{", "}"), caseSensitive: true);
case DirectiveKind.CodeBlock: }
AcceptWhile(IsSpacingToken(includeNewLines: true, includeComments: true));
Output(SpanKindInternal.Markup, AcceptedCharactersInternal.AllWhiteSpace);
ParseDirectiveBlock(descriptor, parseChildren: (startingBraceLocation) => Span.Start = CurrentLocation;
{ Initialize(Span);
NextToken();
Balance(BalancingModes.NoErrorOnFailure, CSharpSymbolType.LeftBrace, CSharpSymbolType.RightBrace, startingBraceLocation); IsNested = wasNested;
Span.ChunkGenerator = new StatementChunkGenerator();
Output(SpanKindInternal.Code); NextToken();
}); });
break; 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( TagHelperDirective(
SyntaxConstants.CSharp.TagHelperPrefixKeyword, SyntaxConstants.CSharp.TagHelperPrefixKeyword,
prefix => new TagHelperPrefixDirectiveChunkGenerator(prefix)); (prefix, errors) => new TagHelperPrefixDirectiveChunkGenerator(prefix, errors));
} }
protected virtual void AddTagHelperDirective() protected virtual void AddTagHelperDirective()
{ {
TagHelperDirective( TagHelperDirective(
SyntaxConstants.CSharp.AddTagHelperKeyword, SyntaxConstants.CSharp.AddTagHelperKeyword,
lookupText => new AddTagHelperChunkGenerator(lookupText)); (lookupText, errors) => new AddTagHelperChunkGenerator(lookupText, errors));
} }
protected virtual void RemoveTagHelperDirective() protected virtual void RemoveTagHelperDirective()
{ {
TagHelperDirective( TagHelperDirective(
SyntaxConstants.CSharp.RemoveTagHelperKeyword, SyntaxConstants.CSharp.RemoveTagHelperKeyword,
lookupText => new RemoveTagHelperChunkGenerator(lookupText)); (lookupText, errors) => new RemoveTagHelperChunkGenerator(lookupText, errors));
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
@ -1866,63 +1894,86 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Output(SpanKindInternal.Code, AcceptedCharactersInternal.AnyExceptNewline); Output(SpanKindInternal.Code, AcceptedCharactersInternal.AnyExceptNewline);
} }
private void TagHelperDirective(string keyword, Func<string, ISpanChunkGenerator> chunkGeneratorFactory) private void TagHelperDirective(string keyword, Func<string, List<RazorDiagnostic>, ISpanChunkGenerator> chunkGeneratorFactory)
{ {
AssertDirective(keyword); AssertDirective(keyword);
var keywordStartLocation = CurrentStart;
// Accept the directive name var savedErrorSink = Context.ErrorSink;
AcceptAndMoveNext(); var directiveErrorSink = new ErrorSink();
Context.ErrorSink = directiveErrorSink;
// Set the block type string directiveValue = null;
Context.Builder.CurrentBlock.Type = BlockKindInternal.Directive; try
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))
{ {
Context.ErrorSink.OnError( EnsureDirectiveIsAtStartOfLine();
keywordStartLocation,
LegacyResources.FormatParseError_DirectiveMustHaveValue(keyword),
keywordLength);
chunkGenerator = chunkGeneratorFactory(string.Empty); var keywordStartLocation = CurrentStart;
}
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 // Accept the directive name
// etc. AcceptAndMoveNext();
AcceptUntil(CSharpSymbolType.NewLine);
// Pull out the value and remove whitespaces and optional quotes // Set the block type
var rawValue = string.Concat(Span.Symbols.Select(s => s.Content)).Trim(); Context.Builder.CurrentBlock.Type = BlockKindInternal.Directive;
var startsWithQuote = rawValue.StartsWith("\"", StringComparison.Ordinal); var keywordLength = Span.End.AbsoluteIndex - Span.Start.AbsoluteIndex;
var endsWithQuote = rawValue.EndsWith("\"", StringComparison.Ordinal);
if (startsWithQuote != endsWithQuote) 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( Context.ErrorSink.OnError(
startLocation, keywordStartLocation,
LegacyResources.FormatParseError_IncompleteQuotesAroundDirective(keyword), LegacyResources.FormatParseError_DirectiveMustHaveValue(keyword),
rawValue.Length); 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<RazorDiagnostic> directiveErrors;
if (directiveErrorSink.Errors.Count > 0)
{
directiveErrors = directiveErrorSink.Errors.Select(RazorDiagnostic.Create).ToList();
}
else
{
directiveErrors = new List<RazorDiagnostic>();
} }
chunkGenerator = chunkGeneratorFactory(rawValue); Span.ChunkGenerator = chunkGeneratorFactory(directiveValue, directiveErrors);
Context.ErrorSink = savedErrorSink;
} }
Span.ChunkGenerator = chunkGenerator;
// Output the span and finish the block // Output the span and finish the block
CompleteBlock(); CompleteBlock();
Output(SpanKindInternal.Code, AcceptedCharactersInternal.AnyExceptNewline); Output(SpanKindInternal.Code, AcceptedCharactersInternal.AnyExceptNewline);

View File

@ -2,6 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
@ -9,6 +12,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
internal class DirectiveChunkGenerator : ParentChunkGenerator internal class DirectiveChunkGenerator : ParentChunkGenerator
{ {
private static readonly Type Type = typeof(DirectiveChunkGenerator); private static readonly Type Type = typeof(DirectiveChunkGenerator);
private List<RazorDiagnostic> _diagnostics;
public DirectiveChunkGenerator(DirectiveDescriptor descriptor) public DirectiveChunkGenerator(DirectiveDescriptor descriptor)
{ {
@ -17,6 +21,19 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
public DirectiveDescriptor Descriptor { get; } public DirectiveDescriptor Descriptor { get; }
public List<RazorDiagnostic> Diagnostics
{
get
{
if (_diagnostics == null)
{
_diagnostics = new List<RazorDiagnostic>();
}
return _diagnostics;
}
}
public override void Accept(ParserVisitor visitor, Block block) public override void Accept(ParserVisitor visitor, Block block)
{ {
visitor.VisitDirectiveBlock(this, block); visitor.VisitDirectiveBlock(this, block);
@ -26,6 +43,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
var other = obj as DirectiveChunkGenerator; var other = obj as DirectiveChunkGenerator;
return base.Equals(other) && return base.Equals(other) &&
Enumerable.SequenceEqual(Diagnostics, other.Diagnostics) &&
DirectiveDescriptorComparer.Default.Equals(Descriptor, other.Descriptor); DirectiveDescriptorComparer.Default.Equals(Descriptor, other.Descriptor);
} }
@ -37,5 +55,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
return combiner.CombinedHash; 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();
}
} }
} }

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
public SyntaxTreeBuilder Builder { get; } public SyntaxTreeBuilder Builder { get; }
public ErrorSink ErrorSink { get; } public ErrorSink ErrorSink { get; set; }
public ITextDocument Source { get; } public ITextDocument Source { get; }

View File

@ -2,19 +2,24 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
internal class RemoveTagHelperChunkGenerator : SpanChunkGenerator internal class RemoveTagHelperChunkGenerator : SpanChunkGenerator
{ {
public RemoveTagHelperChunkGenerator(string lookupText) public RemoveTagHelperChunkGenerator(string lookupText, List<RazorDiagnostic> diagnostics)
{ {
LookupText = lookupText; LookupText = lookupText;
Diagnostics = diagnostics;
} }
public string LookupText { get; } public string LookupText { get; }
public List<RazorDiagnostic> Diagnostics { get; }
public override void Accept(ParserVisitor visitor, Span span) public override void Accept(ParserVisitor visitor, Span span)
{ {
visitor.VisitRemoveTagHelperSpan(this, span); visitor.VisitRemoveTagHelperSpan(this, span);
@ -25,6 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
var other = obj as RemoveTagHelperChunkGenerator; var other = obj as RemoveTagHelperChunkGenerator;
return base.Equals(other) && return base.Equals(other) &&
Enumerable.SequenceEqual(Diagnostics, other.Diagnostics) &&
string.Equals(LookupText, other.LookupText, StringComparison.Ordinal); string.Equals(LookupText, other.LookupText, StringComparison.Ordinal);
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
@ -41,5 +42,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
/// The <see cref="TagHelperDirectiveType"/> of this directive. /// The <see cref="TagHelperDirectiveType"/> of this directive.
/// </summary> /// </summary>
public TagHelperDirectiveType DirectiveType { get; set; } public TagHelperDirectiveType DirectiveType { get; set; }
public List<RazorDiagnostic> Diagnostics { get; set; }
} }
} }

View File

@ -2,19 +2,24 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Razor.Language.Legacy namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
internal class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator internal class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator
{ {
public TagHelperPrefixDirectiveChunkGenerator(string prefix) public TagHelperPrefixDirectiveChunkGenerator(string prefix, List<RazorDiagnostic> diagnostics)
{ {
Prefix = prefix; Prefix = prefix;
Diagnostics = diagnostics;
} }
public string Prefix { get; } public string Prefix { get; }
public List<RazorDiagnostic> Diagnostics { get; }
public override void Accept(ParserVisitor visitor, Span span) public override void Accept(ParserVisitor visitor, Span span)
{ {
visitor.VisitTagHelperPrefixDirectiveSpan(this, span); visitor.VisitTagHelperPrefixDirectiveSpan(this, span);
@ -25,6 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
var other = obj as TagHelperPrefixDirectiveChunkGenerator; var other = obj as TagHelperPrefixDirectiveChunkGenerator;
return base.Equals(other) && return base.Equals(other) &&
Enumerable.SequenceEqual(Diagnostics, other.Diagnostics) &&
string.Equals(Prefix, other.Prefix, StringComparison.Ordinal); string.Equals(Prefix, other.Prefix, StringComparison.Ordinal);
} }

View File

@ -444,6 +444,20 @@ namespace Microsoft.AspNetCore.Razor.Language
internal static string FormatDirectiveMustAppearAtStartOfLine(object p0) internal static string FormatDirectiveMustAppearAtStartOfLine(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("DirectiveMustAppearAtStartOfLine"), p0); => string.Format(CultureInfo.CurrentCulture, GetString("DirectiveMustAppearAtStartOfLine"), p0);
/// <summary>
/// The '{0}' directives value(s) must be separated by whitespace.
/// </summary>
internal static string DirectiveTokensMustBeSeparatedByWhitespace
{
get => GetString("DirectiveTokensMustBeSeparatedByWhitespace");
}
/// <summary>
/// The '{0}' directives value(s) must be separated by whitespace.
/// </summary>
internal static string FormatDirectiveTokensMustBeSeparatedByWhitespace(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("DirectiveTokensMustBeSeparatedByWhitespace"), p0);
/// <summary> /// <summary>
/// The key must not be null. /// The key must not be null.
/// </summary> /// </summary>

View File

@ -210,6 +210,9 @@
<data name="DirectiveMustAppearAtStartOfLine" xml:space="preserve"> <data name="DirectiveMustAppearAtStartOfLine" xml:space="preserve">
<value>The '{0}` directive must appear at the start of the line.</value> <value>The '{0}` directive must appear at the start of the line.</value>
</data> </data>
<data name="DirectiveTokensMustBeSeparatedByWhitespace" xml:space="preserve">
<value>The '{0}' directives value(s) must be separated by whitespace.</value>
</data>
<data name="KeyMustNotBeNull" xml:space="preserve"> <data name="KeyMustNotBeNull" xml:space="preserve">
<value>The key must not be null.</value> <value>The key must not be null.</value>
</data> </data>

View File

@ -28,10 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.IntegrationTests
public void InvalidNamespaceAtEOF_Runtime() public void InvalidNamespaceAtEOF_Runtime()
{ {
var references = CreateCompilationReferences(CurrentMvcShim); var references = CreateCompilationReferences(CurrentMvcShim);
RunRuntimeTest(references, expectedErrors: new[] RunRuntimeTest(references);
{
"Identifier expected"
});
} }
[Fact] [Fact]
@ -44,10 +41,7 @@ public class MyService<TModel>
}"; }";
var compilationReferences = CreateCompilationReferences(CurrentMvcShim, appCode); var compilationReferences = CreateCompilationReferences(CurrentMvcShim, appCode);
RunRuntimeTest(compilationReferences, expectedErrors: new[] RunRuntimeTest(compilationReferences);
{
"Identifier expected"
});
} }
[Fact] [Fact]
@ -267,7 +261,7 @@ public class AllTagHelper : {typeof(TagHelper).FullName}
public void InvalidNamespaceAtEOF_DesignTime() public void InvalidNamespaceAtEOF_DesignTime()
{ {
var references = CreateCompilationReferences(CurrentMvcShim); var references = CreateCompilationReferences(CurrentMvcShim);
RunDesignTimeTest(references, expectedErrors: new[] { "Identifier expected" }); RunDesignTimeTest(references);
} }
[Fact] [Fact]
@ -281,12 +275,7 @@ public class MyService<TModel>
"; ";
var references = CreateCompilationReferences(CurrentMvcShim, appCode); var references = CreateCompilationReferences(CurrentMvcShim, appCode);
RunDesignTimeTest( RunDesignTimeTest(references);
references,
expectedErrors: new[]
{
"Identifier expected"
});
} }
[Fact] [Fact]

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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;
using Microsoft.AspNetCore.Razor.Language.Intermediate; using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit; using Xunit;
@ -9,24 +10,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{ {
public class PageDirectiveTest 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] [Fact]
public void TryGetPageDirective_ReturnsFalse_IfPageDoesNotHaveDirective() public void TryGetPageDirective_ReturnsFalse_IfPageDoesNotHaveDirective()
{ {

View File

@ -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 #line hidden
using TModel = global::System.Object; using TModel = global::System.Object;

View File

@ -1,5 +1,7 @@
Document - 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 - - TModel = global::System.Object
UsingStatement - (1:0,1 [12] ) - System UsingStatement - (1:0,1 [12] ) - System
UsingStatement - (16:1,1 [32] ) - System.Collections.Generic UsingStatement - (16:1,1 [32] ) - System.Collections.Generic
@ -29,20 +31,29 @@ Document -
MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync
HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml) HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml)
RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n
MalformedDirective - (102:4,0 [6] IncompleteDirectives.cshtml)
HtmlContent - (108:4,6 [5] IncompleteDirectives.cshtml) HtmlContent - (108:4,6 [5] IncompleteDirectives.cshtml)
RazorIRToken - (108:4,6 [5] IncompleteDirectives.cshtml) - Html - "\n\n RazorIRToken - (108:4,6 [5] IncompleteDirectives.cshtml) - Html - "\n\n
MalformedDirective - (113:6,0 [6] IncompleteDirectives.cshtml)
HtmlContent - (119:6,6 [2] IncompleteDirectives.cshtml) HtmlContent - (119:6,6 [2] IncompleteDirectives.cshtml)
RazorIRToken - (119:6,6 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (119:6,6 [2] IncompleteDirectives.cshtml) - Html - \n
MalformedDirective - (121:7,0 [7] IncompleteDirectives.cshtml)
HtmlContent - (128:7,7 [4] IncompleteDirectives.cshtml) HtmlContent - (128:7,7 [4] IncompleteDirectives.cshtml)
RazorIRToken - (128:7,7 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (128:7,7 [4] IncompleteDirectives.cshtml) - Html - \n\n
MalformedDirective - (132:9,0 [7] IncompleteDirectives.cshtml)
HtmlContent - (139:9,7 [2] IncompleteDirectives.cshtml) HtmlContent - (139:9,7 [2] IncompleteDirectives.cshtml)
RazorIRToken - (139:9,7 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (139:9,7 [2] IncompleteDirectives.cshtml) - Html - \n
MalformedDirective - (141:10,0 [8] IncompleteDirectives.cshtml)
HtmlContent - (149:10,8 [2] IncompleteDirectives.cshtml) HtmlContent - (149:10,8 [2] IncompleteDirectives.cshtml)
RazorIRToken - (149:10,8 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (149:10,8 [2] IncompleteDirectives.cshtml) - Html - \n
MalformedDirective - (151:11,0 [25] IncompleteDirectives.cshtml)
DirectiveToken - (159:11,8 [17] IncompleteDirectives.cshtml) - MyService<TModel>
HtmlContent - (176:11,25 [4] IncompleteDirectives.cshtml) HtmlContent - (176:11,25 [4] IncompleteDirectives.cshtml)
RazorIRToken - (176:11,25 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (176:11,25 [4] IncompleteDirectives.cshtml) - Html - \n\n
MalformedDirective - (180:13,0 [10] IncompleteDirectives.cshtml)
HtmlContent - (190:13,10 [2] IncompleteDirectives.cshtml) HtmlContent - (190:13,10 [2] IncompleteDirectives.cshtml)
RazorIRToken - (190:13,10 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (190:13,10 [2] IncompleteDirectives.cshtml) - Html - \n
MalformedDirective - (192:14,0 [11] IncompleteDirectives.cshtml)
HtmlContent - (203:14,11 [2] IncompleteDirectives.cshtml) HtmlContent - (203:14,11 [2] IncompleteDirectives.cshtml)
RazorIRToken - (203:14,11 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (203:14,11 [2] IncompleteDirectives.cshtml) - Html - \n
InjectDirective - InjectDirective -

View File

@ -1,5 +1,5 @@
Source Location: (159:11,8 [17] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives.cshtml) Source Location: (159:11,8 [17] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives.cshtml)
|MyService<TModel>| |MyService<TModel>|
Generated Location: (616:16,0 [17] ) Generated Location: (833:17,0 [17] )
|MyService<TModel>| |MyService<TModel>|

View File

@ -1,5 +1,6 @@
#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/IncompleteDirectives.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "fec5cf763044f842fa2114e997bb07e0bf280cd6" #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 #line hidden
using System; using System;

View File

@ -1,5 +1,7 @@
Document - 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 - (1:0,1 [14] ) - System
UsingStatement - (16:1,1 [34] ) - System.Collections.Generic UsingStatement - (16:1,1 [34] ) - System.Collections.Generic
UsingStatement - (51:2,1 [19] ) - System.Linq UsingStatement - (51:2,1 [19] ) - System.Linq
@ -15,48 +17,57 @@ Document -
RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - EndContext(); RazorIRToken - - CSharp - EndContext();
MalformedDirective - (102:4,0 [6] IncompleteDirectives.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(108, 5, true); RazorIRToken - - CSharp - BeginContext(108, 5, true);
HtmlContent - (108:4,6 [5] IncompleteDirectives.cshtml) HtmlContent - (108:4,6 [5] IncompleteDirectives.cshtml)
RazorIRToken - (108:4,6 [5] IncompleteDirectives.cshtml) - Html - "\n\n RazorIRToken - (108:4,6 [5] IncompleteDirectives.cshtml) - Html - "\n\n
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - EndContext(); RazorIRToken - - CSharp - EndContext();
MalformedDirective - (113:6,0 [6] IncompleteDirectives.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(119, 2, true); RazorIRToken - - CSharp - BeginContext(119, 2, true);
HtmlContent - (119:6,6 [2] IncompleteDirectives.cshtml) HtmlContent - (119:6,6 [2] IncompleteDirectives.cshtml)
RazorIRToken - (119:6,6 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (119:6,6 [2] IncompleteDirectives.cshtml) - Html - \n
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - EndContext(); RazorIRToken - - CSharp - EndContext();
MalformedDirective - (121:7,0 [7] IncompleteDirectives.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(128, 4, true); RazorIRToken - - CSharp - BeginContext(128, 4, true);
HtmlContent - (128:7,7 [4] IncompleteDirectives.cshtml) HtmlContent - (128:7,7 [4] IncompleteDirectives.cshtml)
RazorIRToken - (128:7,7 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (128:7,7 [4] IncompleteDirectives.cshtml) - Html - \n\n
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - EndContext(); RazorIRToken - - CSharp - EndContext();
MalformedDirective - (132:9,0 [7] IncompleteDirectives.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(139, 2, true); RazorIRToken - - CSharp - BeginContext(139, 2, true);
HtmlContent - (139:9,7 [2] IncompleteDirectives.cshtml) HtmlContent - (139:9,7 [2] IncompleteDirectives.cshtml)
RazorIRToken - (139:9,7 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (139:9,7 [2] IncompleteDirectives.cshtml) - Html - \n
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - EndContext(); RazorIRToken - - CSharp - EndContext();
MalformedDirective - (141:10,0 [8] IncompleteDirectives.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(149, 2, true); RazorIRToken - - CSharp - BeginContext(149, 2, true);
HtmlContent - (149:10,8 [2] IncompleteDirectives.cshtml) HtmlContent - (149:10,8 [2] IncompleteDirectives.cshtml)
RazorIRToken - (149:10,8 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (149:10,8 [2] IncompleteDirectives.cshtml) - Html - \n
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - EndContext(); RazorIRToken - - CSharp - EndContext();
MalformedDirective - (151:11,0 [25] IncompleteDirectives.cshtml)
DirectiveToken - (159:11,8 [17] IncompleteDirectives.cshtml) - MyService<TModel>
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(176, 4, true); RazorIRToken - - CSharp - BeginContext(176, 4, true);
HtmlContent - (176:11,25 [4] IncompleteDirectives.cshtml) HtmlContent - (176:11,25 [4] IncompleteDirectives.cshtml)
RazorIRToken - (176:11,25 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (176:11,25 [4] IncompleteDirectives.cshtml) - Html - \n\n
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - EndContext(); RazorIRToken - - CSharp - EndContext();
MalformedDirective - (180:13,0 [10] IncompleteDirectives.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(190, 2, true); RazorIRToken - - CSharp - BeginContext(190, 2, true);
HtmlContent - (190:13,10 [2] IncompleteDirectives.cshtml) HtmlContent - (190:13,10 [2] IncompleteDirectives.cshtml)
RazorIRToken - (190:13,10 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (190:13,10 [2] IncompleteDirectives.cshtml) - Html - \n
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - EndContext(); RazorIRToken - - CSharp - EndContext();
MalformedDirective - (192:14,0 [11] IncompleteDirectives.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(203, 2, true); RazorIRToken - - CSharp - BeginContext(203, 2, true);
HtmlContent - (203:14,11 [2] IncompleteDirectives.cshtml) HtmlContent - (203:14,11 [2] IncompleteDirectives.cshtml)

View File

@ -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 #line hidden
using TModel = global::System.Object; using TModel = global::System.Object;

View File

@ -1,5 +1,7 @@
Document - 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 - - TModel = global::System.Object
UsingStatement - (1:0,1 [12] ) - System UsingStatement - (1:0,1 [12] ) - System
UsingStatement - (16:1,1 [32] ) - System.Collections.Generic UsingStatement - (16:1,1 [32] ) - System.Collections.Generic
@ -26,6 +28,7 @@ Document -
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - private static System.Object __o = null; RazorIRToken - - CSharp - private static System.Object __o = null;
MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync
MalformedDirective - (0:0,0 [11] InvalidNamespaceAtEOF.cshtml)
HtmlContent - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) HtmlContent - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml)
RazorIRToken - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) - Html - Test. RazorIRToken - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) - Html - Test.
InjectDirective - InjectDirective -

View File

@ -1,5 +1,6 @@
#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InvalidNamespaceAtEOF.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "de132bd3e2a46a0d2ec953a168427c01e5829cde" #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 #line hidden
using System; using System;

View File

@ -1,5 +1,7 @@
Document - 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 - (1:0,1 [14] ) - System
UsingStatement - (16:1,1 [34] ) - System.Collections.Generic UsingStatement - (16:1,1 [34] ) - System.Collections.Generic
UsingStatement - (51:2,1 [19] ) - System.Linq UsingStatement - (51:2,1 [19] ) - System.Linq
@ -9,6 +11,7 @@ Document -
UsingStatement - (178:6,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures UsingStatement - (178:6,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic> - ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InvalidNamespaceAtEOF_cshtml - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic> -
MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync
MalformedDirective - (0:0,0 [11] InvalidNamespaceAtEOF.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(11, 5, true); RazorIRToken - - CSharp - BeginContext(11, 5, true);
HtmlContent - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml) HtmlContent - (11:0,11 [5] InvalidNamespaceAtEOF.cshtml)

View File

@ -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 namespace AspNetCore
{ {
#line hidden #line hidden
@ -10,7 +10,7 @@ namespace AspNetCore
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures; 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<dynamic>
{ {
#pragma warning disable 219 #pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() { private void __RazorDirectiveTokenHelpers__() {
@ -31,8 +31,6 @@ namespace AspNetCore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> Html { get; private set; } public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml>)PageContext?.ViewData;
public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;
} }
} }

View File

@ -1,6 +1,6 @@
Document - Document -
CSharpCode - 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 NamespaceDeclaration - - AspNetCore
UsingStatement - - TModel = global::System.Object UsingStatement - - TModel = global::System.Object
UsingStatement - (1:0,1 [12] ) - System UsingStatement - (1:0,1 [12] ) - System
@ -10,7 +10,7 @@ Document -
UsingStatement - (102:4,1 [30] ) - Microsoft.AspNetCore.Mvc UsingStatement - (102:4,1 [30] ) - Microsoft.AspNetCore.Mvc
UsingStatement - (135:5,1 [40] ) - Microsoft.AspNetCore.Mvc.Rendering UsingStatement - (135:5,1 [40] ) - Microsoft.AspNetCore.Mvc.Rendering
UsingStatement - (178:6,1 [43] ) - Microsoft.AspNetCore.Mvc.ViewFeatures 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<dynamic> -
DesignTimeDirective - DesignTimeDirective -
DirectiveToken - (231:7,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> DirectiveToken - (231:7,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel>
DirectiveToken - (294:7,71 [4] ) - Html DirectiveToken - (294:7,71 [4] ) - Html
@ -28,6 +28,7 @@ Document -
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - private static System.Object __o = null; RazorIRToken - - CSharp - private static System.Object __o = null;
MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync
MalformedDirective - (0:0,0 [6] MalformedPageDirective.cshtml)
HtmlContent - (6:0,6 [49] MalformedPageDirective.cshtml) HtmlContent - (6:0,6 [49] MalformedPageDirective.cshtml)
RazorIRToken - (6:0,6 [8] MalformedPageDirective.cshtml) - Html - "foo\n\n RazorIRToken - (6:0,6 [8] MalformedPageDirective.cshtml) - Html - "foo\n\n
RazorIRToken - (14:2,0 [4] MalformedPageDirective.cshtml) - Html - <h1> RazorIRToken - (14:2,0 [4] MalformedPageDirective.cshtml) - Html - <h1>
@ -42,7 +43,3 @@ Document -
InjectDirective - InjectDirective -
InjectDirective - InjectDirective -
InjectDirective - InjectDirective -
CSharpCode -
RazorIRToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml>)PageContext?.ViewData;
CSharpCode -
RazorIRToken - - CSharp - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;

View File

@ -1,5 +1,5 @@
#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/MalformedPageDirective.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "5a9ff8440150c6746e4a8ba63bc633ea84930405" #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 namespace AspNetCore
{ {
#line hidden #line hidden
@ -10,7 +10,7 @@ namespace AspNetCore
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures; 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<dynamic>
{ {
#pragma warning disable 1998 #pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync() public async override global::System.Threading.Tasks.Task ExecuteAsync()
@ -29,8 +29,6 @@ namespace AspNetCore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> Html { get; private set; } public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml>)PageContext?.ViewData;
public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;
} }
} }

View File

@ -1,6 +1,6 @@
Document - Document -
CSharpCode - 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 NamespaceDeclaration - - AspNetCore
UsingStatement - (1:0,1 [14] ) - System UsingStatement - (1:0,1 [14] ) - System
UsingStatement - (16:1,1 [34] ) - System.Collections.Generic UsingStatement - (16:1,1 [34] ) - System.Collections.Generic
@ -9,8 +9,9 @@ Document -
UsingStatement - (102:4,1 [32] ) - Microsoft.AspNetCore.Mvc UsingStatement - (102:4,1 [32] ) - Microsoft.AspNetCore.Mvc
UsingStatement - (135:5,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering UsingStatement - (135:5,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering
UsingStatement - (178:6,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures 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<dynamic> -
MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync
MalformedDirective - (0:0,0 [6] MalformedPageDirective.cshtml)
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - BeginContext(6, 49, true); RazorIRToken - - CSharp - BeginContext(6, 49, true);
HtmlContent - (6:0,6 [49] MalformedPageDirective.cshtml) HtmlContent - (6:0,6 [49] MalformedPageDirective.cshtml)
@ -29,7 +30,3 @@ Document -
InjectDirective - InjectDirective -
InjectDirective - InjectDirective -
InjectDirective - InjectDirective -
CSharpCode -
RazorIRToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml>)PageContext?.ViewData;
CSharpCode -
RazorIRToken - - CSharp - public TestFiles_IntegrationTests_CodeGenerationIntegrationTest_MalformedPageDirective_cshtml Model => ViewData.Model;

View File

@ -7,7 +7,6 @@ using System.Linq;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
using Xunit; using Xunit;
using Moq;
namespace Microsoft.AspNetCore.Razor.Language namespace Microsoft.AspNetCore.Razor.Language
{ {
@ -54,7 +53,9 @@ namespace Microsoft.AspNetCore.Razor.Language
// Assert // Assert
var rewrittenTree = codeDocument.GetSyntaxTree(); var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); var directiveValue = rewrittenTree.Root.Children.OfType<Block>().First().Children.Last() as Span;
var chunkGenerator = Assert.IsType<AddTagHelperChunkGenerator>(directiveValue.ChunkGenerator);
Assert.Equal(expectedDiagnostics, chunkGenerator.Diagnostics);
} }
[Fact] [Fact]
@ -98,7 +99,9 @@ namespace Microsoft.AspNetCore.Razor.Language
// Assert // Assert
var rewrittenTree = codeDocument.GetSyntaxTree(); var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); var directiveValue = rewrittenTree.Root.Children.OfType<Block>().First().Children.Last() as Span;
var chunkGenerator = Assert.IsType<RemoveTagHelperChunkGenerator>(directiveValue.ChunkGenerator);
Assert.Equal(expectedDiagnostics, chunkGenerator.Diagnostics);
} }
[Fact] [Fact]
@ -142,7 +145,9 @@ namespace Microsoft.AspNetCore.Razor.Language
// Assert // Assert
var rewrittenTree = codeDocument.GetSyntaxTree(); var rewrittenTree = codeDocument.GetSyntaxTree();
Assert.Equal(expectedDiagnostics, rewrittenTree.Diagnostics); var directiveValue = rewrittenTree.Root.Children.OfType<Block>().First().Children.Last() as Span;
var chunkGenerator = Assert.IsType<TagHelperPrefixDirectiveChunkGenerator>(directiveValue.ChunkGenerator);
Assert.Equal(expectedDiagnostics, chunkGenerator.Diagnostics);
} }
[Fact] [Fact]
@ -464,7 +469,6 @@ namespace Microsoft.AspNetCore.Razor.Language
public void ParseAddOrRemoveDirective_CalculatesAssemblyLocationInLookupText(string text, int assemblyLocation) public void ParseAddOrRemoveDirective_CalculatesAssemblyLocationInLookupText(string text, int assemblyLocation)
{ {
// Arrange // Arrange
var errorSink = new ErrorSink();
var phase = new DefaultRazorTagHelperBinderPhase(); var phase = new DefaultRazorTagHelperBinderPhase();
var directive = new TagHelperDirectiveDescriptor() var directive = new TagHelperDirectiveDescriptor()
@ -472,15 +476,16 @@ namespace Microsoft.AspNetCore.Razor.Language
DirectiveText = text, DirectiveText = text,
DirectiveType = TagHelperDirectiveType.AddTagHelper, DirectiveType = TagHelperDirectiveType.AddTagHelper,
Location = SourceLocation.Zero, Location = SourceLocation.Zero,
Diagnostics = new List<RazorDiagnostic>(),
}; };
var expected = new SourceLocation(assemblyLocation, 0, assemblyLocation); var expected = new SourceLocation(assemblyLocation, 0, assemblyLocation);
// Act // Act
var result = phase.ParseAddOrRemoveDirective(directive, errorSink); var result = phase.ParseAddOrRemoveDirective(directive);
// Assert // Assert
Assert.Empty(errorSink.Errors); Assert.Empty(directive.Diagnostics);
Assert.Equal("foo", result.TypePattern); Assert.Equal("foo", result.TypePattern);
Assert.Equal("assemblyName", result.AssemblyName); Assert.Equal("assemblyName", result.AssemblyName);
Assert.Equal(expected, result.AssemblyNameLocation); Assert.Equal(expected, result.AssemblyNameLocation);
@ -505,7 +510,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = "th ", DirectiveText = "th ",
Location = directiveLocation1, Location = directiveLocation1,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix DirectiveType = TagHelperDirectiveType.TagHelperPrefix,
Diagnostics = new List<RazorDiagnostic>(),
}, },
}, },
new[] new[]
@ -527,7 +533,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = "th\t", DirectiveText = "th\t",
Location = directiveLocation1, Location = directiveLocation1,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix DirectiveType = TagHelperDirectiveType.TagHelperPrefix,
Diagnostics = new List<RazorDiagnostic>(),
} }
}, },
new[] new[]
@ -549,7 +556,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = "th" + Environment.NewLine, DirectiveText = "th" + Environment.NewLine,
Location = directiveLocation1, Location = directiveLocation1,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix DirectiveType = TagHelperDirectiveType.TagHelperPrefix,
Diagnostics = new List<RazorDiagnostic>(),
} }
}, },
new[] new[]
@ -571,7 +579,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = " th ", DirectiveText = " th ",
Location = directiveLocation1, Location = directiveLocation1,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix DirectiveType = TagHelperDirectiveType.TagHelperPrefix,
Diagnostics = new List<RazorDiagnostic>(),
} }
}, },
new[] new[]
@ -593,7 +602,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = "@", DirectiveText = "@",
Location = directiveLocation1, Location = directiveLocation1,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix DirectiveType = TagHelperDirectiveType.TagHelperPrefix,
Diagnostics = new List<RazorDiagnostic>(),
} }
}, },
new[] new[]
@ -615,7 +625,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = "t@h", DirectiveText = "t@h",
Location = directiveLocation1, Location = directiveLocation1,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix DirectiveType = TagHelperDirectiveType.TagHelperPrefix,
Diagnostics = new List<RazorDiagnostic>(),
} }
}, },
new[] new[]
@ -637,7 +648,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = "!", DirectiveText = "!",
Location = directiveLocation1, Location = directiveLocation1,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix DirectiveType = TagHelperDirectiveType.TagHelperPrefix,
Diagnostics = new List<RazorDiagnostic>(),
} }
}, },
new[] new[]
@ -659,7 +671,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = "!th", DirectiveText = "!th",
Location = directiveLocation1, Location = directiveLocation1,
DirectiveType = TagHelperDirectiveType.TagHelperPrefix DirectiveType = TagHelperDirectiveType.TagHelperPrefix,
Diagnostics = new List<RazorDiagnostic>(),
} }
}, },
new[] new[]
@ -685,18 +698,18 @@ namespace Microsoft.AspNetCore.Razor.Language
object expectedErrors) object expectedErrors)
{ {
// Arrange // Arrange
var errorSink = new ErrorSink(); var expectedDiagnostics = ((IEnumerable<RazorError>)expectedErrors).Select(RazorDiagnostic.Create);
var tagHelperDirectives = (IEnumerable<TagHelperDirectiveDescriptor>)directives;
var phase = new DefaultRazorTagHelperBinderPhase(); var phase = new DefaultRazorTagHelperBinderPhase();
// Act // Act
foreach (var directive in ((IEnumerable<TagHelperDirectiveDescriptor>)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
Assert.Equal(((IEnumerable<RazorError>)expectedErrors).ToArray(), errorSink.Errors.ToArray()); Assert.Equal(expectedDiagnostics, tagHelperDirectives.SelectMany(directive => directive.Diagnostics));
} }
private static string AssemblyA => "TestAssembly"; private static string AssemblyA => "TestAssembly";
@ -836,15 +849,15 @@ namespace Microsoft.AspNetCore.Razor.Language
string expectedPrefix) string expectedPrefix)
{ {
// Arrange // Arrange
var errorSink = new ErrorSink();
var phase = new DefaultRazorTagHelperBinderPhase(); var phase = new DefaultRazorTagHelperBinderPhase();
var document = RazorCodeDocument.Create(new StringSourceDocument("Test content", encoding: Encoding.UTF8, filePath: "TestFile")); var document = RazorCodeDocument.Create(new StringSourceDocument("Test content", encoding: Encoding.UTF8, filePath: "TestFile"));
var tagHelperDirectives = (IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors;
// Act // Act
var prefix = phase.ProcessTagHelperPrefix(((IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors).ToList(), document, errorSink); var prefix = phase.ProcessTagHelperPrefix(((IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors).ToList(), document);
// Assert // Assert
Assert.Empty(errorSink.Errors); Assert.Empty(tagHelperDirectives.SelectMany(directive => directive.Diagnostics));
Assert.Equal(expectedPrefix, prefix); Assert.Equal(expectedPrefix, prefix);
} }
@ -1056,20 +1069,17 @@ namespace Microsoft.AspNetCore.Razor.Language
object expectedDescriptors) object expectedDescriptors)
{ {
// Arrange // Arrange
var errorSink = new ErrorSink();
var phase = new DefaultRazorTagHelperBinderPhase(); var phase = new DefaultRazorTagHelperBinderPhase();
var tagHelperDirectives = (IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors;
var expected = (IEnumerable<TagHelperDescriptor>)expectedDescriptors; var expected = (IEnumerable<TagHelperDescriptor>)expectedDescriptors;
// Act // Act
var results = phase.ProcessDirectives( var results = phase.ProcessDirectives(
new List<TagHelperDirectiveDescriptor>((IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors), new List<TagHelperDirectiveDescriptor>(tagHelperDirectives),
new List<TagHelperDescriptor>((IEnumerable<TagHelperDescriptor>)tagHelpers), new List<TagHelperDescriptor>((IEnumerable<TagHelperDescriptor>)tagHelpers));
errorSink);
// Assert // Assert
Assert.Empty(errorSink.Errors); Assert.Empty(tagHelperDirectives.SelectMany(directive => directive.Diagnostics));
Assert.Equal(expected.Count(), results.Count()); Assert.Equal(expected.Count(), results.Count());
foreach (var expectedDescriptor in expected) foreach (var expectedDescriptor in expected)
@ -1224,15 +1234,13 @@ namespace Microsoft.AspNetCore.Razor.Language
object directiveDescriptors) object directiveDescriptors)
{ {
// Arrange // Arrange
var errorSink = new ErrorSink(); var tagHelperDirectives = (IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors;
var phase = new DefaultRazorTagHelperBinderPhase(); var phase = new DefaultRazorTagHelperBinderPhase();
// Act // Act
var results = phase.ProcessDirectives( var results = phase.ProcessDirectives(
new List<TagHelperDirectiveDescriptor>((IEnumerable<TagHelperDirectiveDescriptor>)directiveDescriptors), new List<TagHelperDirectiveDescriptor>(tagHelperDirectives),
new List<TagHelperDescriptor>((IEnumerable<TagHelperDescriptor>)tagHelpers), new List<TagHelperDescriptor>((IEnumerable<TagHelperDescriptor>)tagHelpers));
errorSink);
// Assert // Assert
Assert.Empty(results); Assert.Empty(results);
@ -1264,26 +1272,24 @@ namespace Microsoft.AspNetCore.Razor.Language
public void ProcessDirectives_IgnoresSpaces(string directiveText) public void ProcessDirectives_IgnoresSpaces(string directiveText)
{ {
// Arrange // Arrange
var errorSink = new ErrorSink();
var phase = new DefaultRazorTagHelperBinderPhase(); var phase = new DefaultRazorTagHelperBinderPhase();
var directives = new[] var directives = new[]
{ {
new TagHelperDirectiveDescriptor() new TagHelperDirectiveDescriptor()
{ {
DirectiveText = directiveText, DirectiveText = directiveText,
DirectiveType = TagHelperDirectiveType.AddTagHelper, DirectiveType = TagHelperDirectiveType.AddTagHelper,
} Diagnostics = new List<RazorDiagnostic>(),
}; }
};
// Act // Act
var results = phase.ProcessDirectives( var results = phase.ProcessDirectives(
directives, directives,
new[] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor }, new[] { Valid_PlainTagHelperDescriptor, Valid_InheritedTagHelperDescriptor });
errorSink);
// Assert // Assert
Assert.Empty(errorSink.Errors); Assert.Empty(directives[0].Diagnostics);
var single = Assert.Single(results); var single = Assert.Single(results);
Assert.Equal(Valid_PlainTagHelperDescriptor, single, TagHelperDescriptorComparer.Default); 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) public void DescriptorResolver_CreatesErrorIfInvalidLookupText_DoesNotThrow(string directiveText, int errorLength)
{ {
// Arrange // Arrange
var errorSink = new ErrorSink();
var phase = new DefaultRazorTagHelperBinderPhase(); var phase = new DefaultRazorTagHelperBinderPhase();
var directive = new TagHelperDirectiveDescriptor() var directive = new TagHelperDirectiveDescriptor()
@ -1313,6 +1318,7 @@ namespace Microsoft.AspNetCore.Razor.Language
DirectiveText = directiveText, DirectiveText = directiveText,
DirectiveType = TagHelperDirectiveType.AddTagHelper, DirectiveType = TagHelperDirectiveType.AddTagHelper,
Location = new SourceLocation(1, 2, 3), Location = new SourceLocation(1, 2, 3),
Diagnostics = new List<RazorDiagnostic>(),
}; };
var expectedErrorMessage = string.Format( var expectedErrorMessage = string.Format(
@ -1320,16 +1326,21 @@ namespace Microsoft.AspNetCore.Razor.Language
"format is: \"typeName, assemblyName\".", "format is: \"typeName, assemblyName\".",
directiveText); directiveText);
var expectedError = RazorDiagnostic.Create(
new RazorError(
expectedErrorMessage,
new SourceLocation(1, 2, 3),
errorLength));
// Act // Act
var result = phase.ParseAddOrRemoveDirective(directive, errorSink); var result = phase.ParseAddOrRemoveDirective(directive);
// Assert // Assert
Assert.Null(result); Assert.Null(result);
var error = Assert.Single(errorSink.Errors); var error = Assert.Single(directive.Diagnostics);
Assert.Equal(errorLength, error.Length); Assert.Equal(expectedError, error);
Assert.Equal(new SourceLocation(1, 2, 3), error.Location);
Assert.Equal(expectedErrorMessage, error.Message);
} }
private static TagHelperDescriptor CreatePrefixedValidPlainDescriptor(string prefix) private static TagHelperDescriptor CreatePrefixedValidPlainDescriptor(string prefix)
@ -1367,7 +1378,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
DirectiveText = directiveText, DirectiveText = directiveText,
Location = SourceLocation.Zero, Location = SourceLocation.Zero,
DirectiveType = directiveType DirectiveType = directiveType,
Diagnostics = new List<RazorDiagnostic>(),
}; };
} }
@ -1404,7 +1416,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{ {
foreach (var ruleBuilder in ruleBuilders) foreach (var ruleBuilder in ruleBuilders)
{ {
builder.TagMatchingRule(innerRuleBuilder => { builder.TagMatchingRule(innerRuleBuilder =>
{
innerRuleBuilder.RequireTagName(tagName); innerRuleBuilder.RequireTagName(tagName);
ruleBuilder(innerRuleBuilder); ruleBuilder(innerRuleBuilder);
}); });

View File

@ -13,25 +13,42 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void FunctionsDirectiveAutoCompleteAtEOF() 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( ParseBlockTest(
"@functions{", "@functions{",
new[] { FunctionsDirective.Directive, }, new[] { FunctionsDirective.Directive },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).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));
} }
[Fact] [Fact]
public void SectionDirectiveAutoCompleteAtEOF() public void SectionDirectiveAutoCompleteAtEOF()
{ {
ParseBlockTest("@section Header {", // Arrange
new[] { SectionDirective.Directive, }, var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive);
new DirectiveBlock(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.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), 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.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml())), Factory.EmptyHtml())));
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"),
new SourceLocation(16, 0, 16),
length: 1));
} }
[Fact] [Fact]
public void VerbatimBlockAutoCompleteAtEOF() public void VerbatimBlockAutoCompleteAtEOF()
{ {
ParseBlockTest("@{", ParseBlockTest("@{",
new StatementBlock( new StatementBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None),
Factory.EmptyCSharp() Factory.EmptyCSharp()
.AsStatement() .AsStatement()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }) .With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" })
), ),
new RazorError( new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF( LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(
LegacyResources.BlockName_Code, "}", "{"), LegacyResources.BlockName_Code, "}", "{"),
new SourceLocation(1, 0, 1), new SourceLocation(1, 0, 1),
length: 1)); length: 1));
} }
[Fact] [Fact]
public void FunctionsDirectiveAutoCompleteAtStartOfFile() public void FunctionsDirectiveAutoCompleteAtStartOfFile()
{ {
ParseBlockTest( // Arrange
"@functions{" + Environment.NewLine + "foo", var chunkGenerator = new DirectiveChunkGenerator(FunctionsDirective.Directive);
new[] { FunctionsDirective.Directive, }, chunkGenerator.Diagnostics.Add(
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), RazorDiagnostic.Create(
Factory.CodeTransition(),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
Factory.Code(Environment.NewLine + "foo").AsStatement()),
new RazorError( new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"), LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"),
new SourceLocation(10, 0, 10), 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] [Fact]
public void SectionDirectiveAutoCompleteAtStartOfFile() public void SectionDirectiveAutoCompleteAtStartOfFile()
{ {
ParseBlockTest("@section Header {" + Environment.NewLine // Arrange
+ "<p>Foo</p>", var chunkGenerator = new DirectiveChunkGenerator(SectionDirective.Directive);
new[] { SectionDirective.Directive, }, chunkGenerator.Diagnostics.Add(
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), 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 + "<p>Foo</p>",
new[] { SectionDirective.Directive },
new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
@ -101,37 +130,33 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Factory.Markup("<p>")), Factory.Markup("<p>")),
Factory.Markup("Foo"), Factory.Markup("Foo"),
new MarkupTagBlock( new MarkupTagBlock(
Factory.Markup("</p>")))), Factory.Markup("</p>")))));
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"),
new SourceLocation(16, 0, 16),
length: 1));
} }
[Fact] [Fact]
public void VerbatimBlockAutoCompleteAtStartOfFile() public void VerbatimBlockAutoCompleteAtStartOfFile()
{ {
ParseBlockTest("@{" + Environment.NewLine ParseBlockTest(
+ "<p></p>", "@{" + Environment.NewLine + "<p></p>",
new StatementBlock( new StatementBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None),
Factory.Code(Environment.NewLine) Factory.Code(Environment.NewLine)
.AsStatement() .AsStatement()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }), .With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }),
new MarkupBlock( new MarkupBlock(
new MarkupTagBlock( new MarkupTagBlock(
Factory.Markup("<p>").Accepts(AcceptedCharactersInternal.None)), Factory.Markup("<p>").Accepts(AcceptedCharactersInternal.None)),
new MarkupTagBlock( new MarkupTagBlock(
Factory.Markup("</p>").Accepts(AcceptedCharactersInternal.None))), Factory.Markup("</p>").Accepts(AcceptedCharactersInternal.None))),
Factory.Span(SpanKindInternal.Code, new CSharpSymbol(string.Empty, CSharpSymbolType.Unknown)) Factory.Span(SpanKindInternal.Code, new CSharpSymbol(string.Empty, CSharpSymbolType.Unknown))
.With(new StatementChunkGenerator()) .With(new StatementChunkGenerator())
), ),
new RazorError( new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF( LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(
LegacyResources.BlockName_Code, "}", "{"), LegacyResources.BlockName_Code, "}", "{"),
new SourceLocation(1, 0, 1), new SourceLocation(1, 0, 1),
length: 1)); length: 1));
} }
} }
} }

View File

@ -11,6 +11,32 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
public class CSharpDirectivesTest : CsHtmlCodeParserTestBase 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] [Fact]
public void DirectiveDescriptor_CanHandleEOFIncompleteNamespaceTokens() public void DirectiveDescriptor_CanHandleEOFIncompleteNamespaceTokens()
{ {
@ -19,19 +45,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddNamespaceToken()); b => b.AddNamespaceToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
chunkGenerator.Diagnostics.Add(
RazorDiagnostic.Create(
new RazorError(
LegacyResources.FormatDirectiveExpectsNamespace("custom"),
8, 0, 8, 7)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom System.", "@custom System.",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)));
new RazorError(
LegacyResources.FormatDirectiveExpectsNamespace("custom"),
8, 0, 8, 7));
} }
[Fact] [Fact]
@ -42,19 +70,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddNamespaceToken()); b => b.AddNamespaceToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
chunkGenerator.Diagnostics.Add(
RazorDiagnostic.Create(
new RazorError(
LegacyResources.FormatDirectiveExpectsNamespace("custom"),
8, 0, 8, 7)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom System<", "@custom System<",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)));
new RazorError(
LegacyResources.FormatDirectiveExpectsNamespace("custom"),
8, 0, 8, 7));
} }
[Fact] [Fact]
public void DirectiveDescriptor_CanHandleIncompleteNamespaceTokens() public void DirectiveDescriptor_CanHandleIncompleteNamespaceTokens()
@ -64,19 +94,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddNamespaceToken()); b => b.AddNamespaceToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
chunkGenerator.Diagnostics.Add(
RazorDiagnostic.Create(
new RazorError(
LegacyResources.FormatDirectiveExpectsNamespace("custom"),
8, 0, 8, 7)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom System." + Environment.NewLine, "@custom System." + Environment.NewLine,
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)));
new RazorError(
LegacyResources.FormatDirectiveExpectsNamespace("custom"),
8, 0, 8, 7));
} }
[Fact] [Fact]
@ -87,19 +119,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddNamespaceToken()); b => b.AddNamespaceToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
chunkGenerator.Diagnostics.Add(
RazorDiagnostic.Create(
new RazorError(
LegacyResources.FormatDirectiveExpectsNamespace("custom"),
8, 0, 8, 7)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom System<" + Environment.NewLine, "@custom System<" + Environment.NewLine,
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)));
new RazorError(
LegacyResources.FormatDirectiveExpectsNamespace("custom"),
8, 0, 8, 7));
} }
[Fact] [Fact]
@ -154,13 +188,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.Code("\"*, Foo\"") Factory.Code("\"*, Foo\"")
.AsAddTagHelper("\"*, Foo\"")), .AsAddTagHelper(
"\"*, Foo\"",
new RazorError(Resources.FormatDirectiveMustAppearAtStartOfLine("addTagHelper"), new SourceLocation(4, 0, 4), 12))),
Factory.Code(Environment.NewLine).AsStatement(), Factory.Code(Environment.NewLine).AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)));
new RazorError(
Resources.FormatDirectiveMustAppearAtStartOfLine("addTagHelper"),
new SourceLocation(4, 0, 4),
12));
} }
[Fact] [Fact]
@ -171,6 +203,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddTypeToken()); 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 // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
@ -181,19 +220,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Factory.Code(" ") Factory.Code(" ")
.AsStatement() .AsStatement()
.AutoCompleteWith(autoCompleteString: null, atEndOfSpan: false), .AutoCompleteWith(autoCompleteString: null, atEndOfSpan: false),
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]),
Factory.MetaCode(Environment.NewLine).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.MetaCode(Environment.NewLine).Accepts(AcceptedCharactersInternal.WhiteSpace)),
Factory.EmptyCSharp().AsStatement(), Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)));
new RazorError(
Resources.FormatDirectiveMustAppearAtStartOfLine("custom"),
new SourceLocation(4, 0, 4),
6));
} }
[Fact] [Fact]
@ -309,21 +343,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddStringToken()); b => b.AddStringToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedError = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), RazorDiagnostic.Create(
new SourceLocation(8, 0, 8), new RazorError(
length: 7); LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"),
new SourceLocation(8, 0, 8),
length: 7)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom AString", "@custom AString",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), 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] [Fact]
@ -334,21 +369,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddStringToken()); b => b.AddStringToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedError = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), RazorDiagnostic.Create(
new SourceLocation(8, 0, 8), new RazorError(
length: 1); LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"),
new SourceLocation(8, 0, 8),
length: 1)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom {foo?}", "@custom {foo?}",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), 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] [Fact]
@ -359,21 +395,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddStringToken()); b => b.AddStringToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedError = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), RazorDiagnostic.Create(
new SourceLocation(8, 0, 8), new RazorError(
length: 9); LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"),
new SourceLocation(8, 0, 8),
length: 9)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom 'AString'", "@custom 'AString'",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), 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] [Fact]
@ -384,22 +421,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddStringToken()); b => b.AddStringToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedError = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), RazorDiagnostic.Create(
new SourceLocation(8, 0, 8), new RazorError(
length: 7); LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"),
new SourceLocation(8, 0, 8),
length: 7)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom AString\"", "@custom AString\"",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)));
expectedError);
} }
[Fact] [Fact]
@ -526,22 +563,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddMemberToken()); b => b.AddMemberToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedErorr = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatDirectiveExpectsIdentifier("custom"), RazorDiagnostic.Create(
new SourceLocation(8, 0, 8), new RazorError(
length: 1); LegacyResources.FormatDirectiveExpectsIdentifier("custom"),
new SourceLocation(8, 0, 8),
length: 1)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom -Some_Member", "@custom -Some_Member",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)));
expectedErorr);
} }
[Fact] [Fact]
@ -574,25 +611,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.SingleLine, DirectiveKind.SingleLine,
b => b.AddStringToken()); b => b.AddStringToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedErorr = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "line break"), RazorDiagnostic.Create(
new SourceLocation(16, 0, 16), new RazorError(
length: 7); LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "line break"),
new SourceLocation(16, 0, 16),
length: 7)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom \"hello\" \"world\"", "@custom \"hello\" \"world\"",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "\"hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "\"hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]),
Factory.MetaCode(" ").Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.MetaCode(" ").Accepts(AcceptedCharactersInternal.WhiteSpace)));
expectedErorr);
} }
[Fact] [Fact]
@ -603,25 +640,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.CodeBlock, DirectiveKind.CodeBlock,
b => b.AddStringToken()); b => b.AddStringToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedErorr = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "{"), RazorDiagnostic.Create(
new SourceLocation(16, 0, 16), new RazorError(
length: 5); LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "{"),
new SourceLocation(16, 0, 16),
length: 5)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom \"Hello\" World { foo(); bar(); }", "@custom \"Hello\" World { foo(); bar(); }",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)));
expectedErorr);
} }
[Fact] [Fact]
@ -632,23 +669,23 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.CodeBlock, DirectiveKind.CodeBlock,
b => b.AddStringToken()); b => b.AddStringToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedErorr = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatUnexpectedEOFAfterDirective("custom", "{"), RazorDiagnostic.Create(
new SourceLocation(15, 0, 15), new RazorError(
length: 1); LegacyResources.FormatUnexpectedEOFAfterDirective("custom", "{"),
new SourceLocation(15, 0, 15),
length: 1)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom \"Hello\"", "@custom \"Hello\"",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0])), Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0])));
expectedErorr);
} }
[Fact] [Fact]
@ -659,18 +696,19 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
"custom", "custom",
DirectiveKind.CodeBlock, DirectiveKind.CodeBlock,
b => b.AddStringToken()); b => b.AddStringToken());
var chunkGenerator = new DirectiveChunkGenerator(descriptor);
var expectedErorr = new RazorError( chunkGenerator.Diagnostics.Add(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("custom", "}", "{"), RazorDiagnostic.Create(
new SourceLocation(16, 0, 16), new RazorError(
length: 1); LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("custom", "}", "{"),
new SourceLocation(16, 0, 16),
length: 1)));
// Act & Assert // Act & Assert
ParseCodeBlockTest( ParseCodeBlockTest(
"@custom \"Hello\" {", "@custom \"Hello\" {",
new[] { descriptor }, new[] { descriptor },
new DirectiveBlock( new DirectiveBlock(chunkGenerator,
new DirectiveChunkGenerator(descriptor),
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), 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.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{") Factory.MetaCode("{")
.AutoCompleteWith("}", atEndOfSpan: true) .AutoCompleteWith("}", atEndOfSpan: true)
.Accepts(AcceptedCharactersInternal.None)), .Accepts(AcceptedCharactersInternal.None)));
expectedErorr);
} }
[Fact] [Fact]
@ -724,6 +761,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void TagHelperPrefixDirective_RequiresValue() 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 ", ParseBlockTest("@tagHelperPrefix ",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
@ -731,17 +774,25 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.EmptyCSharp() Factory.EmptyCSharp()
.AsTagHelperPrefixDirective(string.Empty) .AsTagHelperPrefixDirective(string.Empty, expectedError)
.Accepts(AcceptedCharactersInternal.AnyExceptNewline)), .Accepts(AcceptedCharactersInternal.AnyExceptNewline)));
new RazorError(
LegacyResources.FormatParseError_DirectiveMustHaveValue(
SyntaxConstants.CSharp.TagHelperPrefixKeyword),
absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15));
} }
[Fact] [Fact]
public void TagHelperPrefixDirective_StartQuoteRequiresDoubleQuotesAroundValue() 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", ParseBlockTest("@tagHelperPrefix \"Foo",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
@ -749,19 +800,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.Code("\"Foo") Factory.Code("\"Foo")
.AsTagHelperPrefixDirective("\"Foo")), .AsTagHelperPrefixDirective("\"Foo", expectedErrors)));
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));
} }
[Fact] [Fact]
public void TagHelperPrefixDirective_EndQuoteRequiresDoubleQuotesAroundValue() 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 \"", ParseBlockTest("@tagHelperPrefix Foo \"",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
@ -769,14 +825,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
.MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.Code("Foo \"") Factory.Code("Foo \"")
.AsTagHelperPrefixDirective("Foo \"")), .AsTagHelperPrefixDirective("Foo \"", expectedErrors)));
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));
} }
[Fact] [Fact]
@ -831,57 +880,69 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void RemoveTagHelperDirective_RequiresValue() 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 ", ParseBlockTest("@removeTagHelper ",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.EmptyCSharp() Factory.EmptyCSharp()
.AsRemoveTagHelper(string.Empty) .AsRemoveTagHelper(string.Empty, expectedError)
.Accepts(AcceptedCharactersInternal.AnyExceptNewline)), .Accepts(AcceptedCharactersInternal.AnyExceptNewline)));
new RazorError(
LegacyResources.FormatParseError_DirectiveMustHaveValue(
SyntaxConstants.CSharp.RemoveTagHelperKeyword),
absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15));
} }
[Fact] [Fact]
public void RemoveTagHelperDirective_StartQuoteRequiresDoubleQuotesAroundValue() 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", ParseBlockTest("@removeTagHelper \"Foo",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.Code("\"Foo") Factory.Code("\"Foo")
.AsRemoveTagHelper("\"Foo")), .AsRemoveTagHelper("\"Foo", expectedErrors)));
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));
} }
[Fact] [Fact]
public void RemoveTagHelperDirective_EndQuoteRequiresDoubleQuotesAroundValue() 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\"", ParseBlockTest("@removeTagHelper Foo\"",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.Code("Foo\"") Factory.Code("Foo\"")
.AsRemoveTagHelper("Foo\"") .AsRemoveTagHelper("Foo\"", expectedErrors)
.Accepts(AcceptedCharactersInternal.AnyExceptNewline)), .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));
} }
[Fact] [Fact]
@ -935,56 +996,69 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void AddTagHelperDirectiveRequiresValue() 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 ", ParseBlockTest("@addTagHelper ",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.EmptyCSharp() Factory.EmptyCSharp()
.AsAddTagHelper(string.Empty) .AsAddTagHelper(string.Empty, expectedError)
.Accepts(AcceptedCharactersInternal.AnyExceptNewline)), .Accepts(AcceptedCharactersInternal.AnyExceptNewline)));
new RazorError(
LegacyResources.FormatParseError_DirectiveMustHaveValue(SyntaxConstants.CSharp.AddTagHelperKeyword),
absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 12));
} }
[Fact] [Fact]
public void AddTagHelperDirective_StartQuoteRequiresDoubleQuotesAroundValue() 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", ParseBlockTest("@addTagHelper \"Foo",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.Code("\"Foo") Factory.Code("\"Foo")
.AsAddTagHelper("\"Foo")), .AsAddTagHelper("\"Foo", expectedErrors)));
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));
} }
[Fact] [Fact]
public void AddTagHelperDirective_EndQuoteRequiresDoubleQuotesAroundValue() 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\"", ParseBlockTest("@addTagHelper Foo\"",
new DirectiveBlock( new DirectiveBlock(
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ")
.Accepts(AcceptedCharactersInternal.None), .Accepts(AcceptedCharactersInternal.None),
Factory.Code("Foo\"") Factory.Code("Foo\"")
.AsAddTagHelper("Foo\"") .AsAddTagHelper("Foo\"", expectedErrors)
.Accepts(AcceptedCharactersInternal.AnyExceptNewline)), .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));
} }
[Fact] [Fact]

View File

@ -299,18 +299,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseBlockReportsErrorIfClassBlockUnterminatedAtEOF() 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( ParseBlockTest(
"functions { var foo = bar; if(foo != null) { bar(); } ", "functions { var foo = bar; if(foo != null) { bar(); } ",
new[] { FunctionsDirective.Directive, }, new[] { FunctionsDirective.Directive },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ").AsStatement()), 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));
} }
[Fact] [Fact]

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
@ -12,59 +13,77 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockCapturesNewlineImmediatelyFollowing() 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( ParseDocumentTest(
"@section" + Environment.NewLine, "@section" + Environment.NewLine,
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None)), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None)),
Factory.Markup(Environment.NewLine)), Factory.Markup(Environment.NewLine)));
new RazorError(
LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive),
new SourceLocation(8, 0, 8),
length: Environment.NewLine.Length));
} }
[Fact] [Fact]
public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingOpenBrace() 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( ParseDocumentTest(
"@section Foo " + Environment.NewLine + " ", "@section Foo " + Environment.NewLine + " ",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]), Factory.Span(SpanKindInternal.Code, "Foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine + " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine + " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)),
Factory.EmptyHtml()), Factory.EmptyHtml()));
new RazorError(
LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"),
new SourceLocation(25 + Environment.NewLine.Length, 0, 25 + Environment.NewLine.Length),
length: 1));
} }
[Fact] [Fact]
public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingName() 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( ParseDocumentTest(
"@section " + Environment.NewLine + " ", "@section " + Environment.NewLine + " ",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)),
Factory.Markup(Environment.NewLine + " ")), Factory.Markup(Environment.NewLine + " ")));
new RazorError(
LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive),
new SourceLocation(17, 0, 17),
length: Environment.NewLine.Length));
} }
[Fact] [Fact]
@ -72,7 +91,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
ParseDocumentTest( ParseDocumentTest(
"@Section foo", "@Section foo",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new ExpressionBlock( new ExpressionBlock(
@ -86,12 +105,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfKeywordNotFollowedByIdentifierStartCharacter() 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( ParseDocumentTest(
"@section 9 { <p>Foo</p> }", "@section 9 { <p>Foo</p> }",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)),
@ -101,22 +130,28 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Factory.Markup("Foo"), Factory.Markup("Foo"),
new MarkupTagBlock( new MarkupTagBlock(
Factory.Markup("</p>")), Factory.Markup("</p>")),
Factory.Markup(" }")), Factory.Markup(" }")));
new RazorError(
LegacyResources.FormatDirectiveExpectsIdentifier(SectionDirective.Directive.Directive),
new SourceLocation(9, 0, 9),
length: 1));
} }
[Fact] [Fact]
public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfNameNotFollowedByOpenBrace() 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( ParseDocumentTest(
"@section foo-bar { <p>Foo</p> }", "@section foo-bar { <p>Foo</p> }",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
@ -127,19 +162,31 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Factory.Markup("Foo"), Factory.Markup("Foo"),
new MarkupTagBlock( new MarkupTagBlock(
Factory.Markup("</p>")), Factory.Markup("</p>")),
Factory.Markup(" }")), Factory.Markup(" }")));
new RazorError(
LegacyResources.FormatUnexpectedDirectiveLiteral(SectionDirective.Directive.Directive, "{"),
new SourceLocation(12, 0, 12),
length: 1));
} }
[Fact] [Fact]
public void ParserOutputsErrorOnNestedSections() 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( ParseDocumentTest(
"@section foo { @section bar { <p>Foo</p> } }", "@section foo { @section bar { <p>Foo</p> } }",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), 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), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
Factory.Markup(" "), Factory.Markup(" "),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(erroredChunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), 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.MetaCode("}").Accepts(AcceptedCharactersInternal.None)),
Factory.Markup(" ")), Factory.Markup(" ")),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)),
Factory.EmptyHtml()), 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));
} }
[Fact] [Fact]
public void ParseSectionBlockHandlesEOFAfterOpenBrace() 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( ParseDocumentTest(
"@section foo {", "@section foo {",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), 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.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml()))), Factory.EmptyHtml()))));
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(SectionDirective.Directive.Directive, "}", "{"),
new SourceLocation(13, 0, 13),
length: 1));
} }
[Theory] [Theory]
@ -210,12 +255,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[InlineData(" \n abc")] [InlineData(" \n abc")]
public void ParseSectionBlockHandlesEOFAfterOpenContent(string postStartBrace) 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( ParseDocumentTest(
"@section foo {" + postStartBrace, "@section foo {" + postStartBrace,
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), 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.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
new MarkupBlock( new MarkupBlock(
Factory.Markup(postStartBrace)))), Factory.Markup(postStartBrace)))));
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"),
new SourceLocation(13, 0, 13),
length: 1));
} }
[Fact] [Fact]
public void ParseSectionBlockHandlesUnterminatedSection() 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( ParseDocumentTest(
"@section foo { <p>Foo{}</p>", "@section foo { <p>Foo{}</p>",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), 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. // Need to provide the markup span as fragments, since the parser will split the {} into separate symbols.
Factory.Markup("Foo", "{", "}"), Factory.Markup("Foo", "{", "}"),
new MarkupTagBlock( new MarkupTagBlock(
Factory.Markup("</p>"))))), Factory.Markup("</p>"))))));
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"),
new SourceLocation(13, 0, 13),
length: 1));
} }
[Fact] [Fact]
public void ParseSectionBlockHandlesUnterminatedSectionWithNestedIf() public void ParseSectionBlockHandlesUnterminatedSectionWithNestedIf()
{ {
// Arrange
var newLine = Environment.NewLine; 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 = " "; var spaces = " ";
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
string.Format( string.Format(
"@section Test{0}{{{0}{1}@if(true){0}{1}{{{0}{1}{1}<p>Hello World</p>{0}{1}}}", "@section Test{0}{{{0}{1}@if(true){0}{1}{{{0}{1}{1}<p>Hello World</p>{0}{1}}}",
newLine, newLine,
spaces), spaces),
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
@ -291,47 +358,52 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Factory.Markup("Hello World"), Factory.Markup("Hello World"),
BlockFactory.MarkupTagBlock("</p>", AcceptedCharactersInternal.None), BlockFactory.MarkupTagBlock("</p>", AcceptedCharactersInternal.None),
Factory.Markup(newLine).Accepts(AcceptedCharactersInternal.None)), Factory.Markup(newLine).Accepts(AcceptedCharactersInternal.None)),
Factory.Code($"{spaces}}}").AsStatement())))), Factory.Code($"{spaces}}}").AsStatement())))));
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("section", "}", "{"),
new SourceLocation(13 + newLine.Length, 1, 0),
length: 1));
} }
[Fact] [Fact]
public void ParseSectionBlockReportsErrorAndAcceptsWhitespaceToEndOfLineIfSectionNotFollowedByOpenBrace() 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( ParseDocumentTest(
"@section foo " + Environment.NewLine, "@section foo " + Environment.NewLine,
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.CodeTransition(), Factory.CodeTransition(),
Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]), Factory.Span(SpanKindInternal.Code, "foo", CSharpSymbolType.Identifier).AsDirectiveToken(SectionDirective.Directive.Tokens[0]),
Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine, markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), Factory.Span(SpanKindInternal.Markup, " " + Environment.NewLine, markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)),
Factory.EmptyHtml()), Factory.EmptyHtml()));
new RazorError(
LegacyResources.FormatUnexpectedEOFAfterDirective(SectionDirective.Directive.Directive, "{"),
new SourceLocation(18 + Environment.NewLine.Length, 0, 18 + Environment.NewLine.Length),
length: 1));
} }
[Fact] [Fact]
public void ParseSectionBlockAcceptsOpenBraceMultipleLinesBelowSectionName() public void ParseSectionBlockAcceptsOpenBraceMultipleLinesBelowSectionName()
{ {
ParseDocumentTest("@section foo " + Environment.NewLine // Act & Assert
+ Environment.NewLine ParseDocumentTest(
+ Environment.NewLine "@section foo "
+ Environment.NewLine + Environment.NewLine
+ Environment.NewLine + Environment.NewLine
+ Environment.NewLine + Environment.NewLine
+ "{" + Environment.NewLine + Environment.NewLine
+ "<p>Foo</p>" + Environment.NewLine + Environment.NewLine
+ "}", + Environment.NewLine
new[] { SectionDirective.Directive, }, + "{" + Environment.NewLine
+ "<p>Foo</p>" + Environment.NewLine
+ "}",
new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -356,9 +428,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockParsesNamedSectionCorrectly() public void ParseSectionBlockParsesNamedSectionCorrectly()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section foo { <p>Foo</p> }", "@section foo { <p>Foo</p> }",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -383,9 +456,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockDoesNotRequireSpaceBetweenSectionNameAndOpenBrace() public void ParseSectionBlockDoesNotRequireSpaceBetweenSectionNameAndOpenBrace()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section foo{ <p>Foo</p> }", "@section foo{ <p>Foo</p> }",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -409,9 +483,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockBalancesBraces() public void ParseSectionBlockBalancesBraces()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section foo { <script>(function foo() { return 1; })();</script> }", "@section foo { <script>(function foo() { return 1; })();</script> }",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -436,9 +511,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockAllowsBracesInCSharpExpression() public void ParseSectionBlockAllowsBracesInCSharpExpression()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section foo { I really want to render a close brace, so here I go: @(\"}\") }", "@section foo { I really want to render a close brace, so here I go: @(\"}\") }",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -463,11 +539,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void SectionIsCorrectlyTerminatedWhenCloseBraceImmediatelyFollowsCodeBlock() public void SectionIsCorrectlyTerminatedWhenCloseBraceImmediatelyFollowsCodeBlock()
{ {
ParseDocumentTest("@section Foo {" + Environment.NewLine // Act & Assert
+ "@if(true) {" + Environment.NewLine ParseDocumentTest(
+ "}" + Environment.NewLine "@section Foo {" + Environment.NewLine
+ "}", + "@if(true) {" + Environment.NewLine
new[] { SectionDirective.Directive, }, + "}" + Environment.NewLine
+ "}",
new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -490,10 +568,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void SectionIsCorrectlyTerminatedWhenCloseBraceImmediatelyFollowsCodeBlockNoWhitespace() public void SectionIsCorrectlyTerminatedWhenCloseBraceImmediatelyFollowsCodeBlockNoWhitespace()
{ {
ParseDocumentTest("@section Foo {" + Environment.NewLine // Act & Assert
+ "@if(true) {" + Environment.NewLine ParseDocumentTest(
+ "}}", "@section Foo {" + Environment.NewLine
new[] { SectionDirective.Directive, }, + "@if(true) {" + Environment.NewLine
+ "}}",
new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -516,9 +596,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockCorrectlyTerminatesWhenCloseBraceImmediatelyFollowsMarkup() public void ParseSectionBlockCorrectlyTerminatesWhenCloseBraceImmediatelyFollowsMarkup()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section foo {something}", "@section foo {something}",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -537,9 +618,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockParsesComment() public void ParseSectionBlockParsesComment()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section s {<!-- -->}", "@section s {<!-- -->}",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -560,9 +642,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockParsesCommentWithDelimiters() public void ParseSectionBlockParsesCommentWithDelimiters()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section s {<!-- > \" '-->}", "@section s {<!-- > \" '-->}",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -581,9 +664,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockCommentRecoversFromUnclosedTag() public void ParseSectionBlockCommentRecoversFromUnclosedTag()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section s {" + Environment.NewLine + "<a" + Environment.NewLine + "<!-- > \" '-->}", "@section s {" + Environment.NewLine + "<a" + Environment.NewLine + "<!-- > \" '-->}",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -605,9 +689,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseSectionBlockParsesXmlProcessingInstruction() public void ParseSectionBlockParsesXmlProcessingInstruction()
{ {
// Act & Assert
ParseDocumentTest( ParseDocumentTest(
"@section s { <? xml bleh ?>}", "@section s { <? xml bleh ?>}",
new[] { SectionDirective.Directive, }, new[] { SectionDirective.Directive },
new MarkupBlock( new MarkupBlock(
Factory.EmptyHtml(), Factory.EmptyHtml(),
new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(SectionDirective.Directive),
@ -698,7 +783,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
FixupSpans = true; FixupSpans = true;
ParseDocumentTest(input, new[] { SectionDirective.Directive, }, (Block)expected); ParseDocumentTest(input, new[] { SectionDirective.Directive }, (Block)expected);
} }
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Extensions;
using Xunit; using Xunit;
@ -12,14 +13,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace() 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( ParseBlockTest(
"inherits", "inherits",
new[] { InheritsDirective.Directive, }, new[] { InheritsDirective.Directive },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None)), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None)));
new RazorError(
LegacyResources.FormatUnexpectedEOFAfterDirective(InheritsDirective.Directive.Directive, "type"),
new SourceLocation(8, 0, 8), 1));
} }
[Fact] [Fact]
@ -27,7 +34,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
ParseBlockTest( ParseBlockTest(
"inherits Foo.Bar<Biz<Qux>, string, int>.Baz", "inherits Foo.Bar<Biz<Qux>, string, int>.Baz",
new[] { InheritsDirective.Directive, }, new[] { InheritsDirective.Directive },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive),
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace),
@ -37,13 +44,21 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode() 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( ParseBlockTest(
"inherits " + Environment.NewLine + "foo", "inherits " + Environment.NewLine + "foo",
new[] { InheritsDirective.Directive, }, new[] { InheritsDirective.Directive },
new DirectiveBlock(new DirectiveChunkGenerator(InheritsDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace)));
new RazorError(LegacyResources.FormatDirectiveExpectsTypeName(InheritsDirective.Directive.Directive), 24, 0, 24, Environment.NewLine.Length));
} }
[Fact] [Fact]
@ -146,7 +161,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
const string code = " foo(); \"bar}baz\" "; const string code = " foo(); \"bar}baz\" ";
ParseBlockTest( ParseBlockTest(
"functions {" + code + "} zoop", "functions {" + code + "} zoop",
new[] { FunctionsDirective.Directive, }, new[] { FunctionsDirective.Directive },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive),
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
@ -158,18 +173,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
[Fact] [Fact]
public void ParseBlockDoesNoErrorRecoveryForFunctionsBlock() 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( ParseBlockTest(
"functions { { { { { } zoop", "functions { { { { { } zoop",
new[] { FunctionsDirective.Directive, }, new[] { FunctionsDirective.Directive },
new DirectiveBlock(new DirectiveChunkGenerator(FunctionsDirective.Directive), new DirectiveBlock(chunkGenerator,
Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None),
Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace),
Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.MetaCode("{").AutoCompleteWith("}", atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None),
Factory.Code(" { { { { } zoop").AsStatement()), Factory.Code(" { { { { } zoop").AsStatement()));
new RazorError(
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("functions", "}", "{"),
new SourceLocation(10, 0, 10),
length: 1));
} }
[Fact] [Fact]

View File

@ -334,24 +334,27 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
return _self.With(SpanChunkGenerator.Null); 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 return _self
.With(new AddTagHelperChunkGenerator(lookupText)) .With(new AddTagHelperChunkGenerator(lookupText, diagnostics))
.Accepts(AcceptedCharactersInternal.AnyExceptNewline); .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 return _self
.With(new RemoveTagHelperChunkGenerator(lookupText)) .With(new RemoveTagHelperChunkGenerator(lookupText, diagnostics))
.Accepts(AcceptedCharactersInternal.AnyExceptNewline); .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 return _self
.With(new TagHelperPrefixDirectiveChunkGenerator(prefix)) .With(new TagHelperPrefixDirectiveChunkGenerator(prefix, diagnostics))
.Accepts(AcceptedCharactersInternal.AnyExceptNewline); .Accepts(AcceptedCharactersInternal.AnyExceptNewline);
} }

View File

@ -47,12 +47,6 @@ global::System.Object __typeHelper = ";
#pragma warning disable 1998 #pragma warning disable 1998
public async System.Threading.Tasks.Task ExecuteAsync() 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 #pragma warning restore 1998
} }

View File

@ -16,43 +16,57 @@ Document -
MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync
HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml) HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml)
RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n 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) HtmlContent - (100:2,13 [2] IncompleteDirectives.cshtml)
RazorIRToken - (100:2,13 [2] IncompleteDirectives.cshtml) - Html - \n 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) HtmlContent - (116:3,14 [2] IncompleteDirectives.cshtml)
RazorIRToken - (116:3,14 [2] IncompleteDirectives.cshtml) - Html - \n 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) HtmlContent - (133:4,15 [4] IncompleteDirectives.cshtml)
RazorIRToken - (133:4,15 [4] IncompleteDirectives.cshtml) - Html - \n\n 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) HtmlContent - (153:6,16 [2] IncompleteDirectives.cshtml)
RazorIRToken - (153:6,16 [2] IncompleteDirectives.cshtml) - Html - \n 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) HtmlContent - (172:7,17 [2] IncompleteDirectives.cshtml)
RazorIRToken - (172:7,17 [2] IncompleteDirectives.cshtml) - Html - \n 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) HtmlContent - (192:8,18 [4] IncompleteDirectives.cshtml)
RazorIRToken - (192:8,18 [4] IncompleteDirectives.cshtml) - Html - \n\n 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) HtmlContent - (212:10,16 [2] IncompleteDirectives.cshtml)
RazorIRToken - (212:10,16 [2] IncompleteDirectives.cshtml) - Html - \n 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) HtmlContent - (231:11,17 [2] IncompleteDirectives.cshtml)
RazorIRToken - (231:11,17 [2] IncompleteDirectives.cshtml) - Html - \n 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) HtmlContent - (251:12,18 [4] IncompleteDirectives.cshtml)
RazorIRToken - (251:12,18 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (251:12,18 [4] IncompleteDirectives.cshtml) - Html - \n\n
MalformedDirective - (255:14,0 [9] IncompleteDirectives.cshtml)
HtmlContent - (264:14,9 [2] IncompleteDirectives.cshtml) HtmlContent - (264:14,9 [2] IncompleteDirectives.cshtml)
RazorIRToken - (264:14,9 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (264:14,9 [2] IncompleteDirectives.cshtml) - Html - \n
MalformedDirective - (266:15,0 [10] IncompleteDirectives.cshtml)
HtmlContent - (276:15,10 [4] IncompleteDirectives.cshtml) HtmlContent - (276:15,10 [4] IncompleteDirectives.cshtml)
RazorIRToken - (276:15,10 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (276:15,10 [4] IncompleteDirectives.cshtml) - Html - \n\n
CSharpCode - MalformedDirective - (280:17,0 [12] IncompleteDirectives.cshtml)
RazorIRToken - - CSharp - DefineSection("", async (__razor_section_writer) => { MalformedDirective - (292:18,0 [15] IncompleteDirectives.cshtml)
CSharpCode - MalformedDirective - (307:20,0 [8] IncompleteDirectives.cshtml)
RazorIRToken - - CSharp - });
HtmlContent - (315:20,8 [2] IncompleteDirectives.cshtml) HtmlContent - (315:20,8 [2] IncompleteDirectives.cshtml)
RazorIRToken - (315:20,8 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (315:20,8 [2] IncompleteDirectives.cshtml) - Html - \n
CSharpCode - MalformedDirective - (317:21,0 [9] IncompleteDirectives.cshtml)
RazorIRToken - - CSharp - DefineSection("", async (__razor_section_writer) => {
CSharpCode -
RazorIRToken - - CSharp - });
HtmlContent - (326:21,9 [4] IncompleteDirectives.cshtml) HtmlContent - (326:21,9 [4] IncompleteDirectives.cshtml)
RazorIRToken - (326:21,9 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (326:21,9 [4] IncompleteDirectives.cshtml) - Html - \n\n
CSharpCode - MalformedDirective - (330:23,0 [9] IncompleteDirectives.cshtml)
RazorIRToken - - CSharp - DefineSection("", async (__razor_section_writer) => {
CSharpCode -
RazorIRToken - - CSharp - });
HtmlContent - (339:23,9 [3] IncompleteDirectives.cshtml) HtmlContent - (339:23,9 [3] IncompleteDirectives.cshtml)
RazorIRToken - (339:23,9 [3] IncompleteDirectives.cshtml) - Html - {\n RazorIRToken - (339:23,9 [3] IncompleteDirectives.cshtml) - Html - {\n
MalformedDirective - (342:24,0 [12] IncompleteDirectives.cshtml)

View File

@ -13,14 +13,8 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestFiles
WriteLiteral("\r\n"); WriteLiteral("\r\n");
WriteLiteral("\r\n"); WriteLiteral("\r\n");
WriteLiteral("\r\n\r\n"); WriteLiteral("\r\n\r\n");
DefineSection("", async () => {
});
WriteLiteral("\r\n"); WriteLiteral("\r\n");
DefineSection("", async () => {
});
WriteLiteral("\r\n\r\n"); WriteLiteral("\r\n\r\n");
DefineSection("", async () => {
});
WriteLiteral("{\r\n"); WriteLiteral("{\r\n");
} }
#pragma warning restore 1998 #pragma warning restore 1998

View File

@ -4,31 +4,45 @@ Document -
MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync
HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml) HtmlContent - (83:0,83 [4] IncompleteDirectives.cshtml)
RazorIRToken - (83:0,83 [4] IncompleteDirectives.cshtml) - Html - \n\n 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) HtmlContent - (135:5,0 [2] IncompleteDirectives.cshtml)
RazorIRToken - (135:5,0 [2] IncompleteDirectives.cshtml) - Html - \n 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) HtmlContent - (194:9,0 [2] IncompleteDirectives.cshtml)
RazorIRToken - (194:9,0 [2] IncompleteDirectives.cshtml) - Html - \n 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) HtmlContent - (253:13,0 [2] IncompleteDirectives.cshtml)
RazorIRToken - (253:13,0 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (253:13,0 [2] IncompleteDirectives.cshtml) - Html - \n
MalformedDirective - (255:14,0 [9] IncompleteDirectives.cshtml)
HtmlContent - (264:14,9 [2] IncompleteDirectives.cshtml) HtmlContent - (264:14,9 [2] IncompleteDirectives.cshtml)
RazorIRToken - (264:14,9 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (264:14,9 [2] IncompleteDirectives.cshtml) - Html - \n
MalformedDirective - (266:15,0 [10] IncompleteDirectives.cshtml)
HtmlContent - (276:15,10 [4] IncompleteDirectives.cshtml) HtmlContent - (276:15,10 [4] IncompleteDirectives.cshtml)
RazorIRToken - (276:15,10 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (276:15,10 [4] IncompleteDirectives.cshtml) - Html - \n\n
CSharpCode - MalformedDirective - (280:17,0 [12] IncompleteDirectives.cshtml)
RazorIRToken - - CSharp - DefineSection("", async () => { MalformedDirective - (292:18,0 [15] IncompleteDirectives.cshtml)
CSharpCode - MalformedDirective - (307:20,0 [8] IncompleteDirectives.cshtml)
RazorIRToken - - CSharp - });
HtmlContent - (315:20,8 [2] IncompleteDirectives.cshtml) HtmlContent - (315:20,8 [2] IncompleteDirectives.cshtml)
RazorIRToken - (315:20,8 [2] IncompleteDirectives.cshtml) - Html - \n RazorIRToken - (315:20,8 [2] IncompleteDirectives.cshtml) - Html - \n
CSharpCode - MalformedDirective - (317:21,0 [9] IncompleteDirectives.cshtml)
RazorIRToken - - CSharp - DefineSection("", async () => {
CSharpCode -
RazorIRToken - - CSharp - });
HtmlContent - (326:21,9 [4] IncompleteDirectives.cshtml) HtmlContent - (326:21,9 [4] IncompleteDirectives.cshtml)
RazorIRToken - (326:21,9 [4] IncompleteDirectives.cshtml) - Html - \n\n RazorIRToken - (326:21,9 [4] IncompleteDirectives.cshtml) - Html - \n\n
CSharpCode - MalformedDirective - (330:23,0 [9] IncompleteDirectives.cshtml)
RazorIRToken - - CSharp - DefineSection("", async () => {
CSharpCode -
RazorIRToken - - CSharp - });
HtmlContent - (339:23,9 [3] IncompleteDirectives.cshtml) HtmlContent - (339:23,9 [3] IncompleteDirectives.cshtml)
RazorIRToken - (339:23,9 [3] IncompleteDirectives.cshtml) - Html - {\n RazorIRToken - (339:23,9 [3] IncompleteDirectives.cshtml) - Html - {\n
MalformedDirective - (342:24,0 [12] IncompleteDirectives.cshtml)

View File

@ -15,8 +15,6 @@ global::System.Object Link = null;
#pragma warning disable 1998 #pragma warning disable 1998
public async System.Threading.Tasks.Task ExecuteAsync() public async System.Threading.Tasks.Task ExecuteAsync()
{ {
DefineSection("Link", async (__razor_section_writer) => {
});
#line 2 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml" #line 2 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml"
if(link != null) { if(link != null) {

View File

@ -6,10 +6,8 @@ Document -
CSharpCode - CSharpCode -
RazorIRToken - - CSharp - private static System.Object __o = null; RazorIRToken - - CSharp - private static System.Object __o = null;
MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync
CSharpCode - MalformedDirective - (0:0,0 [13] InlineBlocks.cshtml)
RazorIRToken - - CSharp - DefineSection("Link", async (__razor_section_writer) => { DirectiveToken - (9:0,9 [4] InlineBlocks.cshtml) - Link
CSharpCode -
RazorIRToken - - CSharp - });
HtmlContent - (13:0,13 [23] InlineBlocks.cshtml) HtmlContent - (13:0,13 [23] InlineBlocks.cshtml)
RazorIRToken - (13:0,13 [21] InlineBlocks.cshtml) - Html - (string link) {\n RazorIRToken - (13:0,13 [21] InlineBlocks.cshtml) - Html - (string link) {\n
RazorIRToken - (34:1,4 [2] InlineBlocks.cshtml) - Html - <a RazorIRToken - (34:1,4 [2] InlineBlocks.cshtml) - Html - <a

View File

@ -5,21 +5,21 @@ Generated Location: (351:8,22 [4] )
Source Location: (44:1,14 [19] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml) Source Location: (44:1,14 [19] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml)
|if(link != null) { | |if(link != null) { |
Generated Location: (793:20,14 [19] ) Generated Location: (705:18,14 [19] )
|if(link != null) { | |if(link != null) { |
Source Location: (64:1,34 [4] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml) Source Location: (64:1,34 [4] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml)
|link| |link|
Generated Location: (967:25,34 [4] ) Generated Location: (879:23,34 [4] )
|link| |link|
Source Location: (68:1,38 [10] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml) Source Location: (68:1,38 [10] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml)
| } else { | | } else { |
Generated Location: (1131:30,38 [10] ) Generated Location: (1043:28,38 [10] )
| } else { | | } else { |
Source Location: (92:1,62 [2] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml) Source Location: (92:1,62 [2] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/InlineBlocks.cshtml)
| }| | }|
Generated Location: (1324:35,62 [2] ) Generated Location: (1236:33,62 [2] )
| }| | }|

View File

@ -7,8 +7,6 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestFiles
#pragma warning disable 1998 #pragma warning disable 1998
public async System.Threading.Tasks.Task ExecuteAsync() public async System.Threading.Tasks.Task ExecuteAsync()
{ {
DefineSection("Link", async () => {
});
WriteLiteral("(string link) {\r\n <a"); WriteLiteral("(string link) {\r\n <a");
BeginWriteAttribute("href", " href=\"", 36, "\"", 94, 1); BeginWriteAttribute("href", " href=\"", 36, "\"", 94, 1);
WriteAttributeValue("", 43, new Microsoft.AspNetCore.Mvc.Razor.HelperResult(async(__razor_attribute_value_writer) => { WriteAttributeValue("", 43, new Microsoft.AspNetCore.Mvc.Razor.HelperResult(async(__razor_attribute_value_writer) => {

View File

@ -2,10 +2,8 @@ Document -
NamespaceDeclaration - - Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestFiles NamespaceDeclaration - - Microsoft.AspNetCore.Razor.Language.IntegrationTests.TestFiles
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InlineBlocks_Runtime - - ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_InlineBlocks_Runtime - -
MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync MethodDeclaration - - public - async - System.Threading.Tasks.Task - ExecuteAsync
CSharpCode - MalformedDirective - (0:0,0 [13] InlineBlocks.cshtml)
RazorIRToken - - CSharp - DefineSection("Link", async () => { DirectiveToken - (9:0,9 [4] InlineBlocks.cshtml) - Link
CSharpCode -
RazorIRToken - - CSharp - });
HtmlContent - (13:0,13 [23] InlineBlocks.cshtml) HtmlContent - (13:0,13 [23] InlineBlocks.cshtml)
RazorIRToken - (13:0,13 [21] InlineBlocks.cshtml) - Html - (string link) {\n RazorIRToken - (13:0,13 [21] InlineBlocks.cshtml) - Html - (string link) {\n
RazorIRToken - (34:1,4 [2] InlineBlocks.cshtml) - Html - <a RazorIRToken - (34:1,4 [2] InlineBlocks.cshtml) - Html - <a