ucn 5.2.0 → 5.2.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.
- package/.claude/skills/ucn/SKILL.md +17 -3
- package/.claude/skills/ucn/references/commands.md +4 -4
- package/README.md +17 -5
- package/cli/index.js +3 -0
- package/core/accessors.js +183 -0
- package/core/account.js +36 -8
- package/core/analysis.js +46 -0
- package/core/ast-analysis.js +104 -0
- package/core/cache.js +150 -9
- package/core/callers.js +1196 -122
- package/core/command-contracts.js +13 -13
- package/core/deadcode.js +41 -2
- package/core/execute.js +4 -1
- package/core/graph.js +72 -5
- package/core/index-ir.js +15 -3
- package/core/ir.js +58 -9
- package/core/output/analysis.js +30 -1
- package/core/output/graph.js +28 -8
- package/core/output/public.js +4 -0
- package/core/output/refactoring.js +31 -2
- package/core/output/reporting.js +7 -0
- package/core/project.js +88 -3
- package/core/verify.js +85 -3
- package/languages/c-family.js +27 -34
- package/languages/csharp.js +26 -1
- package/languages/go.js +170 -42
- package/languages/javascript.js +258 -10
- package/languages/python.js +591 -32
- package/languages/rust.js +1 -0
- package/package.json +1 -1
package/languages/go.js
CHANGED
|
@@ -653,6 +653,8 @@ const GO_BUILTINS = new Set([
|
|
|
653
653
|
* target with its declared return position)
|
|
654
654
|
* y = q() → { assignedTo: 'y' } (plain `=` only — `+=` etc.
|
|
655
655
|
* don't bind the call's type to the variable)
|
|
656
|
+
* var z = q() → { assignedTo: 'z' } (`var` declarations use
|
|
657
|
+
* repeated AST `name` fields plus a `value` list)
|
|
656
658
|
* a, b := g(), h() → parallel assignment: each call pairs with its
|
|
657
659
|
* own LHS position, single-value semantics
|
|
658
660
|
* Identifier targets only; blank (`_`) targets return undefined.
|
|
@@ -669,18 +671,25 @@ function goAssignmentTargetOf(callNode) {
|
|
|
669
671
|
}
|
|
670
672
|
n = p; p = n.parent;
|
|
671
673
|
}
|
|
672
|
-
if (!p || (p.type !== 'short_var_declaration' &&
|
|
674
|
+
if (!p || (p.type !== 'short_var_declaration' &&
|
|
675
|
+
p.type !== 'assignment_statement' && p.type !== 'var_spec')) return undefined;
|
|
673
676
|
if (p.type === 'assignment_statement') {
|
|
674
677
|
const op = p.childForFieldName('operator');
|
|
675
678
|
if (op && op.text !== '=') return undefined;
|
|
676
679
|
}
|
|
677
|
-
const
|
|
680
|
+
const isVarSpec = p.type === 'var_spec';
|
|
681
|
+
const right = p.childForFieldName(isVarSpec ? 'value' : 'right');
|
|
678
682
|
if (!right || right.id !== n.id) return undefined;
|
|
679
|
-
const left = p.childForFieldName('left');
|
|
680
|
-
if (!left) return undefined;
|
|
681
|
-
const names =
|
|
682
|
-
? Array.from({ length:
|
|
683
|
-
|
|
683
|
+
const left = isVarSpec ? null : p.childForFieldName('left');
|
|
684
|
+
if (!isVarSpec && !left) return undefined;
|
|
685
|
+
const names = isVarSpec
|
|
686
|
+
? Array.from({ length: p.childCount }, (_, i) => ({
|
|
687
|
+
child: p.child(i),
|
|
688
|
+
field: p.fieldNameForChild(i),
|
|
689
|
+
})).filter(({ field }) => field === 'name').map(({ child }) => child)
|
|
690
|
+
: left.type === 'expression_list'
|
|
691
|
+
? Array.from({ length: left.namedChildCount }, (_, i) => left.namedChild(i))
|
|
692
|
+
: [left];
|
|
684
693
|
if (rhsCount > 1) {
|
|
685
694
|
const target = names[rhsIndex];
|
|
686
695
|
return target?.type === 'identifier' && target.text !== '_'
|
|
@@ -762,6 +771,10 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
762
771
|
// types are compiler-true — Go range yields the container's element.
|
|
763
772
|
const scopeContainerTypes = new Map(); // scopeStartLine -> Map<name, typeText>
|
|
764
773
|
const packageContainerTypes = new Map();
|
|
774
|
+
// Local values bound from an indexed declared field. The file parser may
|
|
775
|
+
// not own the receiver struct declaration, so preserve its exact root +
|
|
776
|
+
// field provenance for project-index resolution after all files exist.
|
|
777
|
+
const scopeIndexedSources = new Map();
|
|
765
778
|
// Track function-typed parameter names per scope (scopeStartLine -> Set<name>)
|
|
766
779
|
const funcParamScopes = new Map();
|
|
767
780
|
|
|
@@ -903,11 +916,24 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
903
916
|
return '<anonymous>';
|
|
904
917
|
};
|
|
905
918
|
|
|
906
|
-
// Helper to get current enclosing function
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
919
|
+
// Helper to get current enclosing function. Return-flow assignments are
|
|
920
|
+
// keyed by function scope, so a captured receiver needs the complete
|
|
921
|
+
// lexical path back to the scope that binds it. Start at the binding
|
|
922
|
+
// scope (rather than every outer function) so a parameter/local that
|
|
923
|
+
// shadows the same name cannot inherit an unrelated outer flow entry.
|
|
924
|
+
const getCurrentEnclosingFunction = (refNode = null, name = null) => {
|
|
925
|
+
if (functionStack.length === 0) return null;
|
|
926
|
+
const allScopes = functionStack.map(scope => scope.startLine);
|
|
927
|
+
let scopeChain = [allScopes[allScopes.length - 1]];
|
|
928
|
+
if (refNode && name) {
|
|
929
|
+
const bindingScope = lexicalBindingScopeStart(refNode, name);
|
|
930
|
+
const bindingIndex = allScopes.lastIndexOf(bindingScope);
|
|
931
|
+
if (bindingIndex >= 0) scopeChain = allScopes.slice(bindingIndex);
|
|
932
|
+
}
|
|
933
|
+
return {
|
|
934
|
+
...functionStack[functionStack.length - 1],
|
|
935
|
+
scopeChain,
|
|
936
|
+
};
|
|
911
937
|
};
|
|
912
938
|
|
|
913
939
|
// Resolve a local closure through the lexical function-scope chain.
|
|
@@ -931,21 +957,40 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
931
957
|
|
|
932
958
|
// Look up variable type from scope chain
|
|
933
959
|
const getReceiverType = (varName, refNode) => {
|
|
960
|
+
const bindingScope = refNode
|
|
961
|
+
? lexicalBindingScopeStart(refNode, varName) : null;
|
|
934
962
|
for (let i = functionStack.length - 1; i >= 0; i--) {
|
|
935
|
-
const
|
|
963
|
+
const scopeStart = functionStack[i].startLine;
|
|
964
|
+
const typeMap = scopeTypes.get(scopeStart);
|
|
936
965
|
if (typeMap?.has(varName)) return typeMap.get(varName);
|
|
966
|
+
if (bindingScope === scopeStart) return undefined;
|
|
937
967
|
}
|
|
938
968
|
return refNode && isShadowedByLocal(refNode, varName)
|
|
939
969
|
? undefined : packageTypes.get(varName);
|
|
940
970
|
};
|
|
941
971
|
const getReceiverTypeQualifier = (varName, refNode) => {
|
|
972
|
+
const bindingScope = refNode
|
|
973
|
+
? lexicalBindingScopeStart(refNode, varName) : null;
|
|
942
974
|
for (let i = functionStack.length - 1; i >= 0; i--) {
|
|
943
|
-
const
|
|
975
|
+
const scopeStart = functionStack[i].startLine;
|
|
976
|
+
const qualifiers = scopeTypeQualifiers.get(scopeStart);
|
|
944
977
|
if (qualifiers?.has(varName)) return qualifiers.get(varName);
|
|
978
|
+
if (bindingScope === scopeStart) return undefined;
|
|
945
979
|
}
|
|
946
980
|
return refNode && isShadowedByLocal(refNode, varName)
|
|
947
981
|
? undefined : packageTypeQualifiers.get(varName);
|
|
948
982
|
};
|
|
983
|
+
const getIndexedSource = (varName, refNode) => {
|
|
984
|
+
const bindingScope = refNode
|
|
985
|
+
? lexicalBindingScopeStart(refNode, varName) : null;
|
|
986
|
+
for (let i = functionStack.length - 1; i >= 0; i--) {
|
|
987
|
+
const scopeStart = functionStack[i].startLine;
|
|
988
|
+
const sources = scopeIndexedSources.get(scopeStart);
|
|
989
|
+
if (sources?.has(varName)) return sources.get(varName);
|
|
990
|
+
if (bindingScope === scopeStart) return undefined;
|
|
991
|
+
}
|
|
992
|
+
return undefined;
|
|
993
|
+
};
|
|
949
994
|
// Compiler-true receiver type from a composite-literal receiver
|
|
950
995
|
// expression (fix #298, websocket-measured — the #220(7) typing-sources
|
|
951
996
|
// family): `(&Kit{...}).Run`, `(&net.Dialer{}).DialContext(...)`,
|
|
@@ -1052,6 +1097,22 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1052
1097
|
}
|
|
1053
1098
|
return structFieldsCache;
|
|
1054
1099
|
};
|
|
1100
|
+
const containerTypeOf = (node) => {
|
|
1101
|
+
if (node?.type === 'selector_expression') {
|
|
1102
|
+
const operand = node.childForFieldName('operand');
|
|
1103
|
+
const field = node.childForFieldName('field');
|
|
1104
|
+
if (operand?.type === 'identifier' && field &&
|
|
1105
|
+
!isGuessedType(operand.text)) {
|
|
1106
|
+
const rootType = getReceiverType(operand.text, operand);
|
|
1107
|
+
if (rootType) {
|
|
1108
|
+
return getStructFields().get(rootType)?.get(field.text) || null;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
} else if (node?.type === 'identifier') {
|
|
1112
|
+
return lookupContainerType(node.text);
|
|
1113
|
+
}
|
|
1114
|
+
return null;
|
|
1115
|
+
};
|
|
1055
1116
|
|
|
1056
1117
|
// fix #203 (Go): is a bare-identifier function REFERENCE shadowed by an
|
|
1057
1118
|
// enclosing func-literal/function parameter, method receiver, range/init
|
|
@@ -1102,13 +1163,23 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1102
1163
|
}
|
|
1103
1164
|
return false;
|
|
1104
1165
|
};
|
|
1105
|
-
const
|
|
1166
|
+
const lexicalBindingScopeStart = (refNode, name) => {
|
|
1167
|
+
const owningFunctionStart = (node) => {
|
|
1168
|
+
for (let current = node; current; current = current.parent) {
|
|
1169
|
+
if (isFunctionNode(current)) {
|
|
1170
|
+
return current.startPosition.row + 1;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return null;
|
|
1174
|
+
};
|
|
1106
1175
|
for (let p = refNode.parent; p; p = p.parent) {
|
|
1107
1176
|
if (p.type === 'block') {
|
|
1108
1177
|
for (let i = 0; i < p.namedChildCount; i++) {
|
|
1109
1178
|
const stmt = p.namedChild(i);
|
|
1110
1179
|
if (stmt.startIndex >= refNode.startIndex) break; // declaration-before-use
|
|
1111
|
-
if (_declaresLocal(stmt, name, refNode))
|
|
1180
|
+
if (_declaresLocal(stmt, name, refNode)) {
|
|
1181
|
+
return owningFunctionStart(p);
|
|
1182
|
+
}
|
|
1112
1183
|
}
|
|
1113
1184
|
} else if (p.type === 'for_statement') {
|
|
1114
1185
|
for (let i = 0; i < p.namedChildCount; i++) {
|
|
@@ -1118,38 +1189,55 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1118
1189
|
if (left) {
|
|
1119
1190
|
for (let j = 0; j < left.namedChildCount; j++) {
|
|
1120
1191
|
const id = left.namedChild(j);
|
|
1121
|
-
if (id.type === 'identifier' && id.text === name)
|
|
1192
|
+
if (id.type === 'identifier' && id.text === name) {
|
|
1193
|
+
return owningFunctionStart(p);
|
|
1194
|
+
}
|
|
1122
1195
|
}
|
|
1123
1196
|
}
|
|
1124
1197
|
} else if (c.type === 'for_clause') {
|
|
1125
|
-
if (_declaresLocal(c.childForFieldName('initializer'), name, refNode))
|
|
1198
|
+
if (_declaresLocal(c.childForFieldName('initializer'), name, refNode)) {
|
|
1199
|
+
return owningFunctionStart(p);
|
|
1200
|
+
}
|
|
1126
1201
|
}
|
|
1127
1202
|
}
|
|
1128
1203
|
} else if (p.type === 'if_statement' || p.type === 'expression_switch_statement' ||
|
|
1129
1204
|
p.type === 'type_switch_statement') {
|
|
1130
|
-
if (_declaresLocal(p.childForFieldName('initializer'), name, refNode))
|
|
1205
|
+
if (_declaresLocal(p.childForFieldName('initializer'), name, refNode)) {
|
|
1206
|
+
return owningFunctionStart(p);
|
|
1207
|
+
}
|
|
1131
1208
|
// if/switch initializers are plain named children in some
|
|
1132
1209
|
// grammar versions; type switches bind `v := x.(type)`
|
|
1133
1210
|
for (let i = 0; i < p.namedChildCount; i++) {
|
|
1134
1211
|
const c = p.namedChild(i);
|
|
1135
|
-
if (c.type === 'short_var_declaration' &&
|
|
1212
|
+
if (c.type === 'short_var_declaration' &&
|
|
1213
|
+
_declaresLocal(c, name, refNode)) {
|
|
1214
|
+
return owningFunctionStart(p);
|
|
1215
|
+
}
|
|
1136
1216
|
if (p.type === 'type_switch_statement' && c.type === 'expression_list' &&
|
|
1137
1217
|
c.nextSibling?.type === ':=') {
|
|
1138
1218
|
for (let j = 0; j < c.namedChildCount; j++) {
|
|
1139
1219
|
const id = c.namedChild(j);
|
|
1140
|
-
if (id.type === 'identifier' && id.text === name)
|
|
1220
|
+
if (id.type === 'identifier' && id.text === name) {
|
|
1221
|
+
return owningFunctionStart(p);
|
|
1222
|
+
}
|
|
1141
1223
|
}
|
|
1142
1224
|
}
|
|
1143
1225
|
}
|
|
1144
1226
|
} else if (p.type === 'func_literal' || p.type === 'function_declaration' ||
|
|
1145
1227
|
p.type === 'method_declaration') {
|
|
1146
|
-
if (_paramListDeclares(p.childForFieldName('parameters'), name))
|
|
1228
|
+
if (_paramListDeclares(p.childForFieldName('parameters'), name)) {
|
|
1229
|
+
return p.startPosition.row + 1;
|
|
1230
|
+
}
|
|
1147
1231
|
if (p.type === 'method_declaration' &&
|
|
1148
|
-
_paramListDeclares(p.childForFieldName('receiver'), name))
|
|
1232
|
+
_paramListDeclares(p.childForFieldName('receiver'), name)) {
|
|
1233
|
+
return p.startPosition.row + 1;
|
|
1234
|
+
}
|
|
1149
1235
|
}
|
|
1150
1236
|
}
|
|
1151
|
-
return
|
|
1237
|
+
return null;
|
|
1152
1238
|
};
|
|
1239
|
+
const isShadowedByLocal = (refNode, name) =>
|
|
1240
|
+
lexicalBindingScopeStart(refNode, name) != null;
|
|
1153
1241
|
|
|
1154
1242
|
traverseTree(tree.rootNode, (node) => {
|
|
1155
1243
|
// Track function entry
|
|
@@ -1164,6 +1252,7 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1164
1252
|
scopeTypes.set(entry.startLine, typeMap);
|
|
1165
1253
|
scopeTypeQualifiers.set(entry.startLine, typeQualifierMap);
|
|
1166
1254
|
scopeContainerTypes.set(entry.startLine, containerMap || new Map());
|
|
1255
|
+
scopeIndexedSources.set(entry.startLine, new Map());
|
|
1167
1256
|
if (funcParamNames.size > 0) {
|
|
1168
1257
|
funcParamScopes.set(entry.startLine, funcParamNames);
|
|
1169
1258
|
}
|
|
@@ -1186,21 +1275,7 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1186
1275
|
const valueVar = vars.length === 2 && vars[1].type === 'identifier' &&
|
|
1187
1276
|
vars[1].text !== '_' ? vars[1].text : null;
|
|
1188
1277
|
if (valueVar && right) {
|
|
1189
|
-
|
|
1190
|
-
if (right.type === 'selector_expression') {
|
|
1191
|
-
const operand = right.childForFieldName('operand');
|
|
1192
|
-
const fieldN = right.childForFieldName('field');
|
|
1193
|
-
if (operand?.type === 'identifier' && fieldN &&
|
|
1194
|
-
!isGuessedType(operand.text)) {
|
|
1195
|
-
const rootType = getReceiverType(operand.text, operand);
|
|
1196
|
-
if (rootType) {
|
|
1197
|
-
containerText = getStructFields().get(rootType)?.get(fieldN.text) || null;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
} else if (right.type === 'identifier') {
|
|
1201
|
-
containerText = lookupContainerType(right.text);
|
|
1202
|
-
}
|
|
1203
|
-
const el = containerElementType(containerText);
|
|
1278
|
+
const el = containerElementType(containerTypeOf(right));
|
|
1204
1279
|
if (el) {
|
|
1205
1280
|
const scopeKey = functionStack[functionStack.length - 1].startLine;
|
|
1206
1281
|
const typeMap = scopeTypes.get(scopeKey);
|
|
@@ -1237,6 +1312,7 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1237
1312
|
let typeName = null;
|
|
1238
1313
|
let typeQualifier = null;
|
|
1239
1314
|
let typeGuessed = false;
|
|
1315
|
+
let indexedSource = null;
|
|
1240
1316
|
// &Type{...} or Type{...}
|
|
1241
1317
|
if (val.type === 'composite_literal') {
|
|
1242
1318
|
const typeNode = val.childForFieldName('type');
|
|
@@ -1301,6 +1377,34 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1301
1377
|
}
|
|
1302
1378
|
}
|
|
1303
1379
|
}
|
|
1380
|
+
} else if (val.type === 'index_expression') {
|
|
1381
|
+
// child, ok := holder.children[key] — map lookup
|
|
1382
|
+
// and slice/array indexing yield the container's
|
|
1383
|
+
// declared element type. In a comma-ok lookup the
|
|
1384
|
+
// first LHS receives the value; the existing
|
|
1385
|
+
// single-RHS pairing already selects that target.
|
|
1386
|
+
const container = val.childForFieldName('operand');
|
|
1387
|
+
const element = containerElementType(containerTypeOf(container));
|
|
1388
|
+
if (element) {
|
|
1389
|
+
typeName = element.type;
|
|
1390
|
+
typeQualifier = element.qualifier;
|
|
1391
|
+
}
|
|
1392
|
+
if (container?.type === 'selector_expression') {
|
|
1393
|
+
const root = container.childForFieldName('operand');
|
|
1394
|
+
const field = container.childForFieldName('field');
|
|
1395
|
+
if (root?.type === 'identifier' && field &&
|
|
1396
|
+
!isGuessedType(root.text)) {
|
|
1397
|
+
const rootType = getReceiverType(root.text, root);
|
|
1398
|
+
if (rootType) {
|
|
1399
|
+
indexedSource = {
|
|
1400
|
+
rootType,
|
|
1401
|
+
rootTypeQualifier:
|
|
1402
|
+
getReceiverTypeQualifier(root.text, root) || null,
|
|
1403
|
+
field: field.text,
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1304
1408
|
} else if (val.type === 'type_assertion_expression') {
|
|
1305
1409
|
// d, ok := dialer.(proxy.ContextDialer) — the
|
|
1306
1410
|
// asserted type IS d's static type (fix #298,
|
|
@@ -1333,6 +1437,9 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1333
1437
|
gset.delete(names[vi]); // compiler-true retype clears the guess
|
|
1334
1438
|
}
|
|
1335
1439
|
}
|
|
1440
|
+
const indexedSources = scopeIndexedSources.get(scopeKey);
|
|
1441
|
+
if (indexedSource) indexedSources?.set(names[vi], indexedSource);
|
|
1442
|
+
else indexedSources?.delete(names[vi]);
|
|
1336
1443
|
}
|
|
1337
1444
|
}
|
|
1338
1445
|
}
|
|
@@ -1585,6 +1692,8 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1585
1692
|
? getReceiverType(receiver, operandNode) : undefined;
|
|
1586
1693
|
let receiverTypeQualifier = receiverType
|
|
1587
1694
|
? getReceiverTypeQualifier(receiver, operandNode) : undefined;
|
|
1695
|
+
const receiverIndexedSource = !isPkgCall && receiver && !receiverType
|
|
1696
|
+
? getIndexedSource(receiver, operandNode) : undefined;
|
|
1588
1697
|
// Composite-literal receiver (fix #298):
|
|
1589
1698
|
// (&Kit{...}).Run(...) — compiler-true type, never guessed.
|
|
1590
1699
|
if (!receiver && !receiverType) {
|
|
@@ -1597,7 +1706,7 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1597
1706
|
// fix #202: one-hop declared-field receivers — h.inner.Run().
|
|
1598
1707
|
// receiverRoot/Field/RootType let findCallers hop to the
|
|
1599
1708
|
// field's declared struct-field type cross-file.
|
|
1600
|
-
let receiverRoot, receiverFieldName, receiverRootType,
|
|
1709
|
+
let receiverRoot, receiverRootNode, receiverFieldName, receiverRootType,
|
|
1601
1710
|
receiverRootTypeQualifier, receiverRootTypeGuessed,
|
|
1602
1711
|
receiverRootIsModule;
|
|
1603
1712
|
if (!receiver && operandNode?.type === 'selector_expression') {
|
|
@@ -1605,6 +1714,7 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1605
1714
|
const fldNode = operandNode.childForFieldName('field');
|
|
1606
1715
|
if (rootNode?.type === 'identifier' && fldNode) {
|
|
1607
1716
|
receiverRoot = rootNode.text;
|
|
1717
|
+
receiverRootNode = rootNode;
|
|
1608
1718
|
receiverFieldName = fldNode.text;
|
|
1609
1719
|
if (importAliases.has(rootNode.text)) {
|
|
1610
1720
|
// Package-owned value receiver:
|
|
@@ -1673,6 +1783,13 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1673
1783
|
}
|
|
1674
1784
|
}
|
|
1675
1785
|
const firstArg = getFirstStringArg(node);
|
|
1786
|
+
const receiverBindingNode = receiver ? operandNode : receiverRootNode;
|
|
1787
|
+
const receiverBindingName = receiver || receiverRoot;
|
|
1788
|
+
const methodEnclosingFunction = !isPkgCall &&
|
|
1789
|
+
receiverBindingNode && receiverBindingName
|
|
1790
|
+
? getCurrentEnclosingFunction(
|
|
1791
|
+
receiverBindingNode, receiverBindingName)
|
|
1792
|
+
: enclosingFunction;
|
|
1676
1793
|
calls.push({
|
|
1677
1794
|
name: fieldNode.text,
|
|
1678
1795
|
// Name-node line convention (#201/RUST-2, fix #223):
|
|
@@ -1690,6 +1807,14 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1690
1807
|
...(receiverType && { receiverType }),
|
|
1691
1808
|
...(receiverTypeQualifier && { receiverTypeQualifier }),
|
|
1692
1809
|
...(receiverType && isGuessedType(receiver) && { receiverTypeGuessed: true }),
|
|
1810
|
+
...(receiverIndexedSource && {
|
|
1811
|
+
receiverIndexRootType: receiverIndexedSource.rootType,
|
|
1812
|
+
receiverIndexField: receiverIndexedSource.field,
|
|
1813
|
+
...(receiverIndexedSource.rootTypeQualifier && {
|
|
1814
|
+
receiverIndexRootTypeQualifier:
|
|
1815
|
+
receiverIndexedSource.rootTypeQualifier,
|
|
1816
|
+
}),
|
|
1817
|
+
}),
|
|
1693
1818
|
...(receiverFieldName && { receiverRoot, receiverField: receiverFieldName }),
|
|
1694
1819
|
...(receiverRootIsModule && { receiverRootIsModule: true }),
|
|
1695
1820
|
...(receiverFieldName && receiverRootType && { receiverRootType }),
|
|
@@ -1716,7 +1841,7 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1716
1841
|
assignedTupleTargets: assigned.assignedTupleTargets,
|
|
1717
1842
|
}),
|
|
1718
1843
|
...(assigned?.assignedTupleRest && { assignedTupleRest: assigned.assignedTupleRest }),
|
|
1719
|
-
enclosingFunction,
|
|
1844
|
+
enclosingFunction: methodEnclosingFunction,
|
|
1720
1845
|
uncertain,
|
|
1721
1846
|
...(firstArg && { firstStringArg: firstArg.value, firstStringArgInterp: firstArg.interp })
|
|
1722
1847
|
});
|
|
@@ -1796,7 +1921,9 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
1796
1921
|
receiverTypeQualifier = lit.receiverTypeQualifier;
|
|
1797
1922
|
}
|
|
1798
1923
|
}
|
|
1799
|
-
const enclosingFunction =
|
|
1924
|
+
const enclosingFunction = receiver
|
|
1925
|
+
? getCurrentEnclosingFunction(operandNode, receiver)
|
|
1926
|
+
: getCurrentEnclosingFunction();
|
|
1800
1927
|
calls.push({
|
|
1801
1928
|
name: fieldNode.text,
|
|
1802
1929
|
line: fieldNode.startPosition.row + 1,
|
|
@@ -2070,6 +2197,7 @@ function findCallsInCode(code, parser, options = {}) {
|
|
|
2070
2197
|
closureScopes.delete(leaving.startLine);
|
|
2071
2198
|
scopeTypes.delete(leaving.startLine);
|
|
2072
2199
|
scopeGuesses.delete(leaving.startLine);
|
|
2200
|
+
scopeIndexedSources.delete(leaving.startLine);
|
|
2073
2201
|
}
|
|
2074
2202
|
}
|
|
2075
2203
|
}
|