From 979d7a93934c96fa9d8f87845860c58e90ae0b0d Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Tue, 9 Jun 2026 18:50:16 +0200 Subject: [PATCH] Wrap the highlighting span guard in a using scope WriteKeyword/WritePrimitiveType/WriteIdentifier/WritePrimitiveValue each ended with the same begin-span / base-write / end-span guard. Replace it with `using (Colored(color)) base.WriteX(...)`, backed by an allocation-free ref-struct scope so the per-token hot path takes no closure. Assisted-by: Claude:claude-opus-4-8:Claude Code --- .../CSharpHighlightingTokenWriter.cs | 60 ++++++++----------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/ILSpy/Languages/CSharpHighlightingTokenWriter.cs b/ILSpy/Languages/CSharpHighlightingTokenWriter.cs index 0d39e159d..8df5552e1 100644 --- a/ILSpy/Languages/CSharpHighlightingTokenWriter.cs +++ b/ILSpy/Languages/CSharpHighlightingTokenWriter.cs @@ -291,15 +291,8 @@ namespace ILSpy.Languages } if (nodeStack.PeekOrDefault() is AttributeSection) color = attributeKeywordsColor; - if (color != null) - { - BeginSpan(color); - } - base.WriteKeyword(role, keyword); - if (color != null) - { - EndSpan(); - } + using (Colored(color)) + base.WriteKeyword(role, keyword); } public override void WritePrimitiveType(string type) @@ -340,15 +333,8 @@ namespace ILSpy.Languages color = referenceTypeKeywordsColor; break; } - if (color != null) - { - BeginSpan(color); - } - base.WritePrimitiveType(type); - if (color != null) - { - EndSpan(); - } + using (Colored(color)) + base.WritePrimitiveType(type); } public override void WriteIdentifier(Identifier identifier) @@ -424,15 +410,8 @@ namespace ILSpy.Languages color = eventAccessColor; break; } - if (color != null) - { - BeginSpan(color); - } - base.WriteIdentifier(identifier); - if (color != null) - { - EndSpan(); - } + using (Colored(color)) + base.WriteIdentifier(identifier); } void ApplyTypeColor(IType? type, ref HighlightingColor? color) @@ -468,15 +447,8 @@ namespace ILSpy.Languages { color = trueKeywordColor; } - if (color != null) - { - BeginSpan(color); - } - base.WritePrimitiveValue(value, format); - if (color != null) - { - EndSpan(); - } + using (Colored(color)) + base.WritePrimitiveValue(value, format); } ISymbol? GetCurrentDefinition() @@ -539,6 +511,22 @@ namespace ILSpy.Languages readonly ILocatable? locatable; readonly ISmartTextOutput? textOutput; + // Wraps a base WriteX call so its output lands inside a highlighting span for the given colour + // (or no span when null) -- replacing the begin/end guard each WriteX override used to repeat. + // A ref struct + the using pattern keeps this allocation-free on the per-token hot path. + ColorScope Colored(HighlightingColor? color) + { + if (color == null) + return default; + BeginSpan(color); + return new ColorScope(this); + } + + ref struct ColorScope(CSharpHighlightingTokenWriter? writer) + { + public void Dispose() => writer?.EndSpan(); + } + private void BeginSpan(HighlightingColor highlightingColor) { if (textOutput != null)