Skip to content

When nested folding ranges end on the same line, the outer range is incorrectly truncated #5750

Closed

Description

@FMorschel

Describe the bug
Switch case folding doesn't fold until the next case if a function has parameters that span multiple lines (I think that is the issue, but maybe something similar at least?).

To Reproduce
Add a file with this sample:

Future<void> f() async {
  switch (1) {
    case 1:
      print('something');

      someBigFunctionName(
        someReallyReallyLongNameHereSoItHasToSplit: 1234567,
      );
    case 2:
      print('another thing');
      print('yet another thing');
    case 3:
      print('more things');
  }
}

void someBigFunctionName({
  int? someReallyReallyLongNameHereSoItHasToSplit,
}) {}

Try to fold at case 1 and see that it doesn't fold someBigFunctionName.

Expected behavior
It folds someBigFunctionName.

Please complete the following information:

Workspace Environment
Dart Code extension: 3.121.20250930
Flutter extension: 3.121.20250930 (activated)

App: Visual Studio Code
App Host: desktop
Version: win 1.105.0

Workspace type: Dart (LSP)
Workspace name: bug

Dart (3.11.0-edge.1974c2360e1ee4345b9cb15929b1a2465559dc18): C:\Users\felip_0vh5fa6\dart
Flutter (3.35.5): C:\Users\felip_0vh5fa6\.puro\envs\stable\flutter (No device)

Output from 'dart info'

C:\Users\felip_0vh5fa6\dart\bin\dart.exe info

If providing this information as part of reporting a bug, please review the information
below to ensure it only contains things you're comfortable posting publicly.

General info

  • Dart 3.11.0-edge.1974c2360e1ee4345b9cb15929b1a2465559dc18 (main) (Mon Oct 6 18:46:13 2025 -0700) on "windows_x64"
  • on windows / "Windows 11 Pro" 10.0 (Build 26100)
  • locale is pt-BR

Project info

  • sdk constraint: '^3.9.0'
  • dependencies: analyzer, bloc, meta
  • dev_dependencies: lints, test, test_reflective_loader, very_good_analysis

Process info

Memory CPU Elapsed time Command line
0 MB -- dart.exe
0 MB -- dart.exe
0 MB -- dart.exe
0 MB -- dart.exe
0 MB -- dart.exe
0 MB -- dart.exe
0 MB -- dart.exe
0 MB -- dart.exe
0 MB -- dart.exe
0 MB -- dartvm.exe
0 MB -- dartvm.exe
0 MB -- dartvm.exe
0 MB -- dartvm.exe
  • Operating System and version:
  • VS Code version:
  • Dart extension version:
  • Dart/Flutter SDK version:
  • Target device (if the issue relates to Flutter debugging):

Activity

  1. FMorschel commented on Oct 13, 2025

    @FMorschel
    ContributorAuthor

    I've tried adding some tests to the same files you edited for https://dart-review.googlesource.com/c/sdk/+/431281, but I could not create a test that would fail even with the above example:

    pkg/analysis_server/test/src/computer/folding_computer_test.dart

      Future<void> test_switchCase() async {
        var content = '''
    Future<void> f/*[0*/(int i) async {
      switch (i) {/*[1*/
        case 1:/*[2*/
          print('something');
    
          someBigFunctionName(/*[3*/
            someReallyReallyLongNameHereSoItHasToSplit: 1234567,
          /*3]*/);/*2]*/
        default:/*[4*/
          break;/*4]*/
      }/*1]*/
    }/*0]*/
    
    void someBigFunctionName/*[5*/({
      /*[6*/int? someReallyReallyLongNameHereSoItHasToSplit,
    }/*6]*/) {}/*5]*/
    ''';
        await _computeRegions(content);
        expectRegions({
          0: FoldingKind.FUNCTION_BODY,
          1: FoldingKind.BLOCK,
          2: FoldingKind.BLOCK,
          3: FoldingKind.INVOCATION,
          4: FoldingKind.BLOCK,
          5: FoldingKind.FUNCTION_BODY,
          6: FoldingKind.PARAMETERS,
        });
      }

    pkg/analysis_server/test/lsp/folding_test.dart

      Future<void> test_switchCase() async {
        var content = '''
    Future<void> f/*[0*/(int i) async {
      switch (i) {/*[1*/
        case 1:/*[2*/
          print('something');
    
          someBigFunctionName(/*[3*/
            someReallyReallyLongNameHereSoItHasToSplit: 1234567,
          /*3]*/);/*2]*/
        default:/*[4*/
          break;/*4]*/
      }/*1]*/
    }/*0]*/
    
    void someBigFunctionName/*[5*/({
      /*[6*/int? someReallyReallyLongNameHereSoItHasToSplit,
    }/*6]*/) {}/*5]*/
    ''';
        await _computeRegions(content);
        expectRegions({
          0: FoldingKind.FUNCTION_BODY,
          1: FoldingKind.BLOCK,
          2: FoldingKind.BLOCK,
          3: FoldingKind.INVOCATION,
          4: FoldingKind.BLOCK,
          5: FoldingKind.FUNCTION_BODY,
          6: FoldingKind.PARAMETERS,
        });
      }
  2. DanTup commented on Oct 14, 2025

    @DanTup
    Member

    @FMorschel I think the second test you pasted is incorrect (just the same as the first?) and doesn't compile.

    My first guess would be that this is related to line folding.. After computing the folding ranges, we have to do some work to merge/exclude some if the client only supports line-folding (which VS Code does) - see _compensateForLineFolding. If it is, I think it's a bug though, because on the surface I don't see why we wouldn't produce the outer range as you'd expect.

  3. added
    in editorRelates to code editing or language features
    in lsp/analysis serverSomething to be fixed in the Dart analysis server
    on Oct 14, 2025
  4. DanTup commented on Oct 14, 2025

    @DanTup
    Member

    (I assume you're looking at this, but if you want me to, just let me know!)

  5. FMorschel commented on Oct 14, 2025

    @FMorschel
    ContributorAuthor

    I ran both tests locally, and they passed. I'm not sure what you meant.

    One thing I noticed was, if you close that section and reload the VS Code window (Developer: Reload Window), it shows as fully folded until the extension and server start. At that point, it automatically moves out the invocation outside the folded region.

    I tried looking at this, yes, but since I had no luck reproducing on a test, you may have a better chance of figuring this one out, so please continue this, but feel free to ask for more guidance if you need any. Or if you're having trouble reproducing this.

  6. DanTup commented on Oct 14, 2025

    @DanTup
    Member

    I ran both tests locally, and they passed. I'm not sure what you meant.

    I think you copied the same test twice into your comment above - the one you marked as LSP doesn't compile in the LSP file.

    But if you're not looking at it, I'm happy to look, thanks!

  7. FMorschel commented on Oct 14, 2025

    @FMorschel
    ContributorAuthor

    Oh, yeah, that's probably it hahaha. Here is the correct test:

      Future<void> test_switchPattern_2() async {
        var content = '''
    Future<void> f(int i) async {
      switch (i) {/*[0*/
        case 1:/*[1*/
          print('something');
    
          someBigFunctionName(/*[2*/
            someReallyReallyLongNameHereSoItHasToSplit: 1234567,
          /*2]*/);/*1]*/
        default:/*[3*/
          break;/*3]*/
      }/*0]*/
    }
    
    void someBigFunctionName({
      int? someReallyReallyLongNameHereSoItHasToSplit,
    }) {}
    ''';
    
        await computeRanges(content);
        expectRanges({
          0: noFoldingKind,
          1: noFoldingKind,
          2: noFoldingKind,
          3: noFoldingKind,
        }, requireAll: false);
      }
  8. changed the title [-]Switch case folding doesn't fold until the next `case`[/-] [+]When nested folding ranges end on the same line, the outer range is incorrectly truncated[/+] on Oct 14, 2025
  9. added
    relies on sdk changesSomething that requires changes in the Dart/Flutter SDK to ship before it will become available
    on Oct 14, 2025
  10. DanTup commented on Oct 14, 2025

    @DanTup
    Member

    Off-by-one error 😐

    Got a fix at https://dart-review.googlesource.com/c/sdk/+/454920

    folding.mp4
  11. added this to the v3.122.0 milestone on Oct 16, 2025
  12. DanTup commented on Oct 16, 2025

    @DanTup
    Member

    Fixed by dart-lang/sdk@ceb6b5f, ships in the SDK :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    in editorRelates to code editing or language featuresin lsp/analysis serverSomething to be fixed in the Dart analysis serveris bugrelies on sdk changesSomething that requires changes in the Dart/Flutter SDK to ship before it will become available

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions