| File: Structure\BlockStructureServiceWithProviders.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. #nullable disable using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.Structure; internal abstract class BlockStructureServiceWithProviders : BlockStructureService { private readonly SolutionServices _services; private readonly ImmutableArray<BlockStructureProvider> _providers; protected BlockStructureServiceWithProviders(SolutionServices services) { _services = services; _providers = [.. GetBuiltInProviders(), .. GetImportedProviders()]; } /// <summary> /// Returns the providers always available to the service. /// This does not included providers imported via MEF composition. /// </summary> protected virtual ImmutableArray<BlockStructureProvider> GetBuiltInProviders() => []; private ImmutableArray<BlockStructureProvider> GetImportedProviders() { var language = Language; var mefExporter = _services.ExportProvider; var providers = mefExporter.GetExports<BlockStructureProvider, LanguageMetadata>() .Where(lz => lz.Metadata.Language == language) .Select(lz => lz.Value); return [.. providers]; } public override async Task<BlockStructure> GetBlockStructureAsync( Document document, BlockStructureOptions options, CancellationToken cancellationToken) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); using var context = CreateContext(syntaxTree, options, cancellationToken); return GetBlockStructure(context, _providers); } private static BlockStructureContext CreateContext( SyntaxTree syntaxTree, in BlockStructureOptions options, CancellationToken cancellationToken) { return new BlockStructureContext(syntaxTree, options, cancellationToken); } private static BlockStructure GetBlockStructure( in BlockStructureContext context, ImmutableArray<BlockStructureProvider> providers) { foreach (var provider in providers) provider.ProvideBlockStructure(context); return CreateBlockStructure(context); } private static BlockStructure CreateBlockStructure(in BlockStructureContext context) { for (var i = 0; i < context.Spans.Count; i++) context.Spans[i] = UpdateBlockSpan(context.Spans[i], context.Options); return new BlockStructure(context.Spans.ToImmutable()); } private static BlockSpan UpdateBlockSpan(BlockSpan blockSpan, in BlockStructureOptions options) { var type = blockSpan.Type; var isTopLevel = BlockTypes.IsDeclarationLevelConstruct(type); var isMemberLevel = BlockTypes.IsCodeLevelConstruct(type); var isComment = BlockTypes.IsCommentOrPreprocessorRegion(type); if ((!options.ShowBlockStructureGuidesForDeclarationLevelConstructs && isTopLevel) || (!options.ShowBlockStructureGuidesForCodeLevelConstructs && isMemberLevel) || (!options.ShowBlockStructureGuidesForCommentsAndPreprocessorRegions && isComment)) { type = BlockTypes.Nonstructural; } var isCollapsible = blockSpan.IsCollapsible; if (isCollapsible) { if ((!options.ShowOutliningForDeclarationLevelConstructs && isTopLevel) || (!options.ShowOutliningForCodeLevelConstructs && isMemberLevel) || (!options.ShowOutliningForCommentsAndPreprocessorRegions && isComment)) { isCollapsible = false; } } return blockSpan.With(type: type, isCollapsible: isCollapsible); } }