fix: address review findings 1-4 — varargs arity, static import resolution, importOwningScope, stripGeneric

Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/22308da3-59c9-47e6-8e52-738305b1b80a

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-05-11 13:49:59 +00:00 • committed by GitHub
parent a197e42867
commit 40b6fa8263
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 33 additions and 10 deletions

View file

@ -31,9 +31,15 @@ export function computeJavaArityMetadata(fnNode: SyntaxNode): JavaArityMetadata
if (hasVariadic) types.push('varargs');
const total = params.length;
// For varargs methods, `parameterCount` (max) is unknown — any number of
// trailing arguments is valid. But the fixed-prefix parameters (everything
// before the variadic `...` param) are still required, so we preserve that
// count in `requiredParameterCount` so `javaArityCompatibility` can reject
// calls that undersupply the fixed prefix (e.g. `f(int x, String... args)`
// called with 0 args).
const fixedCount = params.filter((p) => !p.isVariadic).length;
const parameterCount = hasVariadic ? undefined : total;
// Java has no optional parameters (no default values), so required = total
const requiredParameterCount = hasVariadic ? undefined : total;
const requiredParameterCount = hasVariadic ? fixedCount : total;
return {
parameterCount,

View file

@ -40,15 +40,25 @@ export function interpretJavaImport(captures: CaptureMatch): ParsedImport | null
}
case 'static': {
// `import static com.example.Utils.format;`
// The source contains the full path including the member name
// (e.g. `com.example.Utils.format`). For file resolution we need
// the class path (`com.example.Utils`), so strip the final member
// segment. The local binding name is the member itself.
const fullSource = sourceCap.text;
const lastDot = fullSource.lastIndexOf('.');
const classPath = lastDot >= 0 ? fullSource.slice(0, lastDot) : fullSource;
return {
kind: 'named',
localName: nameCap?.text ?? sourceCap.text.split('.').pop() ?? sourceCap.text,
importedName: sourceCap.text,
targetRaw: sourceCap.text,
localName: nameCap?.text ?? (lastDot >= 0 ? fullSource.slice(lastDot + 1) : fullSource),
importedName: fullSource,
targetRaw: classPath,
};
}
case 'static-wildcard': {
// `import static com.example.Utils.*;`
// The source is the class path (e.g. `com.example.Utils`).
// Resolution should target the class file, not a wildcard directory
// scan — `Utils.java` is the file that contains the static members.
return {
kind: 'wildcard',
targetRaw: sourceCap.text + '.*',
@ -87,10 +97,18 @@ export function interpretJavaTypeBinding(captures: CaptureMatch): ParsedTypeBind
* `ArrayList<User>`, `Optional<User>` — to its element type.
*/
function stripGeneric(text: string): string {
// Single-type-argument containers — extract the element type.
const single = text.match(
/^(?:[A-Za-z_][A-Za-z0-9_.]*\.)?(?:List|ArrayList|LinkedList|Set|HashSet|TreeSet|Collection|Iterable|Iterator|Optional|Stream|CompletableFuture|Future|Queue|Deque|ArrayDeque|Vector|Stack)<([^,<>]+)>$/,
/^(?:[A-Za-z_][A-Za-z0-9_.]*\.)?(?:List|ArrayList|LinkedList|Set|HashSet|TreeSet|SortedSet|LinkedHashSet|Collection|Iterable|Iterator|Optional|Stream|CompletableFuture|Future|Queue|Deque|ArrayDeque|PriorityQueue|Vector|Stack|Supplier|Consumer|Predicate|Function)<([^,<>]+)>$/,
);
if (single !== null) return single[1].trim();
// Two-type-argument map/container types — extract the value type (second arg).
const twoArg = text.match(
/^(?:[A-Za-z_][A-Za-z0-9_.]*\.)?(?:Map|HashMap|TreeMap|LinkedHashMap|ConcurrentHashMap|ConcurrentMap|SortedMap|NavigableMap|Hashtable|EnumMap|WeakHashMap|IdentityHashMap|BiFunction|BiConsumer|BiPredicate|Pair|Entry)<[^,<>]+,\s*([^,<>]+)>$/,
);
if (twoArg !== null) return twoArg[1].trim();
return text;
}

View file

@ -35,14 +35,13 @@ export function javaBindingScopeFor(
// ─── importOwningScope ────────────────────────────────────────────────────
/** Java imports are always at file level. Defensively handle nested
* scopes by attaching to the innermost if it's Class or Function. */
/** Java imports are always at compilation-unit (Module) level (JLS §7.5).
* Return `null` unconditionally so the default Module scope is used. */
export function javaImportOwningScope(
_imp: ParsedImport,
innermost: Scope,
_innermost: Scope,
_tree: ScopeTree,
): ScopeId | null {
if (innermost.kind === 'Class' || innermost.kind === 'Function') return innermost.id;
return null;
}