Find header includers from the sources, not only from earlier compiles

unit_deps holds only the units some merge compiled, so a change to a header no merge touched compiled none of its includers. Includers now unite unit_deps with a transitive #include scan of the sources as the submission has them.
This commit is contained in:
ragnarok-clanker 2026-10-26 19:31:30 +01:00
commit 5f8e7493c8
4 changed files with 88 additions and 7 deletions

View file

@ -473,6 +473,18 @@ test('a header batch is verified on its own units and merged with every includer
}
});
test('header includers come from the sources too, also for units no merge has compiled', () => {
ctx.repo.commitFiles({ 'src/deep.h': 'int deep();\n', 'src/mid.h': '#include "deep.h"\n', 'src/user.cpp': '#include "mid.h"\nint u() { return deep(); }\n', 'src/other.cpp': 'int o() { return 0; }\n' }, 'include chain', 'x <x@y.invalid>');
const units = ctx.project.compile?.units;
if (units) Object.assign(units, { 'src/user.cpp': 0, 'src/other.cpp': 0 });
try {
assert.deepEqual(ctx.verifier.includersOf(['src/deep.h']).filter((u) => u.startsWith('src/user') || u.startsWith('src/other')), ['src/user.cpp'], 'a transitive includer, found though no merge recorded it');
assert.deepEqual(ctx.verifier.includersOf(['src/deep.h'], { 'src/user.cpp': 'int u() { return 0; }\n' }).filter((u) => u === 'src/user.cpp'), [], 'as the submission changes it');
} finally {
if (units) for (const u of ['src/user.cpp', 'src/other.cpp']) delete units[u];
}
});
test('agreeing peers accept a function without human review (three ahead)', async () => {
await activeUser('aaauthor');
const author = ctx.accounts.byName('aaauthor');