Skip to content

[Bulk index][Dart] Export analyzer AnalysisSession snapshots atomically #84

Description

@samchon

Outcome

Add one versioned custom request inside the resident Dart Analysis Server that
walks its existing AnalysisDriver/AnalysisSession state and streams
whole-generation or changed-library shards. Use a public package:analyzer
sidecar only as the prototype/batch fallback. Remove all declaration-by-
declaration reference queries from the final path.

Fact-checked timing baseline

PR #147 measured dart-http with a 1,800-second guard:

  • the strict cell first attempted scip-dart, later entered generic LSP work,
    and was terminated while textDocument/references was active;
  • the strict-off cell was terminated in the same generic phase.

The publication proves that neither end-to-end cell finished within 30 minutes.
It does not isolate scip-dart's duration and does not report eventual
completion.

The separate five-minute diagnosis disabled strict providers. Analysis Server
initialization took 0.030 s; all 324 document-symbol calls completed in 0.485 s
total; 1,204 reference calls started, 1,188 completed and 16 remained in flight.
Completed calls accumulated 533.410 s of server time, with one taking 249.253 s.
This proves generic fan-out is pathological, not that analysis itself requires
30 minutes.

Current master can defend no edge families from scip-dart under the common
grounding rules.

Why the analyzer already has the needed truth

AnalysisSession is a consistent view of analyzer results. Its APIs fail with
InconsistentAnalysisException when a result may conflict with an earlier
result in the same session. Resolved units/libraries contain typed AST,
elements, calls, types, diagnostics and source ranges.

AnalysisContext already applies file changes and creates a new current
session. The Analysis Server owns multiple contexts, package configuration,
analysis options, experiments, overlays, scheduler and byte/result caches.

A public AnalysisContextCollection sidecar can prove the traversal, but its
public constructor does not expose every server configuration/cache control.
Depending on package:analyzer/src would pin unstable internals and duplicate
the server's analysis. The fastest final route is a custom Analysis Server
request executed where those internals already live.

Analyzer plugin APIs are not a substitute: they focus on diagnostics/fixes/
assists and do not provide an arbitrary whole-workspace semantic export with
the server's generation transaction.

Decision: pinned Analysis Server request

Add samchon/graphSnapshot to a pinned Dart SDK/Analysis Server fork or upstream
extension:

  1. capture the server's context roots, overlays and configuration generation;
  2. for each context, capture its current AnalysisSession;
  3. enumerate analyzed project libraries/files once;
  4. resolve/walk each library/unit once and emit changed library/source shards;
  5. preserve parts/augmentations/generated origins;
  6. compute pre/post source/config/package hashes across contexts; and
  7. commit only when every session stayed internally consistent and the
    cross-context fence still matches.

One session protects reads inside a context; the pre/post manifest fence is
still required across several contexts.

The request streams #63's protocol and supports cancellation. A compatibility
handshake reports SDK/analyzer/exporter commit/schema. Unknown internals decline
to the public sidecar/scip/LSP fallback.

Fact extraction

Resolved AST and element model can prove:

  • libraries, fragments, parts/augmentations, classes/mixins/enums/extensions/
    extension types, functions, methods, constructors, fields/properties,
    parameters, locals and type aliases;
  • imports/exports, prefixes, deferred imports and show/hide combinators;
  • resolved method/function invocations and constructor creation;
  • reads/writes and type references;
  • direct superclass, interfaces, mixins and overrides;
  • metadata annotations with resolved element/constant value;
  • references and diagnostics; and
  • Flutter renders and package:test/testWidgets facts only through named
    framework enrichers.

Dart methods are virtual by default. The statically resolved declaration is a
call edge, not necessarily runtime implementation. final, base, sealed
and library-closed analysis can sometimes prove a closed target/candidate set.
Emit exact dispatches only when one runtime target is proven; otherwise store
candidates/unresolved.

Dynamic invocation, noSuchMethod, mirrors, FFI/native boundaries, generated
code not loaded in the context and conditional imports outside the selected
configuration remain explicit coverage gaps.

Identity

Do not persist Element.id; it is process-local. ElementLocation is no
longer the public stable route after Element2.

Use:

library URI + fragment/semantic owner chain + lookupName + declaration kind + structural signature where needed.

Rules:

  • collapse substituted views through the base/original element;
  • parts and augmentations share the semantic element but retain all fragments/
    declaration spans;
  • library-private names are namespaced by library URI;
  • accessors/operators use canonical lookup names;
  • locals include source/owner lexical structure;
  • synthetic elements retain origin; and
  • unnamed extensions require a content/structure-derived stable key, not a raw
    offset or an ordinal that changes after unrelated insertions. If that cannot
    be proven, report identity-unstable.

Dart has no overloads, but unnamed extensions, augmentations and generated
fragments are mandatory identity fixtures.

Universe and incremental behavior

The universe includes Dart SDK/analyzer/exporter commit, package config and
lock, workspace/context roots, analysis options/includes, experiments, language
versions, declared variables, platform/conditional imports, generated sources
and overlays.

  • no-op: Analysis Server returns prior manifest without re-walking libraries;
  • edit: AnalysisDriver invalidates affected libraries; export only their
    shards;
  • public API/package/options/experiment change: export the analyzer's dependent
    closure or new context universe;
  • create/delete/rename: explicit shard changes;
  • inconsistent session, analysis error, cancel or server crash: no mixed
    commit.

Cold overhead is compared with the same Analysis Server workspace analysis.
Target no-op p95 below 250 ms and body edit below 2 s on the pinned corpus.
Do not query LSP references per declaration.

Implementation map

  1. Add [Bulk index] Replace symbol-by-symbol LSP scans with compiler-owned snapshots #63's shard/coverage contract.
  2. Implement a public package:analyzer batch prototype to freeze exact graph
    semantics and identities.
  3. Move the same traversal into a pinned Analysis Server request and compare
    byte-equivalent normalized output.
  4. Add the resident provider ahead of scip-dart only after multi-context and
    overlay fencing passes.
  5. Retain the public sidecar, scip-dart and generic/static paths as explicit
    fallbacks.
  6. Add phase-separated dart-http cold/no-op/edit measurement.

Acceptance

  • Exact fixtures cover packages/workspaces, parts, augmentations, unnamed/
    named extensions, extension types, mixins, sealed/final/base hierarchies,
    generics, async, constructors, accesses, annotations, conditional imports,
    code generation, Flutter and tests.
  • One request walks each analyzed unit/library once; no per-symbol LSP
    references occur.
  • Per-context AnalysisSession consistency and cross-context manifest
    fencing are both proven.
  • Persistent identities never use process-local Element.id or raw offset
    alone.
  • All 15 fact families have explicit coverage/unresolved rows.
  • No-op, body/API edit, create/delete/rename, package/options/experiment/
    SDK/context change, diagnostic, inconsistency, cancel, crash and retry are
    atomic.
  • Cold time is compared with native Analysis Server analysis; no-op/edit
    phases are measured separately.
  • Linux/macOS/Windows SDK selection and exact handshake are proven.
  • Public analyzer/scip-dart/generic/static remain truthful fallbacks.
  • Focused tests, Dart experiment, pnpm build, pnpm test, and
    pnpm coverage pass.

Primary references

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions