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; 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) protected override void BuildConstructor(CSharpCodeWriter writer)
{ {
if (writer == null) 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 new SetBaseTypeChunk
{ {
// Microsoft.Aspnet.Mvc.Razor.RazorPage<TModel> // 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, generatedCharacterIndex: 14,
contentLength: 85), contentLength: 85),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 0, documentAbsoluteIndex: 7,
documentLineIndex: 0, documentLineIndex: 0,
documentCharacterIndex: 0, documentCharacterIndex: 7,
generatedAbsoluteIndex: 910, generatedAbsoluteIndex: 938,
generatedLineIndex: 25, generatedLineIndex: 25,
generatedCharacterIndex: 0, generatedCharacterIndex: 28,
contentLength: 46), contentLength: 8),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 139, documentAbsoluteIndex: 139,
documentLineIndex: 4, documentLineIndex: 4,
documentCharacterIndex: 17, documentCharacterIndex: 17,
generatedAbsoluteIndex: 2371, generatedAbsoluteIndex: 2338,
generatedLineIndex: 54, generatedLineIndex: 54,
generatedCharacterIndex: 95, generatedCharacterIndex: 95,
contentLength: 3), contentLength: 3),
@ -156,16 +156,17 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 166, documentAbsoluteIndex: 166,
documentLineIndex: 5, documentLineIndex: 5,
documentCharacterIndex: 18, documentCharacterIndex: 18,
generatedAbsoluteIndex: 2684, generatedAbsoluteIndex: 2651,
generatedLineIndex: 60, generatedLineIndex: 60,
generatedCharacterIndex: 87, generatedCharacterIndex: 87,
contentLength: 5), contentLength: 5),
}; };
// Act and Assert // Act and Assert
RunDesignTimeTest(host, RunDesignTimeTest(
testName: "ModelExpressionTagHelper", host,
expectedLineMappings: expectedLineMappings); testName: "ModelExpressionTagHelper",
expectedLineMappings: expectedLineMappings);
} }
[Theory] [Theory]
@ -197,28 +198,20 @@ namespace Microsoft.AspNet.Mvc.Razor
host.NamespaceImports.Clear(); host.NamespaceImports.Clear();
var expectedLineMappings = new[] var expectedLineMappings = new[]
{ {
BuildLineMapping(
documentAbsoluteIndex: 0,
documentLineIndex: 0,
documentCharacterIndex: 0,
generatedAbsoluteIndex: 343,
generatedLineIndex: 11,
generatedCharacterIndex: 0,
contentLength: 45),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 13, documentAbsoluteIndex: 13,
documentLineIndex: 0, documentLineIndex: 0,
documentCharacterIndex: 13, documentCharacterIndex: 13,
generatedAbsoluteIndex: 1412, generatedAbsoluteIndex: 1269,
generatedLineIndex: 37, generatedLineIndex: 32,
generatedCharacterIndex: 13, generatedCharacterIndex: 13,
contentLength: 4), contentLength: 4),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 43, documentAbsoluteIndex: 43,
documentLineIndex: 2, documentLineIndex: 2,
documentCharacterIndex: 5, documentCharacterIndex: 5,
generatedAbsoluteIndex: 1496, generatedAbsoluteIndex: 1353,
generatedLineIndex: 42, generatedLineIndex: 37,
generatedCharacterIndex: 6, generatedCharacterIndex: 6,
contentLength: 21), contentLength: 21),
}; };
@ -247,20 +240,12 @@ namespace Microsoft.AspNet.Mvc.Razor
generatedLineIndex: 3, generatedLineIndex: 3,
generatedCharacterIndex: 0, generatedCharacterIndex: 0,
contentLength: 17), contentLength: 17),
BuildLineMapping(
documentAbsoluteIndex: 0,
documentLineIndex: 0,
documentCharacterIndex: 0,
generatedAbsoluteIndex: 443,
generatedLineIndex: 17,
generatedCharacterIndex: 0,
contentLength: 45),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 28, documentAbsoluteIndex: 28,
documentLineIndex: 1, documentLineIndex: 1,
documentCharacterIndex: 8, documentCharacterIndex: 8,
generatedAbsoluteIndex: 850, generatedAbsoluteIndex: 706,
generatedLineIndex: 31, generatedLineIndex: 26,
generatedCharacterIndex: 8, generatedCharacterIndex: 8,
contentLength: 20), contentLength: 20),
}; };
@ -282,18 +267,18 @@ namespace Microsoft.AspNet.Mvc.Razor
var expectedLineMappings = new[] var expectedLineMappings = new[]
{ {
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 0, documentAbsoluteIndex: 7,
documentLineIndex: 0, documentLineIndex: 0,
documentCharacterIndex: 0, documentCharacterIndex: 7,
generatedAbsoluteIndex: 363, generatedAbsoluteIndex: 391,
generatedLineIndex: 11, generatedLineIndex: 11,
generatedCharacterIndex: 0, generatedCharacterIndex: 28,
contentLength: 45), contentLength: 7),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 24, documentAbsoluteIndex: 24,
documentLineIndex: 1, documentLineIndex: 1,
documentCharacterIndex: 8, documentCharacterIndex: 8,
generatedAbsoluteIndex: 788, generatedAbsoluteIndex: 755,
generatedLineIndex: 25, generatedLineIndex: 25,
generatedCharacterIndex: 8, generatedCharacterIndex: 8,
contentLength: 20), contentLength: 20),
@ -301,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 54, documentAbsoluteIndex: 54,
documentLineIndex: 2, documentLineIndex: 2,
documentCharacterIndex: 8, documentCharacterIndex: 8,
generatedAbsoluteIndex: 1014, generatedAbsoluteIndex: 981,
generatedLineIndex: 33, generatedLineIndex: 33,
generatedCharacterIndex: 8, generatedCharacterIndex: 8,
contentLength: 23), contentLength: 23),
@ -324,18 +309,18 @@ namespace Microsoft.AspNet.Mvc.Razor
var expectedLineMappings = new[] var expectedLineMappings = new[]
{ {
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 0, documentAbsoluteIndex: 7,
documentLineIndex: 0, documentLineIndex: 0,
documentCharacterIndex: 0, documentCharacterIndex: 7,
generatedAbsoluteIndex: 371, generatedAbsoluteIndex: 399,
generatedLineIndex: 11, generatedLineIndex: 11,
generatedCharacterIndex: 0, generatedCharacterIndex: 28,
contentLength: 45), contentLength: 7),
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 24, documentAbsoluteIndex: 24,
documentLineIndex: 1, documentLineIndex: 1,
documentCharacterIndex: 8, documentCharacterIndex: 8,
generatedAbsoluteIndex: 804, generatedAbsoluteIndex: 771,
generatedLineIndex: 25, generatedLineIndex: 25,
generatedCharacterIndex: 8, generatedCharacterIndex: 8,
contentLength: 20), contentLength: 20),
@ -343,7 +328,7 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 58, documentAbsoluteIndex: 58,
documentLineIndex: 2, documentLineIndex: 2,
documentCharacterIndex: 8, documentCharacterIndex: 8,
generatedAbsoluteIndex: 1034, generatedAbsoluteIndex: 1001,
generatedLineIndex: 33, generatedLineIndex: 33,
generatedCharacterIndex: 8, generatedCharacterIndex: 8,
contentLength: 23), contentLength: 23),
@ -351,7 +336,7 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 93, documentAbsoluteIndex: 93,
documentLineIndex: 3, documentLineIndex: 3,
documentCharacterIndex: 8, documentCharacterIndex: 8,
generatedAbsoluteIndex: 1267, generatedAbsoluteIndex: 1234,
generatedLineIndex: 41, generatedLineIndex: 41,
generatedCharacterIndex: 8, generatedCharacterIndex: 8,
contentLength: 21), contentLength: 21),
@ -359,7 +344,7 @@ namespace Microsoft.AspNet.Mvc.Razor
documentAbsoluteIndex: 129, documentAbsoluteIndex: 129,
documentLineIndex: 4, documentLineIndex: 4,
documentCharacterIndex: 8, documentCharacterIndex: 8,
generatedAbsoluteIndex: 1498, generatedAbsoluteIndex: 1465,
generatedLineIndex: 49, generatedLineIndex: 49,
generatedCharacterIndex: 8, generatedCharacterIndex: 8,
contentLength: 24), contentLength: 24),
@ -382,19 +367,51 @@ namespace Microsoft.AspNet.Mvc.Razor
var expectedLineMappings = new[] var expectedLineMappings = new[]
{ {
BuildLineMapping( BuildLineMapping(
documentAbsoluteIndex: 0, documentAbsoluteIndex: 7,
documentLineIndex: 0, documentLineIndex: 0,
documentCharacterIndex: 0, documentCharacterIndex: 7,
generatedAbsoluteIndex: 366, generatedAbsoluteIndex: 394,
generatedLineIndex: 11, generatedLineIndex: 11,
generatedCharacterIndex: 0, generatedCharacterIndex: 28,
contentLength: 68), contentLength: 30),
}; };
// Act and Assert // Act and Assert
RunDesignTimeTest(host, "Model", expectedLineMappings); 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( private static void RunRuntimeTest(
MvcRazorHost host, MvcRazorHost host,
string testName) 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__() private void @__RazorDesignTimeHelpers__()
{ {
#pragma warning disable 219 #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 #pragma warning restore 219
} }
#line hidden #line hidden

View File

@ -14,11 +14,6 @@ using MyNamespace
private void @__RazorDesignTimeHelpers__() private void @__RazorDesignTimeHelpers__()
{ {
#pragma warning disable 219 #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 #pragma warning restore 219
} }
#line hidden #line hidden

View File

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

View File

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

View File

@ -9,7 +9,7 @@ namespace Asp
{ {
#pragma warning disable 219 #pragma warning disable 219
#line 1 "TestFiles/Input/Model.cshtml" #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 default
#line hidden #line hidden

View File

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