fix(union): complete downstream container handling
This commit is contained in:
@@ -86,6 +86,45 @@ int dispatch(struct ops o) { return o.handler(); }
|
||||
expect(edges.every((e) => e.via === 'ops.handler')).toBe(true);
|
||||
});
|
||||
|
||||
it('bridges function-pointer fields declared in a union', async () => {
|
||||
write('union-ops.c', `
|
||||
union ops { int (*handler)(void); };
|
||||
static int on_open(void) { return 1; }
|
||||
static union ops the_ops = { .handler = on_open };
|
||||
|
||||
int dispatch(union ops o) { return o.handler(); }
|
||||
`);
|
||||
const edges = await load();
|
||||
expect(has(edges, 'dispatch', 'on_open')).toBe(true);
|
||||
expect(edges.every((e) => e.via === 'ops.handler')).toBe(true);
|
||||
});
|
||||
|
||||
it('bridges an inline union table whose entries are macro-built', async () => {
|
||||
write('inline-union.c', `
|
||||
#define SLOT(fn) { fn }
|
||||
static int on_open(void) { return 1; }
|
||||
static union inline_ops { int (*handler)(void); } ops[] = { SLOT(on_open) };
|
||||
|
||||
int dispatch(union inline_ops o) { return o.handler(); }
|
||||
`);
|
||||
const edges = await load();
|
||||
expect(has(edges, 'dispatch', 'on_open')).toBe(true);
|
||||
});
|
||||
|
||||
it('bridges a union table declared through an object-macro type alias', async () => {
|
||||
write('alias-union.c', `
|
||||
#define OPS_TYPE union ops
|
||||
#define SLOT(fn) { fn }
|
||||
union ops { int (*handler)(void); };
|
||||
static int on_open(void) { return 1; }
|
||||
static OPS_TYPE ops[] = { SLOT(on_open) };
|
||||
|
||||
int dispatch(union ops o) { return o.handler(); }
|
||||
`);
|
||||
const edges = await load();
|
||||
expect(has(edges, 'dispatch', 'on_open')).toBe(true);
|
||||
});
|
||||
|
||||
it('bridges the typedef-field + field←field double-hop (the hook_demo.c shape)', async () => {
|
||||
write('hook.c', `
|
||||
typedef void (*hook_func)(void);
|
||||
|
||||
@@ -135,10 +135,16 @@ export function validateEmail(email: string): boolean {
|
||||
`
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(srcDir, 'callback_ops.c'),
|
||||
`union CallbackOps { int (*run)(int); };
|
||||
`
|
||||
);
|
||||
|
||||
// Initialize CodeGraph
|
||||
cg = CodeGraph.initSync(testDir, {
|
||||
config: {
|
||||
include: ['**/*.ts'],
|
||||
include: ['**/*.ts', '**/*.c'],
|
||||
exclude: [],
|
||||
},
|
||||
});
|
||||
@@ -194,6 +200,15 @@ export function validateEmail(email: string): boolean {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('includes union definitions in the default context search', async () => {
|
||||
const result = await cg.findRelevantContext('CallbackOps');
|
||||
const union = [...result.nodes.values()].find(
|
||||
(node) => node.kind === 'union' && node.name === 'CallbackOps'
|
||||
);
|
||||
|
||||
expect(union).toBeDefined();
|
||||
});
|
||||
|
||||
it('should include edges in the result', async () => {
|
||||
const result = await cg.findRelevantContext('checkout', {
|
||||
traversalDepth: 2,
|
||||
|
||||
@@ -1045,6 +1045,34 @@ void initialize() { Packet(); }
|
||||
expect(outgoing.some((e) => e.kind === 'calls' && e.target === packet!.id)).toBe(false);
|
||||
});
|
||||
|
||||
it('resolves a static call through an imported C++ union to its member', async () => {
|
||||
fs.writeFileSync(
|
||||
path.join(tempDir, 'ops.hpp'),
|
||||
`union Ops {
|
||||
static int run() { return 1; }
|
||||
};
|
||||
`
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(tempDir, 'main.cpp'),
|
||||
`#include "ops.hpp"
|
||||
|
||||
int invoke() { return Ops::run(); }
|
||||
`
|
||||
);
|
||||
|
||||
cg = await CodeGraph.init(tempDir, { index: true });
|
||||
cg.resolveReferences();
|
||||
|
||||
const invoke = cg.getNodesByKind('function').find((n) => n.name === 'invoke');
|
||||
const run = cg.getNodesByKind('method').find((n) => n.name === 'run');
|
||||
expect(invoke).toBeDefined();
|
||||
expect(run).toBeDefined();
|
||||
|
||||
const outgoing = cg.getOutgoingEdges(invoke!.id);
|
||||
expect(outgoing.some((e) => e.kind === 'calls' && e.target === run!.id)).toBe(true);
|
||||
});
|
||||
|
||||
it('records instantiates for C++ stack/brace construction, targeting the class (#1035)', async () => {
|
||||
// `Calculator calc(0)` (direct-init) and `Widget w{1, 2}` (brace-init)
|
||||
// carry the constructor args directly on the declarator — there's no
|
||||
|
||||
Reference in New Issue
Block a user