Skip to content

Commit 909f4d7

Browse files
authored
Emit pragmas for empty @ expressions in MVC (#11653)
* Update parsing so that we always emit a marker token for an implicit csharp expression with no content. This ensures that we emit an empty #line pragma and IntelliSense gives the correct set of completion items. * Add tests and baselines * Fix an issue with ZeroWidthLineSpan calculation for spans that don't start at character offset 0.
1 parent ce610e6 commit 909f4d7

10 files changed

+318
-2
lines changed

src/Compiler/Microsoft.AspNetCore.Mvc.Razor.Extensions/test/IntegrationTests/CodeGenerationIntegrationTest.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,27 @@ @inherits MyBase
904904
CompileToAssembly(generated);
905905
}
906906

907+
[Fact, WorkItem("https://github.com/dotnet/razor/issues/10965")]
908+
public void InvalidCode_EmptyImplicitExpression_Runtime()
909+
{
910+
// Act
911+
var generated = CompileToCSharp("""
912+
<html>
913+
<head>
914+
@
915+
</head>
916+
</html>
917+
""", designTime: false);
918+
919+
// Assert
920+
var intermediate = generated.CodeDocument.GetDocumentIntermediateNode();
921+
var csharp = generated.CodeDocument.GetCSharpDocument();
922+
AssertDocumentNodeMatchesBaseline(intermediate);
923+
AssertCSharpDocumentMatchesBaseline(csharp);
924+
AssertSourceMappingsMatchBaseline(generated.CodeDocument);
925+
CompileToAssembly(generated, throwOnFailure: false, ignoreRazorDiagnostics: true);
926+
}
927+
907928
#endregion
908929

909930
#region DesignTime
@@ -1516,6 +1537,26 @@ @inherits MyBase
15161537
CompileToAssembly(generated);
15171538
}
15181539

1540+
[Fact, WorkItem("https://github.com/dotnet/razor/issues/10965")]
1541+
public void InvalidCode_EmptyImplicitExpression_DesignTime()
1542+
{
1543+
// Act
1544+
var generated = CompileToCSharp("""
1545+
<html>
1546+
<head>
1547+
@
1548+
</head>
1549+
</html>
1550+
""", designTime: true);
1551+
1552+
// Assert
1553+
var intermediate = generated.CodeDocument.GetDocumentIntermediateNode();
1554+
var csharp = generated.CodeDocument.GetCSharpDocument();
1555+
AssertDocumentNodeMatchesBaseline(intermediate);
1556+
AssertCSharpDocumentMatchesBaseline(csharp);
1557+
CompileToAssembly(generated, throwOnFailure: false, ignoreRazorDiagnostics: true);
1558+
}
1559+
15191560
#endregion
15201561

15211562
[Theory, CombinatorialData, WorkItem("https://github.com/dotnet/razor/issues/7286")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// <auto-generated/>
2+
#pragma warning disable 1591
3+
namespace AspNetCoreGeneratedDocument
4+
{
5+
#line default
6+
using TModel = global::System.Object;
7+
using global::System;
8+
using global::System.Collections.Generic;
9+
using global::System.Linq;
10+
using global::System.Threading.Tasks;
11+
using global::Microsoft.AspNetCore.Mvc;
12+
using global::Microsoft.AspNetCore.Mvc.Rendering;
13+
using global::Microsoft.AspNetCore.Mvc.ViewFeatures;
14+
#line default
15+
#line hidden
16+
[global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("Identifier", "/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/test.cshtml")]
17+
[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdateAttribute]
18+
#nullable restore
19+
internal sealed class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_test : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
20+
#nullable disable
21+
{
22+
#line hidden
23+
#pragma warning disable 0649
24+
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
25+
#pragma warning restore 0649
26+
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
27+
private global::Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper __Microsoft_AspNetCore_Mvc_Razor_TagHelpers_HeadTagHelper;
28+
#pragma warning disable 219
29+
private void __RazorDirectiveTokenHelpers__() {
30+
}
31+
#pragma warning restore 219
32+
#pragma warning disable 0414
33+
private static object __o = null;
34+
#pragma warning restore 0414
35+
#pragma warning disable 1998
36+
public async override global::System.Threading.Tasks.Task ExecuteAsync()
37+
{
38+
#nullable restore
39+
#line 3 "TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml"
40+
__o = ;
41+
42+
#line default
43+
#line hidden
44+
#nullable disable
45+
__Microsoft_AspNetCore_Mvc_Razor_TagHelpers_HeadTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper>();
46+
await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
47+
}
48+
#pragma warning restore 1998
49+
#nullable restore
50+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
51+
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } = default!;
52+
#nullable disable
53+
#nullable restore
54+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
55+
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } = default!;
56+
#nullable disable
57+
#nullable restore
58+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
59+
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } = default!;
60+
#nullable disable
61+
#nullable restore
62+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
63+
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } = default!;
64+
#nullable disable
65+
#nullable restore
66+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
67+
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; } = default!;
68+
#nullable disable
69+
}
70+
}
71+
#pragma warning restore 1591
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml(3,10): Error RZ1003: A space or line break was encountered after the "@" character. Only valid identifiers, keywords, comments, "(" and "{" are valid at the start of a code block and they must occur immediately following "@" with no space in between.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
Document -
2+
NamespaceDeclaration - - AspNetCoreGeneratedDocument
3+
UsingDirective - - TModel = global::System.Object
4+
UsingDirective - (1:0,1 [20] ) - global::System
5+
UsingDirective - (24:1,1 [40] ) - global::System.Collections.Generic
6+
UsingDirective - (67:2,1 [25] ) - global::System.Linq
7+
UsingDirective - (95:3,1 [36] ) - global::System.Threading.Tasks
8+
UsingDirective - (134:4,1 [38] ) - global::Microsoft.AspNetCore.Mvc
9+
UsingDirective - (175:5,1 [48] ) - global::Microsoft.AspNetCore.Mvc.Rendering
10+
UsingDirective - (226:6,1 [51] ) - global::Microsoft.AspNetCore.Mvc.ViewFeatures
11+
RazorCompiledItemMetadataAttribute -
12+
CreateNewOnMetadataUpdateAttribute -
13+
ClassDeclaration - - internal sealed - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_test - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic> -
14+
DefaultTagHelperRuntime -
15+
FieldDeclaration - - private - global::Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper - __Microsoft_AspNetCore_Mvc_Razor_TagHelpers_HeadTagHelper
16+
DesignTimeDirective -
17+
DirectiveToken - (287:7,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel>
18+
DirectiveToken - (350:7,71 [4] ) - Html
19+
DirectiveToken - (364:8,8 [54] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper
20+
DirectiveToken - (419:8,63 [4] ) - Json
21+
DirectiveToken - (433:9,8 [53] ) - global::Microsoft.AspNetCore.Mvc.IViewComponentHelper
22+
DirectiveToken - (487:9,62 [9] ) - Component
23+
DirectiveToken - (506:10,8 [43] ) - global::Microsoft.AspNetCore.Mvc.IUrlHelper
24+
DirectiveToken - (550:10,52 [3] ) - Url
25+
DirectiveToken - (563:11,8 [70] ) - global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider
26+
DirectiveToken - (634:11,79 [23] ) - ModelExpressionProvider
27+
DirectiveToken - (673:12,14 [104] ) - global::Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor
28+
DirectiveToken - (793:13,14 [95] ) - global::Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor
29+
DirectiveToken - (904:14,14 [95] ) - global::Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor
30+
CSharpCode -
31+
IntermediateToken - - CSharp - #pragma warning disable 0414
32+
CSharpCode -
33+
IntermediateToken - - CSharp - private static object __o = null;
34+
CSharpCode -
35+
IntermediateToken - - CSharp - #pragma warning restore 0414
36+
MethodDeclaration - - public async override - global::System.Threading.Tasks.Task - ExecuteAsync
37+
HtmlContent - (0:0,0 [12] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml)
38+
LazyIntermediateToken - (0:0,0 [5] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - <html
39+
LazyIntermediateToken - (5:0,5 [1] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - >
40+
LazyIntermediateToken - (6:0,6 [6] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n
41+
TagHelper - (12:1,4 [30] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - head - TagMode.StartTagAndEndTag
42+
DefaultTagHelperBody -
43+
HtmlContent - (18:1,10 [10] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml)
44+
LazyIntermediateToken - (18:1,10 [10] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n
45+
CSharpExpression - (29:2,9 [0] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml)
46+
LazyIntermediateToken - (29:2,9 [0] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - CSharp -
47+
HtmlContent - (29:2,9 [6] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml)
48+
LazyIntermediateToken - (29:2,9 [6] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n
49+
DefaultTagHelperCreate - - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper
50+
DefaultTagHelperExecute -
51+
HtmlContent - (42:3,11 [9] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml)
52+
LazyIntermediateToken - (42:3,11 [2] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - \n
53+
LazyIntermediateToken - (44:4,0 [7] TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml) - Html - </html>
54+
Inject -
55+
Inject -
56+
Inject -
57+
Inject -
58+
Inject -
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#pragma checksum "TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "e297cf93ff7f33ab02330169876f3e695dc26e57f3b7b474cac407efa4bed6a0"
2+
// <auto-generated/>
3+
#pragma warning disable 1591
4+
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCoreGeneratedDocument.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_test), @"mvc.1.0.view", @"/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/test.cshtml")]
5+
namespace AspNetCoreGeneratedDocument
6+
{
7+
#line default
8+
using global::System;
9+
using global::System.Collections.Generic;
10+
using global::System.Linq;
11+
using global::System.Threading.Tasks;
12+
using global::Microsoft.AspNetCore.Mvc;
13+
using global::Microsoft.AspNetCore.Mvc.Rendering;
14+
using global::Microsoft.AspNetCore.Mvc.ViewFeatures;
15+
#line default
16+
#line hidden
17+
[global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"Sha256", @"e297cf93ff7f33ab02330169876f3e695dc26e57f3b7b474cac407efa4bed6a0", @"/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/test.cshtml")]
18+
[global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("Identifier", "/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/test.cshtml")]
19+
[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdateAttribute]
20+
#nullable restore
21+
internal sealed class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_test : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
22+
#nullable disable
23+
{
24+
#line hidden
25+
#pragma warning disable 0649
26+
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext;
27+
#pragma warning restore 0649
28+
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
29+
#pragma warning disable 0169
30+
private string __tagHelperStringValueBuffer;
31+
#pragma warning restore 0169
32+
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
33+
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
34+
{
35+
get
36+
{
37+
if (__backed__tagHelperScopeManager == null)
38+
{
39+
__backed__tagHelperScopeManager = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
40+
}
41+
return __backed__tagHelperScopeManager;
42+
}
43+
}
44+
private global::Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper __Microsoft_AspNetCore_Mvc_Razor_TagHelpers_HeadTagHelper;
45+
#pragma warning disable 1998
46+
public async override global::System.Threading.Tasks.Task ExecuteAsync()
47+
{
48+
WriteLiteral("<html>\r\n ");
49+
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("head", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.StartTagAndEndTag, "__UniqueIdSuppressedForTesting__", async() => {
50+
WriteLiteral("\r\n ");
51+
Write(
52+
#nullable restore
53+
#line (3,10)-(3,10) "TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml"
54+
55+
#line default
56+
#line hidden
57+
#nullable disable
58+
);
59+
WriteLiteral("\r\n ");
60+
}
61+
);
62+
__Microsoft_AspNetCore_Mvc_Razor_TagHelpers_HeadTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper>();
63+
__tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_Razor_TagHelpers_HeadTagHelper);
64+
await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
65+
if (!__tagHelperExecutionContext.Output.IsContentModified)
66+
{
67+
await __tagHelperExecutionContext.SetOutputContentAsync();
68+
}
69+
Write(__tagHelperExecutionContext.Output);
70+
__tagHelperExecutionContext = __tagHelperScopeManager.End();
71+
WriteLiteral("\r\n</html>");
72+
}
73+
#pragma warning restore 1998
74+
#nullable restore
75+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
76+
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } = default!;
77+
#nullable disable
78+
#nullable restore
79+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
80+
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } = default!;
81+
#nullable disable
82+
#nullable restore
83+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
84+
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } = default!;
85+
#nullable disable
86+
#nullable restore
87+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
88+
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } = default!;
89+
#nullable disable
90+
#nullable restore
91+
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
92+
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; } = default!;
93+
#nullable disable
94+
}
95+
}
96+
#pragma warning restore 1591
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TestFiles\IntegrationTests\CodeGenerationIntegrationTest\test.cshtml(3,10): Error RZ1003: A space or line break was encountered after the "@" character. Only valid identifiers, keywords, comments, "(" and "{" are valid at the start of a code block and they must occur immediately following "@" with no space in between.

0 commit comments

Comments
 (0)