Skip to content

fix(diagnostics): flag a deleted package declaration on live edit - #323

Merged
Hessesian merged 2 commits into
mainfrom
fix/debounced-missing-package-diagnostic
Sep 22, 2026
Merged

Hessesian merged 2 commits into
mainfrom
fix/debounced-missing-package-diagnostic

Conversation

@Hessesian

Copy link
Copy Markdown
Owner

Summary

The debounced textDocument/didChange diagnostics path (FileChangeHandler)
builds its own semantic-diagnostics list independently of DocumentHandler's
handle_file_opened/republish_open_file_diagnostics, and never called
missing_package_diagnostic — so deleting a file's package line via a live
edit never surfaced the "Missing package declaration" warning, even though
opening (or reopening) the same file correctly did.

Root cause, confirmed not guessed: git log -S"missing_package_diagnostic"
across this file's entire history (including before its extraction from the
monolithic workspace actor in refactor(workspace): extract actor handlers (w5b)) returns zero hits. This call has never existed in this file. It's not
a regression from a recent change removing it — the missing-package
diagnostic feature, when first added, only ever wired the two
DocumentHandler call sites. Three near-identical diagnostic-list-building
blocks exist across two files, and one of them was incomplete from day one.

Fix

Extracted the closure into compute_debounced_semantic_diagnostics so this
list is independently unit-testable (it wasn't reachable as a standalone unit
before — testing it required either mocking tower_lsp::Client or going
through the full async debounce pipeline with no way to inspect what got
published), then added the missing call. The two DocumentHandler call sites
are untouched.

Test plan

  • New regression test debounced_diagnostics_flag_a_deleted_package_declaration
    — real red before the fix (confirmed: panicked ... got: []), real
    green after
  • cargo test — 1967 passed, 0 failed, 3 ignored
  • cargo clippy --all-targets -- -D warnings — clean
  • cargo fmt -- --check — clean

🤖 Generated with Claude Code

FileChangeHandler's debounced textDocument/didChange path builds its
own semantic-diagnostics list independently of DocumentHandler's
handle_file_opened/republish_open_file_diagnostics, and never called
missing_package_diagnostic -- so deleting a file's `package` line via
a live edit never surfaced the "Missing package declaration" warning,
even though opening (or reopening) the same file correctly did.

Root cause confirmed via full history search (git log -S across this
file's entire history, including before its extraction from the
monolithic workspace actor): this call has never existed here. Not a
regression from a recent change removing it -- a gap present since
the missing-package diagnostic feature's first commit, which only
ever wired the two DocumentHandler call sites.

Extracted the closure into compute_debounced_semantic_diagnostics so
this list is independently unit-testable, and added the missing call.
The two DocumentHandler call sites are untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Address the diagnostic-task error handling and ensure the test covers the production publish path.

Pull request overview

Fixes live-edit diagnostics so deleting a package declaration produces the missing-package warning.

Changes:

  • Extracts debounced semantic diagnostic computation.
  • Adds package diagnostics to the debounced path.
  • Adds regression coverage for deleted package declarations.
File summaries
File Summary and review findings
src/workspace/file_change_handler.rs Adds package diagnostics. Address the moderate join-error handling issue and rename pkg_diag to package_diagnostic.
src/workspace/file_change_handler_tests.rs Adds regression coverage. Exercise the actual publish path and rename abbreviated locals (tmp, diags_before, diags_after).
Review details

Suppressed comments (5)

src/workspace/file_change_handler.rs:292

  • pkg_diag is an abbreviated name for a newly introduced local and conflicts with the repository's no-abbreviations convention. Please use the full package_diagnostic name so the diagnostic's purpose is explicit.
    if let Some(pkg_diag) = missing_package_diagnostic(&text_lines, uri) {
        diagnostics.push(pkg_diag);

src/workspace/file_change_handler.rs:293

  • When the index_content blocking task fails, the caller above substitutes diagnostics_text with an empty string. This unconditional check then treats the failed read as an empty Kotlin/Java file and publishes a false “Missing package declaration” warning for any path from which a package can be derived, instead of preserving the prior diagnostics or skipping this publish. Keep the join-error state distinct from a successful cache-hit result and avoid computing package diagnostics when the task failed.
    let text_lines: Vec<String> = diagnostics_text.lines().map(str::to_owned).collect();
    if let Some(pkg_diag) = missing_package_diagnostic(&text_lines, uri) {
        diagnostics.push(pkg_diag);
    }

src/workspace/file_change_handler_tests.rs:188

  • tmp is a newly introduced abbreviated local name; use a descriptive name such as temporary_workspace to follow the repository's no-abbreviations convention and make the fixture setup clearer.
    let tmp = tempfile::tempdir().unwrap();

src/workspace/file_change_handler_tests.rs:207

  • diags_before and the matching diags_after local use the abbreviated diags form, which is explicitly disallowed for new names by the repository's no-abbreviations convention. Rename them to diagnostics_before and diagnostics_after (and update their uses).
    let diags_before =
        super::compute_debounced_semantic_diagnostics(&indexer, &uri, with_package, 0);

src/workspace/file_change_handler_tests.rs:198

  • This test constructs the handler with client: None, so the debounced task returns before compute_debounced_semantic_diagnostics is invoked (the early return is in file_change_handler.rs:136). The later direct calls test the helper, but would still pass if the production closure stopped calling it; please exercise the actual publish path with an injectable/mock client or otherwise assert the task's semantic-diagnostics output.
    let mut handler = FileChangeHandler::new(Arc::clone(&indexer), None);

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

- src/workspace/file_change_handler.rs: rename pkg_diag to
  package_diagnostic (no-abbreviations convention).
- Same file: fix a real false-positive the new package check could
  produce -- when the index_content spawn_blocking join fails, the
  caller substitutes an empty string for diagnostics_text. The other
  diagnostics degrade gracefully against that (an empty file has no
  call args/nullable dots/imports to flag), but missing_package_diagnostic
  does not -- an empty string genuinely has no package line, so it
  would publish a real, false warning for a file whose content was
  never actually re-read. Threaded a diagnostics_text_is_current flag
  through to gate the package check specifically.
- Added a regression test for the false positive (confirmed real red
  without the gate, real green with it) and a doc-comment note arguing
  the remaining residual gap the review flagged (the closure calling
  compute_debounced_semantic_diagnostics could still be edited to stop
  calling it, and no test proves otherwise -- closing that needs a
  real/fake tower_lsp::Client this codebase has no precedent for;
  named explicitly rather than silently left unaddressed).
- src/workspace/file_change_handler_tests.rs: renamed tmp,
  diags_before, diags_after to full words per the same convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Hessesian
Hessesian merged commit 6a6cf5b into main Sep 22, 2026
4 checks passed
@Hessesian
Hessesian deleted the fix/debounced-missing-package-diagnostic branch September 22, 2026 13:09
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.

2 participants