Nimblesite / Nimblesite/SharpLsp

F# folding: the `open` and `xml_doc` arms in collect_folding are dead code

Open
#219 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
132
Forks
5
Avg merge
6h 24m
Merged PRs (30d)
27

Description

Summary

src/sharplsp/src/syntax.rs collect_folding gained F# node kinds on PR #218. Two of the new match arms can never produce a fold:

// Comments: C# `comment`, F# `block_comment` ((* *)) and `xml_doc` (///) — multi-line only.
"comment" | "block_comment" | "xml_doc"
    if node.start_position().row != node.end_position().row => { ... }
// Using directives group (C# `using_directive`, F# `open`)
"using_directive" | "open" => Some(FoldingRangeKind::Imports),
1. "open" matches a keyword token, not a declaration node

In tree-sitter-fsharp 0.3.11 (fsharp/src/node-types.json), open is "named": false — it is the bare open keyword token. The F# import declaration node is import_decl ("named": true, one long_identifier child).

The open keyword token always spans exactly one line, so start.row < end.row in the emit guard is never true. The arm is unreachable in effect.

2. "xml_doc" never spans more than one line

The grammar emits one xml_doc node per /// line, so a multi-line doc block is N single-line nodes, and the start_position().row != end_position().row guard is never satisfied. The arm is dead too.

Reproduction

Adding to the fixture in test_folding_range_on_fsharp_file (src/sharplsp/tests/e2e_modules/folding.rs):

module M
open System
(* a multi-line
   block comment *)
/// Computes the area of a shape.
/// The doc block spans two lines, so it folds.
type Shape =
    ...

textDocument/foldingRange returns 4 ranges — three region folds and exactly one comment fold (the (* *) block, lines 2–3). There is no imports fold for open System and no comment fold for the two /// lines.

The existing assertion passes only because kinds.contains(&"comment") is satisfied by the (* *) block alone.

Expected

  • Consecutive /// (xml_doc) sibling nodes should merge into a single comment fold spanning the run — this is what Visual Studio / Rider / C# Dev Kit do for /// blocks, and F# is a first-class citizen (CLAUDE.md aim #2).
  • Consecutive import_decl (F#) / using_directive (C#) siblings should merge into a single imports fold. Note the C# side has the same latent problem: a one-line using X; also fails the start.row < end.row guard, so FoldingRangeKind::Imports is likely never emitted for either language today.

Both need sibling-run grouping in collect_folding, not just a node-kind rename.

Notes

Coverage does not catch this: the arms share instrumented lines with live arms, so the file reports 220/224 lines covered on both Linux CI and macOS.

Found while auditing PR #218's Rust coverage gate.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/sharplsp/src/syntax.rs at collect_folding and inspect how sibling nodes are traversed and folding ranges are emitted. Reproduce the behavior with the fixture in src/sharplsp/tests/e2e_modules/folding.rs, then extend coverage for consecutive xml_doc and import_decl/using_directive nodes. Done means consecutive documentation and import declarations produce the expected comment and imports ranges.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, rust
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.