Skip to content

test(ide): add headless clangd --check parity harness (#1076) - #1205

Merged
zackees merged 1 commit into
mainfrom
feat/1076-clangd-check-parity
Jul 28, 2026
Merged

test(ide): add headless clangd --check parity harness (#1076)#1205
zackees merged 1 commit into
mainfrom
feat/1076-clangd-check-parity

Conversation

@zackees

@zackeeszackees commented Jul 28, 2026

Copy link
Copy Markdown
Member

The corrected #1076 plan's acceptance harness: CI can't launch Zed, so IDE correctness is proven headlessly with clangd --check.

  • New #[ignore = "requires installed toolchains and clangd on PATH (#1076 parity harness)"] integration test in crates/fbuild-build/tests/clangd_check_parity.rs: generates tests/platform/uno's compile DB in-process (compiledb_only, exercising the real translate_for_clangswap_ino_entries_for_raw pipeline from feat(ide): clangd/compile-DB foundations for fbuild ide (#1076 Phase 0) #1197), asserts the raw-.ino entry replaced the generated .ino.cpp entry (core regression check) with -x c++ -include <prelude> and that the prelude exists, then runs clangd --check=<uno.ino> and fails on any error:-severity diagnostic (documented empty allowlist).
  • Skips cleanly with install guidance when clangd is absent — fbuild deliberately does not distribute clangd (Zed manages its own; per the issue's §1.5 research).
  • Runbook subsection added to docs/DEVELOPMENT.md.

Verification honesty

This machine has no clangd, so the skip path is the live result. The harness's assertions were proven load-bearing with two temporary fake-clangd stubs (never committed): a 0 errors stub → full harness passes end-to-end (DB generated from the cached AVR toolchain, entry/prelude assertions exercised, correct clangd args); an error:-emitting stub → test fails with the offending diagnostic. Normal suite unaffected (test reports ignored).

Part of #1076.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests

    • Added an optional headless check to verify generated IDE configuration works correctly with clangd.
    • The check validates AVR project compilation settings and reports unexpected clangd errors.
    • The check skips automatically when clangd is unavailable.
  • Documentation

    • Added troubleshooting guidance for running the clangd parity check locally, including prerequisites and commands.

Ignored integration test proving the include/define/target correctness
the IDE depends on: generates tests/platform/uno's compile DB
in-process (compiledb_only path, real translate_for_clang +
swap_ino_entries_for_raw pipeline), asserts the raw-.ino entry
replaced the generated .ino.cpp entry with -x c++ -include <prelude>
and the prelude exists, then runs
`clangd --check=<uno.ino> --compile-commands-dir=<project>` and fails
on any error-severity diagnostic. Skips cleanly with guidance when
clangd is not on PATH (fbuild deliberately does not distribute clangd;
Zed manages its own). Runbook added to docs/DEVELOPMENT.md.
Part of #1076 (acceptance harness).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an ignored Rust acceptance test that generates an AVR IDE compile database, validates raw .ino and prelude entries, runs clangd --check, filters diagnostics, and documents local execution and skip behavior.

Changes

Clangd parity validation

Layer / File(s)Summary
Harness setup and diagnostic filtering
crates/fbuild-build/tests/clangd_check_parity.rs
Defines timeout handling, Uno project discovery, clangd lookup, and filtering for allowlisted error diagnostics.
Compile database and clangd execution
crates/fbuild-build/tests/clangd_check_parity.rs, docs/DEVELOPMENT.md
Generates the compile database, verifies raw .ino and prelude handling, runs clangd checks, and documents local invocation and skip behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • FastLED/fbuild#1197: Introduces the prelude-generation and raw .ino compile-database behavior validated by this test.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and concisely describes the main change: a headless clangd --check parity harness for IDE testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/1076-clangd-check-parity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/fbuild-build/tests/clangd_check_parity.rs`:
- Around line 213-227: Add an assertion in the raw-.ino argument checks near the
existing `-include` assertion to require the `-x`, `c++` argument pair,
including validation that `-x` has a following value. Keep the existing prelude
lookup and assertions unchanged.
- Around line 241-251: Update the clangd process setup in the parity test to
include the required allow-direct-spawn marker and configure the tokio Command
with kill_on_drop(true) before invoking output inside under_timeout, preserving
the existing arguments and stdio configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e6a089ef-1c37-4e9e-a6b1-c33c02812dae

📥 Commits

Reviewing files that changed from the base of the PR and between f724a91 and f242c99.

📒 Files selected for processing (2)
  • crates/fbuild-build/tests/clangd_check_parity.rs
  • docs/DEVELOPMENT.md

Comment on lines +213 to +227
let arguments = ino_entry["arguments"]
.as_array()
.expect("entry.arguments must be an array");
let arg_strs: Vec<&str> = arguments.iter().filter_map(|a| a.as_str()).collect();
assert!(
arg_strs.contains(&"-include"),
"raw-.ino entry must carry -include <prelude> per the #1197 prelude design: {:?}",
arg_strs
);
let prelude_index = arg_strs
.iter()
.position(|a| *a == "-include")
.expect("checked above")
+ 1;
let prelude_path = arg_strs[prelude_index];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the required -x c++ argument pair.

The test only verifies -include; a regression dropping language forcing would pass this structural check despite the stated raw-.ino contract.

Proposed assertion
 let arg_strs: Vec<&str> = arguments.iter().filter_map(|a| a.as_str()).collect();
+ assert!(+ arg_strs+ .windows(2)+ .any(|pair| pair[0] == "-x" && pair[1] == "c++"),+ "raw-.ino entry must carry -x c++: {:?}",+ arg_strs+ );
assert!(
arg_strs.contains(&"-include"),
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let arguments = ino_entry["arguments"]
.as_array()
.expect("entry.arguments must be an array");
let arg_strs:Vec<&str> = arguments.iter().filter_map(|a| a.as_str()).collect();
assert!(
arg_strs.contains(&"-include"),
"raw-.ino entry must carry -include <prelude> per the #1197 prelude design: {:?}",
arg_strs
);
let prelude_index = arg_strs
.iter()
.position(|a| *a == "-include")
.expect("checked above")
+ 1;
let prelude_path = arg_strs[prelude_index];
let arguments = ino_entry["arguments"]
.as_array()
.expect("entry.arguments must be an array");
let arg_strs:Vec<&str> = arguments.iter().filter_map(|a| a.as_str()).collect();
assert!(
arg_strs
.windows(2)
.any(|pair| pair[0] == "-x" && pair[1] == "c++"),
"raw-.ino entry must carry -x c++: {:?}",
arg_strs
);
assert!(
arg_strs.contains(&"-include"),
"raw-.ino entry must carry -include <prelude> per the `#1197` prelude design: {:?}",
arg_strs
);
let prelude_index = arg_strs
.iter()
.position(|a| *a == "-include")
.expect("checked above")
1;
let prelude_path = arg_strs[prelude_index];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/fbuild-build/tests/clangd_check_parity.rs` around lines 213 - 227, Add
an assertion in the raw-.ino argument checks near the existing `-include`
assertion to require the `-x`, `c++` argument pair, including validation that
`-x` has a following value. Keep the existing prelude lookup and assertions
unchanged.

Comment on lines +241 to +251
let mut cmd = tokio::process::Command::new(&clangd_path);
cmd.arg(format!("--check={sketch_path}"))
.arg(format!("--compile-commands-dir={}", project_dir.display()))
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped());

let output = under_timeout(async {
cmd.output()
.await
.expect("failed to spawn clangd — found on PATH but could not execute")
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
# Confirm the declared Tokio dependency and inspect existing approved spawn patterns.
fd '^Cargo\.toml$' crates -x sh -c 'echo "--- $1"; rg -n -C2 "tokio" "$1"' _ {}
rg -n -C2 'allow-direct-spawn:|run_command(?:_passthrough)?' crates

Repository: FastLED/fbuild

Length of output: 6441


🏁 Script executed:

#!/bin/bashset -euo pipefail
echo"## repository files matching clangd / direct spawn / run_command"
rg -n -C2 'allow-direct-spawn:|tokio::process::Command|direct_spawn|run_command|under_timeout|kill_on_drop|process::Command'.||trueechoecho"## target file outline"
ast-grep outline crates/fbuild-build/tests/clangd_check_parity.rs --view expanded 2>/dev/null ||trueechoecho"## target file relevant sections"
wc -l crates/fbuild-build/tests/clangd_check_parity.rs
sed -n '1,320p' crates/fbuild-build/tests/clangd_check_parity.rs
echoecho"## Cargo workspace dependency features"
rg -n -C3 '^\[workspace\.dependencies\]|tokio|process' Cargo.toml crates -g 'Cargo.toml'

Repository: FastLED/fbuild

Length of output: 50371


🏁 Script executed:

#!/bin/bashset -euo pipefail
echo"## ci/find_direct_subprocess.py direct-spawn logic"
sed -n '1,170p' ci/find_direct_subprocess.py
echoecho"## target clangd code"
sed -n '220,270p' crates/fbuild-build/tests/clangd_check_parity.rs
echoecho"## fbuild-core subprocess/contained spawn kill-on-drop behavior"
rg -n -C3 'kill_on_drop|spawn_contained|Command::new|tokio::process::Command' crates/fbuild-core crates/fbuild-daemon/src/handlers/operations/build.rs crates/fbuild-daemon/src/handlers/emulator/shared.rs crates/fbuild-daemon/src/handlers/emulator/runners.rs

Repository: FastLED/fbuild

Length of output: 26726


Make the clangd spawn allowlisted and cancellation-safe.

Add the required allow-direct-spawn: marker on this spawn, and set kill_on_drop(true) so dropping/timing out the awaited cmd.output() future doesn’t leave clangd --check running.

Proposed fix
- let mut cmd = tokio::process::Command::new(&clangd_path);+ // allow-direct-spawn: capture clangd diagnostics for the clangd-check-parity acceptance harness.+ let mut cmd = tokio_process::Command::new(&clangd_path);
cmd.arg(format!("--check={sketch_path}"))
.arg(format!("--compile-commands-dir={}", project_dir.display()))
🧰 Tools
🪛 GitHub Actions: Lint subprocess spawns / 0_Lint subprocess spawns.txt

[error] 241-241: Direct spawn detected without an allow-direct-spawn: <reason> marker. New direct subprocess call at line 241 (tokio::process::Command::new(&clangd_path)); annotate with a one-line reason or route via fbuild_core::subprocess::{run_command,run_command_passthrough}.

🪛 GitHub Actions: Lint subprocess spawns / Lint subprocess spawns

[error] 241-241: New direct spawn without an allow-direct-spawn: <reason> marker. Suggested route: fbuild_core::subprocess::{run_command,run_command_passthrough} or add a one-line allow reason (#141). Offending code: let mut cmd = tokio::process::Command::new(&clangd_path);

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/fbuild-build/tests/clangd_check_parity.rs` around lines 241 - 251,
Update the clangd process setup in the parity test to include the required
allow-direct-spawn marker and configure the tokio Command with
kill_on_drop(true) before invoking output inside under_timeout, preserving the
existing arguments and stdio configuration.

Source: Pipeline failures

@zackees
zackees merged commit e4885d3 into mainJul 28, 2026
87 of 93 checks passed
@zackees
zackees deleted the feat/1076-clangd-check-parity branch July 28, 2026 01:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

1 participant

@zackees