mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-21 00:21:30 +00:00
fix: address 4 findings — K&R arity, function-pointer docs, prototype docs, _filePath rename
Finding 1: K&R empty parameter list `int foo()` now returns unknown arity `{}`
instead of `{parameterCount:0}`. Distinguishes from explicit `int foo(void)`.
3 unit tests cover K&R definition, prototype, and void comparison.
Finding 2: Added code comment documenting function-pointer-variable call
capture as known architectural trade-off (same as Go resolver).
Finding 3: Added code comment documenting prototype/definition duplication
as graph-quality concern (no false CALLS edges).
Finding 4: Renamed `_filePath` → `filePath` in captures.ts since it is
actively used in markStaticName().
Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/ab2164f7-972f-4ea8-81fa-a14ce20d7cce
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
This commit is contained in:
parent
dcc764a2a4
commit
48924fcfa8
4 changed files with 54 additions and 2 deletions
|
|
@ -26,6 +26,13 @@ export function computeCDeclarationArity(node: SyntaxNode): CArityInfo {
|
|||
}
|
||||
}
|
||||
|
||||
// K&R old-style declaration: `int foo()` has an empty parameter_list with
|
||||
// no parameter_declaration or variadic_parameter children. Per C89/C99,
|
||||
// this means the function accepts an unspecified number/types of arguments —
|
||||
// NOT zero arguments. Return unknown arity to avoid false 'incompatible'.
|
||||
// `int foo(void)` is the explicit zero-parameter form and is handled below.
|
||||
if (params.length === 0) return {};
|
||||
|
||||
// (void) means zero parameters
|
||||
if (params.length === 1 && params[0].type === 'parameter_declaration') {
|
||||
const typeNode = params[0].childForFieldName('type');
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { markStaticName } from './static-linkage.js';
|
|||
|
||||
export function emitCScopeCaptures(
|
||||
sourceText: string,
|
||||
_filePath: string,
|
||||
filePath: string,
|
||||
cachedTree?: unknown,
|
||||
): readonly CaptureMatch[] {
|
||||
let tree = cachedTree as ReturnType<ReturnType<typeof getCParser>['parse']> | undefined;
|
||||
|
|
@ -102,7 +102,7 @@ export function emitCScopeCaptures(
|
|||
if (hasStaticStorageClass(fnNode)) {
|
||||
const nameText = grouped['@declaration.name']?.text;
|
||||
if (nameText !== undefined) {
|
||||
markStaticName(_filePath, nameText);
|
||||
markStaticName(filePath, nameText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@ const C_SCOPE_QUERY = `
|
|||
declarator: (identifier) @declaration.name))) @declaration.function
|
||||
|
||||
;; Declarations — function declaration (prototype)
|
||||
;; Note: Both prototypes and definitions are captured as @declaration.function.
|
||||
;; This may produce duplicate Function nodes in the knowledge graph when a
|
||||
;; function is declared in a header and defined in a .c file. CALLS edges
|
||||
;; resolve correctly through scope-based wildcard import chains; the
|
||||
;; duplication is a graph-quality concern only (no false edges).
|
||||
(declaration
|
||||
declarator: (function_declarator
|
||||
declarator: (identifier) @declaration.name)) @declaration.function
|
||||
|
|
@ -114,6 +119,12 @@ const C_SCOPE_QUERY = `
|
|||
declarator: (identifier) @type-binding.name)) @type-binding.assignment
|
||||
|
||||
;; References — free calls
|
||||
;; Note: This also captures calls through function pointer variables (e.g. fp(x))
|
||||
;; since tree-sitter-c produces structurally identical AST nodes for both direct
|
||||
;; function calls and function-pointer-variable calls. A type-based guard to
|
||||
;; distinguish variable-calls from function-calls is not implemented — this is a
|
||||
;; known architectural trade-off shared with the Go resolver. The uniqueness
|
||||
;; constraint in pickUniqueGlobalCallable limits false edge exposure.
|
||||
(call_expression
|
||||
function: (identifier) @reference.name) @reference.call.free
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,40 @@ describe('computeCDeclarationArity', () => {
|
|||
expect(arity.parameterCount).toBe(1);
|
||||
expect(arity.requiredParameterCount).toBe(1);
|
||||
});
|
||||
|
||||
it('returns unknown arity for K&R empty parameter list int foo()', () => {
|
||||
const node = parseFunctionNode('int foo() { return 0; }');
|
||||
expect(node).not.toBeNull();
|
||||
const arity = computeCDeclarationArity(node!);
|
||||
// K&R old-style: unspecified parameters, NOT zero parameters
|
||||
expect(arity.parameterCount).toBeUndefined();
|
||||
expect(arity.requiredParameterCount).toBeUndefined();
|
||||
expect(arity.parameterTypes).toBeUndefined();
|
||||
});
|
||||
|
||||
it('distinguishes K&R int foo() from explicit int foo(void)', () => {
|
||||
const knrNode = parseFunctionNode('int foo() { return 0; }');
|
||||
const voidNode = parseFunctionNode('int foo(void) { return 0; }');
|
||||
expect(knrNode).not.toBeNull();
|
||||
expect(voidNode).not.toBeNull();
|
||||
|
||||
const knrArity = computeCDeclarationArity(knrNode!);
|
||||
const voidArity = computeCDeclarationArity(voidNode!);
|
||||
|
||||
// K&R: unknown arity
|
||||
expect(knrArity.parameterCount).toBeUndefined();
|
||||
// Explicit void: zero params
|
||||
expect(voidArity.parameterCount).toBe(0);
|
||||
expect(voidArity.requiredParameterCount).toBe(0);
|
||||
});
|
||||
|
||||
it('returns unknown arity for K&R prototype int foo();', () => {
|
||||
const node = parseFunctionNode('int foo();');
|
||||
expect(node).not.toBeNull();
|
||||
const arity = computeCDeclarationArity(node!);
|
||||
expect(arity.parameterCount).toBeUndefined();
|
||||
expect(arity.requiredParameterCount).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('computeCCallArity', () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue