Generate an expression to create line mappings for ModelChunk directives

This commit is contained in:
Pranav K 2015-09-22 22:43:22 -07:00
parent 89f58aa49f
commit ff4100e292
12 changed files with 213 additions and 68 deletions

View File

@ -67,6 +67,29 @@ namespace Microsoft.AspNet.Mvc.Razor
return csharpCodeVisitor;
}
protected override CSharpDesignTimeCodeVisitor CreateCSharpDesignTimeCodeVisitor(
CSharpCodeVisitor csharpCodeVisitor,
CSharpCodeWriter writer,
CodeGeneratorContext context)
{
if (csharpCodeVisitor == null)
{
throw new ArgumentNullException(nameof(csharpCodeVisitor));
}
if (writer == null)
{
throw new ArgumentNullException(nameof(writer));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new MvcCSharpDesignTimeCodeVisitor(csharpCodeVisitor, writer, context);
}
protected override void BuildConstructor(CSharpCodeWriter writer)
{
if (writer == null)

View File

@ -0,0 +1,70 @@
// 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.Diagnostics;
using Microsoft.AspNet.Razor.Chunks;
using Microsoft.AspNet.Razor.CodeGenerators;
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
namespace Microsoft.AspNet.Mvc.Razor
{
public class MvcCSharpDesignTimeCodeVisitor : CSharpDesignTimeCodeVisitor
{
private const string ModelVariable = "__modelHelper";
private ModelChunk _modelChunk;
public MvcCSharpDesignTimeCodeVisitor(
CSharpCodeVisitor csharpCodeVisitor,
CSharpCodeWriter writer,
CodeGeneratorContext context)
: base(csharpCodeVisitor, writer, context)
{
}
protected override void AcceptTreeCore(ChunkTree tree)
{
base.AcceptTreeCore(tree);
if (_modelChunk != null)
{
WriteModelChunkLineMapping();
}
}
public override void Accept(Chunk chunk)
{
if (chunk is ModelChunk)
{
Visit((ModelChunk)chunk);
}
base.Accept(chunk);
}
private void Visit(ModelChunk chunk)
{
Debug.Assert(chunk != null);
_modelChunk = chunk;
}
private void WriteModelChunkLineMapping()
{
Debug.Assert(Context.Host.DesignTimeMode);
using (var lineMappingWriter =
Writer.BuildLineMapping(_modelChunk.Start, _modelChunk.ModelType.Length, Context.SourceFile))
{
// var __modelHelper = default(MyModel);
Writer.Write("var ")
.Write(ModelVariable)
.Write(" = default(");
lineMappingWriter.MarkLineMappingStart();
Writer.Write(_modelChunk.ModelType);
lineMappingWriter.MarkLineMappingEnd();
Writer.WriteLine(");");
}
}
}
}

View File

@ -45,7 +45,10 @@ namespace Microsoft.AspNet.Mvc.Razor
new SetBaseTypeChunk
{
// Microsoft.Aspnet.Mvc.Razor.RazorPage<TModel>
TypeName = BaseType + ChunkHelper.TModelToken
TypeName = BaseType + ChunkHelper.TModelToken,
// Set the Start to Undefined to prevent Razor design time code generation from rendering a line mapping
// for this chunk.
Start = SourceLocation.Undefined
}
};

View File

@ -137,18 +137,18 @@ namespace Microsoft.AspNet.Mvc.Razor
generatedCharacterIndex: 14,
contentLength: 85),
BuildLineMapping(
documentAbsoluteIndex: 0,
documentAbsoluteIndex: 7,
documentLineIndex: 0,
documentCharacterIndex: 0,
generatedAbsoluteIndex: 910,
documentCharacterIndex: 7,
generatedAbsoluteIndex: 938,
generatedLineIndex: 25,
generatedCharacterIndex: 0,
contentLength: 46),
generatedCharacterIndex: 28,
contentLength: 8),
BuildLineMapping(
documentAbsoluteIndex: 139,
documentLineIndex: 4,
documentCharacterIndex: 17,
generatedAbsoluteIndex: 2371,
generatedAbsoluteIndex: 2338,
generatedLineIndex: 54,
generatedCharacterIndex: 95,
contentLength: 3),
@ -156,16 +156,17 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 166,
documentLineIndex: 5,
documentCharacterIndex: 18,
generatedAbsoluteIndex: 2684,
generatedAbsoluteIndex: 2651,
generatedLineIndex: 60,
generatedCharacterIndex: 87,
contentLength: 5),
};
// Act and Assert
RunDesignTimeTest(host,
testName: "ModelExpressionTagHelper",
expectedLineMappings: expectedLineMappings);
RunDesignTimeTest(
host,
testName: "ModelExpressionTagHelper",
expectedLineMappings: expectedLineMappings);
}
[Theory]
@ -197,28 +198,20 @@ namespace Microsoft.AspNet.Mvc.Razor
host.NamespaceImports.Clear();
var expectedLineMappings = new[]
{
BuildLineMapping(
documentAbsoluteIndex: 0,
documentLineIndex: 0,
documentCharacterIndex: 0,
generatedAbsoluteIndex: 343,
generatedLineIndex: 11,
generatedCharacterIndex: 0,
contentLength: 45),
BuildLineMapping(
documentAbsoluteIndex: 13,
documentLineIndex: 0,
documentCharacterIndex: 13,
generatedAbsoluteIndex: 1412,
generatedLineIndex: 37,
generatedAbsoluteIndex: 1269,
generatedLineIndex: 32,
generatedCharacterIndex: 13,
contentLength: 4),
BuildLineMapping(
documentAbsoluteIndex: 43,
documentLineIndex: 2,
documentCharacterIndex: 5,
generatedAbsoluteIndex: 1496,
generatedLineIndex: 42,
generatedAbsoluteIndex: 1353,
generatedLineIndex: 37,
generatedCharacterIndex: 6,
contentLength: 21),
};
@ -247,20 +240,12 @@ namespace Microsoft.AspNet.Mvc.Razor
generatedLineIndex: 3,
generatedCharacterIndex: 0,
contentLength: 17),
BuildLineMapping(
documentAbsoluteIndex: 0,
documentLineIndex: 0,
documentCharacterIndex: 0,
generatedAbsoluteIndex: 443,
generatedLineIndex: 17,
generatedCharacterIndex: 0,
contentLength: 45),
BuildLineMapping(
documentAbsoluteIndex: 28,
documentLineIndex: 1,
documentCharacterIndex: 8,
generatedAbsoluteIndex: 850,
generatedLineIndex: 31,
generatedAbsoluteIndex: 706,
generatedLineIndex: 26,
generatedCharacterIndex: 8,
contentLength: 20),
};
@ -282,18 +267,18 @@ namespace Microsoft.AspNet.Mvc.Razor
var expectedLineMappings = new[]
{
BuildLineMapping(
documentAbsoluteIndex: 0,
documentAbsoluteIndex: 7,
documentLineIndex: 0,
documentCharacterIndex: 0,
generatedAbsoluteIndex: 363,
documentCharacterIndex: 7,
generatedAbsoluteIndex: 391,
generatedLineIndex: 11,
generatedCharacterIndex: 0,
contentLength: 45),
generatedCharacterIndex: 28,
contentLength: 7),
BuildLineMapping(
documentAbsoluteIndex: 24,
documentLineIndex: 1,
documentCharacterIndex: 8,
generatedAbsoluteIndex: 788,
generatedAbsoluteIndex: 755,
generatedLineIndex: 25,
generatedCharacterIndex: 8,
contentLength: 20),
@ -301,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 54,
documentLineIndex: 2,
documentCharacterIndex: 8,
generatedAbsoluteIndex: 1014,
generatedAbsoluteIndex: 981,
generatedLineIndex: 33,
generatedCharacterIndex: 8,
contentLength: 23),
@ -324,18 +309,18 @@ namespace Microsoft.AspNet.Mvc.Razor
var expectedLineMappings = new[]
{
BuildLineMapping(
documentAbsoluteIndex: 0,
documentAbsoluteIndex: 7,
documentLineIndex: 0,
documentCharacterIndex: 0,
generatedAbsoluteIndex: 371,
documentCharacterIndex: 7,
generatedAbsoluteIndex: 399,
generatedLineIndex: 11,
generatedCharacterIndex: 0,
contentLength: 45),
generatedCharacterIndex: 28,
contentLength: 7),
BuildLineMapping(
documentAbsoluteIndex: 24,
documentLineIndex: 1,
documentCharacterIndex: 8,
generatedAbsoluteIndex: 804,
generatedAbsoluteIndex: 771,
generatedLineIndex: 25,
generatedCharacterIndex: 8,
contentLength: 20),
@ -343,7 +328,7 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 58,
documentLineIndex: 2,
documentCharacterIndex: 8,
generatedAbsoluteIndex: 1034,
generatedAbsoluteIndex: 1001,
generatedLineIndex: 33,
generatedCharacterIndex: 8,
contentLength: 23),
@ -351,7 +336,7 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 93,
documentLineIndex: 3,
documentCharacterIndex: 8,
generatedAbsoluteIndex: 1267,
generatedAbsoluteIndex: 1234,
generatedLineIndex: 41,
generatedCharacterIndex: 8,
contentLength: 21),
@ -359,7 +344,7 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 129,
documentLineIndex: 4,
documentCharacterIndex: 8,
generatedAbsoluteIndex: 1498,
generatedAbsoluteIndex: 1465,
generatedLineIndex: 49,
generatedCharacterIndex: 8,
contentLength: 24),
@ -382,19 +367,51 @@ namespace Microsoft.AspNet.Mvc.Razor
var expectedLineMappings = new[]
{
BuildLineMapping(
documentAbsoluteIndex: 0,
documentAbsoluteIndex: 7,
documentLineIndex: 0,
documentCharacterIndex: 0,
generatedAbsoluteIndex: 366,
documentCharacterIndex: 7,
generatedAbsoluteIndex: 394,
generatedLineIndex: 11,
generatedCharacterIndex: 0,
contentLength: 68),
generatedCharacterIndex: 28,
contentLength: 30),
};
// Act and Assert
RunDesignTimeTest(host, "Model", expectedLineMappings);
}
[Fact]
public void ModelVisitor_GeneratesLineMappingsForLastModel_WhenMultipleModelsArePresent()
{
// Arrange
var fileProvider = new TestFileProvider();
var host = new MvcRazorHostWithNormalizedNewLine(new DefaultChunkTreeCache(fileProvider))
{
DesignTimeMode = true
};
host.NamespaceImports.Clear();
var inputFile = "TestFiles/Input/MultipleModels.cshtml";
var outputFile = "TestFiles/Output/DesignTime/MultipleModels.cs";
var expectedCode = ResourceFile.ReadResource(_assembly, outputFile, sourceFile: false);
// Act
GeneratorResults results;
using (var stream = ResourceFile.GetResourceStream(_assembly, inputFile, sourceFile: true))
{
results = host.GenerateCode(inputFile, stream);
}
// Assert
Assert.False(results.Success);
var parserError = Assert.Single(results.ParserErrors);
Assert.Equal("Only one 'model' statement is allowed in a file.", parserError.Message);
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedCode, results.GeneratedCode);
#else
Assert.Equal(expectedCode, results.GeneratedCode, ignoreLineEndingDifferences: true);
#endif
}
private static void RunRuntimeTest(
MvcRazorHost host,
string testName)

View File

@ -0,0 +1,2 @@
@model ThisShouldNotBeGenerated
@model System.Collections.IEnumerable

View File

@ -8,11 +8,6 @@ namespace Asp
private void @__RazorDesignTimeHelpers__()
{
#pragma warning disable 219
#line 1 "TestFiles/Input/Basic.cshtml"
Microsoft.AspNet.Mvc.Razor.RazorPage<dynamic> __inheritsHelper = null;
#line default
#line hidden
#pragma warning restore 219
}
#line hidden

View File

@ -14,11 +14,6 @@ using MyNamespace
private void @__RazorDesignTimeHelpers__()
{
#pragma warning disable 219
#line 1 "TestFiles/Input/Inject.cshtml"
Microsoft.AspNet.Mvc.Razor.RazorPage<dynamic> __inheritsHelper = null;
#line default
#line hidden
#pragma warning restore 219
}
#line hidden

View File

@ -9,7 +9,7 @@ namespace Asp
{
#pragma warning disable 219
#line 1 "TestFiles/Input/InjectWithModel.cshtml"
Microsoft.AspNet.Mvc.Razor.RazorPage<MyModel> __inheritsHelper = null;
var __modelHelper = default(MyModel);
#line default
#line hidden

View File

@ -9,7 +9,7 @@ namespace Asp
{
#pragma warning disable 219
#line 1 "TestFiles/Input/InjectWithSemicolon.cshtml"
Microsoft.AspNet.Mvc.Razor.RazorPage<MyModel> __inheritsHelper = null;
var __modelHelper = default(MyModel);
#line default
#line hidden

View File

@ -9,7 +9,7 @@ namespace Asp
{
#pragma warning disable 219
#line 1 "TestFiles/Input/Model.cshtml"
Microsoft.AspNet.Mvc.Razor.RazorPage<System.Collections.IEnumerable> __inheritsHelper = null;
var __modelHelper = default(System.Collections.IEnumerable);
#line default
#line hidden

View File

@ -23,7 +23,7 @@ namespace Asp
#line hidden
;
#line 1 "TestFiles/Input/ModelExpressionTagHelper.cshtml"
Microsoft.AspNet.Mvc.Razor.RazorPage<DateTime> __inheritsHelper = null;
var __modelHelper = default(DateTime);
#line default
#line hidden

View File

@ -0,0 +1,40 @@
namespace Asp
{
using System.Threading.Tasks;
public class ASPV_TestFiles_Input_MultipleModels_cshtml : Microsoft.AspNet.Mvc.Razor.RazorPage<System.Collections.IEnumerable>
{
private static object @__o;
private void @__RazorDesignTimeHelpers__()
{
#pragma warning disable 219
#line 2 "TestFiles/Input/MultipleModels.cshtml"
var __modelHelper = default(System.Collections.IEnumerable);
#line default
#line hidden
#pragma warning restore 219
}
#line hidden
public ASPV_TestFiles_Input_MultipleModels_cshtml()
{
}
#line hidden
[Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
public Microsoft.AspNet.Mvc.IUrlHelper Url { get; private set; }
[Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
public Microsoft.AspNet.Mvc.IViewComponentHelper Component { get; private set; }
[Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
public Microsoft.AspNet.Mvc.Rendering.IJsonHelper Json { get; private set; }
[Microsoft.AspNet.Mvc.Razor.Internal.RazorInjectAttribute]
public Microsoft.AspNet.Mvc.Rendering.IHtmlHelper<System.Collections.IEnumerable> Html { get; private set; }
#line hidden
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
}
#pragma warning restore 1998
}
}