Skip to content

Commit 7c550fa

Browse files
bundle: a relation that names a field makes that field listed (#890)
`fields` holds every client field, but a LIBRARY field only when something references it, and the only thing that counted was a field_access row. config_binding names the field a configuration key binds to, which is a statement that the field matters, and it did not count, so its rows pointed at ids the table does not hold. Rather than teach the language-neutral bundler about a Java relation, the adapter now declares which of its relations name a field and in which column, and build.ts folds those ids into the same wanted set field_access already fills. Java declares config-binding.csv column 3. Measured on 8 Spring Boot services solved with one starter as --library: config_binding field ids 154 dangling before 112 dangling after 8 fields table 1427 -> 1531 (+104) call_edges 8315 -> 8315 The residual 8 are a different fault and deliberately not addressed here: those ids appear in no all-fields.csv on either side, so no amount of listing reaches them. They are worth their own issue once someone works out which rule mints them. Suite 56 passed, 0 failed, no golden changes.
1 parent 8357ef5 commit 7c550fa

2 files changed

Lines changed: 24 additions & 0 deletions

File tree

‎graph/bundle/build.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ export async function buildCore(inp: BuildInputs): Promise<CoreTables> {
199199
wantMethods.add(r[1] as string);
200200
if (r[2] !== null) wantFields.add(r[2] as string);
201201
}
202+
// A relation may NAME a field without being a field access, and such a row is exactly a
203+
// statement that the field matters. Counting only field_access left those ids resolving
204+
// to nothing in `fields` (#890). Which relations do this is declared by the adapter.
205+
for (const fr of inp.adapter.raw.fieldRefs ?? []) {
206+
for await (const r of readRaw(path.join(inp.rawDir, fr.file))) {
207+
const id = r[fr.column];
208+
if (id && id !== NONE) wantFields.add(id);
209+
}
210+
}
202211

203212
// ── 3. client entities (all of them — the client is the subject) ──────────
204213
const methods = new Map<string, Row>();

‎graph/bundle/languages.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ export interface LanguageAdapter {
9595
fieldAccess?: RawSource;
9696
/** (ref, owner, ownerKind, enclType, enclMethod, type, prov, context, depth, tier) — #663 */
9797
typeUse?: RawSource;
98+
/**
99+
* Relations that NAME a field without being a field access. `fields` lists every client
100+
* field, but a LIBRARY field only when something references it, and that something was
101+
* `fieldAccess` alone. A relation like a config binding says the field matters and then
102+
* could not resolve it, so its rows pointed at ids the table does not hold (#890).
103+
*
104+
* Each entry is a raw relation plus the column holding the field id. Declared per
105+
* language because which relations name a field is a language's own business, and
106+
* build.ts stays neutral.
107+
*/
108+
fieldRefs?: { file: string; column: number }[];
98109
};
99110
ir: {
100111
methods: MethodsIR;
@@ -126,6 +137,10 @@ const JAVA: LanguageAdapter = {
126137
fieldAccess: { file: 'field-access.csv', columns: [0, 1, 2, 3, 4, 5] },
127138
// ref, type, context, depth, ownerKind, owner, enclMethod, enclType, typeProv, tier
128139
typeUse: { file: 'type-use.csv', columns: [0, 5, 7, 8, 2, 1, 4, 3, 6, 9] },
140+
// config_binding(Key, Mechanism, TargetKind, Target, Owner): column 3 is the bound
141+
// field when TargetKind is "field". A row naming a library field is why that field
142+
// has to be listed at all.
143+
fieldRefs: [{ file: 'config-binding.csv', column: 3 }],
129144
},
130145
ir: {
131146
methods: {

0 commit comments

Comments
 (0)