Esempio n. 1
0
        protected override void CollectBlockSpans(
            TypeDeclarationSyntax typeDeclaration,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            CSharpStructureHelpers.CollectCommentBlockSpans(
                typeDeclaration,
                ref spans,
                optionProvider
                );

            if (
                !typeDeclaration.OpenBraceToken.IsMissing &&
                !typeDeclaration.CloseBraceToken.IsMissing
                )
            {
                var lastToken =
                    typeDeclaration.TypeParameterList == null
                        ? typeDeclaration.Identifier
                        : typeDeclaration.TypeParameterList.GetLastToken(includeZeroWidth: true);

                SyntaxNodeOrToken current = typeDeclaration;
                var nextSibling           = current.GetNextSibling();

                // Check IsNode to compress blank lines after this node if it is the last child of the parent.
                //
                // Collapse to Definitions doesn't collapse type nodes, but a Toggle All Outlining would collapse groups
                // of types to the compressed form of not showing blank lines. All kinds of types are grouped together
                // in Metadata as Source.
                var compressEmptyLines =
                    optionProvider.IsMetadataAsSource &&
                    (!nextSibling.IsNode || nextSibling.AsNode() is BaseTypeDeclarationSyntax);

                spans.AddIfNotNull(
                    CSharpStructureHelpers.CreateBlockSpan(
                        typeDeclaration,
                        lastToken,
                        compressEmptyLines: compressEmptyLines,
                        autoCollapse: false,
                        type: BlockTypes.Type,
                        isCollapsible: true
                        )
                    );
            }

            // add any leading comments before the end of the type block
            if (!typeDeclaration.CloseBraceToken.IsMissing)
            {
                var leadingTrivia = typeDeclaration.CloseBraceToken.LeadingTrivia;
                CSharpStructureHelpers.CollectCommentBlockSpans(leadingTrivia, ref spans);
            }
        }
 protected override void CollectBlockSpans(
     SwitchStatementSyntax node,
     ref TemporaryArray <BlockSpan> spans,
     BlockStructureOptionProvider optionProvider,
     CancellationToken cancellationToken)
 {
     spans.Add(new BlockSpan(
                   isCollapsible: true,
                   textSpan: TextSpan.FromBounds((node.CloseParenToken != default) ? node.CloseParenToken.Span.End : node.Expression.Span.End, node.CloseBraceToken.Span.End),
                   hintSpan: node.Span,
                   type: BlockTypes.Conditional));
 }
        protected override void CollectBlockSpans(
            InitializerExpressionSyntax node,
            ArrayBuilder <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken)
        {
            if (node.Parent is InitializerExpressionSyntax)
            {
                // We have something like:
                //
                //      new Dictionary<int, string>
                //      {
                //          ...
                //          {
                //              ...
                //          },
                //          ...
                //      }
                //
                //  In this case, we want to collapse the "{ ... }," (including the comma).

                var nextToken = node.CloseBraceToken.GetNextToken();
                var end       = nextToken.Kind() == SyntaxKind.CommaToken
                    ? nextToken.Span.End
                    : node.Span.End;

                spans.Add(new BlockSpan(
                              isCollapsible: true,
                              textSpan: TextSpan.FromBounds(node.SpanStart, end),
                              hintSpan: TextSpan.FromBounds(node.SpanStart, end),
                              type: BlockTypes.Expression));
            }
            else
            {
                // Parent is something like:
                //
                //      new Dictionary<int, string> {
                //          ...
                //      }
                //
                // The collapsed textspan should be from the   >   to the   }
                //
                // However, the hint span should be the entire object creation.

                var previousToken = node.OpenBraceToken.GetPreviousToken();
                spans.Add(new BlockSpan(
                              isCollapsible: true,
                              textSpan: TextSpan.FromBounds(previousToken.Span.End, node.Span.End),
                              hintSpan: node.Parent.Span,
                              type: BlockTypes.Expression));
            }
        }
 protected override void CollectBlockSpans(
     EventFieldDeclarationSyntax eventFieldDeclaration,
     ref TemporaryArray <BlockSpan> spans,
     BlockStructureOptionProvider optionProvider,
     CancellationToken cancellationToken
     )
 {
     CSharpStructureHelpers.CollectCommentBlockSpans(
         eventFieldDeclaration,
         ref spans,
         optionProvider
         );
 }
Esempio n. 5
0
 protected override void CollectBlockSpans(
     SyntaxToken previousToken,
     ArrowExpressionClauseSyntax node,
     ref TemporaryArray <BlockSpan> spans,
     BlockStructureOptionProvider optionProvider,
     CancellationToken cancellationToken)
 {
     spans.Add(new BlockSpan(
                   isCollapsible: true,
                   textSpan: TextSpan.FromBounds(previousToken.Span.End, node.Parent.Span.End),
                   hintSpan: node.Parent.Span,
                   type: BlockTypes.Nonstructural,
                   autoCollapse: !node.IsParentKind(SyntaxKind.LocalFunctionStatement)));
 }
Esempio n. 6
0
        protected override void CollectBlockSpans(
            IndexerDeclarationSyntax indexerDeclaration,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            CSharpStructureHelpers.CollectCommentBlockSpans(
                indexerDeclaration,
                ref spans,
                optionProvider
                );

            // fault tolerance
            if (
                indexerDeclaration.AccessorList == null ||
                indexerDeclaration.AccessorList.IsMissing ||
                indexerDeclaration.AccessorList.OpenBraceToken.IsMissing ||
                indexerDeclaration.AccessorList.CloseBraceToken.IsMissing
                )
            {
                return;
            }

            SyntaxNodeOrToken current = indexerDeclaration;
            var nextSibling           = current.GetNextSibling();

            // Check IsNode to compress blank lines after this node if it is the last child of the parent.
            //
            // Indexers are grouped together with properties in Metadata as Source.
            var compressEmptyLines =
                optionProvider.IsMetadataAsSource &&
                (
                    !nextSibling.IsNode ||
                    nextSibling.IsKind(SyntaxKind.IndexerDeclaration) ||
                    nextSibling.IsKind(SyntaxKind.PropertyDeclaration)
                );

            spans.AddIfNotNull(
                CSharpStructureHelpers.CreateBlockSpan(
                    indexerDeclaration,
                    indexerDeclaration.ParameterList.GetLastToken(includeZeroWidth: true),
                    compressEmptyLines: compressEmptyLines,
                    autoCollapse: true,
                    type: BlockTypes.Member,
                    isCollapsible: true
                    )
                );
        }
Esempio n. 7
0
        internal sealed override async Task<ImmutableArray<BlockSpan>> GetBlockSpansWorkerAsync(Document document, int position)
        {
            var root = await document.GetSyntaxRootAsync();
            var trivia = root.FindTrivia(position, findInsideTrivia: true);

            var outliner = CreateProvider();
            using var actualRegions = TemporaryArray<BlockSpan>.Empty;
            var optionProvider = new BlockStructureOptionProvider(
                document.Project.Solution.Options,
                isMetadataAsSource: document.Project.Solution.Workspace.Kind == CodeAnalysis.WorkspaceKind.MetadataAsSource);
            outliner.CollectBlockSpans(trivia, ref actualRegions.AsRef(), optionProvider, CancellationToken.None);

            // TODO: Determine why we get null outlining spans.
            return actualRegions.ToImmutableAndClear();
        }
Esempio n. 8
0
        internal sealed override async Task <ImmutableArray <BlockSpan> > GetBlockSpansWorkerAsync(
            Document document,
            int position
            )
        {
            var root = await document.GetSyntaxRootAsync(CancellationToken.None);

            var token = root.FindToken(position, findInsideTrivia: true);
            var node  = token.Parent.FirstAncestorOrSelf <TSyntaxNode>();

            Assert.NotNull(node);

            // We prefer ancestor nodes if the position is on the edge of the located node's span.
            while (node.Parent is TSyntaxNode)
            {
                if (
                    (position == node.SpanStart && position == node.Parent.SpanStart) ||
                    (position == node.Span.End && position == node.Parent.Span.End)
                    )
                {
                    node = (TSyntaxNode)node.Parent;
                }
                else
                {
                    break;
                }
            }

            var outliner = CreateProvider();

            using var actualRegions = TemporaryArray <BlockSpan> .Empty;
            var optionProvider = new BlockStructureOptionProvider(
                document.Project.Solution.Options,
                isMetadataAsSource: document.Project.Solution.Workspace.Kind
                == CodeAnalysis.WorkspaceKind.MetadataAsSource
                );

            outliner.CollectBlockSpans(
                node,
                ref actualRegions.AsRef(),
                optionProvider,
                CancellationToken.None
                );

            // TODO: Determine why we get null outlining spans.
            return(actualRegions.ToImmutableAndClear());
        }
Esempio n. 9
0
        protected override void CollectBlockSpans(
            ConversionOperatorDeclarationSyntax operatorDeclaration,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            CSharpStructureHelpers.CollectCommentBlockSpans(
                operatorDeclaration,
                ref spans,
                optionProvider
                );

            // fault tolerance
            if (
                operatorDeclaration.Body == null ||
                operatorDeclaration.Body.OpenBraceToken.IsMissing ||
                operatorDeclaration.Body.CloseBraceToken.IsMissing
                )
            {
                return;
            }

            SyntaxNodeOrToken current = operatorDeclaration;
            var nextSibling           = current.GetNextSibling();

            // Check IsNode to compress blank lines after this node if it is the last child of the parent.
            //
            // Whitespace between conversion operators is collapsed in Metadata as Source.
            var compressEmptyLines =
                optionProvider.IsMetadataAsSource &&
                (
                    !nextSibling.IsNode ||
                    nextSibling.IsKind(SyntaxKind.ConversionOperatorDeclaration)
                );

            spans.AddIfNotNull(
                CSharpStructureHelpers.CreateBlockSpan(
                    operatorDeclaration,
                    operatorDeclaration.ParameterList.GetLastToken(includeZeroWidth: true),
                    compressEmptyLines: compressEmptyLines,
                    autoCollapse: true,
                    type: BlockTypes.Member,
                    isCollapsible: true
                    )
                );
        }
Esempio n. 10
0
        protected override void CollectBlockSpans(
            EnumDeclarationSyntax enumDeclaration,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            CSharpStructureHelpers.CollectCommentBlockSpans(
                enumDeclaration,
                ref spans,
                optionProvider
                );

            if (
                !enumDeclaration.OpenBraceToken.IsMissing &&
                !enumDeclaration.CloseBraceToken.IsMissing
                )
            {
                SyntaxNodeOrToken current = enumDeclaration;
                var nextSibling           = current.GetNextSibling();

                // Check IsNode to compress blank lines after this node if it is the last child of the parent.
                //
                // Whitespace between type declarations is collapsed in Metadata as Source.
                var compressEmptyLines =
                    optionProvider.IsMetadataAsSource &&
                    (!nextSibling.IsNode || nextSibling.AsNode() is BaseTypeDeclarationSyntax);

                spans.AddIfNotNull(
                    CSharpStructureHelpers.CreateBlockSpan(
                        enumDeclaration,
                        enumDeclaration.Identifier,
                        compressEmptyLines: compressEmptyLines,
                        autoCollapse: false,
                        type: BlockTypes.Member,
                        isCollapsible: true
                        )
                    );
            }

            // add any leading comments before the end of the type block
            if (!enumDeclaration.CloseBraceToken.IsMissing)
            {
                var leadingTrivia = enumDeclaration.CloseBraceToken.LeadingTrivia;
                CSharpStructureHelpers.CollectCommentBlockSpans(leadingTrivia, ref spans);
            }
        }
Esempio n. 11
0
 protected override void CollectBlockSpans(
     LiteralExpressionSyntax node,
     ref TemporaryArray <BlockSpan> spans,
     BlockStructureOptionProvider optionProvider,
     CancellationToken cancellationToken)
 {
     if (node.IsKind(SyntaxKind.StringLiteralExpression) &&
         !node.ContainsDiagnostics)
     {
         spans.Add(new BlockSpan(
                       isCollapsible: true,
                       textSpan: node.Span,
                       hintSpan: node.Span,
                       type: BlockTypes.Expression,
                       autoCollapse: true,
                       isDefaultCollapsed: false));
     }
 }
Esempio n. 12
0
        protected override void CollectBlockSpans(
            AccessorDeclarationSyntax accessorDeclaration,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            CSharpStructureHelpers.CollectCommentBlockSpans(
                accessorDeclaration,
                ref spans,
                optionProvider
                );

            // fault tolerance
            if (
                accessorDeclaration.Body == null ||
                accessorDeclaration.Body.OpenBraceToken.IsMissing ||
                accessorDeclaration.Body.CloseBraceToken.IsMissing
                )
            {
                return;
            }

            SyntaxNodeOrToken current = accessorDeclaration;
            var nextSibling           = current.GetNextSibling();

            // Check IsNode to compress blank lines after this node if it is the last child of the parent.
            //
            // All accessor kinds are grouped together in Metadata as Source.
            var compressEmptyLines =
                optionProvider.IsMetadataAsSource &&
                (!nextSibling.IsNode || nextSibling.AsNode() is AccessorDeclarationSyntax);

            spans.AddIfNotNull(
                CSharpStructureHelpers.CreateBlockSpan(
                    accessorDeclaration,
                    accessorDeclaration.Keyword,
                    compressEmptyLines: compressEmptyLines,
                    autoCollapse: true,
                    type: BlockTypes.Member,
                    isCollapsible: true
                    )
                );
        }
        protected override void CollectBlockSpans(
            SyntaxToken previousToken,
            NamespaceDeclarationSyntax namespaceDeclaration,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken)
        {
            // add leading comments
            CSharpStructureHelpers.CollectCommentBlockSpans(namespaceDeclaration, ref spans, optionProvider);

            if (!namespaceDeclaration.OpenBraceToken.IsMissing &&
                !namespaceDeclaration.CloseBraceToken.IsMissing)
            {
                spans.AddIfNotNull(CSharpStructureHelpers.CreateBlockSpan(
                                       namespaceDeclaration,
                                       namespaceDeclaration.Name.GetLastToken(includeZeroWidth: true),
                                       compressEmptyLines: false,
                                       autoCollapse: false,
                                       type: BlockTypes.Namespace,
                                       isCollapsible: true));
            }

            // extern aliases and usings are outlined in a single region
            var externsAndUsings = Enumerable.Union <SyntaxNode>(namespaceDeclaration.Externs, namespaceDeclaration.Usings)
                                   .OrderBy(node => node.SpanStart)
                                   .ToList();

            // add any leading comments before the extern aliases and usings
            if (externsAndUsings.Count > 0)
            {
                CSharpStructureHelpers.CollectCommentBlockSpans(externsAndUsings.First(), ref spans, optionProvider);
            }

            spans.AddIfNotNull(CSharpStructureHelpers.CreateBlockSpan(
                                   externsAndUsings, compressEmptyLines: false, autoCollapse: true,
                                   type: BlockTypes.Imports, isCollapsible: true));

            // finally, add any leading comments before the end of the namespace block
            if (!namespaceDeclaration.CloseBraceToken.IsMissing)
            {
                CSharpStructureHelpers.CollectCommentBlockSpans(
                    namespaceDeclaration.CloseBraceToken.LeadingTrivia, ref spans);
            }
        }
Esempio n. 14
0
        protected override void CollectBlockSpans(
            CompilationUnitSyntax compilationUnit,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            CSharpStructureHelpers.CollectCommentBlockSpans(
                compilationUnit,
                ref spans,
                optionProvider
                );

            // extern aliases and usings are outlined in a single region
            var externsAndUsings = new List <SyntaxNode>();

            externsAndUsings.AddRange(compilationUnit.Externs);
            externsAndUsings.AddRange(compilationUnit.Usings);
            externsAndUsings.Sort((node1, node2) => node1.SpanStart.CompareTo(node2.SpanStart));

            spans.AddIfNotNull(
                CSharpStructureHelpers.CreateBlockSpan(
                    externsAndUsings,
                    compressEmptyLines: false,
                    autoCollapse: true,
                    type: BlockTypes.Imports,
                    isCollapsible: true
                    )
                );

            if (
                compilationUnit.Usings.Count > 0 ||
                compilationUnit.Externs.Count > 0 ||
                compilationUnit.Members.Count > 0 ||
                compilationUnit.AttributeLists.Count > 0
                )
            {
                CSharpStructureHelpers.CollectCommentBlockSpans(
                    compilationUnit.EndOfFileToken.LeadingTrivia,
                    ref spans
                    );
            }
        }
Esempio n. 15
0
        protected override void CollectBlockSpans(
            InterpolatedStringExpressionSyntax node,
            ArrayBuilder <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken)
        {
            if (node.StringStartToken.IsMissing ||
                node.StringEndToken.IsMissing)
            {
                return;
            }

            spans.Add(new BlockSpan(
                          isCollapsible: true,
                          textSpan: node.Span,
                          hintSpan: node.Span,
                          type: BlockTypes.Expression,
                          autoCollapse: true,
                          isDefaultCollapsed: false));
        }
        protected override void CollectBlockSpans(
            AnonymousMethodExpressionSyntax anonymousMethod,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            // fault tolerance
            if (
                anonymousMethod.Block.IsMissing ||
                anonymousMethod.Block.OpenBraceToken.IsMissing ||
                anonymousMethod.Block.CloseBraceToken.IsMissing
                )
            {
                return;
            }

            var lastToken = CSharpStructureHelpers.GetLastInlineMethodBlockToken(anonymousMethod);

            if (lastToken.Kind() == SyntaxKind.None)
            {
                return;
            }

            var startToken =
                anonymousMethod.ParameterList != null
                    ? anonymousMethod.ParameterList.GetLastToken(includeZeroWidth : true)
                    : anonymousMethod.DelegateKeyword;

            spans.AddIfNotNull(
                CSharpStructureHelpers.CreateBlockSpan(
                    anonymousMethod,
                    startToken,
                    lastToken,
                    compressEmptyLines: false,
                    autoCollapse: false,
                    type: BlockTypes.Expression,
                    isCollapsible: true
                    )
                );
        }
        protected override void CollectBlockSpans(
            SimpleLambdaExpressionSyntax lambdaExpression,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            // fault tolerance
            if (lambdaExpression.Body.IsMissing)
            {
                return;
            }

            if (
                !(lambdaExpression.Body is BlockSyntax lambdaBlock) ||
                lambdaBlock.OpenBraceToken.IsMissing ||
                lambdaBlock.CloseBraceToken.IsMissing
                )
            {
                return;
            }

            var lastToken = CSharpStructureHelpers.GetLastInlineMethodBlockToken(lambdaExpression);

            if (lastToken.Kind() == SyntaxKind.None)
            {
                return;
            }

            spans.AddIfNotNull(
                CSharpStructureHelpers.CreateBlockSpan(
                    lambdaExpression,
                    lambdaExpression.ArrowToken,
                    lastToken,
                    compressEmptyLines: false,
                    autoCollapse: false,
                    type: BlockTypes.Expression,
                    isCollapsible: true
                    )
                );
        }
Esempio n. 18
0
        protected override void CollectBlockSpans(
            RegionDirectiveTriviaSyntax regionDirective,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            var match = regionDirective.GetMatchingDirective(cancellationToken);

            if (match != null)
            {
                // Always auto-collapse regions for Metadata As Source. These generated files only have one region at
                // the top of the file, which has content like the following:
                //
                //   #region Assembly System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
                //   // C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1\System.Runtime.dll
                //   #endregion
                //
                // For other files, auto-collapse regions based on the user option.
                var autoCollapse =
                    optionProvider.IsMetadataAsSource ||
                    optionProvider.GetOption(
                        BlockStructureOptions.CollapseRegionsWhenCollapsingToDefinitions,
                        LanguageNames.CSharp
                        );

                spans.Add(
                    new BlockSpan(
                        isCollapsible: true,
                        textSpan: TextSpan.FromBounds(regionDirective.SpanStart, match.Span.End),
                        type: BlockTypes.PreprocessorRegion,
                        bannerText: GetBannerText(regionDirective),
                        autoCollapse: autoCollapse,
                        isDefaultCollapsed: !optionProvider.IsMetadataAsSource
                        )
                    );
            }
        }
Esempio n. 19
0
        protected override void CollectBlockSpans(
            DestructorDeclarationSyntax destructorDeclaration,
            ArrayBuilder <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken)
        {
            CSharpStructureHelpers.CollectCommentBlockSpans(destructorDeclaration, spans, optionProvider);

            // fault tolerance
            if (destructorDeclaration.Body == null ||
                destructorDeclaration.Body.OpenBraceToken.IsMissing ||
                destructorDeclaration.Body.CloseBraceToken.IsMissing)
            {
                return;
            }

            spans.AddIfNotNull(CSharpStructureHelpers.CreateBlockSpan(
                                   destructorDeclaration,
                                   destructorDeclaration.ParameterList.GetLastToken(includeZeroWidth: true),
                                   compressEmptyLines: false,
                                   autoCollapse: true,
                                   type: BlockTypes.Member,
                                   isCollapsible: true));
        }
        protected override void CollectBlockSpans(
            DocumentationCommentTriviaSyntax documentationComment,
            ArrayBuilder <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken)
        {
            var startPos = documentationComment.FullSpan.Start;

            // The trailing newline is included in XmlDocCommentSyntax, so we need to strip it.
            var endPos = documentationComment.SpanStart + documentationComment.ToString().TrimEnd().Length;

            var span = TextSpan.FromBounds(startPos, endPos);

            var bannerLength = optionProvider.GetOption(BlockStructureOptions.MaximumBannerLength, LanguageNames.CSharp);
            var bannerText   = CSharpSyntaxFacts.Instance.GetBannerText(
                documentationComment, bannerLength, cancellationToken);

            spans.Add(new BlockSpan(
                          isCollapsible: true,
                          textSpan: span,
                          type: BlockTypes.Comment,
                          bannerText: bannerText,
                          autoCollapse: true));
        }
Esempio n. 21
0
        protected override void CollectBlockSpans(
            BlockSyntax node,
            ref TemporaryArray <BlockSpan> spans,
            BlockStructureOptionProvider optionProvider,
            CancellationToken cancellationToken
            )
        {
            var parentKind = node.Parent.Kind();

            // For most types of statements, just consider the block 'attached' to the
            // parent node.  That means we'll show the parent node header when doing
            // things like hovering over the indent guide.
            //
            // This also works nicely as the close brace for these constructs will always
            // align with the start of these statements.
            if (IsNonBlockStatement(node.Parent) || parentKind == SyntaxKind.ElseClause)
            {
                var type = GetType(node.Parent);
                if (type != null)
                {
                    spans.Add(
                        new BlockSpan(
                            isCollapsible: true,
                            textSpan: GetTextSpan(node),
                            hintSpan: GetHintSpan(node),
                            type: type
                            )
                        );
                }
            }

            // Nested blocks aren't attached to anything.  Just collapse them as is.
            // Switch sections are also special.  Say you have the following:
            //
            //      case 0:
            //          {
            //
            //          }
            //
            // We don't want to consider the block parented by the case, because
            // that would cause us to draw the following:
            //
            //      case 0:
            //      |   {
            //      |
            //      |   }
            //
            // Which would obviously be wonky.  So in this case, we just use the
            // spanof the block alone, without consideration for the case clause.
            if (parentKind == SyntaxKind.Block || parentKind == SyntaxKind.SwitchSection)
            {
                var type = GetType(node.Parent);

                spans.Add(
                    new BlockSpan(
                        isCollapsible: true,
                        textSpan: node.Span,
                        hintSpan: node.Span,
                        type: type
                        )
                    );
            }
        }