You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Replace the current C/C++ navigation artifact with one shared clangd-owned
semantic provider. The final provider must preserve Clang indexing roles and
relations in incremental background-index shards, treat headers as
translation-unit/configuration views, and export one atomic C/C++ generation
without reparsing every translation unit twice.
Current master baseline
PR #147 registers one scip-clang provider for C and C++, prepares/validates a compilation database,
tracks generated inputs, and publishes both languages from one session.
Current strict grounding intentionally claims no edge families:
scip-clang 0.4.0 omits the enclosing source information required by the common
adapter to attribute even references safely.
The exact cold results were:
Redis C: 22.795 s strict versus 262.906 s clangd LSP fallback;
LevelDB C++: 8.353 s strict versus 26.452 s fallback.
Those fast strict cells are useful navigation baselines, not proof of calls,
reads/writes, construction, inheritance, overrides or complete headers.
The generic/static discovery bug is separately verified on master: LANGUAGE_SPECS assigns .h only to C and source enumeration for a C++-only
request can omit .h entirely. A request for both languages partitions every .h into C. Strict scip-clang documents can override that guess, but generic and
static lanes cannot.
Correct semantic model for headers
compile_commands.json contains translation units, not header rows. A header's
semantic language and preprocessor state come from each including translation
unit. Therefore:
Inclusion context
Required graph view
only C TUs
C
only C++ TUs
C++
both, or different defines/targets
separate semantic views in one atomic universe
Do not replace the extension guess with “look up the header in the compilation
database”; no direct entry exists. Build an include-graph/TU ownership map from
the actual index. A shared header may have several legitimate expansions.
Why SCIP plus a second AST pass is rejected as the final route
scip-clang is a maintained portable fallback, but:
it builds its own descriptor scheme rather than publishing Clang USRs;
internal-linkage twins and macros have identity risks;
it deduplicates well-behaved headers through an arbitrary including TU;
the common artifact does not prove call/read/write/construction roles; and
it is batch-only.
A separate libclang/AST enrichment pass would parse every TU a second time,
roughly paying another compiler analysis and losing clangd's resident preambles
and invalidation. That violates the speed objective.
Clang already exposes the required vocabulary. Its SymbolRole includes
declaration, definition, reference, read, write, call, dynamic, implicit,
address-of and relation roles. IndexDataConsumer receives semantic
occurrences. Clangd already stores content-addressed per-file background-index
shards and incremental updates through BackgroundIndex
and BackgroundIndexStorage.
The current clangd shard/collector drops facts the graph needs.
Decision: thin clangd fork
Maintain a narrowly scoped, commit-pinned clangd fork that changes collection,
shard schema and bulk export:
retain every relevant Clang role bit and relation endpoint;
retain local/file-static declarations and their enclosing semantic owner;
store declarations and definitions with full spans;
store includes/modules, macros and expansion/spelling evidence;
record the exact compile-command digest and TU/configuration identity;
This is more than adding transport, so it supersedes the earlier “do not fork
clangd merely to add transport” recommendation. An upstreamable design is still
preferred, but the semantic loss in current storage justifies the thin fork.
Fact mapping
contains: semantic owner relation, including locals and anonymous
declarations;
imports: include/import/module evidence, keeping textual include distinct
in provenance;
calls: call role and called relation;
accesses: read/write roles;
instantiates: constructor calls and construction expressions;
type_ref: type-role references;
extends/implements: direct base relation, with C++ class/protocol modeling
documented rather than guessed;
overrides: direct override relation;
references: reference role;
exports: linkage/module export only where the language/build proves it;
decorates: attributes from the same AST/index event if retained;
tests and renders: framework enrichers, not core Clang facts.
A virtual call normally proves a declaration plus the override closure, not one
executed implementation. Store candidates in structured unresolved data.
Emit exact dispatches only for a compiler-proven closed/final target.
Inactive preprocessor branches are conditional-build.
Identity and universe
Use Clang USRs as the semantic core, then add the coordinates required where a
USR is not globally sufficient:
compile target/configuration;
TU/file discriminator for internal linkage;
module/target triple and language mode;
macro spelling/definition identity plus expansion evidence; and
source owner for local entities.
Exact fixtures must prove:
same-named static functions in two C files do not collide;
anonymous namespaces and anonymous types remain distinct;
overload insertion/reordering does not rename unrelated functions;
templates, specializations and instantiations are not conflated;
a macro survives unrelated line insertion where the compiler identity does;
and
one .h included as C and C++ retains both views without cross-contamination.
The universe includes every compilation command, driver, working directory,
defines, standard, include/module paths, sysroot, target, generated header and
dependency digest. A compilation database is necessary but not sufficient when
wrappers or generated inputs are unresolved. Fail closed to clangd/static
fallback when preparation cannot prove them.
Incremental and platform design
Reuse clangd's preambles, AST caches and digest-based background index.
header change: invalidate every including TU reported by the include graph;
compilation database/config/generated-header change: invalidate the affected
command universe;
delete/rename: explicit shard deletion; and
mid-export shard movement/cancel/crash: keep the prior graph.
Do not run clangd-indexer and call it incremental; its monolithic export is
batch. Do not force --jobs=1 or producer-side deterministic scheduling:
master already canonicalizes incoming facts, and serializing scip-clang caused
orders-of-magnitude slowdowns without fixing header selection.
scip-clang's release assets do not provide a stock Windows binary. The final
fork must have reproducible Windows, Linux and macOS builds or explicitly
decline. Compiler-wrapper and MSVC-clang-cl compatibility belong in the
platform matrix.
Implementation map
Fix source discovery so .h reaches ownership resolution before language
partitioning; add generic/static regression tests.
Prototype full-role collection in a pinned clangd fork and publish a schema
capability handshake.
Add a provider beside the existing scip-clang entry; keep the latter as
portable fallback.
Adapt changed shards through the common transaction and preserve dual C/C++
language slices.
Add exact C and C++ fixtures before real Redis/LevelDB smoke.
Package and verify the fork on all supported platforms.
Acceptance
No per-symbol LSP requests and no duplicate TU semantic analysis in the
final path.
Headers are owned by include/TU configuration, never a global extension
guess.
All 15 fact families carry explicit coverage/unresolved status.
Same header in multiple TUs/configurations is neither arbitrarily
deduplicated nor duplicated as the same identity.
No-op, edit, header, compdb, generated input, create/delete/rename,
compiler error, cancel, crash and retry are atomic.
Cold time is compared with native clangd background indexing; no-op p95
targets below 250 ms and one-TU body edit is proportional to the affected
shard closure.
Windows, Linux and macOS selection/packaging/fallback are proven.
Redis and LevelDB smokes assert exact representative calls, access roles,
type and inheritance facts, not counts.
Outcome
Replace the current C/C++ navigation artifact with one shared clangd-owned
semantic provider. The final provider must preserve Clang indexing roles and
relations in incremental background-index shards, treat headers as
translation-unit/configuration views, and export one atomic C/C++ generation
without reparsing every translation unit twice.
Current master baseline
PR #147 registers one
scip-clangprovider for C and C++, prepares/validates a compilation database,tracks generated inputs, and publishes both languages from one session.
Current strict grounding intentionally claims no edge families:
scip-clang 0.4.0 omits the enclosing source information required by the common
adapter to attribute even references safely.
The exact cold results were:
Those fast strict cells are useful navigation baselines, not proof of calls,
reads/writes, construction, inheritance, overrides or complete headers.
The generic/static discovery bug is separately verified on master:
LANGUAGE_SPECSassigns.honly to C and source enumeration for a C++-onlyrequest can omit
.hentirely. A request for both languages partitions every.hinto C. Strict scip-clang documents can override that guess, but generic andstatic lanes cannot.
Correct semantic model for headers
compile_commands.jsoncontains translation units, not header rows. A header'ssemantic language and preprocessor state come from each including translation
unit. Therefore:
Do not replace the extension guess with “look up the header in the compilation
database”; no direct entry exists. Build an include-graph/TU ownership map from
the actual index. A shared header may have several legitimate expansions.
Why SCIP plus a second AST pass is rejected as the final route
scip-clang is a maintained portable fallback, but:
A separate libclang/AST enrichment pass would parse every TU a second time,
roughly paying another compiler analysis and losing clangd's resident preambles
and invalidation. That violates the speed objective.
Clang already exposes the required vocabulary. Its
SymbolRoleincludesdeclaration, definition, reference, read, write, call, dynamic, implicit,
address-of and relation roles.
IndexDataConsumerreceives semanticoccurrences. Clangd already stores content-addressed per-file background-index
shards and incremental updates through
BackgroundIndexand
BackgroundIndexStorage.The current clangd shard/collector drops facts the graph needs.
Decision: thin clangd fork
Maintain a narrowly scoped, commit-pinned clangd fork that changes collection,
shard schema and bulk export:
samchon/graphSnapshotrequest/CLI that freezes the required shardset, streams it through [Bulk index] Replace symbol-by-symbol LSP scans with compiler-owned snapshots #63's protocol, and refuses to commit if the
compilation database or relevant shard generation moves.
This is more than adding transport, so it supersedes the earlier “do not fork
clangd merely to add transport” recommendation. An upstreamable design is still
preferred, but the semantic loss in current storage justifies the thin fork.
Fact mapping
contains: semantic owner relation, including locals and anonymousdeclarations;
imports: include/import/module evidence, keeping textual include distinctin provenance;
calls: call role and called relation;accesses: read/write roles;instantiates: constructor calls and construction expressions;type_ref: type-role references;extends/implements: direct base relation, with C++ class/protocol modelingdocumented rather than guessed;
overrides: direct override relation;references: reference role;exports: linkage/module export only where the language/build proves it;decorates: attributes from the same AST/index event if retained;testsandrenders: framework enrichers, not core Clang facts.A virtual call normally proves a declaration plus the override closure, not one
executed implementation. Store candidates in structured unresolved data.
Emit exact
dispatchesonly for a compiler-proven closed/final target.Inactive preprocessor branches are
conditional-build.Identity and universe
Use Clang USRs as the semantic core, then add the coordinates required where a
USR is not globally sufficient:
Exact fixtures must prove:
staticfunctions in two C files do not collide;and
.hincluded as C and C++ retains both views without cross-contamination.The universe includes every compilation command, driver, working directory,
defines, standard, include/module paths, sysroot, target, generated header and
dependency digest. A compilation database is necessary but not sufficient when
wrappers or generated inputs are unresolved. Fail closed to clangd/static
fallback when preparation cannot prove them.
Incremental and platform design
Reuse clangd's preambles, AST caches and digest-based background index.
views;
command universe;
Do not run
clangd-indexerand call it incremental; its monolithic export isbatch. Do not force
--jobs=1or producer-side deterministic scheduling:master already canonicalizes incoming facts, and serializing scip-clang caused
orders-of-magnitude slowdowns without fixing header selection.
scip-clang's release assets do not provide a stock Windows binary. The final
fork must have reproducible Windows, Linux and macOS builds or explicitly
decline. Compiler-wrapper and MSVC-clang-cl compatibility belong in the
platform matrix.
Implementation map
.hreaches ownership resolution before languagepartitioning; add generic/static regression tests.
capability handshake.
scip-clangentry; keep the latter asportable fallback.
language slices.
Acceptance
final path.
guess.
generated headers, overloads, templates/specializations, constructors,
fields, inheritance, overrides and virtual calls.
deduplicated nor duplicated as the same identity.
compiler error, cancel, crash and retry are atomic.
targets below 250 ms and one-TU body edit is proportional to the affected
shard closure.
type and inheritance facts, not counts.
pnpm build,pnpm test, andpnpm coveragepass.Primary references