diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/MvcViewDocumentClassifierPass.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/MvcViewDocumentClassifierPass.cs index c2e99715c8..4341c8eec2 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/MvcViewDocumentClassifierPass.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/MvcViewDocumentClassifierPass.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { public class MvcViewDocumentClassifierPass : DocumentClassifierPassBase { - public readonly string MvcViewDocumentKind = "mvc.1.0.view"; + public static readonly string MvcViewDocumentKind = "mvc.1.0.view"; protected override string DocumentKind => MvcViewDocumentKind; diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/NamespaceDirective.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/NamespaceDirective.cs new file mode 100644 index 0000000000..188b60f6ca --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/NamespaceDirective.cs @@ -0,0 +1,191 @@ +// 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; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Intermediate; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public static class NamespaceDirective + { + private static readonly char[] Separators = new char[] { '\\', '/' }; + + public static readonly DirectiveDescriptor Directive = DirectiveDescriptorBuilder.Create("namespace").AddNamespace().Build(); + + public static void Register(IRazorEngineBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(); + } + + builder.AddDirective(Directive); + builder.Features.Add(new Pass()); + } + + // internal for testing + internal class Pass : RazorIRPassBase, IRazorDirectiveClassifierPass + { + public override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument) + { + if (irDocument.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind && + irDocument.DocumentKind != MvcViewDocumentClassifierPass.MvcViewDocumentKind) + { + // Not a page. Skip. + return; + } + + var visitor = new Visitor(); + visitor.Visit(irDocument); + + var directive = visitor.LastNamespaceDirective; + if (directive == null) + { + // No namespace set. Skip. + return; + } + + var @namespace = visitor.FirstNamespace; + if (@namespace == null) + { + // No namespace node. Skip. + return; + } + + if (TryComputeNamespace(codeDocument.Source.FileName, directive, out var computedNamespace)) + { + // Beautify the class name since we're using a hierarchy for namespaces. + var @class = visitor.FirstClass; + if (@class != null && irDocument.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind) + { + @class.Name = Path.GetFileNameWithoutExtension(codeDocument.Source.FileName) + "_Page"; + } + else if (@class != null && irDocument.DocumentKind == MvcViewDocumentClassifierPass.MvcViewDocumentKind) + { + @class.Name = Path.GetFileNameWithoutExtension(codeDocument.Source.FileName) + "_View"; + } + } + + @namespace.Content = computedNamespace; + } + } + + // internal for testing. + // + // This code does a best-effort attempt to compute a namespace 'suffix' - the path difference between + // where the @namespace directive appears and where the current document is on disk. + // + // In the event that these two source either don't have filenames set or don't follow a coherent hierarchy, + // we will just use the namespace verbatim. + internal static bool TryComputeNamespace(string source, DirectiveIRNode directive, out string @namespace) + { + var directiveSource = NormalizeDirectory(directive.Source?.FilePath); + + var baseNamespace = directive.Tokens.First().Content; + if (string.IsNullOrEmpty(source) || directiveSource == null) + { + // No sources, can't compute a suffix. + @namespace = baseNamespace; + return false; + } + + // We're specifically using OrdinalIgnoreCase here because Razor treats all paths as case-insensitive. + if (!source.StartsWith(directiveSource, StringComparison.OrdinalIgnoreCase) || + source.Length <= directiveSource.Length) + { + // The imports are not from the directory hierarchy, can't compute a suffix. + @namespace = baseNamespace; + return false; + } + + // OK so that this point we know that the 'imports' file containing this directive is in the directory + // hierarchy of this soure file. This is the case where we can append a suffix to the baseNamespace. + // + // Everything so far has just been defensiveness on our part. + + var builder = new StringBuilder(baseNamespace); + + var segments = source.Substring(directiveSource.Length).Split(Separators); + + // Skip the last segment because it's the filename. + for (var i = 0; i < segments.Length - 1; i++) + { + builder.Append('.'); + builder.Append(segments[i]); + } + + @namespace = builder.ToString(); + return true; + } + + // We want to normalize the path of the file containing the '@namespace' directive to just the containing + // directory with a trailing separator. + // + // Not using Path.GetDirectoryName here because it doesn't meet these requirements, and we want to handle + // both 'view engine' style paths and absolute paths. + // + // We also don't normalize the separators here. We expect that all documents are using a consistent style of path. + // + // If we can't normalize the path, we just return null so it will be ignored. + private static string NormalizeDirectory(string path) + { + if (string.IsNullOrEmpty(path)) + { + return null; + } + + var lastSeparator = path.LastIndexOfAny(Separators); + if (lastSeparator == -1) + { + return null; + } + + // Includes the separator + return path.Substring(0, lastSeparator + 1); + } + + private class Visitor : RazorIRNodeWalker + { + public ClassDeclarationIRNode FirstClass { get; private set; } + + public NamespaceDeclarationIRNode FirstNamespace { get; private set; } + + // We want the last one, so get them all and then . + public DirectiveIRNode LastNamespaceDirective { get; private set; } + + public override void VisitNamespace(NamespaceDeclarationIRNode node) + { + if (FirstNamespace == null) + { + FirstNamespace = node; + } + + base.VisitNamespace(node); + } + + public override void VisitClass(ClassDeclarationIRNode node) + { + if (FirstClass == null) + { + FirstClass = node; + } + + base.VisitClass(node); + } + + public override void VisitDirective(DirectiveIRNode node) + { + if (node.Descriptor == Directive) + { + LastNamespaceDirective = node; + } + + base.VisitDirective(node); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs index edf39e5216..03bea5e656 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/RazorExtensions.cs @@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions { InjectDirective.Register(builder); ModelDirective.Register(builder); + NamespaceDirective.Register(builder); PageDirective.Register(builder); builder.AddTargetExtension(new InjectDirectiveTargetExtension()); diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs index 4e638e2249..d00d3570f1 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/CSharpCodeParser.cs @@ -110,6 +110,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy { _directiveParsers.Add(directive, handler); Keywords.Add(directive); + + // These C# keywords are reserved for use in directives. It's an error to use them outside of + // a directive. This code removes the error generation if the directive *is* registered. + if (string.Equals(directive, "class", StringComparison.OrdinalIgnoreCase)) + { + _keywordParsers.Remove(CSharpKeyword.Class); + } + else if (string.Equals(directive, "namespace", StringComparison.OrdinalIgnoreCase)) + { + _keywordParsers.Remove(CSharpKeyword.Namespace); + } } } @@ -266,8 +277,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } else if (CurrentSymbol.Type == CSharpSymbolType.Identifier) { - Action handler; - if (TryGetDirectiveHandler(CurrentSymbol.Content, out handler)) + if (TryGetDirectiveHandler(CurrentSymbol.Content, out var handler)) { Span.ChunkGenerator = SpanChunkGenerator.Null; handler(); @@ -295,8 +305,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy } else if (CurrentSymbol.Type == CSharpSymbolType.Keyword) { - KeywordBlock(topLevel: true); - return; + if (TryGetDirectiveHandler(CurrentSymbol.Content, out var handler)) + { + Span.ChunkGenerator = SpanChunkGenerator.Null; + handler(); + return; + } + else + { + KeywordBlock(topLevel: true); + return; + } } else if (CurrentSymbol.Type == CSharpSymbolType.LeftBrace) { @@ -737,7 +756,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy MapKeywords(TryStatement, CSharpKeyword.Try); MapKeywords(UsingKeyword, CSharpKeyword.Using); MapKeywords(DoStatement, CSharpKeyword.Do); - MapKeywords(ReservedDirective, CSharpKeyword.Namespace, CSharpKeyword.Class); + MapKeywords(ReservedDirective, CSharpKeyword.Class, CSharpKeyword.Namespace); } protected virtual void ReservedDirective(bool topLevel) @@ -1748,7 +1767,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy [Conditional("DEBUG")] protected void AssertDirective(string directive) { - Assert(CSharpSymbolType.Identifier); + Debug.Assert(CurrentSymbol.Type == CSharpSymbolType.Identifier || CurrentSymbol.Type == CSharpSymbolType.Keyword); Debug.Assert(string.Equals(CurrentSymbol.Content, directive, StringComparison.Ordinal)); } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs index bff7037e1d..779a691a3a 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/CodeGenerationIntegrationTest.cs @@ -159,6 +159,36 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.IntegrationTests AssertIRMatchesBaseline(document.GetIRDocument()); AssertCSharpDocumentMatchesBaseline(document.GetCSharpDocument()); } + + [Fact] + public void PageWithNamespace_Runtime() + { + // Arrange + var engine = CreateRuntimeEngine(); + var document = CreateCodeDocument(); + + // Act + engine.Process(document); + + // Assert + AssertIRMatchesBaseline(document.GetIRDocument()); + AssertCSharpDocumentMatchesBaseline(document.GetCSharpDocument()); + } + + [Fact] + public void ViewWithNamespace_Runtime() + { + // Arrange + var engine = CreateRuntimeEngine(); + var document = CreateCodeDocument(); + + // Act + engine.Process(document); + + // Assert + AssertIRMatchesBaseline(document.GetIRDocument()); + AssertCSharpDocumentMatchesBaseline(document.GetCSharpDocument()); + } #endregion #region DesignTime @@ -311,6 +341,36 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.IntegrationTests AssertIRMatchesBaseline(document.GetIRDocument()); AssertCSharpDocumentMatchesBaseline(document.GetCSharpDocument()); } + + [Fact] + public void PageWithNamespace_DesignTime() + { + // Arrange + var engine = CreateDesignTimeEngine(); + var document = CreateCodeDocument(); + + // Act + engine.Process(document); + + // Assert + AssertIRMatchesBaseline(document.GetIRDocument()); + AssertCSharpDocumentMatchesBaseline(document.GetCSharpDocument()); + } + + [Fact] + public void ViewWithNamespace_DesignTime() + { + // Arrange + var engine = CreateDesignTimeEngine(); + var document = CreateCodeDocument(); + + // Act + engine.Process(document); + + // Assert + AssertIRMatchesBaseline(document.GetIRDocument()); + AssertCSharpDocumentMatchesBaseline(document.GetCSharpDocument()); + } #endregion protected RazorEngine CreateDesignTimeEngine(IEnumerable descriptors = null) diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/NamespaceDirectiveTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/NamespaceDirectiveTest.cs new file mode 100644 index 0000000000..292afbd945 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/NamespaceDirectiveTest.cs @@ -0,0 +1,278 @@ +// 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 Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Intermediate; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public class NamespaceDirectiveTest + { + // When we don't have a relationship between the source file and the imports file + // we will just use the namespace on the node directly. + [Theory] + [InlineData((string)null, (string)null)] + [InlineData("", "")] + [InlineData(null, "/foo/bar")] + [InlineData("/foo/baz", "/foo/bar/bleh")] + [InlineData("/foo.cshtml", "/foo/bar.cshtml")] + [InlineData("c:\\foo.cshtml", "d:\\foo\\bar.cshtml")] + [InlineData("c:\\foo\\bar\\bleh.cshtml", "c:\\foo\\baz\\bleh.cshtml")] + public void TryComputeNamespace_ForNonRelatedFiles_UsesNamespaceVerbatim(string source, string imports) + { + // Arrange + var node = new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan(imports, 0, 0, 0, 0), + }; + + node.Children.Add(new DirectiveTokenIRNode() { Content = "Base" }); + node.Children[0].Parent = node; + + // Act + var computed = NamespaceDirective.TryComputeNamespace(source, node, out var @namespace); + + // Assert + Assert.False(computed); + Assert.Equal("Base", @namespace); + } + + [Theory] + [InlineData("/foo.cshtml", "/_ViewImports.cshtml", "Base")] + [InlineData("/foo/bar.cshtml", "/_ViewImports.cshtml", "Base.foo")] + [InlineData("/foo/bar/baz.cshtml", "/_ViewImports.cshtml", "Base.foo.bar")] + [InlineData("/foo/bar/baz.cshtml", "/foo/_ViewImports.cshtml", "Base.bar")] + [InlineData("/Foo/bar/baz.cshtml", "/foo/_ViewImports.cshtml", "Base.bar")] + [InlineData("c:\\foo.cshtml", "c:\\_ViewImports.cshtml", "Base")] + [InlineData("c:\\foo\\bar.cshtml", "c:\\_ViewImports.cshtml", "Base.foo")] + [InlineData("c:\\foo\\bar\\baz.cshtml", "c:\\_ViewImports.cshtml", "Base.foo.bar")] + [InlineData("c:\\foo\\bar\\baz.cshtml", "c:\\foo\\_ViewImports.cshtml", "Base.bar")] + [InlineData("c:\\Foo\\bar\\baz.cshtml", "c:\\foo\\_ViewImports.cshtml", "Base.bar")] + public void TryComputeNamespace_ForRelatedFiles_ComputesNamespaceWithSuffix(string source, string imports, string expected) + { + // Arrange + var node = new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan(imports, 0, 0, 0, 0), + }; + + node.Children.Add(new DirectiveTokenIRNode() { Content = "Base" }); + node.Children[0].Parent = node; + + // Act + var computed = NamespaceDirective.TryComputeNamespace(source, node, out var @namespace); + + // Assert + Assert.True(computed); + Assert.Equal(expected, @namespace); + } + + // This is the case where a _ViewImports sets the namespace. + [Fact] + public void Pass_SetsNamespaceAndClassName_ComputedFromImports() + { + // Arrange + var builder = RazorIRBuilder.Document(); + + builder.Push(new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan("/Account/_ViewImports.cshtml", 0, 0, 0, 0), + }); + builder.Add(new DirectiveTokenIRNode() { Content = "WebApplication.Account" }); + builder.Pop(); + + var @namespace = new NamespaceDeclarationIRNode() { Content = "default" }; + builder.Push(@namespace); + + var @class = new ClassDeclarationIRNode() { Name = "default" }; + builder.Add(@class); + + var irDocument = (DocumentIRNode)builder.Build(); + irDocument.DocumentKind = RazorPageDocumentClassifierPass.RazorPageDocumentKind; + + var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage/AddUser.cshtml")); + + var pass = new NamespaceDirective.Pass(); + pass.Engine = RazorEngine.CreateEmpty(b => { }); + + // Act + pass.Execute(codeDocument, irDocument); + + // Assert + Assert.Equal("WebApplication.Account.Manage", @namespace.Content); + Assert.Equal("AddUser_Page", @class.Name); + } + + // This is the case where the source file sets the namespace. + [Fact] + public void Pass_SetsNamespaceAndClassName_ComputedFromSource() + { + // Arrange + var builder = RazorIRBuilder.Document(); + + // This will be ignored. + builder.Push(new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan("/Account/_ViewImports.cshtml", 0, 0, 0, 0), + }); + builder.Add(new DirectiveTokenIRNode() { Content = "ignored" }); + builder.Pop(); + + // This will be used. + builder.Push(new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan("/Account/Manage/AddUser.cshtml", 0, 0, 0, 0), + }); + builder.Add(new DirectiveTokenIRNode() { Content = "WebApplication.Account.Manage" }); + builder.Pop(); + + var @namespace = new NamespaceDeclarationIRNode() { Content = "default" }; + builder.Push(@namespace); + + var @class = new ClassDeclarationIRNode() { Name = "default" }; + builder.Add(@class); + + var irDocument = (DocumentIRNode)builder.Build(); + irDocument.DocumentKind = RazorPageDocumentClassifierPass.RazorPageDocumentKind; + + var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage/AddUser.cshtml")); + + var pass = new NamespaceDirective.Pass(); + pass.Engine = RazorEngine.CreateEmpty(b => { }); + + // Act + pass.Execute(codeDocument, irDocument); + + // Assert + Assert.Equal("WebApplication.Account.Manage", @namespace.Content); + Assert.Equal("AddUser_Page", @class.Name); + } + + // This is the case where the source file sets the namespace. + [Fact] + public void Pass_SetsNamespaceAndClassName_ComputedFromSource_ForView() + { + // Arrange + var builder = RazorIRBuilder.Document(); + + // This will be ignored. + builder.Push(new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan("/Account/_ViewImports.cshtml", 0, 0, 0, 0), + }); + builder.Add(new DirectiveTokenIRNode() { Content = "ignored" }); + builder.Pop(); + + // This will be used. + builder.Push(new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan("/Account/Manage/AddUser.cshtml", 0, 0, 0, 0), + }); + builder.Add(new DirectiveTokenIRNode() { Content = "WebApplication.Account.Manage" }); + builder.Pop(); + + var @namespace = new NamespaceDeclarationIRNode() { Content = "default" }; + builder.Push(@namespace); + + var @class = new ClassDeclarationIRNode() { Name = "default" }; + builder.Add(@class); + + var irDocument = (DocumentIRNode)builder.Build(); + irDocument.DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind; + + var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage/AddUser.cshtml")); + + var pass = new NamespaceDirective.Pass(); + pass.Engine = RazorEngine.CreateEmpty(b => { }); + + // Act + pass.Execute(codeDocument, irDocument); + + // Assert + Assert.Equal("WebApplication.Account.Manage", @namespace.Content); + Assert.Equal("AddUser_View", @class.Name); + } + + // This handles an error case where we can't determine the relationship between the + // imports and the source. + [Fact] + public void Pass_SetsNamespaceButNotClassName_VerbatimFromImports() + { + // Arrange + var builder = RazorIRBuilder.Document(); + + builder.Push(new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan(null, 0, 0, 0, 0), + }); + builder.Add(new DirectiveTokenIRNode() { Content = "WebApplication.Account" }); + builder.Pop(); + + var @namespace = new NamespaceDeclarationIRNode() { Content = "default" }; + builder.Push(@namespace); + + var @class = new ClassDeclarationIRNode() { Name = "default" }; + builder.Add(@class); + + var irDocument = (DocumentIRNode)builder.Build(); + irDocument.DocumentKind = RazorPageDocumentClassifierPass.RazorPageDocumentKind; + + var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage/AddUser.cshtml")); + + var pass = new NamespaceDirective.Pass(); + pass.Engine = RazorEngine.CreateEmpty(b => { }); + + // Act + pass.Execute(codeDocument, irDocument); + + // Assert + Assert.Equal("WebApplication.Account", @namespace.Content); + Assert.Equal("default", @class.Name); + } + + [Fact] + public void Pass_DoesNothing_ForUnknownDocumentKind() + { + // Arrange + var builder = RazorIRBuilder.Document(); + + builder.Push(new DirectiveIRNode() + { + Descriptor = NamespaceDirective.Directive, + Source = new SourceSpan(null, 0, 0, 0, 0), + }); + builder.Add(new DirectiveTokenIRNode() { Content = "WebApplication.Account" }); + builder.Pop(); + + var @namespace = new NamespaceDeclarationIRNode() { Content = "default" }; + builder.Push(@namespace); + + var @class = new ClassDeclarationIRNode() { Name = "default" }; + builder.Add(@class); + + var irDocument = (DocumentIRNode)builder.Build(); + irDocument.DocumentKind = null; + + var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage/AddUser.cshtml")); + + var pass = new NamespaceDirective.Pass(); + pass.Engine = RazorEngine.CreateEmpty(b => { }); + + // Act + pass.Execute(codeDocument, irDocument); + + // Assert + Assert.Equal("default", @namespace.Content); + Assert.Equal("default", @class.Name); + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace.cshtml b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace.cshtml new file mode 100644 index 0000000000..ecee97de58 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace.cshtml @@ -0,0 +1,3 @@ +@page +@namespace Test.Namespace +

Hi There!

diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_DesignTime.codegen.cs new file mode 100644 index 0000000000..c8ba2ad454 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_DesignTime.codegen.cs @@ -0,0 +1,41 @@ +namespace Test.Namespace +{ + #line hidden + using TModel = PageWithNamespace_Page; + using System; + using System.Threading.Tasks; + using System.Linq; + using System.Collections.Generic; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class PageWithNamespace_Page : global::Microsoft.AspNetCore.Mvc.RazorPages.Page + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + ((System.Action)(() => { +global::System.Object __typeHelper = nameof(Test.Namespace); + } + ))(); + } + #pragma warning restore 219 + private static System.Object __o = null; + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + } + #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; + public PageWithNamespace_Page Model => ViewData.Model; + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_DesignTime.ir.txt new file mode 100644 index 0000000000..7007509973 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_DesignTime.ir.txt @@ -0,0 +1,52 @@ +Document - + Checksum - + NamespaceDeclaration - - Test.Namespace + UsingStatement - - TModel = PageWithNamespace_Page + UsingStatement - (1:0,1 [12] ) - System + UsingStatement - - System.Threading.Tasks + UsingStatement - (16:1,1 [17] ) - System.Linq + UsingStatement - (36:2,1 [32] ) - System.Collections.Generic + UsingStatement - (71:3,1 [30] ) - Microsoft.AspNetCore.Mvc + UsingStatement - (104:4,1 [40] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingStatement - (147:5,1 [43] ) - Microsoft.AspNetCore.Mvc.ViewFeatures + ClassDeclaration - - public - PageWithNamespace_Page - global::Microsoft.AspNetCore.Mvc.RazorPages.Page - + DirectiveTokenHelper - + CSharpStatement - + RazorIRToken - - CSharp - #pragma warning disable 219 + CSharpStatement - + RazorIRToken - - CSharp - private void __RazorDirectiveTokenHelpers__() { + DirectiveToken - (200:6,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper + DirectiveToken - (263:6,71 [4] ) - Html + DirectiveToken - (277:7,8 [54] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper + DirectiveToken - (332:7,63 [4] ) - Json + DirectiveToken - (346:8,8 [53] ) - global::Microsoft.AspNetCore.Mvc.IViewComponentHelper + DirectiveToken - (400:8,62 [9] ) - Component + DirectiveToken - (419:9,8 [43] ) - global::Microsoft.AspNetCore.Mvc.IUrlHelper + DirectiveToken - (463:9,52 [3] ) - Url + DirectiveToken - (476:10,8 [70] ) - global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider + DirectiveToken - (547:10,79 [23] ) - ModelExpressionProvider + DirectiveToken - (586:11,14 [96] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (698:12,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (801:13,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (18:1,11 [14] PageWithNamespace.cshtml) - Test.Namespace + CSharpStatement - + RazorIRToken - - CSharp - } + CSharpStatement - + RazorIRToken - - CSharp - #pragma warning restore 219 + CSharpStatement - + RazorIRToken - - CSharp - private static System.Object __o = null; + RazorMethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + HtmlContent - (34:2,0 [20] PageWithNamespace.cshtml) + RazorIRToken - (34:2,0 [4] PageWithNamespace.cshtml) - Html -

+ RazorIRToken - (38:2,4 [9] PageWithNamespace.cshtml) - Html - Hi There! + RazorIRToken - (47:2,13 [5] PageWithNamespace.cshtml) - Html -

+ RazorIRToken - (52:2,18 [2] PageWithNamespace.cshtml) - Html - \n + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + CSharpStatement - + RazorIRToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; + CSharpStatement - + RazorIRToken - - CSharp - public PageWithNamespace_Page Model => ViewData.Model; diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_Runtime.codegen.cs new file mode 100644 index 0000000000..a8d2fad65c --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_Runtime.codegen.cs @@ -0,0 +1,35 @@ +#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "b205857d3dad47cb3f0c1d7775ae251b306ab830" +namespace Test.Namespace +{ + #line hidden + using System; + using System.Threading.Tasks; + using System.Linq; + using System.Collections.Generic; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class PageWithNamespace_Page : global::Microsoft.AspNetCore.Mvc.RazorPages.Page + { + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(34, 20, true); + WriteLiteral("

Hi There!

\r\n"); + EndContext(); + } + #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; + public PageWithNamespace_Page Model => ViewData.Model; + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_Runtime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_Runtime.ir.txt new file mode 100644 index 0000000000..512d0daa1e --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PageWithNamespace_Runtime.ir.txt @@ -0,0 +1,30 @@ +Document - + Checksum - + NamespaceDeclaration - - Test.Namespace + UsingStatement - (1:0,1 [14] ) - System + UsingStatement - - System.Threading.Tasks + UsingStatement - (16:1,1 [19] ) - System.Linq + UsingStatement - (36:2,1 [34] ) - System.Collections.Generic + UsingStatement - (71:3,1 [32] ) - Microsoft.AspNetCore.Mvc + UsingStatement - (104:4,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingStatement - (147:5,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures + ClassDeclaration - - public - PageWithNamespace_Page - global::Microsoft.AspNetCore.Mvc.RazorPages.Page - + RazorMethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + CSharpStatement - + RazorIRToken - - CSharp - BeginContext(34, 20, true); + HtmlContent - (34:2,0 [20] PageWithNamespace.cshtml) + RazorIRToken - (34:2,0 [4] PageWithNamespace.cshtml) - Html -

+ RazorIRToken - (38:2,4 [9] PageWithNamespace.cshtml) - Html - Hi There! + RazorIRToken - (47:2,13 [5] PageWithNamespace.cshtml) - Html -

+ RazorIRToken - (52:2,18 [2] PageWithNamespace.cshtml) - Html - \n + CSharpStatement - + RazorIRToken - - CSharp - EndContext(); + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + CSharpStatement - + RazorIRToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary)PageContext?.ViewData; + CSharpStatement - + RazorIRToken - - CSharp - public PageWithNamespace_Page Model => ViewData.Model; diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace.cshtml b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace.cshtml new file mode 100644 index 0000000000..eaf33e48ec --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace.cshtml @@ -0,0 +1,2 @@ +@namespace Test.Namespace +

Hi There!

diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_DesignTime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_DesignTime.codegen.cs new file mode 100644 index 0000000000..32ada4b8fd --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_DesignTime.codegen.cs @@ -0,0 +1,39 @@ +namespace Test.Namespace +{ + #line hidden + using TModel = global::System.Object; + using System; + using System.Threading.Tasks; + using System.Linq; + using System.Collections.Generic; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class ViewWithNamespace_View : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { + #pragma warning disable 219 + private void __RazorDirectiveTokenHelpers__() { + ((System.Action)(() => { +global::System.Object __typeHelper = nameof(Test.Namespace); + } + ))(); + } + #pragma warning restore 219 + private static System.Object __o = null; + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + } + #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_DesignTime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_DesignTime.ir.txt new file mode 100644 index 0000000000..e8cd81f770 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_DesignTime.ir.txt @@ -0,0 +1,48 @@ +Document - + Checksum - + NamespaceDeclaration - - Test.Namespace + UsingStatement - - TModel = global::System.Object + UsingStatement - (1:0,1 [12] ) - System + UsingStatement - - System.Threading.Tasks + UsingStatement - (16:1,1 [17] ) - System.Linq + UsingStatement - (36:2,1 [32] ) - System.Collections.Generic + UsingStatement - (71:3,1 [30] ) - Microsoft.AspNetCore.Mvc + UsingStatement - (104:4,1 [40] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingStatement - (147:5,1 [43] ) - Microsoft.AspNetCore.Mvc.ViewFeatures + ClassDeclaration - - public - ViewWithNamespace_View - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage - + DirectiveTokenHelper - + CSharpStatement - + RazorIRToken - - CSharp - #pragma warning disable 219 + CSharpStatement - + RazorIRToken - - CSharp - private void __RazorDirectiveTokenHelpers__() { + DirectiveToken - (200:6,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper + DirectiveToken - (263:6,71 [4] ) - Html + DirectiveToken - (277:7,8 [54] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper + DirectiveToken - (332:7,63 [4] ) - Json + DirectiveToken - (346:8,8 [53] ) - global::Microsoft.AspNetCore.Mvc.IViewComponentHelper + DirectiveToken - (400:8,62 [9] ) - Component + DirectiveToken - (419:9,8 [43] ) - global::Microsoft.AspNetCore.Mvc.IUrlHelper + DirectiveToken - (463:9,52 [3] ) - Url + DirectiveToken - (476:10,8 [70] ) - global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider + DirectiveToken - (547:10,79 [23] ) - ModelExpressionProvider + DirectiveToken - (586:11,14 [96] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (698:12,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (801:13,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor + DirectiveToken - (11:0,11 [14] ViewWithNamespace.cshtml) - Test.Namespace + CSharpStatement - + RazorIRToken - - CSharp - } + CSharpStatement - + RazorIRToken - - CSharp - #pragma warning restore 219 + CSharpStatement - + RazorIRToken - - CSharp - private static System.Object __o = null; + RazorMethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + HtmlContent - (27:1,0 [20] ViewWithNamespace.cshtml) + RazorIRToken - (27:1,0 [4] ViewWithNamespace.cshtml) - Html -

+ RazorIRToken - (31:1,4 [9] ViewWithNamespace.cshtml) - Html - Hi There! + RazorIRToken - (40:1,13 [5] ViewWithNamespace.cshtml) - Html -

+ RazorIRToken - (45:1,18 [2] ViewWithNamespace.cshtml) - Html - \n + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_Runtime.codegen.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_Runtime.codegen.cs new file mode 100644 index 0000000000..f467c598d1 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_Runtime.codegen.cs @@ -0,0 +1,33 @@ +#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "2893acf42354a0bc8b6a2698f5d2e4fab0e59dbe" +namespace Test.Namespace +{ + #line hidden + using System; + using System.Threading.Tasks; + using System.Linq; + using System.Collections.Generic; + using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; + using Microsoft.AspNetCore.Mvc.ViewFeatures; + public class ViewWithNamespace_View : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + { + #pragma warning disable 1998 + public async override global::System.Threading.Tasks.Task ExecuteAsync() + { + BeginContext(27, 20, true); + WriteLiteral("

Hi There!

\r\n"); + EndContext(); + } + #pragma warning restore 1998 + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } + [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] + public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_Runtime.ir.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_Runtime.ir.txt new file mode 100644 index 0000000000..60e9a65d25 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/ViewWithNamespace_Runtime.ir.txt @@ -0,0 +1,26 @@ +Document - + Checksum - + NamespaceDeclaration - - Test.Namespace + UsingStatement - (1:0,1 [14] ) - System + UsingStatement - - System.Threading.Tasks + UsingStatement - (16:1,1 [19] ) - System.Linq + UsingStatement - (36:2,1 [34] ) - System.Collections.Generic + UsingStatement - (71:3,1 [32] ) - Microsoft.AspNetCore.Mvc + UsingStatement - (104:4,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering + UsingStatement - (147:5,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures + ClassDeclaration - - public - ViewWithNamespace_View - global::Microsoft.AspNetCore.Mvc.Razor.RazorPage - + RazorMethodDeclaration - - public - async, override - global::System.Threading.Tasks.Task - ExecuteAsync + CSharpStatement - + RazorIRToken - - CSharp - BeginContext(27, 20, true); + HtmlContent - (27:1,0 [20] ViewWithNamespace.cshtml) + RazorIRToken - (27:1,0 [4] ViewWithNamespace.cshtml) - Html -

+ RazorIRToken - (31:1,4 [9] ViewWithNamespace.cshtml) - Html - Hi There! + RazorIRToken - (40:1,13 [5] ViewWithNamespace.cshtml) - Html -

+ RazorIRToken - (45:1,18 [2] ViewWithNamespace.cshtml) - Html - \n + CSharpStatement - + RazorIRToken - - CSharp - EndContext(); + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - + InjectDirective - diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs index 9bbe9030ff..e56b58b482 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/CSharpDirectivesTest.cs @@ -1017,6 +1017,39 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy .With(new DirectiveTokenChunkGenerator(descriptor.Tokens.First())))); } + [Fact] + public void Directives_CanUseReservedWord_Class() + { + // Arrange + var descriptor = DirectiveDescriptorBuilder.Create("class").Build(); + + // Act & Assert + ParseCodeBlockTest( + "@class", + new[] { descriptor }, + new DirectiveBlock( + new DirectiveChunkGenerator(descriptor), + Factory.CodeTransition(), + Factory.MetaCode("class").Accepts(AcceptedCharacters.None))); + } + + [Fact] + public void Directives_CanUseReservedWord_Namespace() + { + // Arrange + var descriptor = DirectiveDescriptorBuilder.Create("namespace").Build(); + + // Act & Assert + ParseCodeBlockTest( + "@namespace", + new[] { descriptor }, + new DirectiveBlock( + new DirectiveChunkGenerator(descriptor), + Factory.CodeTransition(), + Factory.MetaCode("namespace").Accepts(AcceptedCharacters.None))); + } + + internal virtual void ParseCodeBlockTest( string document, IEnumerable descriptors,