Skip to content

fix(document-symbols): unbounded MAP/MODULE scan corrupting the outline - #382

Open
geircodes wants to merge 2 commits into
msarson:version-1.0.1from
geircodes:fix/map-module-symbol-endless-lookahead
Open

fix(document-symbols): unbounded MAP/MODULE scan corrupting the outline#382
geircodes wants to merge 2 commits into
msarson:version-1.0.1from
geircodes:fix/map-module-symbol-endless-lookahead

Conversation

@geircodes

Copy link
Copy Markdown

Summary

Three document-symbol (outline) bugs found while auditing a real production .clw file's Document Structure (outline) panel for a WINDOW procedure — one of them significant beyond just that outline, since it silently corrupted symbol classification for the rest of the file once triggered.

  1. ClarionDocumentSymbolProvider.ts — unbounded MAP/MODULE lookahead. When the parser hits a MAP/MODULE structure, it scans forward to find shorthand procedure declarations, accepting an EndStatement as the structure's true end only if no Structure token had been seen since. A MODULE(...) nested inside a MAP is itself a Structure token, so once one appeared, that condition could never become true again — the scan ran unbounded through the rest of the file. Any later identifier immediately followed by ( (e.g. WINDOW attributes like FONT(...), VALUE(...), FROM(...)) got misclassified as a MAP/MODULE procedure and surfaced as a stray top-level outline entry, for every symbol after that point in the file — not just inside the offending WINDOW.

    Fix: bound the lookahead with the structure's own finishesAt, which the tokenizer already computes with correct nesting depth and which the rest of the codebase (e.g. MapProcedureResolver) already relies on — instead of re-deriving the end with the broken heuristic.

  2. DocumentStructure.ts — single-line structure declarations never got a label. handleStructureToken() computes endsOnSameLine for structures that open and close on one line (e.g. fq QUEUE(FILE:Queue) END) and returns early — before reaching the code further down that reads the preceding same-line token and assigns token.label. Multi-line structures worked fine; any single-line QUEUE/GROUP/etc. never got its declared name attached, so the outline showed a bare "QUEUE" node instead of "QUEUE (fq)".

    Fix: hoisted the label-assignment block (including the Language support: labeled LOOP and BREAK/CYCLE with label target #65 LOOP/ACCEPT special case) to run before the endsOnSameLine check, and removed the now-dead duplicate copy that used to sit after the early return.

  3. ClarionDocumentSymbolProvider.ts — redundant "in <Parent>" detail text. Every variable/method symbol got a detail of "in <ParentName>". This duplicates what's already shown by the tree hierarchy (both this provider's own outline consumers and VS Code's native Outline view), and is redundant even for its originally-intended breadcrumb-dropdown use case — a breadcrumb dropdown only ever lists siblings under one already-visible parent, so repeating that parent's name on every row adds nothing. WorkspaceSymbolProvider's flattened cross-file search — the one place parent context actually matters for disambiguation — already derives its own containerName from the symbol tree and never reads detail.

    Disabled (commented out, not deleted, for a cheap revert if some consumer turns out to need it) the three call sites that set this text.

Checked git history before writing (1) and (2): both bugs were introduced together, from scratch, in the single commit that created DocumentStructure.ts (#280) — not a regression of previously-correct behavior, and no existing helper elsewhere in the codebase does the same job that could have been reused instead.

Test plan

  • npx tsc -b — clean compile after each commit
  • Full test suite: 2340 passing, 0 failing, 4 pending (pre-existing, unrelated) — re-verified after every change in this PR
  • Verified directly against a real production .clw file (tokenizer + provider run outside the test suite): no stray FONT/VALUE/FROM entries, no bare QUEUE nodes, no "in X" detail text anywhere in the resulting symbol tree (1488 symbols checked)
  • Manually verified live in the running IDE after deploy (ClarionAssistant's Monaco "Document Structure" outline panel)

🤖 Generated with Claude Code

…tions

handleStructureToken() computed endsOnSameLine for structures that open and
close on one line (e.g. `fq QUEUE(FILE:Queue) END`) and returned early —
before reaching the code further down that reads the preceding same-line
token and assigns token.label. Multi-line structures worked fine; any
single-line QUEUE/GROUP/etc. never got its declared name attached, so the
outline showed a bare "QUEUE" node instead of "QUEUE (fq)".

Hoisted the label-assignment block (including the msarson#65 LOOP/ACCEPT special
case) to run before the endsOnSameLine check, and removed the now-dead
duplicate copy that used to sit after the early return.
…dant "in X" detail text

Two independent outline bugs found while auditing a WINDOW procedure's
document symbols:

1. The MAP/MODULE shorthand-procedure lookahead accepted an EndStatement as
   the structure's true end only if no Structure token had been seen since —
   but a MODULE nested inside a MAP is itself a Structure token, so that
   condition could never become true again once one appeared, and the scan
   ran unbounded through the rest of the file. Any later identifier
   immediately followed by "(" (e.g. WINDOW attributes like FONT(...),
   VALUE(...), FROM(...)) got misclassified as a MAP/MODULE procedure and
   surfaced as a stray top-level outline entry.

   Fix: bound the lookahead with the structure's own finishesAt, which the
   tokenizer already computes with correct nesting depth (and which the rest
   of the codebase, e.g. MapProcedureResolver, already relies on) — instead
   of re-deriving the end with the broken heuristic.

2. Every variable/method symbol got a `detail` of "in <ParentName>", which
   duplicates what's already shown by the tree hierarchy (both in this
   provider's own Monaco-based outline and VS Code's native Outline view),
   and is redundant even for its originally-intended breadcrumb-dropdown use
   case (a dropdown only ever lists siblings under one already-visible
   parent). WorkspaceSymbolProvider's flattened cross-file search — the one
   place where parent context actually matters — already derives its own
   containerName from the symbol tree and never reads `detail`.

   Disabled (commented out, not deleted, for a cheap revert) the three call
   sites that set this text.

Test plan:
- npx tsc -b — clean compile after each commit
- Full test suite: 2340 passing, 0 failing, 4 pending (pre-existing,
  unrelated) — re-verified after every change in this PR
- Verified directly against a real production .clw file: no stray
  FONT/VALUE/FROM entries, no bare QUEUE nodes, no "in X" detail text
  anywhere in the resulting symbol tree
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant