test(cpp): cover non-type template args and std ADL ambiguity boundary

Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/d8701678-a06a-477a-9c6d-312fd4c54f17

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-05-14 18:44:30 +00:00 • committed by GitHub
parent 60c5bc7a31
commit 0f9be71905
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 40 additions and 2 deletions

View file

@ -188,6 +188,9 @@ export function pickCppAdlCandidates(
if (arg.isReference) continue;
if (arg.simpleClassName !== '') {
// For template args this may be the template name itself (e.g.
// `vector`); simple-name lookup can match project classes with the
// same name (known V1/V2 simplification).
const classDef = findCppClassDefBySimpleName(arg.simpleClassName, scopes);
if (classDef !== undefined) {
const nsQName = classToNamespaceQualifiedName.get(classDef.nodeId);
@ -195,6 +198,9 @@ export function pickCppAdlCandidates(
}
}
// Includes template-owner namespaces (e.g. `std` in std::vector<T>).
// If that surfaces extra candidates, ADL_AMBIGUOUS suppression below
// prevents arbitrary edge emission.
if (arg.templateNamespace.length > 0) associatedNamespaces.add(arg.templateNamespace);
for (const ns of arg.templateArgNamespaces) {

View file

@ -222,8 +222,10 @@ export const cppScopeResolver: ScopeResolver = {
// C++ argument-dependent / Koenig lookup (U2 of plan 2026-05-13-001).
// Fires after `findCallableBindingInScope` returns undefined; surfaces
// candidates from the associated namespaces of class-typed arguments.
// V1 limitation: only direct enclosing-namespace closure for value
// class-typed args; pointer/reference/template-spec args excluded.
// Current boundary: class-typed value/pointer args and template
// specializations with explicit type arguments contribute associated
// namespaces. Reference args, function-pointer args, base-class
// associated namespaces, and full ordinary+ADL merge remain excluded.
resolveAdlCandidates: (site, callerParsed, scopes, parsedFiles) => {
// `using ns::name;` introduces `name` into ordinary unqualified lookup.
// For template-class method bodies, lexical scope walks can miss this

View file

@ -10,4 +10,14 @@ namespace app {
std::map<std::string, std::vector<N::T>> m;
applyNested(m);
}
void runArray() {
std::array<N::T, 4> a;
applyArray(a);
}
void runStdConflict() {
std::vector<N::T> v;
applyStdConflict(v);
}
}

View file

@ -1,5 +1,6 @@
#pragma once
#include <array>
#include <map>
#include <string>
#include <vector>
@ -9,4 +10,10 @@ namespace N {
void apply(std::vector<T> v);
void applyNested(std::map<std::string, std::vector<T>> m);
void applyArray(std::array<T, 4> a);
void applyStdConflict(std::vector<T> v);
}
namespace std {
void applyStdConflict(vector<N::T> v);
}

View file

@ -2248,6 +2248,19 @@ describe('C++ ADL — template specialization args contribute associated namespa
expect(applyCalls.length).toBe(1);
expect(applyCalls[0].targetFilePath).toContain('audit.h');
});
it('applyArray(a) where a is std::array<N::T, 4> resolves to N::applyArray (non-type arg ignored)', () => {
const calls = getRelationships(result, 'CALLS');
const applyCalls = calls.filter((c) => c.source === 'runArray' && c.target === 'applyArray');
expect(applyCalls.length).toBe(1);
expect(applyCalls[0].targetFilePath).toContain('audit.h');
});
it('applyStdConflict(v) is suppressed when ADL surfaces both N and std candidates', () => {
const calls = getRelationships(result, 'CALLS');
const applyCalls = calls.filter((c) => c.source === 'runStdConflict' && c.target === 'applyStdConflict');
expect(applyCalls.length).toBe(0);
});
});
describe('C++ ADL — int/long-collision overloads suppress via OVERLOAD_AMBIGUOUS', () => {