diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs index 1362c42c0dd..1d957c34f87 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs @@ -12149,6 +12149,34 @@ public void LinePragma_Multiline() #region RenderMode + [IntegrationTestFact] + public void RenderMode_Directive_WithTypeParam() + { + var generated = CompileToCSharp(""" + @typeparam T + @rendermode Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + """); + + // Assert + AssertDocumentNodeMatchesBaseline(generated.CodeDocument); + AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); + CompileToAssembly(generated); + } + + [IntegrationTestFact] + public void RenderMode_Directive_WithTypeParam_First() + { + var generated = CompileToCSharp(""" + @rendermode Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + @typeparam T + """); + + // Assert + AssertDocumentNodeMatchesBaseline(generated.CodeDocument); + AssertCSharpDocumentMatchesBaseline(generated.CodeDocument); + CompileToAssembly(generated); + } + [IntegrationTestFact] public void RenderMode_Directive_FullyQualified() { diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentRenderModeDirectiveIntegrationTests.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentRenderModeDirectiveIntegrationTests.cs index b53fb1e279a..0e404a0899b 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentRenderModeDirectiveIntegrationTests.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentRenderModeDirectiveIntegrationTests.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Roslyn.Test.Utilities; using Xunit; @@ -12,6 +13,64 @@ public class ComponentRenderModeDirectiveIntegrationTests : RazorIntegrationTest { internal override RazorFileKind? FileKind => RazorFileKind.Component; + [Fact] + public void RenderMode_GenericComponent_CSharp11() + { + // Arrange & Act + var component = CompileToComponent(""" + @typeparam T + + @rendermode Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + """, genericArity: 1); + + // Assert + VerifyRenderModeAttribute(component, $$""" + file sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } + """); + } + + [Fact] + public void RenderMode_GenericComponent_CSharp10_RazorLang9() + { + // Arrange & Act + var compilationResult = CompileToCSharp(DefaultFileName, cshtmlContent: """ + @typeparam T + + @rendermode Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + """, configuration: Configuration with { LanguageVersion = RazorLanguageVersion.Version_9_0 }); + + CompileToAssembly(compilationResult, + // (13,19): error CS0305: Using the generic type 'TestComponent' requires 1 type arguments + // [global::Test.TestComponent.__PrivateComponentRenderModeAttribute] + Diagnostic(ErrorCode.ERR_BadArity, "TestComponent").WithArguments("Test.TestComponent", "type", "1").WithLocation(13, 19)); + } + + [Fact] + public void RenderMode_GenericComponent_CSharp10() + { + var csharpParseOptions = CSharpParseOptions.WithLanguageVersion(CodeAnalysis.CSharp.LanguageVersion.CSharp10); + + // Arrange & Act + var compilationResult = CompileToCSharp(DefaultFileName, csharpParseOptions: csharpParseOptions, cshtmlContent: """ + @typeparam T + + @rendermode Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + """); + + CompileToAssembly(compilationResult, + // (13,19): error CS0305: Using the generic type 'TestComponent' requires 1 type arguments + // [global::Test.TestComponent.__PrivateComponentRenderModeAttribute] + Diagnostic(ErrorCode.ERR_BadArity, "TestComponent").WithArguments("Test.TestComponent", "type", "1").WithLocation(13, 19), + // (31,70): error CS8936: Feature 'generic attributes' is not available in C# 10.0. Please use language version 11.0 or greater. + // private sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "global::Microsoft.AspNetCore.Components.RenderModeAttribute").WithArguments("generic attributes", "11.0").WithLocation(31, 70)); + } + [Fact] public void RenderMode_With_Fully_Qualified_Type() { @@ -51,6 +110,27 @@ private sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.A """); } + [Fact] + public void RenderMode_With_Static_Usings_GenericComponent() + { + // Arrange & Act + var component = CompileToComponent(""" + @using static Microsoft.AspNetCore.Components.Web.RenderMode + @typeparam T + @rendermode InteractiveServer + """, genericArity: 1); + + // Assert + VerifyRenderModeAttribute(component, """ + file sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => InteractiveServer + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } + """); + } + [Fact] public void RenderMode_Missing_Value() { @@ -369,12 +449,70 @@ private sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.A """); } + [Fact] + public void RenderMode_With_FunctionCall_Generic() + { + // Arrange & Act + var component = CompileToComponent(""" + @typeparam T + @rendermode @(TestComponent.GetRenderMode()) + + @code + { + public static Microsoft.AspNetCore.Components.IComponentRenderMode GetRenderMode() => Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer; + } + """, genericArity: 1); + + // Assert + VerifyRenderModeAttribute(component, $$""" + file sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => + #nullable restore + #line (2,15)-(2,52) "{{DefaultDocumentPath}}" + TestComponent.GetRenderMode() + + #line default + #line hidden + #nullable disable + + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } + """); + } + + [Fact] + public void RenderMode_With_FunctionCall_Generic_BadRef() + { + // Arrange & Act + var compilationResult = CompileToCSharp(""" + @typeparam T + @rendermode @(TestComponent.GetRenderMode()) + + @code + { + public static Microsoft.AspNetCore.Components.IComponentRenderMode GetRenderMode() => Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer; + } + """); + + // Assert + CompileToAssembly(compilationResult, + // x:\dir\subdir\Test\TestComponent.cshtml(2,15): error CS0305: Using the generic type 'TestComponent' requires 1 type arguments + // TestComponent.GetRenderMode() + Diagnostic(ErrorCode.ERR_BadArity, "TestComponent").WithArguments("Test.TestComponent", "type", "1").WithLocation(2, 15)); + } + private static void VerifyRenderModeAttribute(INamedTypeSymbol component, string expected) { var attribute = Assert.Single(component.GetAttributes()); - AssertEx.Equal("__PrivateComponentRenderModeAttribute", attribute.AttributeClass?.Name); + Assert.NotNull(attribute.AttributeClass); + var attributeClass = attribute.AttributeClass; ; + AssertEx.Equal("__PrivateComponentRenderModeAttribute", attributeClass.Name); - var attributeType = component.ContainingAssembly.GetTypeByMetadataName("Test.TestComponent+__PrivateComponentRenderModeAttribute"); + var attributeType = attributeClass.IsFileLocal + ? component.ContainingAssembly.GetTypeByMetadataName($"Test.{attributeClass.MetadataName}") + : component.ContainingAssembly.GetTypeByMetadataName("Test.TestComponent+__PrivateComponentRenderModeAttribute"); Assert.NotNull(attributeType); expected = expected.NormalizeLineEndings(); diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.codegen.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.codegen.cs new file mode 100644 index 00000000000..7f78810f9eb --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.codegen.cs @@ -0,0 +1,73 @@ +// +#pragma warning disable 1591 +namespace Test +{ + #line default + using global::System; + using global::System.Collections.Generic; + using global::System.Linq; + using global::System.Threading.Tasks; + using global::Microsoft.AspNetCore.Components; + #line default + #line hidden + [__PrivateComponentRenderModeAttribute] + #nullable restore + public partial class TestComponent< +#nullable restore +#line 1 "x:\dir\subdir\Test\TestComponent.cshtml" +T + +#line default +#line hidden +#nullable disable + > : global::Microsoft.AspNetCore.Components.ComponentBase + #nullable disable + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + ((global::System.Action)(() => { + } + ))(); + ((global::System.Action)(() => { +#nullable restore +#line 2 "x:\dir\subdir\Test\TestComponent.cshtml" +global::System.Object __typeHelper = nameof(Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer); + +#line default +#line hidden +#nullable disable + } + ))(); + } + #pragma warning restore 219 + #pragma warning disable 0414 + private static object __o = null; + #pragma warning restore 0414 + #pragma warning disable 1998 + protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) + { + } + #pragma warning restore 1998 + } + file sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + } + #pragma warning restore 219 + #pragma warning disable 0414 + private static object __o = null; + #pragma warning restore 0414 + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => +#nullable restore +#line 2 "x:\dir\subdir\Test\TestComponent.cshtml" + Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + +#line default +#line hidden +#nullable disable + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } +} +#pragma warning restore 1591 diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.ir.txt b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.ir.txt new file mode 100644 index 00000000000..9eaa469b410 --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.ir.txt @@ -0,0 +1,35 @@ +Document - + NamespaceDeclaration - - Test + UsingDirective - (3:1,1 [20] ) - global::System + UsingDirective - (26:2,1 [40] ) - global::System.Collections.Generic + UsingDirective - (69:3,1 [25] ) - global::System.Linq + UsingDirective - (97:4,1 [36] ) - global::System.Threading.Tasks + UsingDirective - (136:5,1 [45] ) - global::Microsoft.AspNetCore.Components + CSharpCode - + IntermediateToken - - CSharp - [__PrivateComponentRenderModeAttribute] + ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase - - T + DesignTimeDirective - + DirectiveToken - (11:0,11 [1] x:\dir\subdir\Test\TestComponent.cshtml) - T + DirectiveToken - (26:1,12 [64] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + CSharpCode - + IntermediateToken - - CSharp - #pragma warning disable 0414 + CSharpCode - + IntermediateToken - - CSharp - private static object __o = null; + CSharpCode - + IntermediateToken - - CSharp - #pragma warning restore 0414 + MethodDeclaration - - protected override - void - BuildRenderTree + ClassDeclaration - - file sealed - __PrivateComponentRenderModeAttribute - global::Microsoft.AspNetCore.Components.RenderModeAttribute - + DesignTimeDirective - + CSharpCode - + IntermediateToken - - CSharp - #pragma warning disable 0414 + CSharpCode - + IntermediateToken - - CSharp - private static object __o = null; + CSharpCode - + IntermediateToken - - CSharp - #pragma warning restore 0414 + CSharpCode - + IntermediateToken - - CSharp - private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => + CSharpCode - (26:1,12 [64] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + IntermediateToken - - CSharp - ; + CSharpCode - + IntermediateToken - - CSharp - public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.mappings.txt b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.mappings.txt new file mode 100644 index 00000000000..b0f2e6eba1c --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.mappings.txt @@ -0,0 +1,10 @@ +Source Location: (11:0,11 [1] x:\dir\subdir\Test\TestComponent.cshtml) +|T| +Generated Location: (507:17,0 [1] ) +|T| + +Source Location: (26:1,12 [64] x:\dir\subdir\Test\TestComponent.cshtml) +|Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer| +Generated Location: (971:33,44 [64] ) +|Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer| + diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.codegen.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.codegen.cs new file mode 100644 index 00000000000..f5e7f7bc9ee --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.codegen.cs @@ -0,0 +1,73 @@ +// +#pragma warning disable 1591 +namespace Test +{ + #line default + using global::System; + using global::System.Collections.Generic; + using global::System.Linq; + using global::System.Threading.Tasks; + using global::Microsoft.AspNetCore.Components; + #line default + #line hidden + [__PrivateComponentRenderModeAttribute] + #nullable restore + public partial class TestComponent< +#nullable restore +#line 2 "x:\dir\subdir\Test\TestComponent.cshtml" +T + +#line default +#line hidden +#nullable disable + > : global::Microsoft.AspNetCore.Components.ComponentBase + #nullable disable + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + ((global::System.Action)(() => { +#nullable restore +#line 1 "x:\dir\subdir\Test\TestComponent.cshtml" +global::System.Object __typeHelper = nameof(Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer); + +#line default +#line hidden +#nullable disable + } + ))(); + ((global::System.Action)(() => { + } + ))(); + } + #pragma warning restore 219 + #pragma warning disable 0414 + private static object __o = null; + #pragma warning restore 0414 + #pragma warning disable 1998 + protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) + { + } + #pragma warning restore 1998 + } + file sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + } + #pragma warning restore 219 + #pragma warning disable 0414 + private static object __o = null; + #pragma warning restore 0414 + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => +#nullable restore +#line 1 "x:\dir\subdir\Test\TestComponent.cshtml" + Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + +#line default +#line hidden +#nullable disable + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } +} +#pragma warning restore 1591 diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.ir.txt b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.ir.txt new file mode 100644 index 00000000000..2cb3caa0e59 --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.ir.txt @@ -0,0 +1,35 @@ +Document - + NamespaceDeclaration - - Test + UsingDirective - (3:1,1 [20] ) - global::System + UsingDirective - (26:2,1 [40] ) - global::System.Collections.Generic + UsingDirective - (69:3,1 [25] ) - global::System.Linq + UsingDirective - (97:4,1 [36] ) - global::System.Threading.Tasks + UsingDirective - (136:5,1 [45] ) - global::Microsoft.AspNetCore.Components + CSharpCode - + IntermediateToken - - CSharp - [__PrivateComponentRenderModeAttribute] + ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase - - T + DesignTimeDirective - + DirectiveToken - (12:0,12 [64] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + DirectiveToken - (89:1,11 [1] x:\dir\subdir\Test\TestComponent.cshtml) - T + CSharpCode - + IntermediateToken - - CSharp - #pragma warning disable 0414 + CSharpCode - + IntermediateToken - - CSharp - private static object __o = null; + CSharpCode - + IntermediateToken - - CSharp - #pragma warning restore 0414 + MethodDeclaration - - protected override - void - BuildRenderTree + ClassDeclaration - - file sealed - __PrivateComponentRenderModeAttribute - global::Microsoft.AspNetCore.Components.RenderModeAttribute - + DesignTimeDirective - + CSharpCode - + IntermediateToken - - CSharp - #pragma warning disable 0414 + CSharpCode - + IntermediateToken - - CSharp - private static object __o = null; + CSharpCode - + IntermediateToken - - CSharp - #pragma warning restore 0414 + CSharpCode - + IntermediateToken - - CSharp - private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => + CSharpCode - (12:0,12 [64] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + IntermediateToken - - CSharp - ; + CSharpCode - + IntermediateToken - - CSharp - public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.mappings.txt b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.mappings.txt new file mode 100644 index 00000000000..c4b88fa2dd3 --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.mappings.txt @@ -0,0 +1,10 @@ +Source Location: (89:1,11 [1] x:\dir\subdir\Test\TestComponent.cshtml) +|T| +Generated Location: (507:17,0 [1] ) +|T| + +Source Location: (12:0,12 [64] x:\dir\subdir\Test\TestComponent.cshtml) +|Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer| +Generated Location: (903:30,44 [64] ) +|Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer| + diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.codegen.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.codegen.cs new file mode 100644 index 00000000000..10104da8a51 --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.codegen.cs @@ -0,0 +1,39 @@ +// +#pragma warning disable 1591 +namespace Test +{ + #line default + using global::System; + using global::System.Collections.Generic; + using global::System.Linq; + using global::System.Threading.Tasks; + using global::Microsoft.AspNetCore.Components; + #line default + #line hidden + [__PrivateComponentRenderModeAttribute] + #nullable restore + public partial class TestComponent< +#nullable restore +#line (1,12)-(1,13) "x:\dir\subdir\Test\TestComponent.cshtml" +T + +#line default +#line hidden +#nullable disable + > : global::Microsoft.AspNetCore.Components.ComponentBase + #nullable disable + { + #pragma warning disable 1998 + protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) + { + } + #pragma warning restore 1998 + } + file sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } +} +#pragma warning restore 1591 diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.ir.txt b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.ir.txt new file mode 100644 index 00000000000..cb77278e555 --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.ir.txt @@ -0,0 +1,19 @@ +Document - + NamespaceDeclaration - - Test + UsingDirective - (3:1,1 [20] ) - global::System + UsingDirective - (26:2,1 [40] ) - global::System.Collections.Generic + UsingDirective - (69:3,1 [25] ) - global::System.Linq + UsingDirective - (97:4,1 [36] ) - global::System.Threading.Tasks + UsingDirective - (136:5,1 [45] ) - global::Microsoft.AspNetCore.Components + CSharpCode - + IntermediateToken - - CSharp - [__PrivateComponentRenderModeAttribute] + ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase - - T + MethodDeclaration - - protected override - void - BuildRenderTree + ClassDeclaration - - file sealed - __PrivateComponentRenderModeAttribute - global::Microsoft.AspNetCore.Components.RenderModeAttribute - + CSharpCode - + IntermediateToken - - CSharp - private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => + CSharpCode - (26:1,12 [64] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + IntermediateToken - - CSharp - ; + CSharpCode - + IntermediateToken - - CSharp - public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.mappings.txt b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.mappings.txt new file mode 100644 index 00000000000..d51bcb9ed83 --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam/TestComponent.mappings.txt @@ -0,0 +1,5 @@ +Source Location: (11:0,11 [1] x:\dir\subdir\Test\TestComponent.cshtml) +|T| +Generated Location: (519:17,0 [1] ) +|T| + diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.codegen.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.codegen.cs new file mode 100644 index 00000000000..b39d974fe95 --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.codegen.cs @@ -0,0 +1,39 @@ +// +#pragma warning disable 1591 +namespace Test +{ + #line default + using global::System; + using global::System.Collections.Generic; + using global::System.Linq; + using global::System.Threading.Tasks; + using global::Microsoft.AspNetCore.Components; + #line default + #line hidden + [__PrivateComponentRenderModeAttribute] + #nullable restore + public partial class TestComponent< +#nullable restore +#line (2,12)-(2,13) "x:\dir\subdir\Test\TestComponent.cshtml" +T + +#line default +#line hidden +#nullable disable + > : global::Microsoft.AspNetCore.Components.ComponentBase + #nullable disable + { + #pragma warning disable 1998 + protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) + { + } + #pragma warning restore 1998 + } + file sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } +} +#pragma warning restore 1591 diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.ir.txt b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.ir.txt new file mode 100644 index 00000000000..7953a6f8d4a --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.ir.txt @@ -0,0 +1,19 @@ +Document - + NamespaceDeclaration - - Test + UsingDirective - (3:1,1 [20] ) - global::System + UsingDirective - (26:2,1 [40] ) - global::System.Collections.Generic + UsingDirective - (69:3,1 [25] ) - global::System.Linq + UsingDirective - (97:4,1 [36] ) - global::System.Threading.Tasks + UsingDirective - (136:5,1 [45] ) - global::Microsoft.AspNetCore.Components + CSharpCode - + IntermediateToken - - CSharp - [__PrivateComponentRenderModeAttribute] + ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase - - T + MethodDeclaration - - protected override - void - BuildRenderTree + ClassDeclaration - - file sealed - __PrivateComponentRenderModeAttribute - global::Microsoft.AspNetCore.Components.RenderModeAttribute - + CSharpCode - + IntermediateToken - - CSharp - private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => + CSharpCode - (12:0,12 [64] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer + IntermediateToken - - CSharp - ; + CSharpCode - + IntermediateToken - - CSharp - public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.mappings.txt b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.mappings.txt new file mode 100644 index 00000000000..aa0066860dd --- /dev/null +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/RenderMode_Directive_WithTypeParam_First/TestComponent.mappings.txt @@ -0,0 +1,5 @@ +Source Location: (89:1,11 [1] x:\dir\subdir\Test\TestComponent.cshtml) +|T| +Generated Location: (519:17,0 [1] ) +|T| + diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Components/ComponentRenderModeDirectivePass.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Components/ComponentRenderModeDirectivePass.cs index c67f462d6c1..ebae947de92 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Components/ComponentRenderModeDirectivePass.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Components/ComponentRenderModeDirectivePass.cs @@ -39,12 +39,20 @@ protected override void ExecuteCore( return; } + // If the user is Razor 10 or higher, C# 11 or higher, and has a generic compoment, then we can use a file-scoped class for the generated attribute + // so everything compiles correctly. + var useFileScopedClass = codeDocument.ParserOptions.CSharpParseOptions.LanguageVersion >= CodeAnalysis.CSharp.LanguageVersion.CSharp11 && + codeDocument.ParserOptions.LanguageVersion >= RazorLanguageVersion.Version_10_0 && + @class.TypeParameters.Length > 0; + // generate the inner attribute class var classDecl = new ClassDeclarationIntermediateNode { Name = GeneratedRenderModeAttributeName, BaseType = new BaseTypeWithModel($"global::{ComponentsApi.RenderModeAttribute.FullTypeName}"), - Modifiers = CommonModifiers.PrivateSealed + Modifiers = useFileScopedClass + ? CommonModifiers.FileSealed + : CommonModifiers.PrivateSealed }; classDecl.Children.Add(new CSharpCodeIntermediateNode() @@ -74,13 +82,23 @@ child is not DirectiveTokenIntermediateNode directiveToken } }); - @class.Children.Add(classDecl); + if (useFileScopedClass) + { + @namespace.Children.Add(classDecl); + } + else + { + @class.Children.Add(classDecl); + } // generate the attribute usage on top of the class var attributeNode = new CSharpCodeIntermediateNode(); var namespaceSeparator = string.IsNullOrEmpty(@namespace.Name) ? string.Empty : "."; + var attributeContents = useFileScopedClass + ? GeneratedRenderModeAttributeName + : $"global::{@namespace.Name}{namespaceSeparator}{@class.Name}.{GeneratedRenderModeAttributeName}"; attributeNode.Children.Add( - IntermediateNodeFactory.CSharpToken($"[global::{@namespace.Name}{namespaceSeparator}{@class.Name}.{GeneratedRenderModeAttributeName}]")); + IntermediateNodeFactory.CSharpToken($"[{attributeContents}]")); // Insert the new attribute on top of the class var childCount = @namespace.Children.Count; diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/CommonModifiers.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/CommonModifiers.cs index e30e518cd01..f1b55bfda01 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/CommonModifiers.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/CommonModifiers.cs @@ -34,6 +34,10 @@ private static string GetText(CSharpSyntaxKind kind) GetText(CSharpSyntaxKind.PrivateKeyword), GetText(CSharpSyntaxKind.SealedKeyword)]; + public static ImmutableArray FileSealed { get; } = [ + GetText(CSharpSyntaxKind.FileKeyword), + GetText(CSharpSyntaxKind.SealedKeyword)]; + public static ImmutableArray Protected { get; } = [ GetText(CSharpSyntaxKind.ProtectedKeyword)]; diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorLanguageVersion.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorLanguageVersion.cs index aa55faadba0..9c86963c43d 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorLanguageVersion.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorLanguageVersion.cs @@ -25,7 +25,8 @@ public sealed record RazorLanguageVersion : IComparable public static readonly RazorLanguageVersion Version_7_0 = new(7, 0); public static readonly RazorLanguageVersion Version_8_0 = new(8, 0); public static readonly RazorLanguageVersion Version_9_0 = new(9, 0); - public static readonly RazorLanguageVersion Latest = Version_9_0; + public static readonly RazorLanguageVersion Version_10_0 = new(10, 0); + public static readonly RazorLanguageVersion Latest = Version_10_0; public static readonly RazorLanguageVersion Experimental = new(1337, 1337); private static readonly FrozenDictionary s_knownVersions = BuildKnownVersions(); @@ -53,6 +54,7 @@ private static FrozenDictionary BuildKnownVersions ["7.0"] = Version_7_0, ["8.0"] = Version_8_0, ["9.0"] = Version_9_0, + ["10.0"] = Version_10_0, ["latest"] = Latest, ["experimental"] = Experimental, }; diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/ErrorCode.cs b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/ErrorCode.cs index 94231654484..b6430a65b3d 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/ErrorCode.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/ErrorCode.cs @@ -18,6 +18,7 @@ public enum ErrorCode WRN_UnreferencedVarAssg = 219, ERR_DottedTypeNameNotFoundInNS = 234, ERR_SingleTypeNameNotFound = 246, + ERR_BadArity = 305, ERR_CantInferMethTypeArgs = 411, WRN_UnreferencedFieldAssg = 414, WRN_InvalidAttributeLocation = 658, @@ -45,5 +46,6 @@ public enum ErrorCode WRN_NullReferenceReceiver = 8602, WRN_UninitializedNonNullableField = 8618, WRN_MissingNonNullTypesContextForAnnotationInGeneratedCode = 8669, + ERR_FeatureNotAvailableInVersion10 = 8936, ERR_IllegalAtSequence = 9008, } diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs index 7e34e9906d5..4ad32008cb3 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs @@ -384,11 +384,17 @@ private static MemoryStream EmitCompilation(Compilation compilation) return peStream; } - protected INamedTypeSymbol CompileToComponent(string cshtmlSource) + protected INamedTypeSymbol CompileToComponent(string cshtmlSource, int genericArity = 0) { var assemblyResult = CompileToAssembly(DefaultFileName, cshtmlSource); var componentFullTypeName = $"{DefaultRootNamespace}.{Path.GetFileNameWithoutExtension(DefaultFileName)}"; + + if (genericArity > 0) + { + componentFullTypeName += "`" + genericArity; + } + return CompileToComponent(assemblyResult, componentFullTypeName); }