Tags: clice-io/clice
Tags
chore: upgrade kotatsu, adopt renamed codec entries and KOTATSU_ANNOT… …ATE (#590) ## What changed Bumps the kotatsu pin from `c516e3a` (#181) to `340a32a` (#196) and migrates every call site to the new API surface: - **Codec entry points** now follow kotatsu's payload-based naming: `json::to_json` → `json::to_string`, `json::from_json`/`json::parse` → `json::from_string`, `toml::parse<T>(text)` → `toml::from_string<T>(text)`, `toml::from_toml<Config>(text, out)` → `toml::from_string<Config>(text, out)`. `bincode::to_bytes`/`from_bytes` are unchanged. No flatbuffers migration — clice has no `codec::fbs` call sites; the codec just stays enabled. - **Annotations**: the old `kota::meta::defaulted<T>` / `annotation<T, attrs::skip>` wrappers were removed upstream, so `Config`/`ProjectConfig`/`TrackerConfig`/`ConfigRule`, the three feature options structs, and the cache-metadata struct in `workspace.cpp` now use the `KOTATSU_ANNOTATE(defaulted = true, ...)` / `KOTATSU_ANNOTATE(skip = true)` macro. The macro expands to the same `annotation<T, spec<Tag>>` wrapper, so field access (`.value`, aggregate inheritance) and decode semantics are unchanged. - Every user-facing config option now carries a `description = "..."` attribute (validated against actual usage; options that are declared but not consumed yet are marked "not yet implemented"). The internal cache struct keeps `defaulted` only. - **.clang-format**: ports kotatsu's `StatementMacros: KOTATSU_ANNOTATE` (keeps `<T> field;` on its own line) and `BreakAdjacentStringLiterals: true` (stacks long description literals). The latter reflows adjacent string literals in ~10 test files — content-identical, formatting only. ## Tests All four suites locally on Debug: unit 1167/1167 (7 skipped), integration 340 passed / 2 skipped, smoke 3/3, snap 395 passed / 68 skipped. Unit suite re-run after the final doc-string fixes.
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.
PreviousNext