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..2a5998057a64e 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureContext.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureContext.cs @@ -2,20 +2,22 @@ // 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; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Structure { - internal sealed class BlockStructureContext + [NonCopyable] + internal readonly struct 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 +26,7 @@ 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/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 7d0547a108f51..e560295d67091 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); } @@ -64,7 +63,7 @@ private static BlockStructureContext CreateContext( } private static BlockStructure GetBlockStructure( - BlockStructureContext context, + in BlockStructureContext context, ImmutableArray providers) { foreach (var provider in providers) @@ -73,16 +72,13 @@ private static BlockStructure GetBlockStructure( return CreateBlockStructure(context); } - private static BlockStructure CreateBlockStructure(BlockStructureContext context) + private static BlockStructure CreateBlockStructure(in 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..60d0f6d771fe5 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; @@ -30,7 +28,7 @@ protected AbstractBlockStructureProvider( _triviaProviderMap = defaultTriviaOutlinerMap; } - public override void ProvideBlockStructure(BlockStructureContext context) + public override void ProvideBlockStructure(in BlockStructureContext context) { try { @@ -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)) {