Updated the ir lowering phase to lazily add namespaces.

- The lazy addition of namespaces gives the main document lowering phase an opportunity to add source location information which we then add after the main lowering.
- Re-generated csharp to capture addition of using statements that were previously overridden by defaults/imports.

#1174
This commit is contained in:
N. Taylor Mullen 2017-04-04 10:55:30 -07:00
parent a22bfa5265
commit 68554f8106
36 changed files with 186 additions and 95 deletions

View File

@ -22,20 +22,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution
document.Options = syntaxTree.Options;
var namespaces = new HashSet<string>();
var i = 0;
foreach (var namespaceImport in syntaxTree.Options.NamespaceImports)
var namespaces = new Dictionary<string, SourceSpan?>(StringComparer.Ordinal);
foreach (var defaultNamespace in syntaxTree.Options.NamespaceImports)
{
if (namespaces.Add(namespaceImport))
{
var @using = new UsingStatementIRNode()
{
Content = namespaceImport,
};
builder.Insert(i++, @using);
}
namespaces[defaultNamespace] = null;
}
var checksum = ChecksumIRNode.Create(codeDocument.Source);
@ -64,6 +54,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution
visitor.VisitBlock(syntaxTree.Root);
// In each lowering piece above, namespaces were tracked. We render them here to ensure every
// lowering action has a chance to add a source location to a namespace. Ultimately, closest wins.
var i = builder.Current.Children.IndexOf(checksum) + 1;
foreach (var @namespace in namespaces)
{
var @using = new UsingStatementIRNode()
{
Content = @namespace.Key,
Source = @namespace.Value,
};
builder.Insert(i++, @using);
}
codeDocument.SetIRDocument(document);
}
@ -71,9 +76,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution
{
protected readonly RazorIRBuilder _builder;
protected readonly DocumentIRNode _document;
protected readonly HashSet<string> _namespaces;
protected readonly Dictionary<string, SourceSpan?> _namespaces;
public LoweringVisitor(DocumentIRNode document, RazorIRBuilder builder, HashSet<string> namespaces)
public LoweringVisitor(DocumentIRNode document, RazorIRBuilder builder, Dictionary<string, SourceSpan?> namespaces)
{
_document = document;
_builder = builder;
@ -85,16 +90,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
public override void VisitImportSpan(AddImportChunkGenerator chunkGenerator, Span span)
{
var namespaceImport = chunkGenerator.Namespace.Trim();
// Track seen namespaces so we don't add duplicates from options.
if (_namespaces.Add(namespaceImport))
{
_builder.Add(new UsingStatementIRNode()
{
Content = namespaceImport,
Source = BuildSourceSpanFromNode(span),
});
}
var namespaceSpan = BuildSourceSpanFromNode(span);
_namespaces[namespaceImport] = namespaceSpan;
}
public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunkGenerator, Span span)
@ -179,7 +176,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// this simple.
private bool _insideLineDirective;
public ImportsVisitor(DocumentIRNode document, RazorIRBuilder builder, HashSet<string> namespaces)
public ImportsVisitor(DocumentIRNode document, RazorIRBuilder builder, Dictionary<string, SourceSpan?> namespaces)
: base(document, builder, namespaces)
{
}
@ -223,7 +220,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
private DeclareTagHelperFieldsIRNode _tagHelperFields;
private readonly string _tagHelperPrefix;
public MainSourceVisitor(DocumentIRNode document, RazorIRBuilder builder, HashSet<string> namespaces, string tagHelperPrefix)
public MainSourceVisitor(DocumentIRNode document, RazorIRBuilder builder, Dictionary<string, SourceSpan?> namespaces, string tagHelperPrefix)
: base(document, builder, namespaces)
{
_tagHelperPrefix = tagHelperPrefix;

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = global::System.Object;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,10 +1,10 @@
Source Location: (13:0,13 [4] /TestFiles/Input/Basic.cshtml)
|logo|
Generated Location: (1024:42,13 [4] )
Generated Location: (1063:46,13 [4] )
|logo|
Source Location: (43:2,5 [21] /TestFiles/Input/Basic.cshtml)
|Html.Input("SomeKey")|
Generated Location: (1109:47,6 [21] )
Generated Location: (1148:51,6 [21] )
|Html.Input("SomeKey")|

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = global::System.Object;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,15 +1,15 @@
Source Location: (1:0,1 [17] /TestFiles/Input/Inject.cshtml)
|using MyNamespace|
Generated Location: (574:32,0 [17] )
Generated Location: (613:36,0 [17] )
|using MyNamespace|
Source Location: (28:1,8 [5] /TestFiles/Input/Inject.cshtml)
|MyApp|
Generated Location: (869:41,0 [5] )
Generated Location: (908:45,0 [5] )
|MyApp|
Source Location: (34:1,14 [14] /TestFiles/Input/Inject.cshtml)
|MyPropertyName|
Generated Location: (971:45,14 [14] )
Generated Location: (1010:49,14 [14] )
|MyPropertyName|

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = MyModel;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,25 +1,25 @@
Source Location: (7:0,7 [7] /TestFiles/Input/InjectWithModel.cshtml)
|MyModel|
Generated Location: (771:36,0 [7] )
Generated Location: (810:40,0 [7] )
|MyModel|
Source Location: (24:1,8 [5] /TestFiles/Input/InjectWithModel.cshtml)
|MyApp|
Generated Location: (861:40,0 [5] )
Generated Location: (900:44,0 [5] )
|MyApp|
Source Location: (30:1,14 [14] /TestFiles/Input/InjectWithModel.cshtml)
|MyPropertyName|
Generated Location: (963:44,14 [14] )
Generated Location: (1002:48,14 [14] )
|MyPropertyName|
Source Location: (54:2,8 [17] /TestFiles/Input/InjectWithModel.cshtml)
|MyService<TModel>|
Generated Location: (1047:48,0 [17] )
Generated Location: (1086:52,0 [17] )
|MyService<TModel>|
Source Location: (72:2,26 [4] /TestFiles/Input/InjectWithModel.cshtml)
|Html|
Generated Location: (1161:52,14 [4] )
Generated Location: (1200:56,14 [4] )
|Html|

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = MyModel;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,45 +1,45 @@
Source Location: (7:0,7 [7] /TestFiles/Input/InjectWithSemicolon.cshtml)
|MyModel|
Generated Location: (775:36,0 [7] )
Generated Location: (814:40,0 [7] )
|MyModel|
Source Location: (24:1,8 [5] /TestFiles/Input/InjectWithSemicolon.cshtml)
|MyApp|
Generated Location: (865:40,0 [5] )
Generated Location: (904:44,0 [5] )
|MyApp|
Source Location: (30:1,14 [14] /TestFiles/Input/InjectWithSemicolon.cshtml)
|MyPropertyName|
Generated Location: (967:44,14 [14] )
Generated Location: (1006:48,14 [14] )
|MyPropertyName|
Source Location: (58:2,8 [17] /TestFiles/Input/InjectWithSemicolon.cshtml)
|MyService<TModel>|
Generated Location: (1051:48,0 [17] )
Generated Location: (1090:52,0 [17] )
|MyService<TModel>|
Source Location: (76:2,26 [4] /TestFiles/Input/InjectWithSemicolon.cshtml)
|Html|
Generated Location: (1165:52,14 [4] )
Generated Location: (1204:56,14 [4] )
|Html|
Source Location: (93:3,8 [5] /TestFiles/Input/InjectWithSemicolon.cshtml)
|MyApp|
Generated Location: (1239:56,0 [5] )
Generated Location: (1278:60,0 [5] )
|MyApp|
Source Location: (99:3,14 [15] /TestFiles/Input/InjectWithSemicolon.cshtml)
|MyPropertyName2|
Generated Location: (1341:60,14 [15] )
Generated Location: (1380:64,14 [15] )
|MyPropertyName2|
Source Location: (129:4,8 [17] /TestFiles/Input/InjectWithSemicolon.cshtml)
|MyService<TModel>|
Generated Location: (1426:64,0 [17] )
Generated Location: (1465:68,0 [17] )
|MyService<TModel>|
Source Location: (147:4,26 [5] /TestFiles/Input/InjectWithSemicolon.cshtml)
|Html2|
Generated Location: (1540:68,14 [5] )
Generated Location: (1579:72,14 [5] )
|Html2|

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = System.Collections.IEnumerable;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,5 +1,5 @@
Source Location: (7:0,7 [30] /TestFiles/Input/Model.cshtml)
|System.Collections.IEnumerable|
Generated Location: (807:36,0 [30] )
Generated Location: (846:40,0 [30] )
|System.Collections.IEnumerable|

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = DateTime;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,20 +1,20 @@
Source Location: (7:0,7 [8] /TestFiles/Input/ModelExpressionTagHelper.cshtml)
|DateTime|
Generated Location: (782:36,0 [8] )
Generated Location: (821:40,0 [8] )
|DateTime|
Source Location: (33:2,14 [108] /TestFiles/Input/ModelExpressionTagHelper.cshtml)
|Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Extensions.Test|
Generated Location: (903:40,30 [108] )
Generated Location: (942:44,30 [108] )
|Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Extensions.Test|
Source Location: (162:4,17 [3] /TestFiles/Input/ModelExpressionTagHelper.cshtml)
|Now|
Generated Location: (1798:52,144 [3] )
Generated Location: (1837:56,144 [3] )
|Now|
Source Location: (189:5,18 [5] /TestFiles/Input/ModelExpressionTagHelper.cshtml)
|Model|
Generated Location: (2199:58,136 [5] )
Generated Location: (2238:62,136 [5] )
|Model|

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = System.Collections.IEnumerable;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,10 +1,10 @@
Source Location: (7:0,7 [21] /TestFiles/Input/MultipleModels.cshtml)
|ThisShouldBeGenerated|
Generated Location: (816:36,0 [21] )
Generated Location: (855:40,0 [21] )
|ThisShouldBeGenerated|
Source Location: (37:1,7 [30] /TestFiles/Input/MultipleModels.cshtml)
|System.Collections.IEnumerable|
Generated Location: (920:40,0 [30] )
Generated Location: (959:44,0 [30] )
|System.Collections.IEnumerable|

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = NewModel;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,21 +1,21 @@
Source Location: (60:4,1 [41] /TestFiles/Input/RazorPages.cshtml)
|using Microsoft.AspNetCore.Mvc.RazorPages|
Generated Location: (565:32,0 [41] )
Generated Location: (604:36,0 [41] )
|using Microsoft.AspNetCore.Mvc.RazorPages|
Source Location: (16:2,7 [8] /TestFiles/Input/RazorPages.cshtml)
|NewModel|
Generated Location: (879:41,0 [8] )
Generated Location: (918:45,0 [8] )
|NewModel|
Source Location: (40:3,14 [17] /TestFiles/Input/RazorPages.cshtml)
|"*, TestAssembly"|
Generated Location: (999:45,29 [17] )
Generated Location: (1038:49,29 [17] )
|"*, TestAssembly"|
Source Location: (666:28,47 [4] /TestFiles/Input/RazorPages.cshtml)
|Name|
Generated Location: (1500:57,47 [4] )
Generated Location: (1539:61,47 [4] )
|Name|
Source Location: (117:6,12 [360] /TestFiles/Input/RazorPages.cshtml)
@ -36,7 +36,7 @@ Source Location: (117:6,12 [360] /TestFiles/Input/RazorPages.cshtml)
public string Name { get; set; }
}
|
Generated Location: (1929:68,12 [360] )
Generated Location: (1968:72,12 [360] )
|
public class NewModel : PageModel
{

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = _TestFiles_Input_RazorPagesWithoutModel_cshtml;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,16 +1,16 @@
Source Location: (43:3,1 [41] /TestFiles/Input/RazorPagesWithoutModel.cshtml)
|using Microsoft.AspNetCore.Mvc.RazorPages|
Generated Location: (615:32,0 [41] )
Generated Location: (654:36,0 [41] )
|using Microsoft.AspNetCore.Mvc.RazorPages|
Source Location: (23:2,14 [17] /TestFiles/Input/RazorPagesWithoutModel.cshtml)
|"*, TestAssembly"|
Generated Location: (970:41,29 [17] )
Generated Location: (1009:45,29 [17] )
|"*, TestAssembly"|
Source Location: (571:24,47 [4] /TestFiles/Input/RazorPagesWithoutModel.cshtml)
|Name|
Generated Location: (1483:53,47 [4] )
Generated Location: (1522:57,47 [4] )
|Name|
Source Location: (100:5,12 [283] /TestFiles/Input/RazorPagesWithoutModel.cshtml)
@ -28,7 +28,7 @@ Source Location: (100:5,12 [283] /TestFiles/Input/RazorPagesWithoutModel.cshtml)
public string Name { get; set; }
}
|
Generated Location: (1924:64,12 [283] )
Generated Location: (1963:68,12 [283] )
|
public IActionResult OnPost(Customer customer)
{

View File

@ -2,7 +2,11 @@ namespace AspNetCore
{
#line hidden
using TModel = global::System.Object;
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -1,10 +1,10 @@
Source Location: (8:0,8 [19] /TestFiles/Input/_ViewImports.cshtml)
|IHtmlHelper<TModel>|
Generated Location: (782:36,0 [19] )
Generated Location: (821:40,0 [19] )
|IHtmlHelper<TModel>|
Source Location: (28:0,28 [5] /TestFiles/Input/_ViewImports.cshtml)
|Model|
Generated Location: (898:40,14 [5] )
Generated Location: (937:44,14 [5] )
|Model|

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -2,7 +2,11 @@
namespace AspNetCore
{
#line hidden
using System;
#line 1 ""
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 2 ""
using System.Linq;

View File

@ -155,6 +155,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
{
// Arrange
var codeDocument = TestRazorCodeDocument.Create(@"@using System");
var expectedSourceLocation = new SourceSpan(codeDocument.Source.FileName, 1, 0, 1, 12);
// Act
var irDocument = Lower(codeDocument);
@ -162,7 +163,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// Assert
Children(irDocument,
n => Checksum(n),
n => Using("System", n),
n =>
{
Using("System", n);
Assert.Equal(expectedSourceLocation, n.Source);
},
n => Using(typeof(Task).Namespace, n));
}

View File

@ -1,7 +1,11 @@
namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests.TestFiles
{
#line hidden
using System;
#line 3 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml"
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 1 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml"
using System.IO;

View File

@ -1,7 +1,7 @@
Document -
Checksum -
NamespaceDeclaration - - Microsoft.AspNetCore.Razor.Evolution.IntegrationTests.TestFiles
UsingStatement - - System
UsingStatement - (54:2,1 [12] Usings.cshtml) - System
UsingStatement - - System.Threading.Tasks
UsingStatement - (1:0,1 [15] Usings.cshtml) - System.IO
UsingStatement - (19:1,1 [32] Usings.cshtml) - Foo = System.Text.Encoding

View File

@ -1,35 +1,40 @@
Source Location: (54:2,1 [12] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml)
|using System|
Generated Location: (178:4,0 [12] )
|using System|
Source Location: (1:0,1 [15] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml)
|using System.IO|
Generated Location: (232:6,0 [15] )
Generated Location: (341:10,0 [15] )
|using System.IO|
Source Location: (19:1,1 [32] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml)
|using Foo = System.Text.Encoding|
Generated Location: (363:11,0 [32] )
Generated Location: (472:15,0 [32] )
|using Foo = System.Text.Encoding|
Source Location: (71:4,1 [19] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml)
|using static System|
Generated Location: (511:16,0 [19] )
Generated Location: (620:20,0 [19] )
|using static System|
Source Location: (93:5,1 [27] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml)
|using static System.Console|
Generated Location: (646:21,0 [27] )
Generated Location: (755:25,0 [27] )
|using static System.Console|
Source Location: (123:6,1 [41] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml)
|using static global::System.Text.Encoding|
Generated Location: (789:26,0 [41] )
Generated Location: (898:30,0 [41] )
|using static global::System.Text.Encoding|
Source Location: (197:8,29 [21] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml)
|typeof(Path).FullName|
Generated Location: (1381:41,29 [21] )
Generated Location: (1490:45,29 [21] )
|typeof(Path).FullName|
Source Location: (259:9,35 [20] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml)
|typeof(Foo).FullName|
Generated Location: (1554:46,35 [20] )
Generated Location: (1663:50,35 [20] )
|typeof(Foo).FullName|

View File

@ -2,7 +2,11 @@
namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests.TestFiles
{
#line hidden
using System;
#line 3 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml"
using System;
#line default
#line hidden
using System.Threading.Tasks;
#line 1 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/Usings.cshtml"
using System.IO;

View File

@ -1,7 +1,7 @@
Document -
Checksum -
NamespaceDeclaration - - Microsoft.AspNetCore.Razor.Evolution.IntegrationTests.TestFiles
UsingStatement - - System
UsingStatement - (54:2,1 [14] Usings.cshtml) - System
UsingStatement - - System.Threading.Tasks
UsingStatement - (1:0,1 [17] Usings.cshtml) - System.IO
UsingStatement - (19:1,1 [34] Usings.cshtml) - Foo = System.Text.Encoding