From 0b630e2531a303789c79bb6274d3cf1552ad048a Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 9 Jun 2023 13:15:12 -0700 Subject: [PATCH 1/5] Reduce allocations in outlining in pathlogical files --- ...actCurlyBraceOrBracketCompletionService.cs | 1 + ...tringLiteralExpressionStructureProvider.cs | 22 ++++++++++++++++++- .../Structure/BlockStructureContext.cs | 20 +++++++++-------- .../BlockStructureServiceWithProviders.cs | 12 ++++------ .../Syntax/AbstractBlockStructureProvider.cs | 5 ++--- 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs index 35c0c380c932a..6c6c025708cb1 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; diff --git a/src/Features/CSharp/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.cs index b7c8cafa4d5d3..78b65b2fda29a 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Structure; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Structure { @@ -19,7 +20,8 @@ protected override void CollectBlockSpans( CancellationToken cancellationToken) { if (node.IsKind(SyntaxKind.StringLiteralExpression) && - !node.ContainsDiagnostics) + !node.ContainsDiagnostics && + CouldBeMultiLine()) { spans.Add(new BlockSpan( isCollapsible: true, @@ -29,6 +31,24 @@ protected override void CollectBlockSpans( autoCollapse: true, isDefaultCollapsed: false)); } + + return; + + bool CouldBeMultiLine() + { + if (node.Token.Kind() is SyntaxKind.MultiLineRawStringLiteralToken or SyntaxKind.Utf8MultiLineRawStringLiteralToken) + return true; + + if (node.Token.IsVerbatimStringLiteral()) + { + var span = node.Span; + var sourceText = node.SyntaxTree.GetText(cancellationToken); + return sourceText.Lines.GetLineFromPosition(span.Start).LineNumber != + sourceText.Lines.GetLineFromPosition(span.End).LineNumber; + } + + return false; + } } } } diff --git a/src/Features/Core/Portable/Structure/BlockStructureContext.cs b/src/Features/Core/Portable/Structure/BlockStructureContext.cs index 1a7315d8ef50f..dbdd5fc0cb97f 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureContext.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureContext.cs @@ -2,20 +2,20 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Immutable; using System.Threading; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Structure { - internal sealed class BlockStructureContext + internal sealed class BlockStructureContext : IDisposable { - private readonly ImmutableArray.Builder _spans = ImmutableArray.CreateBuilder(); + public readonly ArrayBuilder Spans = ArrayBuilder.GetInstance(); - public SyntaxTree SyntaxTree { get; } - public BlockStructureOptions Options { get; } - public CancellationToken CancellationToken { get; } - - internal ImmutableArray Spans => _spans.ToImmutable(); + public readonly SyntaxTree SyntaxTree; + public readonly BlockStructureOptions Options; + public readonly CancellationToken CancellationToken; public BlockStructureContext(SyntaxTree syntaxTree, BlockStructureOptions options, CancellationToken cancellationToken) { @@ -24,7 +24,9 @@ public BlockStructureContext(SyntaxTree syntaxTree, BlockStructureOptions option CancellationToken = cancellationToken; } - public void AddBlockSpan(BlockSpan span) - => _spans.Add(span); + public void Dispose() + { + Spans.Free(); + } } } diff --git a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs index 7d0547a108f51..15da11c57dd09 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs @@ -50,8 +50,7 @@ public override async Task GetBlockStructureAsync( CancellationToken cancellationToken) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var context = CreateContext(syntaxTree, options, cancellationToken); - + using var context = CreateContext(syntaxTree, options, cancellationToken); return GetBlockStructure(context, _providers); } @@ -75,14 +74,11 @@ private static BlockStructure GetBlockStructure( private static BlockStructure CreateBlockStructure(BlockStructureContext context) { - using var _ = ArrayBuilder.GetInstance(out var updatedSpans); + using var _ = ArrayBuilder.GetInstance(context.Spans.Count, out var updatedSpans); foreach (var span in context.Spans) - { - var updatedSpan = UpdateBlockSpan(span, context.Options); - updatedSpans.Add(updatedSpan); - } + updatedSpans.Add(UpdateBlockSpan(span, context.Options)); - return new BlockStructure(updatedSpans.ToImmutable()); + return new BlockStructure(updatedSpans.ToImmutableAndClear()); } private static BlockSpan UpdateBlockSpan(BlockSpan blockSpan, in BlockStructureOptions options) diff --git a/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs b/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs index dfa577a0ba675..3aa027c50be8a 100644 --- a/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs +++ b/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Threading.Tasks; @@ -39,8 +37,9 @@ public override void ProvideBlockStructure(BlockStructureContext context) BlockSpanCollector.CollectBlockSpans( syntaxRoot, context.Options, _nodeProviderMap, _triviaProviderMap, ref spans.AsRef(), context.CancellationToken); + context.Spans.EnsureCapacity(context.Spans.Count + spans.Count); foreach (var span in spans) - context.AddBlockSpan(span); + context.Spans.Add(span); } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) { From fd2b9e0d0806531bf7ccce18e2287c0149b27c80 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 9 Jun 2023 13:16:22 -0700 Subject: [PATCH 2/5] Simplify --- .../AbstractCurlyBraceOrBracketCompletionService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs index 6c6c025708cb1..35c0c380c932a 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; From 4c3a9b4b1a722b45e1e29a7529e19bc3701c9ea0 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 9 Jun 2023 13:17:30 -0700 Subject: [PATCH 3/5] Simplify --- .../Core/Portable/Structure/BlockStructureContext.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Features/Core/Portable/Structure/BlockStructureContext.cs b/src/Features/Core/Portable/Structure/BlockStructureContext.cs index dbdd5fc0cb97f..b42611f7399b9 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureContext.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureContext.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Structure { - internal sealed class BlockStructureContext : IDisposable + internal readonly struct BlockStructureContext : IDisposable { public readonly ArrayBuilder Spans = ArrayBuilder.GetInstance(); @@ -25,8 +25,6 @@ public BlockStructureContext(SyntaxTree syntaxTree, BlockStructureOptions option } public void Dispose() - { - Spans.Free(); - } + => Spans.Free(); } } From 72c4f690979d6aa7e1ef74f00677d0a3b1607097 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 9 Jun 2023 13:18:56 -0700 Subject: [PATCH 4/5] REf struct --- .../Core/Portable/Structure/BlockStructureContext.cs | 2 +- .../Structure/BlockStructureServiceWithProviders.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Features/Core/Portable/Structure/BlockStructureContext.cs b/src/Features/Core/Portable/Structure/BlockStructureContext.cs index b42611f7399b9..cccc17aaaba3c 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureContext.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureContext.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Structure { - internal readonly struct BlockStructureContext : IDisposable + internal readonly ref struct BlockStructureContext { public readonly ArrayBuilder Spans = ArrayBuilder.GetInstance(); diff --git a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs index 15da11c57dd09..61046206d83ba 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs @@ -50,8 +50,13 @@ public override async Task GetBlockStructureAsync( CancellationToken cancellationToken) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - using var context = CreateContext(syntaxTree, options, cancellationToken); - return GetBlockStructure(context, _providers); + return GetBlockStructureWorker(); + + BlockStructure GetBlockStructureWorker() + { + using var context = CreateContext(syntaxTree, options, cancellationToken); + return GetBlockStructure(context, _providers); + } } private static BlockStructureContext CreateContext( From ad342f095f0b91321bb5af0e0e0ce7b6d32d445b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 9 Jun 2023 13:36:03 -0700 Subject: [PATCH 5/5] Make noncopyable --- .../Portable/Structure/BlockStructureContext.cs | 4 +++- .../Portable/Structure/BlockStructureProvider.cs | 2 +- .../Structure/BlockStructureServiceWithProviders.cs | 13 ++++--------- .../Syntax/AbstractBlockStructureProvider.cs | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Features/Core/Portable/Structure/BlockStructureContext.cs b/src/Features/Core/Portable/Structure/BlockStructureContext.cs index cccc17aaaba3c..2a5998057a64e 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureContext.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureContext.cs @@ -6,10 +6,12 @@ using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Structure { - internal readonly ref struct BlockStructureContext + [NonCopyable] + internal readonly struct BlockStructureContext : IDisposable { public readonly ArrayBuilder Spans = ArrayBuilder.GetInstance(); diff --git a/src/Features/Core/Portable/Structure/BlockStructureProvider.cs b/src/Features/Core/Portable/Structure/BlockStructureProvider.cs index 05aea7498fd13..961167ecfc59d 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureProvider.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureProvider.cs @@ -6,6 +6,6 @@ namespace Microsoft.CodeAnalysis.Structure { internal abstract class BlockStructureProvider { - public abstract void ProvideBlockStructure(BlockStructureContext context); + public abstract void ProvideBlockStructure(in BlockStructureContext context); } } diff --git a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs index 61046206d83ba..e560295d67091 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs @@ -50,13 +50,8 @@ public override async Task GetBlockStructureAsync( CancellationToken cancellationToken) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - return GetBlockStructureWorker(); - - BlockStructure GetBlockStructureWorker() - { - using var context = CreateContext(syntaxTree, options, cancellationToken); - return GetBlockStructure(context, _providers); - } + using var context = CreateContext(syntaxTree, options, cancellationToken); + return GetBlockStructure(context, _providers); } private static BlockStructureContext CreateContext( @@ -68,7 +63,7 @@ private static BlockStructureContext CreateContext( } private static BlockStructure GetBlockStructure( - BlockStructureContext context, + in BlockStructureContext context, ImmutableArray providers) { foreach (var provider in providers) @@ -77,7 +72,7 @@ private static BlockStructure GetBlockStructure( return CreateBlockStructure(context); } - private static BlockStructure CreateBlockStructure(BlockStructureContext context) + private static BlockStructure CreateBlockStructure(in BlockStructureContext context) { using var _ = ArrayBuilder.GetInstance(context.Spans.Count, out var updatedSpans); foreach (var span in context.Spans) diff --git a/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs b/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs index 3aa027c50be8a..60d0f6d771fe5 100644 --- a/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs +++ b/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs @@ -28,7 +28,7 @@ protected AbstractBlockStructureProvider( _triviaProviderMap = defaultTriviaOutlinerMap; } - public override void ProvideBlockStructure(BlockStructureContext context) + public override void ProvideBlockStructure(in BlockStructureContext context) { try {