Report line/column when reporting mismatching tags

This commit is contained in:
Steve Sanderson 2018-02-21 22:59:35 +00:00
parent 0665d30e19
commit bd455453d6
4 changed files with 51 additions and 8 deletions

View File

@ -8,6 +8,7 @@ using System.Text;
using AngleSharp;
using AngleSharp.Html;
using AngleSharp.Parser.Html;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
@ -286,7 +287,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
_scopeStack.CloseScope(
tagName: isComponent ? tagNameOriginalCase : nextTag.Data,
isComponent: isComponent);
isComponent: isComponent,
source: CalculateSourcePosition(node.Source, nextToken.Position));
var closeMethodName = isComponent
? nameof(RenderTreeBuilder.CloseComponent)
: nameof(RenderTreeBuilder.CloseElement);
@ -315,6 +317,28 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
}
private SourceSpan? CalculateSourcePosition(
SourceSpan? razorTokenPosition,
TextPosition htmlNodePosition)
{
if (razorTokenPosition.HasValue)
{
var razorPos = razorTokenPosition.Value;
return new SourceSpan(
razorPos.FilePath,
razorPos.AbsoluteIndex + htmlNodePosition.Position,
razorPos.LineIndex + htmlNodePosition.Line - 1,
htmlNodePosition.Line == 1
? razorPos.CharacterIndex + htmlNodePosition.Column - 1
: htmlNodePosition.Column - 1,
length: 1);
}
else
{
return null;
}
}
private static string GetTagNameWithOriginalCase(string document, HtmlTagToken tagToken)
{
var offset = tagToken.Type == HtmlTokenType.EndTag ? 1 : 0; // For end tags, skip the '/'

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language;
using System;
namespace Microsoft.AspNetCore.Blazor.Razor
@ -11,16 +12,25 @@ namespace Microsoft.AspNetCore.Blazor.Razor
/// </summary>
public class RazorCompilerException : Exception
{
public RazorCompilerException(string message) : base(message)
private readonly int _line;
private readonly int _column;
public RazorCompilerException(string message) : this(message, null)
{
}
public RazorCompilerException(string message, SourceSpan? source) : base(message)
{
_line = source.HasValue ? (source.Value.LineIndex + 1) : 1;
_column = source.HasValue ? (source.Value.CharacterIndex + 1) : 1;
}
public RazorCompilerDiagnostic ToDiagnostic(string sourceFilePath)
=> new RazorCompilerDiagnostic(
RazorCompilerDiagnostic.DiagnosticType.Error,
sourceFilePath,
line: 1, // Later it might be necessary to take line/col constructor args, but not needed yet
column: 1,
line: _line,
column: _column,
message: Message);
}
}

View File

@ -21,19 +21,19 @@ namespace Microsoft.AspNetCore.Blazor.Razor
_stack.Push(new ScopeEntry(tagName, isComponent));
}
public void CloseScope(string tagName, bool isComponent)
public void CloseScope(string tagName, bool isComponent, SourceSpan? source)
{
if (_stack.Count == 0)
{
throw new RazorCompilerException(
$"Unexpected closing tag '{tagName}' with no matching start tag.");
$"Unexpected closing tag '{tagName}' with no matching start tag.", source);
}
var expected = _stack.Pop();
if (!tagName.Equals(expected.TagName, StringComparison.Ordinal))
{
throw new RazorCompilerException(
$"Mismatching closing tag. Found '{tagName}' but expected '{expected.TagName}'.");
$"Mismatching closing tag. Found '{tagName}' but expected '{expected.TagName}'.", source);
}
// Note: there's no unit test to cover the following, because there's no known way of

View File

@ -525,7 +525,14 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
{
// Arrange/Act
var result = CompileToCSharp(
"<root><other />text<child>more text</root></child>");
$"@{{\n" +
$" var abc = 123;\n" +
$"}}\n" +
$"<root>\n" +
$" <other />\n" +
$" text\n" +
$" <child>more text</root>\n" +
$"</child>\n");
// Assert
Assert.Collection(result.Diagnostics,
@ -533,6 +540,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
{
Assert.Equal(RazorCompilerDiagnostic.DiagnosticType.Error, item.Type);
Assert.StartsWith("Mismatching closing tag. Found 'root' but expected 'child'.", item.Message);
Assert.Equal(7, item.Line);
Assert.Equal(21, item.Column);
});
}