diff --git a/gitnexus/src/core/ingestion/languages/java/arity-metadata.ts b/gitnexus/src/core/ingestion/languages/java/arity-metadata.ts index 38d4f6c80..47cccbff9 100644 --- a/gitnexus/src/core/ingestion/languages/java/arity-metadata.ts +++ b/gitnexus/src/core/ingestion/languages/java/arity-metadata.ts @@ -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, diff --git a/gitnexus/src/core/ingestion/languages/java/interpret.ts b/gitnexus/src/core/ingestion/languages/java/interpret.ts index 9f45f3b4c..107b879cd 100644 --- a/gitnexus/src/core/ingestion/languages/java/interpret.ts +++ b/gitnexus/src/core/ingestion/languages/java/interpret.ts @@ -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`, `Optional` — 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; } diff --git a/gitnexus/src/core/ingestion/languages/java/simple-hooks.ts b/gitnexus/src/core/ingestion/languages/java/simple-hooks.ts index 25da32369..e69f768a6 100644 --- a/gitnexus/src/core/ingestion/languages/java/simple-hooks.ts +++ b/gitnexus/src/core/ingestion/languages/java/simple-hooks.ts @@ -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; }