diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs index bc4c151380..a2f6c6cd7a 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorIRLoweringPhase.cs @@ -1,6 +1,8 @@ // 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.Collections.Generic; +using System.Linq; using Microsoft.AspNetCore.Razor.Evolution.Intermediate; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -11,7 +13,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution protected override void ExecuteCore(RazorCodeDocument codeDocument) { var syntaxTree = codeDocument.GetSyntaxTree(); - ThrowForMissingDependency(syntaxTree); + ThrowForMissingDependency(syntaxTree); var visitor = new Visitor(); @@ -23,80 +25,89 @@ namespace Microsoft.AspNetCore.Razor.Evolution private class Visitor : ParserVisitor { + private readonly Stack _builders; + public Visitor() { - Builder = RazorIRBuilder.Document(); + _builders = new Stack(); + var document = RazorIRBuilder.Document(); + _builders.Push(document); Namespace = new NamespaceDeclarationIRNode(); - NamespaceBuilder = RazorIRBuilder.Create(Namespace); Builder.Push(Namespace); Class = new ClassDeclarationIRNode(); - ClassBuilder = RazorIRBuilder.Create(Class); Builder.Push(Class); - Method = new MethodDeclarationIRNode(); + Method = new RazorMethodDeclarationIRNode(); Builder.Push(Method); } - public RazorIRBuilder Builder { get; } + public RazorIRBuilder Builder => _builders.Peek(); public NamespaceDeclarationIRNode Namespace { get; } - public RazorIRBuilder NamespaceBuilder { get; } - public ClassDeclarationIRNode Class { get; } - public RazorIRBuilder ClassBuilder { get; } + public RazorMethodDeclarationIRNode Method { get; } - public MethodDeclarationIRNode Method { get; } - - public override void VisitStartAttributeBlock(AttributeBlockChunkGenerator chunk, Block block) + public override void VisitStartAttributeBlock(AttributeBlockChunkGenerator chunkGenerator, Block block) { - Builder.Push(new HtmlAttributeIRNode() + var value = new ContainerRazorIRNode(); + Builder.Add(new HtmlAttributeIRNode() { - Name = chunk.Name, - Prefix = chunk.Prefix, - Suffix = chunk.Prefix, + Name = chunkGenerator.Name, + Prefix = chunkGenerator.Prefix, + Value = value, + Suffix = chunkGenerator.Suffix, SourceLocation = block.Start, }); + + var valueBuilder = RazorIRBuilder.Create(value); + _builders.Push(valueBuilder); } - public override void VisitEndAttributeBlock(AttributeBlockChunkGenerator chunk, Block block) + public override void VisitEndAttributeBlock(AttributeBlockChunkGenerator chunkGenerator, Block block) { - Builder.Pop(); + _builders.Pop(); } - public override void VisitStartDynamicAttributeBlock(DynamicAttributeBlockChunkGenerator chunk, Block block) + public override void VisitStartDynamicAttributeBlock(DynamicAttributeBlockChunkGenerator chunkGenerator, Block block) { - Builder.Push(new CSharpAttributeValueIRNode() + var content = new ContainerRazorIRNode(); + Builder.Add(new CSharpAttributeValueIRNode() { - Prefix = chunk.Prefix, + Prefix = chunkGenerator.Prefix, + Content = content, SourceLocation = block.Start, }); + + var valueBuilder = RazorIRBuilder.Create(content); + _builders.Push(valueBuilder); } - public override void VisitEndDynamicAttributeBlock(DynamicAttributeBlockChunkGenerator chunk, Block block) + public override void VisitEndDynamicAttributeBlock(DynamicAttributeBlockChunkGenerator chunkGenerator, Block block) { - Builder.Pop(); + _builders.Pop(); } - public override void VisitLiteralAttributeSpan(LiteralAttributeChunkGenerator chunk, Span span) + public override void VisitLiteralAttributeSpan(LiteralAttributeChunkGenerator chunkGenerator, Span span) { Builder.Add(new HtmlAttributeValueIRNode() { - Prefix = chunk.Prefix, + Prefix = chunkGenerator.Prefix, + Content = chunkGenerator.Value, SourceLocation = span.Start, }); } - public override void VisitStartTemplateBlock(TemplateBlockChunkGenerator chunk, Block block) + public override void VisitStartTemplateBlock(TemplateBlockChunkGenerator chunkGenerator, Block block) { Builder.Push(new TemplateIRNode()); } - public override void VisitEndTemplateBlock(TemplateBlockChunkGenerator chunk, Block block) + public override void VisitEndTemplateBlock(TemplateBlockChunkGenerator chunkGenerator, Block block) { Builder.Pop(); } @@ -107,20 +118,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution // @DateTime.@*This is a comment*@Now // // We need to capture this in the IR so that we can give each piece the correct source mappings - public override void VisitStartExpressionBlock(ExpressionChunkGenerator chunk, Block block) + public override void VisitStartExpressionBlock(ExpressionChunkGenerator chunkGenerator, Block block) { - Builder.Push(new CSharpExpressionIRNode() + var value = new ContainerRazorIRNode(); + Builder.Add(new CSharpExpressionIRNode() { + Content = value, SourceLocation = block.Start, }); + + var valueBuilder = RazorIRBuilder.Create(value); + _builders.Push(valueBuilder); } - public override void VisitEndExpressionBlock(ExpressionChunkGenerator chunk, Block block) + public override void VisitEndExpressionBlock(ExpressionChunkGenerator chunkGenerator, Block block) { - Builder.Pop(); + _builders.Pop(); } - public override void VisitExpressionSpan(ExpressionChunkGenerator chunk, Span span) + public override void VisitExpressionSpan(ExpressionChunkGenerator chunkGenerator, Span span) { Builder.Add(new CSharpTokenIRNode() { @@ -129,44 +145,19 @@ namespace Microsoft.AspNetCore.Razor.Evolution }); } - public override void VisitStartSectionBlock(SectionChunkGenerator chunk, Block block) + public override void VisitTypeMemberSpan(TypeMemberChunkGenerator chunkGenerator, Span span) { - Builder.Push(new SectionIRNode() - { - Name = chunk.SectionName, - }); - } - - public override void VisitEndSectionBlock(SectionChunkGenerator chunk, Block block) - { - Builder.Pop(); - } - - public override void VisitTypeMemberSpan(TypeMemberChunkGenerator chunk, Span span) - { - ClassBuilder.Add(new CSharpStatementIRNode() + var functionsNode = new CSharpStatementIRNode() { Content = span.Content, SourceLocation = span.Start, - }); + Parent = Class, + }; + + Class.Children.Add(functionsNode); } - public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunk, Span span) - { - // Empty for now - } - - public override void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunk, Span span) - { - // Empty for now - } - - public override void VisitTagHelperPrefixSpan(TagHelperPrefixDirectiveChunkGenerator chunk, Span span) - { - // Empty for now - } - - public override void VisitStatementSpan(StatementChunkGenerator chunk, Span span) + public override void VisitStatementSpan(StatementChunkGenerator chunkGenerator, Span span) { Builder.Add(new CSharpStatementIRNode() { @@ -175,21 +166,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution }); } - public override void VisitSetBaseTypeSpan(SetBaseTypeChunkGenerator chunk, Span span) + public override void VisitMarkupSpan(MarkupChunkGenerator chunkGenerator, Span span) { - Class.BaseType = span.Content; - } - - public override void VisitMarkupSpan(MarkupChunkGenerator chunk, Span span) - { - Builder.Add(new HtmlContentIRNode() + var currentChildren = Builder.Current.Children; + if (currentChildren.Count > 0 && currentChildren[currentChildren.Count - 1] is HtmlContentIRNode) { - Content = span.Content, - SourceLocation = span.Start, - }); + var existingHtmlContent = (HtmlContentIRNode)currentChildren[currentChildren.Count - 1]; + existingHtmlContent.Content = string.Concat(existingHtmlContent.Content, span.Content); + } + else + { + Builder.Add(new HtmlContentIRNode() + { + Content = span.Content, + SourceLocation = span.Start, + }); + } } - public override void VisitImportSpan(AddImportChunkGenerator chunk, Span span) + public override void VisitImportSpan(AddImportChunkGenerator chunkGenerator, Span span) { // For prettiness, let's insert the usings before the class declaration. var i = 0; @@ -210,6 +205,47 @@ namespace Microsoft.AspNetCore.Razor.Evolution Namespace.Children.Insert(i, @using); } + + private class ContainerRazorIRNode : RazorIRNode + { + private SourceLocation? _location; + + public override IList Children { get; } = new List(); + + public override RazorIRNode Parent { get; set; } + + internal override SourceLocation SourceLocation + { + get + { + if (_location == null) + { + if (Children.Count > 0) + { + return Children[0].SourceLocation; + } + + return SourceLocation.Undefined; + } + + return _location.Value; + } + set + { + _location = value; + } + } + + public override void Accept(RazorIRNodeVisitor visitor) + { + visitor.VisitDefault(this); + } + + public override TResult Accept(RazorIRNodeVisitor visitor) + { + return visitor.VisitDefault(this); + } + } } } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/BlockDirectiveIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/BlockDirectiveIRNode.cs deleted file mode 100644 index 6c09834b53..0000000000 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/BlockDirectiveIRNode.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Razor.Evolution.Legacy; - -namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate -{ - public class BlockDirectiveIRNode : RazorIRNode - { - public string Name { get; set; } - - public override IList Children { get; } = new List(); - - public override RazorIRNode Parent { get; set; } - - internal override SourceLocation SourceLocation { get; set; } - - public override void Accept(RazorIRNodeVisitor visitor) - { - visitor.VisitBlockDirective(this); - } - - public override TResult Accept(RazorIRNodeVisitor visitor) - { - return visitor.VisitBlockDirective(this); - } - } -} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpAttributeValueIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpAttributeValueIRNode.cs index c3dfa34e5e..a588c54ad0 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpAttributeValueIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpAttributeValueIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -8,21 +9,33 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { public class CSharpAttributeValueIRNode : RazorIRNode { - public string Prefix { get; set; } - - public override IList Children { get; } = new List(); + public override IList Children { get; } = EmptyArray; public override RazorIRNode Parent { get; set; } internal override SourceLocation SourceLocation { get; set; } + public string Prefix { get; set; } + + public RazorIRNode Content { get; set; } + public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitCSharpAttributeValue(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitCSharpAttributeValue(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpExpressionIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpExpressionIRNode.cs index 6b669cb2b3..a90d45b73a 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpExpressionIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpExpressionIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -8,21 +9,31 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { public class CSharpExpressionIRNode : RazorIRNode { - public override IList Children { get; } = new List(); + public override IList Children { get; } = EmptyArray; public override RazorIRNode Parent { get; set; } internal override SourceLocation SourceLocation { get; set; } - public string Content { get; set; } + public RazorIRNode Content { get; set; } public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitCSharpExpression(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitCSharpExpression(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpStatementIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpStatementIRNode.cs index 684f87005b..40fc25e690 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpStatementIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpStatementIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -8,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { public class CSharpStatementIRNode : RazorIRNode { - public override IList Children { get; } = new List(); + public override IList Children { get; } = EmptyArray; public override RazorIRNode Parent { get; set; } @@ -18,11 +19,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitCSharpStatement(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitCSharpStatement(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpTokenIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpTokenIRNode.cs index 1c823e02b0..0d0406de6e 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpTokenIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/CSharpTokenIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -18,11 +19,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitCSharpToken(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitCSharpToken(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/ClassDeclarationIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/ClassDeclarationIRNode.cs index bb57f0829f..e902838955 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/ClassDeclarationIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/ClassDeclarationIRNode.cs @@ -9,6 +9,12 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { public class ClassDeclarationIRNode : RazorIRNode { + public override IList Children { get; } = new List(); + + public override RazorIRNode Parent { get; set; } + + internal override SourceLocation SourceLocation { get; set; } + public string AccessModifier { get; set; } public string Name { get; set; } @@ -17,19 +23,23 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate public IList Interfaces { get; set; } - public override IList Children { get; } = new List(); - - public override RazorIRNode Parent { get; set; } - - internal override SourceLocation SourceLocation { get; set; } - public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitClass(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitClass(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DefaultRazorIRBuilder.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DefaultRazorIRBuilder.cs index 0a0e16d550..05a8f332cd 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DefaultRazorIRBuilder.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DefaultRazorIRBuilder.cs @@ -42,10 +42,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { node = Pop(); } - + return node; } - + public override RazorIRNode Pop() { if (_depth == 0) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DirectiveTokenIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DirectiveTokenIRNode.cs deleted file mode 100644 index ff1988e871..0000000000 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DirectiveTokenIRNode.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Razor.Evolution.Legacy; - -namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate -{ - public class DirectiveTokenIRNode : RazorIRNode - { - public override IList Children { get; } = new List(); - - public override RazorIRNode Parent { get; set; } - - internal override SourceLocation SourceLocation { get; set; } - - public override void Accept(RazorIRNodeVisitor visitor) - { - visitor.VisitDirectiveToken(this); - } - - public override TResult Accept(RazorIRNodeVisitor visitor) - { - return visitor.VisitDirectiveToken(this); - } - } -} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DocumentIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DocumentIRNode.cs index 41f07531fc..cc0e01f8ff 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DocumentIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/DocumentIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -16,11 +17,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitDocument(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitDocument(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlAttributeIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlAttributeIRNode.cs index 02ef2b96bd..0b0ce8e22a 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlAttributeIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlAttributeIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -8,25 +9,37 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { public class HtmlAttributeIRNode : RazorIRNode { - public string Name { get; set; } - - public string Prefix { get; set; } - - public string Suffix { get; set; } - - public override IList Children { get; } = new List(); + public override IList Children { get; } = EmptyArray; public override RazorIRNode Parent { get; set; } internal override SourceLocation SourceLocation { get; set; } + public string Name { get; set; } + + public string Prefix { get; set; } + + public RazorIRNode Value { get; set; } + + public string Suffix { get; set; } + public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitHtmlAttribute(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitHtmlAttribute(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlAttributeValueIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlAttributeValueIRNode.cs index 23657f751d..15e845fb33 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlAttributeValueIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlAttributeValueIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -8,21 +9,33 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { public class HtmlAttributeValueIRNode : RazorIRNode { - public string Prefix { get; set; } - - public override IList Children { get; } = new List(); + public override IList Children { get; } = EmptyArray; public override RazorIRNode Parent { get; set; } internal override SourceLocation SourceLocation { get; set; } + public string Prefix { get; set; } + + public string Content { get; set; } + public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitHtmlAttributeValue(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitHtmlAttributeValue(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlContentIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlContentIRNode.cs index b58cd71362..7744f9c522 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlContentIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/HtmlContentIRNode.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { public string Content { get; set; } - public override IList Children { get; } = new List(); + public override IList Children { get; } = EmptyArray; public override RazorIRNode Parent { get; set; } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/NamespaceDeclarationIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/NamespaceDeclarationIRNode.cs index 7c869c3558..30d9eb3950 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/NamespaceDeclarationIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/NamespaceDeclarationIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -14,13 +15,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate internal override SourceLocation SourceLocation { get; set; } + public string Content { get; set; } + public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitNamespace(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitNamespace(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorIRNodeVisitor.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorIRNodeVisitor.cs index 6e45ed1eb0..d96ca11d5e 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorIRNodeVisitor.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorIRNodeVisitor.cs @@ -3,7 +3,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { - public abstract class RazorIRNodeVisitor + public abstract class RazorIRNodeVisitor { public virtual void Visit(RazorIRNode node) { @@ -14,21 +14,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { } - public virtual void VisitDirectiveToken(DirectiveTokenIRNode node) - { - VisitDefault(node); - } - public virtual void VisitTemplate(TemplateIRNode node) { VisitDefault(node); } - public virtual void VisitSection(SectionIRNode node) - { - VisitDefault(node); - } - public virtual void VisitCSharpStatement(CSharpStatementIRNode node) { VisitDefault(node); @@ -59,22 +49,12 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate VisitDefault(node); } - public virtual void VisitSingleLineDirective(SingleLineDirectiveIRNode node) - { - VisitDefault(node); - } - - public virtual void VisitBlockDirective(BlockDirectiveIRNode node) - { - VisitDefault(node); - } - public virtual void VisitClass(ClassDeclarationIRNode node) { VisitDefault(node); } - public virtual void VisitMethodDeclaration(MethodDeclarationIRNode node) + public virtual void VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node) { VisitDefault(node); } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorIRNodeVisitorOfT.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorIRNodeVisitorOfT.cs index b8ad7ad7ae..a02e0e11bd 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorIRNodeVisitorOfT.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorIRNodeVisitorOfT.cs @@ -15,21 +15,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate return default(TResult); } - public virtual TResult VisitDirectiveToken(DirectiveTokenIRNode node) - { - return VisitDefault(node); - } - public virtual TResult VisitTemplate(TemplateIRNode node) { return VisitDefault(node); } - public virtual TResult VisitSection(SectionIRNode node) - { - return VisitDefault(node); - } - public virtual TResult VisitCSharpStatement(CSharpStatementIRNode node) { return VisitDefault(node); @@ -65,16 +55,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate return VisitDefault(node); } - public virtual TResult VisitSingleLineDirective(SingleLineDirectiveIRNode node) - { - return VisitDefault(node); - } - - public virtual TResult VisitBlockDirective(BlockDirectiveIRNode node) - { - return VisitDefault(node); - } - public virtual TResult VisitMethodDeclaration(MethodDeclarationIRNode node) + public virtual TResult VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node) { return VisitDefault(node); } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/MethodDeclarationIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorMethodDeclarationIRNode.cs similarity index 67% rename from src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/MethodDeclarationIRNode.cs rename to src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorMethodDeclarationIRNode.cs index 38ca704ee9..9953efde30 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/MethodDeclarationIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/RazorMethodDeclarationIRNode.cs @@ -1,13 +1,20 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { - public class MethodDeclarationIRNode : RazorIRNode + public class RazorMethodDeclarationIRNode : RazorIRNode { + public override IList Children { get; } = new List(); + + public override RazorIRNode Parent { get; set; } + + internal override SourceLocation SourceLocation { get; set; } + public string AccessModifier { get; set; } public IList Modifiers { get; set; } @@ -16,20 +23,24 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate public string ReturnType { get; set; } - public override IList Children { get; } = new List(); - - public override RazorIRNode Parent { get; set; } - - internal override SourceLocation SourceLocation { get; set; } - public override void Accept(RazorIRNodeVisitor visitor) { - visitor.VisitMethodDeclaration(this); + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + + visitor.VisitRazorMethodDeclaration(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { - return visitor.VisitMethodDeclaration(this); + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + + return visitor.VisitRazorMethodDeclaration(this); } } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/SectionIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/SectionIRNode.cs deleted file mode 100644 index 9d6dba5f3e..0000000000 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/SectionIRNode.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Razor.Evolution.Legacy; - -namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate -{ - public class SectionIRNode : RazorIRNode - { - public string Name { get; set; } - - public override IList Children { get; } = new List(); - - public override RazorIRNode Parent { get; set; } - - internal override SourceLocation SourceLocation { get; set; } - - public override void Accept(RazorIRNodeVisitor visitor) - { - visitor.VisitSection(this); - } - - public override TResult Accept(RazorIRNodeVisitor visitor) - { - return visitor.VisitSection(this); - } - } -} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/SingleLineDirectiveIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/SingleLineDirectiveIRNode.cs deleted file mode 100644 index a599056b95..0000000000 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/SingleLineDirectiveIRNode.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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.Collections.Generic; -using Microsoft.AspNetCore.Razor.Evolution.Legacy; - -namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate -{ - public class SingleLineDirectiveIRNode : RazorIRNode - { - public string Name { get; set; } - - public override IList Children { get; } = new List(); - - public override RazorIRNode Parent { get; set; } - - internal override SourceLocation SourceLocation { get; set; } - - public override void Accept(RazorIRNodeVisitor visitor) - { - visitor.VisitSingleLineDirective(this); - } - - public override TResult Accept(RazorIRNodeVisitor visitor) - { - return visitor.VisitSingleLineDirective(this); - } - } -} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/TemplateIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/TemplateIRNode.cs index b1cb73ff54..77c1354726 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/TemplateIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/TemplateIRNode.cs @@ -1,6 +1,7 @@ // 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.Collections.Generic; using Microsoft.AspNetCore.Razor.Evolution.Legacy; @@ -16,11 +17,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate public override void Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + visitor.VisitTemplate(this); } public override TResult Accept(RazorIRNodeVisitor visitor) { + if (visitor == null) + { + throw new ArgumentNullException(nameof(visitor)); + } + return visitor.VisitTemplate(this); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/UsingStatementIRNode.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/UsingStatementIRNode.cs index 57cecee3b9..3236f3de9f 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/UsingStatementIRNode.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Intermediate/UsingStatementIRNode.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { public class UsingStatementIRNode : RazorIRNode { - public override IList Children { get; } = new List(); + public override IList Children { get; } = EmptyArray; public override RazorIRNode Parent { get; set; } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/AddTagHelperChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/AddTagHelperChunkGenerator.cs index ca4e2d449f..28f4b9337e 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/AddTagHelperChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/AddTagHelperChunkGenerator.cs @@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public override void Accept(ParserVisitor visitor, Span span) { - visitor.VisitAddTagHelperSpan(this, span); } public override void GenerateChunk(Span target, ChunkGeneratorContext context) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/ParserVisitor.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/ParserVisitor.cs index f8df1b37a5..190a8f2911 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/ParserVisitor.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/ParserVisitor.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public virtual void VisitBlock(Block block) { VisitStartBlock(block); - + for (var i = 0; i < block.Children.Count; i++) { block.Children[i].Accept(this); @@ -69,14 +69,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { } - public virtual void VisitSetBaseTypeSpan(SetBaseTypeChunkGenerator chunk, Span span) - { - } - - public virtual void VisitTagHelperPrefixSpan(TagHelperPrefixDirectiveChunkGenerator chunk, Span span) - { - } - public virtual void VisitTypeMemberSpan(TypeMemberChunkGenerator chunk, Span span) { } @@ -85,18 +77,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { } - public virtual void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunk, Span span) - { - } - public virtual void VisitImportSpan(AddImportChunkGenerator chunk, Span span) { } - public virtual void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunk, Span span) - { - } - public virtual void VisitStatementSpan(StatementChunkGenerator chunk, Span span) { } @@ -113,14 +97,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { } - public virtual void VisitStartSectionBlock(SectionChunkGenerator chunk, Block block) - { - } - - public virtual void VisitEndSectionBlock(SectionChunkGenerator chunk, Block block) - { - } - public virtual void VisitEndCommentBlock(RazorCommentChunkGenerator chunk, Block block) { } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RemoveTagHelperChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RemoveTagHelperChunkGenerator.cs index 6b6506dcfa..4b1341b565 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RemoveTagHelperChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RemoveTagHelperChunkGenerator.cs @@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public override void Accept(ParserVisitor visitor, Span span) { - visitor.VisitRemoveTagHelperSpan(this, span); } public override void GenerateChunk(Span target, ChunkGeneratorContext context) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SectionChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SectionChunkGenerator.cs index cf28e8e704..5f6cb83527 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SectionChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SectionChunkGenerator.cs @@ -16,12 +16,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public override void AcceptStart(ParserVisitor visitor, Block block) { - visitor.VisitStartSectionBlock(this, block); } public override void AcceptEnd(ParserVisitor visitor, Block block) { - visitor.VisitEndSectionBlock(this, block); } public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SetBaseTypeChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SetBaseTypeChunkGenerator.cs index 27015a36a8..3aca881a08 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SetBaseTypeChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SetBaseTypeChunkGenerator.cs @@ -16,7 +16,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public override void Accept(ParserVisitor visitor, Span span) { - visitor.VisitSetBaseTypeSpan(this, span); } public override void GenerateChunk(Span target, ChunkGeneratorContext context) diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperChunkGenerator.cs index ae1bb1aa9e..56cd2713bc 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperChunkGenerator.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { @@ -85,5 +83,13 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { //context.ChunkTreeBuilder.EndParentChunk(); } + + public override void AcceptStart(ParserVisitor visitor, Block block) + { + } + + public override void AcceptEnd(ParserVisitor visitor, Block block) + { + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperPrefixDirectiveChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperPrefixDirectiveChunkGenerator.cs index 401873213f..26b750e71b 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperPrefixDirectiveChunkGenerator.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperPrefixDirectiveChunkGenerator.cs @@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public override void Accept(ParserVisitor visitor, Span span) { - visitor.VisitTagHelperPrefixSpan(this, span); } public override void GenerateChunk(Span target, ChunkGeneratorContext context) diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/DefaultRazorIRLoweringPhaseIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/DefaultRazorIRLoweringPhaseIntegrationTest.cs index 93540a2e52..9928f8b993 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/DefaultRazorIRLoweringPhaseIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/DefaultRazorIRLoweringPhaseIntegrationTest.cs @@ -7,18 +7,21 @@ using System; namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { - public class LoweringIntegrationTest + public class DefaultRazorIRLoweringPhaseIntegrationTest { [Fact] public void Lower_EmptyDocument() { + // Arrange var codeDocument = TestRazorCodeDocument.CreateEmpty(); + // Act var irDocument = Lower(codeDocument); + // Assert var @namespace = SingleChild(irDocument); var @class = SingleChild(@namespace); - var method = SingleChild(@class); + var method = SingleChild(@class); var html = SingleChild(method); Assert.Equal(string.Empty, html.Content); @@ -27,68 +30,118 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate [Fact] public void Lower_HelloWorld() { + // Arrange var codeDocument = TestRazorCodeDocument.Create("Hello, World!"); + // Act var irDocument = Lower(codeDocument); + // Assert var @namespace = SingleChild(irDocument); var @class = SingleChild(@namespace); - var method = SingleChild(@class); + var method = SingleChild(@class); var html = SingleChild(method); Assert.Equal("Hello, World!", html.Content); } [Fact] - public void Lower_HtmlWithAttributes() + public void Lower_HtmlWithDataDashAttributes() { + // Arrange var codeDocument = TestRazorCodeDocument.Create(@" "); + + // Act var irDocument = Lower(codeDocument); - + + // Assert var @namespace = SingleChild(irDocument); var @class = SingleChild(@namespace); - var method = SingleChild(@class); + var method = SingleChild(@class); Children(method, - n => Html(Environment.NewLine, n), - n => Html("", n), - n => Html(Environment.NewLine + " ", n), - n => Html("", n), - n => Html(Environment.NewLine + " ", n), - n => Html(" Html(" data-val=\"", n), + n => Html( +@" + + + CSharpExpression("Hello", n), - n => Html("\"", n), - n => Html(" />", n), - n => Html(Environment.NewLine + " ", n), - n => Html("", n), - n => Html(Environment.NewLine, n), - n => Html("", n)); + n => Html(@""" /> + +", n)); + } + + [Fact] + public void Lower_HtmlWithConditionalAttributes() + { + // Arrange + var codeDocument = TestRazorCodeDocument.Create(@" + + + + +"); + + // Act + var irDocument = Lower(codeDocument); + + // Assert + var @namespace = SingleChild(irDocument); + var @class = SingleChild(@namespace); + var method = SingleChild(@class); + Children(method, + n => Html( +@" + + + ConditionalAttribute( + prefix: " val=\"", + name: "val", + suffix: "\"", + node: n, + valueValidators: new Action[] + { + value => CSharpAttributeValue(string.Empty, "Hello", value), + value => LiteralAttributeValue(" ", "World", value) + }), + n => Html(@" /> + +", n)); } [Fact] public void Lower_WithUsing() { + // Arrange var codeDocument = TestRazorCodeDocument.Create(@"@functions { public int Foo { get; set; }}"); + + // Act var irDocument = Lower(codeDocument); + // Assert var @namespace = SingleChild(irDocument); var @class = SingleChild(@namespace); Children(@class, - n => Assert.IsType(n), + n => Assert.IsType(n), n => Assert.IsType(n)); } [Fact] public void Lower_WithFunctions() { + // Arrange var codeDocument = TestRazorCodeDocument.Create(@"@using System"); + + // Act var irDocument = Lower(codeDocument); + // Assert var @namespace = SingleChild(irDocument); Children(@namespace, n => Using("using System", n), diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/RazorIRAssert.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/RazorIRAssert.cs index ef03f94933..3c3574177e 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/RazorIRAssert.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Intermediate/RazorIRAssert.cs @@ -86,6 +86,60 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate } } + public static void ConditionalAttribute( + string prefix, + string name, + string suffix, + RazorIRNode node, + params Action[] valueValidators) + { + var attribute = Assert.IsType(node); + + try + { + Assert.Equal(prefix, attribute.Prefix); + Assert.Equal(name, attribute.Name); + Assert.Equal(suffix, attribute.Suffix); + + Children(attribute.Value, valueValidators); + } + catch (XunitException e) + { + throw new IRAssertException(attribute, attribute.Value.Children, e.Message, e); + } + } + + public static void CSharpAttributeValue(string prefix, string expected, RazorIRNode node) + { + var attributeValue = Assert.IsType(node); + + try + { + Assert.Equal(prefix, attributeValue.Prefix); + + Children(attributeValue.Content, n => CSharpExpression(expected, n)); + } + catch (XunitException e) + { + throw new IRAssertException(attributeValue, attributeValue.Content.Children, e.Message, e); + } + } + + public static void LiteralAttributeValue(string prefix, string expected, RazorIRNode node) + { + var attributeValue = Assert.IsType(node); + + try + { + Assert.Equal(prefix, attributeValue.Prefix); + Assert.Equal(expected, attributeValue.Content); + } + catch (XunitException e) + { + throw new IRAssertException(attributeValue, e.Message); + } + } + public static void CSharpExpression(string expected, RazorIRNode node) { try @@ -93,9 +147,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate var cSharp = Assert.IsType(node); var content = new StringBuilder(); - for (var i = 0; i < cSharp.Children.Count; i++) + for (var i = 0; i < cSharp.Content.Children.Count; i++) { - content.Append(((CSharpTokenIRNode)cSharp.Children[i]).Content); + content.Append(((CSharpTokenIRNode)cSharp.Content.Children[i]).Content); } Assert.Equal(expected, content.ToString()); @@ -108,7 +162,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate private class IRAssertException : XunitException { - public IRAssertException(RazorIRNode node, string userMessage) + public IRAssertException(RazorIRNode node, string userMessage) : base(Format(node, null, userMessage)) { Node = node; @@ -119,7 +173,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate { Node = node; Nodes = nodes; - } + } public IRAssertException( RazorIRNode node,