Tags: clice-io/clice
Tags
chore(docs): collapsible examples, dated changelogs, bot sync token (#… …587) ## What changed - **Feature-doc examples now render collapsed.** `tools/feature_docs.ts` wraps each generated example in `<details><summary>Example</summary>` (plain HTML rather than VitePress's `::: details`, so the collapse also works on GitHub). All six fixture-generated feature docs regenerated; item titles, status boxes and descriptions stay visible, only the code folds. - **Per-feature `## Changelog` tables normalized.** Every row now carries the real merge date (`YYYY-MM-DD`) and an inline PR link, recovered from git history; rows are reverse-chronological. `—` remains only in the PR column for changes predating the PR workflow. Also fixes hover's changelog date: #452 merged 2026-06-12, not 2025-06. - **Docs sync switched to the bot account.** The deploy job in `main.yml` now uses the `CLICE_DOCS` secret (fine-grained PAT of `clice-bot`) instead of `PUBLISH_DOCS`, so sync PRs in the docs repo no longer impersonate the maintainer. Merging this PR touches `docs/**` and will itself exercise the new token end to end. - Removed `docs/semantic-tokens-example.cpp`, unreferenced since the tests refactor. ## Tests - All four suites pass locally (unit 1174, integration 341, smoke 3, snap 395). - `pixi run check-feature-docs`, `npm run check`, `pixi run format` all clean. - VitePress build of the docs site verified locally with the regenerated pages; the rendered HTML contains the collapsed `<details>` blocks.
chore: upgrade LLVM to 22.1.8 (#586) ## What changed Upgrades the prebuilt LLVM dependency from 21.1.8 to 22.1.8 and adapts clice to the LLVM 22 API. Highlights: - **NNS redesign / ElaboratedType removal** (llvm/llvm-project#147835): `NestedNameSpecifier` is a value type and types carry their elaborated keyword and qualifier themselves. Rewrote NNS handling in the template resolver, semantic visitor, unifier, display, and USR generation; `rewrite_specifier` collapses to a single type-component rewrite since prefixes now live inside type nodes. - **DependentTemplateSpecializationType removed** (llvm/llvm-project#158109): dependent specializations are `TemplateSpecializationType`s with a `DependentTemplateName`. The resolver's DTST lookup/rewrite/pseudo-SFINAE paths merged into the TST paths. - **CompilerInstance owns its VFS** (llvm/llvm-project#158381): compilation and scan now seed the instance VFS before creating diagnostics and the file manager. - **clangOptions split** (llvm/llvm-project#167374) and the new `SUBCOMMANDIDS_OFFSET` OPTION column (llvm/llvm-project#155026): include-path and macro updates in the argument parser. - Assorted renames: `getCanonicalTagType`, `getCanonicalTemplateSpecializationType`, `UsingType::getDecl`, `sys::path::make_absolute`, `clang::GetResourcesPath`. Behavioral changes visible in features (all matching clang/clangd 22 rendering, pinned in snapshots): `__size_t (aka unsigned long)` sugar, `(unnamed enum)` naming, namespace-qualified canonical class types in hover, and converted (qualified) template arguments in hover titles for implicit variable template specializations. One deliberate divergence from clangd: inlay type hints keep written class scopes (`S2::Nested<int>`) that LLVM 22's `SuppressScope` would now drop — restored by printing the outer node's written qualifier. Also cherry-picks the release-triple normalization + prebuilt-respin fixes (`/MT`, macOS deployment target) that the 22.1.8 prebuilt was built with, and adds an `LLVM 21 → 22` section to the LLVM changelog documenting every breaking change with upstream references. Note: CI stays red until the pruned 22.1.8 `clice-llvm` release is published (release-llvm is running against this branch); the version pin in `cmake/package.cmake` will be bumped in a follow-up commit on this branch once it is up. ## Tests All four suites pass locally against the 22.1.8 prebuilt: unit (1174), integration (341), smoke (3/3), snap (393). Snapshot updates are limited to the upstream rendering changes listed above; one selection-tree unit test was re-marked because dependent qualifier chains are now `DependentNameTypeLoc` components with name-only ranges.
refactor(tests): snap multi-file fixtures, materialized workspaces (#585 ) ## What changed A large cleanup and refactor of the snap test framework, plus the migration of the last unit snapshot tests into it. **Multi-file fixtures.** A fixture is now either a single `.cpp` at the corpus root or a subdirectory entered through its `main.cpp` — one unit whose sibling sources (module interfaces, headers, extra sources) belong to it. Files carrying `§`-markers participate in the test; the rest are support. When more than one file participates, the snapshot partitions per file with `--- <file>` section headers. - `clice inspect` treats a directory input as one unit: every file is stripped and remapped into every compile, module interfaces are built serially into PCMs in dependency order (edges from `scan_precise`; the lexer-level `scan_quick` deliberately never reports imports, since import tokens are macro-expanded per [cpp.import] — `scan` was renamed to `scan_quick` and both scan functions now document the standard guarantees from P1857R3 / [cpp.module]/2 that make lexer-level module-declaration detection sound), and a new `--flags` channel (JSON array) replaces CDB lookup for harness-driven runs. - The server path materializes each fixture into a throwaway workspace: stripped sources and a generated CDB on disk, so disk and `didOpen` agree, fixtures never share state, and the corpus workspace lock is gone — the suite dropped from ~19s to ~8s locally, and no `compile_commands.json` is written into the corpus anymore. **Frontmatter.** Fixture meta now has two orthogonal axes — `verify: both|inspect|server` (which paths run) and `snap: shared|separate|skip` (how the two paths of a `verify: both` fixture relate) — plus `diagnostics: expected` (replaces the `error-ok` comment directive; a gate that fails on unexpected diagnostics and on a stale declaration), `indexing: true` (background indexing off by default on the server path), and per-fixture `flags`. Corpus-wide flags live in a `corpus.json` manifest with `${corpus}` substitution and a `config_section` override (the `inlay_hint` corpus configures `[inlay_hints]`). The old wire/standalone vocabulary is gone everywhere; snapshot variants are `<name>.inspect.snap.yml` / `<name>.server.snap.yml`. **TS reshape.** `tools/snap/` is now a corpus model (`corpus.ts`), shared render primitives (`render.ts`), one module per feature with a `fromInspect`/`fromServer` adapter pair feeding a single formatter (`features/*.ts`), and a single registry both drivers resolve through. Shared snapshots stay owned by the inspect driver; a non-owning snapshot context now refuses to author missing files. **Unit snapshot tests migrated and machinery retired.** The `tu_index` snapshot glob became a `verify: inspect` corpus backed by a new `tu_index` inspect dump; the hover `present*` snapshot tests are replaced by a config-A/B fixture pinning the markdown and plaintext renderings on both paths — enabled by promoting `HoverOptions` to a real `[hover]` config section wired through the worker (documented in the configuration guide); `parse_documentation` became inline assertions. `tests/snapshots/unit/` and the `--snapshot-dir` flag are gone. The module scan unit tests were merged into one file using the `#[file]` multi-file fixture grammar. Hover cards for macros, headers and invalid symbol kinds were only reachable by hand-built `HoverInfo` values, not by the real pipeline (verified empirically); their synthetic tests were removed rather than ported, and the renderer branches they pinned will regain coverage when the features that produce them (e.g. macro expansion preview) land. ## Tests All four suites (unit, integration, smoke, snap) pass locally on both RelWithDebInfo and Debug (ASan), plus `npm run check`. New tests: multi-file/module-diamond inspect driver tests, corpus meta and snapshot-ownership unit tests, quick-vs-precise scan contract tests (`ImportsNotCollected`, `ImportMacroExpandedName`, `ConditionalImport`), `#elif`/`#include_next` scan cases. Snapshot churn is line-number shifts from fixture headers gaining meta keys (audited: positions only), plus two new snapshots (`tu_index`, hover `presentation`).
chore: split agent docs into skills, add pr workflow (#582) ## What changed - Slimmed `.claude/CLAUDE.md` (277 → ~65 lines): project overview, hard rules, working style, source layout, and short build/test/commit references. All detailed knowledge moved into skills. - Migrated every `.claude/commands/*` file to a skill; `build` and `test` run in forked context and return only a digest. - New skills: - `cpp-style` — the C++ conventions, extended with sections distilled from the codebase: redundancy elimination, file organization (`.cc` entry points vs `.cpp`), no-exceptions/no-RTTI error policy, `std::unreachable` over `llvm_unreachable`, struct-first types, kota coroutines, `LOG_*` logging. - `pr` — the full pipeline from "code is ready" to "ready to merge": pre-push verification, three-way self-review, opening rules, a sustained watch loop (CI + review threads each round), maintainer merges. - `resolve-comments` (forked) — pulls unresolved review threads via GraphQL, applies root-cause fixes, resolves every handled thread, returns a compact summary. - `write-tests` absorbed the snap snapshot-ownership rules (`shared`/`separate`/`skip`) and test style notes from CLAUDE.md. - Cleanup per the new convention: replaced the 5 remaining `llvm_unreachable` calls with `std::unreachable()`. All sites verified unreachable (guarded by dyn_cast branches, an assert, an exhaustive switch, and a tree-root invariant). Note: unlike `llvm_unreachable`, `std::unreachable` does not abort loudly in assert builds — accepted deliberately; the sites are invariant-protected. - `.gitignore`: re-include `.claude/skills/build/` (the `*build*/` rule would swallow it), drop the obsolete `.claude/commands/` entry. ## Tests All four suites pass locally on RelWithDebInfo: unit 1171, integration 336, smoke 3/3, snap 389. Doc-only commits after that run touch no code. Three parallel review agents (correctness / style / tests) went over the diff; their findings are fixed in the last commit.
refactor(config): born-valid options, layered decode, drop mirrors (#576 ) ## What Unifies the config system around one set of structs and one decode mechanism, then simplifies everything that existed to work around the old split. **One struct set.** Feature options structs (`CodeCompletionOptions`, `InlayHintsOptions`) now double as their clice.toml / initializationOptions sections: every field is `defaulted<T>` with its default as the field initializer. The all-optional mirror structs (`InlayHintsConfig`, `CodeCompletionConfig`) are deleted, along with all three hand-written field-by-field overlay blocks (`apply_defaults`, the compiler copy sites, inspect's `--config` parser). Adding a new option key is now a one-line change. **Born-valid Config.** A default-constructed `Config` is fully valid — no two-phase init, `with_defaults()` is gone. `apply_defaults()` shrinks to `finalize()`: derived paths, `${workspace}` substitution, canonicalization, rule glob compilation, and validation (an explicit zero worker count / memory budget is warned and reset — it was previously a silent auto sentinel). **Layering is the decode.** Config sources are decoded sequentially onto one object (clice.toml, then initializationOptions); the decoder only touches named fields and nested sections merge per field. This is the mechanism the server already used for the initializationOptions overlay — the refactor removes everything that duplicated it. **Workers carry the whole Config.** `QueryParams`/`BuildParams` lose their per-feature forwarded option fields (`inlay_options`, `completion_options`) and carry one `Config`; features read their own section. No per-feature forwarding field is ever added again. Also: the dead `project.max_active_file` knob is removed (it had no reader; unknown keys in existing configs surface as a warning, not an error), and the tiny `document_link.h` / `inactive_regions.h` headers are folded into `feature.h`. ## Compatibility No key renames — existing clice.toml files and initializationOptions payloads behave identically, except `max_active_file` (now an unknown-key warning) and explicit zero worker counts (now warned and reset instead of silently corrected). ## Tests New unit tests pin the load-bearing semantics: section deep-merge across TOML/JSON layers (including a field set in both — later source wins), JSON `null` on an option is a decode error, typos inside feature sections still warn, the full born-valid default surface, and zero-value validation. All four suites pass on RelWithDebInfo plus unit tests under Debug (ASan + assertions); the snap suite passes with zero snapshot diffs, confirming the wire behavior is unchanged.
feat(completion): snap corpora, config channel and wire-only fixtures (… …#574) ## What Migrates code completion and signature help to the snap framework and deletes their unit test files. Every deleted assertion is now pinned by a snapshot fixture, and the corpora grow well beyond the old coverage (42 fixtures across both features). ### clice inspect - New completion shape: each `§` marker gets its own completion compile (the offset parameterizes the parse itself), plus one plain compile for the clean-fixture gate. - `--config=<json>`: a strict partial overlay onto the feature options, decoded through the same all-optional mirror the server config uses. Unknown keys are errors. ### Server - New `[code_completion]` config section (mirrors `feature::CodeCompletionOptions` field by field, same pattern as `[inlay_hints]`), resolved by the master per request and threaded through `BuildParams` to the stateless worker. Options like `bundle_overloads` now actually take effect over LSP. ### Snap framework - `config:` fixture meta — A/B snapshots: the same markers pinned under default options and under the overlay (`default:` / `configured:` blocks). The wire side replays the configured half on a second server initialized with `initializationOptions`, so a shared snapshot cross-checks the server config plumbing against inspect byte-for-byte. - `snap: wire` — fixtures whose feature path only exists in the server (include and import completion, answered by the master); the wire suite owns their snapshots. - Multi-file fixtures: a corpus subdirectory entered through `main.cpp` is one fixture and **its own workspace** — it gets its own generated CDB, the wire session initializes on it, and sibling sources are opened first (module registration). Units are fully isolated from each other. - Completion/signature snapshots pin the top 10 items (score desc, label asc) and announce any cut with a `… +N more` tail. ### Docs `completion.md` and `signature-help.md` now render generated items from the corpora, like the other migrated features. ## Found along the way (not fixed here) - Four of the six `CodeCompletionOptions` knobs are plumbed but never read by the feature: `enable_keyword_snippet`, `enable_template_arguments_snippet`, `insert_paren_in_function_call`, `limit`. Docs now mark them unimplemented. - Macro completion does not fire (the collector's default `CodeCompleteOptions` excludes macros); the docs previously claimed it worked. - Private members are not filtered from member completion outside the class. ## Testing All four suites pass locally: unit (with docs check), integration, smoke, and snap (update + verify runs byte-identical). The snap suite pins every fixture from both the standalone and wire paths.
refactor(syntax): in-place lexer, lexical scan, Module/Comment nodes (#… …573) ## Summary This round refactors the lexing layer and gives the semantics table first-class coverage of everything the AST and preprocessor callbacks fail to record. ### Lexer - **In-place lexing**: `Lexer::from_line(content, offset)` starts at the line containing `offset`; token ranges stay in file coordinates, so they compose directly with feature offsets. The hand-written `rfind('\n') → substr → rebase` dance at call sites is gone. - Positional bool parameters replaced by `LexerOptions`; the dead `ignore_end_of_directive` flag and the unused `is_directive_keyword` helper removed. - **Header-name automation** now covers the `__has_include`/`__has_embed` family (mode switches after the opening paren) and the `#import` directive; the residual "pick the filename argument" grammar moved next to its only consumer (document links). - Retained comments are **transparent to the directive state machine**: a line-leading comment no longer consumes the start-of-line state or ends the module-declaration context. - clang's NUL-terminated-buffer contract is documented and asserted: lex full buffers or suffixes, never a prefix slice; bound the lexing logically instead. ### lexical_scan (new) One pass over the file collects what neither the AST nor PPCallbacks report, as structured data: comments (range + line/block kind) and the three module-declaration forms (`module;`, `[export] module x.y:z;`, `module :private;`) with per-token ranges. ### Semantics table: Module and Comment nodes New `Module` and `Comment` node kinds are fed by the lexical scan at build time, cross-checked against the compiler before becoming nodes: named-module gate, DefinitionLoc anchor for the declaration form (macro-spelled names survive, disabled-branch duplicates die), spelled-token liveness for the private fragment. Module nodes own their written tokens like other directive nodes. Consumers then deleted their own scanners: - **semantic_tokens**: the module-declaration matcher and the per-request whole-file comment scan are gone; comments come precomputed from the table (build-time once instead of per request), module tokens paint from the node like imports do. - **tu_index**: the module-declaration lexer state machine is gone; the occurrence is emitted from the validated table data, partition span included. ### Fixes along the way - `#pragma region/endregion` is classified by the first argument token instead of substring matching — a pragma merely *mentioning* "endregion" no longer closes a fold early (pinned by a new folding fixture). - `is_preamble_complete`: a trailing comment no longer hides a terminating semicolon (or fakes one), and angled `#import <...>` completes. - `detect_completion_context` rewritten on the lexer: comment-tolerant, exact keyword boundaries, and the cursor-at-line-start case no longer leaks the previous line. - A wire-only divergence where the global module fragment lost its keyword highlight under a preamble PCH (its spelled token counts as preprocessed-away there) — gates are now per-form and the case is pinned by a PCH unit test. ### Import-channel audit The preprocessor callback channel and the AST `ImportDecl` channel agree on all three import forms (named, export-import, partition); pinned by a unit test. The preamble-PCH boundary remains the shared, by-design gap handled per feature by PreambleState. ## Tests - New unit coverage: lexer in-place lexing / header-name automation / incomplete input, lexical_scan with negative controls (identifier named `module`, strings, comments, disabled branches), semantics-table nodes and gates, module painting under a real PCH split, partition and implementation-unit indexing, preamble/completion edge cases including CRLF and cursor-mid-keyword. - New folding fixture for the pragma classification fix; feature docs regenerated. - All four suites green on both Debug and RelWithDebInfo; zero snapshot drift outside the new fixture.
feat(document symbols): specializations, aliases, macro names, semant… …ics walk (#566) Third per-feature round after semantic tokens (#564) and inlay hints (#565): document symbols gets its traversal migrated onto the `Semantics` node table, four outline bugs fixed (plus one table-level bug in the builder), and its snap corpus rewoven into 24 doc-generating fixtures. ## Traversal migrated onto the semantics node table `document_symbols.cpp` no longer runs a `FilteredASTVisitor` over the TU. A single `Collector` walks the cached `unit.semantics().node_entries()` — the DFS pre-order record of the interested file's written AST. Nesting comes for free: a symbol's frame stays open while the walk index is inside its `subtree_end`, so the outline tree is rebuilt with a plain `(subtree_end, cursor)` stack, and implicit instantiations are skipped as an index jump. The migration was proven equivalent against the pre-existing snapshots and full unit suite before any behavior was changed. One behavior improvement falls out of the table's recording contract: abbreviated function templates (`void f(Concept auto x)`) used to vanish from the outline entirely — the written `FunctionDecl` hides inside an implicit `FunctionTemplateDecl`, which the old visitor skipped wholesale. The builder records written children of implicit decls, so these functions now appear (pinned in `kinds_templates`). ## Table-level fix: structured bindings recorded twice Namespace-scope `BindingDecl`s are members of the enclosing `DeclContext` *and* explicitly traversed by `TraverseDecompositionDecl`'s bindings loop, so the builder recorded each one twice — every table consumer saw doubles (the outline showed each binding twice). The builder now records a `BindingDecl` only when its walk parent is its own `DecompositionDecl`. Block-scope and TU-scope bindings were already single-visit; both are pinned. ## Outline fixes - **Template specializations**: explicit and partial specializations of class and variable templates never appeared (`is_interested` lacked their decl kinds); their members were orphaned at namespace level. Now `Box<void>`, `Box<T*>`, `pi<int>`, `pi<T*>` appear with members correctly nested. - **Type aliases**: `typedef`, `using` aliases and alias templates never appeared at all. They now render with a `type alias` detail, mapped to LSP `Class` (matching clangd). - **Multi-token name selection ranges**: `~Widget` selected only the `~`; `operator==` and `operator bool` selected only `operator`. Selection ranges now come from `DeclarationNameInfo` and cover the full written name. - **Names spelled in macro arguments** (clangd#1941): `VAR(name)` selected the macro name instead of `name`. The name range now goes through `getFileLoc`, so argument-spelled names select their written spelling while body-spelled names keep the invocation site; the symbol range is widened when needed to preserve the LSP range ⊇ selection-range invariant. ## Corpus rewoven: 24 fixtures, doc generated from them The 4 seed fixtures were replaced by 24 itemized fixtures with `///` doc headers; `document_symbol` is registered in `feature_docs.ts` and the checklist sections of `docs/en/features/document-symbols.md` are now generated from the corpus. Probes confirmed several checklist items are supported by construction and are now pinned: default-argument stripping (clangd#221), multiline signature ranges (clangd#2221), macro-expansion symbol locations (clangd#475), friend function definitions, local symbols inside function bodies (clangd#616), and UTF-16 column counting (CJK fixture). Unsupported items (access-specifier grouping clangd#499, base-class detail, macro/include/module/`#pragma mark` outline entries, symbol tags clangd#2123) are recorded as compiled-out stubs. The count-based unit tests are retired; every case they touched is pinned structurally by a snapshot, including implicit instantiations *not* appearing. ## Verification All four suites green: unit (1168) and snap (280) on both RelWithDebInfo and Debug (LLVM assertions), integration (336), smoke (3/3), `npm run check`, `feature_docs.ts check`. Three-way pre-PR review (correctness / style / test coverage); findings addressed: inline comment style, reuse of `decls::is_implicit_instantiation`, and three added pins (implicit instantiation absence, block-scope bindings, static data member + named nested struct).
refactor(semantic): rewrite TemplateResolver without Sema (#560) ## Summary Rewrites `TemplateResolver` to work directly on the AST, dropping its dependency on `Sema`/`TreeTransform` entirely. The resolver now only needs an `ASTContext`, which removes the diagnostic-silencing layer and the `TypeLoc` plumbing the old implementation required. On top of the rewrite, this PR went through extensive review hardening (~15 bot-review rounds, 60+ findings triaged; every confirmed defect fixed with a pinned regression test). ## Design - **New `TypeUnifier`** (`src/semantic/unifier.{h,cpp}`): Sema-free structural unification of template argument lists, replacing `Sema::DeduceTemplateArguments` and partial ordering. Works on sugared types (bindings stay as-written: `T = std::string`, not the canonical expansion) and binds template parameters to dependent arguments, which pseudo-instantiation relies on. - **Rewritten `TemplateResolver`** (`src/semantic/resolver.{h,cpp}`), key invariants: - Canonical specialization arguments simulate Sema's argument conversion (trailing pack grouping, default filling, alias heads carry their computed aliased type) through a single construction point, so results compare canonically equal to parsed types. - Instantiation frames match parameters by **decl pointer**, not depth — unrelated same-depth templates can never capture each other's parameters (incl. across redeclarations). - Pseudo-SFINAE probe with a three-state verdict (Found / Absent / Unknown). Absent requires a conclusive proof: recursion-guard trips, step-budget exhaustion, dependent arguments with member-declaring specializations, dependent bases, non-type/non-public/template-kind mismatches all stay Unknown or prune correctly. - Node-keyed resolution caches never store context-dependent results (scope-threaded, pack-narrowed, or budget-truncated resolutions are not cached). ## Capabilities Primary/partial/explicit specialization member lookup (incl. bases), alias templates (defaults, template template parameter binding, dependent template names), NNS chains, pointers/references (collapsing) / arrays (constant, unbounded, dependent bounds with value forwarding) / function types (noexcept incl. deduction and substitution of bare operands, method cv/ref qualifiers, ABI info, parameter decay) / member pointers / `__underlying_type` / `_Atomic` / attributed and decayed wrappers; structured pack expansion element-wise (type, template and value packs, lockstep zip, per-element consistency, arity-determined non-trailing suffixes, empty-pack cardinality); overload candidate filtering by call arity (incl. C++23 explicit object parameters and pack-expansion arguments), wired through semantic tokens, hover and indexing; partial-ordering ambiguity and unverifiable constrained partials degrade instead of guessing. ## Crash safety The resolver must never crash on any input, including error-recovery ASTs from mid-edit code. Every AST construction site guards its preconditions (malformed pointers/references/arrays/member pointers/function types/atomics degrade); two crash-safety sweeps (`StandardSweep` over libstdc++-heavy TUs, `BrokenCodeSweep` over deliberately broken code) run under the assertion-enabled ASan Debug build on every CI platform — this caught a libc++-only abort (dependent template names in specialization heads) and a dangling-pointer bug in pack narrowing (fixed via stable slot handles). ## Known limitations (follow-up PR) Expression-level matching was never part of this design: compound NTTP expressions (`X<N + 1>`), post-deduction validation of dependent-name/decltype patterns, dependent noexcept beyond bare operands, and constraint subsumption (constrained partials currently degrade to unresolved) are deferred to a dedicated follow-up. `TODO(nttp-expr)` anchors mark the sites. All of these degrade — they never produce wrong answers or crashes. ## Tests Resolver unit suite: 171 cases (each review finding pinned by a regression test with a negative control where applicable). All four suites pass locally on both Debug and RelWithDebInfo.
refactor(semantic): retire find_target and activate TemplateResolver (#… …558) ## Background clice inherited two parallel answers to "which declaration does this token name": - `find_target` — a per-node targeting helper ported from clangd, driven by `HeuristicResolver` (clangd's shallow dependent-name resolver: direct lookup in the primary template, no partial specializations, no argument deduction, no typedef-chain expansion). Hover was its only consumer. - clice's own `TemplateResolver` — a deep dependent-name resolver built on Sema pseudo-instantiation (tracks parameter propagation, matches partial specializations, expands typedef chains). It was implemented long ago but **never wired into any feature**. #557 replaced the per-query SelectionTree machinery with the unified per-compilation `Semantics` map: one AST traversal, one extraction function (`resolve_occurrences`) serving hover, semantic tokens and the index. That left find_target as the last private AST walker — redundant machinery on a weaker resolver. This PR finishes the story: find_target and the HeuristicResolver dependency are deleted, and `TemplateResolver` is activated as the single dependent-name authority for every consumer of the semantic map. ## What changed - **`resolve_occurrences` takes a `TemplateResolver*`**: dependent constructs (`DependentNameType`, `DependentTemplateSpecializationType`, dependent nested-name specifiers, `DependentScopeDeclRefExpr`, `UnresolvedUsing{Value,Typename}Decl`) resolve through pseudo-instantiation and emit `WeakReference` occurrences. All three consumers pass the unit's resolver, so the index and semantic tokens now see dependent names too — not just hover. - **`TemplateResolver::lookup(CXXDependentScopeMemberExpr)` is now real** (it was a hardcoded empty stub): the base type is resolved through pseudo-instantiation — including unwrapping the injected class name for `this` — and the member is looked up in the resolved record. `this->foo()` inherited from `Base<T>` resolves again, and deeper than HeuristicResolver ever did. - **Hover reads the map**: a hover-local `decls_at` walks the touched token's owner and ancestor chain and collects every declaration whose occurrence sits on that token — the formal answer to "one position, several declarations". `find_target.{h,cpp}` deleted. - **Extraction coverage completed** (review-driven, each pinned by a fixture or unit test): ctor-initializer members, designated-initializer fields, rewritten comparison operators, CTAD placeholders, injected class names, `UsingType`, using-shadow unwrapping (declaration site and overload sets), labels, template-template arguments, `sizeof...(pack)`, class-provided `operator new`/`delete` (anchored on the keyword even when `::`-qualified), constructor references on construction punctuation, `__super`, namespace-alias-preserving using-directives, `UnresolvedMemberExpr` candidate sets. ## Hardening surfaced by the migration - **Windows worker crashes (0xC0000005) root-caused to the resolver's TreeTransform derivatives**: they never overrode `getBaseLocation()` (the base-class `setBase` is a no-op CRTP trap), so every synthesized `TypeLoc` carried invalid locations, and `TypeLocBuilder::push` records were left fully uninitialized — garbage qualifier pointers that crashed any later `getSourceRange()` (Debug builds hit the equivalent Sema assertions). All transformers now carry a valid base location and every pushed record is initialized. - **Speculative diagnostics no longer leak**: resolver lookups on real-world headers emitted error-level diagnostics into the unit (and even tripped Sema's error limit). Lookups now run under a consumer swap; error *counting* deliberately still accumulates — per-lookup resets hand every pathological instantiation chain a fresh budget, which measures as minutes of resolver time on STL-heavy TUs. The trade-off is documented in code; a resolver-owned work budget is planned follow-up work. - **Integration workspace lock is now FIFO**: the mkdir-poll lock let a worker whose tests run back-to-back re-acquire within microseconds while cross-process waiters polled on a 100 ms clock — structural starvation behind the long-standing `socket mode connects` CI timeouts. A ticket queue (dead-owner tickets self-clean) restores fairness. ## Cost Full-TU indexing of an STL-heavy TU: ~80 ms with the resolver vs ~55 ms without (warm) — the resolver only engages on dependent constructs and caches per node. The interactive path is unaffected: per-edit, main-file-only indexing stays sub-millisecond. ## Testing All previously failing hover fixtures reproduce their old snapshots byte-identically; no snapshot was regenerated over a divergence. New coverage: dependent-name and dependent-member hover fixtures pinning the resolver end to end, plus index unit tests for the new relation rows. All four suites pass locally in both configurations (unit 1064, snap 76, integration 332, smoke).
PreviousNext