Edges
The single relationship concept. Every edge, regardless of kind, carries:
| Attribute | Type | Required | Meaning |
|---|---|---|---|
edge | EdgeKind | yes | discriminant, see below |
from | EntityId | yes | source |
to | EntityId | yes | primary target (best candidate if uncertain) |
provenance | Provenance | yes | how we know |
anchor | SourceAnchor | yes | where observed |
candidates | EntityId[] | no | possible targets when dispatch is uncertain; non-empty iff resolution was ambiguous |
sourceFile | string | no | disambiguates which declaration site produced the edge (C# partial classes, TS declaration merging) |
Rules
- Outgoing only, stored once. All inverse views — callers of X, subtypes of Y, importers of M, and
children(the inverse ofparent) — are derived in memory, never serialized. Onlyparentis a stored fact. - Closure:
fromandtomust resolve to a known entity or a stub — a tested property of every model. - No self-reference:
from ≠ to.
Edge kinds
| Kind | From → To | Extra attributes | Notes |
|---|---|---|---|
import | Module → Module | First-class layer: the only relation reliable ≈100% across all languages, hence the granularity for cross-language comparison. Rust has two levels (mod, crate) | |
inheritance | Type → Type | N edges for multiple inheritance (Python); optional MRO order left to profile notes | |
interfaceImplementation | Type → Type (interface/trait/protocol) | declared (Java implements) or derived (Go, TS structural) depending on language. For Rust/Clojure the anchor is the reified impl block | |
invocation | Invocable → Invocable | candidates | uncertain dispatch → provenance: dynamic-candidate + candidates list |
access | Invocable → Structural | isRead: bool, isWrite: bool | field/variable reads and writes; a compound assignment sets both |
reference | Entity → Type | type usage that is none of the above (declarations, generics, casts) | |
annotationUse | Entity → Type (annotation) | arguments: NamedArgument[] | a written annotation on any entity, with its arguments. The dedicated kind carries the values and lets a consumer select annotation usages without guessing from the target’s kind — which a stub target cannot answer |
throws | Invocable → Type (exception) | a written throw statement whose static exception type resolved; the anchor is the throw SITE. A declared propagation clause (Java throws E) is a plain reference, not this | |
embedding | Type → Type | Go struct { Base } — neither inheritance nor attribute (method promotion); dedicated relation | |
traitUsage | Type → Trait (PHP) | PHP use TraitX; — kept as a usage edge, never flattened into the class | |
fileInclude | CodeFile → CodeFile | PHP include/require — the only file-to-file dependency in the metamodel |
The order above is the order the header dictionary’s enum declares.
Relations: edges connect entities; are licensed per language profile (a profile lists which edge kinds its extractor can emit); carry a SourceAnchor and a Provenance.
Folded edges
Analyses do not read base edges directly: the analyzer folds them to --level module or --level type first, aggregating every base edge between two folded nodes into one arrow that carries the count, the set of base kinds and the set of provenances. A folded arrow is an inference about a group, not a written fact; what it aggregates is stated in every rendering.
Last updated on