Skip to content

Tags: clice-io/clice

Tags

v0.1.2026080903

Toggle v0.1.2026080903's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.

v0.1.2026080803

Toggle v0.1.2026080803's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.

v0.1.2026080704

Toggle v0.1.2026080704's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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`).

v0.1.2026080605

Toggle v0.1.2026080605's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.

v0.1.2026080405

Toggle v0.1.2026080405's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.

v0.1.2026080305

Toggle v0.1.2026080305's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.

v0.1.2026080205

Toggle v0.1.2026080205's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.

v0.1.2026080105

Toggle v0.1.2026080105's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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).

v0.1.2026073105

Toggle v0.1.2026073105's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.

v0.1.2026073005

Toggle v0.1.2026073005's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
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).