Plumb `ParserErrorSink` through to `CodeBuilderContext`

- precursor for #129
- remove unused `GeneratorResults` ctor to avoid duplicating `ParserResults` code

nit: make a few `ParserResults` properties immutable
- also change `ParserErrors` type to `IEnumerable<RazorError>`
This commit is contained in:
Doug Bunting 2015-01-13 20:54:45 -08:00
parent 8c47f6a67e
commit 26afdbd889
14 changed files with 105 additions and 72 deletions

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.Generator
{
/// <summary>
@ -12,9 +14,14 @@ namespace Microsoft.AspNet.Razor.Generator
/// Instantiates a new instance of the <see cref="CodeBuilderContext"/> object.
/// </summary>
/// <param name="generatorContext">A <see cref="CodeGeneratorContext"/> to copy information from.</param>
public CodeBuilderContext(CodeGeneratorContext generatorContext)
/// <param name="errorSink">
/// The <see cref="ParserErrorSink"/> used to collect <see cref="Parser.SyntaxTree.RazorError"/>s encountered
/// when parsing the current Razor document.
/// </param>
public CodeBuilderContext(CodeGeneratorContext generatorContext, ParserErrorSink errorSink)
: base(generatorContext)
{
ErrorSink = errorSink;
ExpressionRenderingMode = ExpressionRenderingMode.WriteToOutput;
}
@ -23,9 +30,11 @@ namespace Microsoft.AspNet.Razor.Generator
string className,
string rootNamespace,
string sourceFile,
bool shouldGenerateLinePragmas)
bool shouldGenerateLinePragmas,
ParserErrorSink errorSink)
: base(host, className, rootNamespace, sourceFile, shouldGenerateLinePragmas)
{
ErrorSink = errorSink;
ExpressionRenderingMode = ExpressionRenderingMode.WriteToOutput;
}
@ -56,5 +65,10 @@ namespace Microsoft.AspNet.Razor.Generator
/// <see cref="CodeGeneratorContext.SourceFile"/>.
/// </summary>
public string Checksum { get; set; }
/// <summary>
/// Used to aggregate <see cref="Parser.SyntaxTree.RazorError"/>s.
/// </summary>
public ParserErrorSink ErrorSink { get; }
}
}

View File

@ -3,6 +3,7 @@
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
@ -24,7 +25,7 @@ namespace Microsoft.AspNet.Razor
[NotNull] CodeTree codeTree)
: this(parserResults.Document,
parserResults.TagHelperDescriptors,
parserResults.ParserErrors,
parserResults.ErrorSink,
codeBuilderResult,
codeTree)
{
@ -34,35 +35,21 @@ namespace Microsoft.AspNet.Razor
/// Instantiates a new <see cref="GeneratorResults"/> instance.
/// </summary>
/// <param name="document">The <see cref="Block"/> for the syntax tree.</param>
/// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s for the document.</param>
/// <param name="parserErrors"><see cref="RazorError"/>s encountered when parsing the document.</param>
/// <param name="tagHelperDescriptors">
/// The <see cref="TagHelperDescriptor"/>s that apply to the current Razor document.
/// </param>
/// <param name="errorSink">
/// The <see cref="ParserErrorSink"/> used to collect <see cref="RazorError"/>s encountered when parsing the
/// current Razor document.
/// </param>
/// <param name="codeBuilderResult">The results of generating code for the document.</param>
/// <param name="codeTree">A <see cref="CodeTree"/> for the document.</param>
public GeneratorResults([NotNull] Block document,
[NotNull] IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
[NotNull] IList<RazorError> parserErrors,
[NotNull] ParserErrorSink errorSink,
[NotNull] CodeBuilderResult codeBuilderResult,
[NotNull] CodeTree codeTree)
: this(parserErrors.Count == 0, document, tagHelperDescriptors, parserErrors, codeBuilderResult, codeTree)
{
}
/// <summary>
/// Instantiates a new <see cref="GeneratorResults"/> instance.
/// </summary>
/// <param name="success"><c>true</c> if parsing was successful, <c>false</c> otherwise.</param>
/// <param name="document">The <see cref="Block"/> for the syntax tree.</param>
/// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s for the document.</param>
/// <param name="parserErrors"><see cref="RazorError"/>s encountered when parsing the document.</param>
/// <param name="codeBuilderResult">The results of generating code for the document.</param>
/// <param name="codeTree">A <see cref="CodeTree"/> for the document.</param>
protected GeneratorResults(bool success,
[NotNull] Block document,
[NotNull] IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
[NotNull] IList<RazorError> parserErrors,
[NotNull] CodeBuilderResult codeBuilderResult,
[NotNull] CodeTree codeTree)
: base(success, document, tagHelperDescriptors, parserErrors)
: base(document, tagHelperDescriptors, errorSink)
{
GeneratedCode = codeBuilderResult.Code;
DesignTimeLineMappings = codeBuilderResult.DesignTimeLineMappings;

View File

@ -230,7 +230,7 @@ namespace Microsoft.AspNet.Razor.Parser
// TagHelperDescriptors are not found by default. The RazorParser is responsible
// for identifying TagHelperDescriptors and rebuilding ParserResults.
tagHelperDescriptors: Enumerable.Empty<TagHelperDescriptor>(),
parserErrors: _errorSink.Errors.ToList());
errorSink: _errorSink);
}
[Conditional("DEBUG")]

View File

@ -197,7 +197,7 @@ namespace Microsoft.AspNet.Razor.Parser
}
// Return the new result
return new ParserResults(syntaxTree, descriptors, errorSink.Errors.ToList());
return new ParserResults(syntaxTree, descriptors, errorSink);
}
/// <summary>

View File

@ -2,6 +2,8 @@
// 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;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
@ -15,15 +17,18 @@ namespace Microsoft.AspNet.Razor
/// <summary>
/// Instantiates a new <see cref="ParserResults"/> instance.
/// </summary>
/// <param name="document">The Razor syntax tree.</param>
/// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s that apply to the current Razor
/// document.</param>
/// <param name="parserErrors"><see cref="RazorError"/>s encountered when parsing the current Razor
/// document.</param>
/// <param name="document">The <see cref="Block"/> for the syntax tree.</param>
/// <param name="tagHelperDescriptors">
/// The <see cref="TagHelperDescriptor"/>s that apply to the current Razor document.
/// </param>
/// <param name="errorSink">
/// The <see cref="ParserErrorSink"/> used to collect <see cref="RazorError"/>s encountered when parsing the
/// current Razor document.
/// </param>
public ParserResults([NotNull] Block document,
[NotNull] IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
[NotNull] IList<RazorError> parserErrors)
: this(parserErrors == null || parserErrors.Count == 0, document, tagHelperDescriptors, parserErrors)
[NotNull] ParserErrorSink errorSink)
: this(!errorSink.Errors.Any(), document, tagHelperDescriptors, errorSink)
{
}
@ -31,40 +36,50 @@ namespace Microsoft.AspNet.Razor
/// Instantiates a new <see cref="ParserResults"/> instance.
/// </summary>
/// <param name="success"><c>true</c> if parsing was successful, <c>false</c> otherwise.</param>
/// <param name="document">The Razor syntax tree.</param>
/// <param name="tagHelperDescriptors"><see cref="TagHelperDescriptor"/>s that apply to the current Razor
/// document.</param>
/// <param name="errors"><see cref="RazorError"/>s encountered when parsing the current Razor
/// document.</param>
/// <param name="document">The <see cref="Block"/> for the syntax tree.</param>
/// <param name="tagHelperDescriptors">
/// The <see cref="TagHelperDescriptor"/>s that apply to the current Razor document.
/// </param>
/// <param name="errorSink">
/// The <see cref="ParserErrorSink"/> used to collect <see cref="RazorError"/>s encountered when parsing the
/// current Razor document.
/// </param>
protected ParserResults(bool success,
[NotNull] Block document,
[NotNull] IEnumerable<TagHelperDescriptor> tagHelperDescriptors,
[NotNull] IList<RazorError> errors)
[NotNull] ParserErrorSink errorSink)
{
Success = success;
Document = document;
TagHelperDescriptors = tagHelperDescriptors;
ParserErrors = errors ?? new List<RazorError>();
ErrorSink = errorSink;
ParserErrors = errorSink.Errors;
}
/// <summary>
/// Indicates if parsing was successful (no errors)
/// Indicates if parsing was successful (no errors).
/// </summary>
public bool Success { get; private set; }
/// <value><c>true</c> if parsing was successful, <c>false</c> otherwise.</value>
public bool Success { get; }
/// <summary>
/// The root node in the document's syntax tree
/// The root node in the document's syntax tree.
/// </summary>
public Block Document { get; private set; }
public Block Document { get; }
/// <summary>
/// Used to aggregate <see cref="RazorError"/>s.
/// </summary>
public ParserErrorSink ErrorSink { get; }
/// <summary>
/// The list of errors which occurred during parsing.
/// </summary>
public IList<RazorError> ParserErrors { get; private set; }
public IEnumerable<RazorError> ParserErrors { get; }
/// <summary>
/// The <see cref="TagHelperDescriptor"/>s found for the current Razor document.
/// </summary>
public IEnumerable<TagHelperDescriptor> TagHelperDescriptors { get; private set; }
public IEnumerable<TagHelperDescriptor> TagHelperDescriptors { get; }
}
}

View File

@ -252,7 +252,7 @@ namespace Microsoft.AspNet.Razor
generator.DesignTimeMode = Host.DesignTimeMode;
generator.Visit(results);
var codeBuilderContext = new CodeBuilderContext(generator.Context);
var codeBuilderContext = new CodeBuilderContext(generator.Context, results.ErrorSink);
codeBuilderContext.Checksum = checksum;
var builder = CreateCodeBuilder(codeBuilderContext);
var builderResult = builder.Build();

View File

@ -54,7 +54,8 @@ namespace Microsoft.AspNet.Razor.Test
"myclass",
"myns",
string.Empty,
shouldGenerateLinePragmas: false);
shouldGenerateLinePragmas: false,
errorSink: new ParserErrorSink());
// Act
var generator = language.CreateCodeBuilder(codeBuilderContext);

View File

@ -434,28 +434,30 @@ namespace Microsoft.AspNet.Razor.Test.Framework
collector.AddError("{0} - FAILED :: Actual: << Null >>", expected);
}
public static void EvaluateRazorErrors(IList<RazorError> actualErrors, IList<RazorError> expectedErrors)
public static void EvaluateRazorErrors(IEnumerable<RazorError> actualErrors, IList<RazorError> expectedErrors)
{
var realCount = actualErrors.Count();
// Evaluate the errors
if (expectedErrors == null || expectedErrors.Count == 0)
{
Assert.True(actualErrors.Count == 0,
Assert.True(realCount == 0,
String.Format("Expected that no errors would be raised, but the following errors were:\r\n{0}", FormatErrors(actualErrors)));
}
else
{
Assert.True(expectedErrors.Count == actualErrors.Count,
Assert.True(expectedErrors.Count == realCount,
String.Format("Expected that {0} errors would be raised, but {1} errors were.\r\nExpected Errors: \r\n{2}\r\nActual Errors: \r\n{3}",
expectedErrors.Count,
actualErrors.Count,
realCount,
FormatErrors(expectedErrors),
FormatErrors(actualErrors)));
Assert.Equal(expectedErrors.ToArray(), actualErrors.ToArray());
Assert.Equal(expectedErrors, actualErrors);
}
WriteTraceLine("Expected Errors were raised:\r\n{0}", FormatErrors(expectedErrors));
}
public static string FormatErrors(IList<RazorError> errors)
public static string FormatErrors(IEnumerable<RazorError> errors)
{
if (errors == null)
{

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.TagHelpers;
using Xunit;
@ -161,7 +162,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator
"MyClass",
"MyNamespace",
string.Empty,
shouldGenerateLinePragmas: true));
shouldGenerateLinePragmas: true),
new ParserErrorSink());
}
private class TrackingUniqueIdsTagHelperCodeRenderer : CSharpTagHelperCodeRenderer

View File

@ -3,6 +3,7 @@
#if !ASPNETCORE50
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Utils;
using Moq;
@ -23,7 +24,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator.CodeTree
"TestClass",
"TestNamespace",
"Foo.cs",
shouldGenerateLinePragmas: false);
shouldGenerateLinePragmas: false,
errorSink: new ParserErrorSink());
codeBuilderContext.CodeTreeBuilder.AddUsingChunk("FakeNamespace1", syntaxTreeNode.Object);
codeBuilderContext.CodeTreeBuilder.AddUsingChunk("FakeNamespace2.SubNamespace", syntaxTreeNode.Object);
var codeBuilder = language.CreateCodeBuilder(codeBuilderContext);

View File

@ -4,6 +4,7 @@
#if !ASPNETCORE50
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser;
using Moq;
using Moq.Protected;
using Xunit;
@ -34,7 +35,8 @@ namespace Microsoft.AspNet.Razor
"myclass",
"myns",
string.Empty,
shouldGenerateLinePragmas: false);
shouldGenerateLinePragmas: false,
errorSink: new ParserErrorSink());
var writer = Mock.Of<CodeWriter>();
return new Mock<ChunkVisitor<CodeWriter>>(writer, codeBuilderContext);
}

View File

@ -190,7 +190,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
var rewritten = rewritingContext.SyntaxTree;
// Assert
Assert.Equal(0, results.ParserErrors.Count);
Assert.Equal(0, results.ParserErrors.Count());
EvaluateParseTree(rewritten,
new MarkupBlock(
new MarkupTagBlock(
@ -277,7 +277,7 @@ namespace Microsoft.AspNet.Razor.Test.Parser.Html
var rewritten = rewritingContext.SyntaxTree;
// Assert
Assert.Equal(0, results.ParserErrors.Count);
Assert.Equal(0, results.ParserErrors.Count());
Assert.Equal(rewritten.Children.Count(), results.Document.Children.Count());
}

View File

@ -19,9 +19,10 @@ namespace Microsoft.AspNet.Razor.Test.Parser
public void VisitThrowsOnNullVisitor()
{
ParserVisitor target = null;
var errorSink = new ParserErrorSink();
var results = new ParserResults(new BlockBuilder() { Type = BlockType.Comment }.Build(),
Enumerable.Empty<TagHelperDescriptor>(),
parserErrors: new List<RazorError>());
errorSink);
Assert.Throws<ArgumentNullException>("self", () => target.Visit(results));
}
@ -39,9 +40,10 @@ namespace Microsoft.AspNet.Razor.Test.Parser
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
var root = new BlockBuilder() { Type = BlockType.Comment }.Build();
var errorSink = new ParserErrorSink();
var results = new ParserResults(root,
Enumerable.Empty<TagHelperDescriptor>(),
parserErrors: new List<RazorError>());
errorSink);
// Act
targetMock.Object.Visit(results);
@ -56,11 +58,17 @@ namespace Microsoft.AspNet.Razor.Test.Parser
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
var root = new BlockBuilder() { Type = BlockType.Comment }.Build();
List<RazorError> errors = new List<RazorError>() {
var errorSink = new ParserErrorSink();
List<RazorError> errors = new List<RazorError>
{
new RazorError("Foo", 1, 0, 1),
new RazorError("Bar", 2, 0, 2)
new RazorError("Bar", 2, 0, 2),
};
var results = new ParserResults(root, Enumerable.Empty<TagHelperDescriptor>(), errors);
foreach (var error in errors)
{
errorSink.OnError(error);
}
var results = new ParserResults(root, Enumerable.Empty<TagHelperDescriptor>(), errorSink);
// Act
targetMock.Object.Visit(results);
@ -76,11 +84,10 @@ namespace Microsoft.AspNet.Razor.Test.Parser
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
var root = new BlockBuilder() { Type = BlockType.Comment }.Build();
List<RazorError> errors = new List<RazorError>() {
new RazorError("Foo", 1, 0, 1),
new RazorError("Bar", 2, 0, 2)
};
var results = new ParserResults(root, Enumerable.Empty<TagHelperDescriptor>(), errors);
var errorSink = new ParserErrorSink();
errorSink.OnError(new RazorError("Foo", 1, 0, 1));
errorSink.OnError(new RazorError("Bar", 2, 0, 2));
var results = new ParserResults(root, Enumerable.Empty<TagHelperDescriptor>(), errorSink);
// Act
targetMock.Object.Visit(results);

View File

@ -119,7 +119,8 @@ namespace Microsoft.AspNet.Razor.Test
"different-class",
"different-ns",
string.Empty,
shouldGenerateLinePragmas: true);
shouldGenerateLinePragmas: true,
errorSink: new ParserErrorSink());
var expected = new CSharpCodeBuilder(codeBuilderContext);