samchon / samchon/compiler-knowledge-graph

[Bulk index][Swift] Freeze SourceKit index generations through IndexStoreDB

Open
#78 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
TypeScript
Stars
6
Forks
3
PR merge metrics
No merged PRs in 30d

Description

Outcome

Export Swift facts from the compiler-generated index store already maintained by
SourceKit-LSP/build tooling, freeze an explicit set of output units as one graph
generation, and enrich each changed source once for spans/signatures/access/
attributes. Do not rely on a mutable store-wide scan or issue per-symbol
SourceKit requests.

Current master baseline

No Swift strict provider is registered. PR #147 intentionally withdrew the
placeholder because no compiled IndexStoreDB sidecar exists; Swift remains on
its ordinary SourceKit-LSP/static fallback and has no committed strict timing
cell.

The feasibility gate nevertheless passes:

  • Swift/Clang emit index-unit and record files during compilation;
  • IndexStoreDB provides efficient
    symbol/occurrence/relation queries over that data; and
  • SourceKit-LSP already owns background target preparation, per-source indexing,
    up-to-date tracking and scheduling.

The official
background-indexing design
states that cross-file references use the index store, that target preparation
performs minimal dependency-module work, and that unchanged source units can
take a fast path without launching the compiler.

Consistency finding

Individual index unit files are written atomically, so torn unit contents are
not the main hazard. The store is append-oriented and can contain stale units
from prior targets/builds. A mutable global query can also observe a different
unit set from the one preparation just completed.

IndexStoreDB's public explicit-output-unit mode is the generation primitive:
construct/read with useExplicitOutputUnits, name the exact output-unit paths,
wait for processing, and query only that set. workspace/synchronize is a
useful readiness fence but does not itself make the store immutable after the
request returns.

Decision: SourceKit-LSP hook preferred, standalone sidecar fallback

Resident preferred route

Add an upstreamable custom request or narrow pinned SourceKit-LSP extension in
the same process that owns SemanticIndexManager and its build system:

  1. resolve the exact target/build settings and expected output-unit paths;
  2. wait for target preparation and source indexing using existing scheduling;
  3. capture the explicit unit set and its build/source manifest under the
    manager's serialized state;
  4. query occurrences/relations for that frozen set;
  5. run one changed-source SourceKit/SwiftSyntax enrichment pass; and
  6. commit only if build settings, source hashes and unit set remain unchanged.

This route reuses the resident compiler/index caches and avoids reconstructing
the SwiftPM/Xcode build plan outside the owning server.

Standalone fallback

A compiled Swift sidecar linked to the toolchain-matching IndexStoreDB may read
an isolated store created by a completed swift build --enable-index-store, or
a caller-supplied explicit unit list. It is suitable for CI/batch operation but
must not claim resident incrementality without the SourceKit-LSP owner.

Pin IndexStoreDB by the branch and commit matching the Swift toolchain; it does
not offer a normal semver release line, and libIndexStore compatibility is a
hard gate.

Fact mapping

Index-store roles/relations directly support:

  • contains via child/owner relations;
  • calls via call/called-by roles;
  • accesses via read/write/accessor roles;
  • direct base/conformance and override relations;
  • references;
  • construction from a constructor call; and
  • type references filtered by compiler symbol kind.

Module-unit dependencies support imports; syntax enrichment provides exact
import statement spans. unitTests() can identify test symbols, while
test-to-subject needs a named call-graph/framework enricher.

The index lacks complete declaration spans, signatures, access levels and
attributes/property-wrapper detail. Enrich them in one per-source pass using
the same build settings and map them by Swift USR/source occurrence. Do not
call cursor-info once per symbol.

The dynamic role proves a call is dynamically dispatched, not which
implementation executes. Candidate overrides/conformances belong in unresolved
data. Emit exact dispatches only for a statically closed final target.

Identity and build universe

Swift USRs are the primary persistent identity and handle overloads, modules,
generics and extensions better than position-based schemes. Explicitly cover:

  • locals, which require the compiler index-local option and a stable
    owner/source namespace;
  • macro-generated declarations and source mappings;
  • extensions and synthesized accessors;
  • same symbol compiled for multiple triples/configurations; and
  • Objective-C/C cross-language occurrences.

The universe includes toolchain/IndexStoreDB commit, package/Xcode/BSP target,
triple, SDK, configuration, Swift language/features, compiler flags, module
dependencies, package resolution, plugins/macros, generated sources and exact
output-unit set. Conditional compilation outside that universe is
conditional-build, not absent.

Incremental and performance behavior

Reuse SourceKit-LSP's status trackers and task scheduler:

  • known up-to-date source/unit: immediate manifest/shard reuse;
  • source edit: update only the affected compiler index unit and enrichment
    shard;
  • public/module change: prepare/reindex the build-system-reported dependent
    closure;
  • build settings/package/triple change: select a different universe;
  • delete/rename: remove obsolete unit/source shards explicitly; and
  • cancel/crash/unit-set movement: retain the prior graph.

Avoid a full filesystem pollForUnitChangesAndWait on every refresh; use it only
where the owning manager cannot name the changed unit set.
Cold overhead is compared with native SourceKit-LSP background indexing or the
same Swift build. Warm targets follow #63.

Implementation map

  1. Add #63's shard/coverage protocol.
  2. Build a toolchain-pinned Swift probe that proves explicit unit selection,
    roles, relations, locals and stale-unit rejection.
  3. Implement the standalone sidecar as the schema oracle.
  4. Add the SourceKit-LSP hook/custom request and compare exact output with the
    oracle.
  5. Register the preferred provider only on a matching toolchain/handshake;
    otherwise decline.
  6. Add SwiftPM and multi-target/configuration lifecycle fixtures before real
    smoke/benchmark publication.

Acceptance

  • Every graph generation names an explicit unit set; stale units in the
    surrounding store cannot leak in.
  • Exact fixtures cover modules, extensions, protocols/conformance,
    overrides, virtual calls, constructors, properties/accessors,
    read/write roles, generics, async, macros, conditional compilation,
    locals and tests.
  • USR identity and multi-triple separation are proven.
  • One per-source enrichment pass supplies spans/signatures/access/attributes;
    no per-symbol SourceKit fan-out occurs.
  • All 15 fact families have explicit coverage/unresolved rows.
  • No-op, edit, API/module, create/delete/rename, package/build-setting/
    triple/toolchain change, error, cancel, crash and retry are atomic.
  • Cold time is compared with native background indexing/build; no-op/edit
    phases are measured separately.
  • macOS and Linux toolchain packaging is proven; unsupported platforms
    decline explicitly.
  • SourceKit-LSP/static remain truthful fallbacks.
  • Focused tests, Swift experiment, pnpm build, pnpm test, and
    pnpm coverage pass.

Primary references

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with #63's shard/coverage protocol, then read the SourceKit-LSP SemanticIndexManager and the IndexStoreDB explicit-output-unit mode described in the issue. Build the toolchain-pinned Swift probe first, followed by focused fixtures for stale-unit rejection and fact coverage; done requires the listed lifecycle tests, exact output comparison, and passing pnpm build, test, and coverage.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift, typescript
Domain
compilers, devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.