Skip to content

Commit d83f1ce

Browse files
committed
fix(resolver): apply confidence filter to static receiver fallback
The direct qualified-name fallback in resolveByMethodOrGlobal was the only resolution path that did not apply computeConfidence >= 0.5, risking false edges from distant files in polyglot projects with name collisions. Closes #1398
1 parent 4e8134a commit d83f1ce

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

src/domain/graph/builder/call-resolver.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,11 @@ export function resolveByMethodOrGlobal(
155155
const qualifiedName = `${effectiveReceiver}.${call.name}`;
156156
const direct = lookup
157157
.byName(qualifiedName)
158-
.filter((n) => n.kind === 'method' || n.kind === 'function');
158+
.filter(
159+
(n) =>
160+
(n.kind === 'method' || n.kind === 'function') &&
161+
computeConfidence(relPath, n.file, null) >= 0.5,
162+
);
159163
if (direct.length > 0) return direct;
160164
}
161165

tests/unit/call-resolver.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
* one dot segment (e.g. 'Namespace.ClassName.method'), the same-class dispatch
66
* must use only the segment immediately before the method name ('ClassName'),
77
* not the full qualified prefix ('Namespace.ClassName').
8+
*
9+
* Also covers the static receiver confidence filter (#1398): the direct qualified
10+
* method fallback must apply computeConfidence >= 0.5 to avoid false edges from
11+
* distant files in a polyglot project.
812
*/
913
import { describe, expect, it } from 'vitest';
1014
import type { CallNodeLookup } from '../../src/domain/graph/builder/call-resolver.js';
@@ -88,3 +92,29 @@ describe('resolveByMethodOrGlobal — same-class this-dispatch with qualified ca
8892
expect(result).toEqual([]);
8993
});
9094
});
95+
96+
describe('resolveByMethodOrGlobal — static receiver confidence filter (#1398)', () => {
97+
it('returns same-directory static target (confidence 0.7 >= 0.5)', () => {
98+
const target = { id: 1, file: 'app/Validators.cs', kind: 'method' };
99+
const lookup = makeLookup({ 'Validators.IsValidEmail': [target] });
100+
const result = resolveByMethodOrGlobal(
101+
lookup,
102+
{ name: 'IsValidEmail', receiver: 'Validators' },
103+
'app/Program.cs',
104+
new Map(),
105+
);
106+
expect(result).toEqual([target]);
107+
});
108+
109+
it('filters out distant static target (confidence 0.3 < 0.5)', () => {
110+
const target = { id: 2, file: 'lib/util/Validators.cs', kind: 'method' };
111+
const lookup = makeLookup({ 'Validators.IsValidEmail': [target] });
112+
const result = resolveByMethodOrGlobal(
113+
lookup,
114+
{ name: 'IsValidEmail', receiver: 'Validators' },
115+
'app/main/Program.cs',
116+
new Map(),
117+
);
118+
expect(result).toEqual([]);
119+
});
120+
});

0 commit comments

Comments
 (0)