diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperParseTreeRewriterTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperParseTreeRewriterTest.cs index bb03a301559..e98e1346a2a 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperParseTreeRewriterTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/legacyTest/Legacy/TagHelperParseTreeRewriterTest.cs @@ -59,7 +59,7 @@ public void GetAttributeNameValuePairs_ParsesPairsCorrectly( Assert.Empty(errorSink.GetErrorsAndClear()); // Act - var pairs = TagHelperParseTreeRewriter.Rewriter.GetAttributeNameValuePairs(element.StartTag); + var pairs = TagHelperParseTreeRewriter.Rewriter.GetAttributeNameValuePairs(element.MarkupStartTag); // Assert Assert.Equal(expectedPairs, pairs); diff --git a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperParseTreeRewriterTest.cs b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperParseTreeRewriterTest.cs index 5047a11285b..f8c7e58a4aa 100644 --- a/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperParseTreeRewriterTest.cs +++ b/src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Legacy/TagHelperParseTreeRewriterTest.cs @@ -59,7 +59,7 @@ public void GetAttributeNameValuePairs_ParsesPairsCorrectly( Assert.Empty(errorSink.GetErrorsAndClear()); // Act - var pairs = TagHelperParseTreeRewriter.Rewriter.GetAttributeNameValuePairs(element.StartTag); + var pairs = TagHelperParseTreeRewriter.Rewriter.GetAttributeNameValuePairs(element.MarkupStartTag); // Assert Assert.Equal(expectedPairs, pairs); diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorIntermediateNodeLoweringPhase.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorIntermediateNodeLoweringPhase.cs index 34dec6e2cde..5a89872d3a3 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorIntermediateNodeLoweringPhase.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/DefaultRazorIntermediateNodeLoweringPhase.cs @@ -1300,8 +1300,8 @@ public override void DefaultVisit(SyntaxNode node) public override void VisitMarkupElement(MarkupElementSyntax node) { - if ((node.StartTag != null && node.StartTag.IsMarkupTransition) || - (node.EndTag != null && node.EndTag.IsMarkupTransition)) + if ((node.MarkupStartTag != null && node.MarkupStartTag.IsMarkupTransition) || + (node.MarkupEndTag != null && node.MarkupEndTag.IsMarkupTransition)) { // We don't want to create a node for Markup transitions (). Treat their contents as regular markup. // Technically there shouldn't be an end transition without a start transition but just being defensive. @@ -1317,33 +1317,33 @@ public override void VisitMarkupElement(MarkupElementSyntax node) TagName = node.StartTag?.Name.Content ?? node.EndTag?.Name.Content ?? string.Empty, }; - if (node.StartTag != null && node.EndTag != null && node.StartTag.IsVoidElement()) + if (node.MarkupStartTag != null && node.MarkupEndTag != null && node.MarkupStartTag.IsVoidElement()) { element.AddDiagnostic( ComponentDiagnosticFactory.Create_UnexpectedClosingTagForVoidElement( - BuildSourceSpanFromNode(node.EndTag), node.EndTag.GetTagNameWithOptionalBang())); + BuildSourceSpanFromNode(node.MarkupEndTag), node.MarkupEndTag.GetTagNameWithOptionalBang())); } - else if (node.StartTag != null && node.EndTag == null && !node.StartTag.IsVoidElement() && !node.StartTag.IsSelfClosing()) + else if (node.MarkupStartTag != null && node.MarkupEndTag == null && !node.MarkupStartTag.IsVoidElement() && !node.MarkupStartTag.IsSelfClosing()) { element.AddDiagnostic( ComponentDiagnosticFactory.Create_UnclosedTag( - BuildSourceSpanFromNode(node.StartTag), node.StartTag.GetTagNameWithOptionalBang())); + BuildSourceSpanFromNode(node.MarkupStartTag), node.MarkupStartTag.GetTagNameWithOptionalBang())); } - else if (node.StartTag == null && node.EndTag != null) + else if (node.MarkupStartTag == null && node.MarkupEndTag != null) { element.AddDiagnostic( ComponentDiagnosticFactory.Create_UnexpectedClosingTag( - BuildSourceSpanFromNode(node.EndTag), node.EndTag.GetTagNameWithOptionalBang())); + BuildSourceSpanFromNode(node.MarkupEndTag), node.MarkupEndTag.GetTagNameWithOptionalBang())); } - if (node.StartTag != null && !_document.Options.SuppressPrimaryMethodBody) + if (node.MarkupStartTag != null && !_document.Options.SuppressPrimaryMethodBody) { // We only want this error during the second phase of the two phase compilation. - var startTagName = node.StartTag.GetTagNameWithOptionalBang(); + var startTagName = node.MarkupStartTag.GetTagNameWithOptionalBang(); if (!string.IsNullOrEmpty(startTagName) && LooksLikeAComponentName(_document, startTagName)) { element.AddDiagnostic( - ComponentDiagnosticFactory.Create_UnexpectedMarkupElement(startTagName, BuildSourceSpanFromNode(node.StartTag))); + ComponentDiagnosticFactory.Create_UnexpectedMarkupElement(startTagName, BuildSourceSpanFromNode(node.MarkupStartTag))); } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/HtmlMarkupParser.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/HtmlMarkupParser.cs index 40d69e2c29a..784373f35d4 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/HtmlMarkupParser.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/HtmlMarkupParser.cs @@ -88,14 +88,14 @@ public RazorDocumentSyntax ParseDocument() // We were tracking a void element but we reached the end of the document without finding a matching end tag. // So, close that element and move its content to its parent. var children = builder.Consume(); - var voidElement = SyntaxFactory.MarkupElement(tracker.StartTag, EmptySyntaxList, endTag: null); + var voidElement = SyntaxFactory.MarkupElement(tracker.StartTag, EmptySyntaxList, markupEndTag: null); builder.AddRange(tracker.PreviousNodes); builder.Add(voidElement); builder.AddRange(children); } else { - var element = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), endTag: null); + var element = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), markupEndTag: null); builder.AddRange(tracker.PreviousNodes); builder.Add(element); } @@ -322,7 +322,7 @@ private void CompleteMarkupInCodeBlock(in SyntaxListBuilder bui while (_tagTracker.Count > 0) { var tracker = _tagTracker.Pop(); - var element = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), endTag: null); + var element = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), markupEndTag: null); builder.AddRange(tracker.PreviousNodes); builder.Add(element); @@ -498,7 +498,7 @@ private void ParseMarkupElement(in SyntaxListBuilder builder, P if (tagMode == MarkupTagMode.SelfClosing || tagMode == MarkupTagMode.Invalid || tagMode == MarkupTagMode.Void) { // For cases like , or invalid cases like |<|

- var element = SyntaxFactory.MarkupElement(startTag, EmptySyntaxList, endTag: null); + var element = SyntaxFactory.MarkupElement(startTag, EmptySyntaxList, markupEndTag: null); builder.Add(element); return; } @@ -532,7 +532,7 @@ private void ParseMarkupElement(in SyntaxListBuilder builder, P if (!TryRecoverStartTag(builder, endTagName, endTag)) { // Could not recover. - var element = SyntaxFactory.MarkupElement(startTag: null, body: EmptySyntaxList, endTag: endTag); + var element = SyntaxFactory.MarkupElement(markupStartTag: null, body: EmptySyntaxList, markupEndTag: endTag); builder.Add(element); if (mode == ParseMode.MarkupInCodeBlock) @@ -563,7 +563,7 @@ private void CompleteEndTag( while (_tagTracker.Count > 0) { var tracker = _tagTracker.Pop(); - var unclosedElement = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), endTag: null); + var unclosedElement = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), markupEndTag: null); builder.AddRange(tracker.PreviousNodes); builder.Add(unclosedElement); @@ -589,7 +589,7 @@ private bool TryRecoverStartTag(in SyntaxListBuilder builder, s { var tracker = _tagTracker.Pop(); var children = builder.Consume(); - var voidElement = SyntaxFactory.MarkupElement(tracker.StartTag, EmptySyntaxList, endTag: null); + var voidElement = SyntaxFactory.MarkupElement(tracker.StartTag, EmptySyntaxList, markupEndTag: null); builder.AddRange(tracker.PreviousNodes); builder.Add(voidElement); builder.AddRange(children); @@ -612,7 +612,7 @@ private bool TryRecoverStartTag(in SyntaxListBuilder builder, s for (var i = 0; i < malformedTagCount; i++) { var tracker = _tagTracker.Pop(); - var malformedElement = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), endTag: null); + var malformedElement = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), markupEndTag: null); builder.AddRange(tracker.PreviousNodes); builder.Add(malformedElement); } @@ -2149,7 +2149,7 @@ private void NestingBlock(in SyntaxListBuilder builder, Tuple 0) { var tracker = _tagTracker.Pop(); - var element = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), endTag: null); + var element = SyntaxFactory.MarkupElement(tracker.StartTag, builder.Consume(), markupEndTag: null); builder.AddRange(tracker.PreviousNodes); builder.Add(element); } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperParseTreeRewriter.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperParseTreeRewriter.cs index 7706ba59913..cc59d2ae3c5 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperParseTreeRewriter.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/TagHelperParseTreeRewriter.cs @@ -115,14 +115,14 @@ public override SyntaxNode VisitMarkupElement(MarkupElementSyntax node) if (startTag != null) { var tagName = startTag.GetTagNameWithOptionalBang(); - if (TryRewriteTagHelperStart(startTag, node.EndTag, out tagHelperStart, out tagHelperInfo)) + if (TryRewriteTagHelperStart(startTag, node.MarkupEndTag, out tagHelperStart, out tagHelperInfo)) { // This is a tag helper. if (tagHelperInfo.TagMode == TagMode.SelfClosing || tagHelperInfo.TagMode == TagMode.StartTagOnly) { - var tagHelperElement = SyntaxFactory.MarkupTagHelperElement(tagHelperStart, body: default, endTag: null, tagHelperInfo); + var tagHelperElement = SyntaxFactory.MarkupTagHelperElement(tagHelperStart, body: default, tagHelperEndTag: null, tagHelperInfo); - if (node.Body.Count == 0 && node.EndTag == null) + if (node.Body.Count == 0 && node.MarkupEndTag == null) { return tagHelperElement; } @@ -134,14 +134,14 @@ public override SyntaxNode VisitMarkupElement(MarkupElementSyntax node) var rewrittenBody = VisitList(node.Body); rewrittenNodes.AddRange(rewrittenBody); - return SyntaxFactory.MarkupElement(startTag: null, body: rewrittenNodes.ToList(), endTag: node.EndTag); + return SyntaxFactory.MarkupElement(markupStartTag: null, body: rewrittenNodes.ToList(), markupEndTag: node.MarkupEndTag); } else if (node.EndTag == null) { // Start tag helper with no corresponding end tag. var source = new SourceSpan(SourceLocationTracker.Advance(startTag.GetSourceLocation(_source), "<"), tagName.Length); _errorSink.OnError( - node.StartTag.IsVoidElement() + startTag.IsVoidElement() ? RazorDiagnosticFactory.CreateParsing_VoidElement(source, tagName) : RazorDiagnosticFactory.CreateParsing_TagHelperFoundMalformedTagHelper(source, tagName)); } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/BaseMarkupEndTagSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/BaseMarkupEndTagSyntax.cs index 981cf77bb86..7d014f0dee8 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/BaseMarkupEndTagSyntax.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/BaseMarkupEndTagSyntax.cs @@ -101,5 +101,6 @@ static bool IsValidToken(SyntaxToken token, out SyntaxToken validToken) } } - public abstract BaseMarkupStartTagSyntax? GetStartTag(); + public BaseMarkupStartTagSyntax? GetStartTag() + => (Parent as BaseMarkupElementSyntax)?.StartTag; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/BaseMarkupStartTagSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/BaseMarkupStartTagSyntax.cs index fced98fe7a1..32fff8333c4 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/BaseMarkupStartTagSyntax.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/BaseMarkupStartTagSyntax.cs @@ -10,6 +10,8 @@ internal abstract partial class BaseMarkupStartTagSyntax { private SyntaxNode? _lazyChildren; + public BaseMarkupElementSyntax ParentElement => (BaseMarkupElementSyntax)Parent; + public SyntaxList LegacyChildren { get @@ -130,5 +132,6 @@ static bool IsValidToken(SyntaxToken token, out SyntaxToken validToken) } } - public abstract BaseMarkupEndTagSyntax? GetEndTag(); + public BaseMarkupEndTagSyntax? GetEndTag() + => (Parent as BaseMarkupElementSyntax)?.EndTag; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Internal.Generated.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Internal.Generated.cs index 06e8864573d..70acc04f72b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Internal.Generated.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Internal.Generated.cs @@ -1082,64 +1082,81 @@ internal BaseMarkupEndTagSyntax(SyntaxKind kind) public abstract SpanEditHandler EditHandler { get; } } -internal sealed partial class MarkupElementSyntax : MarkupSyntaxNode +internal abstract partial class BaseMarkupElementSyntax : MarkupSyntaxNode { - internal readonly MarkupStartTagSyntax _startTag; + internal BaseMarkupElementSyntax(SyntaxKind kind, RazorDiagnostic[] diagnostics) + : base(kind, diagnostics) + { + } + + internal BaseMarkupElementSyntax(SyntaxKind kind) + : base(kind) + { + } + + public abstract BaseMarkupStartTagSyntax StartTag { get; } + + public abstract BaseMarkupEndTagSyntax EndTag { get; } +} + +internal sealed partial class MarkupElementSyntax : BaseMarkupElementSyntax +{ + internal readonly MarkupStartTagSyntax _markupStartTag; internal readonly GreenNode _body; - internal readonly MarkupEndTagSyntax _endTag; + internal readonly MarkupEndTagSyntax _markupEndTag; - internal MarkupElementSyntax(SyntaxKind kind, MarkupStartTagSyntax startTag, GreenNode body, MarkupEndTagSyntax endTag, RazorDiagnostic[] diagnostics) + internal MarkupElementSyntax(SyntaxKind kind, MarkupStartTagSyntax markupStartTag, GreenNode body, MarkupEndTagSyntax markupEndTag, RazorDiagnostic[] diagnostics) : base(kind, diagnostics) { SlotCount = 3; - if (startTag != null) + if (markupStartTag != null) { - AdjustFlagsAndWidth(startTag); - _startTag = startTag; + AdjustFlagsAndWidth(markupStartTag); + _markupStartTag = markupStartTag; } if (body != null) { AdjustFlagsAndWidth(body); _body = body; } - if (endTag != null) + if (markupEndTag != null) { - AdjustFlagsAndWidth(endTag); - _endTag = endTag; + AdjustFlagsAndWidth(markupEndTag); + _markupEndTag = markupEndTag; } } - internal MarkupElementSyntax(SyntaxKind kind, MarkupStartTagSyntax startTag, GreenNode body, MarkupEndTagSyntax endTag) + internal MarkupElementSyntax(SyntaxKind kind, MarkupStartTagSyntax markupStartTag, GreenNode body, MarkupEndTagSyntax markupEndTag) : base(kind) { SlotCount = 3; - if (startTag != null) + if (markupStartTag != null) { - AdjustFlagsAndWidth(startTag); - _startTag = startTag; + AdjustFlagsAndWidth(markupStartTag); + _markupStartTag = markupStartTag; } if (body != null) { AdjustFlagsAndWidth(body); _body = body; } - if (endTag != null) + if (markupEndTag != null) { - AdjustFlagsAndWidth(endTag); - _endTag = endTag; + AdjustFlagsAndWidth(markupEndTag); + _markupEndTag = markupEndTag; } } - public MarkupStartTagSyntax StartTag => _startTag; + public MarkupStartTagSyntax MarkupStartTag => _markupStartTag; public SyntaxList Body => new SyntaxList(_body); - public MarkupEndTagSyntax EndTag => _endTag; + public MarkupEndTagSyntax MarkupEndTag => _markupEndTag; internal override GreenNode GetSlot(int index) => index switch { - 0 => _startTag, + 0 => _markupStartTag, 1 => _body, - 2 => _endTag, + 2 => _markupEndTag, _ => null }; @@ -1148,11 +1165,11 @@ internal override GreenNode GetSlot(int index) public override TResult Accept(SyntaxVisitor visitor) => visitor.VisitMarkupElement(this); public override void Accept(SyntaxVisitor visitor) => visitor.VisitMarkupElement(this); - public MarkupElementSyntax Update(MarkupStartTagSyntax startTag, InternalSyntax.SyntaxList body, MarkupEndTagSyntax endTag) + public MarkupElementSyntax Update(MarkupStartTagSyntax markupStartTag, InternalSyntax.SyntaxList body, MarkupEndTagSyntax markupEndTag) { - if (startTag != StartTag || body != Body || endTag != EndTag) + if (markupStartTag != MarkupStartTag || body != Body || markupEndTag != MarkupEndTag) { - var newNode = SyntaxFactory.MarkupElement(startTag, body, endTag); + var newNode = SyntaxFactory.MarkupElement(markupStartTag, body, markupEndTag); var diags = GetDiagnostics(); if (diags != null && diags.Length > 0) newNode = newNode.WithDiagnosticsGreen(diags); @@ -1163,7 +1180,7 @@ public MarkupElementSyntax Update(MarkupStartTagSyntax startTag, InternalSyntax. } internal override GreenNode SetDiagnostics(RazorDiagnostic[] diagnostics) - => new MarkupElementSyntax(Kind, _startTag, _body, _endTag, diagnostics); + => new MarkupElementSyntax(Kind, _markupStartTag, _body, _markupEndTag, diagnostics); } internal sealed partial class MarkupStartTagSyntax : BaseMarkupStartTagSyntax @@ -1394,62 +1411,68 @@ internal override GreenNode SetDiagnostics(RazorDiagnostic[] diagnostics) => new MarkupEndTagSyntax(Kind, _openAngle, _forwardSlash, _bang, _name, _miscAttributeContent, _closeAngle, _isMarkupTransition, _chunkGenerator, _editHandler, diagnostics); } -internal sealed partial class MarkupTagHelperElementSyntax : MarkupSyntaxNode +internal sealed partial class MarkupTagHelperElementSyntax : BaseMarkupElementSyntax { - internal readonly MarkupTagHelperStartTagSyntax _startTag; + internal readonly MarkupTagHelperStartTagSyntax _tagHelperStartTag; internal readonly GreenNode _body; - internal readonly MarkupTagHelperEndTagSyntax _endTag; + internal readonly MarkupTagHelperEndTagSyntax _tagHelperEndTag; internal readonly TagHelperInfo _tagHelperInfo; - internal MarkupTagHelperElementSyntax(SyntaxKind kind, MarkupTagHelperStartTagSyntax startTag, GreenNode body, MarkupTagHelperEndTagSyntax endTag, TagHelperInfo tagHelperInfo, RazorDiagnostic[] diagnostics) + internal MarkupTagHelperElementSyntax(SyntaxKind kind, MarkupTagHelperStartTagSyntax tagHelperStartTag, GreenNode body, MarkupTagHelperEndTagSyntax tagHelperEndTag, TagHelperInfo tagHelperInfo, RazorDiagnostic[] diagnostics) : base(kind, diagnostics) { SlotCount = 3; - AdjustFlagsAndWidth(startTag); - _startTag = startTag; + if (tagHelperStartTag != null) + { + AdjustFlagsAndWidth(tagHelperStartTag); + _tagHelperStartTag = tagHelperStartTag; + } if (body != null) { AdjustFlagsAndWidth(body); _body = body; } - if (endTag != null) + if (tagHelperEndTag != null) { - AdjustFlagsAndWidth(endTag); - _endTag = endTag; + AdjustFlagsAndWidth(tagHelperEndTag); + _tagHelperEndTag = tagHelperEndTag; } _tagHelperInfo = tagHelperInfo; } - internal MarkupTagHelperElementSyntax(SyntaxKind kind, MarkupTagHelperStartTagSyntax startTag, GreenNode body, MarkupTagHelperEndTagSyntax endTag, TagHelperInfo tagHelperInfo) + internal MarkupTagHelperElementSyntax(SyntaxKind kind, MarkupTagHelperStartTagSyntax tagHelperStartTag, GreenNode body, MarkupTagHelperEndTagSyntax tagHelperEndTag, TagHelperInfo tagHelperInfo) : base(kind) { SlotCount = 3; - AdjustFlagsAndWidth(startTag); - _startTag = startTag; + if (tagHelperStartTag != null) + { + AdjustFlagsAndWidth(tagHelperStartTag); + _tagHelperStartTag = tagHelperStartTag; + } if (body != null) { AdjustFlagsAndWidth(body); _body = body; } - if (endTag != null) + if (tagHelperEndTag != null) { - AdjustFlagsAndWidth(endTag); - _endTag = endTag; + AdjustFlagsAndWidth(tagHelperEndTag); + _tagHelperEndTag = tagHelperEndTag; } _tagHelperInfo = tagHelperInfo; } - public MarkupTagHelperStartTagSyntax StartTag => _startTag; + public MarkupTagHelperStartTagSyntax TagHelperStartTag => _tagHelperStartTag; public SyntaxList Body => new SyntaxList(_body); - public MarkupTagHelperEndTagSyntax EndTag => _endTag; + public MarkupTagHelperEndTagSyntax TagHelperEndTag => _tagHelperEndTag; public TagHelperInfo TagHelperInfo => _tagHelperInfo; internal override GreenNode GetSlot(int index) => index switch { - 0 => _startTag, + 0 => _tagHelperStartTag, 1 => _body, - 2 => _endTag, + 2 => _tagHelperEndTag, _ => null }; @@ -1458,11 +1481,11 @@ internal override GreenNode GetSlot(int index) public override TResult Accept(SyntaxVisitor visitor) => visitor.VisitMarkupTagHelperElement(this); public override void Accept(SyntaxVisitor visitor) => visitor.VisitMarkupTagHelperElement(this); - public MarkupTagHelperElementSyntax Update(MarkupTagHelperStartTagSyntax startTag, InternalSyntax.SyntaxList body, MarkupTagHelperEndTagSyntax endTag, TagHelperInfo tagHelperInfo) + public MarkupTagHelperElementSyntax Update(MarkupTagHelperStartTagSyntax tagHelperStartTag, InternalSyntax.SyntaxList body, MarkupTagHelperEndTagSyntax tagHelperEndTag, TagHelperInfo tagHelperInfo) { - if (startTag != StartTag || body != Body || endTag != EndTag) + if (tagHelperStartTag != TagHelperStartTag || body != Body || tagHelperEndTag != TagHelperEndTag) { - var newNode = SyntaxFactory.MarkupTagHelperElement(startTag, body, endTag, tagHelperInfo); + var newNode = SyntaxFactory.MarkupTagHelperElement(tagHelperStartTag, body, tagHelperEndTag, tagHelperInfo); var diags = GetDiagnostics(); if (diags != null && diags.Length > 0) newNode = newNode.WithDiagnosticsGreen(diags); @@ -1473,7 +1496,7 @@ public MarkupTagHelperElementSyntax Update(MarkupTagHelperStartTagSyntax startTa } internal override GreenNode SetDiagnostics(RazorDiagnostic[] diagnostics) - => new MarkupTagHelperElementSyntax(Kind, _startTag, _body, _endTag, _tagHelperInfo, diagnostics); + => new MarkupTagHelperElementSyntax(Kind, _tagHelperStartTag, _body, _tagHelperEndTag, _tagHelperInfo, diagnostics); } internal sealed partial class MarkupTagHelperStartTagSyntax : BaseMarkupStartTagSyntax @@ -3277,7 +3300,7 @@ public override GreenNode VisitMarkupDynamicAttributeValue(MarkupDynamicAttribut => node.Update((MarkupTextLiteralSyntax)Visit(node.Prefix), (RazorBlockSyntax)Visit(node.Value)); public override GreenNode VisitMarkupElement(MarkupElementSyntax node) - => node.Update((MarkupStartTagSyntax)Visit(node.StartTag), VisitList(node.Body), (MarkupEndTagSyntax)Visit(node.EndTag)); + => node.Update((MarkupStartTagSyntax)Visit(node.MarkupStartTag), VisitList(node.Body), (MarkupEndTagSyntax)Visit(node.MarkupEndTag)); public override GreenNode VisitMarkupStartTag(MarkupStartTagSyntax node) => node.Update((SyntaxToken)Visit(node.OpenAngle), (SyntaxToken)Visit(node.Bang), (SyntaxToken)Visit(node.Name), VisitList(node.Attributes), (SyntaxToken)Visit(node.ForwardSlash), (SyntaxToken)Visit(node.CloseAngle), node.IsMarkupTransition, node.ChunkGenerator, node.EditHandler); @@ -3286,7 +3309,7 @@ public override GreenNode VisitMarkupEndTag(MarkupEndTagSyntax node) => node.Update((SyntaxToken)Visit(node.OpenAngle), (SyntaxToken)Visit(node.ForwardSlash), (SyntaxToken)Visit(node.Bang), (SyntaxToken)Visit(node.Name), (MarkupMiscAttributeContentSyntax)Visit(node.MiscAttributeContent), (SyntaxToken)Visit(node.CloseAngle), node.IsMarkupTransition, node.ChunkGenerator, node.EditHandler); public override GreenNode VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node) - => node.Update((MarkupTagHelperStartTagSyntax)Visit(node.StartTag), VisitList(node.Body), (MarkupTagHelperEndTagSyntax)Visit(node.EndTag), node.TagHelperInfo); + => node.Update((MarkupTagHelperStartTagSyntax)Visit(node.TagHelperStartTag), VisitList(node.Body), (MarkupTagHelperEndTagSyntax)Visit(node.TagHelperEndTag), node.TagHelperInfo); public override GreenNode VisitMarkupTagHelperStartTag(MarkupTagHelperStartTagSyntax node) => node.Update((SyntaxToken)Visit(node.OpenAngle), (SyntaxToken)Visit(node.Bang), (SyntaxToken)Visit(node.Name), VisitList(node.Attributes), (SyntaxToken)Visit(node.ForwardSlash), (SyntaxToken)Visit(node.CloseAngle), node.ChunkGenerator, node.EditHandler); @@ -3488,9 +3511,9 @@ public static MarkupDynamicAttributeValueSyntax MarkupDynamicAttributeValue(Mark return result; } - public static MarkupElementSyntax MarkupElement(MarkupStartTagSyntax startTag, Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList body, MarkupEndTagSyntax endTag) + public static MarkupElementSyntax MarkupElement(MarkupStartTagSyntax markupStartTag, Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList body, MarkupEndTagSyntax markupEndTag) { - var result = new MarkupElementSyntax(SyntaxKind.MarkupElement, startTag, body.Node, endTag); + var result = new MarkupElementSyntax(SyntaxKind.MarkupElement, markupStartTag, body.Node, markupEndTag); return result; } @@ -3534,11 +3557,9 @@ public static MarkupEndTagSyntax MarkupEndTag(SyntaxToken openAngle, SyntaxToken return new MarkupEndTagSyntax(SyntaxKind.MarkupEndTag, openAngle, forwardSlash, bang, name, miscAttributeContent, closeAngle, isMarkupTransition, chunkGenerator, editHandler); } - public static MarkupTagHelperElementSyntax MarkupTagHelperElement(MarkupTagHelperStartTagSyntax startTag, Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList body, MarkupTagHelperEndTagSyntax endTag, TagHelperInfo tagHelperInfo) + public static MarkupTagHelperElementSyntax MarkupTagHelperElement(MarkupTagHelperStartTagSyntax tagHelperStartTag, Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList body, MarkupTagHelperEndTagSyntax tagHelperEndTag, TagHelperInfo tagHelperInfo) { - ArgHelper.ThrowIfNull(startTag); - - return new MarkupTagHelperElementSyntax(SyntaxKind.MarkupTagHelperElement, startTag, body.Node, endTag, tagHelperInfo); + return new MarkupTagHelperElementSyntax(SyntaxKind.MarkupTagHelperElement, tagHelperStartTag, body.Node, tagHelperEndTag, tagHelperInfo); } public static MarkupTagHelperStartTagSyntax MarkupTagHelperStartTag(SyntaxToken openAngle, SyntaxToken bang, SyntaxToken name, Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList attributes, SyntaxToken forwardSlash, SyntaxToken closeAngle, ISpanChunkGenerator chunkGenerator, SpanEditHandler editHandler) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Main.Generated.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Main.Generated.cs index 92681edad34..1d6e7973ba5 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Main.Generated.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Main.Generated.cs @@ -306,7 +306,7 @@ public override SyntaxNode VisitMarkupDynamicAttributeValue(MarkupDynamicAttribu => node.Update((MarkupTextLiteralSyntax)Visit(node.Prefix), (RazorBlockSyntax)Visit(node.Value)); public override SyntaxNode VisitMarkupElement(MarkupElementSyntax node) - => node.Update((MarkupStartTagSyntax)Visit(node.StartTag), VisitList(node.Body), (MarkupEndTagSyntax)Visit(node.EndTag)); + => node.Update((MarkupStartTagSyntax)Visit(node.MarkupStartTag), VisitList(node.Body), (MarkupEndTagSyntax)Visit(node.MarkupEndTag)); public override SyntaxNode VisitMarkupStartTag(MarkupStartTagSyntax node) => node.Update((SyntaxToken)VisitToken(node.OpenAngle), (SyntaxToken)VisitToken(node.Bang), (SyntaxToken)VisitToken(node.Name), VisitList(node.Attributes), (SyntaxToken)VisitToken(node.ForwardSlash), (SyntaxToken)VisitToken(node.CloseAngle), node.IsMarkupTransition, node.ChunkGenerator, node.EditHandler); @@ -315,7 +315,7 @@ public override SyntaxNode VisitMarkupEndTag(MarkupEndTagSyntax node) => node.Update((SyntaxToken)VisitToken(node.OpenAngle), (SyntaxToken)VisitToken(node.ForwardSlash), (SyntaxToken)VisitToken(node.Bang), (SyntaxToken)VisitToken(node.Name), (MarkupMiscAttributeContentSyntax)Visit(node.MiscAttributeContent), (SyntaxToken)VisitToken(node.CloseAngle), node.IsMarkupTransition, node.ChunkGenerator, node.EditHandler); public override SyntaxNode VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node) - => node.Update((MarkupTagHelperStartTagSyntax)Visit(node.StartTag), VisitList(node.Body), (MarkupTagHelperEndTagSyntax)Visit(node.EndTag), node.TagHelperInfo); + => node.Update((MarkupTagHelperStartTagSyntax)Visit(node.TagHelperStartTag), VisitList(node.Body), (MarkupTagHelperEndTagSyntax)Visit(node.TagHelperEndTag), node.TagHelperInfo); public override SyntaxNode VisitMarkupTagHelperStartTag(MarkupTagHelperStartTagSyntax node) => node.Update((SyntaxToken)VisitToken(node.OpenAngle), (SyntaxToken)VisitToken(node.Bang), (SyntaxToken)VisitToken(node.Name), VisitList(node.Attributes), (SyntaxToken)VisitToken(node.ForwardSlash), (SyntaxToken)VisitToken(node.CloseAngle), node.ChunkGenerator, node.EditHandler); @@ -532,8 +532,8 @@ public static MarkupDynamicAttributeValueSyntax MarkupDynamicAttributeValue(Razo => SyntaxFactory.MarkupDynamicAttributeValue(default(MarkupTextLiteralSyntax), value); ///

Creates a new MarkupElementSyntax instance. - public static MarkupElementSyntax MarkupElement(MarkupStartTagSyntax startTag, SyntaxList body, MarkupEndTagSyntax endTag) - => (MarkupElementSyntax)InternalSyntax.SyntaxFactory.MarkupElement(startTag == null ? null : (InternalSyntax.MarkupStartTagSyntax)startTag.Green, body.Node.ToGreenList(), endTag == null ? null : (InternalSyntax.MarkupEndTagSyntax)endTag.Green).CreateRed(); + public static MarkupElementSyntax MarkupElement(MarkupStartTagSyntax markupStartTag, SyntaxList body, MarkupEndTagSyntax markupEndTag) + => (MarkupElementSyntax)InternalSyntax.SyntaxFactory.MarkupElement(markupStartTag == null ? null : (InternalSyntax.MarkupStartTagSyntax)markupStartTag.Green, body.Node.ToGreenList(), markupEndTag == null ? null : (InternalSyntax.MarkupEndTagSyntax)markupEndTag.Green).CreateRed(); /// Creates a new MarkupElementSyntax instance. public static MarkupElementSyntax MarkupElement(SyntaxList body = default(SyntaxList)) @@ -578,15 +578,12 @@ public static MarkupEndTagSyntax MarkupEndTag(bool isMarkupTransition, ISpanChun => SyntaxFactory.MarkupEndTag(SyntaxFactory.Token(SyntaxKind.OpenAngle), SyntaxFactory.Token(SyntaxKind.ForwardSlash), default(SyntaxToken), SyntaxFactory.Token(SyntaxKind.Text), default(MarkupMiscAttributeContentSyntax), SyntaxFactory.Token(SyntaxKind.CloseAngle), isMarkupTransition, chunkGenerator, editHandler); /// Creates a new MarkupTagHelperElementSyntax instance. - public static MarkupTagHelperElementSyntax MarkupTagHelperElement(MarkupTagHelperStartTagSyntax startTag, SyntaxList body, MarkupTagHelperEndTagSyntax endTag, TagHelperInfo tagHelperInfo) - { - ArgHelper.ThrowIfNull(startTag); - return (MarkupTagHelperElementSyntax)InternalSyntax.SyntaxFactory.MarkupTagHelperElement(startTag == null ? null : (InternalSyntax.MarkupTagHelperStartTagSyntax)startTag.Green, body.Node.ToGreenList(), endTag == null ? null : (InternalSyntax.MarkupTagHelperEndTagSyntax)endTag.Green, tagHelperInfo).CreateRed(); - } + public static MarkupTagHelperElementSyntax MarkupTagHelperElement(MarkupTagHelperStartTagSyntax tagHelperStartTag, SyntaxList body, MarkupTagHelperEndTagSyntax tagHelperEndTag, TagHelperInfo tagHelperInfo) + => (MarkupTagHelperElementSyntax)InternalSyntax.SyntaxFactory.MarkupTagHelperElement(tagHelperStartTag == null ? null : (InternalSyntax.MarkupTagHelperStartTagSyntax)tagHelperStartTag.Green, body.Node.ToGreenList(), tagHelperEndTag == null ? null : (InternalSyntax.MarkupTagHelperEndTagSyntax)tagHelperEndTag.Green, tagHelperInfo).CreateRed(); /// Creates a new MarkupTagHelperElementSyntax instance. - public static MarkupTagHelperElementSyntax MarkupTagHelperElement(MarkupTagHelperStartTagSyntax startTag, TagHelperInfo tagHelperInfo) - => SyntaxFactory.MarkupTagHelperElement(startTag, default(SyntaxList), default(MarkupTagHelperEndTagSyntax), tagHelperInfo); + public static MarkupTagHelperElementSyntax MarkupTagHelperElement(TagHelperInfo tagHelperInfo) + => SyntaxFactory.MarkupTagHelperElement(default(MarkupTagHelperStartTagSyntax), default(SyntaxList), default(MarkupTagHelperEndTagSyntax), tagHelperInfo); /// Creates a new MarkupTagHelperStartTagSyntax instance. public static MarkupTagHelperStartTagSyntax MarkupTagHelperStartTag(SyntaxToken openAngle, SyntaxToken bang, SyntaxToken name, SyntaxList attributes, SyntaxToken forwardSlash, SyntaxToken closeAngle, ISpanChunkGenerator chunkGenerator, SpanEditHandler editHandler) diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Syntax.Generated.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Syntax.Generated.cs index 0696c0dd066..b09a3a135a9 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Syntax.Generated.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Generated/Syntax.xml.Syntax.Generated.cs @@ -795,47 +795,63 @@ internal BaseMarkupEndTagSyntax(GreenNode green, SyntaxNode parent, int position public abstract SpanEditHandler EditHandler { get; } } -internal sealed partial class MarkupElementSyntax : MarkupSyntaxNode +internal abstract partial class BaseMarkupElementSyntax : MarkupSyntaxNode { - private MarkupStartTagSyntax _startTag; + internal BaseMarkupElementSyntax(GreenNode green, SyntaxNode parent, int position) + : base(green, parent, position) + { + } + + public abstract BaseMarkupStartTagSyntax StartTag { get; } + public BaseMarkupElementSyntax WithStartTag(BaseMarkupStartTagSyntax startTag) => WithStartTagCore(startTag); + internal abstract BaseMarkupElementSyntax WithStartTagCore(BaseMarkupStartTagSyntax startTag); + + public abstract BaseMarkupEndTagSyntax EndTag { get; } + public BaseMarkupElementSyntax WithEndTag(BaseMarkupEndTagSyntax endTag) => WithEndTagCore(endTag); + internal abstract BaseMarkupElementSyntax WithEndTagCore(BaseMarkupEndTagSyntax endTag); +} + +internal sealed partial class MarkupElementSyntax : BaseMarkupElementSyntax +{ + private MarkupStartTagSyntax _markupStartTag; private SyntaxNode _body; - private MarkupEndTagSyntax _endTag; + private MarkupEndTagSyntax _markupEndTag; internal MarkupElementSyntax(GreenNode green, SyntaxNode parent, int position) : base(green, parent, position) { } - public MarkupStartTagSyntax StartTag => GetRedAtZero(ref _startTag); + public MarkupStartTagSyntax MarkupStartTag => GetRedAtZero(ref _markupStartTag); public SyntaxList Body => new SyntaxList(GetRed(ref _body, 1)); - public MarkupEndTagSyntax EndTag => GetRed(ref _endTag, 2); + public MarkupEndTagSyntax MarkupEndTag => GetRed(ref _markupEndTag, 2); internal override SyntaxNode GetNodeSlot(int index) => index switch { - 0 => GetRedAtZero(ref _startTag), + 0 => GetRedAtZero(ref _markupStartTag), 1 => GetRed(ref _body, 1), - 2 => GetRed(ref _endTag, 2), + 2 => GetRed(ref _markupEndTag, 2), _ => null }; internal override SyntaxNode GetCachedSlot(int index) => index switch { - 0 => this._startTag, + 0 => this._markupStartTag, 1 => this._body, - 2 => this._endTag, + 2 => this._markupEndTag, _ => null }; public override TResult Accept(SyntaxVisitor visitor) => visitor.VisitMarkupElement(this); public override void Accept(SyntaxVisitor visitor) => visitor.VisitMarkupElement(this); - public MarkupElementSyntax Update(MarkupStartTagSyntax startTag, SyntaxList body, MarkupEndTagSyntax endTag) + public MarkupElementSyntax Update(MarkupStartTagSyntax markupStartTag, SyntaxList body, MarkupEndTagSyntax markupEndTag) { - if (startTag != StartTag || body != Body || endTag != EndTag) + if (markupStartTag != MarkupStartTag || body != Body || markupEndTag != MarkupEndTag) { - var newNode = SyntaxFactory.MarkupElement(startTag, body, endTag); + var newNode = SyntaxFactory.MarkupElement(markupStartTag, body, markupEndTag); var diagnostics = GetDiagnostics(); if (diagnostics != null && diagnostics.Length > 0) newNode = newNode.WithDiagnostics(diagnostics); @@ -845,9 +861,9 @@ public MarkupElementSyntax Update(MarkupStartTagSyntax startTag, SyntaxList Update(startTag, Body, EndTag); - public MarkupElementSyntax WithBody(SyntaxList body) => Update(StartTag, body, EndTag); - public MarkupElementSyntax WithEndTag(MarkupEndTagSyntax endTag) => Update(StartTag, Body, endTag); + public MarkupElementSyntax WithMarkupStartTag(MarkupStartTagSyntax markupStartTag) => Update(markupStartTag, Body, MarkupEndTag); + public MarkupElementSyntax WithBody(SyntaxList body) => Update(MarkupStartTag, body, MarkupEndTag); + public MarkupElementSyntax WithMarkupEndTag(MarkupEndTagSyntax markupEndTag) => Update(MarkupStartTag, Body, markupEndTag); public MarkupElementSyntax AddBody(params RazorSyntaxNode[] items) => WithBody(this.Body.AddRange(items)); } @@ -997,48 +1013,48 @@ public MarkupEndTagSyntax Update(SyntaxToken openAngle, SyntaxToken forwardSlash } } -internal sealed partial class MarkupTagHelperElementSyntax : MarkupSyntaxNode +internal sealed partial class MarkupTagHelperElementSyntax : BaseMarkupElementSyntax { - private MarkupTagHelperStartTagSyntax _startTag; + private MarkupTagHelperStartTagSyntax _tagHelperStartTag; private SyntaxNode _body; - private MarkupTagHelperEndTagSyntax _endTag; + private MarkupTagHelperEndTagSyntax _tagHelperEndTag; internal MarkupTagHelperElementSyntax(GreenNode green, SyntaxNode parent, int position) : base(green, parent, position) { } - public MarkupTagHelperStartTagSyntax StartTag => GetRedAtZero(ref _startTag); + public MarkupTagHelperStartTagSyntax TagHelperStartTag => GetRedAtZero(ref _tagHelperStartTag); public SyntaxList Body => new SyntaxList(GetRed(ref _body, 1)); - public MarkupTagHelperEndTagSyntax EndTag => GetRed(ref _endTag, 2); + public MarkupTagHelperEndTagSyntax TagHelperEndTag => GetRed(ref _tagHelperEndTag, 2); public TagHelperInfo TagHelperInfo => ((InternalSyntax.MarkupTagHelperElementSyntax)Green).TagHelperInfo; internal override SyntaxNode GetNodeSlot(int index) => index switch { - 0 => GetRedAtZero(ref _startTag), + 0 => GetRedAtZero(ref _tagHelperStartTag), 1 => GetRed(ref _body, 1), - 2 => GetRed(ref _endTag, 2), + 2 => GetRed(ref _tagHelperEndTag, 2), _ => null }; internal override SyntaxNode GetCachedSlot(int index) => index switch { - 0 => this._startTag, + 0 => this._tagHelperStartTag, 1 => this._body, - 2 => this._endTag, + 2 => this._tagHelperEndTag, _ => null }; public override TResult Accept(SyntaxVisitor visitor) => visitor.VisitMarkupTagHelperElement(this); public override void Accept(SyntaxVisitor visitor) => visitor.VisitMarkupTagHelperElement(this); - public MarkupTagHelperElementSyntax Update(MarkupTagHelperStartTagSyntax startTag, SyntaxList body, MarkupTagHelperEndTagSyntax endTag, TagHelperInfo tagHelperInfo) + public MarkupTagHelperElementSyntax Update(MarkupTagHelperStartTagSyntax tagHelperStartTag, SyntaxList body, MarkupTagHelperEndTagSyntax tagHelperEndTag, TagHelperInfo tagHelperInfo) { - if (startTag != StartTag || body != Body || endTag != EndTag) + if (tagHelperStartTag != TagHelperStartTag || body != Body || tagHelperEndTag != TagHelperEndTag) { - var newNode = SyntaxFactory.MarkupTagHelperElement(startTag, body, endTag, tagHelperInfo); + var newNode = SyntaxFactory.MarkupTagHelperElement(tagHelperStartTag, body, tagHelperEndTag, tagHelperInfo); var diagnostics = GetDiagnostics(); if (diagnostics != null && diagnostics.Length > 0) newNode = newNode.WithDiagnostics(diagnostics); @@ -1048,12 +1064,10 @@ public MarkupTagHelperElementSyntax Update(MarkupTagHelperStartTagSyntax startTa return this; } - public MarkupTagHelperElementSyntax WithStartTag(MarkupTagHelperStartTagSyntax startTag) => Update(startTag, Body, EndTag, TagHelperInfo); - public MarkupTagHelperElementSyntax WithBody(SyntaxList body) => Update(StartTag, body, EndTag, TagHelperInfo); - public MarkupTagHelperElementSyntax WithEndTag(MarkupTagHelperEndTagSyntax endTag) => Update(StartTag, Body, endTag, TagHelperInfo); - public MarkupTagHelperElementSyntax WithTagHelperInfo(TagHelperInfo tagHelperInfo) => Update(StartTag, Body, EndTag, tagHelperInfo); - - public MarkupTagHelperElementSyntax AddStartTagAttributes(params RazorSyntaxNode[] items) => WithStartTag(this.StartTag.WithAttributes(this.StartTag.Attributes.AddRange(items))); + public MarkupTagHelperElementSyntax WithTagHelperStartTag(MarkupTagHelperStartTagSyntax tagHelperStartTag) => Update(tagHelperStartTag, Body, TagHelperEndTag, TagHelperInfo); + public MarkupTagHelperElementSyntax WithBody(SyntaxList body) => Update(TagHelperStartTag, body, TagHelperEndTag, TagHelperInfo); + public MarkupTagHelperElementSyntax WithTagHelperEndTag(MarkupTagHelperEndTagSyntax tagHelperEndTag) => Update(TagHelperStartTag, Body, tagHelperEndTag, TagHelperInfo); + public MarkupTagHelperElementSyntax WithTagHelperInfo(TagHelperInfo tagHelperInfo) => Update(TagHelperStartTag, Body, TagHelperEndTag, tagHelperInfo); public MarkupTagHelperElementSyntax AddBody(params RazorSyntaxNode[] items) => WithBody(this.Body.AddRange(items)); } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/InternalSyntax/MarkupElementSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/InternalSyntax/MarkupElementSyntax.cs new file mode 100644 index 00000000000..3e591e91e5b --- /dev/null +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/InternalSyntax/MarkupElementSyntax.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax; + +internal sealed partial class MarkupElementSyntax +{ + public override BaseMarkupStartTagSyntax StartTag + => MarkupStartTag; + + public override BaseMarkupEndTagSyntax EndTag + => MarkupEndTag; +} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/InternalSyntax/MarkupTagHelperElementSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/InternalSyntax/MarkupTagHelperElementSyntax.cs new file mode 100644 index 00000000000..b5c33af2880 --- /dev/null +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/InternalSyntax/MarkupTagHelperElementSyntax.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax; + +internal sealed partial class MarkupTagHelperElementSyntax +{ + public override BaseMarkupStartTagSyntax StartTag + => TagHelperStartTag; + + public override BaseMarkupEndTagSyntax EndTag + => TagHelperEndTag; +} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupElementSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupElementSyntax.cs new file mode 100644 index 00000000000..450b3125e59 --- /dev/null +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupElementSyntax.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Razor.Language.Syntax; + +internal partial class MarkupElementSyntax +{ + public override BaseMarkupStartTagSyntax? StartTag + => MarkupStartTag; + + internal override BaseMarkupElementSyntax WithStartTagCore(BaseMarkupStartTagSyntax startTag) + => WithMarkupStartTag((MarkupStartTagSyntax?)startTag); + + public override BaseMarkupEndTagSyntax? EndTag + => MarkupEndTag; + + internal override BaseMarkupElementSyntax WithEndTagCore(BaseMarkupEndTagSyntax endTag) + => WithMarkupEndTag((MarkupEndTagSyntax?)endTag); +} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupEndTagSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupEndTagSyntax.cs index 4a67861b292..de4233c7801 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupEndTagSyntax.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupEndTagSyntax.cs @@ -9,7 +9,4 @@ public string GetTagNameWithOptionalBang() { return Name.IsMissing ? string.Empty : Bang.Content + Name.Content; } - - public override BaseMarkupStartTagSyntax? GetStartTag() - => (Parent as MarkupElementSyntax)?.StartTag; } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupStartTagSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupStartTagSyntax.cs index cdbfda38533..626e74e1680 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupStartTagSyntax.cs +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupStartTagSyntax.cs @@ -9,9 +9,4 @@ public string GetTagNameWithOptionalBang() { return Name.IsMissing ? string.Empty : Bang.Content + Name.Content; } - - public override BaseMarkupEndTagSyntax? GetEndTag() - { - return (Parent as MarkupElementSyntax)?.EndTag; - } } diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperElementSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperElementSyntax.cs new file mode 100644 index 00000000000..1320510f855 --- /dev/null +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperElementSyntax.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Razor.Language.Syntax; + +internal partial class MarkupTagHelperElementSyntax +{ + public override BaseMarkupStartTagSyntax? StartTag + => TagHelperStartTag; + + internal override BaseMarkupElementSyntax WithStartTagCore(BaseMarkupStartTagSyntax startTag) + => WithTagHelperStartTag((MarkupTagHelperStartTagSyntax)startTag); + + public override BaseMarkupEndTagSyntax? EndTag + => TagHelperEndTag; + + internal override BaseMarkupElementSyntax WithEndTagCore(BaseMarkupEndTagSyntax endTag) + => WithTagHelperEndTag((MarkupTagHelperEndTagSyntax?)endTag); +} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperEndTagSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperEndTagSyntax.cs deleted file mode 100644 index 60963eede1c..00000000000 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperEndTagSyntax.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.AspNetCore.Razor.Language.Syntax; - -internal partial class MarkupTagHelperEndTagSyntax -{ - public override BaseMarkupStartTagSyntax? GetStartTag() - => (Parent as MarkupTagHelperElementSyntax)?.StartTag; -} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperStartTagSyntax.cs b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperStartTagSyntax.cs deleted file mode 100644 index 27f99eebe71..00000000000 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/MarkupTagHelperStartTagSyntax.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.AspNetCore.Razor.Language.Syntax; - -internal partial class MarkupTagHelperStartTagSyntax -{ - public override BaseMarkupEndTagSyntax? GetEndTag() - { - return (Parent as MarkupTagHelperElementSyntax)?.EndTag; - } -} diff --git a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Syntax.xml b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Syntax.xml index 4aaf621fbf6..a59f3b8e54b 100644 --- a/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Syntax.xml +++ b/src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Syntax/Syntax.xml @@ -149,11 +149,15 @@ - + + + + + - + - + @@ -199,11 +203,11 @@ - + - + - + diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs index 9668fed1272..7edbb96be6e 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs @@ -196,15 +196,10 @@ private static bool CouldAutoCloseParentOrSelf(string currentTagName, RazorSynta { string? potentialStartTagName = null; RazorSyntaxNode? endTag = null; - if (node is MarkupTagHelperElementSyntax parentTagHelper) + if (node is BaseMarkupElementSyntax element) { - potentialStartTagName = parentTagHelper.StartTag?.Name.Content ?? parentTagHelper.EndTag?.Name.Content; - endTag = parentTagHelper.EndTag; - } - else if (node is MarkupElementSyntax parentElement) - { - potentialStartTagName = parentElement.StartTag?.Name.Content ?? parentElement.EndTag?.Name.Content; - endTag = parentElement.EndTag; + potentialStartTagName = element.StartTag?.Name.Content ?? element.EndTag?.Name.Content; + endTag = element.EndTag; } // Note - potentialStartTagName can be null for cases when markup element is contained in markup diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs index ee690b6d1e9..f2e37f32a12 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs @@ -206,14 +206,10 @@ private static async Task> FindMatchingTagHelpersA // Get all data necessary for matching var tagName = startTag.Name.Content; string? parentTagName = null; - if (startTag.Parent?.Parent is MarkupElementSyntax parentElement) + if (startTag.Parent?.Parent is BaseMarkupElementSyntax parentElement) { parentTagName = parentElement.StartTag?.Name.Content ?? parentElement.EndTag?.Name.Content; } - else if (startTag.Parent?.Parent is MarkupTagHelperElementSyntax parentTagHelperElement) - { - parentTagName = parentTagHelperElement.StartTag?.Name.Content ?? parentTagHelperElement.EndTag?.Name.Content; - } var attributes = TagHelperFacts.StringifyAttributes(startTag.Attributes); @@ -297,7 +293,7 @@ private static WorkspaceEdit CreateRenameTagEdit( textEdits.Add(startTagTextEdit); - var endTag = (startTag.Parent as MarkupElementSyntax)?.EndTag; + var endTag = startTag.GetEndTag(); if (endTag != null) { var endTagTextEdit = LspFactory.CreateTextEdit(endTag.Name.GetRange(context.CodeDocument.Source), newTagName); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyFullyQualifiedComponentCodeActionProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyFullyQualifiedComponentCodeActionProvider.cs index 7aeabc4e1c0..a1a738157a1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyFullyQualifiedComponentCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyFullyQualifiedComponentCodeActionProvider.cs @@ -41,12 +41,13 @@ public Task> ProvideAsync(RazorCodeAct // Find the tag at the cursor position, if it's on the start tag (name portion) or end tag only. var owner = syntaxRoot.FindInnermostNode(context.StartAbsoluteIndex, includeWhitespace: true) switch { - MarkupTagHelperStartTagSyntax startTag when startTag.Name.Span.Contains(context.StartAbsoluteIndex) => startTag.Parent, + MarkupTagHelperStartTagSyntax ownerStartTag when ownerStartTag.Name.Span.Contains(context.StartAbsoluteIndex) => ownerStartTag.Parent, MarkupTagHelperEndTagSyntax endTag => endTag.Parent, _ => null }; - if (owner is not MarkupTagHelperElementSyntax markupElementSyntax) + if (owner is not MarkupTagHelperElementSyntax markupElementSyntax || + markupElementSyntax.TagHelperStartTag is not { } startTag) { return SpecializedTasks.EmptyImmutableArray(); } @@ -68,10 +69,10 @@ MarkupTagHelperStartTagSyntax startTag when startTag.Name.Span.Contains(context. { Namespace = @namespace, ComponentName = componentName, - StartTagSpanStart = markupElementSyntax.StartTag.Name.SpanStart, - StartTagSpanEnd = markupElementSyntax.StartTag.Name.Span.End, - EndTagSpanStart = markupElementSyntax.EndTag?.Name.SpanStart ?? -1, - EndTagSpanEnd = markupElementSyntax.EndTag?.Name.Span.End ?? -1, + StartTagSpanStart = startTag.Name.SpanStart, + StartTagSpanEnd = startTag.Name.Span.End, + EndTagSpanStart = markupElementSyntax.TagHelperEndTag?.Name.SpanStart ?? -1, + EndTagSpanEnd = markupElementSyntax.TagHelperEndTag?.Name.Span.End ?? -1, }; var resolutionParams = new RazorCodeActionResolutionParams() @@ -94,7 +95,12 @@ private static bool HasDiagnosticsOnStartTag(MarkupTagHelperElementSyntax elemen return false; } - var startTagSpan = element.StartTag.Span; + if (element.TagHelperStartTag is not { } startTag) + { + return false; + } + + var startTagSpan = startTag.Span; foreach (var diagnostic in context.Request.Context.Diagnostics) { if (diagnostic.Range is null) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyTagToSelfClosingCodeActionProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyTagToSelfClosingCodeActionProvider.cs index 5afe590e988..4f7490ce536 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyTagToSelfClosingCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/SimplifyTagToSelfClosingCodeActionProvider.cs @@ -50,7 +50,9 @@ public Task> ProvideAsync(RazorCodeAct } var owner = syntaxTree.Root.FindInnermostNode(context.StartAbsoluteIndex, includeWhitespace: false)?.FirstAncestorOrSelf(); - if (owner is not MarkupTagHelperElementSyntax markupElementSyntax) + if (owner is not MarkupTagHelperElementSyntax markupElementSyntax || + markupElementSyntax.TagHelperStartTag is not { } startTag || + markupElementSyntax.TagHelperEndTag is not { } endTag) { return SpecializedTasks.EmptyImmutableArray(); } @@ -64,8 +66,8 @@ public Task> ProvideAsync(RazorCodeAct // Provide code action to simplify var actionParams = new SimplifyTagToSelfClosingCodeActionParams { - StartTagCloseAngleIndex = markupElementSyntax.StartTag.CloseAngle.SpanStart, - EndTagCloseAngleIndex = markupElementSyntax.EndTag.CloseAngle.EndPosition, + StartTagCloseAngleIndex = startTag.CloseAngle.SpanStart, + EndTagCloseAngleIndex = endTag.CloseAngle.EndPosition, }; var resolutionParams = new RazorCodeActionResolutionParams() diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/Delegation/DelegatedCompletionHelper.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/Delegation/DelegatedCompletionHelper.cs index 33932af8231..d0c384f02f4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/Delegation/DelegatedCompletionHelper.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Completion/Delegation/DelegatedCompletionHelper.cs @@ -253,7 +253,7 @@ static bool IsInScriptOrStyleOrHtmlComment(AspNetCore.Razor.Language.Syntax.Synt { for (var node = initialNode; node != null; node = node.Parent) { - if (node is MarkupElementSyntax elementNode) + if (node is BaseMarkupElementSyntax elementNode) { if (RazorSyntaxFacts.IsScriptOrStyleBlock(elementNode)) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorTranslateDiagnosticsService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorTranslateDiagnosticsService.cs index ac2ece1272b..f733380b229 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorTranslateDiagnosticsService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorTranslateDiagnosticsService.cs @@ -291,7 +291,7 @@ static bool IsAtCSharpTransitionInStyleBlock(LspDiagnostic diagnostic, SourceTex return false; } - return owner.FirstAncestorOrSelf(static n => n.StartTag?.Name.Content == "style") is not null; + return owner.FirstAncestorOrSelf(static n => n.StartTag?.Name.Content == "style") is not null; } // Ideally this would be solved instead by not emitting the "!" at the HTML backing file, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingVisitor.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingVisitor.cs index 0c9ccdd2600..5a392347cbb 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingVisitor.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingVisitor.cs @@ -289,6 +289,11 @@ static bool ParentHasProperty(MarkupTagHelperElementSyntax parentComponent, stri static bool HasUnspecifiedCascadingTypeParameter(MarkupTagHelperElementSyntax node) { + if (node.TagHelperStartTag is not { } startTag) + { + return false; + } + if (node.TagHelperInfo.BindingResult.TagHelpers is not { Count: > 0 } descriptors) { return false; @@ -308,7 +313,7 @@ static bool HasUnspecifiedCascadingTypeParameter(MarkupTagHelperElementSyntax no // Get all type parameters for later use. Array is fine to use as the list should be tiny (I hope!!) var typeParameterNames = descriptors.SelectMany(d => d.GetTypeParameters().Select(p => p.Name)).ToArray(); - var attributes = node.StartTag.Attributes.OfType(); + var attributes = startTag.Attributes.OfType(); foreach (var attribute in attributes) { if (attribute.TagHelperAttributeInfo.Bound) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs index 4810ce22df5..5270996e5f1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/CSharpFormattingPass.CSharpDocumentGenerator.cs @@ -561,31 +561,42 @@ private LineInfo VisitCSharpLiteral(RazorSyntaxNode node, RazorSyntaxToken lastT public override LineInfo VisitMarkupStartTag(MarkupStartTagSyntax node) { - var element = (MarkupElementSyntax)node.Parent; + return VisitStartTag(node); + } + public override LineInfo VisitMarkupTagHelperStartTag(MarkupTagHelperStartTagSyntax node) + { + return VisitStartTag(node); + } + + private LineInfo VisitStartTag(BaseMarkupStartTagSyntax node) + { + var closeAngle = node.GetEndTag()?.CloseAngle ?? node.CloseAngle; if (ElementHasSignificantWhitespace(node)) { // The contents of some html tags is significant, so we never want any formatting to happen in their contents if (GetLineNumber(node) == GetLineNumber(node.CloseAngle)) { - _ignoreUntilLine = GetLineNumber(element.EndTag?.CloseAngle ?? element.StartTag.CloseAngle); + _ignoreUntilLine = GetLineNumber(closeAngle); } return EmitCurrentLineAsComment(); } - var result = VisitStartTag(node); + var lineInfo = ElementCausesIndentation(node) + ? EmitOpenBraceLine() // When an element causes indentation, we emit an open brace to tell the C# formatter to indent. + : EmitCurrentLineAsComment(); // This is a single line element, so it doesn't cause indentation - if (RazorSyntaxFacts.IsScriptOrStyleBlock(element) && + if (RazorSyntaxFacts.IsScriptOrStyleBlock(node.ParentElement) && _honourHtmlFormattingUntilLine is null) { // If this is an element at the root level, we want to record where it ends. We can't rely on the Visit method // for it, because it might not be at the start of a line. We only care about contents though, so thats why // we are doing this after emitting this line, and subtracting one from the end element line number. - _honourHtmlFormattingUntilLine = GetLineNumber(element.EndTag?.CloseAngle ?? element.StartTag.CloseAngle) - 1; + _honourHtmlFormattingUntilLine = GetLineNumber(closeAngle) - 1; } - return result; + return lineInfo; } public override LineInfo VisitMarkupEndTag(MarkupEndTagSyntax node) @@ -593,6 +604,11 @@ public override LineInfo VisitMarkupEndTag(MarkupEndTagSyntax node) return VisitEndTag(node); } + public override LineInfo VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) + { + return VisitEndTag(node); + } + private LineInfo VisitEndTag(BaseMarkupEndTagSyntax node) { // End tags are emited as close braces, to remove the indent their start tag caused. We don't need to worry @@ -616,23 +632,6 @@ private LineInfo VisitEndTag(BaseMarkupEndTagSyntax node) return CreateLineInfo(); } - public override LineInfo VisitMarkupTagHelperStartTag(MarkupTagHelperStartTagSyntax node) - { - return VisitStartTag(node); - } - - private LineInfo VisitStartTag(BaseMarkupStartTagSyntax node) - { - if (ElementCausesIndentation(node)) - { - // When an element causes indentation, we emit an open brace to tell the C# formatter to indent. - return EmitOpenBraceLine(); - } - - // This is a single line element, so it doesn't cause indentation - return EmitCurrentLineAsComment(); - } - private bool ElementCausesIndentation(BaseMarkupStartTagSyntax node) { if (node.Name.Content.Equals("html", StringComparison.OrdinalIgnoreCase)) @@ -796,11 +795,6 @@ private void GetAttributeIndentation(BaseMarkupStartTagSyntax startTag, out int } } - public override LineInfo VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) - { - return VisitEndTag(node); - } - public override LineInfo VisitMarkupTransition(MarkupTransitionSyntax node) { // A transition to Html means the start of a RenderFragment. These are challenging because conceptually diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/HtmlFormattingPass.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/HtmlFormattingPass.cs index af8ad21b570..7f667d39e8f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/HtmlFormattingPass.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/Passes/HtmlFormattingPass.cs @@ -268,7 +268,9 @@ private static (ImmutableArray ScriptAndStyleSpans, ImmutableArray ScriptAndStyleSpans, ImmutableArray", then the contents end at the start of the line, so // we are free to modify the whitespace in front of the end tag. If the last line is " foo();" // however, then we want the Html formatter to be in charge of the whitespace, so the contents end at the "f"; - var endTagLine = sourceText.Lines.GetLineFromPosition(element.EndTag.SpanStart); + var endTagLine = sourceText.Lines.GetLineFromPosition(endTag.SpanStart); var firstNonWhitespace = endTagLine.GetFirstNonWhitespacePosition(); - var end = firstNonWhitespace == element.EndTag.SpanStart + var end = firstNonWhitespace == endTag.SpanStart ? endTagLine.Start : firstNonWhitespace.GetValueOrDefault() + 1; - scriptStyleBuilder.Add(TextSpan.FromBounds(element.StartTag.EndPosition, end)); + scriptStyleBuilder.Add(TextSpan.FromBounds(startTag.EndPosition, end)); } else if (node is RazorCommentBlockSyntax comment && comment.GetLinePositionSpan(codeDocument.Source).SpansMultipleLines()) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LinkedEditingRange/LinkedEditingRangeHelper.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LinkedEditingRange/LinkedEditingRangeHelper.cs index 655729f714b..74d344cd27b 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LinkedEditingRange/LinkedEditingRangeHelper.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LinkedEditingRange/LinkedEditingRangeHelper.cs @@ -57,24 +57,14 @@ private static bool TryGetNearestMarkupNameTokens( return false; } - switch (element) + if (element is BaseMarkupElementSyntax { StartTag: var startTag, EndTag: var endTag }) { - // Tag helper - case MarkupTagHelperElementSyntax { StartTag: var startTag, EndTag: var endTag }: - startTagNameToken = startTag?.Name ?? default; - endTagNameToken = endTag?.Name ?? default; + startTagNameToken = startTag?.Name ?? default; + endTagNameToken = endTag?.Name ?? default; - return startTagNameToken.IsValid() && endTagNameToken.IsValid(); - - // HTML - case MarkupElementSyntax { StartTag: var startTag, EndTag: var endTag }: - startTagNameToken = startTag?.Name ?? default; - endTagNameToken = endTag?.Name ?? default; - - return startTagNameToken.IsValid() && endTagNameToken.IsValid(); - - default: - throw new InvalidOperationException("Element is expected to be a MarkupTagHelperElement or MarkupElement."); + return startTagNameToken.IsValid() && endTagNameToken.IsValid(); } + + throw new InvalidOperationException("Element is expected to be a MarkupTagHelperElement or MarkupElement."); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorSyntaxFacts.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorSyntaxFacts.cs index ed90d0f6bda..81f037ae994 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorSyntaxFacts.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorSyntaxFacts.cs @@ -198,7 +198,7 @@ internal static bool IsInUsingDirective(RazorSyntaxNode node) return node.AncestorsAndSelf().OfType().Any(); } - internal static bool IsScriptOrStyleBlock(MarkupElementSyntax? element) + internal static bool IsScriptOrStyleBlock(BaseMarkupElementSyntax? element) { // StartTag is annotated as not nullable, but on invalid documents it can be. The 'Format_DocumentWithDiagnostics' test // illustrates this. diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SpellCheck/SpellCheckService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SpellCheck/SpellCheckService.cs index d09ba4722d4..6cd7c0b99fa 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SpellCheck/SpellCheckService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SpellCheck/SpellCheckService.cs @@ -49,7 +49,7 @@ private static void AddRazorSpellCheckRanges(ref PooledArrayBuilder n is not MarkupElementSyntax { StartTag.Name.Content: "script" or "style" })) + foreach (var node in syntaxTree.Root.DescendantNodes(static n => n is not BaseMarkupElementSyntax element || !RazorSyntaxFacts.IsScriptOrStyleBlock(element))) { if (node is RazorCommentBlockSyntax commentBlockSyntax) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/TagHelperFacts.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/TagHelperFacts.cs index 1c3b53a4363..bb25e25d17f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/TagHelperFacts.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/TagHelperFacts.cs @@ -196,21 +196,11 @@ public static (string? ancestorTagName, bool ancestorIsTagHelper) GetNearestAnce { foreach (var ancestor in ancestors) { - switch (ancestor) + if (ancestor is BaseMarkupElementSyntax { StartTag: var startTag }) { - case MarkupElementSyntax { StartTag: var startTag }: - { - // It's possible for start tag to be null in malformed cases. - var name = startTag?.Name.Content ?? string.Empty; - return (name, ancestorIsTagHelper: false); - } - - case MarkupTagHelperElementSyntax { StartTag: var startTag }: - { - // It's possible for start tag to be null in malformed cases. - var name = startTag?.Name.Content ?? string.Empty; - return (name, ancestorIsTagHelper: true); - } + // It's possible for start tag to be null in malformed cases. + var name = startTag?.Name.Content ?? string.Empty; + return (name, ancestorIsTagHelper: ancestor is MarkupTagHelperElementSyntax); } } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.Test/Formatting/DocumentFormattingTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.Test/Formatting/DocumentFormattingTest.cs index 64f6a2f29f0..f97c2a89696 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.Test/Formatting/DocumentFormattingTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.CohostingShared.Test/Formatting/DocumentFormattingTest.cs @@ -12242,6 +12242,151 @@ @using System """, validateHtmlFormattedMatchesWebTools: false); + [Theory] + [CombinatorialData] + public Task ScriptTagTagHelper(bool scriptTagHelper) + { + var directive = scriptTagHelper + ? "@addTagHelper *, SomeProject" + : ""; + return RunFormattingTestAsync( + input: $$""" + {{directive}} + + + """, + htmlFormatted: $$""" + {{directive}} + + + """, + expected: $$""" + {{directive}} + + + """, + validateHtmlFormattedMatchesWebTools: false, // We don't have JS formatting in tests, so the method param wouldn't really move + fileKind: RazorFileKind.Legacy, + additionalFiles: + [ + (FilePath("ScriptTagHelper.cs"), """ + using Microsoft.AspNetCore.Razor.TagHelpers; + + [HtmlTargetElement("script")] + public class ScriptTagHelper : TagHelper + { + } + """) + ]); + } + + [Theory] + [CombinatorialData] + public Task VoidTagTagHelper(bool useTagHelper) + { + var directive = useTagHelper + ? "@addTagHelper *, SomeProject" + : ""; + return RunFormattingTestAsync( + input: $$""" + {{directive}} + +
+ + This shouldn't be indented. + + + Neither should this +
+ """, + htmlFormatted: $$""" + {{directive}} + +
+ + This shouldn't be indented. + + + Neither should this +
+ """, + expected: $$""" + {{directive}} + +
+ + This shouldn't be indented. + + + Neither should this +
+ """, + validateHtmlFormattedMatchesWebTools: false, + fileKind: RazorFileKind.Legacy, + additionalFiles: + [ + (FilePath("InputTagHelper.cs"), """ + using Microsoft.AspNetCore.Razor.TagHelpers; + + [HtmlTargetElement("input")] + public class InputTagHelper : TagHelper + { + } + """) + ]); + } + private static RazorCSharpSyntaxFormattingOptions GetNewLineBeforeBraceInLambdaExpressionOptions(bool newLineBeforeBraceInLambda) => RazorCSharpSyntaxFormattingOptions.Default with {