diff --git a/AGENTS.md b/AGENTS.md index cd70281f9..43c71b854 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ # GitNexus — Code Intelligence -This project is indexed by GitNexus as **GitNexus** (2169 symbols, 5213 relationships, 165 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. +This project is indexed by GitNexus as **GitNexus** (2174 symbols, 5218 relationships, 166 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. diff --git a/CLAUDE.md b/CLAUDE.md index cd70281f9..43c71b854 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,7 @@ # GitNexus — Code Intelligence -This project is indexed by GitNexus as **GitNexus** (2169 symbols, 5213 relationships, 165 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. +This project is indexed by GitNexus as **GitNexus** (2174 symbols, 5218 relationships, 166 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. diff --git a/gitnexus/src/core/ingestion/parsing-processor.ts b/gitnexus/src/core/ingestion/parsing-processor.ts index b116e8452..9866b5eca 100644 --- a/gitnexus/src/core/ingestion/parsing-processor.ts +++ b/gitnexus/src/core/ingestion/parsing-processor.ts @@ -84,6 +84,7 @@ const processParsingWithWorkers = async ( for (const sym of result.symbols) { symbolTable.add(sym.filePath, sym.name, sym.nodeId, sym.type, { parameterCount: sym.parameterCount, + parameterTypes: sym.parameterTypes, returnType: sym.returnType, declaredType: sym.declaredType, ownerId: sym.ownerId, @@ -303,6 +304,7 @@ const processParsingSequential = async ( symbolTable.add(file.path, nodeName, nodeId, nodeLabel, { parameterCount: methodSig?.parameterCount, + parameterTypes: methodSig?.parameterTypes, returnType: methodSig?.returnType, declaredType, ownerId: enclosingClassId ?? undefined, diff --git a/gitnexus/src/core/ingestion/symbol-table.ts b/gitnexus/src/core/ingestion/symbol-table.ts index 92d705db7..ea8d0f9b3 100644 --- a/gitnexus/src/core/ingestion/symbol-table.ts +++ b/gitnexus/src/core/ingestion/symbol-table.ts @@ -5,6 +5,9 @@ export interface SymbolDefinition { filePath: string; type: NodeLabel; parameterCount?: number; + /** Per-parameter type names for overload disambiguation (e.g. ['int', 'String']). + * Only populated for overloading languages (Java, Kotlin, C#, C++). */ + parameterTypes?: string[]; /** Raw return type text extracted from AST (e.g. 'User', 'Promise') */ returnType?: string; /** Declared type for non-callable symbols — fields/properties (e.g. 'Address', 'List') */ @@ -22,7 +25,7 @@ export interface SymbolTable { name: string, nodeId: string, type: NodeLabel, - metadata?: { parameterCount?: number; returnType?: string; declaredType?: string; ownerId?: string } + metadata?: { parameterCount?: number; parameterTypes?: string[]; returnType?: string; declaredType?: string; ownerId?: string } ) => void; /** @@ -102,13 +105,14 @@ export const createSymbolTable = (): SymbolTable => { name: string, nodeId: string, type: NodeLabel, - metadata?: { parameterCount?: number; returnType?: string; declaredType?: string; ownerId?: string } + metadata?: { parameterCount?: number; parameterTypes?: string[]; returnType?: string; declaredType?: string; ownerId?: string } ) => { const def: SymbolDefinition = { nodeId, filePath, type, ...(metadata?.parameterCount !== undefined ? { parameterCount: metadata.parameterCount } : {}), + ...(metadata?.parameterTypes !== undefined ? { parameterTypes: metadata.parameterTypes } : {}), ...(metadata?.returnType !== undefined ? { returnType: metadata.returnType } : {}), ...(metadata?.declaredType !== undefined ? { declaredType: metadata.declaredType } : {}), ...(metadata?.ownerId !== undefined ? { ownerId: metadata.ownerId } : {}), diff --git a/gitnexus/src/core/ingestion/utils.ts b/gitnexus/src/core/ingestion/utils.ts index da411cad4..699ff47f4 100644 --- a/gitnexus/src/core/ingestion/utils.ts +++ b/gitnexus/src/core/ingestion/utils.ts @@ -1,6 +1,7 @@ import type Parser from 'tree-sitter'; import { SupportedLanguages } from '../../config/supported-languages.js'; import { generateId } from '../../lib/utils.js'; +import { extractSimpleTypeName } from './type-extractors/shared.js'; /** Tree-sitter AST node. Re-exported for use across ingestion modules. */ export type SyntaxNode = Parser.SyntaxNode; @@ -599,6 +600,10 @@ export const getLanguageFromFilename = (filename: string): SupportedLanguages | export interface MethodSignature { parameterCount: number | undefined; + /** Per-parameter type names extracted via extractSimpleTypeName. + * Only populated for languages with method overloading (Java, Kotlin, C#, C++). + * undefined (not []) when no types are extractable — avoids empty array allocations. */ + parameterTypes: string[] | undefined; returnType: string | undefined; } @@ -616,8 +621,9 @@ export const extractMethodSignature = (node: SyntaxNode | null | undefined): Met let parameterCount: number | undefined = 0; let returnType: string | undefined; let isVariadic = false; + const paramTypes: string[] = []; - if (!node) return { parameterCount, returnType }; + if (!node) return { parameterCount, parameterTypes: undefined, returnType }; const paramListTypes = new Set([ 'formal_parameters', 'parameters', 'parameter_list', @@ -679,6 +685,30 @@ export const extractMethodSignature = (node: SyntaxNode | null | undefined): Met isVariadic = true; } } + // Extract parameter type name for overload disambiguation. + // Works for Java (formal_parameter), Kotlin (parameter), C# (parameter), + // C++ (parameter_declaration). Uses childForFieldName('type') which is the + // standard tree-sitter field for typed parameters across these languages. + // Kotlin uses positional children instead of 'type' field — fall back to + // searching for user_type/nullable_type/predefined_type children. + const paramTypeNode = param.childForFieldName('type'); + if (paramTypeNode) { + const typeName = extractSimpleTypeName(paramTypeNode); + paramTypes.push(typeName ?? 'unknown'); + } else { + // Kotlin: parameter → [simple_identifier, user_type|nullable_type] + let found = false; + for (const child of param.namedChildren) { + if (child.type === 'user_type' || child.type === 'nullable_type' + || child.type === 'type_identifier' || child.type === 'predefined_type') { + const typeName = extractSimpleTypeName(child); + paramTypes.push(typeName ?? 'unknown'); + found = true; + break; + } + } + if (!found) paramTypes.push('unknown'); + } parameterCount++; } // C/C++: bare `...` token in parameter list (not a named child — check all children) @@ -767,7 +797,10 @@ export const extractMethodSignature = (node: SyntaxNode | null | undefined): Met if (isVariadic) parameterCount = undefined; - return { parameterCount, returnType }; + // Only include parameterTypes when at least one type was successfully extracted. + // Use undefined (not []) to avoid empty array allocations for untyped parameters. + const hasTypes = paramTypes.length > 0 && paramTypes.some(t => t !== 'unknown'); + return { parameterCount, parameterTypes: hasTypes ? paramTypes : undefined, returnType }; }; /** diff --git a/gitnexus/src/core/ingestion/workers/parse-worker.ts b/gitnexus/src/core/ingestion/workers/parse-worker.ts index 3847b3bbf..4240a621d 100644 --- a/gitnexus/src/core/ingestion/workers/parse-worker.ts +++ b/gitnexus/src/core/ingestion/workers/parse-worker.ts @@ -88,6 +88,7 @@ interface ParsedSymbol { nodeId: string; type: NodeLabel; parameterCount?: number; + parameterTypes?: string[]; returnType?: string; declaredType?: string; ownerId?: string; @@ -1183,11 +1184,13 @@ const processFileGroup = ( : null; let parameterCount: number | undefined; + let parameterTypes: string[] | undefined; let returnType: string | undefined; let declaredType: string | undefined; if (nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor') { const sig = extractMethodSignature(definitionNode); parameterCount = sig.parameterCount; + parameterTypes = sig.parameterTypes; returnType = sig.returnType; // Language-specific return type fallback (e.g. Ruby YARD @return [Type]) @@ -1236,6 +1239,7 @@ const processFileGroup = ( nodeId, type: nodeLabel, ...(parameterCount !== undefined ? { parameterCount } : {}), + ...(parameterTypes !== undefined ? { parameterTypes } : {}), ...(returnType !== undefined ? { returnType } : {}), ...(declaredType !== undefined ? { declaredType } : {}), ...(enclosingClassId ? { ownerId: enclosingClassId } : {}),