ucn 5.5.1 → 5.5.3
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.
- package/.claude/skills/ucn/SKILL.md +35 -9
- package/.claude/skills/ucn/references/commands.md +40 -18
- package/.claude/skills/ucn/references/resolution-rules.md +126 -20
- package/.claude/skills/ucn/references/trust-contract.md +5 -3
- package/README.md +32 -21
- package/cli/index.js +2 -1
- package/core/accessors.js +341 -54
- package/core/account.js +74 -20
- package/core/analysis.js +257 -125
- package/core/ast-analysis.js +12 -3
- package/core/bridge.js +15 -65
- package/core/brief.js +8 -4
- package/core/build-worker.js +2 -1
- package/core/cache.js +137 -6
- package/core/call-name-cache.js +134 -0
- package/core/callable-scope.js +21 -0
- package/core/callers.js +4726 -940
- package/core/check.js +22 -5
- package/core/class-identity.js +399 -12
- package/core/client-receivers.js +189 -0
- package/core/constructor-calls.js +831 -0
- package/core/constructor-hierarchy.js +147 -0
- package/core/constructor-protocol.js +196 -0
- package/core/contract-membership.js +346 -140
- package/core/cpp-conversion-constraints.js +123 -0
- package/core/cpp-conversion-syntax.js +216 -0
- package/core/cpp-conversions.js +414 -0
- package/core/cpp-scope.js +245 -44
- package/core/deadcode.js +61 -16
- package/core/decorator-binding.js +137 -3
- package/core/enum-reference-syntax.js +134 -0
- package/core/execute.js +17 -1
- package/core/external-macros.js +42 -10
- package/core/go-packages.js +171 -0
- package/core/graph-build.js +2 -0
- package/core/graph.js +75 -59
- package/core/ignore-rules.js +2 -1
- package/core/imports.js +145 -19
- package/core/index-ir.js +41 -4
- package/core/inprocess-clients.js +41 -15
- package/core/ir.js +27 -6
- package/core/macro-expansion.js +38 -2
- package/core/out-of-class-members.js +182 -0
- package/core/output/analysis-ext.js +4 -2
- package/core/output/analysis.js +89 -20
- package/core/output/graph.js +12 -3
- package/core/output/lines.js +4 -3
- package/core/output/public.js +2 -0
- package/core/output/reporting.js +12 -1
- package/core/output/shared.js +2 -0
- package/core/output/tracing.js +28 -22
- package/core/output-budget.js +2 -2
- package/core/parallel-build.js +52 -1
- package/core/project.js +217 -112
- package/core/provenance-constructor-base.js +161 -0
- package/core/provenance-facts.js +257 -27
- package/core/provenance-overload.js +458 -54
- package/core/provenance-type.js +487 -0
- package/core/provenance.js +234 -15
- package/core/public-command.js +17 -2
- package/core/query-bodies.js +159 -0
- package/core/reflection.js +270 -2
- package/core/rename-token-syntax.js +111 -0
- package/core/reporting.js +13 -7
- package/core/request-helpers.js +63 -7
- package/core/rust-macro-expansion.js +151 -19
- package/core/rust-modules.js +1 -1
- package/core/rust-names.js +607 -0
- package/core/search.js +70 -17
- package/core/shared.js +98 -1
- package/core/source-memo.js +201 -0
- package/core/text-usage-syntax.js +38 -0
- package/core/tracing.js +7 -1
- package/core/type-denotation.js +124 -37
- package/core/type-references.js +615 -246
- package/core/value-references.js +2777 -0
- package/core/verify.js +1097 -281
- package/languages/adapter.js +28 -4
- package/languages/c-family.js +1118 -164
- package/languages/constructor-bases.js +105 -0
- package/languages/cpp-platform.js +26 -0
- package/languages/cpp-site-syntax.js +83 -0
- package/languages/csharp-scope.js +439 -0
- package/languages/csharp.js +428 -68
- package/languages/go.js +385 -207
- package/languages/html.js +4 -2
- package/languages/index.js +397 -2
- package/languages/java-platform.js +226 -0
- package/languages/java-unicode.js +269 -0
- package/languages/java.js +461 -117
- package/languages/javascript.js +418 -66
- package/languages/lexical-scope.js +190 -23
- package/languages/python.js +404 -54
- package/languages/rust.js +510 -82
- package/languages/utils.js +67 -8
- package/mcp/server.js +8 -2
- package/package.json +3 -3
package/core/type-denotation.js
CHANGED
|
@@ -45,6 +45,7 @@ const fs = require('fs');
|
|
|
45
45
|
const path = require('path');
|
|
46
46
|
const { langTraits } = require('../languages');
|
|
47
47
|
const { findCargoRoot, findGoModule } = require('./imports');
|
|
48
|
+
const { projectFact, projectHas, fileSymbolFact } = require('./provenance-overload');
|
|
48
49
|
|
|
49
50
|
const TYPE_KINDS = new Set(['class', 'struct', 'interface', 'trait', 'enum', 'record', 'union']);
|
|
50
51
|
|
|
@@ -232,15 +233,20 @@ function projectNamespaces(index, language) {
|
|
|
232
233
|
});
|
|
233
234
|
}
|
|
234
235
|
|
|
236
|
+
/** Does the project declare namespace/package `name`? A witness records
|
|
237
|
+
* the answer, never every file the inventory reads (fix #418). */
|
|
238
|
+
function projectNamespaceDeclared(index, language, name) {
|
|
239
|
+
return projectHas(index, `namespaces:${language}`, name, live => projectNamespaces(live, language));
|
|
240
|
+
}
|
|
241
|
+
|
|
235
242
|
/** Is some leading dotted prefix of `qualified` (the full path excluded) a
|
|
236
243
|
* namespace/package the project declares? `org.junit.Assert` is project
|
|
237
244
|
* code when `org.junit` is a project package; nested types keep their
|
|
238
245
|
* package prefix (`a.b.Outer.Inner`). */
|
|
239
246
|
function hasProjectNamespacePrefix(index, language, qualified) {
|
|
240
|
-
const names = projectNamespaces(index, language);
|
|
241
247
|
const segments = String(qualified).split('.');
|
|
242
248
|
for (let i = segments.length - 1; i > 0; i--) {
|
|
243
|
-
if (
|
|
249
|
+
if (projectNamespaceDeclared(index, language, segments.slice(0, i).join('.'))) return true;
|
|
244
250
|
}
|
|
245
251
|
return false;
|
|
246
252
|
}
|
|
@@ -363,7 +369,10 @@ function externalTypeDenotation(index, filePath, name, qualifier, line, options
|
|
|
363
369
|
// `unscoped`: the site's spelling of the name is unknown (the parser kept
|
|
364
370
|
// only the last segment), so package/namespace scoping cannot apply.
|
|
365
371
|
const unscoped = options.unscoped === true;
|
|
366
|
-
|
|
372
|
+
// Java/C# scoping reads the site's package or namespace (fix #433): a
|
|
373
|
+
// C# file with several namespace blocks decides a name per block.
|
|
374
|
+
const siteScope = !qualifier && !unscoped ? scopingSiteKey(index, filePath, line) : '';
|
|
375
|
+
const key = `${filePath}\x00${name}\x00${qualifier || ''}\x00${scoped ?? ''}\x00${unscoped ? 1 : 0}\x00${siteScope}`;
|
|
367
376
|
return memoized(index, key, () => {
|
|
368
377
|
const fileEntry = index.files.get(filePath);
|
|
369
378
|
if (!fileEntry) return null;
|
|
@@ -465,7 +474,7 @@ function scopedTypeDenotation(index, fileEntry, filePath, name, line, scoping) {
|
|
|
465
474
|
}
|
|
466
475
|
if (implicitHas) return { original: name, via: `${implicit.module}.${name}` };
|
|
467
476
|
const external = onDemand.filter(module => !hasProjectNamespacePrefix(index, language, `${module}.${name}`) &&
|
|
468
|
-
!
|
|
477
|
+
!projectNamespaceDeclared(index, language, module));
|
|
469
478
|
if (external.length === 0) return null;
|
|
470
479
|
return { original: name, via: `${external[0]}.*`,
|
|
471
480
|
...(!external.every(module => standardRooted(language, module)) && { certain: false }) };
|
|
@@ -485,10 +494,26 @@ function scopedTypeDenotation(index, fileEntry, filePath, name, line, scoping) {
|
|
|
485
494
|
// `using static T` also brings T's nested types (already abstained above).
|
|
486
495
|
const usings = new Set([...scope.namespaces, ...scope.statics]);
|
|
487
496
|
if (projectTypes.some(definition => usings.has(definition.namespace))) return null;
|
|
488
|
-
const external = [...usings].filter(module =>
|
|
497
|
+
const external = [...usings].filter(module =>
|
|
498
|
+
!projectHas(index, 'cs-declared-namespaces', module, live => csharpDeclaredNames(live).namespaces));
|
|
489
499
|
return { original: name, via: external.length > 0 ? `${external.sort()[0]}.${name}` : name };
|
|
490
500
|
}
|
|
491
501
|
|
|
502
|
+
/** What `scopedTypeDenotation` reads of the site: its package/namespace
|
|
503
|
+
* (`siteNamespaceOf`), constant for a file whose types share one namespace;
|
|
504
|
+
* '' for a language without type-name scoping. */
|
|
505
|
+
function scopingSiteKey(index, filePath, line) {
|
|
506
|
+
const fileEntry = index.files.get(filePath);
|
|
507
|
+
if (!fileEntry || !langTraits(fileEntry.language)?.typeNameScoping) return '';
|
|
508
|
+
const namespaces = memoized(index, `\x01site-ns\x00${filePath}`, () => new Set(
|
|
509
|
+
fileSymbolFact(index, filePath, `file-type-namespaces\0${filePath}`, (symbols, live) => symbols
|
|
510
|
+
? memoized(live, `\x01site-ns-facts\x00${filePath}`, () => symbols
|
|
511
|
+
.filter(symbol => TYPE_KINDS.has(symbol.type)).map(symbol => symbol.namespace || '')) : [])));
|
|
512
|
+
if (namespaces.size <= 1) return '\x01';
|
|
513
|
+
const namespace = siteNamespaceOf(fileEntry, line);
|
|
514
|
+
return namespace === undefined ? '\x02' : `\x03${namespace}`;
|
|
515
|
+
}
|
|
516
|
+
|
|
492
517
|
/** Could a project type named `name` be the type `fqn` names? Only a type
|
|
493
518
|
* in a named package/namespace that prefixes it (nested types included). */
|
|
494
519
|
function fqnMayName(index, language, name, fqn) {
|
|
@@ -551,10 +576,12 @@ function csharpResolveUsingName(index, written, enclosing) {
|
|
|
551
576
|
const text = String(written || '').replace(/\s+/g, '').replace(/^global::/, '');
|
|
552
577
|
if (!enclosing || !text) return text;
|
|
553
578
|
const first = text.split('.')[0].replace(/<.*$/s, '');
|
|
554
|
-
const { namespaces, types } = csharpDeclaredNames(index);
|
|
555
579
|
for (let parts = String(enclosing).split('.'); parts.length > 0; parts = parts.slice(0, -1)) {
|
|
556
580
|
const candidate = `${parts.join('.')}.${first}`;
|
|
557
|
-
if (
|
|
581
|
+
if (projectHas(index, 'cs-declared-namespaces', candidate, live => csharpDeclaredNames(live).namespaces) ||
|
|
582
|
+
projectHas(index, 'cs-declared-types', candidate, live => csharpDeclaredNames(live).types)) {
|
|
583
|
+
return `${parts.join('.')}.${text}`;
|
|
584
|
+
}
|
|
558
585
|
}
|
|
559
586
|
return text;
|
|
560
587
|
}
|
|
@@ -584,17 +611,36 @@ function csharpUsingTarget(text) {
|
|
|
584
611
|
return String(text || '').replace(/<.*$/s, '');
|
|
585
612
|
}
|
|
586
613
|
|
|
587
|
-
function csharpAddDirective(scope, index, { module, names, static: isStatic, namespace }) {
|
|
588
|
-
const
|
|
614
|
+
function csharpAddDirective(scope, index, { module, names, static: isStatic, namespace, lexicalNamespace = namespace, rooted = false }) {
|
|
615
|
+
const syntax = csharpResolveUsingName(index, module,
|
|
616
|
+
rooted || String(module || '').startsWith('global::') ? '' : namespace);
|
|
617
|
+
const target = csharpUsingTarget(syntax);
|
|
589
618
|
if (!target) return;
|
|
590
619
|
const alias = (names || []).find(name => name && name !== '*');
|
|
591
620
|
if (alias) {
|
|
621
|
+
const at = lexicalNamespace || '';
|
|
622
|
+
if (!scope.aliasDefinitions.has(alias)) scope.aliasDefinitions.set(alias, []);
|
|
623
|
+
scope.aliasDefinitions.get(alias).push({ namespace: at, syntax,
|
|
624
|
+
absolute: rooted || String(module || '').startsWith('global::') });
|
|
625
|
+
const previous = scope.aliasScopes?.get(alias);
|
|
626
|
+
// Project-file imports are added after source directives; that order
|
|
627
|
+
// cannot override a nearer namespace's alias.
|
|
628
|
+
if (scope.scoped && previous != null && previous.length > at.length) return;
|
|
629
|
+
if (scope.aliases.has(alias) && previous === at && scope.aliases.get(alias) !== target) {
|
|
630
|
+
scope.ambiguousAliases.add(alias);
|
|
631
|
+
} else if (previous !== at) scope.ambiguousAliases.delete(alias);
|
|
592
632
|
scope.aliases.set(alias, target);
|
|
633
|
+
scope.aliasSyntax.set(alias, syntax);
|
|
593
634
|
if (!scope.aliasScopes) scope.aliasScopes = new Map();
|
|
594
|
-
scope.aliasScopes.set(alias,
|
|
635
|
+
scope.aliasScopes.set(alias, at);
|
|
636
|
+
} else {
|
|
637
|
+
const values = isStatic ? scope.statics : scope.namespaces;
|
|
638
|
+
const origins = isStatic ? scope.staticScopes : scope.namespaceScopes;
|
|
639
|
+
values.add(target);
|
|
640
|
+
if (isStatic) scope.staticSyntax.set(target, syntax);
|
|
641
|
+
if (!origins.has(target)) origins.set(target, new Set());
|
|
642
|
+
origins.get(target).add(lexicalNamespace || '');
|
|
595
643
|
}
|
|
596
|
-
else if (isStatic) scope.statics.add(target);
|
|
597
|
-
else scope.namespaces.add(target);
|
|
598
644
|
}
|
|
599
645
|
|
|
600
646
|
/**
|
|
@@ -602,29 +648,53 @@ function csharpAddDirective(scope, index, { module, names, static: isStatic, nam
|
|
|
602
648
|
* directives (resolved from the namespace each is written in), `global
|
|
603
649
|
* using` directives of every source file, and the <Using> items of the
|
|
604
650
|
* project files above it (`csharpProjectFileUsings`).
|
|
605
|
-
*
|
|
606
|
-
*
|
|
651
|
+
* An optional namespace restricts local directives to that lexical chain;
|
|
652
|
+
* origins and original alias syntax support positive identity proofs.
|
|
653
|
+
* Returns namespaces/statics Sets, aliases and origin Maps, and unreadable.
|
|
654
|
+
* unreadable is true when a project file could not
|
|
607
655
|
* be read (its items are unknown).
|
|
608
656
|
*/
|
|
609
|
-
function csharpUsings(index, filePath) {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
657
|
+
function csharpUsings(index, filePath, namespace = null, siteNode = null, syntax = null) {
|
|
658
|
+
const scopes = syntax?.scopes || (siteNode ? require('../languages/csharp-scope').usingScopesOf(siteNode) : null);
|
|
659
|
+
const scopeKey = scopes?.map(scope => `${scope.startIndex}:${scope.endIndex}`).join(',') ?? '*';
|
|
660
|
+
return memoized(index, `\x01cs-usings\x00${filePath}\x00${namespace ?? '*'}\x00${scopeKey}`, () => {
|
|
661
|
+
const scope = { namespaces: new Set(), statics: new Set(), aliases: new Map(),
|
|
662
|
+
ambiguousAliases: new Set(), aliasSyntax: new Map(), aliasDefinitions: new Map(), scoped: namespace != null,
|
|
663
|
+
namespaceScopes: new Map(), staticScopes: new Map(), staticSyntax: new Map(), unreadable: false };
|
|
664
|
+
const globals = projectFact(index, 'cs-global-usings', live => memoized(live, '\x01cs-global-usings', () => {
|
|
613
665
|
const out = [];
|
|
614
|
-
for (const [, entry] of
|
|
666
|
+
for (const [, entry] of live.files) {
|
|
615
667
|
if (entry.language !== 'csharp') continue;
|
|
616
668
|
for (const detail of entry.importDetails || []) {
|
|
617
669
|
if (detail.global && detail.module) out.push(detail);
|
|
618
670
|
}
|
|
619
671
|
}
|
|
620
672
|
return out;
|
|
621
|
-
});
|
|
673
|
+
}));
|
|
622
674
|
for (const detail of globals) csharpAddDirective(scope, index, detail);
|
|
623
675
|
const fileEntry = index.files.get(filePath);
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
676
|
+
let local = fileEntry?.importDetails || [];
|
|
677
|
+
if (syntax) local = syntax.directives;
|
|
678
|
+
else if (scopes) {
|
|
679
|
+
const content = index._readFile(filePath);
|
|
680
|
+
const language = require('../languages');
|
|
681
|
+
const parser = language.getParser(fileEntry.language);
|
|
682
|
+
const adapter = language.getLanguageAdapter(fileEntry.language);
|
|
683
|
+
const tree = (index.isProvenanceFactIndex && siteNode.tree) ||
|
|
684
|
+
(require('./query-bodies').isLocalNameTree(siteNode.tree) && siteNode.tree) ||
|
|
685
|
+
index._getParsedTree(filePath, content, fileEntry.language) ||
|
|
686
|
+
adapter.queryTree(content, parser, fileEntry);
|
|
687
|
+
local = adapter.queryUsingDirectives(tree);
|
|
688
|
+
}
|
|
689
|
+
for (const detail of local) {
|
|
690
|
+
if (detail.type !== 'using' || !detail.module || detail.global) continue;
|
|
691
|
+
if (scopes) {
|
|
692
|
+
const owner = detail.usingScopes.at(-1);
|
|
693
|
+
if (owner && !scopes.some(current => current.startIndex === owner.startIndex &&
|
|
694
|
+
current.endIndex === owner.endIndex)) continue;
|
|
695
|
+
csharpAddDirective(scope, index, { ...detail, lexicalNamespace: owner?.namespace || '' });
|
|
696
|
+
} else if (namespace == null || !detail.namespace || namespace === detail.namespace ||
|
|
697
|
+
namespace.startsWith(detail.namespace + '.')) csharpAddDirective(scope, index, detail);
|
|
628
698
|
}
|
|
629
699
|
for (const item of csharpProjectFileUsings(index, filePath)) {
|
|
630
700
|
if (item === null) { scope.unreadable = true; continue; }
|
|
@@ -643,26 +713,41 @@ function csharpUsings(index, filePath) {
|
|
|
643
713
|
*/
|
|
644
714
|
function csharpExpandAliasTargets(scope) {
|
|
645
715
|
const scopes = scope.aliasScopes;
|
|
646
|
-
if (!scopes
|
|
716
|
+
if (!scopes) return;
|
|
647
717
|
const encloses = (outer, inner) => outer !== inner && (outer === '' || inner.startsWith(`${outer}.`));
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
718
|
+
const expand = (definition, seen = new Set()) => {
|
|
719
|
+
if (definition.absolute) return definition.syntax;
|
|
720
|
+
if (seen.has(definition) || seen.size >= 16) return null;
|
|
721
|
+
const [head, ...rest] = definition.syntax.split('.');
|
|
722
|
+
const outer = (scope.aliasDefinitions.get(head) || []).filter(other =>
|
|
723
|
+
encloses(other.namespace, definition.namespace));
|
|
724
|
+
if (!outer.length) return definition.syntax;
|
|
725
|
+
const nearest = Math.max(...outer.map(other => other.namespace.length));
|
|
726
|
+
const next = new Set(seen); next.add(definition);
|
|
727
|
+
const targets = new Set(outer.filter(other => other.namespace.length === nearest)
|
|
728
|
+
.map(other => expand(other, next)));
|
|
729
|
+
if (targets.has(null) || targets.size !== 1) return null;
|
|
730
|
+
return [[...targets][0], ...rest].join('.');
|
|
731
|
+
};
|
|
732
|
+
for (const [alias, at] of scopes) {
|
|
733
|
+
const definitions = (scope.aliasDefinitions.get(alias) || []).filter(definition => definition.namespace === at);
|
|
734
|
+
const targets = new Set(definitions.map(definition => expand(definition)));
|
|
735
|
+
if (targets.has(null) || targets.size !== 1) {
|
|
736
|
+
scope.ambiguousAliases.add(alias);
|
|
737
|
+
continue;
|
|
656
738
|
}
|
|
657
|
-
|
|
739
|
+
const syntax = [...targets][0];
|
|
740
|
+
scope.aliasSyntax.set(alias, syntax);
|
|
741
|
+
scope.aliases.set(alias, csharpUsingTarget(syntax));
|
|
658
742
|
}
|
|
659
743
|
}
|
|
660
744
|
|
|
661
745
|
/** The directory whose `.git` marks the repository holding `dir`, or null. */
|
|
662
746
|
function gitTopOf(index, dir) {
|
|
663
747
|
return memoized(index, `\x01git-top\x00${dir}`, () => {
|
|
748
|
+
const sourceFs = index.isProvenanceFactIndex ? index.provenanceFs : fs;
|
|
664
749
|
for (let current = dir; ; current = path.dirname(current)) {
|
|
665
|
-
try { if (
|
|
750
|
+
try { if (sourceFs.existsSync(path.join(current, '.git'))) return current; } catch { /* keep walking */ }
|
|
666
751
|
if (current === path.dirname(current)) return null;
|
|
667
752
|
}
|
|
668
753
|
});
|
|
@@ -679,6 +764,7 @@ function gitTopOf(index, dir) {
|
|
|
679
764
|
* null marks a file that could not be read.
|
|
680
765
|
*/
|
|
681
766
|
function csharpProjectFileUsings(index, filePath) {
|
|
767
|
+
const sourceFs = index.isProvenanceFactIndex ? index.provenanceFs : fs;
|
|
682
768
|
const dirs = [];
|
|
683
769
|
const root = path.resolve(index.root);
|
|
684
770
|
let dir = path.dirname(filePath);
|
|
@@ -697,12 +783,12 @@ function csharpProjectFileUsings(index, filePath) {
|
|
|
697
783
|
}
|
|
698
784
|
return dirs.flatMap(current => memoized(index, `\x01cs-proj-usings\x00${current}`, () => {
|
|
699
785
|
let names;
|
|
700
|
-
try { names =
|
|
786
|
+
try { names = sourceFs.readdirSync(current); } catch { return []; }
|
|
701
787
|
const out = [];
|
|
702
788
|
for (const file of names.sort()) {
|
|
703
789
|
if (!/\.csproj$|^Directory\.Build\.(props|targets)$/.test(file)) continue;
|
|
704
790
|
let text;
|
|
705
|
-
try { text =
|
|
791
|
+
try { text = sourceFs.readFileSync(path.join(current, file), 'utf-8'); } catch { out.push(null); continue; }
|
|
706
792
|
for (const match of text.matchAll(/<Using\b([^>]*)>/g)) {
|
|
707
793
|
const include = /\bInclude\s*=\s*"([^"]+)"/.exec(match[1]);
|
|
708
794
|
if (!include) continue;
|
|
@@ -1167,6 +1253,7 @@ function stripExternalReceiverType(call, via) {
|
|
|
1167
1253
|
}
|
|
1168
1254
|
|
|
1169
1255
|
module.exports = {
|
|
1256
|
+
memoizedDerivation: memoized,
|
|
1170
1257
|
externalTypeDenotation,
|
|
1171
1258
|
externalReceiverVerdict,
|
|
1172
1259
|
externalProducerVia,
|