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
@@ -0,0 +1,414 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const scope = require('./cpp-scope');
5
+ const { sharedRead } = require('./provenance-overload');
6
+ const { standardStringType, CHARACTERS } = require('../languages/cpp-platform');
7
+ const { declarationSyntax, classSyntax } = require('./cpp-conversion-syntax');
8
+ const { sameDeclaration, declarationIdentity } = require('./provenance');
9
+
10
+ function substituteType(text, bindings) {
11
+ return String(text || '').replace(/\b[A-Za-z_]\w*\b/g, name => {
12
+ const bound = bindings?.get(name);
13
+ return typeof bound === 'string' ? bound : name;
14
+ });
15
+ }
16
+
17
+ function qualifiedParts(text) {
18
+ const parts = [];
19
+ let depth = 0, from = 0;
20
+ for (let i = 0; i < text.length; i++) {
21
+ if ('<(['.includes(text[i])) depth++;
22
+ else if ('>)]'.includes(text[i])) depth--;
23
+ else if (depth === 0 && text.slice(i, i + 2) === '::') {
24
+ parts.push(text.slice(from, i)); from = i + 2; i++;
25
+ }
26
+ }
27
+ parts.push(text.slice(from));
28
+ return parts;
29
+ }
30
+
31
+ function builtinType(text) {
32
+ const bare = typeText(text);
33
+ const pointer = /\*|\[/.test(scope.stripTemplateArguments(bare));
34
+ const base = bare.replace(/\*|\[[^\]]*\]/g, '').replace(/\(\s*\)/g, '').trim();
35
+ if (pointer) {
36
+ const levels = (bare.match(/\*|\[/g) || []).length;
37
+ return { kind: 'builtin', category: 'pointer', text, base, levels,
38
+ ...(levels === 1 && CHARACTERS.has(base) && { character: base }) };
39
+ }
40
+ if (CHARACTERS.has(base)) return { kind: 'builtin', category: 'arithmetic', text, base };
41
+ if (base === 'bool') return { kind: 'builtin', category: 'bool', text, base };
42
+ if (base === 'void') return { kind: 'builtin', category: 'void', text, base };
43
+ if (/^(?:(?:signed|unsigned)\s*)?(?:char|short|int|long(?:\s+long)?|float|double|long\s+double)?(?:\s+int)?$/.test(base) && base) {
44
+ return { kind: 'builtin', category: 'arithmetic', text, base };
45
+ }
46
+ if (base === 'std::nullptr_t' || base === 'decltype(nullptr)') return { kind: 'builtin', category: 'null', text, base };
47
+ return null;
48
+ }
49
+
50
+ function templateBindings(index, definition, arguments_, inherited, context, depth) {
51
+ const bindings = new Map(inherited || []);
52
+ if (!definition.templateParams && arguments_.length === 0) return bindings;
53
+ const syntax = declarationSyntax(index, definition);
54
+ let position = 0;
55
+ for (const param of syntax.template?.parameters || []) {
56
+ if (!param.name) continue;
57
+ if (param.variadic) {
58
+ bindings.set(param.name, null);
59
+ break;
60
+ }
61
+ const actual = arguments_[position++];
62
+ if (actual != null) {
63
+ const head = typeText(actual);
64
+ const bound = inherited?.get(head);
65
+ const text = substituteType(actual, inherited);
66
+ const isType = param.type.includes('type_parameter');
67
+ const resolved = isType && !builtinType(text) && !(bound && typeof bound === 'object')
68
+ ? resolveType(index, actual, context, inherited, depth + 1) : null;
69
+ bindings.set(param.name, bound && typeof bound === 'object' ? bound : resolved
70
+ ? resolved.kind === 'unknown' ? null : resolved : text);
71
+ }
72
+ else if (param.default != null) bindings.set(param.name, substituteType(param.default, bindings));
73
+ else if (!bindings.has(param.name)) bindings.set(param.name, null);
74
+ }
75
+ return bindings;
76
+ }
77
+
78
+ function resolvedDeclaration(index, definition, text, context, bindings, depth) {
79
+ const arguments_ = typeArguments(qualifiedParts(text).at(-1));
80
+ const own = templateBindings(index, definition, arguments_, bindings, context, depth);
81
+ if (definition.type === 'type') {
82
+ if (!definition.aliasOf) return { kind: 'unknown', text };
83
+ return resolveType(index, definition.aliasOf, contextOf(index, definition), own, depth + 1);
84
+ }
85
+ return { kind: definition.type === 'enum' ? 'enum' : 'project', definition, bindings: own, text,
86
+ context: contextOf(index, definition) };
87
+ }
88
+
89
+ function resolveType(index, spelling, context, bindings = new Map(), depth = 0) {
90
+ const key = `cpp-conversion-type:${JSON.stringify([spelling, context, [...bindings], depth], (_, value) => value instanceof Map ? [...value] : value)}`;
91
+ return sharedRead(index, key, view => resolveTypeUncached(view, spelling, context, bindings, depth));
92
+ }
93
+
94
+ function resolveTypeUncached(index, spelling, context, bindings, depth) {
95
+ const result = resolveTypeInner(index, spelling, context, bindings, depth);
96
+ const outside = scope.stripTemplateArguments(substituteType(spelling, bindings));
97
+ const qualifiers = new Set(result.qualifiers || []);
98
+ for (const qualifier of outside.match(/\b(?:const|volatile)\b|&&|&/g) || []) qualifiers.add(qualifier);
99
+ return { ...result, context: result.context || context, bindings: result.bindings || bindings,
100
+ qualifiers: [...qualifiers].sort() };
101
+ }
102
+
103
+ function resolveTypeInner(index, spelling, context, bindings, depth) {
104
+ if (!context || depth > 12) return { kind: 'unknown', text: spelling };
105
+ const original = typeText(spelling);
106
+ const first = qualifiedParts(original)[0]?.trim();
107
+ const bound = bindings.get(first);
108
+ if (bound && typeof bound === 'object') {
109
+ if (qualifiedParts(original).length === 1) return bound;
110
+ if (bound.kind === 'builtin') return { kind: 'invalid', text: spelling };
111
+ }
112
+ if (bindings.has(first) && bindings.get(first) === null || context.typeParameters?.includes(first) && !bindings.has(first)) {
113
+ return { kind: 'unknown', text: spelling };
114
+ }
115
+ if (qualifiedParts(original).length > 1 && typeof bound === 'string' && builtinType(bound)) {
116
+ return { kind: 'invalid', text: spelling };
117
+ }
118
+ const text = substituteType(original, bindings);
119
+ const builtin = builtinType(substituteType(spelling, bindings));
120
+ if (builtin) return builtin;
121
+ const parts = qualifiedParts(text);
122
+ const found = bound && typeof bound === 'object' ? { kind: 'unknown' } :
123
+ scope.resolveQualifier(index, context, text, scope.includeClosure(index, context.file), 0,
124
+ { declarations: true, externalTypes: true });
125
+ if (found.kind === 'type' && found.visible && found.declarations.length === 1) {
126
+ return resolvedDeclaration(index, found.declarations[0], text, context, bindings, depth);
127
+ }
128
+ // A qualifier can itself be a class alias with template arguments.
129
+ // Resolve that class first so its member aliases inherit those bindings.
130
+ if (parts.length > 1 && parts.at(-1) && !parts.at(-1).includes('<')) {
131
+ const parent = resolveType(index, parts.slice(0, -1).join('::'), context, bindings, depth + 1);
132
+ const member = parts.at(-1).trim();
133
+ if (parent.kind === 'builtin') return { kind: 'invalid', text };
134
+ if (parent.kind === 'project') {
135
+ const syntax = classSyntax(index, parent.definition);
136
+ const matches = syntax.members.filter(definition => definition.name === member &&
137
+ ['type', 'class', 'struct', 'enum', 'union'].includes(definition.type));
138
+ if (matches.length === 1) return resolvedDeclaration(index, matches[0], member, context,
139
+ parent.bindings, depth + 1);
140
+ if (matches.length === 0 && syntax.complete && !syntax.bases.length) return { kind: 'invalid', text };
141
+ }
142
+ if (parent.kind === 'standard' && member === 'value_type') return builtinType(parent.platform.character);
143
+ if (parent.kind === 'external') return { ...parent, qualified: `${parent.qualified}::${member}`, text };
144
+ }
145
+ if (found.kind === 'external') {
146
+ const arguments_ = typeArguments(text);
147
+ const platform = standardStringType(found.qualified, arguments_);
148
+ return { kind: platform ? 'standard' : 'external', qualified: found.qualified,
149
+ arguments: arguments_, text, context, bindings, ...(platform && { platform }) };
150
+ }
151
+ return { kind: 'unknown', text };
152
+ }
153
+
154
+ function sameType(a, b) {
155
+ if (['unknown', 'invalid'].includes(a.kind) || ['unknown', 'invalid'].includes(b.kind)) return null;
156
+ if (a.kind !== b.kind) return false;
157
+ if (a.kind === 'builtin' && a.category !== b.category) return false;
158
+ if (a.genericTypeUnknown || b.genericTypeUnknown) return null;
159
+ if ([a, b].some(type => type.qualifiers?.includes('&') && type.qualifiers?.includes('&&'))) return null;
160
+ if (JSON.stringify(a.qualifiers || []) !== JSON.stringify(b.qualifiers || [])) return false;
161
+ if (a.kind === 'project' || a.kind === 'enum') {
162
+ if (!sameDeclaration(declarationIdentity(a.definition), declarationIdentity(b.definition))) return false;
163
+ const encoded = bindings => JSON.stringify([...bindings], (_, value) => value instanceof Map ? [...value] : value);
164
+ return encoded(a.bindings) === encoded(b.bindings) ? true : null;
165
+ }
166
+ if (a.kind === 'standard') return a.platform.family === b.platform.family && a.platform.character === b.platform.character;
167
+ if (a.kind === 'external') return a.qualified === b.qualified && a.text === b.text ? true : null;
168
+ const canonical = type => type.base.replace(/^signed\s+(?=(?:short|int|long)\b)/, '').replace(/^signed$/, 'int')
169
+ .replace(/^(unsigned)$/, '$1 int').replace(/^(short|long|long long|unsigned short|unsigned long|unsigned long long) int$/, '$1');
170
+ if (a.category !== b.category || canonical(a) !== canonical(b)) return false;
171
+ if (a.category === 'pointer') return a.text.replace(/\s/g, '') === b.text.replace(/\s/g, '') &&
172
+ !a.text.includes('[') ? true : null;
173
+ return true;
174
+ }
175
+
176
+ function argumentType(index, kind, call, position) {
177
+ if (kind?.startsWith('string:')) return { ...builtinType(`const ${kind.slice(7)}[]`), literal: true };
178
+ if (kind?.startsWith('char:')) return { ...builtinType(kind.slice(5)), genericTypeUnknown: kind === 'char:char' };
179
+ if (kind === 'number:zero') return { ...builtinType('int'), zero: true, genericTypeUnknown: true };
180
+ if (kind === 'number:integer') return { ...builtinType('int'), genericTypeUnknown: true };
181
+ if (kind === 'number:floating') return { ...builtinType('double'), genericTypeUnknown: true };
182
+ if (kind === 'bool') return builtinType('bool');
183
+ if (kind === 'null') return builtinType('std::nullptr_t');
184
+ if (kind?.startsWith('type:')) {
185
+ const builtin = builtinType(kind.slice(5));
186
+ const origin = call?.argTypeOrigins?.[position];
187
+ if (call?.argumentFile && origin) return resolveType(index, kind.slice(5), {
188
+ ...origin, file: path.resolve(index.root, call.argumentFile),
189
+ });
190
+ if (builtin) return builtin;
191
+ }
192
+ return { kind: 'unknown', text: kind };
193
+ }
194
+
195
+ function derivedFrom(index, source, target, depth) {
196
+ if (depth > 10) return null;
197
+ if (sameDeclaration(declarationIdentity(source.definition), declarationIdentity(target.definition))) return true;
198
+ const syntax = classSyntax(index, source.definition);
199
+ let unknown = !syntax.complete;
200
+ for (const base of syntax.bases) {
201
+ const parent = resolveType(index, base, source.context, source.bindings);
202
+ if (parent.kind !== 'project') { unknown = true; continue; }
203
+ const reaches = derivedFrom(index, parent, target, depth + 1);
204
+ if (reaches === true) return true;
205
+ if (reaches === null) unknown = true;
206
+ }
207
+ return unknown ? null : false;
208
+ }
209
+
210
+ function deduceConstructor(source, constructor, inherited) {
211
+ const bindings = new Map(inherited);
212
+ for (const parameter of constructor.syntax.template?.parameters || []) {
213
+ if (parameter.name && !bindings.has(parameter.name)) bindings.set(parameter.name, null);
214
+ }
215
+ const formal = constructor.definition.paramsStructured?.[0]?.type || constructor.syntax.parameterTypes?.[0];
216
+ const head = typeText(formal);
217
+ if (bindings.has(head) && source.kind !== 'unknown') {
218
+ const uncertain = source.genericTypeUnknown || source.category === 'pointer' || /&&/.test(formal);
219
+ const qualifiers = (source.qualifiers || []).filter(qualifier => {
220
+ if (qualifier === '&' || qualifier === '&&') return false;
221
+ if (!formal.includes('&')) return !['const', 'volatile'].includes(qualifier);
222
+ return !new RegExp(`\\b${qualifier}\\b`).test(formal);
223
+ });
224
+ bindings.set(head, { ...source, qualifiers, zero: false,
225
+ ...(uncertain && { genericTypeUnknown: true }) });
226
+ }
227
+ return bindings;
228
+ }
229
+
230
+ function constraintConversion(index, source, target, depth) {
231
+ const result = typeConversion(index, source, target, depth);
232
+ // A type trait also tests reference binding and volatile qualification.
233
+ // Category compatibility alone does not prove those standard conversions.
234
+ return result === true && [source, target].some(type =>
235
+ type.qualifiers?.some(qualifier => ['&', '&&', 'volatile'].includes(qualifier))) ? null : result;
236
+ }
237
+
238
+ function operatorPossibilities(index, source, target, depth) {
239
+ if (source.kind !== 'project') return [];
240
+ const syntax = classSyntax(index, source.definition), results = [];
241
+ if (!syntax.complete) results.push(null);
242
+ for (const operator of syntax.operators) {
243
+ if (operator.syntax.explicit === 'explicit') continue;
244
+ const context = contextOf(index, operator.definition);
245
+ const bindings = new Map(source.bindings);
246
+ for (const parameter of operator.syntax.template?.parameters || []) {
247
+ if (parameter.name) bindings.set(parameter.name,
248
+ typeText(operator.syntax.conversionType) === parameter.name ? target : null);
249
+ }
250
+ const constraints = require('./cpp-conversion-constraints').constraintResult(index, operator.syntax,
251
+ context, bindings, (a, b) => constraintConversion(index, a, b, depth + 1));
252
+ if (constraints === false) continue;
253
+ const result = resolveType(index, operator.syntax.conversionType, context, bindings);
254
+ if (typeConversion(index, result, target, depth + 1, false) !== false) results.push(null);
255
+ }
256
+ for (const base of syntax.bases) {
257
+ const parent = resolveType(index, base, source.context, source.bindings);
258
+ if (parent.kind === 'project' && depth < 10) results.push(...operatorPossibilities(index, parent, target, depth + 1));
259
+ else results.push(null);
260
+ }
261
+ return results;
262
+ }
263
+
264
+ /** true: standard conversion; false: impossible; null: undecided. */
265
+ function typeConversion(index, source, target, depth = 0, userDefined = true) {
266
+ if (depth > 10 || source.kind === 'unknown' || target.kind === 'unknown') return null;
267
+ if (source.kind === 'invalid' || target.kind === 'invalid') return false;
268
+ if (source.kind === 'builtin' && target.kind === 'builtin') {
269
+ if (source.category === 'void' || target.category === 'void') return source.category === target.category;
270
+ if (source.zero) return true;
271
+ if (source.category === 'null') return ['pointer', 'null'].includes(target.category);
272
+ if (target.category === 'bool') return true;
273
+ if (source.category === 'pointer' || target.category === 'pointer') {
274
+ if (source.category !== target.category) return false;
275
+ if (target.base === 'void') return true;
276
+ if (source.base === target.base) return null;
277
+ const a = builtinType(source.base), b = builtinType(target.base);
278
+ if (a && b) return false;
279
+ const ap = a || resolveType(index, source.base, source.context, source.bindings);
280
+ const bp = b || resolveType(index, target.base, target.context, target.bindings);
281
+ if (a && ['project', 'enum', 'standard'].includes(bp.kind) ||
282
+ b && ['project', 'enum', 'standard'].includes(ap.kind)) return false;
283
+ return null;
284
+ }
285
+ if (target.category === 'null') return false;
286
+ return true;
287
+ }
288
+ if (target.kind === 'standard') {
289
+ if (source.kind === 'standard') {
290
+ if (source.platform.character !== target.platform.character) return false;
291
+ if (source.platform.family === target.platform.family) return true;
292
+ return userDefined && target.platform.family === 'view';
293
+ }
294
+ if (source.kind === 'builtin') {
295
+ if (!userDefined) return false;
296
+ if (source.zero || source.category === 'null') return null;
297
+ if (source.category !== 'pointer' || source.levels !== 1) return false;
298
+ if (/\bvolatile\b/.test(source.text.split(/\*|\[/)[0])) return false;
299
+ if (source.character) return source.character === target.platform.character;
300
+ const pointee = resolveType(index, source.base, source.context, source.bindings);
301
+ if (pointee.kind === 'builtin') return !pointee.qualifiers?.includes('volatile') &&
302
+ CHARACTERS.has(pointee.base) && pointee.base === target.platform.character;
303
+ return ['project', 'enum', 'standard'].includes(pointee.kind) ? false : null;
304
+ }
305
+ }
306
+ if (source.kind === 'project' && target.kind === 'project') {
307
+ const related = derivedFrom(index, source, target, depth);
308
+ if (related !== false) return null;
309
+ }
310
+ if (target.kind === 'enum') {
311
+ if (source.kind === 'enum') return sameType(source, target);
312
+ if (source.kind === 'builtin' || source.kind === 'standard') return false;
313
+ }
314
+ if (source.kind === 'enum' && target.kind === 'builtin') return null;
315
+ if (source.kind === 'enum' && target.kind === 'standard') return false;
316
+ if (source.kind === 'external' || target.kind === 'external') return null;
317
+ const possibilities = userDefined ? operatorPossibilities(index, source, target, depth) : [];
318
+ if (target.kind === 'project' && userDefined) {
319
+ const syntax = classSyntax(index, target.definition);
320
+ if (!syntax.complete) possibilities.push(null);
321
+ for (const constructor of syntax.constructors) {
322
+ const params = constructor.definition.paramsStructured;
323
+ if (!Array.isArray(params)) { possibilities.push(null); continue; }
324
+ const required = params.filter(param => !param.optional && param.default === undefined && !param.rest).length;
325
+ if (required > 1 || params.length === 0 || constructor.syntax.explicit === 'explicit') continue;
326
+ const parameterType = params[0].type || constructor.syntax.parameterTypes?.[0];
327
+ if (!parameterType || params[0].rest) { possibilities.push(null); continue; }
328
+ const bindings = deduceConstructor(source, constructor, target.bindings);
329
+ const context = contextOf(index, constructor.definition);
330
+ const constraints = require('./cpp-conversion-constraints').constraintResult(index, constructor.syntax,
331
+ context, bindings, (a, b) => constraintConversion(index, a, b, depth + 1));
332
+ if (constraints === false) continue;
333
+ const parameter = resolveType(index, parameterType, context, bindings);
334
+ if (typeConversion(index, source, parameter, depth + 1, false) !== false) possibilities.push(null);
335
+ }
336
+ }
337
+ return possibilities.length ? null : false;
338
+ }
339
+
340
+ function argumentConversion(index, kind, parameterType, definition, call, position) {
341
+ const origin = kind?.startsWith('type:') ? [call?.argumentFile, call?.argTypeOrigins?.[position]] : null;
342
+ if (!index.isProvenanceFactIndex) {
343
+ const inventory = scope.conversionResultMemo(index);
344
+ let memo = inventory.get(definition);
345
+ if (!memo) inventory.set(definition, memo = new Map());
346
+ const key = `${kind}\0${parameterType}\0${origin ? JSON.stringify(origin) : ''}`;
347
+ if (!memo.has(key)) memo.set(key, typeConversion(index, argumentType(index, kind, call, position),
348
+ resolveType(index, parameterType, contextOf(index, definition))));
349
+ return memo.get(key);
350
+ }
351
+ const context = contextOf(index, definition);
352
+ const key = `cpp-argument-conversion:${JSON.stringify([kind, parameterType, context, origin])}`;
353
+ return sharedRead(index, key, view => typeConversion(view, argumentType(view, kind, call, position),
354
+ resolveType(view, parameterType, context)));
355
+ }
356
+
357
+ function typeText(type) {
358
+ const text = String(type || '');
359
+ let depth = 0, result = '';
360
+ for (let i = 0; i < text.length;) {
361
+ const ch = text[i];
362
+ if ('<(['.includes(ch)) depth++;
363
+ else if ('>)]'.includes(ch)) depth--;
364
+ if (depth === 0) {
365
+ const qualifier = /^(?:const|volatile|typename|class|struct)\b/.exec(text.slice(i));
366
+ if (qualifier && (i === 0 || !/\w/.test(text[i - 1]))) { i += qualifier[0].length; continue; }
367
+ if (ch === '&') { i++; continue; }
368
+ }
369
+ result += ch; i++;
370
+ }
371
+ return result.replace(/\s*::\s*/g, '::').replace(/\s*</g, '<').replace(/\s+/g, ' ').trim();
372
+ }
373
+
374
+ function typeArguments(text) {
375
+ const start = text.indexOf('<');
376
+ if (start < 0) return [];
377
+ const result = [];
378
+ let depth = 0, from = start + 1;
379
+ for (let i = from; i < text.length; i++) {
380
+ const ch = text[i];
381
+ if (ch === '<' || ch === '(' || ch === '[') depth++;
382
+ else if (ch === '>' && depth === 0) {
383
+ if (i > from) result.push(text.slice(from, i).trim());
384
+ return result;
385
+ } else if (ch === '>' || ch === ')' || ch === ']') depth--;
386
+ else if (ch === ',' && depth === 0) { result.push(text.slice(from, i).trim()); from = i + 1; }
387
+ }
388
+ return [];
389
+ }
390
+
391
+ function contextOf(index, definition) {
392
+ if (!definition?.file) return null;
393
+ const file = path.resolve(index.root, definition.file);
394
+ return { file, line: definition.startLine || definition.line || 1,
395
+ className: definition.className || definition.enclosingType || null,
396
+ ...(definition.templateParams && { typeParameters: typeArguments(`Type${definition.templateParams}`) }),
397
+ ...(definition.namespace != null && { namespace: scope.effectiveNamespace(index, { ...definition, file }) }) };
398
+ }
399
+
400
+ // Positive platform proofs use the same resolved types as exclusions.
401
+ function platformConversion(index, kind, parameterType, definition, call, position) {
402
+ const target = resolveType(index, parameterType, contextOf(index, definition));
403
+ if (target.kind !== 'standard') return null;
404
+ const source = argumentType(index, kind, call, position);
405
+ const qualifiers = target.qualifiers || [];
406
+ // Constructibility does not prove reference binding or access through a
407
+ // volatile object. Those need value-category and qualified-member facts.
408
+ if (qualifiers.includes('&&') || qualifiers.includes('&') && !qualifiers.includes('const') ||
409
+ [source, target].some(type => type.qualifiers?.includes('volatile'))) return null;
410
+ return typeConversion(index, source, target);
411
+ }
412
+
413
+ module.exports = { platformConversion, typeText, typeArguments, contextOf,
414
+ resolveType, sameType, substituteType, builtinType, qualifiedParts, argumentConversion, typeConversion };