mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-14 05:19:23 +08:00
Found by the README-wide sweep: halo's most-depended-on symbols were an `EmailVerificationService.verify` (1,038 — Mockito's `verify(mock)`) and a builder's `eq` (845 — ArgumentMatchers `eq`); retrofit's a test helper's `assertThat` (1,357 — Truth); mall's a DTO's `hashCode` (Object's). A bare Java call (`verify(x)`, `helper()`, `this.x()`, `super.x()`) now has only method candidates declared on a class around it, on one of that class's supertypes (read transitively from the declarations' `extends` / `implements` — the resolved edges don't exist yet on the first pass), or imported statically (`import static a.B.m;` / `a.B.*`). Memoized per type and per file. A/B vs main (edge diffs, every change classified): halo −2,103/+145, retrofit −1,380/+18, commons-lang −202/+87, jsoup −92/+45, mall −76, gson −7/+4. Gains are the right target where one exists: halo's `and` / `equal` / `isNull` through `import static …Queries.*`, jsoup's `attr(…)` through `LeafNode`, commons-lang's `addExact` on its own class instead of a nested MathBridge, retrofit's `getRawType` through `CallAdapter.Factory`. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
/**
|
|
* A bare Java call reaches a method of a class around it, a supertype of that
|
|
* class, or a static import — not another class's method that shares the name.
|
|
* halo's Mockito `verify(…)` bound 1,038 calls to `EmailVerificationService.verify`.
|
|
*/
|
|
import { describe, it, expect, afterAll } from 'vitest';
|
|
import * as fs from 'fs';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
import { CodeGraph } from '../src';
|
|
|
|
const roots: string[] = [];
|
|
afterAll(() => {
|
|
for (const r of roots.splice(0)) fs.rmSync(r, { recursive: true, force: true });
|
|
});
|
|
|
|
const FILES: Record<string, string> = {
|
|
'src/main/java/app/EmailVerificationService.java': `package app;
|
|
public class EmailVerificationService {
|
|
public boolean verify(String token) { return true; }
|
|
}
|
|
`,
|
|
'src/main/java/app/Util.java': `package app;
|
|
public class Util {
|
|
public static String format(String s) { return s; }
|
|
}
|
|
`,
|
|
'src/main/java/app/Base.java': `package app;
|
|
public class Base {
|
|
protected void helper() {}
|
|
}
|
|
`,
|
|
'src/main/java/app/Child.java': `package app;
|
|
import static app.Util.format;
|
|
public class Child extends Base {
|
|
public void run() {
|
|
helper();
|
|
format("x");
|
|
own();
|
|
}
|
|
private void own() {}
|
|
}
|
|
`,
|
|
'src/test/java/app/ChildTest.java': `package app;
|
|
import static org.mockito.Mockito.verify;
|
|
public class ChildTest {
|
|
public void sends(Object mock) {
|
|
verify(mock);
|
|
}
|
|
}
|
|
`,
|
|
};
|
|
|
|
describe('Java: a bare call reaches what is in scope', () => {
|
|
it('own class, a supertype, a static import — not a same-named method elsewhere', async () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-java-bare-'));
|
|
roots.push(root);
|
|
for (const [rel, content] of Object.entries(FILES)) {
|
|
fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true });
|
|
fs.writeFileSync(path.join(root, rel), content);
|
|
}
|
|
const cg = await CodeGraph.init(root, { index: true });
|
|
try {
|
|
const callsFrom = (name: string): string[] => {
|
|
const from = cg.getNodesByName(name).find((n) => n.kind === 'method')!;
|
|
return cg.getOutgoingEdgesFrom([from.id], ['calls']).map((e) => cg.getNode(e.target)!.name).sort();
|
|
};
|
|
expect(callsFrom('sends')).not.toContain('verify');
|
|
expect(callsFrom('run')).toEqual(['format', 'helper', 'own']);
|
|
} finally {
|
|
cg.close();
|
|
}
|
|
});
|
|
});
|