diff --git a/Src/CSharpier.Core/CSharp/SyntaxPrinter/SyntaxNodePrinters/CompilationUnit.cs b/Src/CSharpier.Core/CSharp/SyntaxPrinter/SyntaxNodePrinters/CompilationUnit.cs index a33f88ba8..57beb134f 100644 --- a/Src/CSharpier.Core/CSharp/SyntaxPrinter/SyntaxNodePrinters/CompilationUnit.cs +++ b/Src/CSharpier.Core/CSharp/SyntaxPrinter/SyntaxNodePrinters/CompilationUnit.cs @@ -29,9 +29,11 @@ public static Doc Print(CompilationUnitSyntax node, PrintingContext context) && previousList.Contents[^2] is HardLine ) { - while (list.Contents[0] is HardLine { SkipBreakIfFirstInGroup: true }) + var i = 0; + while (list.Contents[i] is HardLine { SkipBreakIfFirstInGroup: true }) { - list.Contents.RemoveAt(0); + list.Contents[i] = Doc.Null; + i++; } docs.Add(finalTrivia); diff --git a/Src/CSharpier.Core/CSharp/SyntaxPrinter/SyntaxNodePrinters/ExpressionStatement.cs b/Src/CSharpier.Core/CSharp/SyntaxPrinter/SyntaxNodePrinters/ExpressionStatement.cs index 3105835a9..4b6da5259 100644 --- a/Src/CSharpier.Core/CSharp/SyntaxPrinter/SyntaxNodePrinters/ExpressionStatement.cs +++ b/Src/CSharpier.Core/CSharp/SyntaxPrinter/SyntaxNodePrinters/ExpressionStatement.cs @@ -15,7 +15,7 @@ node.Expression is InvocationExpressionSyntax && concat.Contents[0] is LeadingComment ) { - concat.Contents.RemoveAt(concat.Contents.Count - 1); + concat.Contents[^1] = Doc.Null; semicolonLeadingTrivia = Doc.Concat(Doc.Indent(semicolonLeadingTrivia), Doc.HardLine); } diff --git a/Src/CSharpier.Core/CSharp/SyntaxPrinter/Token.cs b/Src/CSharpier.Core/CSharp/SyntaxPrinter/Token.cs index ad06443fd..399b662d9 100644 --- a/Src/CSharpier.Core/CSharp/SyntaxPrinter/Token.cs +++ b/Src/CSharpier.Core/CSharp/SyntaxPrinter/Token.cs @@ -237,7 +237,7 @@ private static Doc PrivatePrintLeadingTrivia( return Doc.Null; } - var docs = new List(); + var docs = new ValueListBuilder([null, null, null, null, null, null, null, null]); // we don't print any new lines until we run into a comment or directive // the PrintExtraNewLines method takes care of printing the initial new lines for a given node @@ -250,20 +250,20 @@ private static Doc PrivatePrintLeadingTrivia( if (printNewLines && kind == SyntaxKind.EndOfLineTrivia) { - if (docs.Count > 0 && docs[^1] == Doc.HardLineSkipBreakIfFirstInGroup) + if (docs.Length > 0 && docs[^1] == Doc.HardLineSkipBreakIfFirstInGroup) { printNewLines = false; } if ( !( - docs.Count > 1 + docs.Length > 1 && docs[^1] == Doc.HardLineSkipBreakIfFirstInGroup && docs[^2] is LeadingComment { Type: CommentType.SingleLine } ) ) { - docs.Add(Doc.HardLineSkipBreakIfFirstInGroup); + docs.Append(Doc.HardLineSkipBreakIfFirstInGroup); } } if (kind is not (SyntaxKind.EndOfLineTrivia or SyntaxKind.WhitespaceTrivia)) @@ -271,7 +271,7 @@ private static Doc PrivatePrintLeadingTrivia( printNewLines = true; } - void AddLeadingComment(CommentType commentType) + void AddLeadingComment(CommentType commentType, ref ValueListBuilder docs) { var comment = trivia.ToFullString().TrimEnd('\n', '\r'); if ( @@ -283,13 +283,13 @@ void AddLeadingComment(CommentType commentType) comment = leadingTrivia[x - 1] + comment; } - docs.Add(Doc.LeadingComment(comment, commentType)); + docs.Append(Doc.LeadingComment(comment, commentType)); } if (IsSingleLineComment(kind)) { - AddLeadingComment(CommentType.SingleLine); - docs.Add( + AddLeadingComment(CommentType.SingleLine, ref docs); + docs.Append( kind == SyntaxKind.SingleLineDocumentationCommentTrivia ? Doc.HardLineSkipBreakIfFirstInGroup : Doc.Null @@ -297,29 +297,29 @@ void AddLeadingComment(CommentType commentType) } else if (IsMultiLineComment(kind)) { - AddLeadingComment(CommentType.MultiLine); + AddLeadingComment(CommentType.MultiLine, ref docs); } else if (kind == SyntaxKind.DisabledTextTrivia) { - docs.Add(Doc.Trim, trivia.ToString()); + docs.Append(Doc.Trim, trivia.ToString()); } else if (IsRegion(kind)) { var triviaText = trivia.ToString(); - docs.Add(Doc.HardLineIfNoPreviousLine); - docs.Add(Doc.Trim); - docs.Add( + docs.Append(Doc.HardLineIfNoPreviousLine); + docs.Append(Doc.Trim); + docs.Append( kind == SyntaxKind.RegionDirectiveTrivia ? Doc.BeginRegion(triviaText) : Doc.EndRegion(triviaText) ); - docs.Add(Doc.HardLine); + docs.Append(Doc.HardLine); } else if (trivia.IsDirective) { var triviaText = trivia.ToString(); - docs.Add( + docs.Append( // adding two of these to ensure we get a new line when a directive follows a trailing comment Doc.HardLineIfNoPreviousLineSkipBreakIfFirstInGroup, Doc.HardLineIfNoPreviousLineSkipBreakIfFirstInGroup, @@ -337,16 +337,16 @@ void AddLeadingComment(CommentType commentType) ) { x++; - docs.Add(Doc.HardLineSkipBreakIfFirstInGroup); + docs.Append(Doc.HardLineSkipBreakIfFirstInGroup); } printNewLines = false; } } } - while (skipLastHardline && docs.Count != 0 && docs.Last() is HardLine or NullDoc) + while (skipLastHardline && docs.Length != 0 && docs[^1] is HardLine or NullDoc) { - docs.RemoveAt(docs.Count - 1); + docs.Pop(); } if (context.State.NextTriviaNeedsLine) @@ -362,7 +362,7 @@ void AddLeadingComment(CommentType commentType) } else { - var index = docs.Count - 1; + var index = docs.Length - 1; while ( index >= 0 && (docs[index] is HardLine or LeadingComment || docs[index] == Doc.Null) @@ -373,7 +373,7 @@ void AddLeadingComment(CommentType commentType) // this handles an edge case where we get here but already added the line // it relates to the fact that single line comments include new line directives if ( - index + 2 >= docs.Count + index + 2 >= docs.Length || !(docs[index + 1] is HardLine && docs[index + 2] is HardLine) ) { @@ -383,7 +383,7 @@ void AddLeadingComment(CommentType commentType) context.State.NextTriviaNeedsLine = false; } - return docs.Count > 0 ? Doc.Concat(docs) : Doc.Null; + return Doc.Concat(ref docs); } private static bool IsSingleLineComment(SyntaxKind kind) => diff --git a/Src/CSharpier.Core/Utilities/ValueListBuilder.cs b/Src/CSharpier.Core/Utilities/ValueListBuilder.cs index c02a71e7b..45931c328 100644 --- a/Src/CSharpier.Core/Utilities/ValueListBuilder.cs +++ b/Src/CSharpier.Core/Utilities/ValueListBuilder.cs @@ -90,18 +90,16 @@ private void AppendMultiChar(scoped ReadOnlySpan source) this.pos += source.Length; } - public void Insert(int index, scoped ReadOnlySpan source) + public void Insert(int index, T item) { - Debug.Assert(index == 0, "Implementation currently only supports index == 0"); - - if ((uint)(this.pos + source.Length) > (uint)this.span.Length) + if ((uint)(this.pos + 1) > (uint)this.span.Length) { - this.Grow(source.Length); + this.Grow(1); } - this.span[..this.pos].CopyTo(this.span[source.Length..]); - source.CopyTo(this.span); - this.pos += source.Length; + span[index..this.pos].CopyTo(this.span[(index + 1)..]); + this.span[index] = item; + this.pos += 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -142,6 +140,13 @@ private void AddWithResize(T item) this.pos = pos + 1; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Pop() + { + this.pos--; + return this.span[this.pos]; + } + public readonly ReadOnlySpan AsSpan() { return this.span[..this.pos];