| File: Structure\Syntax\AbstractBlockStructureProvider.cs | Web Access |
| Project: src\roslyn\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features) |
// Licensed to the .NET Foundation under one or more agreements. // 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.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Threading; namespace Microsoft.CodeAnalysis.Structure; /// <summary> /// Note: this type is for subclassing by the VB and C# provider only. /// It presumes that the language supports Syntax Trees. /// </summary> internal abstract class AbstractBlockStructureProvider : BlockStructureProvider { private static readonly IComparer<BlockSpan> s_blockSpanComparer = Comparer<BlockSpan>.Create(static (x, y) => y.TextSpan.Start.CompareTo(x.TextSpan.Start)); private readonly ImmutableDictionary<Type, ImmutableArray<AbstractSyntaxStructureProvider>> _nodeProviderMap; private readonly ImmutableDictionary<int, ImmutableArray<AbstractSyntaxStructureProvider>> _triviaProviderMap; protected AbstractBlockStructureProvider( ImmutableDictionary<Type, ImmutableArray<AbstractSyntaxStructureProvider>> defaultNodeOutlinerMap, ImmutableDictionary<int, ImmutableArray<AbstractSyntaxStructureProvider>> defaultTriviaOutlinerMap) { _nodeProviderMap = defaultNodeOutlinerMap; _triviaProviderMap = defaultTriviaOutlinerMap; } public override void ProvideBlockStructure(in BlockStructureContext context) { try { var syntaxRoot = context.SyntaxTree.GetRoot(context.CancellationToken); var initialContextCount = context.Spans.Count; BlockSpanCollector.CollectBlockSpans( syntaxRoot, context.Options, _nodeProviderMap, _triviaProviderMap, context.Spans, context.CancellationToken); // Sort descending, and keep track of the "last added line". // Then, ignore if we found a span on the same line. // The effect for this is if we have something like: // // M1(M2( // ... // ... // ) // // We only collapse the "inner" span which has larger start. context.Spans.Sort(initialContextCount, s_blockSpanComparer); var text = context.SyntaxTree.GetText(context.CancellationToken); BlockSpan? lastSpan = null; context.Spans.RemoveAll((span, index, _) => { // do not remove items before the first item that we added if (index < initialContextCount) return false; if (span.IsOverlappingBlockSpan(text.Lines, lastSpan)) return true; lastSpan = span; return false; }, arg: default(VoidResult)); } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable(); } } }