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

@zackees zackees 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

coderabbitai Bot 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 name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: a headless clangd --check parity harness for IDE testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check 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.

@coderabbitai coderabbitai Bot 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/bash
set -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/bash
set -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' . || true

echo
echo "## target file outline"
ast-grep outline crates/fbuild-build/tests/clangd_check_parity.rs --view expanded 2>/dev/null || true

echo
echo "## 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

echo
echo "## 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/bash
set -euo pipefail

echo "## ci/find_direct_subprocess.py direct-spawn logic"
sed -n '1,170p' ci/find_direct_subprocess.py

echo
echo "## target clangd code"
sed -n '220,270p' crates/fbuild-build/tests/clangd_check_parity.rs

echo
echo "## 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 main Jul 28, 2026
87 of 93 checks passed
@zackees
zackees deleted the feat/1076-clangd-check-parity branch July 28, 2026 01:47
@fastled-project-sync fastled-project-sync Bot moved this to Triage in FastLED Tracker Jul 28, 2026
Sign up for free to 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