ucn 5.5.0 → 5.5.2

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 (93) hide show
  1. package/.claude/skills/ucn/SKILL.md +35 -9
  2. package/.claude/skills/ucn/references/commands.md +38 -16
  3. package/.claude/skills/ucn/references/resolution-rules.md +126 -20
  4. package/.claude/skills/ucn/references/trust-contract.md +5 -3
  5. package/README.md +41 -27
  6. package/cli/index.js +6 -1
  7. package/core/accessors.js +341 -54
  8. package/core/account.js +106 -31
  9. package/core/analysis.js +266 -127
  10. package/core/ast-analysis.js +12 -3
  11. package/core/brief.js +8 -4
  12. package/core/build-worker.js +2 -1
  13. package/core/cache.js +144 -6
  14. package/core/call-name-cache.js +134 -0
  15. package/core/callable-scope.js +21 -0
  16. package/core/callers.js +5111 -1024
  17. package/core/check.js +22 -5
  18. package/core/class-identity.js +399 -12
  19. package/core/constructor-calls.js +831 -0
  20. package/core/constructor-hierarchy.js +147 -0
  21. package/core/constructor-protocol.js +196 -0
  22. package/core/contract-membership.js +346 -140
  23. package/core/cpp-conversion-constraints.js +123 -0
  24. package/core/cpp-conversion-syntax.js +216 -0
  25. package/core/cpp-conversions.js +414 -0
  26. package/core/cpp-scope.js +245 -44
  27. package/core/deadcode.js +35 -15
  28. package/core/decorator-binding.js +137 -3
  29. package/core/enum-reference-syntax.js +134 -0
  30. package/core/execute.js +17 -1
  31. package/core/external-macros.js +42 -10
  32. package/core/go-packages.js +171 -0
  33. package/core/graph-build.js +2 -0
  34. package/core/graph.js +75 -59
  35. package/core/ignore-rules.js +2 -1
  36. package/core/imports.js +145 -19
  37. package/core/index-ir.js +41 -4
  38. package/core/ir.js +27 -6
  39. package/core/macro-expansion.js +38 -2
  40. package/core/out-of-class-members.js +182 -0
  41. package/core/output/analysis-ext.js +4 -2
  42. package/core/output/analysis.js +89 -20
  43. package/core/output/graph.js +12 -3
  44. package/core/output/lines.js +4 -3
  45. package/core/output/public.js +1 -0
  46. package/core/output/reporting.js +6 -1
  47. package/core/output/shared.js +2 -0
  48. package/core/output/tracing.js +28 -22
  49. package/core/output-budget.js +2 -2
  50. package/core/parallel-build.js +52 -1
  51. package/core/project.js +228 -114
  52. package/core/provenance-constructor-base.js +161 -0
  53. package/core/provenance-facts.js +257 -27
  54. package/core/provenance-overload.js +458 -54
  55. package/core/provenance-type.js +487 -0
  56. package/core/provenance.js +234 -15
  57. package/core/public-command.js +17 -2
  58. package/core/query-bodies.js +159 -0
  59. package/core/reflection.js +255 -2
  60. package/core/rename-token-syntax.js +111 -0
  61. package/core/reporting.js +13 -7
  62. package/core/rust-macro-expansion.js +1202 -157
  63. package/core/rust-modules.js +21 -3
  64. package/core/rust-names.js +607 -0
  65. package/core/search.js +70 -17
  66. package/core/shared.js +98 -1
  67. package/core/source-memo.js +201 -0
  68. package/core/text-usage-syntax.js +38 -0
  69. package/core/tracing.js +7 -1
  70. package/core/type-denotation.js +157 -46
  71. package/core/type-references.js +615 -246
  72. package/core/value-references.js +2777 -0
  73. package/core/verify.js +1097 -281
  74. package/languages/adapter.js +28 -4
  75. package/languages/c-family.js +1118 -164
  76. package/languages/constructor-bases.js +105 -0
  77. package/languages/cpp-platform.js +26 -0
  78. package/languages/cpp-site-syntax.js +83 -0
  79. package/languages/csharp-scope.js +439 -0
  80. package/languages/csharp.js +428 -68
  81. package/languages/go.js +385 -207
  82. package/languages/html.js +4 -2
  83. package/languages/index.js +397 -2
  84. package/languages/java-platform.js +226 -0
  85. package/languages/java-unicode.js +269 -0
  86. package/languages/java.js +461 -117
  87. package/languages/javascript.js +418 -66
  88. package/languages/lexical-scope.js +190 -23
  89. package/languages/python.js +404 -54
  90. package/languages/rust.js +548 -89
  91. package/languages/utils.js +67 -8
  92. package/mcp/server.js +8 -2
  93. package/package.json +2 -2
@@ -291,13 +291,26 @@ function pyScopeBindings(scopeNode, body, name, isFunction, includeClasses = fal
291
291
  }
292
292
  }
293
293
 
294
- function pyVerdict(info) {
294
+ function pyVerdict(info, scopeNode) {
295
295
  if (info.import || info.starImport) return 'unknown';
296
- if (info.other) return { local: true, defRows: null };
297
- return { local: true, defRows: info.defRows.slice() };
296
+ if (info.other) return withScopeNode({ local: true, defRows: null }, scopeNode);
297
+ return withScopeNode({ local: true, defRows: info.defRows.slice() }, scopeNode);
298
298
  }
299
299
 
300
- function pythonReferenceScope(node, name, memo, includeClasses) {
300
+ /** A local verdict names its binding scope node only when asked for. */
301
+ function withScopeNode(verdict, scopeNode) {
302
+ if (scopeNode) Object.defineProperty(verdict, 'scopeNode', { value: scopeNode, enumerable: false });
303
+ return verdict;
304
+ }
305
+
306
+ /**
307
+ * `globalBindsModule` (fix #420): a name a function declares `global` is the
308
+ * module variable there, assigned or not. Callable resolution keeps 'unknown'
309
+ * for an assigned global (the binding the call reaches changes at run time);
310
+ * a value reference names the variable itself.
311
+ */
312
+ function pythonReferenceScope(node, name, memo, includeClasses, globalBindsModule = false) {
313
+ const local = scope => (globalBindsModule ? scope : null);
301
314
  const parent = node.parent;
302
315
  if (!parent) return 'unknown';
303
316
  if (parent.type === 'keyword_argument' && sameNode(parent.childForFieldName('name'), node)) return 'none';
@@ -316,6 +329,7 @@ function pythonReferenceScope(node, name, memo, includeClasses) {
316
329
  if (info.global) {
317
330
  // A function that assigns a `global` name rebinds the module
318
331
  // binding at run time.
332
+ if (globalBindsModule) return 'module';
319
333
  return info.other || info.defRows.length > 0 || info.import ? 'unknown' : 'module';
320
334
  }
321
335
  if (info.nonlocal) {
@@ -323,7 +337,7 @@ function pythonReferenceScope(node, name, memo, includeClasses) {
323
337
  crossedFunction = true;
324
338
  continue;
325
339
  }
326
- if (info.bound) return pyVerdict(info);
340
+ if (info.bound) return pyVerdict(info, local(scope));
327
341
  crossedFunction = true;
328
342
  continue;
329
343
  }
@@ -331,7 +345,7 @@ function pythonReferenceScope(node, name, memo, includeClasses) {
331
345
  if (!sameNode(scope.childForFieldName('body'), child)) continue;
332
346
  const names = [];
333
347
  pyParameterNames(scope.childForFieldName('parameters'), names);
334
- if (names.some(n => n.text === name)) return { local: true, defRows: null };
348
+ if (names.some(n => n.text === name)) return withScopeNode({ local: true, defRows: null }, local(scope));
335
349
  crossedFunction = true;
336
350
  continue;
337
351
  }
@@ -354,7 +368,7 @@ function pythonReferenceScope(node, name, memo, includeClasses) {
354
368
  for (const clause of clauses) {
355
369
  const names = [];
356
370
  pyTargetNames(clause.childForFieldName('left'), names);
357
- if (names.some(n => n.text === name)) return { local: true, defRows: null };
371
+ if (names.some(n => n.text === name)) return withScopeNode({ local: true, defRows: null }, local(scope));
358
372
  }
359
373
  crossedFunction = true;
360
374
  continue;
@@ -372,7 +386,9 @@ function pythonReferenceScope(node, name, memo, includeClasses) {
372
386
 
373
387
  const JS_FUNCTIONS = new Set(['function_declaration', 'function_expression', 'function',
374
388
  'arrow_function', 'method_definition', 'generator_function',
375
- 'generator_function_declaration']);
389
+ 'generator_function_declaration', 'function_signature', 'function_type',
390
+ 'constructor_type', 'call_signature', 'construct_signature', 'method_signature',
391
+ 'abstract_method_signature']);
376
392
  const JS_BLOCKS = new Set(['statement_block', 'switch_body', 'class_static_block', 'program']);
377
393
 
378
394
  function jsPatternNames(pattern, out) {
@@ -537,12 +553,50 @@ function jsVerdict(info) {
537
553
  return { local: true, defRows: info.defRows.slice() };
538
554
  }
539
555
 
556
+ /**
557
+ * What a destructuring pattern's target name does (fix #431): 'declaration'
558
+ * (a declarator, parameter, catch or `for (const [a] of ..)` pattern binds
559
+ * it), 'assignment' (`[a, b] = f()`, `({ a } = o)`, `for ([a] of ..)` write
560
+ * the binding in scope) or null (a default value or key, not a target).
561
+ */
562
+ function jsPatternTarget(node) {
563
+ let current = node;
564
+ for (let parent = node.parent; parent; current = parent, parent = parent.parent) {
565
+ switch (parent.type) {
566
+ case 'array_pattern': case 'object_pattern': case 'rest_pattern':
567
+ continue;
568
+ case 'pair_pattern':
569
+ if (fieldIs(current, 'value')) continue;
570
+ return null;
571
+ case 'assignment_pattern': case 'object_assignment_pattern':
572
+ if (fieldIs(current, 'left')) continue;
573
+ return null;
574
+ case 'assignment_expression':
575
+ return current !== node && fieldIs(current, 'left') ? 'assignment' : null;
576
+ case 'for_in_statement':
577
+ if (current === node || !fieldIs(current, 'left')) return null;
578
+ return parent.childForFieldName('kind') ? 'declaration' : 'assignment';
579
+ case 'parenthesized_expression':
580
+ return null;
581
+ default:
582
+ return current === node ? null : 'declaration';
583
+ }
584
+ }
585
+ return null;
586
+ }
587
+
588
+ function fieldIs(node, field) {
589
+ const child = node.parent?.childForFieldName(field);
590
+ return !!child && sameNode(child, node);
591
+ }
592
+
540
593
  function jsReferenceScope(node, name, memo, includeClasses) {
541
- if (node.type !== 'identifier' && node.type !== 'shorthand_property_identifier') {
594
+ if (node.type !== 'identifier' && node.type !== 'shorthand_property_identifier' &&
595
+ !(node.type === 'shorthand_property_identifier_pattern' && jsPatternTarget(node) === 'assignment')) {
542
596
  // Keys, member properties and type names are not variable
543
597
  // references. Object shorthand `{ name }` is both key and value:
544
598
  // its value resolves like an identifier (fix #397; the rename keeps
545
- // the key).
599
+ // the key), as `({ name } = o)` writes it (fix #431).
546
600
  return 'none';
547
601
  }
548
602
  const parent = node.parent;
@@ -668,8 +722,27 @@ function goParamNames(list, out) {
668
722
  }
669
723
  }
670
724
 
725
+ /** A Go qualified type that is a type argument of an instantiation written
726
+ * in an expression: `x[a.b]` parses as one, though `a` may be a value whose
727
+ * field `b` indexes `x` (fix #431). */
728
+ function goExpressionTypeArgument(qualifiedType) {
729
+ let current = qualifiedType?.parent;
730
+ // `h.funcs[i](n)` reads as a conversion to the generic type `h.funcs[i]`
731
+ // (fix #434): its base is a selector when `h` is a value.
732
+ if (current?.type === 'generic_type' && sameNode(current.childForFieldName('type'), qualifiedType) &&
733
+ current.parent?.type === 'type_conversion_expression' &&
734
+ sameNode(current.parent.childForFieldName('type'), current)) return true;
735
+ if (current?.type === 'type_elem') current = current.parent;
736
+ if (current?.type !== 'type_arguments') return false;
737
+ current = current.parent;
738
+ if (current?.type === 'generic_type') current = current.parent;
739
+ return current?.type === 'type_instantiation_expression';
740
+ }
741
+
671
742
  function goReferenceScope(node, name) {
672
- if (node.type !== 'identifier') return 'none';
743
+ // The package of an expression type argument may be a value (fix #431).
744
+ if (node.type !== 'identifier' && !(node.type === 'package_identifier' &&
745
+ node.parent?.type === 'qualified_type' && goExpressionTypeArgument(node.parent))) return 'none';
673
746
  const parent = node.parent;
674
747
  if (!parent) return 'unknown';
675
748
  // `T{field: v}`: a struct field name or a map key, undecidable here.
@@ -854,14 +927,44 @@ function cDeclarationBinds(statement, name) {
854
927
  return verdict;
855
928
  }
856
929
 
857
- function cReferenceScope(node, name) {
930
+ function cBlockBinding(scope, name, start, memo) {
931
+ let trees = memo.get('c-block-bindings');
932
+ if (!trees) { trees = new WeakMap(); memo.set('c-block-bindings', trees); }
933
+ let blocks = trees.get(scope.tree);
934
+ if (!blocks) { blocks = new Map(); trees.set(scope.tree, blocks); }
935
+ let block = blocks.get(scope.id);
936
+ if (!block) {
937
+ block = { statements: namedChildrenOf(scope), names: new Map() };
938
+ blocks.set(scope.id, block);
939
+ }
940
+ let state = block.names.get(name);
941
+ if (!state) { state = { next: 0, bindings: [] }; block.names.set(name, state); }
942
+ // Extend only through the requested position. Earlier queries can use
943
+ // this prefix too, without seeing any later declaration.
944
+ while (state.next < block.statements.length) {
945
+ const statement = block.statements[state.next];
946
+ if (statement.startIndex >= start) break;
947
+ const verdict = cDeclarationBinds(statement, name);
948
+ if (verdict) state.bindings.push([statement.startIndex, verdict]);
949
+ state.next++;
950
+ }
951
+ let lo = 0, hi = state.bindings.length;
952
+ while (lo < hi) {
953
+ const mid = (lo + hi) >> 1;
954
+ if (state.bindings[mid][0] < start) lo = mid + 1;
955
+ else hi = mid;
956
+ }
957
+ return lo ? state.bindings[lo - 1][1] : null;
958
+ }
959
+
960
+ function cReferenceScope(node, name, memo) {
858
961
  if (node.type !== 'identifier') return 'none';
859
962
  const parent = node.parent;
860
963
  if (!parent) return 'unknown';
861
964
  // The declared name of a variable or parameter is a binding, never a
862
965
  // reference to a function of the same spelling.
863
- for (let up = parent, child = node; up && C_DECLARATOR_WRAPPERS.has(up.type); child = up, up = up.parent) {
864
- if (up.type === 'init_declarator' && !sameNode(up.childForFieldName('declarator'), child)) break;
966
+ for (let up = parent; up && C_DECLARATOR_WRAPPERS.has(up.type); up = up.parent) {
967
+ if (!sameNode(cDeclaratorName(up)?.node, node)) break;
865
968
  const owner = up.parent;
866
969
  if (owner && (owner.type === 'declaration' || owner.type === 'parameter_declaration' ||
867
970
  owner.type === 'field_declaration')) return 'none';
@@ -876,12 +979,7 @@ function cReferenceScope(node, name) {
876
979
  case 'ERROR':
877
980
  return 'unknown';
878
981
  case 'compound_statement': {
879
- let bound = null;
880
- for (const statement of namedChildrenOf(scope)) {
881
- if (statement.startIndex >= start) break;
882
- const verdict = cDeclarationBinds(statement, name);
883
- if (verdict) bound = verdict;
884
- }
982
+ const bound = cBlockBinding(scope, name, start, memo);
885
983
  if (bound === 'function') return 'unknown';
886
984
  if (bound) return { local: true, defRows: null };
887
985
  continue;
@@ -1182,11 +1280,12 @@ function referenceScope(node, language, memo = new Map(), name = node?.text, opt
1182
1280
  memo = classMemo;
1183
1281
  }
1184
1282
  switch (family) {
1185
- case 'python': return pythonReferenceScope(node, name, memo, includeClasses);
1283
+ case 'python': return pythonReferenceScope(node, name, memo, includeClasses,
1284
+ options.globalBindsModule === true);
1186
1285
  case 'js': return jsReferenceScope(node, name, memo, includeClasses);
1187
1286
  case 'go': return goReferenceScope(node, name, memo);
1188
1287
  case 'rust': return rustReferenceScope(node, name, memo);
1189
- case 'c': return cReferenceScope(node, name);
1288
+ case 'c': return cReferenceScope(node, name, memo);
1190
1289
  default: return null;
1191
1290
  }
1192
1291
  } catch {
@@ -1269,6 +1368,23 @@ function referenceScopeNode(node, name, memo = new Map()) {
1269
1368
  return null;
1270
1369
  }
1271
1370
 
1371
+ /**
1372
+ * Every binding of `name` in the Python scope (module or function) that
1373
+ * holds `node` (fix #424), with its kind: 'def' (def and class
1374
+ * statements), 'binding' (assignment targets, parameters, captures) or
1375
+ * 'import'.
1376
+ */
1377
+ function pythonScopeBindingKinds(node, name) {
1378
+ let scope = node;
1379
+ while (scope && !['module', 'function_definition', 'class_definition'].includes(scope.type)) scope = scope.parent;
1380
+ if (!scope || scope.type === 'class_definition') return [];
1381
+ const sites = [];
1382
+ const isFunction = scope.type === 'function_definition';
1383
+ pyScopeBindings(scope, isFunction ? scope.childForFieldName('body') : scope, name, isFunction, true,
1384
+ (site, kind) => sites.push({ node: site, kind }));
1385
+ return sites;
1386
+ }
1387
+
1272
1388
  /** Declaration tokens binding one name in a Python function's own scope. */
1273
1389
  function pythonBindingSites(scope, name) {
1274
1390
  const sites = [];
@@ -1277,4 +1393,55 @@ function pythonBindingSites(scope, name) {
1277
1393
  return sites;
1278
1394
  }
1279
1395
 
1280
- module.exports = { referenceScope, referenceScopeNode, scopeFields, familyOf, rustLetBindingOf, rustSelfFieldBinding, pythonBindingSites };
1396
+ /**
1397
+ * Statement-order lookup of a name read directly in a Python class body
1398
+ * whose body also binds it (fix #420): a class body reads its namespace,
1399
+ * then the scope around the class, as it executes. 'outer' when every
1400
+ * binding of the name in the body runs after the read (`limit = limit`
1401
+ * reads the outer binding), 'class' when an unconditional earlier
1402
+ * statement of the body binds it, null when the order cannot settle it
1403
+ * (loops, conditional bindings, `global` in the body).
1404
+ */
1405
+ function pythonClassBodyOrder(classNode, node, name) {
1406
+ const body = classNode?.childForFieldName('body');
1407
+ if (!body) return null;
1408
+ const sites = [];
1409
+ const info = pyScopeBindings(classNode, body, name, false, false, site => sites.push(site));
1410
+ if (info.global || info.nonlocal || info.starImport || sites.length === 0) return null;
1411
+ const statementOf = site => {
1412
+ let current = site;
1413
+ while (current.parent && !sameNode(current.parent, body)) current = current.parent;
1414
+ return sameNode(current.parent, body) ? current : null;
1415
+ };
1416
+ const readStatement = statementOf(node);
1417
+ if (!readStatement) return null;
1418
+ for (let current = node.parent; current && !sameNode(current, body); current = current.parent) {
1419
+ if (['for_statement', 'while_statement'].includes(current.type)) return null;
1420
+ }
1421
+ let before = 0;
1422
+ for (const site of sites) {
1423
+ const statement = statementOf(site);
1424
+ if (!statement) return null;
1425
+ if (statement.startIndex > readStatement.startIndex) continue;
1426
+ if (sameNode(statement, readStatement)) {
1427
+ // `x = <reads x>`: the value is evaluated before the target binds.
1428
+ const assignment = statement.type === 'expression_statement' ? statement.namedChild(0) : statement;
1429
+ const left = assignment?.type === 'assignment' ? assignment.childForFieldName('left') : null;
1430
+ const right = assignment?.type === 'assignment' ? assignment.childForFieldName('right') : null;
1431
+ if (left && right && within(site, left) && within(node, right)) continue;
1432
+ // A decorator runs before the definition it decorates binds the
1433
+ // name (fix #431: `@plain.setter` reads the earlier `plain`).
1434
+ if (statement.type === 'decorated_definition' && statement.namedChildren.some(child =>
1435
+ child.type === 'decorator' && within(node, child)) && !statement.namedChildren.some(child =>
1436
+ child.type === 'decorator' && within(site, child))) continue;
1437
+ return null;
1438
+ }
1439
+ if (statement.type !== 'expression_statement' && statement.type !== 'function_definition' &&
1440
+ statement.type !== 'class_definition' && statement.type !== 'decorated_definition') return null;
1441
+ before++;
1442
+ }
1443
+ return before === 0 ? 'outer' : 'class';
1444
+ }
1445
+
1446
+ module.exports = { referenceScope, referenceScopeNode, scopeFields, familyOf, rustLetBindingOf, rustSelfFieldBinding,
1447
+ pythonBindingSites, pythonClassBodyOrder, pythonScopeBindingKinds, goExpressionTypeArgument, jsPatternTarget };