fix(pascal): attribute a free routine's calls to it, not the file (#795)
A Pascal/Delphi procedure or function defined ONLY in the implementation section (no interface declaration, not a class method) had no node of its own, so extractPascalDefProc's caller lookup fell through to the nodeStack top — the file node. Every call in such a routine's body was lumped under the unit: callers returned the file, and impact couldn't attribute the call to the routine. (Methods were fine — they get a node from their class declaration.) Fix: when extractPascalDefProc finds no existing node for a FREE routine (a name with no `.`), create a function node for it and attribute the body's calls to it. Interface-declared free routines already have a node (found via the methodIndex), so there's no duplicate; methods keep their existing class-declaration node. PascalCoin A/B: +511 / -145 — the +511 are calls now correctly attributed to their actual routine (`allocate_new_datablock -> TDisposables::GetMem`), replacing -145 file-level aggregates; +248 new function nodes for the implementation-only routines. New synthetic test asserts a free routine's call attributes to it alongside a method caller. EXTRACTION_VERSION 17->18. Full suite green. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
5342f7a93e
commit
dac00e7d44
@@ -21,4 +21,4 @@
|
||||
* turns the re-index hint into noise — keep it honest (see CLAUDE.md, "Honesty
|
||||
* in the product is load-bearing").
|
||||
*/
|
||||
export const EXTRACTION_VERSION = 17;
|
||||
export const EXTRACTION_VERSION = 18;
|
||||
|
||||
@@ -4281,10 +4281,30 @@ export class TreeSitterExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
const parentId =
|
||||
let parentId =
|
||||
this.methodIndex.get(fullNameKey) ||
|
||||
this.methodIndex.get(shortNameKey) ||
|
||||
this.nodeStack[this.nodeStack.length - 1];
|
||||
this.methodIndex.get(shortNameKey);
|
||||
|
||||
// No existing node? This is an implementation-only **free** procedure/function
|
||||
// (`procedure Helper; begin … end;` with no interface declaration and not a
|
||||
// class method). Create a function node so its body's calls attribute to it,
|
||||
// not to the enclosing file/module. A method (`TClass.Method`, a dotted name)
|
||||
// always has a node from its class declaration, so this only fires for free
|
||||
// routines — and the methodIndex lookup above already covers interface-declared
|
||||
// free routines, so there's no duplicate.
|
||||
if (!parentId && !fullName.includes('.')) {
|
||||
const fnNode = this.createNode('function', fullName, declProc, {
|
||||
signature: this.extractor?.getSignature?.(declProc, this.source),
|
||||
visibility: this.extractor?.getVisibility?.(declProc),
|
||||
});
|
||||
if (fnNode) {
|
||||
parentId = fnNode.id;
|
||||
this.methodIndex.set(fullNameKey, fnNode.id);
|
||||
if (!this.methodIndex.has(shortNameKey)) this.methodIndex.set(shortNameKey, fnNode.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!parentId) parentId = this.nodeStack[this.nodeStack.length - 1];
|
||||
if (!parentId) return;
|
||||
|
||||
// Visit the block for calls
|
||||
|
||||
Reference in New Issue
Block a user