gitnexus 1.6.6-rc.91 → 1.6.6-rc.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -538,8 +538,9 @@ const HTTPX_ASYNC_CLIENT_GENERIC_PATTERNS = compilePatterns({
538
538
  });
539
539
  /** Strip `.py` and return the bare basename (e.g. `api/users.py` → `users`). */
540
540
  function fileShortKey(rel) {
541
- const slash = rel.lastIndexOf('/');
542
- const file = slash >= 0 ? rel.slice(slash + 1) : rel;
541
+ const normalized = rel.replace(/\\/g, '/');
542
+ const slash = normalized.lastIndexOf('/');
543
+ const file = slash >= 0 ? normalized.slice(slash + 1) : normalized;
543
544
  return file.endsWith('.py') ? file.slice(0, -3) : file;
544
545
  }
545
546
  /**
@@ -548,7 +549,8 @@ function fileShortKey(rel) {
548
549
  * case callers should fall back to the short key.
549
550
  */
550
551
  function fileLongKey(rel) {
551
- const noExt = rel.endsWith('.py') ? rel.slice(0, -3) : rel;
552
+ const normalized = rel.replace(/\\/g, '/');
553
+ const noExt = normalized.endsWith('.py') ? normalized.slice(0, -3) : normalized;
552
554
  const lastSlash = noExt.lastIndexOf('/');
553
555
  if (lastSlash < 0)
554
556
  return '';
@@ -2,6 +2,7 @@
2
2
  // Verified against tree-sitter-cpp ^0.23.4
3
3
  import { SupportedLanguages } from '../../../../_shared/index.js';
4
4
  import { hasKeyword } from '../../field-extractors/configs/helpers.js';
5
+ import { classifyCppParameterType } from '../../languages/cpp/arity-metadata.js';
5
6
  import { extractSimpleTypeName } from '../../type-extractors/shared.js';
6
7
  // ---------------------------------------------------------------------------
7
8
  // C/C++ helpers
@@ -140,6 +141,7 @@ function extractCppParameters(node) {
140
141
  ? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
141
142
  : null,
142
143
  rawType: typeNode?.text?.trim() ?? null,
144
+ typeClass: classifyCppParameterType(typeNode?.text?.trim() ?? 'unknown', declNode?.text, param.text),
143
145
  isOptional: false,
144
146
  isVariadic: false,
145
147
  });
@@ -155,6 +157,7 @@ function extractCppParameters(node) {
155
157
  ? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
156
158
  : null,
157
159
  rawType: typeNode?.text?.trim() ?? null,
160
+ typeClass: classifyCppParameterType(typeNode?.text?.trim() ?? 'unknown', declNode?.text, param.text),
158
161
  isOptional: true,
159
162
  isVariadic: false,
160
163
  });
@@ -171,6 +174,7 @@ function extractCppParameters(node) {
171
174
  ? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
172
175
  : null,
173
176
  rawType: typeNode?.text?.trim() ?? null,
177
+ typeClass: classifyCppParameterType(typeNode?.text?.trim() ?? 'unknown', declNode?.text, param.text),
174
178
  isOptional: false,
175
179
  isVariadic: true,
176
180
  });
@@ -1,4 +1,4 @@
1
- import type { SupportedLanguages } from '../../_shared/index.js';
1
+ import type { ParameterTypeClass, SupportedLanguages } from '../../_shared/index.js';
2
2
  import type { FieldVisibility } from './field-types.js';
3
3
  import type { SyntaxNode } from './utils/ast-helpers.js';
4
4
  export type MethodVisibility = FieldVisibility;
@@ -9,6 +9,7 @@ export interface ParameterInfo {
9
9
  * Used by typeTagForId for overload disambiguation where generic args matter.
10
10
  * Falls back to `type` when not set. */
11
11
  rawType?: string | null;
12
+ typeClass?: ParameterTypeClass;
12
13
  isOptional: boolean;
13
14
  isVariadic: boolean;
14
15
  }
@@ -10,7 +10,7 @@ import { isVerboseIngestionEnabled } from './utils/verbose.js';
10
10
  import { getDefinitionNodeFromCaptures, findEnclosingClassInfo, findObjectLiteralBindingInfo, getLabelFromCaptures, CLASS_CONTAINER_TYPES, } from './utils/ast-helpers.js';
11
11
  import { detectFrameworkFromAST } from './framework-detection.js';
12
12
  import { buildTypeEnv } from './type-env.js';
13
- import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, } from './utils/method-props.js';
13
+ import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, parameterShapeIdTag, } from './utils/method-props.js';
14
14
  import { extractTemplateArguments, templateArgumentsIdTag, templateConstraintsIdTag, } from './utils/template-arguments.js';
15
15
  import { logger } from '../logger.js';
16
16
  import { getTreeSitterBufferSize, getTreeSitterContentByteLength, TREE_SITTER_MAX_BUFFER, } from './constants.js';
@@ -504,6 +504,9 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
504
504
  arityTag += typeTagForId(cached.map, nodeName, arityForId, seqDefMethodInfo, language, cached.groups);
505
505
  arityTag += constTagForId(cached.map, nodeName, arityForId, seqDefMethodInfo, cached.groups);
506
506
  }
507
+ const parameterShapeTag = nodeLabel === 'Function' || nodeLabel === 'Method'
508
+ ? parameterShapeIdTag(methodProps.parameterTypes, methodProps.parameterTypeClasses)
509
+ : '';
507
510
  const classTemplateArguments = extractedClassSymbol?.templateArguments ??
508
511
  provider.classExtractor?.extractTemplateArgumentsFromCapture?.({
509
512
  captureMap,
@@ -551,7 +554,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
551
554
  constraintsTag = '';
552
555
  }
553
556
  }
554
- const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${classTemplateTag}${arityTag}${constraintsTag}`);
557
+ const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${classTemplateTag}${arityTag}${constraintsTag}${parameterShapeTag}`);
555
558
  const classNodeForSymbol = definitionNodeForRange || definitionNode || nameNode;
556
559
  const qualifiedTypeName = extractedClassSymbol?.qualifiedName ??
557
560
  (classNodeForSymbol && provider.classExtractor?.isTypeDeclaration(classNodeForSymbol)
@@ -16,7 +16,7 @@
16
16
  * a different file-level fallback — cross that bridge when they
17
17
  * migrate.
18
18
  */
19
- import type { NodeLabel, ScopeId, SymbolDefinition } from '../../../../_shared/index.js';
19
+ import type { NodeLabel, ParameterTypeClass, ScopeId, SymbolDefinition } from '../../../../_shared/index.js';
20
20
  import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
21
21
  import { type GraphNodeLookup } from '../graph-bridge/node-lookup.js';
22
22
  /**
@@ -40,6 +40,7 @@ export declare function resolveDefGraphId(filePath: string, def: {
40
40
  qualifiedName?: string;
41
41
  type?: NodeLabel;
42
42
  parameterTypes?: readonly string[];
43
+ parameterTypeClasses?: readonly ParameterTypeClass[];
43
44
  templateArguments?: readonly string[];
44
45
  templateConstraints?: unknown;
45
46
  }, nodeLookup: GraphNodeLookup): string | undefined;
@@ -19,6 +19,7 @@
19
19
  import { generateId } from '../../../../lib/utils.js';
20
20
  import { qualifiedKey, simpleKey } from '../graph-bridge/node-lookup.js';
21
21
  import { templateConstraintsIdTag } from '../../utils/template-arguments.js';
22
+ import { parameterShapeIdTag } from '../../utils/method-props.js';
22
23
  /**
23
24
  * Labels that may legitimately ANCHOR a CALLS/ACCESSES edge as the
24
25
  * source ("caller"). A Variable / Property can be the TARGET of an
@@ -82,10 +83,21 @@ export function resolveDefGraphId(filePath, def, nodeLookup) {
82
83
  if (cHit !== undefined)
83
84
  return cHit;
84
85
  }
86
+ if ((def.type === 'Function' || def.type === 'Method') &&
87
+ def.parameterTypes !== undefined &&
88
+ def.parameterTypeClasses !== undefined) {
89
+ const shapeTag = parameterShapeIdTag(def.parameterTypes, def.parameterTypeClasses);
90
+ if (shapeTag !== '') {
91
+ const shapeKey = qualifiedKey(filePath, def.type, `${qn}${shapeTag}`);
92
+ const shapeHit = nodeLookup.get(shapeKey);
93
+ if (shapeHit !== undefined)
94
+ return shapeHit;
95
+ }
96
+ }
85
97
  // Overload disambiguation: when the def carries parameter types,
86
98
  // try the parameter-typed key first so same-name same-arity
87
99
  // overloads route to their distinct graph nodes.
88
- if (def.type === 'Method' &&
100
+ if ((def.type === 'Function' || def.type === 'Method') &&
89
101
  def.parameterTypes !== undefined &&
90
102
  def.parameterTypes.length > 0) {
91
103
  const pKey = qualifiedKey(filePath, def.type, `${qn}~${def.parameterTypes.join(',')}`);
@@ -18,6 +18,7 @@
18
18
  * format that downstream consumers (queries, edges, MCP) expect.
19
19
  */
20
20
  import { templateConstraintsIdTag } from '../../utils/template-arguments.js';
21
+ import { parameterShapeIdTag } from '../../utils/method-props.js';
21
22
  /**
22
23
  * Parse a qualified name out of a Function/Method node id.
23
24
  *
@@ -37,6 +38,9 @@ function parseQualifiedFromId(id, label, filePath) {
37
38
  const hash = suffix.indexOf('#');
38
39
  return hash === -1 ? suffix : suffix.slice(0, hash);
39
40
  }
41
+ function stripCallableDisambiguatorTags(qualifiedName) {
42
+ return qualifiedName.replace(/~shape:.*$/, '').replace(/~c:[a-z0-9]+$/, '');
43
+ }
40
44
  /**
41
45
  * Build a qualified-key string in a separate keyspace from simple-key
42
46
  * strings. Prefix `<q>` can't appear in a valid filePath on any OS, so
@@ -72,7 +76,8 @@ export function buildGraphNodeLookup(graph) {
72
76
  // `def save` vs `class User: def save`).
73
77
  const qualified = props.qualifiedName ?? parseQualifiedFromId(node.id, node.label, props.filePath);
74
78
  if (qualified !== undefined && qualified.length > 0) {
75
- const qKey = qualifiedKey(props.filePath, node.label, qualified);
79
+ const keyQualified = stripCallableDisambiguatorTags(qualified);
80
+ const qKey = qualifiedKey(props.filePath, node.label, keyQualified);
76
81
  if (!lookup.has(qKey))
77
82
  lookup.set(qKey, node.id);
78
83
  // Overload-disambiguating key: include parameter types so two
@@ -82,10 +87,21 @@ export function buildGraphNodeLookup(graph) {
82
87
  // a parameter-types-suffixed key so resolveDefGraphId can find
83
88
  // the right overload by matching its def's parameterTypes.
84
89
  const pTypes = props.parameterTypes;
85
- if (pTypes !== undefined && pTypes.length > 0 && node.label === 'Method') {
86
- const pKey = qualifiedKey(props.filePath, node.label, `${qualified}~${pTypes.join(',')}`);
90
+ if (pTypes !== undefined &&
91
+ pTypes.length > 0 &&
92
+ (node.label === 'Function' || node.label === 'Method')) {
93
+ const pKey = qualifiedKey(props.filePath, node.label, `${keyQualified}~${pTypes.join(',')}`);
87
94
  // Each overload is unique — set unconditionally.
88
- lookup.set(pKey, node.id);
95
+ if (!lookup.has(pKey))
96
+ lookup.set(pKey, node.id);
97
+ }
98
+ const pClasses = props
99
+ .parameterTypeClasses;
100
+ const shapeTag = parameterShapeIdTag(pTypes, pClasses);
101
+ if (shapeTag !== '' && (node.label === 'Function' || node.label === 'Method')) {
102
+ const shapeKey = qualifiedKey(props.filePath, node.label, `${keyQualified}${shapeTag}`);
103
+ if (!lookup.has(shapeKey))
104
+ lookup.set(shapeKey, node.id);
89
105
  }
90
106
  // SFINAE / `requires`-clause disambiguation (issue #1579) — register
91
107
  // a constraint-fingerprinted key so resolveDefGraphId can locate the
@@ -95,7 +111,7 @@ export function buildGraphNodeLookup(graph) {
95
111
  // `parameterTypes=['T']` would otherwise collide.
96
112
  const tConstraints = props.templateConstraints;
97
113
  if (tConstraints !== undefined && (node.label === 'Function' || node.label === 'Method')) {
98
- const cKey = qualifiedKey(props.filePath, node.label, `${qualified}${templateConstraintsIdTag(tConstraints)}`);
114
+ const cKey = qualifiedKey(props.filePath, node.label, `${keyQualified}${templateConstraintsIdTag(tConstraints)}`);
99
115
  lookup.set(cKey, node.id);
100
116
  }
101
117
  if ((node.label === 'Class' ||
@@ -105,7 +121,7 @@ export function buildGraphNodeLookup(graph) {
105
121
  node.label === 'Record') &&
106
122
  props.templateArguments !== undefined &&
107
123
  props.templateArguments.length > 0) {
108
- const tKey = qualifiedKey(props.filePath, node.label, `${qualified}~${props.templateArguments.join(',')}`);
124
+ const tKey = qualifiedKey(props.filePath, node.label, `${keyQualified}~${props.templateArguments.join(',')}`);
109
125
  if (!lookup.has(tKey))
110
126
  lookup.set(tKey, node.id);
111
127
  }
@@ -35,6 +35,11 @@
35
35
  * candidates whose template constraints provably fail at the
36
36
  * call site. Three-valued; `'unknown'` keeps the candidate
37
37
  * (monotonicity).
38
+ * 4d. Conservative C++ template partial-order approximation. When
39
+ * template-placeholder overloads remain tied, prefer a candidate
40
+ * whose parameter shape is more specialized for the observed
41
+ * argument shape (`T*` over `T`, `const T&` over `T`). Unknown or
42
+ * incomparable shapes are left ambiguous.
38
43
  * 5. Empty input returns empty output.
39
44
  */
40
45
  import type { ArityVerdict, Callsite, ConstraintContext, ParameterTypeClass, SymbolDefinition } from '../../../../_shared/index.js';
@@ -35,6 +35,11 @@
35
35
  * candidates whose template constraints provably fail at the
36
36
  * call site. Three-valued; `'unknown'` keeps the candidate
37
37
  * (monotonicity).
38
+ * 4d. Conservative C++ template partial-order approximation. When
39
+ * template-placeholder overloads remain tied, prefer a candidate
40
+ * whose parameter shape is more specialized for the observed
41
+ * argument shape (`T*` over `T`, `const T&` over `T`). Unknown or
42
+ * incomparable shapes are left ambiguous.
38
43
  * 5. Empty input returns empty output.
39
44
  */
40
45
  export function narrowOverloadCandidates(overloads, argCount, argTypes, hookCtx) {
@@ -133,6 +138,11 @@ export function narrowOverloadCandidates(overloads, argCount, argTypes, hookCtx)
133
138
  return hookCtx.constraintCompatibility(callsite, def, ctx) !== 'incompatible';
134
139
  });
135
140
  }
141
+ if (result.length > 1 && argTypes !== undefined && argTypes.length > 0) {
142
+ const partiallyOrdered = rankByTemplatePartialOrdering(result, argTypes, hookCtx?.argumentTypeClasses);
143
+ if (partiallyOrdered !== undefined)
144
+ result = partiallyOrdered;
145
+ }
136
146
  return result;
137
147
  }
138
148
  function exactTypeSlotMatches(argType, paramType, argTypeClass, paramTypeClass) {
@@ -248,6 +258,110 @@ function pairwiseCompare(a, b) {
248
258
  return 1;
249
259
  return 0;
250
260
  }
261
+ /**
262
+ * Closed-table approximation of C++ function-template partial ordering.
263
+ *
264
+ * Full `[temp.func.order]` requires template argument deduction. GitNexus
265
+ * keeps this graph-safe by recognizing only syntactic placeholder shapes
266
+ * that the C++ parameter sidecar already preserves:
267
+ * - `T*` is more specialized than `T` for pointer arguments.
268
+ *
269
+ * Anything with unknown argument shape, non-template parameter spelling, or
270
+ * incomparable specialized shapes stays ambiguous so callers suppress. The
271
+ * placeholder detector is intentionally narrow: lowercase template parameters
272
+ * are left ambiguous rather than guessed.
273
+ */
274
+ function rankByTemplatePartialOrdering(candidates, argTypes, argTypeClasses) {
275
+ if (argTypeClasses === undefined)
276
+ return undefined;
277
+ const viable = [];
278
+ for (const def of candidates) {
279
+ const params = def.parameterTypes;
280
+ const paramClasses = def.parameterTypeClasses;
281
+ if (params === undefined || paramClasses === undefined)
282
+ continue;
283
+ const ranks = [];
284
+ let sawTemplateSlot = false;
285
+ let ok = true;
286
+ for (let i = 0; i < argTypes.length; i++) {
287
+ const paramType = parameterTypeAt(params, i);
288
+ const paramClass = parameterTypeClassAt(paramClasses, i);
289
+ const argClass = argTypeClasses[i];
290
+ if (paramType === undefined || paramClass === undefined || argClass === undefined) {
291
+ ok = false;
292
+ break;
293
+ }
294
+ const rank = templatePartialOrderSlotRank(paramType, paramClass, argClass);
295
+ if (rank === undefined) {
296
+ ok = false;
297
+ break;
298
+ }
299
+ sawTemplateSlot ||= isTemplatePlaceholder(paramType);
300
+ ranks.push(rank);
301
+ }
302
+ if (ok && sawTemplateSlot)
303
+ viable.push({ def, ranks });
304
+ }
305
+ if (viable.length === 0)
306
+ return undefined;
307
+ if (viable.length !== candidates.length)
308
+ return [];
309
+ if (viable.length <= 1)
310
+ return viable.map((v) => v.def);
311
+ const dominated = new Set();
312
+ for (let i = 0; i < viable.length; i++) {
313
+ if (dominated.has(i))
314
+ continue;
315
+ for (let j = i + 1; j < viable.length; j++) {
316
+ if (dominated.has(j))
317
+ continue;
318
+ const cmp = compareSpecializationRanks(viable[i].ranks, viable[j].ranks);
319
+ if (cmp < 0)
320
+ dominated.add(j);
321
+ else if (cmp > 0)
322
+ dominated.add(i);
323
+ }
324
+ }
325
+ return viable.filter((_, idx) => !dominated.has(idx)).map((v) => v.def);
326
+ }
327
+ function templatePartialOrderSlotRank(paramType, paramClass, argClass) {
328
+ if (!isTemplatePlaceholder(paramType))
329
+ return undefined;
330
+ if (argClass.indirection === 'unknown' || paramClass.indirection === 'unknown') {
331
+ return undefined;
332
+ }
333
+ if (isPointerShape(paramClass)) {
334
+ return isPointerShape(argClass) ? 3 : undefined;
335
+ }
336
+ if (paramClass.indirection === 'value')
337
+ return 1;
338
+ return undefined;
339
+ }
340
+ function isTemplatePlaceholder(typeName) {
341
+ return /^[A-Z]\w*$/.test(typeName);
342
+ }
343
+ /**
344
+ * Higher specialization rank is better. Returns -1 when `a` dominates `b`,
345
+ * +1 when `b` dominates `a`, and 0 for ties / incomparable vectors.
346
+ */
347
+ function compareSpecializationRanks(a, b) {
348
+ let aBetter = false;
349
+ let bBetter = false;
350
+ const len = Math.min(a.length, b.length);
351
+ for (let i = 0; i < len; i++) {
352
+ if (a[i] > b[i])
353
+ aBetter = true;
354
+ else if (b[i] > a[i])
355
+ bBetter = true;
356
+ if (aBetter && bBetter)
357
+ return 0;
358
+ }
359
+ if (aBetter && !bBetter)
360
+ return -1;
361
+ if (bBetter && !aBetter)
362
+ return 1;
363
+ return 0;
364
+ }
251
365
  /**
252
366
  * Detect when >1 candidate share identical `parameterTypes` after the
253
367
  * per-language normalizer has collapsed distinct underlying types. This
@@ -1,5 +1,5 @@
1
1
  import type { MethodInfo } from '../method-types.js';
2
- import { SupportedLanguages } from '../../../_shared/index.js';
2
+ import { SupportedLanguages, type ParameterTypeClass } from '../../../_shared/index.js';
3
3
  /**
4
4
  * Compute arity for ID-generation purposes.
5
5
  * Returns `undefined` when any parameter is variadic (arity is indeterminate).
@@ -28,5 +28,15 @@ collisionGroups?: Map<string, MethodInfo[]>): string;
28
28
  export declare function constTagForId(methodMap: Map<string, MethodInfo>, methodName: string, arity: number | undefined, currentInfo: MethodInfo,
29
29
  /** Pre-built collision groups from buildCollisionGroups(). Avoids O(N) scan per call. */
30
30
  collisionGroups?: Map<string, MethodInfo[]>): string;
31
+ /**
32
+ * Disambiguate function-template overloads whose normalized parameter types
33
+ * intentionally collapse to the same placeholder token (`T`, `U`, ...), but
34
+ * whose C++ sidecar shape is semantically different (`T` vs `T*` / `T&`).
35
+ *
36
+ * Kept intentionally narrow: concrete types already use the existing raw-type
37
+ * overload tag, and non-template languages should not acquire sidecar-shaped
38
+ * IDs.
39
+ */
40
+ export declare function parameterShapeIdTag(parameterTypes?: readonly string[], parameterTypeClasses?: readonly ParameterTypeClass[]): string;
31
41
  /** Convert MethodInfo from methodExtractor into flat properties for a graph node. */
32
42
  export declare function buildMethodProps(info: MethodInfo): Record<string, unknown>;
@@ -113,14 +113,53 @@ collisionGroups) {
113
113
  }
114
114
  return '';
115
115
  }
116
+ /**
117
+ * Disambiguate function-template overloads whose normalized parameter types
118
+ * intentionally collapse to the same placeholder token (`T`, `U`, ...), but
119
+ * whose C++ sidecar shape is semantically different (`T` vs `T*` / `T&`).
120
+ *
121
+ * Kept intentionally narrow: concrete types already use the existing raw-type
122
+ * overload tag, and non-template languages should not acquire sidecar-shaped
123
+ * IDs.
124
+ */
125
+ export function parameterShapeIdTag(parameterTypes, parameterTypeClasses) {
126
+ if (parameterTypes === undefined ||
127
+ parameterTypeClasses === undefined ||
128
+ parameterTypes.length === 0) {
129
+ return '';
130
+ }
131
+ let hasTemplatePlaceholder = false;
132
+ let hasDisambiguatingShape = false;
133
+ const parts = [];
134
+ for (let i = 0; i < parameterTypes.length; i++) {
135
+ const type = parameterTypes[i];
136
+ const typeClass = parameterTypeClasses[i];
137
+ if (typeClass === undefined)
138
+ return '';
139
+ if (/^[A-Z]\w*$/.test(type))
140
+ hasTemplatePlaceholder = true;
141
+ if (typeClass.indirection !== 'value' ||
142
+ typeClass.pointerDepth > 0 ||
143
+ (typeClass.cv !== 'none' && typeClass.cv !== 'unknown')) {
144
+ hasDisambiguatingShape = true;
145
+ }
146
+ parts.push(`${type}:${typeClass.cv}:${typeClass.indirection}:${typeClass.pointerDepth.toString()}`);
147
+ }
148
+ if (!hasTemplatePlaceholder || !hasDisambiguatingShape)
149
+ return '';
150
+ return `~shape:${parts.join('|')}`;
151
+ }
116
152
  /** Convert MethodInfo from methodExtractor into flat properties for a graph node. */
117
153
  export function buildMethodProps(info) {
118
154
  const types = [];
155
+ const typeClasses = [];
119
156
  let optionalCount = 0;
120
157
  let hasVariadic = false;
121
158
  for (const p of info.parameters) {
122
159
  if (p.type !== null)
123
160
  types.push(p.type);
161
+ if (p.typeClass !== undefined)
162
+ typeClasses.push(p.typeClass);
124
163
  if (p.isOptional)
125
164
  optionalCount++;
126
165
  if (p.isVariadic)
@@ -132,6 +171,9 @@ export function buildMethodProps(info) {
132
171
  ? { requiredParameterCount: info.parameters.length - optionalCount }
133
172
  : {}),
134
173
  ...(types.length > 0 ? { parameterTypes: types } : {}),
174
+ ...(typeClasses.length === info.parameters.length && typeClasses.length > 0
175
+ ? { parameterTypeClasses: typeClasses }
176
+ : {}),
135
177
  returnType: info.returnType ?? undefined,
136
178
  visibility: info.visibility,
137
179
  isStatic: info.isStatic,
@@ -44,7 +44,7 @@ import { detectFrameworkFromAST } from '../framework-detection.js';
44
44
  import { generateId } from '../../../lib/utils.js';
45
45
  import { preprocessImportPath } from '../import-processor.js';
46
46
  import { extractVueScript, extractTemplateComponents, isVueSetupTopLevel, } from '../vue-sfc-extractor.js';
47
- import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, } from '../utils/method-props.js';
47
+ import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, parameterShapeIdTag, } from '../utils/method-props.js';
48
48
  import { extractTemplateArguments, templateArgumentsIdTag } from '../utils/template-arguments.js';
49
49
  import { extractParsedFile } from '../scope-extractor-bridge.js';
50
50
  import { extractLaravelRoutes } from '../route-extractors/laravel.js';
@@ -1357,6 +1357,9 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1357
1357
  arityTag += typeTagForId(defMethodMap, nodeName, arityForId, defMethodInfo, language, groups);
1358
1358
  arityTag += constTagForId(defMethodMap, nodeName, arityForId, defMethodInfo, groups);
1359
1359
  }
1360
+ const parameterShapeTag = nodeLabel === 'Function' || nodeLabel === 'Method'
1361
+ ? parameterShapeIdTag(methodProps.parameterTypes, methodProps.parameterTypeClasses)
1362
+ : '';
1360
1363
  const classTemplateArguments = extractedClassSymbol?.templateArguments ??
1361
1364
  provider.classExtractor?.extractTemplateArgumentsFromCapture?.({
1362
1365
  captureMap,
@@ -1376,7 +1379,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1376
1379
  classTemplateArguments.length > 0
1377
1380
  ? templateArgumentsIdTag(classTemplateArguments)
1378
1381
  : '';
1379
- const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${classTemplateTag}${arityTag}`);
1382
+ const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${classTemplateTag}${arityTag}${parameterShapeTag}`);
1380
1383
  const classNodeForSymbol = definitionNode || nameNode;
1381
1384
  const qualifiedTypeName = extractedClassSymbol?.qualifiedName ??
1382
1385
  (classNodeForSymbol && provider.classExtractor?.isTypeDeclaration(classNodeForSymbol)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.6-rc.91",
3
+ "version": "1.6.6-rc.92",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",