Skip to content

Conversation

DustinCampbell
Copy link
Member

@DustinCampbell DustinCampbell commented May 8, 2025

This change is primarily about removing the Syntax.SyntaxListBuilder and Syntax.SyntaxListBuilder<T> from the compiler and replacing usages with PooledArrayBuilder<T>. This allows the compiler to use stack memory for small lists and only acquire pooled heap memory for larger lists.

In addition, I've made several other changes and some small refactorings along the way. In particular, I've introduced BaseMarkupStartTagSyntax and BaseMarkupEndTagSyntax types to share code between the normal markup tag syntax types and their tag helper variants.


CI Build: https://dev.azure.com/dnceng/internal/_build/results?buildId=2704937&view=results
Test Insertion: https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequest/635185
Toolset Test Run: https://dev.azure.com/dnceng/internal/_build/results?buildId=2704938&view=results#SourceCard

Add a handful of extension methods for PooledArrayBuidler<TNode> that facilitate constructing green syntax list nodes and red syntax lists.
This change includes fairly substantial refactoring of the methods on SyntaxUtilities, and changes all methods to use PooledArrayBuilder<T> rather than other collections.
This change updates the syntax API for Razor to add two abstract types:

- BaseMarkupStartTagSyntax - inherited by MarkupStartTagSyntax and MarkupTagHelperStartTagSyntax
- BaseMarkupEndTagSyntax - inherited by by MarkupEndTagSyntax and MarkupTagHelperEndTagSyntax

The IStartTagSyntaxNode and IEndTagSyntaxNode interfaces have been removed.
GreenNode.WriteTo(...) performs three loops for each node:

1. Find the first non-null slot index.
2. Find the last non-null slot index.
3. Loop from the last non-null slot index to the first non-null slow index and push non-null children.

These loops don't really perform any additional work, but the extra complexity doesn't add any value either.
Introduce SyntaxNode.DescendantTokens(...) to avoid building a string for each attribute's content just to check string.IsNullOrWhitespace.
@DustinCampbell DustinCampbell requested review from a team as code owners May 8, 2025 16:20
@davidwengier
Copy link
Member

I've introduced BaseMarkupStartTagSyntax and BaseMarkupEndTagSyntax

😍😍😍

Copy link
Member

@davidwengier davidwengier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Tooling changes are awesome

@@ -42,7 +41,7 @@ public async Task<ImmutableArray<RazorVSInternalCodeAction>> ProvideAsync(RazorC
// We also check for tag helper start tags here, because an invalid start tag with a valid tag helper
// anywhere in it would otherwise not match. We rely on the IsTagUnknown method below, to ensure we
// only offer on actual potential component tags (because it checks for the compiler diagnostic)
var startTag = (IStartTagSyntaxNode?)node.FirstAncestorOrSelf<SyntaxNode>(n => n is IStartTagSyntaxNode);
var startTag = node.FirstAncestorOrSelf<BaseMarkupStartTagSyntax>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! This is literally the dream I had when I created that interface. If only I'd known how, and was brave enough, to use the syntax generator :)

@chsienki chsienki self-requested a review May 8, 2025 22:52
@DustinCampbell DustinCampbell merged commit 42419be into main May 9, 2025
11 checks passed
@DustinCampbell DustinCampbell deleted the dev/dustinca/list-builders branch May 9, 2025 23:12
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone May 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants