Skip to content

feat(server): implement compilation contexts end to end - #479

Merged
16bit-ykiko merged 29 commits into
mainfrom
header-context-synthesis
Jul 4, 2026
Merged

16bit-ykiko merged 29 commits into
mainfrom
header-context-synthesis

Conversation

@16bit-ykiko

@16bit-ykiko 16bit-ykiko commented Jul 3, 2026 •

Copy link
Copy Markdown
Member

Implements the full compilation-context design (docs/*/design/compilation-context.md), closing the gap between the documented model and the implementation, and fixing several latent bugs found along the way.

What changed

Synthesis & invalidation

  • cdb.lookup() never returns empty (it synthesizes a default command), which made automatic header-context resolution dead code — headers silently compiled with a bare default command. Gated on has_entry(); the default command remains as the final fallback for isolated files.
  • Preamble synthesis rewritten on scan() + real search-path resolution: quoted includes are absolutized (the prefix file lives in the cache dir), matching prefers unconditional directives, and a cut inside #if blocks (include guards on intermediate headers) emits balancing #endifs.
  • HeaderContext tracks its include chain with a content snapshot; changing any chain file re-synthesizes the prefix. Fixed the on_file_saved shadowing bug that made host-save invalidation a no-op.
  • didSave incrementally rescans the saved file's include edges (per CDB configuration), so newly added/removed #includes update host lookups without a full workspace rescan.

Suffix injection

  • The include-chain context after the header (an X-macro .def included mid-enum, mid-function, or mid-class now sees the rest of its includer) is restored by appending a single #include line past the buffer's EOF, pointing at a synthesized suffix file. #if nesting cut at the include point is closed by the prefix and reopened at equal depth in the suffix; braces need no balancing since prefix/main/suffix form one continuous token stream.
  • Self-include recursion (the header's path is remapped to the suffixed buffer) is broken by redirecting other occurrences of the target on the chain to an on-disk snapshot (<hash>.self.h), which participates in staleness tracking.
  • Synthesized artifacts (prefix/suffix/snapshot files) opened by the user compile as self-contained TUs with their host's command, via a persisted artifact→host map — never deriving a context from synthesized state.

PCH

  • A header-context session builds its PCH even when the header has no directives of its own (bound == 0): the -include'd prefix is baked in via the predefines buffer, and clang's PPOpts subsumption prevents double processing. X-macro .def files stop re-parsing the prefix per edit.
  • pch_cache re-keyed by content key: identical preambles share one build; cache.json v2. Metadata is dropped when the store evicts the blob, and the cache store self-heals externally wiped directories.

Protocol

  • Include-occurrence contexts (guard-less header included N times by one host → N contexts, selectable individually).
  • Multi-configuration support end to end: one context per CDB entry, identified by a canonical command hash (working directory included) that survives CDB reordering — for sources and for multi-config hosts of headers.
  • queryContext dedupes by canonical flags hash (self-contained files only; NeedsContext headers stay per-host), ranks hosts by relevance, and paginates. switchContext validates the host actually includes the header, the command hash names a real entry, and the listing epoch is current (stale listings force a re-query); it bumps the session generation so an in-flight compile cannot clobber the switch.
  • Context choices persist across sessions and are validated against the current CDB/include graph on restore; stale choices are dropped instead of stranding the file on a fallback command.
  • New clice/inactiveRegions push notification: inactive preprocessor regions are computed by the worker (PCH-covered preamble regions merged with the resumed main-file scan, threading the open conditional stack across the boundary) and rendered dimmed in VSCode.

Self-containment detection

  • Headers without a CDB entry compile self-contained first; a strict diagnostic set (unknown typename, undeclared identifier, unterminated conditional) triggers a transparent fallback re-compile with a synthesized prefix. Trial diagnostics are never published. .def/.inc/.inl/.tpp/.ipp skip the trial and always get context.
  • Only the NeedsContext verdict persists (cache.json), fingerprinted by the header's content hash — edits made while the server was down invalidate it on load. The trial re-runs when compile inputs change for non-typing reasons (dependency saves, chain invalidation, context switches), so a stale verdict cannot survive.

Editors & docs

  • VSCode: compilation-contexts TreeView (paginated incremental expansion for huge context sets, epoch-checked activation, active-context checkmark) + Clice: Switch/Show Current/Query Compilation Contexts commands in the palette and editor context menu, driving the three custom requests.
  • Plaintext fragment files (.def/.inc/.inl/.tpp/.ipp) are flipped to C++ when the server knows a context for them; the extension activates on startup so first-opened fragments are detected.
  • header_context E2E scenario for vscode/nvim harnesses, including direct custom-request roundtrips through the real extension client.
  • zh/en design docs updated to match the implementation (five-tier command decision with the reserved Inferred tier, self-containment, suffix mechanism, inactiveRegions); known limitations rewritten to those that actually remain.

Fixed along the way

  • DocumentLink emitted invalid JSON (trailing comma) when a PCH had no links, killing the client connection.
  • CVK_False conditions were recorded as Condition::None in the directive table.
  • Worker termination by SIGTERM/SIGINT/SIGHUP was misreported as a WorkerCrash anomaly (and SIGHUP doesn't exist on Windows).

Review fixes — 3-agent adversarial review, then two Codex review rounds (all threads addressed and resolved; latest: e668a22)

  • Command hashes include the working directory (identical argv under different build dirs are distinct compiles).
  • Pinned host hashes match through a host-rules lookup (header-path rules change the hashed argv).
  • PCH inactive-region state is copied before awaiting the worker (StringMap rehash across a suspension point).
  • switchContext resets the self-containment trial for the new context.

Testing

  • Unit: 763 passed (synthesis incl. suffix/self-include/brace cases, occurrence selection, rank_hosts, inactive regions).
  • Integration: 220 passed (staleness via mtime and via didSave-with-restored-mtime, PCH at bound==0, prefix-not-reprocessed, command/occurrence switching, multi-config hosts, dedup+ranking, pagination, epoch staleness, self-containment trial/fallback/persistence, verdict reset on header save, dependency-change re-trial, inactive regions incl. PCH-boundary resume).
  • Smoke: 3/3.
  • VSCode E2E (all 3 fixtures, run locally under WSLg): the compilation context requests test passes.

Known follow-ups (out of scope)

  • Cross-file go-to-definition into headers returns no locations — pre-existing index gap, confirmed on main; the header_context E2E scenario skips the definition step for now.
  • Occurrence counting in queryContext is spelling-based while synthesis resolves paths; they can disagree for same-named headers from different directories (switch validation falls back to synthesis as arbiter).
  • Multi-configuration hosts offer every CDB entry for a reachable header even when only one configuration's search paths actually resolve it; filtering needs unified per-config include-edge semantics (initial scan groups by flags, incremental rescan by entry index). A wrong pick falls back with an explicit guidance diagnostic.
  • The Inferred command tier (D12: -I directory reverse lookup walking up from parent dirs, nearest-path inference) is designed and reserved (CommandSource::Inferred) but not implemented.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds compilation-context selection for headers and sources, synthesized prefix fallback, content-keyed PCH reuse, editor commands/UI for switching contexts, and integration/unit coverage. The English and Chinese design docs are updated to match the new flow.

Changes

Header compilation context feature

Layer / File(s) Summary
Contracts and public types
src/server/workspace/workspace.h, src/server/service/session.h, src/server/compiler/compiler.h, src/server/protocol/extension.h, src/command/argument_parser.{h,cpp}, src/syntax/preamble_synthesis.{h,cpp}, src/syntax/scan.{h,cpp}
Adds the new header context, cache, session, protocol pinning, hashing, prefix synthesis, and include metadata interfaces.
Preamble synthesis and include scanning
src/syntax/preamble_synthesis.{h,cpp}, src/syntax/scan.{h,cpp}, tests/unit/syntax/*
Implements include matching and synthesized preamble generation, with unit coverage for include relocation and scan offsets.
Compiler routing and cache reuse
src/server/compiler/compiler.cpp, src/server/workspace/workspace.cpp, tests/unit/server/rank_hosts_tests.cpp
Adds header-mode classification, host ranking, self-containment trial/fallback compilation, content-keyed PCH reuse, and cache load/save updates.
LSP handlers and editor wiring
src/server/service/lsp_client.cpp, src/server/service/master_server.cpp, editors/vscode/*, editors/nvim/tests/e2e.lua, pixi.toml, tests/integration/*, tests/integration/utils/*
Adds the context request handlers, save invalidation, editor command/UI wiring, fixture setup, and integration coverage for switching, persistence, and staleness.

Estimated code review effort: 5 (Critical) | ~120 minutes

Compilation context design documentation

Layer / File(s) Summary
Design doc updates
docs/en/design/compilation-context.md, docs/zh/design/compilation-context.md
Revises the documented context-selection priority, LSP request semantics, self-containedness detection, prefix synthesis, cache invalidation, and limitations.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • clice-io/clice#398: Both PRs implement header-context resolution and the clice/queryContext/clice/currentContext/clice/switchContext LSP handlers.
  • clice-io/clice#453: Both PRs rework PCH cache identity toward content-key semantics and related session/workspace state.
  • clice-io/clice#381: Both PRs touch MasterServer::on_file_saved and related invalidation behavior for build state.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: end-to-end compilation-context support in the server and related tooling.
✨ 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 header-context-synthesis

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.

- Gate CDB lookup on has_entry() so automatic header context resolution
  is reachable: lookup() always synthesizes a fallback command, which
  made the dependency-graph path dead code for auto resolution. The
  synthesized command remains as the final fallback for standalone files.
- Rewrite preamble synthesis on scan() + real include resolution instead
  of textual basename matching. Quoted includes are absolutized so the
  preamble compiles correctly from the cache directory; matching prefers
  unconditional directives, and a cut inside #if blocks (e.g. include
  guards on intermediate headers) emits balancing #endifs.
- Track the include chain in HeaderContext with a DepsSnapshot hashed
  from the buffers embedded in the preamble; is_stale and
  fill_header_context_args re-synthesize when any chain file changes.
- Fix on_file_saved shadowing bug that made host-save invalidation a
  no-op. The save now zeroes the snapshot's build_at to force content
  re-validation instead of resetting the context, which would race with
  in-flight compiles and leave sessions permanently stale.
- Normalize resolver output through the path pool so exact matching
  works with native separators on Windows; escape #line marker paths.
- queryContext/switchContext use has_entry too: no more bogus contexts
  for headers with no hosts, and switch validation actually validates.
- Drop the thread_local context hack, delete unused semantic/context.h,
  rename HeaderFileContext to HeaderContext.
- A header context session builds its PCH even when the header itself
  has no preamble directives (bound == 0): the -include'd synthesized
  prefix is processed through the predefines buffer and baked into the
  PCH, so X-macro style headers stop re-parsing the prefix per edit.
- Re-key Workspace.pch_cache by the content key instead of path_id:
  files with identical preambles now share one build, concurrent builds
  of the same key coalesce, and didClose no longer drops shared state.
- cache.json v2: PCH entries drop source_file; bump cache format.
- Include-occurrence contexts: a guard-less header included N times by
  one host exposes N contexts; synthesis, queryContext enumeration,
  switchContext pinning and currentContext reporting all carry the
  0-based occurrence index.
- Source files with multiple CDB entries switch via canonical command
  hash (stable across CDB reordering); fill_compile_args honors the
  pinned entry.
- queryContext dedupes contexts by canonical frontend flags hash and
  orders hosts by relevance (stem match > same directory > path
  proximity, deterministic tie-break).
- switchContext validates the chosen host actually includes the header
  and the occurrence is in range, instead of accepting anything.
- Headers without a CDB entry compile self-contained first (borrowed
  host command, no prefix). If the trial diagnostics hit a strict set of
  missing-context signals (unknown type name, undeclared identifier,
  unterminated conditional), the header is recompiled with a synthesized
  prefix; trial diagnostics are never published.
- .def/.inc files skip the trial and go straight to prefix synthesis.
- Verdicts and user switchContext choices persist in cache.json and are
  restored on didOpen; saving a header resets its verdict.
- New clice.selectContext command: QuickPick over clice/queryContext
  with pagination, switching via clice/switchContext (occurrence and
  command hash aware); status bar shows the active context.
- Remove the dead header-contexts TreeView skeleton.
- Add header_context E2E scenario for vscode and nvim harnesses.
- Update compilation-context design docs (zh/en) to match the
  implementation: resolution priority, self-containment detection,
  dedup semantics, occurrence contexts, staleness, PCH unification.
- switchContext bumps session generation: an in-flight compile could
  otherwise clobber ast_dirty on completion and publish results for the
  old context with nothing left for is_stale to recover from.
- Self-containment verdicts self-heal: only NeedsContext persists; the
  session-local trial re-runs whenever compile inputs change for reasons
  other than buffer edits (didSave cascades, chain invalidation, mtime
  staleness), so a stale self-contained impression cannot survive a
  dependency change. header_mode moves to Workspace.
- queryContext no longer merges hosts of a NeedsContext header by flags
  hash: each host synthesizes a different prefix, so each is distinct.
- An explicit occurrence choice (> 0) forces prefix synthesis.
- ensure_pch drops content-keyed metadata whose blob the store evicted,
  bounding the in-memory map.
- Promote get_field/write_entries into tests/integration/utils; add
  rank_hosts unit tests, trial-with-ordinary-error, header-save verdict
  reset, dependency-change re-trial, occurrence out-of-range rejection
  and queryContext pagination tests.
The header_context scenario now drives clice/queryContext,
clice/switchContext and clice/currentContext through the real extension
client (exported from activate() for tests).
Cross-file go-to-definition into headers returns no locations — a
pre-existing index gap confirmed on main — so the header_context
scenario skips the definition step instead of asserting a known
failure.
@16bit-ykiko
16bit-ykiko force-pushed the header-context-synthesis branch from a427457 to 5991caf Compare July 3, 2026 07:03
@16bit-ykiko
16bit-ykiko force-pushed the header-context-synthesis branch from b0a3c85 to fffff04 Compare July 3, 2026 07:18

@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: 1

🧹 Nitpick comments (5)
editors/vscode/src/feature/context.ts (1)

60-63: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add error handling around select()'s LSP requests.

refresh() wraps its request in try/catch (Lines 36-45), but select()'s clice/queryContext and clice/switchContext calls (Lines 60-63, 105-108) are unguarded. If the server throws (disconnected, method unsupported, etc.), the command handler's promise rejects without a user-facing message, unlike the graceful status.hide() fallback elsewhere.

♻️ Suggested fix
     async function select() {
         const editor = vscode.window.activeTextEditor;
         if (!isCppEditor(editor)) {
             return;
         }
         const uri = editor.document.uri.toString();
 
         const loaded: ContextItem[] = [];
         let total = Number.POSITIVE_INFINITY;
 
+        try {
         while (true) {
             ...
         }
+        } catch (err) {
+            vscode.window.showErrorMessage(`clice: failed to load compilation contexts: ${err}`);
+        }
     }

Also applies to: 105-108

🤖 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 `@editors/vscode/src/feature/context.ts` around lines 60 - 63, The `select()`
flow in `context.ts` sends unguarded LSP requests via `client.sendRequest` for
both `clice/queryContext` and `clice/switchContext`, so add try/catch around
those calls similar to `refresh()`. In the `select()` method, catch request
failures, surface a user-facing message or fallback, and ensure the command does
not reject silently when the server is disconnected or the method is
unsupported.
tests/integration/extensions/test_context_switching.py (1)

33-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename ambiguous variable l.

Ruff flags l as an ambiguous single-letter name (E741) at Lines 33-34.

🔧 Proposed fix
-    plain_hash = next(h for l, h in hashes.items() if "-DEXPECTED" not in l)
-    defined_hash = next(h for l, h in hashes.items() if "-DEXPECTED" in l)
+    plain_hash = next(h for label, h in hashes.items() if "-DEXPECTED" not in label)
+    defined_hash = next(h for label, h in hashes.items() if "-DEXPECTED" in label)
🤖 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 `@tests/integration/extensions/test_context_switching.py` around lines 33 - 34,
The generator expression in the test_context_switching logic uses the ambiguous
single-letter variable l, which Ruff flags as E741. Update the comprehensions
that derive plain_hash and defined_hash to use a clearer name like line or label
so the intent is obvious, while keeping the same filtering behavior based on the
"-DEXPECTED" substring.

Source: Linters/SAST tools

tests/integration/compilation/test_staleness.py (1)

474-474: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the shared MTIME_GRANULARITY constant instead of hardcoded 1.1.

This file already defines/uses MTIME_GRANULARITY for the same purpose elsewhere (e.g. test_didsave_triggers_recompile_for_dependents). Reusing it here keeps the sleep duration tunable in one place and avoids drift if the granularity needs to change for a different CI filesystem.

♻️ Proposed fix
-    await asyncio.sleep(1.1)
+    await asyncio.sleep(MTIME_GRANULARITY)

Also applies to: 504-504

🤖 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 `@tests/integration/compilation/test_staleness.py` at line 474, Replace the
hardcoded asyncio.sleep duration in the staleness tests with the shared
MTIME_GRANULARITY constant. Update the affected assertions in test_staleness.py,
including the one in the same flow as
test_didsave_triggers_recompile_for_dependents, so the wait time is derived from
MTIME_GRANULARITY everywhere instead of 1.1. This keeps the timing consistent
and makes the test behavior easier to adjust in one place.
src/server/workspace/workspace.h (2)

49-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Missing default initializer on host_path_id.

Unlike sibling structs in this same diff (SavedContext::host_path_id = 0, Session::ActiveContext::host_path_id = 0), HeaderContext::host_path_id has no default value. If HeaderContext is ever default/value-constructed (e.g. via std::optional<HeaderContext>::emplace() with no args, container resize, or future refactors), this field would be left uninitialized. Current call sites use full aggregate initialization, so this isn't exploitable today, but it's an inconsistent contract vs. the rest of this file.

🛡️ Proposed fix
 struct HeaderContext {
-    std::uint32_t host_path_id;   ///< Source file acting as host.
+    std::uint32_t host_path_id = 0;  ///< Source file acting as host.
     std::string preamble_path;    ///< Path to generated preamble file on disk.
     std::uint64_t preamble_hash;  ///< Hash of preamble content for staleness.
🤖 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 `@src/server/workspace/workspace.h` around lines 49 - 65,
HeaderContext::host_path_id is missing a default initializer, unlike the
matching host_path_id fields in SavedContext and Session::ActiveContext. Update
HeaderContext so host_path_id has an explicit default value, keeping its
initialization contract consistent and safe for default/value construction
across future call sites.

184-190: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

rank_hosts could be const.

Per the linked implementation (workspace.cpp:32-61), rank_hosts only reads path_pool and produces a sorted copy — it doesn't mutate Workspace state. Marking it const would better document the contract and let it be called from const contexts.

🤖 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 `@src/server/workspace/workspace.h` around lines 184 - 190, `rank_hosts` is
read-only and should be callable on const `Workspace` instances. Update the
`Workspace::rank_hosts` declaration (and matching definition in `workspace.cpp`)
to be `const`, since it only consults `path_pool` and returns a sorted copy
without mutating state. Ensure any callers or overrides, if present, match the
new const-qualified signature.
🤖 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 `@src/server/compiler/compiler.cpp`:
- Around line 738-751: The fast path in compiler.cpp’s PCH decision logic is too
broad because it treats every header_context as if an injected -include exists,
which makes self-contained header contexts with bound == 0 still build a useless
PCH. Update the guard around compute_preamble_bound(text) so it only skips the
PCH when there is no bound and no actual injected preamble content to
precompile, using the resolved header_context / preamble_path state from
resolve_header_context rather than header_context.has_value() alone. Keep the
existing PCH build path for real injected preambles, but let self-contained
headers and .def-like files with empty own preambles hit the reset/co_return
fast path.

---

Nitpick comments:
In `@editors/vscode/src/feature/context.ts`:
- Around line 60-63: The `select()` flow in `context.ts` sends unguarded LSP
requests via `client.sendRequest` for both `clice/queryContext` and
`clice/switchContext`, so add try/catch around those calls similar to
`refresh()`. In the `select()` method, catch request failures, surface a
user-facing message or fallback, and ensure the command does not reject silently
when the server is disconnected or the method is unsupported.

In `@src/server/workspace/workspace.h`:
- Around line 49-65: HeaderContext::host_path_id is missing a default
initializer, unlike the matching host_path_id fields in SavedContext and
Session::ActiveContext. Update HeaderContext so host_path_id has an explicit
default value, keeping its initialization contract consistent and safe for
default/value construction across future call sites.
- Around line 184-190: `rank_hosts` is read-only and should be callable on const
`Workspace` instances. Update the `Workspace::rank_hosts` declaration (and
matching definition in `workspace.cpp`) to be `const`, since it only consults
`path_pool` and returns a sorted copy without mutating state. Ensure any callers
or overrides, if present, match the new const-qualified signature.

In `@tests/integration/compilation/test_staleness.py`:
- Line 474: Replace the hardcoded asyncio.sleep duration in the staleness tests
with the shared MTIME_GRANULARITY constant. Update the affected assertions in
test_staleness.py, including the one in the same flow as
test_didsave_triggers_recompile_for_dependents, so the wait time is derived from
MTIME_GRANULARITY everywhere instead of 1.1. This keeps the timing consistent
and makes the test behavior easier to adjust in one place.

In `@tests/integration/extensions/test_context_switching.py`:
- Around line 33-34: The generator expression in the test_context_switching
logic uses the ambiguous single-letter variable l, which Ruff flags as E741.
Update the comprehensions that derive plain_hash and defined_hash to use a
clearer name like line or label so the intent is obvious, while keeping the same
filtering behavior based on the "-DEXPECTED" substring.
🪄 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

Run ID: d912b673-b29c-42b5-9730-b1d32d90814d

📥 Commits

Reviewing files that changed from the base of the PR and between 27717f3 and 5991caf.

📒 Files selected for processing (38)
  • docs/en/design/compilation-context.md
  • docs/zh/design/compilation-context.md
  • editors/nvim/tests/e2e.lua
  • editors/vscode/.vscode-test.mjs
  • editors/vscode/package.json
  • editors/vscode/src/extension.ts
  • editors/vscode/src/feature/context.ts
  • editors/vscode/src/feature/header.ts
  • editors/vscode/src/test/e2e.test.ts
  • pixi.toml
  • src/command/argument_parser.cpp
  • src/command/argument_parser.h
  • src/semantic/context.h
  • src/server/compiler/compiler.cpp
  • src/server/compiler/compiler.h
  • src/server/protocol/extension.h
  • src/server/service/lsp_client.cpp
  • src/server/service/master_server.cpp
  • src/server/service/session.h
  • src/server/workspace/workspace.cpp
  • src/server/workspace/workspace.h
  • src/syntax/preamble_synthesis.cpp
  • src/syntax/preamble_synthesis.h
  • src/syntax/scan.cpp
  • src/syntax/scan.h
  • tests/integration/compilation/test_header_pch.py
  • tests/integration/compilation/test_persistent_cache.py
  • tests/integration/compilation/test_self_containment.py
  • tests/integration/compilation/test_staleness.py
  • tests/integration/extensions/test_context_switching.py
  • tests/integration/extensions/test_header_context.py
  • tests/integration/utils/__init__.py
  • tests/integration/utils/cache.py
  • tests/integration/utils/client.py
  • tests/integration/utils/workspace.py
  • tests/unit/server/rank_hosts_tests.cpp
  • tests/unit/syntax/preamble_synthesis_tests.cpp
  • tests/unit/syntax/scan_tests.cpp
💤 Files with no reviewable changes (2)
  • src/semantic/context.h
  • editors/vscode/src/feature/header.ts

Comment thread src/server/compiler/compiler.cpp
A self-contained header context borrows a command but injects no
-include, so a bound == 0 header under it has nothing to precompile —
gate the PCH build on an actual synthesized prefix instead of the mere
presence of a header context.
pnpm-workspace.yaml carried literal 'set this to true or false'
placeholders from an unfinished pnpm approve-builds run, failing every
pnpm install with ERR_PNPM_IGNORED_BUILDS. vsce-sign and keytar build
scripts are not needed for local dev, so decline them explicitly.
The extension-host launch configs used the watch task whose
$ts-webpack-watch matcher comes from an optional extension; without it
the background task never reports ready and F5 stalls with matcher
errors. Pre-launch now runs a one-shot compile with no matcher.
@16bit-ykiko
16bit-ykiko force-pushed the header-context-synthesis branch from 7e17e4c to 33db73f Compare July 3, 2026 13:15
When the editor tears the whole process group down (hard restart), all
workers die from SIGTERM before the master has entered its own stop
path, and each one was reported through the WorkerCrash anomaly channel
straight to the user. SIGTERM/SIGINT/SIGHUP are termination requests,
not crashes — log a warning and restart quietly.
Explorer view listing the active file's contexts (active one checked,
click to switch, Load more for pagination, refresh button), plus an
editor context-menu entry for Select Compilation Context. The QuickPick
command stays.
Splicing the PCH's pre-serialized links into the worker's array left a
trailing comma when the PCH side was an empty [] (a preamble of only
defines), producing invalid JSON that killed the client connection.
queryContext stamps its results with a workspace epoch (bumped on
didSave); switchContext rejects choices made against an older epoch
with stale = true, so a client can never silently apply a context
picked from an outdated listing.
Tree view and QuickPick pass the listing epoch through switchContext
and re-query on a stale answer. Files like .def/.inc/.inl that open as
plain text are flipped to C++ when clice reports compilation contexts
for them, so the language server attaches to X-macro fragments.
Workers compute the untaken #if branch bodies from the tracked
condition directives; the master pushes them as a clice/inactiveRegions
notification after every compile and the vscode extension renders them
dimmed. Switching the compilation context recompiles and flips the
dimmed regions — the most direct visual feedback of a switch.
The content after the include position is synthesized (mirrored along
the chain) into a suffix file, injected by appending one #include line
to the header's buffer: X-macro fragments embedded in enums or function
bodies now see their braces close instead of piling errors at EOF.
A cut inside #if blocks is reopened with matching '#if 1's so both
sides stay balanced. Includes of the header itself along the chain are
redirected to a disk snapshot — its real path is remapped to the buffer
with the trailing include, which would otherwise recurse forever. The
snapshot joins the staleness snapshot; docs updated, suffix removed
from known limitations.
A user can open the synthesized prefix/suffix/snapshot files for
debugging. They are fragments of the TU they were synthesized for, so
resolve_header_context records an artifact -> host mapping (persisted
in cache.json) and fill_header_context_args compiles them with the
host's command, treated as self-contained — never deriving context
from other synthesized state. Stale artifacts without a recorded host
fall back to the default command.
Windows' <csignal> defines only a POSIX subset; compare against
POSIX SIGHUP's value directly — a worker can only receive it on
POSIX anyway.
@16bit-ykiko

Copy link
Copy Markdown
Member Author

@codex review

Three stacked causes kept clice/inactiveRegions empty:
- DirectiveCollector mapped CVK_False to ConditionValue::None, so a
  failed #if was never recorded as False (latent — no reader used the
  value until now).
- #else carries no condition value; inactivity is now derived from
  whether an earlier branch of the level was taken.
- Conditions inside the preamble bound live in the PCH and never replay
  in the AST compile. The PCH build now scans its share and reports the
  conditional stack still open at the bound; the AST compile resumes
  from that stack and the master publishes both halves.
A user resetting state with rm -rf .clice under a running server left
the store's tmp and namespace directories gone forever — every PCH
build after that failed with 'unable to open output file'. Re-create
them on demand in begin_store/commit.
The palette exposed one blended command; now it mirrors the protocol:
Switch (query + pick + switch, formerly Select), Show Current (the
active choice as a message), and Query (focus and refresh the contexts
view). Switch and Show Current also sit in the editor context menu.
@16bit-ykiko

Copy link
Copy Markdown
Member Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e4a77ade35

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/compiler/compiler.cpp Outdated
Comment thread src/server/service/lsp_client.cpp Outdated
Comment thread src/server/workspace/workspace.cpp
Comment thread src/server/workspace/workspace.cpp
Comment thread src/server/service/master_server.cpp
Comment thread src/feature/inactive_regions.cpp Outdated
Comment thread editors/vscode/src/feature/context.ts
Comment thread src/server/workspace/workspace.cpp Outdated
Comment thread src/server/workspace/workspace.cpp Outdated
Comment thread src/server/service/lsp_client.cpp Outdated
- Hash CDB entries after applying config rules everywhere, so command
  switching works in workspaces with clice.toml rules.
- A multi-configuration host provides one context per CDB entry;
  switchContext pins the entry by hash (ActiveContext.command_hash,
  threaded through resolution, persistence and currentContext).
- Path pool ids start at 0: use ~0u as the saved-host sentinel instead
  of a truthiness test that dropped choices for the first indexed file.
- Rescan a saved file's include edges (Workspace::rescan_includes +
  DependencyGraph::reset_includes), so context queries see includes the
  save added or removed instead of the startup snapshot.
- A chain-file save also drops a persisted NeedsContext verdict: the
  dependency may now provide the missing declarations.
- Align the forced-fragment extensions (.def/.inc/.inl/.tpp/.ipp) with
  the client's C++ fragment detection.
- ActiveContext.occurrence is optional: an explicitly chosen occurrence
  — including #0 — forces prefix synthesis.
- Persist PCH inactive-region metadata in cache.json; encode the open
  conditional stack with both the inactive and branch-taken bits so an
  #else after the bound resolves correctly.
- The vscode extension fires a documentSymbol request after switching,
  refreshing diagnostics and inactive regions without user interaction.
- Nits: default-init HeaderContext::host_path_id, const rank_hosts,
  rename an ambiguous test variable.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e1ef041b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/service/lsp_client.cpp
Comment thread src/command/argument_parser.cpp Outdated
Comment thread src/server/compiler/compiler.cpp Outdated
Comment thread src/server/service/lsp_client.cpp
Comment thread src/server/compiler/compiler.cpp
Comment thread editors/vscode/src/feature/context.ts
Comment thread src/server/service/lsp_client.cpp Outdated
Comment thread src/server/workspace/workspace.cpp Outdated
Comment thread src/server/workspace/workspace.cpp Outdated
- Include the working directory in canonical command hashes so
  identical argv under different build dirs stay distinct contexts.
- Match pinned host hashes through a host-rules lookup: header-path
  rules change the argv the published hashes were computed from.
- Copy PCH inactive regions before awaiting the stateful worker; the
  pch_cache StringMap can rehash across the suspension point.
- Reset trial_done on switchContext so the new context re-earns its
  self-containment verdict.
- Persist the pinned command hash for header contexts and validate
  restored choices in didOpen, dropping stale saved contexts.
- Resolve incremental didSave rescans under every CDB entry instead
  of collapsing all configs to the first command's search paths.
- Fingerprint persisted NeedsContext verdicts with the header's
  content hash; a mismatch on cache load drops the verdict.
- Activate the VSCode extension on startup so first-opened fragment
  files (.def/.inc/...) are detected.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e668a225db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/compiler/compiler.cpp Outdated
Comment thread src/server/compiler/compiler.cpp
Comment thread src/server/service/lsp_client.cpp Outdated
Comment thread src/server/service/master_server.cpp
Comment thread editors/vscode/src/feature/context.ts
Comment thread editors/vscode/src/feature/context.ts Outdated
Comment thread src/server/service/lsp_client.cpp Outdated
- Escape backslashes/quotes in the appended suffix #include so
  Windows cache paths survive string-literal parsing.
- Drop diagnostics remapped onto the phantom suffix line (past the
  user's EOF) before publishing.
- Offer a file's own CDB contexts even when hosts exist, so a host
  override can be switched back.
- Drop orphaned context choices when a save removes the include edge
  they depend on, instead of stranding the header on the fallback
  command; bump the generation to invalidate in-flight compiles.
- Record an earned SelfContained verdict in memory (never persisted)
  and dedup queryContext hosts only on that confirmed verdict, not on
  un-trialed Unknown; clear it wherever the trial is re-armed.
- VSCode: align the language client's documentSelector with the
  context UI (c/cuda-cpp); pin the QuickPick's target document so
  switching editors mid-pick cannot retarget the request.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c733c59cc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread editors/vscode/src/feature/context.ts
Comment thread src/syntax/preamble_synthesis.cpp Outdated
Comment thread src/feature/inactive_regions.cpp
Comment thread src/server/service/master_server.cpp Outdated
Comment thread src/server/service/lsp_client.cpp
Comment thread editors/vscode/src/feature/context.ts
- Record branch truth (taken or not) for #ifndef/#elifndef conditions
  instead of macro definedness — inactive-region dimming was painting
  include-guard bodies as inactive.
- Escape backslashes/quotes in rewritten include paths emitted into
  synthesized preambles/suffixes (Windows paths).
- Revalidate pinned occurrences after saves: a vanished occurrence
  drops the context choice even when other inclusions keep the chain
  alive; occurrence counting hoisted to Workspace::count_occurrences.
- VSCode: discard stale context-tree refresh/loadMore responses that
  finish after the active editor changed; scan already-open documents
  for C++ fragments on activation (onDidOpenTextDocument does not
  fire retroactively).
- Make the dedup integration test deterministic: dedup now requires a
  confirmed self-contained verdict, so wait for the header's trial
  compile before querying.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a00953c95d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/compiler/compiler.cpp
Comment thread src/server/compiler/compiler.cpp
Comment thread src/server/compiler/compiler.cpp
Comment thread src/server/compiler/compiler.cpp
Comment thread src/server/compiler/compiler.cpp
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