From cab6eea66332f911a2f620c89997956840a59592 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Tue, 21 Mar 2017 17:19:21 -0700 Subject: [PATCH] Set file path from RazorSourceDocument in syntax tree --- .../Legacy/LanguageCharacteristics.cs | 2 +- .../Legacy/LineTrackingStringBuffer.cs | 13 ++++--- .../Legacy/RazorParser.cs | 2 +- .../Legacy/SeekableTextReader.cs | 10 +++--- .../DefaultDirectiveSyntaxTreePassTest.cs | 4 +-- .../IntegrationTests/BasicIntegrationTest.cs | 8 ++--- .../Legacy/LineTrackingStringBufferTest.cs | 8 ++--- .../Legacy/ParserTestBase.cs | 34 +++++++++++------- .../Legacy/TestSpanBuilder.cs | 2 +- .../Legacy/TokenizerLookaheadTest.cs | 2 +- .../Legacy/TokenizerTestBase.cs | 2 +- .../RazorSyntaxTreeTest.cs | 36 +++++++++++++++++++ .../TagHelperBinderSyntaxTreePassTest.cs | 4 +-- .../TestRazorSourceDocument.cs | 4 +-- 14 files changed, 91 insertions(+), 40 deletions(-) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/LanguageCharacteristics.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/LanguageCharacteristics.cs index 92df79a27c..1aab1253fa 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/LanguageCharacteristics.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/LanguageCharacteristics.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public virtual IEnumerable TokenizeString(SourceLocation start, string input) { - using (var reader = new SeekableTextReader(input)) + using (var reader = new SeekableTextReader(input, start.FilePath)) { var tok = CreateTokenizer(reader); TSymbol sym; diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/LineTrackingStringBuffer.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/LineTrackingStringBuffer.cs index 336736026b..f7f867a036 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/LineTrackingStringBuffer.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/LineTrackingStringBuffer.cs @@ -11,20 +11,23 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy internal class LineTrackingStringBuffer { private readonly IList _lines; + private readonly string _filePath; private TextLine _currentLine; private TextLine _endLine; - public LineTrackingStringBuffer(string content) - : this(content.ToCharArray()) + public LineTrackingStringBuffer(string content, string filePath) + : this(content.ToCharArray(), filePath) { } - public LineTrackingStringBuffer(char[] content) + public LineTrackingStringBuffer(char[] content, string filePath) { _endLine = new TextLine(0, 0); _lines = new List() { _endLine }; Append(content); + + _filePath = filePath; } public int Length @@ -34,7 +37,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public SourceLocation EndLocation { - get { return new SourceLocation(Length, _lines.Count - 1, _lines[_lines.Count - 1].Length); } + get { return new SourceLocation(_filePath, Length, _lines.Count - 1, _lines[_lines.Count - 1].Length); } } public CharacterReference CharAt(int absoluteIndex) @@ -45,7 +48,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy throw new ArgumentOutOfRangeException(nameof(absoluteIndex)); } var idx = absoluteIndex - line.Start; - return new CharacterReference(line.Content[idx], new SourceLocation(absoluteIndex, line.Index, idx)); + return new CharacterReference(line.Content[idx], new SourceLocation(_filePath, absoluteIndex, line.Index, idx)); } private void Append(char[] content) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RazorParser.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RazorParser.cs index c9734e7c02..5b9c84fdce 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RazorParser.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RazorParser.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy var chars = new char[source.Length]; source.CopyTo(0, chars, 0, source.Length); - var reader = new SeekableTextReader(chars); + var reader = new SeekableTextReader(chars, source.FileName); var context = new ParserContext(reader, Options.DesignTimeMode); diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SeekableTextReader.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SeekableTextReader.cs index 3f6839dee6..25cd4cf104 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SeekableTextReader.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SeekableTextReader.cs @@ -10,20 +10,22 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { private readonly LineTrackingStringBuffer _buffer; private int _position = 0; - private SourceLocation _location = SourceLocation.Zero; + private SourceLocation _location; private char? _current; - public SeekableTextReader(string source) : this(source.ToCharArray()) { } + public SeekableTextReader(string source, string filePath) : this(source.ToCharArray(), filePath) { } - public SeekableTextReader(char[] source) + public SeekableTextReader(char[] source, string filePath) { if (source == null) { throw new ArgumentNullException(nameof(source)); } - _buffer = new LineTrackingStringBuffer(source); + _buffer = new LineTrackingStringBuffer(source, filePath); UpdateState(); + + _location = new SourceLocation(filePath, 0, 0, 0); } public SourceLocation Location => _location; diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultDirectiveSyntaxTreePassTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultDirectiveSyntaxTreePassTest.cs index ab5e66332b..53db161896 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultDirectiveSyntaxTreePassTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultDirectiveSyntaxTreePassTest.cs @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution @section Baz { } }"; - var sourceDocument = TestRazorSourceDocument.Create(content); + var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); @@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution @section Baz { } }"; - var sourceDocument = TestRazorSourceDocument.Create(content); + var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); var erroredOriginalTree = RazorSyntaxTree.Create( diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/IntegrationTests/BasicIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/IntegrationTests/BasicIntegrationTest.cs index 7caa0a4865..846c8c73d0 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/IntegrationTests/BasicIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/IntegrationTests/BasicIntegrationTest.cs @@ -78,11 +78,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests // Arrange var engine = RazorEngine.Create(); - var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create("@!!!")); + var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create("@!!!", fileName: "test.cshtml")); var expected = RazorDiagnostic.Create(new RazorError( LegacyResources.FormatParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS("!"), - new SourceLocation(1, 0, 1), + new SourceLocation("test.cshtml", 1, 0, 1), length: 1)); // Act @@ -100,11 +100,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests // Arrange var engine = RazorEngine.CreateDesignTime(); - var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create("@{")); + var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create("@{", fileName: "test.cshtml")); var expected = RazorDiagnostic.Create(new RazorError( LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(LegacyResources.BlockName_Code, "}", "{"), - new SourceLocation(1, 0, 1), + new SourceLocation("test.cshtml", 1, 0, 1), length: 1)); // Act diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/LineTrackingStringBufferTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/LineTrackingStringBufferTest.cs index 8809cc182c..8c766f821b 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/LineTrackingStringBufferTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/LineTrackingStringBufferTest.cs @@ -10,17 +10,17 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy [Fact] public void CtorInitializesProperties() { - var buffer = new LineTrackingStringBuffer(string.Empty); + var buffer = new LineTrackingStringBuffer(string.Empty, "test.cshtml"); Assert.Equal(0, buffer.Length); } [Fact] public void CharAtCorrectlyReturnsLocation() { - var buffer = new LineTrackingStringBuffer("foo\rbar\nbaz\r\nbiz"); - LineTrackingStringBuffer.CharacterReference chr = buffer.CharAt(14); + var buffer = new LineTrackingStringBuffer("foo\rbar\nbaz\r\nbiz", "test.cshtml"); + var chr = buffer.CharAt(14); Assert.Equal('i', chr.Character); - Assert.Equal(new SourceLocation(14, 3, 1), chr.Location); + Assert.Equal(new SourceLocation("test.cshtml", 14, 3, 1), chr.Location); } } } diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/ParserTestBase.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/ParserTestBase.cs index 826bc5b340..541b8fd5b6 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/ParserTestBase.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/ParserTestBase.cs @@ -34,26 +34,36 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy internal virtual RazorSyntaxTree ParseDocument(string document, bool designTime = false) { - using (var reader = new SeekableTextReader(document)) - { - var options = RazorParserOptions.CreateDefaultOptions(); - options.DesignTimeMode = designTime; + var source = TestRazorSourceDocument.Create(document); + var reader = new SeekableTextReader(document, filePath: null); - var parser = new RazorParser(options); + var context = new ParserContext(reader, designTime); - var tree = parser.Parse(TestRazorSourceDocument.Create(document)); - var defaultDirectivePass = new DefaultDirectiveSyntaxTreePass(); - tree = defaultDirectivePass.Execute(codeDocument: null, syntaxTree: tree); + var codeParser = new CSharpCodeParser(context); + var markupParser = new HtmlMarkupParser(context); - return tree; - } + codeParser.HtmlParser = markupParser; + markupParser.CodeParser = codeParser; + + markupParser.ParseDocument(); + + var root = context.Builder.Build(); + var diagnostics = context.ErrorSink.Errors?.Select(error => RazorDiagnostic.Create(error)); + var options = RazorParserOptions.CreateDefaultOptions(); + options.DesignTimeMode = designTime; + + var tree = RazorSyntaxTree.Create(root, source, diagnostics, options); + var defaultDirectivePass = new DefaultDirectiveSyntaxTreePass(); + tree = defaultDirectivePass.Execute(codeDocument: null, syntaxTree: tree); + + return tree; } internal virtual RazorSyntaxTree ParseHtmlBlock(string document, bool designTime = false) { var source = TestRazorSourceDocument.Create(document); - using (var reader = new SeekableTextReader(document)) + using (var reader = new SeekableTextReader(document, filePath: null)) { var context = new ParserContext(reader, designTime); @@ -86,7 +96,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { var source = TestRazorSourceDocument.Create(document); - using (var reader = new SeekableTextReader(document)) + using (var reader = new SeekableTextReader(document, filePath: null)) { var context = new ParserContext(reader, designTime); diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TestSpanBuilder.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TestSpanBuilder.cs index 5775fd227d..9fc359227c 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TestSpanBuilder.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TestSpanBuilder.cs @@ -227,7 +227,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy private IEnumerable Tokenize(string content, bool markup) { - var tokenizer = MakeTokenizer(markup, new SeekableTextReader(content)); + var tokenizer = MakeTokenizer(markup, new SeekableTextReader(content, filePath: null)); ISymbol symbol; ISymbol last = null; diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TokenizerLookaheadTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TokenizerLookaheadTest.cs index 7008606c66..9cb0b22b37 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TokenizerLookaheadTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TokenizerLookaheadTest.cs @@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy private class ExposedTokenizer : Tokenizer { public ExposedTokenizer(string input) - : base(new SeekableTextReader(input)) + : base(new SeekableTextReader(input, filePath: null)) { } diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TokenizerTestBase.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TokenizerTestBase.cs index 3f8286d2fa..5bad078522 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TokenizerTestBase.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TokenizerTestBase.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy // Arrange var success = true; var output = new StringBuilder(); - using (var source = new SeekableTextReader(input)) + using (var source = new SeekableTextReader(input, filePath: null)) { var tokenizer = (Tokenizer)CreateTokenizer(source); var counter = 0; diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorSyntaxTreeTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorSyntaxTreeTest.cs index 50ea54a893..7dd2da0d0b 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorSyntaxTreeTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorSyntaxTreeTest.cs @@ -1,6 +1,8 @@ // 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 Microsoft.AspNetCore.Razor.Evolution.Legacy; using Xunit; namespace Microsoft.AspNetCore.Razor.Evolution.Test @@ -20,5 +22,39 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Test Assert.NotNull(syntaxTree); Assert.Empty(syntaxTree.Diagnostics); } + + [Fact] + public void Parse_Persists_FilePath() + { + // Arrange + var filePath = "test.cshtml"; + var source = TestRazorSourceDocument.Create("@if (true) { @if(false) {
@something.
} }", fileName: filePath); + + // Act + var syntaxTree = RazorSyntaxTree.Parse(source); + + // Assert + Assert.Empty(syntaxTree.Diagnostics); + Assert.NotNull(syntaxTree); + + var spans = new List(); + GetChildren(syntaxTree.Root); + Assert.All(spans, node => Assert.Equal(filePath, node.Start.FilePath)); + + void GetChildren(SyntaxTreeNode node) + { + if (node is Block block) + { + foreach (var child in block.Children) + { + GetChildren(child); + } + } + else + { + spans.Add(node); + } + } + } } } diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/TagHelperBinderSyntaxTreePassTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/TagHelperBinderSyntaxTreePassTest.cs index 5299ca4b40..4ef18892bc 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/TagHelperBinderSyntaxTreePassTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/TagHelperBinderSyntaxTreePassTest.cs @@ -385,7 +385,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution @addTagHelper *, TestAssembly
"; - var sourceDocument = TestRazorSourceDocument.Create(content); + var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); @@ -1334,7 +1334,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
"; - var sourceDocument = TestRazorSourceDocument.Create(content); + var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); return sourceDocument; } diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorSourceDocument.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorSourceDocument.cs index 99cf6529ec..22eb2d99ff 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorSourceDocument.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/TestRazorSourceDocument.cs @@ -52,14 +52,14 @@ namespace Microsoft.AspNetCore.Razor.Evolution return stream; } - public static RazorSourceDocument Create(string content = "Hello, world!", Encoding encoding = null, bool normalizeNewLines = false) + public static RazorSourceDocument Create(string content = "Hello, world!", Encoding encoding = null, bool normalizeNewLines = false, string fileName = "test.cshtml") { if (normalizeNewLines) { content = NormalizeNewLines(content); } - return new TestRazorSourceDocument(content, encoding ?? Encoding.UTF8, "test.cshtml"); + return new TestRazorSourceDocument(content, encoding ?? Encoding.UTF8, fileName); } private static string NormalizeNewLines(string content)