81 Commits

Author SHA1 Message Date
Myriad-Dreamin
3b45888622 fix(semantic-tokens): filter ineligible highlight references (#434)
Add a reusable declaration-name eligibility helper that mirrors clangd's
`canHighlightName`, use it to suppress unsupported reference tokens in
the semantic-token collector, and cover the change with focused
semantic-token regression tests plus a constructor/destructor positive
case.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved semantic token highlighting to suppress ineligible operator
references lacking meaningful source text.
* Ensured constructor and destructor names remain properly highlighted
with correct visual modifiers.

* **Tests**
* Added test coverage for semantic token highlighting behavior across
various declaration types.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/clice-io/clice/pull/434?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-05 00:03:18 +08:00
ykiko
cc5b25d5c3 refactor: public feature types and snapshot testing infrastructure (#442)
## Summary

- **Public feature types**: Move `SemanticToken`, `FoldingRange`,
`DocumentSymbol`, `InlayHint`, and `HintCategory` from internal `.cpp`
files to `feature.h` as public API types. Each feature now exposes two
overloads: a raw overload returning offset-based types and a protocol
overload that converts to LSP wire-format with explicit
`PositionEncoding`.
- **Snapshot testing**: Add corpus-driven snapshot tests using
`ASSERT_SNAPSHOT_GLOB` for semantic tokens, folding ranges, inlay hints,
document symbols, and TU index. Tests compile real C++ corpus files,
format output as YAML flow mappings, and diff against `.snap.yml`
baselines.
- **Test infrastructure**: Add `compile_file()` to `Tester`,
`yaml_str()` utility, `--corpus-dir` / `--snapshot-dir` CLI options, and
`--verbose` flag for unit tests. Migrate to kotatsu's unified
`kota::zest::Options` API.
- **Toolchain robustness**: Filter unknown cc1 args via
`clang::driver::getDriverOptTable()` to handle system compilers newer
than embedded LLVM.
- **Dependency bump**: Update kotatsu to 7381404 (unified zest Options,
out-param `from_json` API).

## Details

### Feature type changes
All five feature modules (`semantic_tokens`, `folding_ranges`,
`document_symbols`, `inlay_hints`, `document_links`) now follow the same
two-overload pattern. The raw overload returns offset-based structs
suitable for indexing and testing; the protocol overload adds
`PositionEncoding` conversion for LSP responses. `stateful_worker.cpp`
explicitly passes `PositionEncoding::UTF16` at every call site.

### Snapshot tests
Corpus files live in `tests/corpus/` (organized by language construct).
Snapshot baselines live in `tests/snapshots/<feature>/`. Format lambdas
are inlined directly in test bodies — no separate format functions for
single-use formatters. YAML output uses flow mappings (`- { key: value
}`) for compact, diffable baselines.

### cc1 arg filtering
`src/command/toolchain.cpp` now parses the cc1 argument list through
LLVM's driver option table and drops any args classified as
`UnknownClass`. This prevents compilation failures when the system
compiler emits flags that the embedded LLVM version doesn't recognize.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-24 19:36:27 +08:00
ykiko
3305465d1f feat(formatting): wire up textDocument/formatting and rangeFormatting (#441)
## Summary

- Wire up the existing `document_format` feature to LSP via stateless
workers
- Add `Format` kind to stateless worker dispatch, with a lightweight
`forward_format` path in `Compiler` (no compilation/deps needed — just
file path + content)
- Register `textDocument/formatting` and `textDocument/rangeFormatting`
handlers with `scoped_pause`
- Style lookup uses `clang::format::getStyle` which walks parent
directories for `.clang-format`, matching clangd's behavior

## Test plan

- [x] 4 unit tests: simple format, range format, idempotent (no edits),
include sort
- [x] 3 integration tests: full document format (verifies applied edits
match expected output), range format, already-formatted no-op
- [x] Capability assertions added to `test_capabilities`
- [x] All existing tests pass (554 unit, 170 integration, 2 smoke)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Added document formatting and range formatting capabilities to the LSP
server
* Formatting can target the entire document or a specific range of code
  * Server now advertises formatting support to LSP clients

* **Tests**
  * Added comprehensive test coverage for formatting functionality

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-04 19:15:07 +08:00
ykiko
75b9ea05b8 refactor(server): split into service layer, add agentic protocol, adopt task_group (#437)
## Summary

- **Restructure `src/server/` into subdirectories** (`service/`,
`compiler/`, `worker/`, `workspace/`, `protocol/`) to separate concerns:
transport/session management, compilation, worker orchestration, and
persistent workspace state.
- **Decouple MasterServer from transport**: MasterServer no longer holds
a `JsonPeer&` reference or registers handlers itself. New `LSPClient`
and `AgentClient` classes own their peer references and register
protocol handlers, accessing MasterServer internals via `friend class`.
- **Add agentic protocol**: A TCP-based side channel
(`agentic/compileCommand`) that lets external tools (AI agents, build
systems) query compile commands from a running clice server. Includes a
CLI client mode (`--mode agentic --port N --path FILE`), server-side
listener when `--port` is specified in pipe mode, and integration tests
for happy path, fallback, concurrency, and connection-refused.
- **Replace fire-and-forget `loop.schedule()` with `kota::task_group`**:
Compiler compile tasks, Indexer background indexing + resource monitor,
WorkerPool worker monitors, and socket accept loops now use structured
concurrency. This eliminates manual `alive_count_`/generation counters
and ensures all spawned tasks are joined on shutdown.
- **Fix flaky integration test**: `CliceClient.initialize()` now always
sets `cache_dir` to a workspace-local `.clice/` directory, preventing
stale PCH artifacts from the global `~/.cache/clice/` from polluting
test runs.

## Details

**Compiler peer lifetime**: `Compiler` and `Indexer` previously took
`JsonPeer&` in their constructors, coupling them to a single connection.
They now store a `JsonPeer*` set via `set_peer()`, with null checks
before sending diagnostics/progress. This supports the multi-connection
model where agentic clients don't need diagnostics.

**Socket mode single-LSP enforcement**: `accept_connections()` takes a
`register_lsp` flag; when true, only the first connection gets an
`LSPClient`. All connections get an `AgentClient`. This prevents
multiple LSP sessions from racing on shared server state.

**Structured shutdown**: `Compiler::stop()` cancels in-flight compile
tasks and joins them. `WorkerPool::stop()` signals workers and joins the
monitor task group. `Indexer` uses a `cancellation_source` to stop its
resource monitor when a background indexing run completes.

**Pin kotatsu**: Changed from `GIT_TAG main` + `GIT_SHALLOW TRUE` to an
exact commit hash for reproducible builds.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-02 01:06:18 +08:00
ykiko
939ab6d0d4 feat(server): concurrent background indexing with priority control (#432)
## Summary

- Rewrite serial background indexing to concurrent dispatch (up to
`stateless_worker_count / 2` parallel tasks)
- Add depth-counted pause/resume mechanism: completion and
signature-help handlers pause new index dispatches to prioritize user
requests
- Report indexing progress via LSP `$/progress` notifications
(percentage + file count)
- Lower thread scheduling priority (`nice +10`) for index tasks in
stateless workers via RAII `ScopedNice` guard

## Test plan

- [x] `pixi run format` — no changes
- [x] `pixi run unit-test Debug` — 551 passed, 9 skipped (pre-existing)
- [x] `pixi run smoke-test Debug` — 2/2 passed
- [x] `pixi run integration-test Debug` — 121 passed, 3 failed (all
pre-existing on main: header_context x2, staleness x1)
- [ ] Manual test: open a large project (e.g. LLVM), verify progress bar
appears and completion remains responsive during indexing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Pause/resume controls for background indexing
* Concurrent, adaptive background indexing with configurable concurrency
* LSP progress reporting (create/begin/report/end) and updated
completion metrics

* **Behavior Change**
* Code completion and signature help temporarily pause indexing for
responsiveness
* Background indexing runs with reduced scheduling priority on
non-Windows and logs "files dispatched" at finish

* **Tests**
* Test client fixture defaults init options and sets workspace cache dir
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 13:28:59 +08:00
ykiko
e1202d2fa5 fix: prevent worker crashes from null ASTConsumer, invalid FileID, and missing PCH cache dir (#435)
## Summary

Three pre-existing bugs cause worker processes to crash with SEGV or
SIGABRT. On the main branch these crashes are silent (workers die,
requests fail fast with "transport closed", tests still pass because
null responses are accepted). However when combined with #432's worker
respawn mechanism, the crash-respawn-crash cycle on low-core CI machines
causes request timeouts and smoke test hangs.

### Fixes

- **compilation.cpp**: `ProxyAction::CreateASTConsumer` now checks for
null before passing to `MultiplexConsumer`. When the wrapped action's
`CreateASTConsumer` fails (e.g. missing system headers during PCH
generation), this previously caused a null pointer dereference, SEGV,
ASAN kills the stateless worker.
- **compilation_unit.cpp**: `file_path()` returns empty `StringRef` on
invalid `FileID` instead of asserting. The assert fired when
`IncludeGraph::from()` called `file_path(interested_file())` on an AST
compiled with synthesized default commands (no compile_commands.json,
clang++ -std=c++20 fallback, no system headers, invalid main file ID),
SIGABRT, stateful worker crash.
- **compiler.cpp**: `ensure_pch` now creates the PCH cache directory
before sending the build request. Previously, when `load_workspace()`
exited early (no compile_commands.json), the cache subdirectories were
never created, causing every PCH write to fail with "No such file or
directory".
- **master_server.cpp/h**: `load_workspace()` changed from
`kota::task<>` to plain `void` -- it contains only synchronous
filesystem operations and no co_await, so the coroutine wrapper was
unnecessary. Called directly instead of via `loop.schedule()`.

## Test plan

- [x] Verified zero SEGV/SIGABRT/assertion crashes in worker stderr
after fix
- [x] rapid_edit.jsonl smoke test passes 3/3 runs consistently (34s
each)
- [x] Behavior matches main branch (both return 134 responses, 0
pending)
- [x] Debug build with ASAN (detect_leaks=0) -- clean run, no sanitizer
reports

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/clice-io/codesmith/clice/pr/435"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-light.svg"><img
alt="View in Codesmith"
src="https://pr-comments-assets.blacksmith.sh/codesmith/view-in-codesmith-dark.svg"></picture></a>
<sup>Codesmith can help with this PR — just tag <code>@codesmith</code>
or enable autofix.</sup>

- [ ] Autofix CI and bot reviews
<!-- /codesmith:footer -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved error handling for AST consumer creation with null checks and
a clear failure path.
* Safer file-path access that returns empty for invalid identifiers
instead of asserting.
* PCH cache handling now validates cache configuration, attempts
directory creation, logs warnings, and aborts PCH builds on failure.

* **Refactor**
* Workspace loading changed from asynchronous to synchronous execution.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-23 10:36:03 +08:00
ykiko
17e68010a0 feat(server): improve configuration file handling (#423)
## Summary

- **`[[rules]]`**: TOML array-of-tables config for per-file compilation
flag rules with glob pattern matching (`append`/`remove`). Patterns are
pre-compiled at config load time. Rules whose patterns all fail to
compile are dropped entirely (no silent no-op entries), and rules now
apply uniformly to every compilation — including the header-context
fallback path used when editing a header without its own CDB entry.
- **CDB auto-scan**: Default search scans workspace root + all immediate
subdirectories for `compile_commands.json`, replacing the hardcoded
directory list.
- **LSP `initializationOptions`**: Clients can pass config as JSON via
the LSP initialize request; priority is `initializationOptions >
clice.toml > defaults`.
- **XDG cache paths**: Default cache/index/logging paths prefer
`$XDG_CACHE_HOME/clice/<workspace-hash>/`; fall back to
`$HOME/.cache/clice/<hash>/`, then `<workspace>/.clice/`.
- **`${workspace}` substitution**: supported in `cache_dir`,
`index_dir`, `logging_dir`, and every `compile_commands_paths` entry.
No-op when `workspace_root` is empty.
- **Partial config support**: All TOML/JSON fields are optional via
`kota::meta::defaulted<T>`, so minimal config files work correctly.
- **Detailed diagnostics**: malformed `clice.toml` now logs line, column
and parser description (via toml++ direct parse); a malformed workspace
config surfaces a clear fallback warning instead of silently reverting
to defaults.

## Test plan

- [x] 28 unit tests for config (full suite 545 unit tests pass, Debug)
- [x] 119 integration tests pass
- [x] 2 smoke tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* XDG-based, workspace-scoped project cache (PCH/PCM and header caches
moved under project cache) with workspace fallback
* Initialization options JSON can override config (takes precedence over
file/defaults)
* Per-file pattern rules to append/remove compile flags; expanded
discovery of compilation databases (multiple paths)

* **Refactor**
* Configuration fields reorganized under a project scope; runtime
behavior now respects project-scoped values

* **Tests**
* New unit and integration tests for config parsing, rule matching, and
persistent cache behavior

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 00:21:31 +08:00
ykiko
3fa653bcaf feat(completion): mark deprecated symbols with strikethrough (#414)
## Summary
- Check `CXAvailability_Deprecated` on `CodeCompletionResult` and set
`CompletionItemTag::Deprecated`
- Editors render deprecated completions with a strikethrough on the
label

## Test plan
- [x] `DeprecatedTag` — `[[deprecated]]` function gets the tag
- [x] `NotDeprecated` — normal function has no Deprecated tag
- [x] All 491 unit tests pass
- [x] `pixi run format` clean

Stacked on #411.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Code completion now marks deprecated declarations with a deprecated
tag so users can see deprecated items in completion lists.

* **Tests**
* Added unit tests ensuring deprecated declarations produce completion
items with the deprecated tag and non-deprecated items do not.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 13:42:32 +08:00
ykiko
418e190fa0 chore(deps): migrate from eventide to kotatsu (#428)
## Summary

- The `eventide` dep was renamed to
[kotatsu](https://github.com/clice-io/kotatsu) with a broad rename of
CMake identifiers, namespaces, header paths, and a few module reorgs
(`serde` → `codec`, `reflection` → `meta`, `common` → `support`). Align
clice to the new names.
- CMake: FetchContent target, option prefix (`ETD_*` → `KOTA_*`,
`ETD_SERDE_*` → `KOTA_CODEC_*`), target names
(`eventide::{ipc::lsp,serde::toml,deco,zest}` →
`kota::{ipc::lsp,codec::toml,deco,zest}`).
- Namespaces: `eventide::` → `kota::`, `eventide::serde::` →
`kota::codec::`, `eventide::refl::` → `kota::meta::`. The short `et`
alias is dropped — all usages now spell `kota::` directly.
- Headers: `eventide/*` → `kota/*`, including special cases
`serde/serde/raw_value.h` → `codec/raw_value.h`, `ipc/json_codec.h` →
`ipc/codec/json.h`, `common/meta.h` → `support/type_traits.h`,
`common/ranges.h` → `support/ranges.h`.
- Kotatsu split `JsonPeer` / `BincodePeer` out of `ipc/peer.h` into the
codec-specific headers; added `kota/ipc/codec/{json,bincode}.h` includes
where those types are used.
- Depends on clice-io/kotatsu#110 (already merged) to prevent `-Wall
-Wextra -Werror` from transitively propagating out of
`kota::project_options`.

## Test plan

- [x] `pixi run unit-test RelWithDebInfo` — 518/518 pass (9 skipped,
unchanged from main)
- [x] `pixi run integration-test RelWithDebInfo` — 119/119 pass
- [x] `pixi run smoke-test RelWithDebInfo` — 2/2 pass
- [x] `pixi run format` clean

## Notes

- `tests/smoke/rapid_edit.jsonl` was intentionally left untouched: the
embedded `#include "eventide/..."` strings are frozen snapshots of file
contents the client sent at record time, not clice source.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated internal dependencies from `eventide` to `kota`, including
async runtime, IPC transport, serialization codec, and metadata
libraries.
* Updated build configuration and CMake variables to align with the new
dependency.

* **Refactor**
* Migrated internal implementation to use `kota` namespace and APIs
throughout the codebase.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:49:07 +08:00
ykiko
d42d9d5b29 refactor(document links): use Lexer for unified directive argument scanning (#421)
## Summary
- Replace hand-written character scanning in `document_links.cpp` with
the project's `Lexer` class for finding filename arguments in
preprocessor directives
- Extend `Lexer` to activate `header_name` mode for
`#embed`/`#include_next`, and expose `set_header_name_mode()` for
`__has_include`/`__has_embed` contexts
- Remove unused `Include::filename_range` field (had a latent assert
crash on macro-expanded includes)
- Add `MacroInclude` unit test covering `#include MACRO` scenario

## Test plan
- [x] 498 unit tests pass (including new `MacroInclude` test)
- [x] 119 integration tests pass
- [x] 2/2 smoke tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Document links now resolve includes written via macros; directive
parsing recognizes include, include_next, embed and __has_* patterns
more reliably using lexer-driven argument detection.

* **Refactor**
* Removed an internal filename-range field previously stored for include
directives.

* **Tests**
* Added unit tests covering directive argument extraction and
macro-based include linking.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:17:10 +08:00
ykiko
9c89d20e76 feat(tests): add compile_with_modules helper to Tester (#420)
## Summary
- Add `add_module()` and `compile_with_modules()` to the `Tester` test
framework
- Supports both separate `add_module()` calls and single-string
`#[filename]` syntax via `add_files()`
- Automatically scans module dependencies with `scan_precise`,
topologically sorts, builds PCMs in order, then compiles the main file
- Temporary PCM files cleaned up automatically in destructor
- Migrated `ModuleImport` and `ModuleReexport` semantic tokens tests to
use the new API

## Test plan
- [x] All 505 unit tests pass
- [x] All 113 integration tests pass
- [x] All 2 smoke tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Centralized, module-aware test compilation with automatic module
discovery, dependency ordering, and cycle detection.
* Unified "compile with modules" flow; tests now add module sources
directly and no longer manage temporary module artifacts manually.
* Reduced duplicated compile/diagnostic logic and improved cleanup of
generated artifacts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:16:53 +08:00
ykiko
8bafaa8171 feat(document links): preserve PCH document links and add #embed support (#413)
## Summary
- PCH compilation now serializes document links via `pch_links_json` in
`BuildResult` and stores them in `PCHState`
- Master server merges PCH document links with main-file links on
`textDocument/documentLink` requests, fixing missing links for
`#include` directives inside the preamble
- Adds document link support for `#embed` and `__has_embed` directives

## Test plan
- [x] Unit tests: `DocumentLink.Embed` and `DocumentLink.HasEmbed` added
- [x] Integration tests: `test_document_links.py` verifies PCH + main
merge and `#embed` links
- [x] All 483 unit tests pass
- [x] All 4 integration tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Document links now detect embeds and __has_embed directives for both
quoted and angled filenames.
* Document links produced during precompiled builds are cached and
merged into document-link responses for more complete link sets.

* **Tests**
* Added integration tests for merged PCH/main links and embed/has-embed
cases.
  * Added unit tests verifying embed handling under C++23.

* **Chores**
* Added test fixtures and compile command entries for document-links
tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 21:35:10 +08:00
ykiko
92dae18fd4 feat(semantic tokens): highlight module names in declarations and imports (#417)
## Summary
- Highlight module name identifiers (e.g. `foo`, `bar` in `export module
foo.bar;`) as `SymbolKind::Module` in semantic tokens
- Highlight import module names (e.g. `foo` in `import foo;`) using
`directives.imports` name locations
- Module declarations use `getCurrentNamedModule()->DefinitionLoc` +
lexer scan to find name tokens

## Test plan
- [x] `SemanticTokens.ModuleDeclaration` — `export module foo;`
- [x] `SemanticTokens.ModuleDeclarationDotted` — `export module
foo.bar;`
- [x] `SemanticTokens.ModuleImport` — PCM build + `import foo;`
- [x] All 16 SemanticTokens tests pass, no regressions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Enhanced semantic token support for C++20 modules, including dotted
module names, partitions, fragments, imports and re-exports for more
accurate highlighting.

* **Bug Fixes**
* Improved conflict resolution so directive tokens no longer mask other
semantic kinds; ensures `module`/`import` used as identifiers are
tokenized correctly.

* **Tests**
* Added unit tests covering module declarations, imports, partitions and
edge cases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 21:34:06 +08:00
ykiko
e554660c06 fix(completion): use class name for constructor/deduction guide labels (#416)
## Summary
Fixes a bug where constructors and deduction guides had labels like
`vector<_Tp, _Alloc>` instead of just `vector`, causing:
1. Label deduplication to fail (class `vector` != constructor
`vector<_Tp, _Alloc>`)
2. Selecting the completion to insert invalid text `vector<_Tp, _Alloc>`

Now uses `getParent()->getName()` for constructors and
`getDeducedTemplate()->getName()` for deduction guides.

## Test plan
- [x] All 494 unit tests pass (existing `DeduplicateByLabel` test covers
this)
- [x] `pixi run format` clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Constructor and deduction-guide completions now show the parent type
name without template parameters, improving readability and preventing
duplicate entries.

* **Tests**
* Added a unit test verifying completion items for these entries use the
parent type name (no template-parameterized labels) and insertion text
starts with that name.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 19:15:38 +08:00
ykiko
3dab2ead93 feat(completion): snippet insertion for function/method parameters (#412)
## Summary
- Generate LSP snippet placeholders (`${1:param}`, `${2:param}`) for
function and method completions in non-bundle mode
- Controlled by
`CodeCompletionOptions::enable_function_arguments_snippet` (default off)
- No-arg functions produce plain text insertion (no empty snippet)
- Bundle mode is unaffected — snippets only apply when each overload is
a separate item
- Optional chunks (default arguments) are skipped in snippet generation

## Example
```
// Before: typing "fo" and selecting foooo inserts just "foooo"
// After:  typing "fo" and selecting foooo inserts "foooo(${1:int x}, ${2:float y})"
```

## Test plan
- [x] `SnippetFunctionArgs` — verifies placeholders are generated
- [x] `SnippetNoArgs` — no-arg functions don't produce snippet
- [x] `SnippetDisabled` — respects the option flag
- [x] `SnippetBundleMode` — bundle mode doesn't generate snippets
- [x] `SnippetMethod` — works for member methods too
- [x] All 494 unit tests pass
- [x] `pixi run format` clean

Stacked on #411.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Code completion now generates function argument snippets with
interactive placeholders, helping users efficiently navigate through
parameters during autocompletion. The feature works with functions and
methods, with configurable options to control behavior for overloaded
scenarios.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 16:39:46 +08:00
ykiko
bd238fe59c feat(completion): signature display, underscore filtering, label dedup (#411)
## Summary
- Extract function/method signatures from Clang `CodeCompletionString`
into `labelDetails.detail` (parameter list) and
`labelDetails.description` (return type)
- Filter `_`/`__` prefixed internal symbols (e.g. `_Vector_base`,
`_Alloc`) unless the user explicitly typed `_`
- Fix `completion_kind` isa ordering: `CXXMethodDecl` checked before
`FunctionDecl` so methods get correct Kind
- Bundle mode: extend overload bundling to Method and Constructor (was
Function only)
- Bundle mode: deduplicate by label — when the same name appears as
Class + Constructor + deduction guide, keep only one (priority: Class >
Function > Constructor)
- Bundled overloads show `(…) +N overloads` in `labelDetails.detail`
instead of `detail`

## Test plan
- [x] 12 unit tests covering: signature extraction, return type,
overload bundling, underscore filtering, label deduplication, non-bundle
mode, method signatures
- [x] All 489 unit tests pass
- [x] `pixi run format` applied

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Code completion now displays function signatures and return types in
completion items
  * Overloaded functions are bundled together with a count indicator
* Internal symbols (underscore-prefixed) are filtered from suggestions
unless explicitly typed
* Duplicate completion items are deduplicated while preserving
higher-priority variants

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 16:08:14 +08:00
ykiko
2bbdf6c02b refactor(command): split CompilationContext into ResolvedFlags → CompileCommand → to_argv() (#408)
## Summary

- Replace flat `CompilationContext { directory, arguments }` with a
three-layer abstraction: `ResolvedFlags` (file-independent flags) →
`CompileCommand` (+ source file) → `to_argv()` (full argv on demand)
- `ResolvedFlags.flags` never contains source file path or
`-main-file-name`, making it directly usable as a clean cache key input
(e.g. PCH sharing across files with identical preambles)
- `to_argv()` handles `-main-file-name` insertion for cc1 mode
automatically — consumers no longer need to search/replace in the
argument list
- Eliminates the pollute-then-clean anti-pattern in `lookup()` and the
manual source-file replacement in `fill_header_context_args()`

## Test plan

- [x] `pixi run format` — no changes
- [x] `pixi run unit-test` — 481 passed
- [x] `pixi run integration-test` — 113 passed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Unified compile-command handling across the server and tools for more
consistent argument and flag behavior (driver vs frontend modes).
* **New Features**
* Added an LRU-backed in-memory cache to improve performance and
eviction control.
* **Chores**
* Added an option to control injection of resource-directory flags
(enabled by default).
* **Tests**
* Updated unit and integration tests to adopt the new command
representation and verify cache behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 22:18:25 +08:00
ykiko
9c9e6b0bcb refactor: introduce Workspace/Session state model and clarify component responsibilities (#406)
## Summary

Introduces a two-layer state model that cleanly separates disk-based
project state from per-open-file editing state, and redistributes
responsibilities across server components so each has a single, clear
role.

## New types

**Workspace** — all persistent, project-wide shared state:
- CompilationDatabase, PathPool, DependencyGraph, CompileGraph
- path_to_module mapping, PCH cache, PCM cache, PCM paths
- ProjectIndex, MergedIndex shards
- CliceConfig
- Methods: on_file_saved(), on_file_closed(), load/save/cleanup_cache(),
build_module_map(), fill_pcm_deps(), cancel_all()

**Session** — volatile per-open-file editing state:
- text, version, generation, ast_dirty
- pch_ref (references Workspace.pch_cache), ast_deps, header_context
- file_index (OpenFileIndex for unsaved buffer)
- path_id member for self-identification

## Component responsibilities after refactor

| Component | Role | Owns state? |
|-----------|------|-------------|
| **Workspace** | Disk truth + shared caches | Yes (all project state) |
| **Session** | One open file editing state | Yes (per-file only) |
| **Compiler** | Compilation pipeline, worker communication | No
(references only) |
| **Indexer** | Index queries + background indexing scheduling |
Scheduling state only |
| **MasterServer** | LSP protocol dispatch + lifecycle coordination |
sessions map |

## What moved where

**Into Workspace** (from Compiler/MasterServer):
- PCH/PCM cache management (load_cache, save_cache, cleanup_cache)
- Module map building (build_module_map, fill_pcm_deps)
- File lifecycle hooks (on_file_saved, on_file_closed)
- cancel_all, OpenFileIndex/MergedIndexShard type definitions

**Into Session** (from Compiler documents map):
- Document text, version, generation, ast_dirty
- PCH reference, dependency snapshot, header context

**Into Indexer** (from MasterServer):
- Background indexing queue, scheduling state, idle timer
- schedule(), enqueue(), run_background_indexing()

**Into syntax/completion.h** (from Compiler):
- detect_completion_context() — pure text parsing
- complete_module_import() — prefix match on module names
- complete_include_path() — directory listing against search paths

**Inlined into MasterServer** (from Compiler):
- didOpen/didChange/didClose/didSave handlers
- switchContext/currentContext
- publish_diagnostics/clear_diagnostics

**Deleted from Compiler** (9 methods):
- open_document, apply_changes, close_document, on_save
- switch_context, get_active_context, invalidate_host_contexts
- on_file_closed, on_file_saved, complete_include, complete_import

## Tests

- 481 tests pass (465 existing + 16 new completion tests)
- New: tests/unit/syntax/completion_tests.cpp

## Diff stats

15 files changed, +1857, -1555

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Enhanced completion support for include paths and module imports with
improved context detection.
* Added background indexing system for automatic project symbol
indexing.

* **Bug Fixes**
* Improved reliability of document change tracking and compilation state
management.
  * Better handling of header file compilation contexts.

* **Tests**
* Added unit tests for completion context detection and module/include
path completion.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:03:39 +08:00
ykiko
bb0b160a28 refactor(server): extract Indexer and Compiler from MasterServer (#403)
## Summary

- **Extract `Indexer` class** — owns all index state (ProjectIndex,
MergedIndex shards, OpenFileIndex) and query methods (definition,
references, call/type hierarchy, workspace symbol search)
- **Extract `Compiler` class** — owns document state, PCH/PCM cache,
compile argument resolution, header context, `ensure_compiled`, and
worker forwarding
- **MasterServer is now a pure LSP handler registration layer** (~700
lines, down from ~3200)
- **`MergedIndexShard`** wraps `index::MergedIndex` with a lazily-cached
PositionMapper; `OpenFileIndex` gains matching
`find_occurrence()`/`find_relations()` APIs — callers get pre-converted
LSP ranges directly
- **Indexer returns typed values** (`vector<Location>`,
`vector<CallHierarchyIncomingCall>`, etc.) instead of pre-serialized
JSON, fixing the references handler from JSON string surgery to simple
vector concatenation
- **Fix**: duplicate `workspace/symbol` loop in the original code

## Test plan

- [x] 465 unit tests pass
- [x] 113 integration tests pass
- [x] 2/2 smoke tests pass
- [x] `clang-format` applied

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Server-side C++ compilation orchestration (module & precompiled header
builds) with LSP-integrated document handling.

* **Improvements**
* Deterministic, persistent, dependency-aware caching to avoid redundant
rebuilds and speed up incremental work.
* Better cross-file indexing and navigation, improved diagnostics and
more reliable include/import-aware completions.

* **Tests**
  * Unit tests updated to the unified worker query/build request shapes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:30:12 +08:00
Shiyu
d253c1f099 feat: collect #embed and __has_embed directives in PPCallbacks (#309)
## Summary
- Add `Embed` and `HasEmbed` structs to `directive.h` for storing
`#embed` / `__has_embed` directive info
- Implement `EmbedDirective` and `HasEmbed` PPCallbacks in
`DirectiveCollector`, using the current `CompilationUnitRef` API
- Add unit tests for both directives (including non-existent file
handling)

Rebased onto current main, resolving conflicts from the `Compiler/` →
`compile/` restructuring and the `CompilationUnitRef` API migration.

Original PR by @Guo-Shiyu.

## Test plan
- [x] `pixi run unit-test` — 465 tests passed, 0 failures

Co-authored-by: ykiko <ykikoykikoykiko@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:51:26 +08:00
ykiko
e239b0d32c feat: smart PCH rebuild, #include/import completion, rapid-edit robustness (#394)
## Summary

### Preamble completeness check
- `is_preamble_complete()` in `scan.cpp`: checks whether
`#include`/`import`/`export module` directives in the preamble region
are syntactically complete (have closing `>`/`"`/`;`)
- `ensure_pch` defers PCH rebuild when preamble is incomplete (user
still typing), reuses old PCH instead of failing

### #include / import completion
- Master intercepts completion requests in `#include "..."` / `#include
<...>` / `import ...` contexts before forwarding to worker
- `complete_include()`: searches include paths (from compile args via
`SearchConfig`) using `DirListingCache`, supports
quoted/angled/multi-level paths
- `complete_import()`: filters `path_to_module` map by prefix
- Word boundary checks prevent false matches (e.g. `important` not
treated as `import`)

### Detached compile task (rapid-edit fix)
- Compile operations (`ensure_deps` + `send_stateful` +
`publish_diagnostics`) run as detached tasks via `loop.schedule()`,
independent of the LSP request coroutine chain
- LSP `$/cancelRequest` can no longer kill in-flight compilations —
previously, cancellation would destroy the `ensure_compiled` coroutine
frame, leaving `doc.compiling` permanently set and hanging all
subsequent requests
- `CompileGuard` RAII ensures `doc.compiling` is always cleaned up even
if the detached task fails
- Stale feature requests (where `ast_dirty` became true after compile
finished) are dropped before forwarding to worker

### Other fixes
- `signal(SIGPIPE, SIG_IGN)` on POSIX: prevents server crash when LSP
client disconnects mid-write
- `CompilationUnitRef::file_path()` / `deps()`: null-check
`FileEntryRef` to prevent segfault on invalid FileID
- `stateless_worker.cpp`: log BuildPCH diagnostic errors for
debuggability
- Default worker counts changed to 2 stateful + 3 stateless
- `logging_dir` default changed to `.clice/logs` in config

### Tests
- 19 unit tests for `is_preamble_complete` (incomplete `#include`,
`import`, `export module`, mixed cases)
- Integration tests: `test_include_completion.py` (5 tests),
`test_import_completion.py` (4 tests), `test_rapid_edit.py` (2 tests),
`test_pch.py` (4 new tests)
- Smoke test: `rapid_edit.jsonl` — recorded VSCode session with 40 rapid
edits + 61 cancel requests

## Test plan
- [x] Unit tests: 463 passed
- [x] Integration tests: 104 passed
- [x] Smoke test (rapid_edit.jsonl): PASS
- [x] Manual VSCode testing with `#include <iostream>` project

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:49:09 +08:00
Myriad-Dreamin
8d4ad26834 feat: classify dependent-name semantic token modifier (#387)
## Summary
- classify unresolved using declarations with the `dependentName`
semantic token modifier
- include the declaration modifier on definitions to match clangd's
semantic token behavior
- extend the semantic token modifier legend coverage in integration
tests

## Testing
- pixi run python -m pytest -s --log-cli-level=INFO
tests/integration/test_server.py -k 'semantic_token_modifier_legend or
capabilities' --executable=./build/bin/clice

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added many new semantic token modifiers (deprecated, deduced,
readonly, static, abstract, virtual, dependent-name,
constructor/destructor, user-defined, mutable-usage flags) and new scope
markers (function, class, file, global).
* Improved tagging for declarations, definitions and dependent names in
semantic tokens.

* **Tests**
* Added an integration test verifying the semantic token modifier legend
and its ordering.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-06 00:38:09 +08:00
ykiko
c14b8de18f chore: remove xmake, clean up unused files, simplify CLI parsing (#392)
## Summary
- **Remove xmake build system**: delete `xmake.lua`, `test-xmake.yml`
workflow, and all xmake-related pixi tasks
- **Migrate packaging to CMake**: `publish-clice.yml` now uses `cmake
-DCLICE_RELEASE=ON` instead of xmake pack
- **Clean up**: remove unused `tests/uv.lock`, `.xmake/` from
`.gitignore`, xmake references from docs
- **Benchmark CI**: change trigger from `pull_request` to
`workflow_dispatch` (manual only)
- **Simplify CLI parsing**: use `DecoKV(style =
KVStyle::JoinedOrSeparate)` in `clice.cc` and `unit_tests.cc`, replacing
verbose `DecoKVStyled` with manual `static_cast` bitmask; use comma
separators; explicit `names` only for underscore fields

## Test plan
- [x] `pixi run cmake-build RelWithDebInfo` compiles successfully
- [x] Verify `pixi run test` passes
- [x] Verify `pixi run package` produces correct archives via CMake
release build
- [x] Verify benchmark workflow can be triggered manually via `gh
workflow run benchmark`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Consolidated CI workflows; some automated triggers converted to manual
invocation
* Standardized shell for workflow steps and removed legacy build
workflow
* Switched packaging/build tasks to a CMake/Ninja flow and updated
artifact paths
  * Adjusted ignore rules to include previously-ignored build metadata

* **Documentation**
* Removed XMake-specific build and test instructions; docs now reflect
the CMake-based workflow

* **Style**
* Updated CLI option declaration style (no user-facing flag name
changes)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 17:33:20 +08:00
ykiko
3838bedcbf feat: persistent PCH/PCM cache across sessions (#391)
## Summary

PCH and PCM artifacts are now cached to disk at
`.clice/cache/{pch/,pcm/}` with content-addressed filenames, so they
survive server restarts. Dependency metadata is persisted in
`cache.json` (using eventide serde) with a shared path table for
deduplication.

### Key changes

- **protocol.h**: `output_path` field on `BuildPCHParams` /
`BuildPCMParams` so master specifies where workers write
- **stateless_worker.cpp**: Atomic write via `.tmp` + `fs::rename`;
`CompilationUnit` destroyed before rename to flush the file to disk;
fallback to temp file when `output_path` is empty (unit tests)
- **master_server.h**: `PCMState` struct, `pcm_states` map,
`load_cache()` / `save_cache()` / `cleanup_cache()` methods
- **master_server.cpp**: Cache lifecycle — load from `cache.json` on
startup, save after each PCH/PCM build and on exit; deterministic path
computation (`xxh3` preamble hash for PCH, module name + source path
hash for PCM); stale files (>7 days) cleaned on startup; `cache.json`
uses shared path table to avoid redundant storage of header paths across
entries
- **filesystem.h**: `fs::rename()` helper; `ThreadSafeFS` broadened to
match `.pch` extension instead of `preamble-` prefix
- **tests**: 11 new integration tests covering PCH/PCM persistence,
cross-session reuse, staleness detection, shared preamble dedup, and
restart survival; unit tests updated with `output_path`

### Naming scheme

- **PCH**: `.clice/cache/pch/<016x(xxh3(preamble))>.pch`
- **PCM**:
`.clice/cache/pcm/<module_name>-<016x(xxh3(source_path))>.pcm`

## Test plan

- [x] Unit tests — 448 passed
- [x] Integration tests — 92 passed (including 11 new persistent cache
tests)
- [x] Smoke tests — 1 passed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:29:21 +08:00
ykiko
31d9c609b6 fix: data race in stateful worker between Compile and DocumentUpdate (#389)
## Summary

Fix two data races in the stateful worker that caused spurious
"redefinition" errors during rapid edits, and remove a didChange
workaround that is no longer needed after clice-io/eventide#95.

### stateful_worker.cpp

**Compile handler**: move `params` → `doc` field copy **after**
`strand.lock()`. Previously the copy happened before the lock, so a
concurrent Compile request waiting on the strand could overwrite
`doc.text` while `et::queue` was reading it on the thread pool:

```
T1: Compile A → doc.text = text_A → lock → et::queue reads doc.text
T2: Compile B → doc.text = text_B → waits for strand (overwrites!)
T3: et::queue sees text_B instead of text_A → PCH/text mismatch
```

**DocumentUpdate handler**: only mark `dirty`, stop modifying
`doc.text`/`doc.version`. The event loop notification can fire while
`et::queue` work is running on the thread pool — writing `doc.text` from
one thread while reading it from another is a data race.

### master_server.cpp

Remove the `{0,0}-{0,0}` range workaround for whole-document
`didChange`. eventide's variant deserialization now correctly rejects
`TextDocumentContentChangePartial` when the `range` field is absent
(clice-io/eventide#95), so `TextDocumentContentChangeWholeDocument` is
matched as intended.

### protocol.h

Remove `text` field from `DocumentUpdateParams` — the worker no longer
needs it since DocumentUpdate only sets the dirty flag.

### Integration tests (+312 lines)

Extend test_staleness.py from 5 to 14 tests covering document lifecycle:
- `didChange` body edit → recompilation with updated diagnostics
- `didChange` preamble edit → PCH rebuild + clean recompilation
- `didClose` + reopen → compiles fresh from disk
- `didClose` → hover returns None
- `didSave` header → dependent file recompiles
- `didSave` module → CompileGraph dependents invalidated

## Test plan

- [x] 422 unit tests pass (426 on CI with extra test suites)
- [x] 14 integration tests pass locally
- [x] Depends on clice-io/eventide#95 (merged)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Smaller document-update notifications sent to background workers (only
path and version).

* **Bug Fixes**
  * Reduced races and unnecessary work between update and compile flows.
* Prevented notifications from overwriting in-memory document text,
improving state consistency.
* Safer concurrent handling to avoid mid-request eviction of active
documents.

* **Tests**
* Added integration tests for staleness, dependency propagation, and LSP
lifecycle.
  * Updated unit tests to match revised update behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 12:20:13 +08:00
ykiko
a1b6c0632d refactor(semantic): rewrite template resolver — eliminate SubstType, fix crashes (#388)
## Summary

Rewrites the template resolver to eliminate
`SubstType`/`CodeSynthesisContexts` dependency, fixing widespread
crashes on real-world C++ code.

### What changed

**Architecture**: replaced double-TreeTransform (PseudoInstantiator +
SubstType) with single-layer design:
- **`SubstituteOnly`** — new lightweight TreeTransform for Phase 2
(typedef expansion + parameter substitution). Does NOT override
`TransformDependentNameType`, breaking the typedef ↔ lookup infinite
cycle.
- **`PseudoInstantiator`** — retains heuristic lookup (the unique value
clang doesn't provide), delegates substitution to `SubstituteOnly`.

**Deleted**:
- `DesugarOnly` class
- `instantiate()` method and all `CodeSynthesisContexts` / `SubstType`
usage
- `state()` / `rewind()` stack management
- `std::abort()` on valid NNS kinds
- `#ifndef NDEBUG` debug flag + `std::print` logging

**Added**:
- `SubstituteOnly` class with depth guard
- `InstantiationStack::findArgument()` — depth/index based parameter
lookup
- CTD→TST resolution for `DependentTemplateSpecializationType` (enables
`__alloc_traits::rebind<T>::other` resolution)
- `active_resolutions` (DNT cycle detection) + `active_ctd_lookups` (CTD
cycle detection via RAII guard)
- Stack frame pollution fix: pop lookup frames before further
`TransformType`
- Pack argument support (single-element forwarding)
- Null safety on all Transform return paths
- Structured `LOG_DEBUG` trace logging with indentation
- `--log-level` / `--test-filter` CLI options for unit test runner
- Bounds checks in `hole()`, `ResugarOnly`, `visitTemplateDeclContexts`

**Tests**: 20 → 36 passing test cases (+5 documented TODOs for known
limitations). New coverage: recursive base classes, multiple
inheritance, typedef chains, CRTP, `remove_reference` partial specs,
`std::map`, `std::basic_string`, pack forwarding.

### Stress test result

```
CDB: llvm-project build (4669 C++ files)
Types resolved: 3,690,190
Types unchanged: 75,907,298
Crashes: 0
```

Before this PR, the same test produced ~52% crash rate (413 crashes in
800 files).

### Known limitations (documented as TODOs)

- NTTP partial specialization matching (`enable_if<true, X>`, `A<X, 0>`)
- Template template parameter deduction
- Non-dependent qualifier nested class templates
(`Outer<int>::Inner<X>`)
- Multi-element pack expansion
- `CXXDependentScopeMemberExpr` lookup (unimplemented)
- Operator-name lookup in dependent contexts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Enhanced template resolution with improved cycle detection to prevent
infinite loops
  * Better type substitution handling for complex dependent types

* **Bug Fixes**
  * Fixed edge cases in template specialization resolution
  * Improved null-safety in type transformations
  * Enhanced handling of standard library template traits

* **Tests**
  * Expanded test coverage for recursive and complex template patterns
  * Added validation for standard library type resolution

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:18:07 +08:00
ykiko
e24eff6c16 refactor: pull-based compilation for document lifecycle (#385)
## Summary

Replace the push-based compilation model with a pull-based (lazy) model
where compilation is driven entirely by feature requests.

### Server core (`master_server.cpp/h`)
- **Remove** `schedule_build()`, `run_build_drain()`, debounce timers,
and `DocumentState` flags (`build_running`, `build_requested`,
`drain_scheduled`)
- **Remove** `debounce_ms` config field
- `didOpen`/`didChange` only update `DocumentState` and mark `ast_dirty`
— no compilation triggered
- `didSave` marks dependent docs dirty via `CompileGraph::update()`,
invalidates PCH hashes, marks **all** open documents `ast_dirty` (header
saves), and queues background indexing
- **Implement** `ensure_compiled(path_id)` — the pull-based entry point
called by `forward_stateful()`/`forward_stateless()` before every
feature request:
  1. Fast-path if `!ast_dirty`
  2. Compile C++20 module deps via `compile_graph->compile_deps()`
  3. Build/reuse PCH via `ensure_pch()` (only attach on success)
  4. Send `CompileParams` to stateful worker
  5. Publish diagnostics, clear dirty, schedule indexing
  6. Generation mismatch → return `false`, keep dirty for retry
- `forward_stateless()` now also calls `compile_graph->compile_deps()`
before stateless requests (completion/signatureHelp)
- Move module-implementation-unit implicit dependency handling into
`resolve_fn` (was duplicated in `run_build_drain` and `ensure_compiled`)

### CompileGraph (`compile_graph.cpp/h`)
- **Add** `compile_deps(path_id)` — compiles all transitive module
dependencies but NOT the file itself (used for plain .cpp files that
`import` modules)
- Unify `compile`/`compile_deps` via `compile_impl(path_id, ancestors,
dispatch_self)` parameter
- `compile_deps` compiles dependencies concurrently via `when_all`
- Extract `finish()` lambda to deduplicate `compiling=false;
completion->set()` cleanup across all exit paths
- Use `std::ranges::remove` instead of legacy `std::remove`

### Test infrastructure (`conftest.py`)
- `open_and_wait()` now sends a hover request to trigger
`ensure_compiled()` (pull-based model requires a feature request to
compile)
- Fix URI handling: send percent-encoded URI on the wire, normalize for
internal lookups, store diagnostics under both raw and normalized URI
keys
- Add `_normalize_uri()` helper using `urllib.parse.unquote`

### Integration tests
- Update all tests for pull-based model: no more waiting on `didOpen`
diagnostics
- `_wait_for_index()` sends hover to trigger compilation before polling
`workspace/symbol`
- `test_hover_save_close` simplified — hover directly triggers
compilation
- `test_save_recompile` and `test_pch_*` wait for fresh diagnostics
after hover-triggered recompilation

### Unit tests (`compile_graph_tests.cpp`)
- Extract `compiled`/`graph` as TEST_SUITE members with
`std::optional<CompileGraph>`
- Extract `execute(callback)` helper to deduplicate event_loop
boilerplate
- Add 8 new `compile_deps` tests: no-deps, single dep, chain, diamond,
failure, plain-cpp, concurrent dedup, resolve-once
- Remove redundant `inline` on file-scope helpers

## Test plan
- [x] Unit tests: 426 passed, 5 skipped
- [x] Smoke tests: 1/1 passed
- [x] Integration tests: 69 passed, 0 failed, no hangs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 02:35:17 +08:00
ykiko
e43bb14998 feat: implement index system with LSP query handlers (#382)
## Summary

Implement the complete index system for cross-file LSP features. This
adds persistent two-tier indexing (ProjectIndex + per-file MergedIndex
shards), background indexing triggered on idle, and index-based query
handlers for major LSP requests.

### Index Data Layer (`src/index/`)

- **TUIndex**: Add binary serialization/deserialization via FlatBuffers,
enabling IPC between stateless worker and master server
- **ProjectIndex**: Add symbol name/kind storage, `PathPool` path
normalization (backslash -> forward slash), and binary persistence
- **MergedIndex**: Add `content` field to store file content for
reliable offset<->position mapping; add `removed` bitmap for garbage
collection of deleted entries; filter removed IDs in `lookup()` queries
- **schema.fbs**: Add TUIndex tables, `Symbol.name` field,
`MergedIndex.removed` bitmap and `MergedIndex.content` string

### Server (`src/server/`)

- **Background indexing**: Idle-triggered coroutine dequeues files from
CDB, dispatches `IndexParams` to stateless workers, merges returned
`TUIndex` into ProjectIndex/MergedIndex, and persists to `.clice/index/`
- **Index persistence**: `save_index()` / `load_index()` for startup
restoration; only rewrites shards flagged `need_rewrite()`
- **LSP handlers**:
- `textDocument/definition` -- index-first lookup with stateful worker
fallback
  - `textDocument/references` -- cross-file reference query via index
- `callHierarchy/prepare`, `incomingCalls`, `outgoingCalls` --
Caller/Callee relation traversal
- `typeHierarchy/prepare`, `supertypes`, `subtypes` -- Base/Derived
relation traversal
- `workspace/symbol` -- case-insensitive substring search over
ProjectIndex symbols
- **Stateless worker**: Add `Index` request handler that builds
`TUIndex` from compiled AST and returns serialized data
- **Config**: Add `enable_indexing` (default true) and `idle_timeout_ms`
(default 3000ms)

### Fixes and Cross-platform

- **ElaboratedType handling** in `decl_of()` for correct Base/Derived
relation emission
- **Windows path normalization** in `PathPool::intern()` and
`ProjectIndex::from()` (backslash -> forward slash)
- **`.gitattributes`**: Force LF in `tests/data/**` to prevent CRLF
byte-offset mismatches on Windows CI
- **Test fixture**: Clean `.clice/` before each test for hermetic index
state

### Tests

- **370-line** `index_query_tests.cpp`: unit tests for occurrence
lookup, relation queries, content retrieval, removed bitmap filtering
- **282-line** `test_index.py`: E2E integration tests for
GoToDefinition, FindReferences, CallHierarchy
(prepare/incoming/outgoing), TypeHierarchy
(prepare/supertypes/subtypes), WorkspaceSymbol
- Updated existing MergedIndex and ProjectIndex tests for new schema
fields

## Test plan

- [x] 414 C++ unit tests pass (including new IndexQuery, MergedIndex,
ProjectIndex tests)
- [x] 69 Python integration tests pass (including 10 new index feature
tests)
- [x] CI green on Linux, macOS, Windows
- [ ] Manual smoke test with VSCode extension

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 00:20:41 +08:00
ykiko
21a969af27 feat: integrate PCH into MasterServer build drain (#381)
## Summary
- Add `ensure_pch()` helper to MasterServer that builds/reuses
precompiled headers via stateless workers, with preamble hash-based
staleness detection (xxh3_64bits)
- Fix `BuildPCHParams` to carry `preamble_bound` so the stateless worker
truncates content at the preamble boundary (fixes redefinition errors
when PCH included full file)
- Wire PCH into both `run_build_drain` (stateful compile path) and
`forward_stateless` (completion/signatureHelp path)
- Add PCH state cleanup on `didClose` and hash invalidation on `didSave`

## Test plan
- [x] 398 unit tests pass (including 6 new PCH tests: PreambleHash x3,
PCHWorker x2, BuildPCHRequest assertion)
- [x] 5 new integration tests pass (`test_pch.py`: diagnostics on open,
body edit recompile, no-include file, hover with PCH, completion with
PCH)
- [x] 21 existing integration tests pass unchanged
- [x] Build succeeds with 0 errors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Precompiled header (PCH) caching to speed compilations and reduce edit
latency
* Automatic attachment of cached PCH to compile requests, improving
hover and completion responsiveness
* Module-aware completions expanded to include available module
artifacts from other files

* **Bug Fixes**
* PCH cache cleared on file close; saving now triggers broader PCH
invalidation to prevent stale PCH use

* **Tests**
* Added unit and integration tests exercising PCH build, reuse, and
editor interactions
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-01 18:33:33 +08:00
ykiko
bc04845293 refactor(tests): CMake-based CDB, workspace fixture, test cleanup (#378)
## Summary

- **CMake-based CDB generation for module tests**: Replace hand-written
compile_commands.json with CMakeLists.txt (CMake 3.28 `FILE_SET
CXX_MODULES`) in all 26 `tests/data/modules/*/` directories. CDB is
generated on-the-fly via `cmake -G Ninja` during test setup.
- **`@pytest.mark.workspace()` decorator**: Introduce a marker + fixture
pattern so tests declare their workspace via decorator and receive a
resolved `workspace` path. The fixture auto-generates CDB when a
CMakeLists.txt is present.
- **`CliceClient` helper methods**: Add `initialize()`, `open()`,
`wait_diagnostics()`, and `open_and_wait()` to reduce boilerplate across
all test files.
- **Use `asyncio_mode = "auto"`**: Switch from `@pytest_asyncio.fixture`
+ `@pytest.mark.asyncio` to `@pytest.fixture` + auto mode for proper
Pylance type inference on fixtures.
- **Test cleanup**: Remove redundant section separators and docstrings,
delete `tests/pyproject.toml` (config moved to `pytest.ini`).
- **Format task**: Add `.cppm` to `format-cpp` glob pattern.
- **CI fix**: Disable `CMAKE_CXX_SCAN_FOR_MODULES` and prefer pixi
clang++ to fix macOS CI where CMake rejects module scanning.

## Test plan

- [x] All 26 module test directories have CMakeLists.txt with FILE_SET
CXX_MODULES
- [x] generate_cdb() produces valid compile_commands.json with module
flags
- [x] Integration tests pass locally
- [ ] CI passes on all platforms (Linux, macOS, Windows)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Unified fixtures and client workflow: new init/open/wait helpers,
workspace marker support, bounded diagnostics waiting, CMake-based
compilation-database generation, and directory-backed temp-file
workflows; enabled asyncio test mode.
* **Chores**
* Added many C++20 module test projects and test data; removed prior
test pyproject in favor of pytest config; updated formatter to include
.cppm files.
* **Style**
* Reformatted many module/source implementations to consistent
multi-line function bodies.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 16:57:48 +08:00
ykiko
0a891d8b4a refactor(tests): use Tester fixture, normalize helpers, add index tests (#377)
## Summary

- **Use `Tester` as fixture base** for all test suites that need
compilation, replacing `TesterFixture` and removing redundant
`tester.clear()` calls (eventide zest now creates fresh instances per
TEST_CASE)
- **Remove local `Tester` variables** in `compilation_tests`,
`template_resolver_tests`, `selection_tests` — use inherited fixture
members directly
- **Normalize helper naming**: `expect_xxx` → `EXPECT_XXX`,
`go_to_definition` → `GO_TO_DEFINITION` for consistency
- **Extract shared `test/cdb_helper.h`**: deduplicate `CDBEntry`,
`json_escape`, `build_cdb_json` from `dependency_graph_tests` and
`compile_graph_integration_tests`
- **Add new test files/cases**: `project_index_tests.cpp`, expanded
`tu_index_tests`, `merged_index_tests`, `compilation_tests`

## Test plan

- [x] All existing unit tests pass
- [x] New index tests (TUIndex, MergedIndex, ProjectIndex) pass
- [x] Compilation tests (PCH, PCM, stop) pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Standardized test fixtures and helper naming, moved suites to a shared
fixture, and unified in-memory VFS and compile flows.
* Added broad new coverage: indexing, project indexing, compilation/PCH,
diagnostics, semantic features, and many targeted unit cases.
* Introduced a small compile-database helper and improved driver-style
test compilation paths.

* **Chores**
* Consolidated and reorganized test utilities and tester APIs for easier
maintenance and reuse.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 10:29:49 +08:00
ykiko
6d3b6acc82 feat: initial CompileGraph integration into MasterServer (#376)
## Summary

Initial integration of `CompileGraph` (#375) into `MasterServer`,
enabling basic end-to-end C++20 module support: on-demand PCM building,
dependency-ordered compilation, cascade invalidation on save, and
diagnostic integration.

This is a **first-pass implementation** — the core pipeline works, but
there are known areas for follow-up:

- PCM files go to system temp dir instead of `.clice/cache/`; no disk
cleanup on invalidation
- `run_build_drain` scans imports itself rather than delegating fully to
CompileGraph
- No incremental/partial rebuild (full PCM rebuild on any change)
- Cycle detection is tested at unit level but integration-level coverage
is minimal

## Changes

### Module dependency compilation (`master_server.cpp`)

Before sending a file to the stateful worker, `run_build_drain` now:

1. Scans imports via `scan_precise()` to discover module dependencies
2. Compiles each dep through `compile_graph->compile()`, which
recursively builds transitive PCMs
3. Handles implementation units — `module M;` implicitly needs the
interface PCM
4. Passes all built PCMs to the stateful worker, excluding the file's
own PCM
5. Skips compile on dep failure and resets `build_running` /
`drain_scheduled`
6. Re-lookups iterators after `co_await` to avoid use-after-invalidation

### Cascade invalidation (`didSave` / `didClose`)

- `didSave`: calls `compile_graph->update()` to mark transitive
dependents dirty, removes stale PCM paths, schedules rebuilds for open
dirtied files
- `didClose`: cancels in-flight compilations for the closed file

### Other fixes in this PR

- Debounce timers switched to `shared_ptr` to prevent use-after-free
when `didClose` destroys the timer mid-wait
- `fill_compile_args` returns `bool`; callers handle empty CDB
gracefully
- Adapt all `PositionMapper` call sites to the new `optional` return API
from eventide

## Test plan

- [x] 25 C++ unit tests for CompileGraph (cycles, partial failure,
cancel, update, empty graph)
- [x] 24 C++ integration tests with real clang PCM compilation
- [x] 3 worker-level module tests (BuildPCM, PCM-dependent compile,
multi-module)
- [x] 26 Python LSP integration tests (single module through circular
deps, hover, error diagnostics)
- [x] 371 unit tests + 54 integration tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 20:05:58 +08:00
ykiko
7ed558c1e7 feat: add CompileGraph for pull-based module dependency compilation (#375)
## Summary

Add `CompileGraph`, a pull-based async scheduler for C++20 module
compilation. When a file is compiled that imports modules, the graph
automatically resolves, builds, and caches PCM dependencies in the
correct order before the main compile proceeds.

## Design

### Data model

Each compilation unit (`CompileUnit`) tracks:
- `dependencies` / `dependents` — forward and reverse dependency edges
- `dirty` / `compiling` — current state flags
- `generation` — monotonic counter incremented by `update()`, used for
ABA-safe stale detection
- `source` + `completion` — cancellation token source and completion
event for cooperative async

### `compile(path_id)` — pull-based compilation

Lazily resolves dependencies (via `resolve_fn`) on first access, then
recursively compiles all transitive deps before dispatching the unit
itself:

- **Concurrent**: sibling deps compiled in parallel via `when_all`
- **Dedup**: diamond dependencies (A->B->D, A->C->D) — the second branch
waits on the first via `completion.wait()` instead of re-compiling
- **Cycle detection**: per-branch `ancestors` set (passed by value)
catches direct cycles; `has_wait_cycle()` BFS catches cross-branch
cycles (e.g. `1->{2,3}, 2->3, 3->2`) that would deadlock at
`completion.wait()`
- **Cancellation**: all `co_await` wrapped with `with_token()`, so
`update()` can cancel in-flight compilations immediately
- **Generation check**: captures generation counter before `co_await`;
if `update()` bumped it during dispatch, the result is discarded (unit
stays dirty)

### `update(path_id)` — cascade invalidation

BFS along `dependents` edges to mark the entire reverse-transitive
closure as dirty. For the source node, clears `resolved` and dependency
edges so they are re-scanned on next compile. Cancels any in-flight
compilations via `source->cancel()`.

## Test plan

22 unit tests covering:
- [x] No deps, single dep, chain, diamond (compile ordering + dedup)
- [x] Update invalidation, cascade through chains and diamonds
- [x] Re-resolution after update (deps can change)
- [x] Stale back-edge cleanup
- [x] Direct cycle detection (A->B->A)
- [x] Cross-branch cycle detection (when_all deadlock case)
- [x] Self-loop
- [x] Dispatch failure propagation
- [x] cancel_all + recompile
- [x] Update during in-flight compile (cancellation + generation check)
- [x] CI green on Linux, macOS, Windows

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 14:38:15 +08:00
ykiko
a536865fca feat: add scan_module_decl() fallback for conditional module declarations (#373)
## Summary

- Add `scan_module_decl()` — a lightweight preprocessor-based fallback
that resolves module declarations inside `#if`/`#ifdef` conditionals.
When `scan()` detects `need_preprocess=true`, this function runs clang's
preprocessor to evaluate conditions and extract the actual module name.
It stops lexing as soon as the module declaration is found, making it
much cheaper than `scan_precise()`.
- Integrate the fallback into `scan_dependency_graph()` for wave 0
source files, so conditional module declarations (e.g. `#ifdef
USE_MODULES / export module M; / #endif`) are correctly registered in
the dependency graph.
- Add comprehensive test cases covering all C++20 module declaration
forms from cppreference, including `scan_module_decl()` tests for
conditional resolution and `scan_precise()` tests for module import
semantics.

## Test plan

- [x] All 310 unit tests pass (0 failures, 9 skipped)
- [x] `scan()` tests cover: primary interface, implementation, dotted
names, partitions, GMF, conditional module declarations, private module
fragment
- [x] `scan_module_decl()` tests cover: basic, conditional with `-D`,
conditional with `#if` expression, GMF with conditional, implementation
unit, dotted name, partition, no-module file
- [x] `scan_precise()` tests cover: named import, multiple imports,
dotted import, partition import, export-import, export-import partition,
implementation import, GMF with import, mixed includes/imports,
no-module file

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved detection of module declarations hidden by conditional
compilation via a lightweight fallback scan. Resolved module vs.
interface classification is cached to avoid repeated work and is used
consistently in dependency mapping.
* Better handling and classification of module imports, partitions, and
global-fragment includes when building module relationships.

* **Tests**
* Added comprehensive unit tests covering module declaration extraction,
fallback resolution under preprocessor guards, imports, partitions,
includes, and macro-driven cases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 22:27:49 +08:00
ykiko
f8a39147a7 feat: add include resolver, dependency graph, BFS scanner (#368)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 17:40:29 +08:00
ykiko
46ba1e4db6 refactor: simplify CompilationDatabase, extract ArgumentParser, remove pimpl (#371)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 13:15:49 +08:00
ykiko
498c975042 feat: add SearchConfig, ToolchainProvider, PathPool and related tests (#370)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 21:27:18 +08:00
ykiko
848065265c refactor: move resource_dir to CompilationDatabase, rename test dirs (#369)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 10:40:20 +08:00
ykiko
f7a8d104ce refactor: move command files to src/command/, remove scan_fuzzy (#366)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 23:54:32 +08:00
ykiko
020c2cb3cc feat: implement multi-process LSP server architecture (#364)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 23:37:08 +08:00
ykiko
73afcfbb58 refactor: introduce syntax/scan module with DependencyDirectivesGetter (#357)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:45:31 +08:00
ykiko
ce2f355988 refactor: introduce eventide and rewrite server architecture (#355) 2026-03-01 18:17:02 +08:00
ykiko
dd8f0dd90d refactor: diagnostic handling (#337) 2026-01-03 16:23:06 +08:00
ykiko
7a29560065 build: optimize the workflow (#331) 2025-12-29 09:19:45 +08:00
ykiko
7105e36803 chore: use pixi to manage the format tools and format the world (#330) 2025-12-28 19:36:06 +08:00
ykiko
cec13ec29b refactor: tests and format the world (#314) 2025-11-30 15:21:27 +08:00
ykiko
8aff090a08 refactor: incremental update for compilation database and introduce query toolchain (#311) 2025-11-23 18:43:36 +08:00
ykiko
9e1039f861 refactor: improve logging (#301) 2025-11-08 00:37:07 +08:00
ykiko
336ca639f0 refactor: CompilationDatabase and scan (#286) 2025-11-05 23:01:28 +08:00
ykiko
397eb71dad build: update llvm to 21.1.4 (#292) 2025-11-02 22:23:11 +08:00