@lzehrung/codegraph 2.3.27 → 2.3.29

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.
Files changed (188) hide show
  1. package/codegraph-skill/codegraph/SKILL.md +1 -0
  2. package/dist/agent/explain.d.ts +9 -1
  3. package/dist/agent/explain.d.ts.map +1 -1
  4. package/dist/agent/explain.js +18 -1
  5. package/dist/agent/explain.js.map +1 -1
  6. package/dist/agent/refactor-plan.d.ts +2 -0
  7. package/dist/agent/refactor-plan.d.ts.map +1 -1
  8. package/dist/agent/refactor-plan.js +11 -0
  9. package/dist/agent/refactor-plan.js.map +1 -1
  10. package/dist/agent/rename-preview.d.ts.map +1 -1
  11. package/dist/agent/rename-preview.js +49 -11
  12. package/dist/agent/rename-preview.js.map +1 -1
  13. package/dist/agent-tools.d.ts +2 -1
  14. package/dist/agent-tools.d.ts.map +1 -1
  15. package/dist/agent-tools.js +8 -0
  16. package/dist/agent-tools.js.map +1 -1
  17. package/dist/agent.d.ts +1 -1
  18. package/dist/agent.d.ts.map +1 -1
  19. package/dist/agent.js.map +1 -1
  20. package/dist/bin/cli.js +3236 -1275
  21. package/dist/bin/query-index-worker.js +151 -29
  22. package/dist/cli/navigation.d.ts.map +1 -1
  23. package/dist/cli/navigation.js +4 -0
  24. package/dist/cli/navigation.js.map +1 -1
  25. package/dist/graphs/edge-resolution.d.ts.map +1 -1
  26. package/dist/graphs/edge-resolution.js +5 -0
  27. package/dist/graphs/edge-resolution.js.map +1 -1
  28. package/dist/graphs/symbol-graph-detailed/ast.d.ts.map +1 -1
  29. package/dist/graphs/symbol-graph-detailed/ast.js +3 -0
  30. package/dist/graphs/symbol-graph-detailed/ast.js.map +1 -1
  31. package/dist/graphs/symbol-graph-detailed/edge-passes.d.ts.map +1 -1
  32. package/dist/graphs/symbol-graph-detailed/edge-passes.js +40 -6
  33. package/dist/graphs/symbol-graph-detailed/edge-passes.js.map +1 -1
  34. package/dist/graphs/symbol-graph-detailed/receiver-calls.d.ts.map +1 -1
  35. package/dist/graphs/symbol-graph-detailed/receiver-calls.js +8 -1
  36. package/dist/graphs/symbol-graph-detailed/receiver-calls.js.map +1 -1
  37. package/dist/impact/analyzer.d.ts.map +1 -1
  38. package/dist/impact/analyzer.js +82 -4
  39. package/dist/impact/analyzer.js.map +1 -1
  40. package/dist/impact/call-compatibility.js +3 -3
  41. package/dist/impact/call-compatibility.js.map +1 -1
  42. package/dist/impact/direct.js +1 -1
  43. package/dist/impact/direct.js.map +1 -1
  44. package/dist/impact/map.d.ts.map +1 -1
  45. package/dist/impact/map.js +58 -1
  46. package/dist/impact/map.js.map +1 -1
  47. package/dist/impact/member-resolution-coverage.d.ts.map +1 -1
  48. package/dist/impact/member-resolution-coverage.js +1 -4
  49. package/dist/impact/member-resolution-coverage.js.map +1 -1
  50. package/dist/impact/reference-cache.d.ts +1 -0
  51. package/dist/impact/reference-cache.d.ts.map +1 -1
  52. package/dist/impact/reference-cache.js +44 -18
  53. package/dist/impact/reference-cache.js.map +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js.map +1 -1
  57. package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
  58. package/dist/indexer/build-cache/module-cache.js +30 -0
  59. package/dist/indexer/build-cache/module-cache.js.map +1 -1
  60. package/dist/indexer/build-cache/options.d.ts +17 -2
  61. package/dist/indexer/build-cache/options.d.ts.map +1 -1
  62. package/dist/indexer/build-cache/options.js +17 -2
  63. package/dist/indexer/build-cache/options.js.map +1 -1
  64. package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
  65. package/dist/indexer/build-cache/project-snapshot.js +60 -5
  66. package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
  67. package/dist/indexer/import-types.d.ts +14 -1
  68. package/dist/indexer/import-types.d.ts.map +1 -1
  69. package/dist/indexer/imports/binding-ranges.d.ts +50 -0
  70. package/dist/indexer/imports/binding-ranges.d.ts.map +1 -0
  71. package/dist/indexer/imports/binding-ranges.js +297 -0
  72. package/dist/indexer/imports/binding-ranges.js.map +1 -0
  73. package/dist/indexer/imports/js-text-imports.d.ts +4 -0
  74. package/dist/indexer/imports/js-text-imports.d.ts.map +1 -1
  75. package/dist/indexer/imports/js-text-imports.js +210 -48
  76. package/dist/indexer/imports/js-text-imports.js.map +1 -1
  77. package/dist/indexer/imports/language-specific.d.ts +3 -0
  78. package/dist/indexer/imports/language-specific.d.ts.map +1 -1
  79. package/dist/indexer/imports/language-specific.js +127 -24
  80. package/dist/indexer/imports/language-specific.js.map +1 -1
  81. package/dist/indexer/imports/native-captures.d.ts.map +1 -1
  82. package/dist/indexer/imports/native-captures.js +52 -30
  83. package/dist/indexer/imports/native-captures.js.map +1 -1
  84. package/dist/indexer/imports/python.d.ts +2 -0
  85. package/dist/indexer/imports/python.d.ts.map +1 -1
  86. package/dist/indexer/imports/python.js +55 -18
  87. package/dist/indexer/imports/python.js.map +1 -1
  88. package/dist/indexer/imports.d.ts.map +1 -1
  89. package/dist/indexer/imports.js +15 -1
  90. package/dist/indexer/imports.js.map +1 -1
  91. package/dist/indexer/locals-and-exports.d.ts.map +1 -1
  92. package/dist/indexer/locals-and-exports.js +3 -0
  93. package/dist/indexer/locals-and-exports.js.map +1 -1
  94. package/dist/indexer/navigation-goto.d.ts +1 -1
  95. package/dist/indexer/navigation-goto.d.ts.map +1 -1
  96. package/dist/indexer/navigation-goto.js +397 -17
  97. package/dist/indexer/navigation-goto.js.map +1 -1
  98. package/dist/indexer/navigation-references.d.ts +23 -2
  99. package/dist/indexer/navigation-references.d.ts.map +1 -1
  100. package/dist/indexer/navigation-references.js +196 -4
  101. package/dist/indexer/navigation-references.js.map +1 -1
  102. package/dist/indexer/navigation.d.ts +9 -3
  103. package/dist/indexer/navigation.d.ts.map +1 -1
  104. package/dist/indexer/navigation.js +164 -41
  105. package/dist/indexer/navigation.js.map +1 -1
  106. package/dist/indexer/scope.d.ts.map +1 -1
  107. package/dist/indexer/scope.js +18 -0
  108. package/dist/indexer/scope.js.map +1 -1
  109. package/dist/indexer/symbols.d.ts +1 -0
  110. package/dist/indexer/symbols.d.ts.map +1 -1
  111. package/dist/indexer/types.d.ts +10 -0
  112. package/dist/indexer/types.d.ts.map +1 -1
  113. package/dist/indexer.d.ts +1 -1
  114. package/dist/indexer.d.ts.map +1 -1
  115. package/dist/indexer.js.map +1 -1
  116. package/dist/languages/definitions/cpp.d.ts.map +1 -1
  117. package/dist/languages/definitions/cpp.js +28 -1
  118. package/dist/languages/definitions/cpp.js.map +1 -1
  119. package/dist/languages/definitions/csharp.js +1 -1
  120. package/dist/languages/definitions/csharp.js.map +1 -1
  121. package/dist/languages/definitions/javascript.d.ts.map +1 -1
  122. package/dist/languages/definitions/javascript.js +10 -2
  123. package/dist/languages/definitions/javascript.js.map +1 -1
  124. package/dist/languages/definitions/php.d.ts.map +1 -1
  125. package/dist/languages/definitions/php.js +15 -8
  126. package/dist/languages/definitions/php.js.map +1 -1
  127. package/dist/languages/definitions/python.d.ts +5 -1
  128. package/dist/languages/definitions/python.d.ts.map +1 -1
  129. package/dist/languages/definitions/python.js +50 -1
  130. package/dist/languages/definitions/python.js.map +1 -1
  131. package/dist/languages/definitions/scss.d.ts.map +1 -1
  132. package/dist/languages/definitions/scss.js +23 -1
  133. package/dist/languages/definitions/scss.js.map +1 -1
  134. package/dist/languages/definitions/typescript.d.ts.map +1 -1
  135. package/dist/languages/definitions/typescript.js +43 -6
  136. package/dist/languages/definitions/typescript.js.map +1 -1
  137. package/dist/languages/definitions/zig.d.ts.map +1 -1
  138. package/dist/languages/definitions/zig.js +10 -3
  139. package/dist/languages/definitions/zig.js.map +1 -1
  140. package/dist/languages/import-statement-parsers.d.ts +3 -0
  141. package/dist/languages/import-statement-parsers.d.ts.map +1 -1
  142. package/dist/languages/import-statement-parsers.js +4 -0
  143. package/dist/languages/import-statement-parsers.js.map +1 -1
  144. package/dist/mcp/handlers.d.ts +2 -1
  145. package/dist/mcp/handlers.d.ts.map +1 -1
  146. package/dist/mcp/handlers.js +15 -1
  147. package/dist/mcp/handlers.js.map +1 -1
  148. package/dist/review/summaries.d.ts.map +1 -1
  149. package/dist/review/summaries.js +11 -19
  150. package/dist/review/summaries.js.map +1 -1
  151. package/dist/review/types.d.ts +2 -1
  152. package/dist/review/types.d.ts.map +1 -1
  153. package/dist/review/types.js.map +1 -1
  154. package/dist/session.d.ts +2 -9
  155. package/dist/session.d.ts.map +1 -1
  156. package/dist/session.js.map +1 -1
  157. package/dist/sql/graph.d.ts +1 -1
  158. package/dist/sql/graph.d.ts.map +1 -1
  159. package/dist/sql/graph.js.map +1 -1
  160. package/dist/sql/lookup.d.ts +7 -0
  161. package/dist/sql/lookup.d.ts.map +1 -1
  162. package/dist/sql/lookup.js +17 -0
  163. package/dist/sql/lookup.js.map +1 -1
  164. package/dist/sql/navigation.d.ts +6 -1
  165. package/dist/sql/navigation.d.ts.map +1 -1
  166. package/dist/sql/navigation.js +35 -3
  167. package/dist/sql/navigation.js.map +1 -1
  168. package/dist/sql/source-graph.d.ts +2 -0
  169. package/dist/sql/source-graph.d.ts.map +1 -1
  170. package/dist/sql/source-graph.js +20 -1
  171. package/dist/sql/source-graph.js.map +1 -1
  172. package/dist/util/comments.d.ts +10 -0
  173. package/dist/util/comments.d.ts.map +1 -1
  174. package/dist/util/comments.js +43 -2
  175. package/dist/util/comments.js.map +1 -1
  176. package/dist/util/lines.d.ts +2 -0
  177. package/dist/util/lines.d.ts.map +1 -1
  178. package/dist/util/lines.js +14 -0
  179. package/dist/util/lines.js.map +1 -1
  180. package/dist/util/resolution/csharp.d.ts +7 -0
  181. package/dist/util/resolution/csharp.d.ts.map +1 -0
  182. package/dist/util/resolution/csharp.js +189 -0
  183. package/dist/util/resolution/csharp.js.map +1 -0
  184. package/dist/util/resolution.d.ts.map +1 -1
  185. package/dist/util/resolution.js +2 -0
  186. package/dist/util/resolution.js.map +1 -1
  187. package/docs/mcp.md +1 -1
  188. package/package.json +3 -3
@@ -1,4 +1,5 @@
1
1
  import { isJsTsLanguage } from "../languages/js-family.js";
2
+ import { isPythonReceiverAttributeAssignmentName } from "../languages/definitions/python.js";
2
3
  import { sliceText } from "../util/ast.js";
3
4
  import { fileIdentityKey } from "../util/paths.js";
4
5
  import { getMemberAccessParts, getNavigationExpressionProperty, isMemberAccessNode, memberAccessTraversalTypes, } from "../util/member-access.js";
@@ -6,6 +7,7 @@ import { CSHARP_IDENTIFIER_SOURCE, JAVA_IDENTIFIER_SOURCE, XID_IDENTIFIER_SOURCE
6
7
  import { ensureParsedContext } from "./parse-context.js";
7
8
  import { okGoToResult } from "./navigation-provenance.js";
8
9
  import { resolveExport, resolveImported } from "./navigation-resolve.js";
10
+ import { SymbolKind, } from "./types.js";
9
11
  const RUBY_CONSTANT_SOURCE = String.raw `(?=\p{Lu})${XID_IDENTIFIER_SOURCE}`;
10
12
  const CSHARP_CONSTANT_SOURCE = String.raw `(?=@?\p{Lu})${CSHARP_IDENTIFIER_SOURCE}`;
11
13
  const JAVA_CONSTANT_SOURCE = String.raw `(?=\p{Lu})${JAVA_IDENTIFIER_SOURCE}`;
@@ -133,6 +135,16 @@ export async function resolveMemberAccessDefinition(params) {
133
135
  (sup.id === "rust" && /^(?:self|Self)$/.test(receiverName));
134
136
  if (obj && prop && node.id === prop.id && (supportsReceiverMemberResolution(sup.id) || implicitClassReceiver)) {
135
137
  const member = sliceText(prop, source);
138
+ if (sup.id === "python") {
139
+ const memberDef = await resolvePythonReceiverMember(index, mod, node, obj, member, source, sup, resolveExpression);
140
+ if (!memberDef)
141
+ return null;
142
+ return okGoToResult(index, memberDef, {
143
+ via: { exportedName: member },
144
+ resolution: "member-access",
145
+ confidence: "medium",
146
+ });
147
+ }
136
148
  if (!sup.membersAreImplicitlyInScope && implicitClassReceiver) {
137
149
  const classContainer = findEnclosingClassContainer(node);
138
150
  const memberDef = classContainer
@@ -146,8 +158,9 @@ export async function resolveMemberAccessDefinition(params) {
146
158
  });
147
159
  }
148
160
  }
149
- const objDef = await resolveReceiverDefinition(obj, source, sup, resolveExpression);
150
- if (objDef) {
161
+ const receiver = await resolveReceiverDefinition(obj, source, sup, resolveExpression);
162
+ if (receiver) {
163
+ const objDef = receiver.def;
151
164
  const targetContext = await ensureParsedContext(objDef.file, undefined, index.languageExtensions);
152
165
  const start = objDef.range.start;
153
166
  const targetPosition = {
@@ -156,13 +169,27 @@ export async function resolveMemberAccessDefinition(params) {
156
169
  };
157
170
  const nameNode = targetContext.tree.rootNode.descendantForPosition(targetPosition, targetPosition);
158
171
  const container = nameNode.parent;
172
+ if (receiver.runtimeTypeOnly &&
173
+ container &&
174
+ container.type !== "enum_declaration" &&
175
+ container.type !== "internal_module" &&
176
+ container.type !== "module") {
177
+ return null;
178
+ }
159
179
  if (container) {
160
180
  const targetModule = index.byFile.get(fileIdentityKey(objDef.file));
161
181
  if (targetModule) {
162
182
  const normalizeIdentifier = targetContext.sup.normalizeIdentifier;
163
- const memberDef = targetContext.sup.id === "java"
164
- ? findDirectLocalWithinNode(targetModule.locals, member, container, targetContext, normalizeIdentifier)
165
- : findReceiverMemberDefinition(targetModule.locals, member, objDef, container, targetContext, normalizeIdentifier);
183
+ let memberDef;
184
+ if (receiver.runtimeTypeOnly) {
185
+ memberDef = findDirectLocalWithinNode(targetModule.locals, member, container, targetContext, normalizeIdentifier);
186
+ }
187
+ else if (targetContext.sup.id === "java") {
188
+ memberDef = findDirectLocalWithinNode(targetModule.locals, member, container, targetContext, normalizeIdentifier);
189
+ }
190
+ else {
191
+ memberDef = findReceiverMemberDefinition(targetModule.locals, member, objDef, container, targetContext, normalizeIdentifier, receiver.memberScope);
192
+ }
166
193
  if (memberDef) {
167
194
  return okGoToResult(index, memberDef, {
168
195
  via: { exportedName: member },
@@ -206,17 +233,24 @@ async function resolveReceiverDefinition(obj, source, sup, resolveExpression) {
206
233
  if (constructor) {
207
234
  const result = await resolveExpression(constructor);
208
235
  if (result?.kind === "resolved") {
209
- return result.def;
236
+ return {
237
+ def: result.def,
238
+ memberScope: isJsTsLanguage(sup.id) ? "instance" : "any",
239
+ };
210
240
  }
211
241
  }
212
- if (isJsTsLanguage(sup.id)) {
213
- if (sup.nodeTypes.identifier.includes(obj.type)) {
214
- return null;
242
+ const direct = await resolveExpression(obj);
243
+ if (isJsTsLanguage(sup.id) && sup.nodeTypes.identifier.includes(obj.type)) {
244
+ if (direct?.kind === "resolved" && direct.def.kind === SymbolKind.Class) {
245
+ return { def: direct.def, memberScope: "static" };
215
246
  }
247
+ if (direct?.kind === "resolved" && direct.def.kind === SymbolKind.TypeAlias) {
248
+ return { def: direct.def, memberScope: "any", runtimeTypeOnly: true };
249
+ }
250
+ return null;
216
251
  }
217
- const direct = await resolveExpression(obj);
218
252
  if (direct?.kind === "resolved") {
219
- return direct.def;
253
+ return { def: direct.def, memberScope: "any" };
220
254
  }
221
255
  return null;
222
256
  }
@@ -275,6 +309,7 @@ const BINDING_CONTAINER_TYPES = new Set([
275
309
  "block",
276
310
  "function_declaration",
277
311
  "function_item",
312
+ "function_definition",
278
313
  "function",
279
314
  "function_expression",
280
315
  "arrow_function",
@@ -289,6 +324,9 @@ const BINDING_DECLARATION_TYPES = new Set([
289
324
  "formal_parameter",
290
325
  "required_parameter",
291
326
  "optional_parameter",
327
+ "parameter_declaration",
328
+ "short_var_declaration",
329
+ "var_spec",
292
330
  ]);
293
331
  function findVisiblePriorNewConstructor(receiver, receiverName, source, sup) {
294
332
  let current = receiver;
@@ -355,6 +393,16 @@ function findPriorNewConstructorInContainer(node, receiver, receiverName, source
355
393
  constructor = candidate;
356
394
  }
357
395
  }
396
+ if (sup.id === "go" && (current.type === "short_var_declaration" || current.type === "var_spec")) {
397
+ const candidate = constructorFromGoBinding(current, receiverName, source, sup);
398
+ if (candidate) {
399
+ if (constructor && sliceText(constructor, source) !== sliceText(candidate, source)) {
400
+ constructor = null;
401
+ return false;
402
+ }
403
+ constructor = candidate;
404
+ }
405
+ }
358
406
  for (const child of current.namedChildren) {
359
407
  if (!visit(child)) {
360
408
  return false;
@@ -383,6 +431,8 @@ function bindingContainerDeclaresNameBefore(node, receiver, receiverName, source
383
431
  return false;
384
432
  }
385
433
  if (BINDING_DECLARATION_TYPES.has(current.type)) {
434
+ if (goBindingDeclaresName(current, receiverName, source, sup))
435
+ return true;
386
436
  const name = current.childForFieldName("name") ?? current.child(0);
387
437
  if (name && sup.nodeTypes.identifier.includes(name.type) && sliceText(name, source) === receiverName) {
388
438
  return true;
@@ -419,8 +469,88 @@ function constructorFromAssignmentLike(node, receiverName, source, sup) {
419
469
  return null;
420
470
  return findNamedChildText(node, match[1], source, sup);
421
471
  }
472
+ if (sup.id === "python") {
473
+ return pythonConstructorFromAssignment(node, receiverName, source, sup);
474
+ }
422
475
  return null;
423
476
  }
477
+ function goBindingNameNodes(node) {
478
+ if (node.type === "short_var_declaration") {
479
+ const left = node.childForFieldName("left");
480
+ return (left?.namedChildren ?? []).filter((child) => child.type === "identifier");
481
+ }
482
+ if (node.type === "var_spec") {
483
+ return (node.namedChildren ?? []).filter((child) => child.type === "identifier");
484
+ }
485
+ return [];
486
+ }
487
+ function goBindingDeclaresName(node, receiverName, source, sup) {
488
+ if (sup.id !== "go")
489
+ return false;
490
+ return goBindingNameNodes(node).some((name) => sliceText(name, source) === receiverName);
491
+ }
492
+ function constructorFromGoBinding(node, receiverName, source, sup) {
493
+ if (!goBindingDeclaresName(node, receiverName, source, sup))
494
+ return null;
495
+ if (node.type === "short_var_declaration") {
496
+ const left = node.childForFieldName("left");
497
+ const right = node.childForFieldName("right");
498
+ if (!left || !right)
499
+ return null;
500
+ const names = (left.namedChildren ?? []).filter((child) => child.type === "identifier");
501
+ const values = right.namedChildren ?? [];
502
+ const index = names.findIndex((name) => sliceText(name, source) === receiverName);
503
+ if (index < 0)
504
+ return null;
505
+ const value = values[index] ?? null;
506
+ return value ? goCompositeLiteralTypeName(value, source) : null;
507
+ }
508
+ if (node.type !== "var_spec")
509
+ return null;
510
+ const value = node.childForFieldName("value");
511
+ if (value) {
512
+ const first = value.type === "expression_list" ? (value.namedChildren[0] ?? null) : value;
513
+ const fromValue = first ? goCompositeLiteralTypeName(first, source) : null;
514
+ if (fromValue)
515
+ return fromValue;
516
+ }
517
+ const typeNode = node.childForFieldName("type");
518
+ return typeNode ? unwrapGoConstructorType(typeNode) : null;
519
+ }
520
+ function goCompositeLiteralTypeName(expr, source) {
521
+ let current = expr;
522
+ if (current.type === "unary_expression") {
523
+ const operand = current.childForFieldName("operand");
524
+ if (!operand)
525
+ return null;
526
+ const operator = current.childForFieldName("operator");
527
+ let isAddr = sliceText(current, source).startsWith("&");
528
+ if (operator)
529
+ isAddr = sliceText(operator, source) === "&";
530
+ if (!isAddr)
531
+ return null;
532
+ current = operand;
533
+ }
534
+ if (current.type !== "composite_literal")
535
+ return null;
536
+ const typeNode = current.childForFieldName("type");
537
+ return typeNode ? unwrapGoConstructorType(typeNode) : null;
538
+ }
539
+ function unwrapGoConstructorType(node) {
540
+ let current = node;
541
+ while (current) {
542
+ if (current.type === "parenthesized_type" || current.type === "pointer_type") {
543
+ current = current.namedChildren[0] ?? null;
544
+ continue;
545
+ }
546
+ if (current.type === "generic_type") {
547
+ current = current.childForFieldName("type") ?? current.namedChildren[0] ?? null;
548
+ continue;
549
+ }
550
+ break;
551
+ }
552
+ return current?.type === "type_identifier" ? current : null;
553
+ }
424
554
  function findNamedChildText(node, name, source, sup) {
425
555
  const isNameNode = (candidate) => (sup.nodeTypes.identifier.includes(candidate.type) ||
426
556
  candidate.type === "type_identifier" ||
@@ -460,8 +590,13 @@ async function resolveMemberDefinitionForBase(index, baseDef, member) {
460
590
  return undefined;
461
591
  return findReceiverMemberDefinition(targetModule.locals, member, baseDef, container, targetContext, normalizeIdentifier);
462
592
  }
463
- function findReceiverMemberDefinition(locals, member, receiverDef, container, targetContext, normalizeIdentifier) {
464
- const containerHit = findLocalWithinNode(locals, member, container, normalizeIdentifier);
593
+ function findReceiverMemberDefinition(locals, member, receiverDef, container, targetContext, normalizeIdentifier, memberScope = "any") {
594
+ const memberPredicate = memberScope === "any"
595
+ ? undefined
596
+ : (local) => hasStaticModifier(local, targetContext, container) === (memberScope === "static");
597
+ const containerHit = memberScope === "any"
598
+ ? findLocalWithinNode(locals, member, container, normalizeIdentifier)
599
+ : findDirectLocalWithinNode(locals, member, container, targetContext, normalizeIdentifier, memberPredicate);
465
600
  if (containerHit)
466
601
  return containerHit;
467
602
  if (targetContext.sup.id !== "rust")
@@ -469,7 +604,7 @@ function findReceiverMemberDefinition(locals, member, receiverDef, container, ta
469
604
  const implNode = findRustImplForType(targetContext.tree.rootNode, receiverDef.localName, targetContext.source);
470
605
  return implNode ? findLocalWithinNode(locals, member, implNode, normalizeIdentifier) : undefined;
471
606
  }
472
- function findLocalWithinNode(locals, member, node, normalizeIdentifier = (name) => name) {
607
+ function findLocalWithinNode(locals, member, node, normalizeIdentifier = (name) => name, predicate) {
473
608
  const containerStart = node.startIndex;
474
609
  const containerEnd = node.endIndex;
475
610
  const normalizedMember = normalizeIdentifier(member);
@@ -480,9 +615,28 @@ function findLocalWithinNode(locals, member, node, normalizeIdentifier = (name)
480
615
  startIndex !== undefined &&
481
616
  endIndex !== undefined &&
482
617
  startIndex >= containerStart &&
483
- endIndex <= containerEnd);
618
+ endIndex <= containerEnd &&
619
+ (!predicate || predicate(local)));
484
620
  });
485
621
  }
622
+ function hasStaticModifier(local, targetContext, container) {
623
+ const position = {
624
+ row: local.range.start.line - 1,
625
+ column: local.range.start.column - 1,
626
+ };
627
+ let current = targetContext.tree.rootNode.descendantForPosition(position, position);
628
+ while (current && current !== container) {
629
+ for (let childIndex = 0;; childIndex += 1) {
630
+ const child = current.child(childIndex);
631
+ if (!child)
632
+ break;
633
+ if (child.type === "static")
634
+ return true;
635
+ }
636
+ current = current.parent;
637
+ }
638
+ return false;
639
+ }
486
640
  const NESTED_MEMBER_LOCAL_CONTAINERS = new Set([
487
641
  "block",
488
642
  "class",
@@ -502,7 +656,7 @@ const NESTED_MEMBER_LOCAL_CONTAINERS = new Set([
502
656
  "module",
503
657
  "statement_block",
504
658
  ]);
505
- function findDirectLocalWithinNode(locals, member, container, targetContext, normalizeIdentifier) {
659
+ function findDirectLocalWithinNode(locals, member, container, targetContext, normalizeIdentifier, predicate) {
506
660
  const containerStart = container.startIndex;
507
661
  const containerEnd = container.endIndex;
508
662
  const normalizedMember = normalizeIdentifier(member);
@@ -524,7 +678,9 @@ function findDirectLocalWithinNode(locals, member, container, targetContext, nor
524
678
  let current = targetContext.tree.rootNode.descendantForPosition(position, position).parent;
525
679
  let isDeclarationParent = true;
526
680
  while (current && current !== container) {
681
+ const isDirectBody = (current.type === "statement_block" || current.type === "block") && current.parent === container;
527
682
  if (!isDeclarationParent &&
683
+ !isDirectBody &&
528
684
  ((current.type === "class_body" && current.parent !== container) ||
529
685
  NESTED_MEMBER_LOCAL_CONTAINERS.has(current.type))) {
530
686
  current = null;
@@ -533,7 +689,7 @@ function findDirectLocalWithinNode(locals, member, container, targetContext, nor
533
689
  isDeclarationParent = false;
534
690
  current = current.parent;
535
691
  }
536
- if (current)
692
+ if (current && (!predicate || predicate(local)))
537
693
  return local;
538
694
  }
539
695
  return undefined;
@@ -557,6 +713,230 @@ function findRustImplForType(root, typeName, source) {
557
713
  visit(root);
558
714
  return found;
559
715
  }
716
+ function pythonConstructorFromAssignment(node, receiverName, source, sup) {
717
+ const left = node.childForFieldName("left");
718
+ if (!left || !sup.nodeTypes.identifier.includes(left.type) || sliceText(left, source) !== receiverName) {
719
+ return null;
720
+ }
721
+ const right = node.childForFieldName("right");
722
+ if (!right || right.type !== "call")
723
+ return null;
724
+ const callee = right.childForFieldName("function") ?? right.namedChildren[0] ?? null;
725
+ if (!callee || !sup.nodeTypes.identifier.includes(callee.type))
726
+ return null;
727
+ return callee;
728
+ }
729
+ const PYTHON_SUPERTYPE_DEPTH = 16;
730
+ function pythonClassKey(def) {
731
+ const start = def.range.start;
732
+ return `${fileIdentityKey(def.file)}:${start.index ?? `${start.line}:${start.column}`}`;
733
+ }
734
+ async function resolvePythonReceiverMember(index, mod, node, obj, member, source, sup, resolveExpression) {
735
+ const classRef = await pythonReceiverClassRef(index, mod, node, obj, source, sup, resolveExpression);
736
+ if (!classRef)
737
+ return undefined;
738
+ return lookupPythonClassMember(index, classRef, member);
739
+ }
740
+ async function pythonReceiverClassRef(index, mod, node, obj, source, sup, resolveExpression) {
741
+ const receiverName = sliceText(obj, source);
742
+ if (receiverName === "self" || receiverName === "cls") {
743
+ const container = findEnclosingClassContainer(node);
744
+ if (!container)
745
+ return null;
746
+ const nameNode = container.childForFieldName("name");
747
+ if (!nameNode)
748
+ return null;
749
+ const className = sliceText(nameNode, source);
750
+ const def = mod.locals.find((local) => {
751
+ const startIndex = local.range.start.index;
752
+ const endIndex = local.range.end.index;
753
+ return (local.kind === SymbolKind.Class &&
754
+ local.localName === className &&
755
+ startIndex !== undefined &&
756
+ endIndex !== undefined &&
757
+ startIndex >= container.startIndex &&
758
+ endIndex <= container.endIndex);
759
+ });
760
+ if (!def)
761
+ return null;
762
+ return pythonClassRefFromDef(index, def);
763
+ }
764
+ let classDef;
765
+ const constructor = receiverConstructorExpression(obj, source, sup);
766
+ if (constructor) {
767
+ const result = await resolveExpression(constructor);
768
+ if (result?.kind === "resolved" && result.def.kind === SymbolKind.Class) {
769
+ classDef = result.def;
770
+ }
771
+ }
772
+ if (!classDef) {
773
+ const direct = await resolveExpression(obj);
774
+ if (direct?.kind === "resolved" && direct.def.kind === SymbolKind.Class) {
775
+ classDef = direct.def;
776
+ }
777
+ }
778
+ if (!classDef)
779
+ return null;
780
+ return pythonClassRefFromDef(index, classDef);
781
+ }
782
+ async function pythonClassRefFromDef(index, def) {
783
+ const module = index.byFile.get(fileIdentityKey(def.file));
784
+ if (!module)
785
+ return null;
786
+ const context = await ensureParsedContext(def.file, undefined, index.languageExtensions);
787
+ const start = def.range.start;
788
+ const position = {
789
+ row: start.line - 1,
790
+ column: start.column - 1,
791
+ };
792
+ let current = context.tree.rootNode.descendantForPosition(position, position);
793
+ while (current && current.type !== "class_definition") {
794
+ current = current.parent;
795
+ }
796
+ if (!current)
797
+ return null;
798
+ return { def, container: current, context, module };
799
+ }
800
+ function pythonMembersOnClass(classRef, member) {
801
+ const normalizeIdentifier = classRef.context.sup.normalizeIdentifier;
802
+ const direct = findDirectLocalWithinNode(classRef.module.locals, member, classRef.container, classRef.context, normalizeIdentifier);
803
+ if (direct)
804
+ return [direct];
805
+ const attribute = findPythonInstanceAttributeWithinClass(classRef.module.locals, member, classRef.container, classRef.context, normalizeIdentifier);
806
+ return attribute ? [attribute] : [];
807
+ }
808
+ function findPythonInstanceAttributeWithinClass(locals, member, container, targetContext, normalizeIdentifier) {
809
+ const containerStart = container.startIndex;
810
+ const containerEnd = container.endIndex;
811
+ const normalizedMember = normalizeIdentifier(member);
812
+ for (const local of locals) {
813
+ const startIndex = local.range.start.index;
814
+ const endIndex = local.range.end.index;
815
+ if (normalizeIdentifier(local.localName) !== normalizedMember ||
816
+ startIndex === undefined ||
817
+ endIndex === undefined ||
818
+ startIndex < containerStart ||
819
+ endIndex > containerEnd) {
820
+ continue;
821
+ }
822
+ const start = local.range.start;
823
+ const position = {
824
+ row: start.line - 1,
825
+ column: start.column - 1,
826
+ };
827
+ const nameNode = targetContext.tree.rootNode.descendantForPosition(position, position);
828
+ if (isPythonReceiverAttributeAssignmentName(nameNode))
829
+ return local;
830
+ }
831
+ return undefined;
832
+ }
833
+ function pythonBaseIdentifierNodes(classNode) {
834
+ const bases = classNode.childForFieldName("superclasses") ??
835
+ (classNode.namedChildren ?? []).find((child) => child.type === "argument_list");
836
+ if (!bases)
837
+ return [];
838
+ const names = [];
839
+ const visit = (node) => {
840
+ if (node.type === "keyword_argument" || node.type === "dictionary_splat" || node.type === "list_splat") {
841
+ return;
842
+ }
843
+ if (node.type === "identifier") {
844
+ names.push(node);
845
+ return;
846
+ }
847
+ if (node.type === "subscript") {
848
+ const value = node.childForFieldName("value");
849
+ if (value)
850
+ visit(value);
851
+ return;
852
+ }
853
+ for (const child of node.namedChildren)
854
+ visit(child);
855
+ };
856
+ visit(bases);
857
+ return names;
858
+ }
859
+ function resolvePythonNamedClass(index, mod, name) {
860
+ const classes = mod.locals.filter((local) => local.kind === SymbolKind.Class && local.localName === name);
861
+ const topLevel = classes.filter((local) => !local.isMember);
862
+ const candidates = topLevel.length ? topLevel : classes;
863
+ if (candidates.length === 1)
864
+ return candidates[0];
865
+ if (candidates.length > 1)
866
+ return undefined;
867
+ for (const imp of mod.imports) {
868
+ if (imp.kind === "named" && imp.local === name) {
869
+ const result = resolveImported(index, imp, imp.imported);
870
+ if (result && !("namespace" in result) && result.kind === SymbolKind.Class)
871
+ return result;
872
+ }
873
+ if (imp.kind === "star") {
874
+ const result = resolveImported(index, imp, name);
875
+ if (result && !("namespace" in result) && result.kind === SymbolKind.Class)
876
+ return result;
877
+ }
878
+ }
879
+ const exported = resolveExport(index, mod.file, name, { preferredKind: SymbolKind.Class, allowLocalFallback: false });
880
+ if (exported?.kind === "resolved" && exported.def.kind === SymbolKind.Class)
881
+ return exported.def;
882
+ return undefined;
883
+ }
884
+ async function pythonBaseClassRefs(index, classRef) {
885
+ const names = pythonBaseIdentifierNodes(classRef.container);
886
+ const refs = [];
887
+ const seen = new Set();
888
+ for (const nameNode of names) {
889
+ const def = resolvePythonNamedClass(index, classRef.module, sliceText(nameNode, classRef.context.source));
890
+ if (!def)
891
+ continue;
892
+ const key = pythonClassKey(def);
893
+ if (seen.has(key))
894
+ continue;
895
+ seen.add(key);
896
+ const ref = await pythonClassRefFromDef(index, def);
897
+ if (ref)
898
+ refs.push(ref);
899
+ }
900
+ return refs;
901
+ }
902
+ async function lookupPythonClassMember(index, start, member) {
903
+ const own = pythonMembersOnClass(start, member);
904
+ if (own.length === 1)
905
+ return own[0];
906
+ if (own.length > 1)
907
+ return undefined;
908
+ let level = await pythonBaseClassRefs(index, start);
909
+ const visited = new Set([pythonClassKey(start.def), ...level.map((base) => pythonClassKey(base.def))]);
910
+ for (let depth = 0; depth < PYTHON_SUPERTYPE_DEPTH && level.length; depth += 1) {
911
+ const matches = [];
912
+ const seenMatch = new Set();
913
+ for (const base of level) {
914
+ for (const hit of pythonMembersOnClass(base, member)) {
915
+ const key = pythonClassKey(hit);
916
+ if (seenMatch.has(key))
917
+ continue;
918
+ seenMatch.add(key);
919
+ matches.push(hit);
920
+ }
921
+ }
922
+ if (matches.length === 1)
923
+ return matches[0];
924
+ if (matches.length > 1)
925
+ return undefined;
926
+ const next = [];
927
+ for (const base of level) {
928
+ for (const parent of await pythonBaseClassRefs(index, base)) {
929
+ const key = pythonClassKey(parent.def);
930
+ if (visited.has(key))
931
+ continue;
932
+ visited.add(key);
933
+ next.push(parent);
934
+ }
935
+ }
936
+ level = next;
937
+ }
938
+ return undefined;
939
+ }
560
940
  function escapeRegExp(value) {
561
941
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
562
942
  }