@suss/adapter-python 0.26.0 → 0.28.0
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/dist/index.cjs +1016 -495
- package/dist/index.d.cts +255 -204
- package/dist/index.d.ts +255 -204
- package/dist/index.js +1009 -483
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -43,6 +43,7 @@ __export(index_exports, {
|
|
|
43
43
|
emitValueFacts: () => emitValueFacts,
|
|
44
44
|
extractPythonProject: () => extractPythonProject,
|
|
45
45
|
findPythonFiles: () => findPythonFiles,
|
|
46
|
+
nameKeyIn: () => nameKeyIn,
|
|
46
47
|
nodeId: () => nodeId,
|
|
47
48
|
objectReturnedBy: () => objectReturnedBy,
|
|
48
49
|
parsePython: () => parsePython,
|
|
@@ -90,6 +91,11 @@ function isType(node, ...types) {
|
|
|
90
91
|
function isFunction(node) {
|
|
91
92
|
return node.type === "function_definition" || node.type === "lambda";
|
|
92
93
|
}
|
|
94
|
+
var LATER_BODY_TYPES = /* @__PURE__ */ new Set([
|
|
95
|
+
"function_definition",
|
|
96
|
+
"lambda",
|
|
97
|
+
"class_definition"
|
|
98
|
+
]);
|
|
93
99
|
function enclosingFunction(node) {
|
|
94
100
|
let current = node.parent;
|
|
95
101
|
while (current !== null) {
|
|
@@ -159,6 +165,25 @@ function children(node) {
|
|
|
159
165
|
function bodyStatements(body) {
|
|
160
166
|
return children(body);
|
|
161
167
|
}
|
|
168
|
+
function nestedStatements(stmt) {
|
|
169
|
+
const found = [];
|
|
170
|
+
for (const child of children(stmt)) {
|
|
171
|
+
if (child.type === "block") {
|
|
172
|
+
for (const inner of children(child)) {
|
|
173
|
+
if (inner.type.endsWith("_clause")) {
|
|
174
|
+
found.push(...nestedStatements(inner));
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
found.push(inner);
|
|
178
|
+
}
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (child.type.endsWith("_clause")) {
|
|
182
|
+
found.push(...nestedStatements(child));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return found;
|
|
186
|
+
}
|
|
162
187
|
function stripDecorators(node) {
|
|
163
188
|
if (node.type !== "decorated_definition") {
|
|
164
189
|
return { definition: node, decorators: [] };
|
|
@@ -519,8 +544,36 @@ function resolveNonlocal(scope, name) {
|
|
|
519
544
|
}
|
|
520
545
|
|
|
521
546
|
// src/annotations.ts
|
|
522
|
-
function createAnnotationContext(scopeFor) {
|
|
523
|
-
return {
|
|
547
|
+
function createAnnotationContext(scopeFor, importedDefinition = null) {
|
|
548
|
+
return {
|
|
549
|
+
scopeMaps: [scopeFor],
|
|
550
|
+
definitions: /* @__PURE__ */ new Map(),
|
|
551
|
+
importedDefinition,
|
|
552
|
+
expanding: /* @__PURE__ */ new Set()
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function scopeOfNode(ctx, node) {
|
|
556
|
+
for (const scopeFor of ctx.scopeMaps) {
|
|
557
|
+
const scope = scopeFor.get(node.id);
|
|
558
|
+
if (scope !== void 0) {
|
|
559
|
+
return scope;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return void 0;
|
|
563
|
+
}
|
|
564
|
+
function aliasValueOf(name, scope, ctx) {
|
|
565
|
+
const binding = resolveName(scope, name);
|
|
566
|
+
if (binding?.kind === "assignment") {
|
|
567
|
+
return binding.value === null ? null : { node: binding.value, scope };
|
|
568
|
+
}
|
|
569
|
+
if (binding?.kind !== "import" && binding?.kind !== "importFrom") {
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
const imported = ctx.importedDefinition?.(scope, name) ?? null;
|
|
573
|
+
if (imported === null || imported.node.type === "class_definition") {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
return { node: imported.node, scope: imported.moduleScope };
|
|
524
577
|
}
|
|
525
578
|
function collectedDefinitions(ctx) {
|
|
526
579
|
const out = {};
|
|
@@ -563,6 +616,7 @@ var EXPRESSION_SHAPERS = {
|
|
|
563
616
|
identifier: (node, scope, ctx) => shapeFromName(node.text, scope, ctx),
|
|
564
617
|
none: () => ({ type: "null" }),
|
|
565
618
|
generic_type: shapeFromGenericType,
|
|
619
|
+
subscript: shapeFromSubscript,
|
|
566
620
|
binary_operator: shapeFromBinaryOperator
|
|
567
621
|
};
|
|
568
622
|
function shapeFromExpression(node, scope, ctx) {
|
|
@@ -584,8 +638,46 @@ function shapeFromName(name, scope, ctx) {
|
|
|
584
638
|
if (binding?.kind === "classDef") {
|
|
585
639
|
return recordShapeRef(name, binding.node, ctx);
|
|
586
640
|
}
|
|
641
|
+
if (binding?.kind === "import" || binding?.kind === "importFrom") {
|
|
642
|
+
const imported = ctx.importedDefinition?.(scope, name) ?? null;
|
|
643
|
+
if (imported?.node.type === "class_definition") {
|
|
644
|
+
if (!ctx.scopeMaps.includes(imported.scopeFor)) {
|
|
645
|
+
ctx.scopeMaps.push(imported.scopeFor);
|
|
646
|
+
}
|
|
647
|
+
return recordShapeRef(name, imported.node, ctx);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
const alias = aliasValueOf(name, scope, ctx);
|
|
651
|
+
if (alias !== null) {
|
|
652
|
+
return shapeFromAliasValue(name, alias, ctx);
|
|
653
|
+
}
|
|
587
654
|
return { type: "ref", name };
|
|
588
655
|
}
|
|
656
|
+
function shapeFromAliasValue(name, alias, ctx) {
|
|
657
|
+
if (ctx.expanding.has(alias.node.id)) {
|
|
658
|
+
return { type: "ref", name };
|
|
659
|
+
}
|
|
660
|
+
ctx.expanding.add(alias.node.id);
|
|
661
|
+
try {
|
|
662
|
+
return shapeFromExpression(alias.node, alias.scope, ctx);
|
|
663
|
+
} finally {
|
|
664
|
+
ctx.expanding.delete(alias.node.id);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
function shapeFromSubscript(node, scope, ctx) {
|
|
668
|
+
const base = field(node, "value");
|
|
669
|
+
const args = fields(node, "subscript");
|
|
670
|
+
const baseName = base?.type === "identifier" ? base.text : null;
|
|
671
|
+
if (baseName === "Annotated") {
|
|
672
|
+
const first = args[0];
|
|
673
|
+
return first === void 0 ? { type: "unknown" } : shapeFromExpression(first, scope, ctx);
|
|
674
|
+
}
|
|
675
|
+
return shapeFromGeneric(
|
|
676
|
+
baseName,
|
|
677
|
+
node.text,
|
|
678
|
+
args.map((arg) => shapeFromExpression(arg, scope, ctx))
|
|
679
|
+
);
|
|
680
|
+
}
|
|
589
681
|
function genericTypeArgs(node) {
|
|
590
682
|
const typeParameter = node.namedChildren.find(
|
|
591
683
|
(child) => child !== null && child.type === "type_parameter"
|
|
@@ -596,14 +688,20 @@ function genericTypeArgs(node) {
|
|
|
596
688
|
}
|
|
597
689
|
function shapeFromGenericType(node, scope, ctx) {
|
|
598
690
|
const base = node.namedChild(0);
|
|
599
|
-
const args = genericTypeArgs(node);
|
|
600
|
-
const shapeOf = (arg) => arg !== void 0 ? annotationToShape(arg, scope, ctx) : { type: "unknown" };
|
|
601
691
|
const baseName = base?.type === "identifier" ? base.text : null;
|
|
692
|
+
return shapeFromGeneric(
|
|
693
|
+
baseName,
|
|
694
|
+
node.text,
|
|
695
|
+
genericTypeArgs(node).map((arg) => annotationToShape(arg, scope, ctx))
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
function shapeFromGeneric(baseName, text2, args) {
|
|
699
|
+
const shapeOf = (arg) => arg ?? { type: "unknown" };
|
|
602
700
|
if (baseName === "Optional") {
|
|
603
701
|
return { type: "union", variants: [shapeOf(args[0]), { type: "null" }] };
|
|
604
702
|
}
|
|
605
703
|
if (baseName === "Union") {
|
|
606
|
-
return { type: "union", variants: args
|
|
704
|
+
return { type: "union", variants: args };
|
|
607
705
|
}
|
|
608
706
|
if (baseName !== null && LIST_NAMES.has(baseName)) {
|
|
609
707
|
return { type: "array", items: shapeOf(args[0]) };
|
|
@@ -614,7 +712,7 @@ function shapeFromGenericType(node, scope, ctx) {
|
|
|
614
712
|
if (baseName !== null && TUPLE_SET_NAMES.has(baseName)) {
|
|
615
713
|
return { type: "array", items: shapeOf(args[0]) };
|
|
616
714
|
}
|
|
617
|
-
return { type: "ref", name: baseName ??
|
|
715
|
+
return { type: "ref", name: baseName ?? text2 };
|
|
618
716
|
}
|
|
619
717
|
function shapeFromBinaryOperator(node, scope, ctx) {
|
|
620
718
|
const operator = field(node, "operator");
|
|
@@ -639,7 +737,7 @@ function recordShapeRef(name, classNode, ctx) {
|
|
|
639
737
|
}
|
|
640
738
|
ctx.definitions.set(key, null);
|
|
641
739
|
const bodyNode = field(classNode, "body");
|
|
642
|
-
const classScope = ctx
|
|
740
|
+
const classScope = scopeOfNode(ctx, classNode);
|
|
643
741
|
ctx.definitions.set(
|
|
644
742
|
key,
|
|
645
743
|
bodyNode !== null && classScope !== void 0 ? recordShapeOf(bodyNode, classScope, ctx) : { type: "record", properties: {} }
|
|
@@ -1372,14 +1470,14 @@ function invocationEffects(definitionNode) {
|
|
|
1372
1470
|
if (calls.length === 0) {
|
|
1373
1471
|
return [];
|
|
1374
1472
|
}
|
|
1375
|
-
const
|
|
1473
|
+
const statementOf3 = /* @__PURE__ */ new Map();
|
|
1376
1474
|
const statements = [];
|
|
1377
1475
|
for (const call of calls) {
|
|
1378
1476
|
const statement = enclosingStatement(call, body);
|
|
1379
1477
|
if (statement === null) {
|
|
1380
1478
|
continue;
|
|
1381
1479
|
}
|
|
1382
|
-
|
|
1480
|
+
statementOf3.set(call.id, statement);
|
|
1383
1481
|
statements.push(statement);
|
|
1384
1482
|
}
|
|
1385
1483
|
const lowered = lowerPythonBody(body, statements);
|
|
@@ -1391,7 +1489,7 @@ function invocationEffects(definitionNode) {
|
|
|
1391
1489
|
statements
|
|
1392
1490
|
);
|
|
1393
1491
|
return calls.map((call) => {
|
|
1394
|
-
const statement =
|
|
1492
|
+
const statement = statementOf3.get(call.id);
|
|
1395
1493
|
const conditions = (0, import_extractor3.sharedGatingConditions)(
|
|
1396
1494
|
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement),
|
|
1397
1495
|
predicateOf
|
|
@@ -1407,40 +1505,28 @@ function invocationEffects(definitionNode) {
|
|
|
1407
1505
|
}
|
|
1408
1506
|
|
|
1409
1507
|
// src/routers.ts
|
|
1410
|
-
var
|
|
1508
|
+
var import_resolution4 = require("@suss/resolution");
|
|
1411
1509
|
|
|
1412
1510
|
// src/facts/resolve.ts
|
|
1413
|
-
var import_datalog = require("@suss/datalog");
|
|
1414
1511
|
var import_resolution = require("@suss/resolution");
|
|
1415
|
-
var RESOLUTION_PROGRAM = (0, import_datalog.deriveOnDemand)(
|
|
1416
|
-
[...import_resolution.RESOLUTION_RULES, ...import_resolution.RESOLUTION_QUESTIONS],
|
|
1417
|
-
import_resolution.ANSWER_RELATIONS
|
|
1418
|
-
);
|
|
1419
1512
|
function resolveCalls(db, callKeys) {
|
|
1420
|
-
|
|
1421
|
-
const fresh = callKeys.filter((key) => !asked.has(key));
|
|
1422
|
-
if (fresh.length === 0) {
|
|
1423
|
-
return;
|
|
1424
|
-
}
|
|
1425
|
-
for (const callKey of fresh) {
|
|
1426
|
-
db.add("wanted", [callKey]);
|
|
1427
|
-
}
|
|
1428
|
-
(0, import_datalog.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
1513
|
+
(0, import_resolution.askResolution)(db, callKeys);
|
|
1429
1514
|
}
|
|
1430
1515
|
function writtenValueOf(db, key) {
|
|
1431
1516
|
resolveCalls(db, [key]);
|
|
1432
1517
|
return (0, import_resolution.writtenValueOf)(db, key, (keys) => resolveCalls(db, keys));
|
|
1433
1518
|
}
|
|
1519
|
+
function originsOf(db, nameKey2) {
|
|
1520
|
+
(0, import_resolution.askResolution)(db, [nameKey2], "wantedOrigin");
|
|
1521
|
+
return db.facts("wantedComesFrom").filter((row) => String(row[0]) === nameKey2).map((row) => ({ module: String(row[1]), name: String(row[2]) }));
|
|
1522
|
+
}
|
|
1434
1523
|
function subjectConstructions(db, valueKeys) {
|
|
1435
1524
|
const found = /* @__PURE__ */ new Map();
|
|
1436
1525
|
if (valueKeys.length === 0) {
|
|
1437
1526
|
return found;
|
|
1438
1527
|
}
|
|
1439
1528
|
const askSubjects = (keys) => {
|
|
1440
|
-
|
|
1441
|
-
db.add("wantedSubject", [key]);
|
|
1442
|
-
}
|
|
1443
|
-
(0, import_datalog.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
1529
|
+
(0, import_resolution.askResolution)(db, keys, "wantedSubject");
|
|
1444
1530
|
};
|
|
1445
1531
|
askSubjects(valueKeys);
|
|
1446
1532
|
const placeholders = (0, import_resolution.placeholderValues)(db);
|
|
@@ -1487,6 +1573,7 @@ function objectReturnedBy(db, callKey) {
|
|
|
1487
1573
|
}
|
|
1488
1574
|
|
|
1489
1575
|
// src/facts/values.ts
|
|
1576
|
+
var import_resolution2 = require("@suss/resolution");
|
|
1490
1577
|
function nodeId(filePath, node) {
|
|
1491
1578
|
return `${filePath}:${node.startIndex}-${node.endIndex}`;
|
|
1492
1579
|
}
|
|
@@ -1497,10 +1584,10 @@ function readKey(filePath, node, enclosing) {
|
|
|
1497
1584
|
if (node.type !== "identifier") {
|
|
1498
1585
|
return nodeId(filePath, node);
|
|
1499
1586
|
}
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
return
|
|
1587
|
+
return nameKeyIn(filePath, enclosing, node.text);
|
|
1588
|
+
}
|
|
1589
|
+
function nameKeyIn(filePath, enclosing, name) {
|
|
1590
|
+
return nameKey(filePath, scopeChainOf(filePath, enclosing), name);
|
|
1504
1591
|
}
|
|
1505
1592
|
var WRITTEN_VALUE_TYPES = /* @__PURE__ */ new Set([
|
|
1506
1593
|
"string",
|
|
@@ -1538,9 +1625,6 @@ function parameterName2(param) {
|
|
|
1538
1625
|
}
|
|
1539
1626
|
return children(param).find((child) => child.type === "identifier") ?? null;
|
|
1540
1627
|
}
|
|
1541
|
-
function parameterList(fn) {
|
|
1542
|
-
return parameterShapes(fn).map((parameter) => parameter.name);
|
|
1543
|
-
}
|
|
1544
1628
|
function parameterShapes(fn) {
|
|
1545
1629
|
const params = field(fn, "parameters");
|
|
1546
1630
|
const declared = [];
|
|
@@ -1555,24 +1639,52 @@ function parameterShapes(fn) {
|
|
|
1555
1639
|
}
|
|
1556
1640
|
return declared;
|
|
1557
1641
|
}
|
|
1558
|
-
function
|
|
1559
|
-
|
|
1642
|
+
function boundParameterNames(fn) {
|
|
1643
|
+
const params = field(fn, "parameters");
|
|
1644
|
+
const names = [];
|
|
1645
|
+
for (const param of params === null ? [] : children(params)) {
|
|
1646
|
+
const name = parameterName2(param);
|
|
1647
|
+
if (name !== null) {
|
|
1648
|
+
names.push(name.text);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
return names;
|
|
1560
1652
|
}
|
|
1561
1653
|
function add(emitter, relation, ...tuple) {
|
|
1562
1654
|
emitter.db.add(relation, tuple);
|
|
1563
1655
|
}
|
|
1656
|
+
function nameKey(filePath, scope, name) {
|
|
1657
|
+
for (let current = scope; current !== null; current = current.parent) {
|
|
1658
|
+
if (current.globals.has(name)) {
|
|
1659
|
+
return nameId(filePath, name);
|
|
1660
|
+
}
|
|
1661
|
+
if (current.locals.has(name)) {
|
|
1662
|
+
return `${current.funcKey}#${name}`;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return nameId(filePath, name);
|
|
1666
|
+
}
|
|
1667
|
+
function scopeChainOf(filePath, fn) {
|
|
1668
|
+
if (fn === null) {
|
|
1669
|
+
return null;
|
|
1670
|
+
}
|
|
1671
|
+
const reading = scopeReadingOf(fn);
|
|
1672
|
+
return {
|
|
1673
|
+
funcKey: nodeId(filePath, fn),
|
|
1674
|
+
locals: reading.locals,
|
|
1675
|
+
globals: reading.globals,
|
|
1676
|
+
parent: scopeChainOf(filePath, enclosingFunction(fn))
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1564
1679
|
function emitCall(emitter, call) {
|
|
1565
1680
|
add(emitter, "writtenValue", nodeId(emitter.filePath, call));
|
|
1566
1681
|
const callee = field(call, "function");
|
|
1567
|
-
|
|
1682
|
+
const args = field(call, "arguments");
|
|
1683
|
+
if (callee === null || args === null) {
|
|
1568
1684
|
return;
|
|
1569
1685
|
}
|
|
1570
1686
|
const callKey = nodeId(emitter.filePath, call);
|
|
1571
1687
|
add(emitter, "call", callKey, valueKey(emitter, callee));
|
|
1572
|
-
const args = field(call, "arguments");
|
|
1573
|
-
if (args === null) {
|
|
1574
|
-
return;
|
|
1575
|
-
}
|
|
1576
1688
|
let position = 0;
|
|
1577
1689
|
for (const argument of children(args)) {
|
|
1578
1690
|
if (argument.type === "keyword_argument") {
|
|
@@ -1603,11 +1715,7 @@ function valueKey(emitter, value) {
|
|
|
1603
1715
|
if (value.type !== "identifier") {
|
|
1604
1716
|
return nodeId(emitter.filePath, value);
|
|
1605
1717
|
}
|
|
1606
|
-
|
|
1607
|
-
if (enclosing !== null && enclosing.params.has(value.text)) {
|
|
1608
|
-
return `${enclosing.funcKey}#${value.text}`;
|
|
1609
|
-
}
|
|
1610
|
-
return nameId(emitter.filePath, value.text);
|
|
1718
|
+
return nameKey(emitter.filePath, emitter.enclosing, value.text);
|
|
1611
1719
|
}
|
|
1612
1720
|
function emitSequence(emitter, sequence) {
|
|
1613
1721
|
const objectKey = nodeId(emitter.filePath, sequence);
|
|
@@ -1697,7 +1805,6 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1697
1805
|
const funcKey = nodeId(emitter.filePath, fn);
|
|
1698
1806
|
add(emitter, "func", funcKey);
|
|
1699
1807
|
const params = field(fn, "parameters");
|
|
1700
|
-
const declared = parameterNames(fn);
|
|
1701
1808
|
let position = classKey === void 0 ? 0 : -1;
|
|
1702
1809
|
let byPosition = true;
|
|
1703
1810
|
let receiver = null;
|
|
@@ -1720,24 +1827,22 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1720
1827
|
}
|
|
1721
1828
|
position += 1;
|
|
1722
1829
|
}
|
|
1830
|
+
const reading = scopeReadingOf(fn);
|
|
1723
1831
|
const inside = {
|
|
1724
1832
|
...emitter,
|
|
1725
|
-
enclosing: {
|
|
1833
|
+
enclosing: {
|
|
1834
|
+
funcKey,
|
|
1835
|
+
locals: reading.locals,
|
|
1836
|
+
globals: reading.globals,
|
|
1837
|
+
parent: emitter.enclosing
|
|
1838
|
+
}
|
|
1726
1839
|
};
|
|
1840
|
+
emitScopeWrites(inside, reading, false);
|
|
1727
1841
|
const body = field(fn, "body");
|
|
1728
1842
|
if (body === null) {
|
|
1729
1843
|
return funcKey;
|
|
1730
1844
|
}
|
|
1731
|
-
|
|
1732
|
-
for (const child of children(node)) {
|
|
1733
|
-
if (isFunction(child)) {
|
|
1734
|
-
add(emitter, "containsFn", funcKey, nodeId(emitter.filePath, child));
|
|
1735
|
-
continue;
|
|
1736
|
-
}
|
|
1737
|
-
recordNested(child);
|
|
1738
|
-
}
|
|
1739
|
-
};
|
|
1740
|
-
recordNested(body);
|
|
1845
|
+
emitNestedDefinitions(inside, body);
|
|
1741
1846
|
walkExpressions(inside, body, (child) => {
|
|
1742
1847
|
if (child.type === "return_statement") {
|
|
1743
1848
|
const returned = child.namedChildren[0];
|
|
@@ -1748,29 +1853,17 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1748
1853
|
if (child.type === "call") {
|
|
1749
1854
|
add(inside, "bodyCalls", funcKey, nodeId(inside.filePath, child));
|
|
1750
1855
|
}
|
|
1751
|
-
if (child.type === "assignment") {
|
|
1752
|
-
|
|
1856
|
+
if (child.type === "assignment" && receiver !== null) {
|
|
1857
|
+
emitReceiverProperty(inside, child, receiver);
|
|
1753
1858
|
}
|
|
1754
1859
|
emitExpressionFact(inside, child);
|
|
1755
1860
|
});
|
|
1756
1861
|
return funcKey;
|
|
1757
1862
|
}
|
|
1758
|
-
function
|
|
1863
|
+
function emitReceiverProperty(emitter, assignment2, receiver) {
|
|
1759
1864
|
const left = field(assignment2, "left");
|
|
1760
1865
|
const right = field(assignment2, "right");
|
|
1761
|
-
if (left === null || right === null) {
|
|
1762
|
-
return;
|
|
1763
|
-
}
|
|
1764
|
-
if (left.type === "identifier") {
|
|
1765
|
-
add(
|
|
1766
|
-
emitter,
|
|
1767
|
-
"binds",
|
|
1768
|
-
nameId(emitter.filePath, left.text),
|
|
1769
|
-
valueKey(emitter, right)
|
|
1770
|
-
);
|
|
1771
|
-
return;
|
|
1772
|
-
}
|
|
1773
|
-
if (receiver === null || left.type !== "attribute") {
|
|
1866
|
+
if (left === null || right === null || left.type !== "attribute") {
|
|
1774
1867
|
return;
|
|
1775
1868
|
}
|
|
1776
1869
|
const object = field(left, "object");
|
|
@@ -1786,20 +1879,13 @@ function emitBinding(emitter, assignment2, receiver) {
|
|
|
1786
1879
|
valueKey(emitter, right)
|
|
1787
1880
|
);
|
|
1788
1881
|
}
|
|
1789
|
-
function
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
const right = field(assignment2, "right");
|
|
1793
|
-
if (left === null || right === null || left.type !== "identifier") {
|
|
1794
|
-
return;
|
|
1882
|
+
function assignedValue(right) {
|
|
1883
|
+
if (right.type !== "subscript") {
|
|
1884
|
+
return right;
|
|
1795
1885
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
emitter.filePath,
|
|
1800
|
-
left.text,
|
|
1801
|
-
valueKey(emitter, right)
|
|
1802
|
-
);
|
|
1886
|
+
const outer = field(right, "value");
|
|
1887
|
+
const first = fields(right, "subscript")[0];
|
|
1888
|
+
return outer?.text === "Annotated" && first !== void 0 ? first : right;
|
|
1803
1889
|
}
|
|
1804
1890
|
function declaredBy(statement) {
|
|
1805
1891
|
if (statement.type === "decorated_definition") {
|
|
@@ -1843,40 +1929,361 @@ function emitClassFacts(emitter, cls) {
|
|
|
1843
1929
|
}
|
|
1844
1930
|
continue;
|
|
1845
1931
|
}
|
|
1846
|
-
const
|
|
1932
|
+
const memberKey2 = declaredMemberKey(emitter, member, classKey);
|
|
1847
1933
|
const name = field(member, "name");
|
|
1848
|
-
if (
|
|
1849
|
-
add(emitter, "holdsProperty", classKey, name.text,
|
|
1934
|
+
if (memberKey2 !== null && name !== null) {
|
|
1935
|
+
add(emitter, "holdsProperty", classKey, name.text, memberKey2);
|
|
1850
1936
|
}
|
|
1851
1937
|
}
|
|
1852
1938
|
return classKey;
|
|
1853
1939
|
}
|
|
1854
|
-
function
|
|
1855
|
-
const
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1940
|
+
function emitNestedDefinitions(emitter, node) {
|
|
1941
|
+
for (const child of children(node)) {
|
|
1942
|
+
if (isFunction(child)) {
|
|
1943
|
+
emitFunctionFacts(emitter, child);
|
|
1944
|
+
if (emitter.enclosing !== null) {
|
|
1945
|
+
add(
|
|
1946
|
+
emitter,
|
|
1947
|
+
"containsFn",
|
|
1948
|
+
emitter.enclosing.funcKey,
|
|
1949
|
+
nodeId(emitter.filePath, child)
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
continue;
|
|
1953
|
+
}
|
|
1954
|
+
if (child.type === "class_definition") {
|
|
1955
|
+
emitClassFacts(emitter, child);
|
|
1956
|
+
continue;
|
|
1957
|
+
}
|
|
1958
|
+
emitNestedDefinitions(emitter, child);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
var readingsByTree = /* @__PURE__ */ new WeakMap();
|
|
1962
|
+
function scopeReadingOf(fn) {
|
|
1963
|
+
const tree = fn.tree;
|
|
1964
|
+
let byNode = readingsByTree.get(tree);
|
|
1965
|
+
if (byNode === void 0) {
|
|
1966
|
+
byNode = /* @__PURE__ */ new Map();
|
|
1967
|
+
readingsByTree.set(tree, byNode);
|
|
1968
|
+
}
|
|
1969
|
+
const remembered = byNode.get(fn.id);
|
|
1970
|
+
if (remembered !== void 0) {
|
|
1971
|
+
return remembered;
|
|
1972
|
+
}
|
|
1973
|
+
const body = field(fn, "body");
|
|
1974
|
+
const reading = readScope(
|
|
1975
|
+
body !== null && body.type === "block" ? body : null,
|
|
1976
|
+
boundParameterNames(fn)
|
|
1977
|
+
);
|
|
1978
|
+
byNode.set(fn.id, reading);
|
|
1979
|
+
return reading;
|
|
1980
|
+
}
|
|
1981
|
+
var TARGET_PATTERN_TYPES = /* @__PURE__ */ new Set([
|
|
1982
|
+
"pattern_list",
|
|
1983
|
+
"tuple_pattern",
|
|
1984
|
+
"list_pattern"
|
|
1985
|
+
]);
|
|
1986
|
+
function targetNames(target, found = []) {
|
|
1987
|
+
if (target.type === "identifier") {
|
|
1988
|
+
found.push(target);
|
|
1989
|
+
return found;
|
|
1990
|
+
}
|
|
1991
|
+
if (TARGET_PATTERN_TYPES.has(target.type)) {
|
|
1992
|
+
for (const child of children(target)) {
|
|
1993
|
+
targetNames(child, found);
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
return found;
|
|
1997
|
+
}
|
|
1998
|
+
function readAssignment(node, sink) {
|
|
1999
|
+
const left = field(node, "left");
|
|
2000
|
+
const right = field(node, "right");
|
|
2001
|
+
if (left === null) {
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
const written = right === null ? null : assignedValue(right);
|
|
2005
|
+
const names = targetNames(left);
|
|
2006
|
+
for (const name of names) {
|
|
2007
|
+
sink.record(name.text, {
|
|
2008
|
+
// An unpacked target takes one piece of the value, and which piece
|
|
2009
|
+
// is not something the assignment says.
|
|
2010
|
+
value: names.length === 1 ? written : null,
|
|
2011
|
+
given: null,
|
|
2012
|
+
at: node,
|
|
2013
|
+
direct: isDirectStatement(node, sink.bodyOwner)
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
function readAugmentedAssignment(node, sink) {
|
|
2018
|
+
const left = field(node, "left");
|
|
2019
|
+
if (left === null || left.type !== "identifier") {
|
|
2020
|
+
return;
|
|
2021
|
+
}
|
|
2022
|
+
sink.record(left.text, {
|
|
2023
|
+
value: null,
|
|
2024
|
+
given: null,
|
|
2025
|
+
at: node,
|
|
2026
|
+
direct: isDirectStatement(node, sink.bodyOwner)
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
function readIterationTarget(node, sink) {
|
|
2030
|
+
const left = field(node, "left");
|
|
2031
|
+
if (left === null) {
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2034
|
+
for (const name of targetNames(left)) {
|
|
2035
|
+
sink.record(name.text, {
|
|
2036
|
+
value: null,
|
|
2037
|
+
given: null,
|
|
2038
|
+
at: node,
|
|
2039
|
+
direct: false
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
function identifierOf(node) {
|
|
2044
|
+
if (node.type === "identifier") {
|
|
2045
|
+
return node;
|
|
2046
|
+
}
|
|
2047
|
+
return children(node).find((child) => child.type === "identifier") ?? null;
|
|
2048
|
+
}
|
|
2049
|
+
function readAsPattern(node, sink) {
|
|
2050
|
+
const target = field(node, "alias") ?? children(node)[1];
|
|
2051
|
+
const name = target === void 0 ? null : identifierOf(target);
|
|
2052
|
+
if (name === null) {
|
|
2053
|
+
return;
|
|
2054
|
+
}
|
|
2055
|
+
sink.record(name.text, {
|
|
2056
|
+
value: null,
|
|
2057
|
+
given: null,
|
|
2058
|
+
at: node,
|
|
2059
|
+
direct: false
|
|
2060
|
+
});
|
|
2061
|
+
}
|
|
2062
|
+
function readWalrus(node, sink) {
|
|
2063
|
+
const name = field(node, "name");
|
|
2064
|
+
if (name === null || name.type !== "identifier") {
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2067
|
+
sink.record(name.text, {
|
|
2068
|
+
value: field(node, "value"),
|
|
2069
|
+
given: null,
|
|
2070
|
+
at: node,
|
|
2071
|
+
direct: false
|
|
2072
|
+
});
|
|
2073
|
+
}
|
|
2074
|
+
function readGlobalStatement(node, sink) {
|
|
2075
|
+
for (const child of children(node)) {
|
|
2076
|
+
if (child.type === "identifier") {
|
|
2077
|
+
sink.globals.add(child.text);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
function readNonlocalStatement(node, sink) {
|
|
2082
|
+
for (const child of children(node)) {
|
|
2083
|
+
if (child.type === "identifier") {
|
|
2084
|
+
sink.nonlocals.add(child.text);
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
var WRITE_READERS = {
|
|
2089
|
+
assignment: readAssignment,
|
|
2090
|
+
augmented_assignment: readAugmentedAssignment,
|
|
2091
|
+
for_statement: readIterationTarget,
|
|
2092
|
+
for_in_clause: readIterationTarget,
|
|
2093
|
+
as_pattern: readAsPattern,
|
|
2094
|
+
named_expression: readWalrus,
|
|
2095
|
+
global_statement: readGlobalStatement,
|
|
2096
|
+
nonlocal_statement: readNonlocalStatement
|
|
2097
|
+
};
|
|
2098
|
+
function readScope(bodyOwner, parameterNames) {
|
|
2099
|
+
const writes = /* @__PURE__ */ new Map();
|
|
2100
|
+
const globals = /* @__PURE__ */ new Set();
|
|
2101
|
+
const nonlocals = /* @__PURE__ */ new Set();
|
|
2102
|
+
const record = (name, write) => {
|
|
2103
|
+
const existing = writes.get(name);
|
|
2104
|
+
if (existing === void 0) {
|
|
2105
|
+
writes.set(name, [write]);
|
|
1859
2106
|
return;
|
|
1860
2107
|
}
|
|
1861
|
-
|
|
1862
|
-
add(emitter, "exportsAs", filePath, name.text, key);
|
|
2108
|
+
existing.push(write);
|
|
1863
2109
|
};
|
|
1864
|
-
const
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
2110
|
+
const sink = { bodyOwner, globals, nonlocals, record };
|
|
2111
|
+
const visit = (node) => {
|
|
2112
|
+
if (isFunction(node) || node.type === "class_definition") {
|
|
2113
|
+
const name = field(node, "name");
|
|
2114
|
+
if (name !== null) {
|
|
2115
|
+
record(name.text, {
|
|
2116
|
+
value: node,
|
|
2117
|
+
given: null,
|
|
2118
|
+
at: node,
|
|
2119
|
+
direct: isDirectStatement(node, bodyOwner)
|
|
2120
|
+
});
|
|
1875
2121
|
}
|
|
1876
|
-
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
WRITE_READERS[node.type]?.(node, sink);
|
|
2125
|
+
for (const child of children(node)) {
|
|
2126
|
+
visit(child);
|
|
1877
2127
|
}
|
|
1878
2128
|
};
|
|
1879
|
-
|
|
2129
|
+
for (const statement of bodyOwner === null ? [] : children(bodyOwner)) {
|
|
2130
|
+
visit(statement);
|
|
2131
|
+
}
|
|
2132
|
+
const locals = new Set(writes.keys());
|
|
2133
|
+
for (const name of [...globals, ...nonlocals]) {
|
|
2134
|
+
locals.delete(name);
|
|
2135
|
+
}
|
|
2136
|
+
for (const name of parameterNames) {
|
|
2137
|
+
locals.add(name);
|
|
2138
|
+
addParameterWrite(writes.get(name), name);
|
|
2139
|
+
}
|
|
2140
|
+
return { bodyOwner, writes, locals, globals };
|
|
2141
|
+
}
|
|
2142
|
+
function addParameterWrite(later, name) {
|
|
2143
|
+
const first = later?.[0];
|
|
2144
|
+
if (later === void 0 || first === void 0) {
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2147
|
+
later.unshift({ value: null, given: name, at: first.at, direct: false });
|
|
2148
|
+
}
|
|
2149
|
+
function statementOf(node) {
|
|
2150
|
+
let current = node;
|
|
2151
|
+
while (current !== null) {
|
|
2152
|
+
const parent = current.parent;
|
|
2153
|
+
if (parent === null) {
|
|
2154
|
+
return null;
|
|
2155
|
+
}
|
|
2156
|
+
if (parent.type === "block" || parent.type === "module") {
|
|
2157
|
+
return current;
|
|
2158
|
+
}
|
|
2159
|
+
current = parent;
|
|
2160
|
+
}
|
|
2161
|
+
return null;
|
|
2162
|
+
}
|
|
2163
|
+
function isDirectStatement(node, bodyOwner) {
|
|
2164
|
+
if (bodyOwner === null) {
|
|
2165
|
+
return false;
|
|
2166
|
+
}
|
|
2167
|
+
const statement = statementOf(node);
|
|
2168
|
+
return statement !== null && statement.parent?.id === bodyOwner.id;
|
|
2169
|
+
}
|
|
2170
|
+
var UNREAD_PARENTS = /* @__PURE__ */ new Set([
|
|
2171
|
+
"as_pattern_target",
|
|
2172
|
+
"global_statement",
|
|
2173
|
+
"nonlocal_statement",
|
|
2174
|
+
"pattern_list",
|
|
2175
|
+
"tuple_pattern",
|
|
2176
|
+
"list_pattern",
|
|
2177
|
+
"dotted_name"
|
|
2178
|
+
]);
|
|
2179
|
+
var UNREAD_FIELDS = {
|
|
2180
|
+
assignment: "left",
|
|
2181
|
+
augmented_assignment: "left",
|
|
2182
|
+
for_statement: "left",
|
|
2183
|
+
for_in_clause: "left",
|
|
2184
|
+
named_expression: "name",
|
|
2185
|
+
function_definition: "name",
|
|
2186
|
+
class_definition: "name",
|
|
2187
|
+
attribute: "attribute",
|
|
2188
|
+
keyword_argument: "name"
|
|
2189
|
+
};
|
|
2190
|
+
function isNameRead(name) {
|
|
2191
|
+
const parent = name.parent;
|
|
2192
|
+
if (parent === null) {
|
|
2193
|
+
return true;
|
|
2194
|
+
}
|
|
2195
|
+
if (UNREAD_PARENTS.has(parent.type)) {
|
|
2196
|
+
return false;
|
|
2197
|
+
}
|
|
2198
|
+
const fieldName = UNREAD_FIELDS[parent.type];
|
|
2199
|
+
return fieldName === void 0 || field(parent, fieldName)?.id !== name.id;
|
|
2200
|
+
}
|
|
2201
|
+
var READ_FIRST = {
|
|
2202
|
+
call: "function",
|
|
2203
|
+
attribute: "object"
|
|
2204
|
+
};
|
|
2205
|
+
function readFirst(node) {
|
|
2206
|
+
if (node.type === "parenthesized_expression") {
|
|
2207
|
+
return children(node)[0] ?? null;
|
|
2208
|
+
}
|
|
2209
|
+
const fieldName = READ_FIRST[node.type];
|
|
2210
|
+
return fieldName === void 0 ? null : field(node, fieldName);
|
|
2211
|
+
}
|
|
2212
|
+
var NAME_READS = {
|
|
2213
|
+
nameTypes: /* @__PURE__ */ new Set(["identifier"]),
|
|
2214
|
+
laterBodies: LATER_BODY_TYPES,
|
|
2215
|
+
childrenOf: children,
|
|
2216
|
+
isRead: isNameRead,
|
|
2217
|
+
readFirst
|
|
2218
|
+
};
|
|
2219
|
+
var CONSTRUCTION_TYPES = /* @__PURE__ */ new Set([
|
|
2220
|
+
"call",
|
|
2221
|
+
"list",
|
|
2222
|
+
"dictionary",
|
|
2223
|
+
"set",
|
|
2224
|
+
"tuple",
|
|
2225
|
+
"list_comprehension",
|
|
2226
|
+
"dictionary_comprehension",
|
|
2227
|
+
"set_comprehension",
|
|
2228
|
+
"generator_expression"
|
|
2229
|
+
]);
|
|
2230
|
+
function describeWrite(emitter, write, name) {
|
|
2231
|
+
if (write.value === null) {
|
|
2232
|
+
return {
|
|
2233
|
+
value: write.given,
|
|
2234
|
+
placeholder: false,
|
|
2235
|
+
construction: null,
|
|
2236
|
+
narrowsName: false
|
|
2237
|
+
};
|
|
2238
|
+
}
|
|
2239
|
+
return {
|
|
2240
|
+
value: valueKey(emitter, write.value),
|
|
2241
|
+
placeholder: write.value.type === "none",
|
|
2242
|
+
construction: CONSTRUCTION_TYPES.has(write.value.type) ? write.value.text.replace(/\s+/g, " ").trim() : null,
|
|
2243
|
+
narrowsName: write.value.type === "call" && (0, import_resolution2.startsAtName)(write.value, name, NAME_READS)
|
|
2244
|
+
};
|
|
2245
|
+
}
|
|
2246
|
+
function settledValue(emitter, reading, name, writes) {
|
|
2247
|
+
const only = writes.length === 1 ? writes[0] : void 0;
|
|
2248
|
+
if (only !== void 0) {
|
|
2249
|
+
return only.value === null ? only.given : valueKey(emitter, only.value);
|
|
2250
|
+
}
|
|
2251
|
+
return (0, import_resolution2.valueLeftByWrites)(
|
|
2252
|
+
writes.map((write) => describeWrite(emitter, write, name)),
|
|
2253
|
+
(0, import_resolution2.writesRunInOrder)(reading.bodyOwner, name, writes, NAME_READS)
|
|
2254
|
+
);
|
|
2255
|
+
}
|
|
2256
|
+
function emitScopeWrites(emitter, reading, atModule) {
|
|
2257
|
+
for (const [name, writes] of reading.writes) {
|
|
2258
|
+
const settled = settledValue(emitter, reading, name, writes);
|
|
2259
|
+
const key = nameKey(emitter.filePath, emitter.enclosing, name);
|
|
2260
|
+
if (settled === null) {
|
|
2261
|
+
emitCandidates(emitter, key, name, writes);
|
|
2262
|
+
continue;
|
|
2263
|
+
}
|
|
2264
|
+
add(emitter, writes.length === 1 ? "binds" : "endsHolding", key, settled);
|
|
2265
|
+
if (atModule) {
|
|
2266
|
+
add(emitter, "exportsAs", emitter.filePath, name, settled);
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
function emitCandidates(emitter, key, name, writes) {
|
|
2271
|
+
for (const write of writes) {
|
|
2272
|
+
if (write.value === null) {
|
|
2273
|
+
if (write.given === null) {
|
|
2274
|
+
add(emitter, "writesUnstated", key);
|
|
2275
|
+
}
|
|
2276
|
+
continue;
|
|
2277
|
+
}
|
|
2278
|
+
if (!describeWrite(emitter, write, name).narrowsName) {
|
|
2279
|
+
add(emitter, "mayHold", key, valueKey(emitter, write.value));
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
function emitValueFacts(db, filePath, root) {
|
|
2284
|
+
const emitter = { db, filePath, enclosing: null };
|
|
2285
|
+
emitNestedDefinitions(emitter, root);
|
|
2286
|
+
emitScopeWrites(emitter, readScope(root, []), true);
|
|
1880
2287
|
emitExpressionFacts(emitter, root);
|
|
1881
2288
|
}
|
|
1882
2289
|
|
|
@@ -1962,7 +2369,7 @@ function resolveModule(importingFile, spec, options) {
|
|
|
1962
2369
|
}
|
|
1963
2370
|
|
|
1964
2371
|
// src/values/evaluator.ts
|
|
1965
|
-
var
|
|
2372
|
+
var import_resolution3 = require("@suss/resolution");
|
|
1966
2373
|
var import_values3 = require("@suss/values");
|
|
1967
2374
|
|
|
1968
2375
|
// src/values/lowering.ts
|
|
@@ -1989,7 +2396,7 @@ function pythonLowering(options) {
|
|
|
1989
2396
|
return {
|
|
1990
2397
|
idOf: (node) => node.id,
|
|
1991
2398
|
expression: (node) => expressionOf(node, originOf2),
|
|
1992
|
-
statement:
|
|
2399
|
+
statement: statementOf2,
|
|
1993
2400
|
siteOf,
|
|
1994
2401
|
functionOf,
|
|
1995
2402
|
writtenTo: (node) => context === null ? null : context.writtenTo(node),
|
|
@@ -2253,7 +2660,7 @@ var STATEMENT_TYPES = {
|
|
|
2253
2660
|
body: blockStatements2(field(node, "body"))
|
|
2254
2661
|
})
|
|
2255
2662
|
};
|
|
2256
|
-
function
|
|
2663
|
+
function statementOf2(node) {
|
|
2257
2664
|
const lower = STATEMENT_TYPES[node.type];
|
|
2258
2665
|
return lower === void 0 ? { kind: "opaque" } : lower(node);
|
|
2259
2666
|
}
|
|
@@ -2750,7 +3157,7 @@ function contextOver(db, nodes) {
|
|
|
2750
3157
|
return null;
|
|
2751
3158
|
}
|
|
2752
3159
|
const answer = writtenValueOf(db, key);
|
|
2753
|
-
return answer === null ? null : (0,
|
|
3160
|
+
return answer === null ? null : (0, import_resolution3.nodeOfKey)(rootsByFile, answer);
|
|
2754
3161
|
},
|
|
2755
3162
|
callable: (call) => {
|
|
2756
3163
|
const callee = field(call, "function");
|
|
@@ -2879,7 +3286,7 @@ function composedPrefixOf(index, construction, routerPath) {
|
|
|
2879
3286
|
return { kind: "composed", value: composed.value + ownPrefix.value };
|
|
2880
3287
|
}
|
|
2881
3288
|
function composedMountPrefix(index, construction) {
|
|
2882
|
-
const paths = (0,
|
|
3289
|
+
const paths = (0, import_resolution4.mountPathsOf)(mountEdgesOf(index), construction.valueKey);
|
|
2883
3290
|
if (paths === null) {
|
|
2884
3291
|
return {
|
|
2885
3292
|
kind: "abstain",
|
|
@@ -3302,9 +3709,13 @@ function constructionThroughFacts(name, scope, scan) {
|
|
|
3302
3709
|
if (binding.kind !== "assignment" && binding.kind !== "importFrom") {
|
|
3303
3710
|
return null;
|
|
3304
3711
|
}
|
|
3305
|
-
const
|
|
3306
|
-
|
|
3307
|
-
|
|
3712
|
+
const nameKey2 = nameKeyIn(
|
|
3713
|
+
scan.bound.file,
|
|
3714
|
+
scope.kind === "function" ? scope.node : enclosingFunction(scope.node),
|
|
3715
|
+
name
|
|
3716
|
+
);
|
|
3717
|
+
const constructionKey2 = subjectConstructions(facts, [nameKey2]).get(
|
|
3718
|
+
nameKey2
|
|
3308
3719
|
)?.constructionKey;
|
|
3309
3720
|
return constructionKey2 === void 0 ? null : scan.index.byValueKey.get(constructionKey2) ?? null;
|
|
3310
3721
|
}
|
|
@@ -3375,11 +3786,15 @@ var WALK_DESCENTS = {
|
|
|
3375
3786
|
scan,
|
|
3376
3787
|
visit
|
|
3377
3788
|
);
|
|
3378
|
-
}
|
|
3789
|
+
},
|
|
3790
|
+
if_statement: descendInPlace,
|
|
3791
|
+
try_statement: descendInPlace,
|
|
3792
|
+
while_statement: descendInPlace,
|
|
3793
|
+
with_statement: descendInPlace,
|
|
3794
|
+
match_statement: descendInPlace
|
|
3379
3795
|
};
|
|
3380
|
-
function
|
|
3381
|
-
|
|
3382
|
-
return body === null ? [] : bodyStatements(body);
|
|
3796
|
+
function descendInPlace(stmt, position, scan, visit) {
|
|
3797
|
+
walkStatements(nestedStatements(stmt), position, scan, visit);
|
|
3383
3798
|
}
|
|
3384
3799
|
function walkStatements(statements, position, scan, visit) {
|
|
3385
3800
|
for (const stmt of statements) {
|
|
@@ -3391,11 +3806,11 @@ function walkStatements(statements, position, scan, visit) {
|
|
|
3391
3806
|
visit(stmt, position, scan);
|
|
3392
3807
|
}
|
|
3393
3808
|
}
|
|
3394
|
-
function
|
|
3809
|
+
function targetNames2(node) {
|
|
3395
3810
|
if (node.type === "identifier") {
|
|
3396
3811
|
return [node.text];
|
|
3397
3812
|
}
|
|
3398
|
-
return bodyStatements(node).flatMap(
|
|
3813
|
+
return bodyStatements(node).flatMap(targetNames2);
|
|
3399
3814
|
}
|
|
3400
3815
|
function sequenceElementNames(node) {
|
|
3401
3816
|
if (node === null || node.type !== "list" && node.type !== "tuple") {
|
|
@@ -3432,7 +3847,7 @@ function loopBindingsOf(stmt, position, scan) {
|
|
|
3432
3847
|
});
|
|
3433
3848
|
return bindings;
|
|
3434
3849
|
}
|
|
3435
|
-
for (const name of
|
|
3850
|
+
for (const name of targetNames2(left)) {
|
|
3436
3851
|
bindings.set(name, { kind: "unenumerable", location });
|
|
3437
3852
|
}
|
|
3438
3853
|
return bindings;
|
|
@@ -4460,7 +4875,7 @@ function rawSqlEffects(calls, options) {
|
|
|
4460
4875
|
binding: (0, import_ir_core.storageBinding)({
|
|
4461
4876
|
recognition: `python-${pattern.module}`,
|
|
4462
4877
|
storageSystem: pattern.storageSystem,
|
|
4463
|
-
scope:
|
|
4878
|
+
scope: "default",
|
|
4464
4879
|
container: access.table
|
|
4465
4880
|
}),
|
|
4466
4881
|
callee: field(call, "function")?.text ?? "",
|
|
@@ -4604,16 +5019,23 @@ function typeNameOf(annotation) {
|
|
|
4604
5019
|
if (quoted !== null) {
|
|
4605
5020
|
return quoted;
|
|
4606
5021
|
}
|
|
5022
|
+
if (annotation.type === "binary_operator") {
|
|
5023
|
+
const named = [field(annotation, "left"), field(annotation, "right")].find(
|
|
5024
|
+
(side) => side !== null && side.type !== "none"
|
|
5025
|
+
);
|
|
5026
|
+
return named === void 0 || named === null ? null : typeNameOf(named);
|
|
5027
|
+
}
|
|
4607
5028
|
if (annotation.type === "generic_type") {
|
|
4608
5029
|
const outer = annotation.namedChildren[0];
|
|
4609
5030
|
const first = genericTypeArgs(annotation)[0];
|
|
4610
5031
|
if ((outer?.text === "Annotated" || outer?.text === "Optional") && first !== void 0) {
|
|
4611
5032
|
return typeNameOf(first);
|
|
4612
5033
|
}
|
|
5034
|
+
return outer?.type === "identifier" ? outer.text : null;
|
|
4613
5035
|
}
|
|
4614
5036
|
return null;
|
|
4615
5037
|
}
|
|
4616
|
-
function typeGivenBy(statement, name) {
|
|
5038
|
+
function typeGivenBy(statement, name, options) {
|
|
4617
5039
|
if (statement.type === "assignment") {
|
|
4618
5040
|
if (field(statement, "left")?.text !== name) {
|
|
4619
5041
|
return null;
|
|
@@ -4623,8 +5045,7 @@ function typeGivenBy(statement, name) {
|
|
|
4623
5045
|
return typeNameOf(annotation);
|
|
4624
5046
|
}
|
|
4625
5047
|
const right = field(statement, "right");
|
|
4626
|
-
|
|
4627
|
-
return callee?.type === "identifier" ? callee.text : null;
|
|
5048
|
+
return right?.type === "call" ? builtType(right, options) : null;
|
|
4628
5049
|
}
|
|
4629
5050
|
if (statement.type === "as_pattern") {
|
|
4630
5051
|
const alias = field(statement, "alias");
|
|
@@ -4634,7 +5055,34 @@ function typeGivenBy(statement, name) {
|
|
|
4634
5055
|
}
|
|
4635
5056
|
return null;
|
|
4636
5057
|
}
|
|
4637
|
-
function
|
|
5058
|
+
function builtType(call, options) {
|
|
5059
|
+
const root = rootOf(call);
|
|
5060
|
+
const callee = field(root, "function");
|
|
5061
|
+
if (callee?.type === "identifier") {
|
|
5062
|
+
return isClassName(callee.text) ? callee.text : resolvedReturnType(options, callee);
|
|
5063
|
+
}
|
|
5064
|
+
const object = callee?.type === "attribute" ? field(callee, "object") : null;
|
|
5065
|
+
if (object?.type === "identifier" && isClassName(object.text)) {
|
|
5066
|
+
return object.text;
|
|
5067
|
+
}
|
|
5068
|
+
const args = field(root, "arguments");
|
|
5069
|
+
const first = (args === null ? [] : children(args))[0];
|
|
5070
|
+
if (first?.type === "identifier" && isClassName(first.text)) {
|
|
5071
|
+
return first.text;
|
|
5072
|
+
}
|
|
5073
|
+
return callee === null ? null : resolvedReturnType(options, callee);
|
|
5074
|
+
}
|
|
5075
|
+
function resolvedReturnType(options, callee) {
|
|
5076
|
+
const settled = settledCallee(options, callee);
|
|
5077
|
+
return settled === void 0 ? null : returnTypeName(options.definitionAt(settled));
|
|
5078
|
+
}
|
|
5079
|
+
function settledCallee(options, callee) {
|
|
5080
|
+
const key = readKey(options.filePath, callee, enclosingFunction(callee));
|
|
5081
|
+
resolveCalls(options.facts, [key]);
|
|
5082
|
+
const resolved = options.facts.facts("wantedResolves").filter((row) => String(row[0]) === key).map((row) => String(row[1]));
|
|
5083
|
+
return resolved.length === 1 ? resolved[0] : void 0;
|
|
5084
|
+
}
|
|
5085
|
+
function declaredTypeName(name, from, options) {
|
|
4638
5086
|
const fn = enclosingFunction(from);
|
|
4639
5087
|
if (fn === null) {
|
|
4640
5088
|
return null;
|
|
@@ -4647,7 +5095,7 @@ function declaredTypeName(name, from) {
|
|
|
4647
5095
|
}
|
|
4648
5096
|
}
|
|
4649
5097
|
const visit = (node) => {
|
|
4650
|
-
const given = typeGivenBy(node, name);
|
|
5098
|
+
const given = typeGivenBy(node, name, options);
|
|
4651
5099
|
if (given !== null) {
|
|
4652
5100
|
return given;
|
|
4653
5101
|
}
|
|
@@ -4676,16 +5124,27 @@ function typedReceiverPattern(options, chain) {
|
|
|
4676
5124
|
if (receiver === null) {
|
|
4677
5125
|
return void 0;
|
|
4678
5126
|
}
|
|
4679
|
-
const typeName = declaredTypeName(receiver, chain.root);
|
|
5127
|
+
const typeName = declaredTypeName(receiver, chain.root, options);
|
|
4680
5128
|
if (typeName === null) {
|
|
4681
5129
|
return void 0;
|
|
4682
5130
|
}
|
|
4683
|
-
const
|
|
4684
|
-
|
|
4685
|
-
|
|
5131
|
+
const typeKey = `${options.filePath}#${typeName}`;
|
|
5132
|
+
const imported = options.facts.facts("pyImportedName").find((row) => String(row[0]) === typeKey);
|
|
5133
|
+
const direct = imported === void 0 ? void 0 : queryTypePattern(options, String(imported[1]), String(imported[2]));
|
|
5134
|
+
if (direct !== void 0) {
|
|
5135
|
+
return direct;
|
|
4686
5136
|
}
|
|
5137
|
+
for (const origin of originsOf(options.facts, typeKey)) {
|
|
5138
|
+
const pattern = queryTypePattern(options, origin.module, origin.name);
|
|
5139
|
+
if (pattern !== void 0) {
|
|
5140
|
+
return pattern;
|
|
5141
|
+
}
|
|
5142
|
+
}
|
|
5143
|
+
return void 0;
|
|
5144
|
+
}
|
|
5145
|
+
function queryTypePattern(options, module2, name) {
|
|
4687
5146
|
return options.patterns.find(
|
|
4688
|
-
(pattern) =>
|
|
5147
|
+
(pattern) => module2 === pattern.module && pattern.queryTypes.includes(name)
|
|
4689
5148
|
);
|
|
4690
5149
|
}
|
|
4691
5150
|
function fieldsOf(chain, valueMethods) {
|
|
@@ -4731,16 +5190,80 @@ function keywordNames(call) {
|
|
|
4731
5190
|
}
|
|
4732
5191
|
}
|
|
4733
5192
|
}
|
|
4734
|
-
return picked;
|
|
5193
|
+
return picked;
|
|
5194
|
+
}
|
|
5195
|
+
function selectorOf(chain, valueMethods) {
|
|
5196
|
+
return [
|
|
5197
|
+
...new Set(
|
|
5198
|
+
laterCalls(chain).filter((call) => !valueMethods.includes(methodNameOf(call))).flatMap(keywordNames)
|
|
5199
|
+
)
|
|
5200
|
+
];
|
|
5201
|
+
}
|
|
5202
|
+
var TABLE_METHODS = ["select_from", "join"];
|
|
5203
|
+
function modelOf(chain, options) {
|
|
5204
|
+
const fromRoot = modelArgument(chain.root, chain.root, options);
|
|
5205
|
+
if (fromRoot !== null) {
|
|
5206
|
+
return fromRoot;
|
|
5207
|
+
}
|
|
5208
|
+
for (const call of laterCalls(chain)) {
|
|
5209
|
+
if (TABLE_METHODS.includes(methodNameOf(call))) {
|
|
5210
|
+
const named = modelArgument(call, chain.root, options);
|
|
5211
|
+
if (named !== null) {
|
|
5212
|
+
return named;
|
|
5213
|
+
}
|
|
5214
|
+
}
|
|
5215
|
+
}
|
|
5216
|
+
return isClassName(chain.subject) ? chain.subject : null;
|
|
5217
|
+
}
|
|
5218
|
+
function modelArgument(call, from, options) {
|
|
5219
|
+
const args = field(call, "arguments");
|
|
5220
|
+
const first = (args === null ? [] : children(args)).find(
|
|
5221
|
+
(argument) => argument.type !== "keyword_argument"
|
|
5222
|
+
);
|
|
5223
|
+
return first === void 0 ? null : modelNamed(first, from, options);
|
|
5224
|
+
}
|
|
5225
|
+
function modelNamed(node, from, options) {
|
|
5226
|
+
if (node.type === "identifier") {
|
|
5227
|
+
if (isClassName(node.text)) {
|
|
5228
|
+
return node.text;
|
|
5229
|
+
}
|
|
5230
|
+
const declared = declaredTypeName(node.text, from, options);
|
|
5231
|
+
return declared === null ? null : classBehind(declared, options);
|
|
5232
|
+
}
|
|
5233
|
+
if (node.type === "attribute") {
|
|
5234
|
+
const property = field(node, "attribute");
|
|
5235
|
+
if (property !== null && isClassName(property.text)) {
|
|
5236
|
+
return property.text;
|
|
5237
|
+
}
|
|
5238
|
+
const object = field(node, "object");
|
|
5239
|
+
return object === null ? null : modelNamed(object, from, options);
|
|
5240
|
+
}
|
|
5241
|
+
if (node.type === "call") {
|
|
5242
|
+
const callee = field(node, "function");
|
|
5243
|
+
const built = callee === null ? null : modelNamed(callee, from, options);
|
|
5244
|
+
return built ?? modelArgument(node, from, options);
|
|
5245
|
+
}
|
|
5246
|
+
return null;
|
|
4735
5247
|
}
|
|
4736
|
-
function
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
)
|
|
4741
|
-
|
|
5248
|
+
function classBehind(typeName, options) {
|
|
5249
|
+
const key = `${options.filePath}#${typeName}`;
|
|
5250
|
+
originsOf(options.facts, key);
|
|
5251
|
+
const reached = new Set(
|
|
5252
|
+
options.facts.facts("wantedComesTo").filter((row) => String(row[0]) === key).map((row) => String(row[1]))
|
|
5253
|
+
);
|
|
5254
|
+
const classes = new Set(
|
|
5255
|
+
options.facts.facts("objectValue").map((row) => String(row[0])).filter((value) => reached.has(value))
|
|
5256
|
+
);
|
|
5257
|
+
const exported = options.facts.facts("exportsAs").find((row) => classes.has(String(row[2])));
|
|
5258
|
+
if (exported !== void 0) {
|
|
5259
|
+
return String(exported[1]);
|
|
5260
|
+
}
|
|
5261
|
+
return isClassName(typeName) ? typeName : null;
|
|
4742
5262
|
}
|
|
4743
|
-
function
|
|
5263
|
+
function isClassName(name) {
|
|
5264
|
+
return /^[A-Z][A-Za-z0-9_]*$/.test(name) && name !== name.toUpperCase();
|
|
5265
|
+
}
|
|
5266
|
+
function effectFor(pattern, chain, operation, options) {
|
|
4744
5267
|
const valueMethods = pattern.valueMethods ?? [];
|
|
4745
5268
|
const picked = selectorOf(chain, valueMethods);
|
|
4746
5269
|
return {
|
|
@@ -4748,8 +5271,8 @@ function effectFor(pattern, chain, operation) {
|
|
|
4748
5271
|
binding: (0, import_ir_core2.storageBinding)({
|
|
4749
5272
|
recognition: "python-storage",
|
|
4750
5273
|
storageSystem: pattern.storageSystem,
|
|
4751
|
-
scope:
|
|
4752
|
-
container: chain
|
|
5274
|
+
scope: "default",
|
|
5275
|
+
container: modelOf(chain, options)
|
|
4753
5276
|
}),
|
|
4754
5277
|
callee: chain.last.text,
|
|
4755
5278
|
interaction: {
|
|
@@ -4766,23 +5289,14 @@ function fileOf(key) {
|
|
|
4766
5289
|
return at === -1 ? key : key.slice(0, at);
|
|
4767
5290
|
}
|
|
4768
5291
|
function returnTypeName(node) {
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
}
|
|
4772
|
-
const annotation = field(node, "return_type");
|
|
4773
|
-
if (annotation === null) {
|
|
4774
|
-
return null;
|
|
4775
|
-
}
|
|
4776
|
-
return annotation.type === "subscript" ? field(annotation, "value")?.text ?? null : annotation.text;
|
|
5292
|
+
const annotation = node === void 0 ? null : field(node, "return_type");
|
|
5293
|
+
return annotation === null ? null : typeNameOf(annotation);
|
|
4777
5294
|
}
|
|
4778
5295
|
function storageCallees(calls, filePath, couldMatch) {
|
|
4779
5296
|
return chainsIn(calls).filter((chain) => couldMatch.has(methodName(chain.root))).map((chain) => field(chain.root, "function")).filter((callee) => callee !== null).map((callee) => readKey(filePath, callee, enclosingFunction(callee)));
|
|
4780
5297
|
}
|
|
4781
5298
|
function resolvedMethodPattern(options, callee) {
|
|
4782
|
-
const
|
|
4783
|
-
(row) => String(row[0]) === readKey(options.filePath, callee, enclosingFunction(callee))
|
|
4784
|
-
).map((row) => String(row[1]));
|
|
4785
|
-
const settled = resolved.length === 1 ? resolved[0] : void 0;
|
|
5299
|
+
const settled = settledCallee(options, callee);
|
|
4786
5300
|
if (settled === void 0) {
|
|
4787
5301
|
return void 0;
|
|
4788
5302
|
}
|
|
@@ -4809,14 +5323,9 @@ function matchedChains(calls, options) {
|
|
|
4809
5323
|
if (chains.length === 0) {
|
|
4810
5324
|
return [];
|
|
4811
5325
|
}
|
|
4812
|
-
const alreadyAsked = new Set(
|
|
4813
|
-
options.facts.facts("wanted").map((row) => String(row[0]))
|
|
4814
|
-
);
|
|
4815
5326
|
resolveCalls(
|
|
4816
5327
|
options.facts,
|
|
4817
|
-
storageCallees(calls, options.filePath, options.couldMatch)
|
|
4818
|
-
(key) => !alreadyAsked.has(key)
|
|
4819
|
-
)
|
|
5328
|
+
storageCallees(calls, options.filePath, options.couldMatch)
|
|
4820
5329
|
);
|
|
4821
5330
|
const matched = [];
|
|
4822
5331
|
for (const chain of chains) {
|
|
@@ -4859,7 +5368,7 @@ function storageCallIds(calls, options) {
|
|
|
4859
5368
|
}
|
|
4860
5369
|
function storageEffects(calls, options) {
|
|
4861
5370
|
return matchedChains(calls, options).flatMap(
|
|
4862
|
-
({ chain, pattern, operation }) => operation === null ? [] : [effectFor(pattern, chain, operation)]
|
|
5371
|
+
({ chain, pattern, operation }) => operation === null ? [] : [effectFor(pattern, chain, operation, options)]
|
|
4863
5372
|
);
|
|
4864
5373
|
}
|
|
4865
5374
|
|
|
@@ -5155,6 +5664,7 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
5155
5664
|
pattern
|
|
5156
5665
|
),
|
|
5157
5666
|
storage: options.storage,
|
|
5667
|
+
importedDefinition: options.importedDefinition,
|
|
5158
5668
|
wrappers: wrappersAround(
|
|
5159
5669
|
pattern,
|
|
5160
5670
|
pack,
|
|
@@ -5484,7 +5994,10 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
5484
5994
|
if (functionName === void 0) {
|
|
5485
5995
|
return [];
|
|
5486
5996
|
}
|
|
5487
|
-
const ctx = createAnnotationContext(
|
|
5997
|
+
const ctx = createAnnotationContext(
|
|
5998
|
+
module2.scopeFor,
|
|
5999
|
+
options.importedDefinition ?? null
|
|
6000
|
+
);
|
|
5488
6001
|
return readRoutePaths(
|
|
5489
6002
|
pattern,
|
|
5490
6003
|
readPathArgument(classification, options),
|
|
@@ -5523,6 +6036,7 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
5523
6036
|
),
|
|
5524
6037
|
definitionsCtx: ctx,
|
|
5525
6038
|
storage: options.storage,
|
|
6039
|
+
importedDefinition: options.importedDefinition,
|
|
5526
6040
|
wrappers: wrappersAround(
|
|
5527
6041
|
pattern,
|
|
5528
6042
|
pack,
|
|
@@ -5620,7 +6134,10 @@ function buildRouteUnit(options) {
|
|
|
5620
6134
|
storage: storageLookup
|
|
5621
6135
|
} = options;
|
|
5622
6136
|
const template = (0, import_extractor5.valueToReadFurtherFrom)(routePath);
|
|
5623
|
-
const ctx = definitionsCtx ?? createAnnotationContext(
|
|
6137
|
+
const ctx = definitionsCtx ?? createAnnotationContext(
|
|
6138
|
+
module2.scopeFor,
|
|
6139
|
+
options.importedDefinition ?? null
|
|
6140
|
+
);
|
|
5624
6141
|
const parameters = readParameters(
|
|
5625
6142
|
definitionNode,
|
|
5626
6143
|
enclosingScope,
|
|
@@ -5701,7 +6218,7 @@ function buildRouteUnit(options) {
|
|
|
5701
6218
|
declaredContract: null,
|
|
5702
6219
|
readings: [
|
|
5703
6220
|
routePath,
|
|
5704
|
-
...unreadRoleReadings(parameters, rangeOf(definitionNode)),
|
|
6221
|
+
...template === null ? unreadRoleReadings(parameters, rangeOf(definitionNode)) : [],
|
|
5705
6222
|
...responseShape.passedOver
|
|
5706
6223
|
],
|
|
5707
6224
|
...collectedDefinitions(ctx) !== null ? { definitions: collectedDefinitions(ctx) } : {},
|
|
@@ -5796,7 +6313,7 @@ function readParameter(param, scope, ctx, pathParamNames, requestBodyFromAnnotat
|
|
|
5796
6313
|
}
|
|
5797
6314
|
const { name, typeNode } = info;
|
|
5798
6315
|
const shape = typeNode !== null ? annotationToShape(typeNode, scope, ctx) : null;
|
|
5799
|
-
const role = isInjectedParameter(param, injectedCallees) ? null : roleOf(name, shape, pathParamNames, requestBodyFromAnnotatedClass);
|
|
6316
|
+
const role = isInjectedParameter(param, injectedCallees, scope, ctx) ? null : roleOf(name, shape, pathParamNames, requestBodyFromAnnotatedClass);
|
|
5800
6317
|
return {
|
|
5801
6318
|
name,
|
|
5802
6319
|
position,
|
|
@@ -5830,7 +6347,7 @@ function calleeName2(call) {
|
|
|
5830
6347
|
}
|
|
5831
6348
|
return null;
|
|
5832
6349
|
}
|
|
5833
|
-
function isInjectedParameter(param, injectedCallees) {
|
|
6350
|
+
function isInjectedParameter(param, injectedCallees, scope, ctx) {
|
|
5834
6351
|
if (injectedCallees.size === 0) {
|
|
5835
6352
|
return false;
|
|
5836
6353
|
}
|
|
@@ -5844,25 +6361,33 @@ function isInjectedParameter(param, injectedCallees) {
|
|
|
5844
6361
|
if (callsAnInjector(field(param, "value"))) {
|
|
5845
6362
|
return true;
|
|
5846
6363
|
}
|
|
5847
|
-
const
|
|
6364
|
+
const followed = /* @__PURE__ */ new Set();
|
|
6365
|
+
const containsInjectorCall = (node, nodeScope, depth) => {
|
|
5848
6366
|
if (node === null || depth > MAX_ANNOTATION_DEPTH) {
|
|
5849
6367
|
return false;
|
|
5850
6368
|
}
|
|
5851
6369
|
if (callsAnInjector(node)) {
|
|
5852
6370
|
return true;
|
|
5853
6371
|
}
|
|
6372
|
+
if (node.type === "identifier" && !followed.has(node.id)) {
|
|
6373
|
+
followed.add(node.id);
|
|
6374
|
+
const alias = aliasValueOf(node.text, nodeScope, ctx);
|
|
6375
|
+
if (alias !== null && containsInjectorCall(alias.node, alias.scope, 0)) {
|
|
6376
|
+
return true;
|
|
6377
|
+
}
|
|
6378
|
+
}
|
|
5854
6379
|
return node.namedChildren.some(
|
|
5855
|
-
(child) => containsInjectorCall(child, depth + 1)
|
|
6380
|
+
(child) => containsInjectorCall(child, nodeScope, depth + 1)
|
|
5856
6381
|
);
|
|
5857
6382
|
};
|
|
5858
|
-
return containsInjectorCall(field(param, "type"), 0);
|
|
6383
|
+
return containsInjectorCall(field(param, "type"), scope, 0);
|
|
5859
6384
|
}
|
|
5860
6385
|
|
|
5861
6386
|
// src/facts/why.ts
|
|
5862
6387
|
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
5863
6388
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
5864
|
-
var
|
|
5865
|
-
var
|
|
6389
|
+
var import_datalog3 = require("@suss/datalog");
|
|
6390
|
+
var import_resolution6 = require("@suss/resolution");
|
|
5866
6391
|
|
|
5867
6392
|
// src/facts.ts
|
|
5868
6393
|
function unitKey(filePath, range, name) {
|
|
@@ -5880,7 +6405,7 @@ function emitModuleImportFacts(db, filePath, module2, resolverOptions) {
|
|
|
5880
6405
|
if (binding.kind !== "import" && binding.kind !== "importFrom") {
|
|
5881
6406
|
continue;
|
|
5882
6407
|
}
|
|
5883
|
-
const
|
|
6408
|
+
const nameKey2 = `${filePath}#${localName}`;
|
|
5884
6409
|
const moduleText = importedModuleText(
|
|
5885
6410
|
binding.module,
|
|
5886
6411
|
binding.relativeLevel
|
|
@@ -5896,16 +6421,16 @@ function emitModuleImportFacts(db, filePath, module2, resolverOptions) {
|
|
|
5896
6421
|
resolution.status === "resolved" ? "resolved" : resolution.reason
|
|
5897
6422
|
]);
|
|
5898
6423
|
const importedName = binding.kind === "import" ? binding.localName : binding.importedName;
|
|
5899
|
-
db.add("pyImportedName", [
|
|
6424
|
+
db.add("pyImportedName", [nameKey2, moduleText, importedName]);
|
|
5900
6425
|
if (scope.kind === "module") {
|
|
5901
|
-
db.add("exportsAs", [filePath, localName,
|
|
6426
|
+
db.add("exportsAs", [filePath, localName, nameKey2]);
|
|
5902
6427
|
}
|
|
5903
6428
|
if (resolution.status === "resolved") {
|
|
5904
6429
|
db.add("pyImportResolved", [filePath, moduleText, resolution.file]);
|
|
5905
|
-
db.add("imports", [
|
|
6430
|
+
db.add("imports", [nameKey2, resolution.file, importedName]);
|
|
5906
6431
|
continue;
|
|
5907
6432
|
}
|
|
5908
|
-
db.add("imports", [
|
|
6433
|
+
db.add("imports", [nameKey2, moduleText, importedName]);
|
|
5909
6434
|
}
|
|
5910
6435
|
}
|
|
5911
6436
|
for (const openModule of module2.openImports) {
|
|
@@ -5973,7 +6498,7 @@ function parseWith(language, source) {
|
|
|
5973
6498
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
5974
6499
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
5975
6500
|
var import_behavioral_ir5 = require("@suss/behavioral-ir");
|
|
5976
|
-
var
|
|
6501
|
+
var import_datalog2 = require("@suss/datalog");
|
|
5977
6502
|
var import_extractor10 = require("@suss/extractor");
|
|
5978
6503
|
|
|
5979
6504
|
// src/diagnostics.ts
|
|
@@ -5991,271 +6516,300 @@ function buildPythonExtractionReport(args) {
|
|
|
5991
6516
|
});
|
|
5992
6517
|
}
|
|
5993
6518
|
|
|
6519
|
+
// src/importedDefinitions.ts
|
|
6520
|
+
function importedDefinitionLookup(db, files) {
|
|
6521
|
+
const fileOfModuleScope = /* @__PURE__ */ new Map();
|
|
6522
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
6523
|
+
for (const file of files) {
|
|
6524
|
+
fileOfModuleScope.set(file.module.moduleScope.node.id, file.file);
|
|
6525
|
+
byFile.set(file.file, file);
|
|
6526
|
+
}
|
|
6527
|
+
const found = /* @__PURE__ */ new Map();
|
|
6528
|
+
return (scope, name) => {
|
|
6529
|
+
const fromFile = fileOfModuleScope.get(moduleScopeOf(scope).node.id);
|
|
6530
|
+
if (fromFile === void 0) {
|
|
6531
|
+
return null;
|
|
6532
|
+
}
|
|
6533
|
+
const key = `${fromFile}#${name}`;
|
|
6534
|
+
const known = found.get(key);
|
|
6535
|
+
if (known !== void 0) {
|
|
6536
|
+
return known;
|
|
6537
|
+
}
|
|
6538
|
+
const definition = definitionAmong(originsOf(db, key), byFile);
|
|
6539
|
+
found.set(key, definition);
|
|
6540
|
+
return definition;
|
|
6541
|
+
};
|
|
6542
|
+
}
|
|
6543
|
+
function definitionAmong(origins, byFile) {
|
|
6544
|
+
for (const origin of origins) {
|
|
6545
|
+
const file = byFile.get(origin.module);
|
|
6546
|
+
const binding = file?.module.moduleScope.bindings.get(origin.name);
|
|
6547
|
+
if (file === void 0 || binding === void 0) {
|
|
6548
|
+
continue;
|
|
6549
|
+
}
|
|
6550
|
+
const node = definedNodeOf(binding);
|
|
6551
|
+
if (node !== null) {
|
|
6552
|
+
return {
|
|
6553
|
+
node,
|
|
6554
|
+
moduleScope: file.module.moduleScope,
|
|
6555
|
+
scopeFor: file.module.scopeFor
|
|
6556
|
+
};
|
|
6557
|
+
}
|
|
6558
|
+
}
|
|
6559
|
+
return null;
|
|
6560
|
+
}
|
|
6561
|
+
function definedNodeOf(binding) {
|
|
6562
|
+
if (binding.kind === "classDef") {
|
|
6563
|
+
return binding.node;
|
|
6564
|
+
}
|
|
6565
|
+
if (binding.kind === "assignment") {
|
|
6566
|
+
return binding.value;
|
|
6567
|
+
}
|
|
6568
|
+
return null;
|
|
6569
|
+
}
|
|
6570
|
+
|
|
5994
6571
|
// src/reach/closure.ts
|
|
5995
6572
|
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
5996
|
-
var
|
|
6573
|
+
var import_datalog = require("@suss/datalog");
|
|
5997
6574
|
var import_extractor7 = require("@suss/extractor");
|
|
5998
6575
|
|
|
5999
6576
|
// src/reach/resolveCallee.ts
|
|
6000
|
-
var
|
|
6001
|
-
var
|
|
6002
|
-
|
|
6003
|
-
|
|
6577
|
+
var import_resolution5 = require("@suss/resolution");
|
|
6578
|
+
var STOP_FOR = {
|
|
6579
|
+
severalSources: "multipleSources",
|
|
6580
|
+
outsideRun: "outsideRun",
|
|
6581
|
+
unsettled: "unsettledValue",
|
|
6582
|
+
undeclared: "noDeclaration"
|
|
6004
6583
|
};
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6584
|
+
var NO_DECLARATION = {
|
|
6585
|
+
kind: "stopped",
|
|
6586
|
+
reason: "noDeclaration"
|
|
6587
|
+
};
|
|
6588
|
+
function calleeSpellings(calls, ctx) {
|
|
6589
|
+
const spellingOf = /* @__PURE__ */ new Map();
|
|
6590
|
+
const keys = /* @__PURE__ */ new Set();
|
|
6591
|
+
for (const { call, site } of calls) {
|
|
6592
|
+
const spelling = spellingFor(call, site, ctx);
|
|
6593
|
+
spellingOf.set(call.id, spelling);
|
|
6594
|
+
if (spelling.kind === "key") {
|
|
6595
|
+
keys.add(spelling.key);
|
|
6596
|
+
}
|
|
6009
6597
|
}
|
|
6010
|
-
return
|
|
6598
|
+
return { spellingOf, outcomes: (0, import_resolution5.calleeOutcomes)(ctx.facts, [...keys]) };
|
|
6011
6599
|
}
|
|
6012
|
-
function
|
|
6013
|
-
|
|
6014
|
-
|
|
6600
|
+
function resolveCallee2(call, site, ctx, read) {
|
|
6601
|
+
const spelling = read?.spellingOf.get(call.id) ?? spellingFor(call, site, ctx);
|
|
6602
|
+
if (spelling.kind === "stopped") {
|
|
6603
|
+
return spelling;
|
|
6015
6604
|
}
|
|
6016
|
-
const
|
|
6017
|
-
|
|
6605
|
+
const outcome = read?.outcomes.get(spelling.key) ?? (0, import_resolution5.calleeOutcomeOf)(ctx.facts, spelling.key);
|
|
6606
|
+
return asCallee(outcome, site.owner, ctx);
|
|
6607
|
+
}
|
|
6608
|
+
function functionNamed(nameKey2, ctx) {
|
|
6609
|
+
if (assignedElsewhere(ctx.facts, nameKey2)) {
|
|
6018
6610
|
return null;
|
|
6019
6611
|
}
|
|
6020
|
-
const
|
|
6021
|
-
return
|
|
6612
|
+
const outcome = (0, import_resolution5.calleeOutcomeOf)(ctx.facts, nameKey2);
|
|
6613
|
+
return outcome.kind === "function" ? functionAt(outcome.key, ctx) : null;
|
|
6022
6614
|
}
|
|
6023
|
-
function
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
);
|
|
6032
|
-
}
|
|
6033
|
-
if (resolved.kind === "stop") {
|
|
6034
|
-
return { kind: "stopped", reason: resolved.reason };
|
|
6035
|
-
}
|
|
6036
|
-
if (resolved.kind === "package") {
|
|
6037
|
-
return { kind: "stopped", reason: "outsideRun" };
|
|
6615
|
+
function assignedElsewhere(facts, nameKey2) {
|
|
6616
|
+
return (0, import_resolution5.writtenSourcesOf)(facts, nameKey2).some(
|
|
6617
|
+
(source) => !facts.has("func", [source])
|
|
6618
|
+
);
|
|
6619
|
+
}
|
|
6620
|
+
function readThrough(node) {
|
|
6621
|
+
if (node?.type !== "parenthesized_expression") {
|
|
6622
|
+
return node;
|
|
6038
6623
|
}
|
|
6039
|
-
return
|
|
6624
|
+
return readThrough(children(node)[0] ?? null);
|
|
6040
6625
|
}
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
const attribute = field(node, "attribute");
|
|
6046
|
-
if (object === null || attribute === null) {
|
|
6047
|
-
return stop("noDeclaration");
|
|
6048
|
-
}
|
|
6049
|
-
return memberOf(resolveExpression(object, site, ctx), attribute.text, ctx);
|
|
6050
|
-
},
|
|
6051
|
-
// `Service().run()` runs a method on whatever the constructor built.
|
|
6052
|
-
call: (node, site, ctx) => {
|
|
6053
|
-
const callee = field(node, "function");
|
|
6054
|
-
if (callee === null) {
|
|
6055
|
-
return stop("noDeclaration");
|
|
6056
|
-
}
|
|
6057
|
-
const built = resolveExpression(callee, site, ctx);
|
|
6058
|
-
return built.kind === "class" ? built : stop("noDeclaration");
|
|
6059
|
-
},
|
|
6060
|
-
parenthesized_expression: (node, site, ctx) => {
|
|
6061
|
-
const inner = node.namedChildren[0];
|
|
6062
|
-
return inner === null || inner === void 0 ? stop("noDeclaration") : resolveExpression(inner, site, ctx);
|
|
6626
|
+
function spellingFor(call, site, ctx) {
|
|
6627
|
+
const callee = readThrough(field(call, "function"));
|
|
6628
|
+
if (callee === null) {
|
|
6629
|
+
return { kind: "stopped", reason: "noDeclaration" };
|
|
6063
6630
|
}
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6631
|
+
return throughModules(callee, site, ctx) ?? {
|
|
6632
|
+
kind: "key",
|
|
6633
|
+
key: readKey(site.file.file, callee, enclosingFunction(callee))
|
|
6634
|
+
};
|
|
6068
6635
|
}
|
|
6069
|
-
function
|
|
6070
|
-
if (
|
|
6071
|
-
return
|
|
6636
|
+
function asCallee(outcome, owner, ctx) {
|
|
6637
|
+
if (outcome.kind === "function") {
|
|
6638
|
+
return functionCallee(outcome.key, ctx);
|
|
6072
6639
|
}
|
|
6073
|
-
if (
|
|
6074
|
-
return
|
|
6640
|
+
if (outcome.kind === "object") {
|
|
6641
|
+
return constructorOf(outcome.key, ctx);
|
|
6075
6642
|
}
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
return throughOpenImports(site.file, name, ctx, /* @__PURE__ */ new Set());
|
|
6643
|
+
if (outcome.kind === "callerSupplied") {
|
|
6644
|
+
return outcome.key.startsWith(`${owner}#`) ? { kind: "stopped", reason: "callerSupplied" } : { kind: "stopped", reason: "unsettledValue" };
|
|
6079
6645
|
}
|
|
6080
|
-
return
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6646
|
+
return {
|
|
6647
|
+
kind: "stopped",
|
|
6648
|
+
reason: STOP_FOR[outcome.kind] ?? "noDeclaration"
|
|
6649
|
+
};
|
|
6084
6650
|
}
|
|
6085
|
-
function
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
return stop("noDeclaration");
|
|
6651
|
+
function functionCallee(key, ctx) {
|
|
6652
|
+
if (ctx.definitions.get(key)?.type === "lambda") {
|
|
6653
|
+
return { kind: "stopped", reason: "unsettledValue" };
|
|
6089
6654
|
}
|
|
6090
|
-
|
|
6091
|
-
}
|
|
6092
|
-
var BINDING_RESOLVERS = {
|
|
6093
|
-
functionDef: (binding, file) => ({
|
|
6094
|
-
kind: "function",
|
|
6095
|
-
target: reachedFunction(file, binding.node)
|
|
6096
|
-
}),
|
|
6097
|
-
classDef: (binding, file) => ({ kind: "class", file, node: binding.node }),
|
|
6098
|
-
parameter: () => stop("callerSupplied"),
|
|
6099
|
-
// `import a.b.c` binds `a`, and `import a.b.c as m` binds `m` to `a.b.c`.
|
|
6100
|
-
import: (binding, file, _scope, ctx) => moduleNamed(
|
|
6101
|
-
file,
|
|
6102
|
-
binding.localName === binding.module.split(".")[0] ? binding.localName : binding.module,
|
|
6103
|
-
0,
|
|
6104
|
-
ctx
|
|
6105
|
-
),
|
|
6106
|
-
importFrom: (binding, file, _scope, ctx, visited) => memberOf(
|
|
6107
|
-
moduleNamed(file, binding.module, binding.relativeLevel, ctx),
|
|
6108
|
-
binding.importedName,
|
|
6109
|
-
ctx,
|
|
6110
|
-
visited
|
|
6111
|
-
),
|
|
6112
|
-
// `run = load` is an alias worth one hop; anything else is a value.
|
|
6113
|
-
assignment: (binding, file, scope, ctx, visited) => aliasedValue(binding.value, file, scope, ctx, visited),
|
|
6114
|
-
global: () => stop("unsettledValue"),
|
|
6115
|
-
nonlocal: () => stop("unsettledValue")
|
|
6116
|
-
};
|
|
6117
|
-
function resolveBinding(binding, file, scope, ctx, visited) {
|
|
6118
|
-
const resolver = BINDING_RESOLVERS[binding.kind];
|
|
6119
|
-
return resolver(binding, file, scope, ctx, visited);
|
|
6655
|
+
const target = functionAt(key, ctx);
|
|
6656
|
+
return target === null ? NO_DECLARATION : { kind: "followed", target };
|
|
6120
6657
|
}
|
|
6121
|
-
function
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
if (value.type === "identifier") {
|
|
6126
|
-
const binding = resolveName(scope, value.text);
|
|
6127
|
-
if (binding === null || binding.kind === "assignment") {
|
|
6128
|
-
return stop("unsettledValue");
|
|
6129
|
-
}
|
|
6130
|
-
return resolveBinding(binding, file, scope, ctx, visited);
|
|
6131
|
-
}
|
|
6132
|
-
if (value.type === "call") {
|
|
6133
|
-
const callee = field(value, "function");
|
|
6134
|
-
const built = callee === null ? stop("unsettledValue") : aliasedValue(callee, file, scope, ctx, visited);
|
|
6135
|
-
return built.kind === "class" ? built : stop("unsettledValue");
|
|
6136
|
-
}
|
|
6137
|
-
if (value.type === "attribute") {
|
|
6138
|
-
const object = field(value, "object");
|
|
6139
|
-
const attribute = field(value, "attribute");
|
|
6140
|
-
if (object === null || attribute === null) {
|
|
6141
|
-
return stop("unsettledValue");
|
|
6142
|
-
}
|
|
6143
|
-
return memberOf(
|
|
6144
|
-
aliasedValue(object, file, scope, ctx, visited),
|
|
6145
|
-
attribute.text,
|
|
6146
|
-
ctx
|
|
6147
|
-
);
|
|
6658
|
+
function constructorOf(classKey, ctx) {
|
|
6659
|
+
const declared = ctx.facts.lookup("holdsProperty", 0, classKey).find((row) => String(row[1]) === "__init__");
|
|
6660
|
+
if (declared === void 0) {
|
|
6661
|
+
return NO_DECLARATION;
|
|
6148
6662
|
}
|
|
6149
|
-
return
|
|
6663
|
+
return functionCallee(String(declared[2]), ctx);
|
|
6150
6664
|
}
|
|
6151
|
-
function
|
|
6665
|
+
function functionAt(key, ctx) {
|
|
6666
|
+
const node = ctx.definitions.get(key);
|
|
6667
|
+
const file = ctx.filesByPath.get(key.slice(0, key.lastIndexOf(":")));
|
|
6668
|
+
if (node === void 0 || file === void 0) {
|
|
6669
|
+
return null;
|
|
6670
|
+
}
|
|
6152
6671
|
const name = field(node, "name")?.text ?? "<anon>";
|
|
6153
|
-
const
|
|
6672
|
+
const owner = ownerClassOf(node);
|
|
6673
|
+
const ownerName = owner === null ? void 0 : field(owner, "name")?.text;
|
|
6154
6674
|
return {
|
|
6155
6675
|
file,
|
|
6156
6676
|
node,
|
|
6157
6677
|
name,
|
|
6158
|
-
exportPath: ownerName ===
|
|
6678
|
+
exportPath: ownerName === void 0 ? [name] : [ownerName, name]
|
|
6159
6679
|
};
|
|
6160
6680
|
}
|
|
6161
|
-
function
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6681
|
+
function ownerClassOf(node) {
|
|
6682
|
+
for (let up = node.parent; up !== null; up = up.parent) {
|
|
6683
|
+
if (isFunction(up)) {
|
|
6684
|
+
return null;
|
|
6685
|
+
}
|
|
6686
|
+
if (up.type === "class_definition") {
|
|
6687
|
+
return up;
|
|
6688
|
+
}
|
|
6169
6689
|
}
|
|
6170
|
-
|
|
6171
|
-
return file === void 0 ? stop("outsideRun") : { kind: "module", file };
|
|
6690
|
+
return null;
|
|
6172
6691
|
}
|
|
6173
|
-
function
|
|
6174
|
-
if (
|
|
6175
|
-
return
|
|
6692
|
+
function throughModules(callee, site, ctx) {
|
|
6693
|
+
if (callee.type === "identifier") {
|
|
6694
|
+
return resolveName(site.scope, callee.text) === null ? openImportMember(site.file, callee.text, ctx, /* @__PURE__ */ new Set()) : null;
|
|
6176
6695
|
}
|
|
6177
|
-
if (
|
|
6178
|
-
return
|
|
6179
|
-
base.from,
|
|
6180
|
-
base.dotted === "" ? name : `${base.dotted}.${name}`,
|
|
6181
|
-
base.relativeLevel,
|
|
6182
|
-
ctx
|
|
6183
|
-
);
|
|
6696
|
+
if (callee.type !== "attribute") {
|
|
6697
|
+
return null;
|
|
6184
6698
|
}
|
|
6185
|
-
|
|
6186
|
-
|
|
6699
|
+
const object = field(callee, "object");
|
|
6700
|
+
const attribute = field(callee, "attribute");
|
|
6701
|
+
if (object === null || attribute === null) {
|
|
6702
|
+
return null;
|
|
6187
6703
|
}
|
|
6188
|
-
|
|
6189
|
-
|
|
6704
|
+
const base = moduleAt(object, site, ctx);
|
|
6705
|
+
return base === null ? null : memberKey(base, attribute.text, ctx);
|
|
6706
|
+
}
|
|
6707
|
+
function openImportMember(file, name, ctx, visited) {
|
|
6708
|
+
if (visited.has(file.file)) {
|
|
6709
|
+
return null;
|
|
6710
|
+
}
|
|
6711
|
+
visited.add(file.file);
|
|
6712
|
+
const found = /* @__PURE__ */ new Set();
|
|
6713
|
+
for (const spec of file.module.openImports) {
|
|
6714
|
+
const dots = spec.length - spec.replace(/^\.+/, "").length;
|
|
6715
|
+
const opened = moduleNamed(file, spec.slice(dots), dots, ctx);
|
|
6716
|
+
if (opened === null || opened.kind !== "module") {
|
|
6717
|
+
continue;
|
|
6718
|
+
}
|
|
6719
|
+
const member = opened.file.module.moduleScope.bindings.has(name) ? { kind: "key", key: `${opened.file.file}#${name}` } : openImportMember(opened.file, name, ctx, visited);
|
|
6720
|
+
if (member?.kind === "key") {
|
|
6721
|
+
found.add(member.key);
|
|
6722
|
+
}
|
|
6190
6723
|
}
|
|
6191
|
-
|
|
6724
|
+
if (found.size > 1) {
|
|
6725
|
+
return { kind: "stopped", reason: "multipleSources" };
|
|
6726
|
+
}
|
|
6727
|
+
const only = [...found][0];
|
|
6728
|
+
return only === void 0 ? null : { kind: "key", key: only };
|
|
6192
6729
|
}
|
|
6193
|
-
function
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
if (binding === void 0) {
|
|
6197
|
-
return stop("noDeclaration");
|
|
6730
|
+
function moduleAt(node, site, ctx) {
|
|
6731
|
+
if (node.type === "identifier") {
|
|
6732
|
+
return importedModule(node.text, site, ctx);
|
|
6198
6733
|
}
|
|
6199
|
-
if (
|
|
6200
|
-
return
|
|
6201
|
-
kind: "function",
|
|
6202
|
-
target: reachedFunction(file, binding.node, classNode)
|
|
6203
|
-
};
|
|
6734
|
+
if (node.type !== "attribute") {
|
|
6735
|
+
return null;
|
|
6204
6736
|
}
|
|
6205
|
-
|
|
6737
|
+
const object = field(node, "object");
|
|
6738
|
+
const attribute = field(node, "attribute");
|
|
6739
|
+
if (object === null || attribute === null) {
|
|
6740
|
+
return null;
|
|
6741
|
+
}
|
|
6742
|
+
const base = moduleAt(object, site, ctx);
|
|
6743
|
+
return base === null ? null : submoduleOf(base, attribute.text, ctx);
|
|
6206
6744
|
}
|
|
6207
|
-
function
|
|
6208
|
-
const
|
|
6209
|
-
if (
|
|
6210
|
-
|
|
6745
|
+
function importedModule(name, site, ctx) {
|
|
6746
|
+
const binding = resolveName(site.scope, name);
|
|
6747
|
+
if (binding?.kind === "import") {
|
|
6748
|
+
const head = binding.module.split(".")[0];
|
|
6749
|
+
const dotted = binding.localName === head ? binding.localName : binding.module;
|
|
6750
|
+
return moduleNamed(site.file, dotted, 0, ctx);
|
|
6211
6751
|
}
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
if (binding !== void 0) {
|
|
6215
|
-
return resolveBinding(binding, file, file.module.moduleScope, ctx, visited);
|
|
6752
|
+
if (binding?.kind !== "importFrom") {
|
|
6753
|
+
return null;
|
|
6216
6754
|
}
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6755
|
+
const from = moduleNamed(
|
|
6756
|
+
site.file,
|
|
6757
|
+
binding.module,
|
|
6758
|
+
binding.relativeLevel,
|
|
6759
|
+
ctx
|
|
6760
|
+
);
|
|
6761
|
+
return from === null ? null : submoduleOf(from, binding.importedName, ctx);
|
|
6762
|
+
}
|
|
6763
|
+
function submoduleOf(base, name, ctx) {
|
|
6764
|
+
if (base.kind === "package") {
|
|
6765
|
+
return moduleNamed(
|
|
6766
|
+
base.from,
|
|
6767
|
+
base.dotted === "" ? name : `${base.dotted}.${name}`,
|
|
6768
|
+
base.relativeLevel,
|
|
6769
|
+
ctx
|
|
6770
|
+
);
|
|
6222
6771
|
}
|
|
6223
|
-
return
|
|
6772
|
+
return base.file.file.endsWith("__init__.py") ? moduleNamed(base.file, name, 1, ctx) : null;
|
|
6224
6773
|
}
|
|
6225
|
-
function
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
const dots = spec.length - spec.replace(/^\.+/, "").length;
|
|
6229
|
-
const opened = moduleNamed(file, spec.slice(dots), dots, ctx);
|
|
6230
|
-
if (opened.kind !== "module") {
|
|
6231
|
-
continue;
|
|
6232
|
-
}
|
|
6233
|
-
const member = memberOfModule(opened.file, name, ctx, visited);
|
|
6234
|
-
if (member.kind !== "stop") {
|
|
6235
|
-
found.push(member);
|
|
6236
|
-
}
|
|
6774
|
+
function memberKey(base, name, ctx) {
|
|
6775
|
+
if (base.kind === "package") {
|
|
6776
|
+
return null;
|
|
6237
6777
|
}
|
|
6238
|
-
if (
|
|
6239
|
-
return
|
|
6778
|
+
if (base.file.module.moduleScope.bindings.has(name)) {
|
|
6779
|
+
return { kind: "key", key: `${base.file.file}#${name}` };
|
|
6780
|
+
}
|
|
6781
|
+
return openImportMember(base.file, name, ctx, /* @__PURE__ */ new Set());
|
|
6782
|
+
}
|
|
6783
|
+
function moduleNamed(from, module2, relativeLevel, ctx) {
|
|
6784
|
+
const resolution = resolveModule(
|
|
6785
|
+
from.file,
|
|
6786
|
+
{ module: module2, relativeLevel },
|
|
6787
|
+
{ roots: ctx.roots }
|
|
6788
|
+
);
|
|
6789
|
+
if (resolution.status !== "resolved") {
|
|
6790
|
+
return resolution.reason === "external" ? { kind: "package", dotted: module2, relativeLevel, from } : null;
|
|
6240
6791
|
}
|
|
6241
|
-
|
|
6792
|
+
const file = ctx.filesByPath.get(resolution.file);
|
|
6793
|
+
return file === void 0 ? null : { kind: "module", file };
|
|
6242
6794
|
}
|
|
6243
6795
|
|
|
6244
6796
|
// src/reach/closure.ts
|
|
6245
6797
|
var REACHABLE_RULES = [
|
|
6246
|
-
(0,
|
|
6247
|
-
(0,
|
|
6798
|
+
(0, import_datalog.rule)("reachable", [(0, import_datalog.variable)("f")], [(0, import_datalog.lit)("entry", (0, import_datalog.variable)("f"))]),
|
|
6799
|
+
(0, import_datalog.rule)(
|
|
6248
6800
|
"reachable",
|
|
6249
|
-
[(0,
|
|
6250
|
-
[(0,
|
|
6801
|
+
[(0, import_datalog.variable)("g")],
|
|
6802
|
+
[(0, import_datalog.lit)("reachable", (0, import_datalog.variable)("f")), (0, import_datalog.lit)("calls", (0, import_datalog.variable)("f"), (0, import_datalog.variable)("g"))]
|
|
6251
6803
|
)
|
|
6252
6804
|
];
|
|
6253
6805
|
function reachedFunctions(seeds, options) {
|
|
6254
6806
|
const ctx = {
|
|
6255
6807
|
filesByPath: new Map(options.files.map((file) => [file.file, file])),
|
|
6256
|
-
roots: options.roots
|
|
6808
|
+
roots: options.roots,
|
|
6809
|
+
facts: options.facts,
|
|
6810
|
+
definitions: options.definitions
|
|
6257
6811
|
};
|
|
6258
|
-
const db = new
|
|
6812
|
+
const db = new import_datalog.Database();
|
|
6259
6813
|
const functionByKey = /* @__PURE__ */ new Map();
|
|
6260
6814
|
const seedKeys = /* @__PURE__ */ new Set();
|
|
6261
6815
|
const scanned = /* @__PURE__ */ new Set();
|
|
@@ -6275,21 +6829,26 @@ function reachedFunctions(seeds, options) {
|
|
|
6275
6829
|
db.add("entry", [seed.key]);
|
|
6276
6830
|
}
|
|
6277
6831
|
for (; ; ) {
|
|
6278
|
-
(0,
|
|
6832
|
+
(0, import_datalog.evaluate)(db, REACHABLE_RULES);
|
|
6279
6833
|
const frontier = db.facts("reachable").map(([key]) => String(key)).filter((key) => !scanned.has(key));
|
|
6280
6834
|
if (frontier.length === 0) {
|
|
6281
6835
|
break;
|
|
6282
6836
|
}
|
|
6283
|
-
|
|
6837
|
+
const bodies = frontier.flatMap((key) => {
|
|
6284
6838
|
scanned.add(key);
|
|
6285
6839
|
const source = functionByKey.get(key);
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6840
|
+
return source === void 0 ? [] : [{ key, source, ...bodyOf(source) }];
|
|
6841
|
+
});
|
|
6842
|
+
const spellings = calleeSpellings(
|
|
6843
|
+
bodies.flatMap((body) => body.written),
|
|
6844
|
+
ctx
|
|
6845
|
+
);
|
|
6846
|
+
for (const { key, source, body, written } of bodies) {
|
|
6289
6847
|
const scan = scanBody(
|
|
6290
6848
|
source,
|
|
6291
6849
|
ctx,
|
|
6292
|
-
recognizedCallIds(source.node, options.storageFor(source.file))
|
|
6850
|
+
recognizedCallIds(source.node, options.storageFor(source.file)),
|
|
6851
|
+
{ body, written, spellings }
|
|
6293
6852
|
);
|
|
6294
6853
|
if (scan.stops.length > 0) {
|
|
6295
6854
|
stopsByKey.set(key, scan.stops);
|
|
@@ -6355,7 +6914,18 @@ var EMPTY_SCAN = {
|
|
|
6355
6914
|
parameterCalls: [],
|
|
6356
6915
|
passedPositions: /* @__PURE__ */ new Set()
|
|
6357
6916
|
};
|
|
6358
|
-
function
|
|
6917
|
+
function bodyOf(source) {
|
|
6918
|
+
const { file, node } = source;
|
|
6919
|
+
const body = field(node, "body");
|
|
6920
|
+
if (body === null) {
|
|
6921
|
+
return { body, written: [] };
|
|
6922
|
+
}
|
|
6923
|
+
return {
|
|
6924
|
+
body,
|
|
6925
|
+
written: callsWritten(file, body, scopeAt2(file, node), keyOf(source))
|
|
6926
|
+
};
|
|
6927
|
+
}
|
|
6928
|
+
function scanBody(source, ctx, recognized, read) {
|
|
6359
6929
|
const followed = [];
|
|
6360
6930
|
const stops = [];
|
|
6361
6931
|
const placements = new import_behavioral_ir4.TargetPlacements();
|
|
@@ -6364,12 +6934,12 @@ function scanBody(source, ctx, recognized) {
|
|
|
6364
6934
|
const seen = /* @__PURE__ */ new Set();
|
|
6365
6935
|
const parameterCallsSeen = /* @__PURE__ */ new Set();
|
|
6366
6936
|
const { file, node } = source;
|
|
6367
|
-
const
|
|
6368
|
-
if (body === null) {
|
|
6937
|
+
const { written, spellings } = read;
|
|
6938
|
+
if (read.body === null) {
|
|
6369
6939
|
return EMPTY_SCAN;
|
|
6370
6940
|
}
|
|
6371
6941
|
const ownParameters = callParameterNames(node, source.exportPath.length > 1);
|
|
6372
|
-
const recordPassedArgs = (call, callee, calleeKey
|
|
6942
|
+
const recordPassedArgs = (call, callee, calleeKey) => {
|
|
6373
6943
|
const args = field(call, "arguments");
|
|
6374
6944
|
if (args === null) {
|
|
6375
6945
|
return;
|
|
@@ -6378,9 +6948,8 @@ function scanBody(source, ctx, recognized) {
|
|
|
6378
6948
|
if (arg === null || arg.type !== "identifier") {
|
|
6379
6949
|
return;
|
|
6380
6950
|
}
|
|
6381
|
-
const resolved =
|
|
6382
|
-
|
|
6383
|
-
{ file, scope: where.scope, rebound: where.rebound },
|
|
6951
|
+
const resolved = functionNamed(
|
|
6952
|
+
readKey(file.file, arg, enclosingFunction(arg)),
|
|
6384
6953
|
ctx
|
|
6385
6954
|
);
|
|
6386
6955
|
if (resolved === null) {
|
|
@@ -6400,13 +6969,9 @@ function scanBody(source, ctx, recognized) {
|
|
|
6400
6969
|
}
|
|
6401
6970
|
});
|
|
6402
6971
|
};
|
|
6403
|
-
const record = (call,
|
|
6972
|
+
const record = (call, site) => {
|
|
6404
6973
|
const callee = calleeText(call);
|
|
6405
|
-
const outcome = resolveCallee2(
|
|
6406
|
-
call,
|
|
6407
|
-
{ file, scope: where.scope, rebound: where.rebound },
|
|
6408
|
-
ctx
|
|
6409
|
-
);
|
|
6974
|
+
const outcome = resolveCallee2(call, site, ctx, spellings);
|
|
6410
6975
|
const placed = outcome.kind === "followed" ? {
|
|
6411
6976
|
file: outcome.target.file.displayPath,
|
|
6412
6977
|
span: spanOf(outcome.target.node)
|
|
@@ -6415,8 +6980,7 @@ function scanBody(source, ctx, recognized) {
|
|
|
6415
6980
|
recordPassedArgs(
|
|
6416
6981
|
call,
|
|
6417
6982
|
callee,
|
|
6418
|
-
outcome.kind === "followed" ? keyOf(outcome.target) : null
|
|
6419
|
-
where
|
|
6983
|
+
outcome.kind === "followed" ? keyOf(outcome.target) : null
|
|
6420
6984
|
);
|
|
6421
6985
|
if (outcome.kind === "stopped") {
|
|
6422
6986
|
const stopKey = `${outcome.reason}:${callee}`;
|
|
@@ -6439,32 +7003,9 @@ function scanBody(source, ctx, recognized) {
|
|
|
6439
7003
|
followed.push(outcome.target);
|
|
6440
7004
|
}
|
|
6441
7005
|
};
|
|
6442
|
-
(
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
{
|
|
6446
|
-
at: (child, where) => {
|
|
6447
|
-
if (child.type === "call") {
|
|
6448
|
-
record(child, where);
|
|
6449
|
-
}
|
|
6450
|
-
},
|
|
6451
|
-
into: (child, where) => {
|
|
6452
|
-
if (child.type === "function_definition") {
|
|
6453
|
-
return import_extractor7.SKIP_CHILDREN;
|
|
6454
|
-
}
|
|
6455
|
-
if (child.type === "lambda") {
|
|
6456
|
-
return {
|
|
6457
|
-
scope: where.scope,
|
|
6458
|
-
rebound: /* @__PURE__ */ new Set([...where.rebound, ...lambdaParameters(child)])
|
|
6459
|
-
};
|
|
6460
|
-
}
|
|
6461
|
-
return {
|
|
6462
|
-
scope: file.module.scopeFor.get(child.id) ?? where.scope,
|
|
6463
|
-
rebound: where.rebound
|
|
6464
|
-
};
|
|
6465
|
-
}
|
|
6466
|
-
}
|
|
6467
|
-
);
|
|
7006
|
+
for (const { call, site } of written) {
|
|
7007
|
+
record(call, site);
|
|
7008
|
+
}
|
|
6468
7009
|
return {
|
|
6469
7010
|
followed,
|
|
6470
7011
|
stops,
|
|
@@ -6474,6 +7015,18 @@ function scanBody(source, ctx, recognized) {
|
|
|
6474
7015
|
passedPositions
|
|
6475
7016
|
};
|
|
6476
7017
|
}
|
|
7018
|
+
function callsWritten(file, body, outer, owner) {
|
|
7019
|
+
const found = [];
|
|
7020
|
+
(0, import_extractor7.walkDescendants)(body, outer, {
|
|
7021
|
+
at: (child, scope) => {
|
|
7022
|
+
if (child.type === "call") {
|
|
7023
|
+
found.push({ call: child, site: { file, scope, owner } });
|
|
7024
|
+
}
|
|
7025
|
+
},
|
|
7026
|
+
into: (child, scope) => child.type === "function_definition" ? import_extractor7.SKIP_CHILDREN : file.module.scopeFor.get(child.id) ?? scope
|
|
7027
|
+
});
|
|
7028
|
+
return found;
|
|
7029
|
+
}
|
|
6477
7030
|
function scopeAt2(file, node) {
|
|
6478
7031
|
let current = node;
|
|
6479
7032
|
while (current !== null) {
|
|
@@ -6485,40 +7038,6 @@ function scopeAt2(file, node) {
|
|
|
6485
7038
|
}
|
|
6486
7039
|
return file.module.moduleScope;
|
|
6487
7040
|
}
|
|
6488
|
-
var REBINDING_FIELDS = {
|
|
6489
|
-
assignment: "left",
|
|
6490
|
-
augmented_assignment: "left",
|
|
6491
|
-
named_expression: "name",
|
|
6492
|
-
for_statement: "left",
|
|
6493
|
-
for_in_clause: "left",
|
|
6494
|
-
as_pattern: "alias"
|
|
6495
|
-
};
|
|
6496
|
-
function reboundNames(body) {
|
|
6497
|
-
const names = /* @__PURE__ */ new Set();
|
|
6498
|
-
(0, import_extractor7.walkDescendants)(body, null, {
|
|
6499
|
-
at: (node) => {
|
|
6500
|
-
const target = REBINDING_FIELDS[node.type];
|
|
6501
|
-
if (target === void 0 || boundByBinder(node, body)) {
|
|
6502
|
-
return;
|
|
6503
|
-
}
|
|
6504
|
-
const written = field(node, target);
|
|
6505
|
-
if (written !== null) {
|
|
6506
|
-
for (const name of identifiersUnder(written)) {
|
|
6507
|
-
names.add(name);
|
|
6508
|
-
}
|
|
6509
|
-
}
|
|
6510
|
-
},
|
|
6511
|
-
into: (node) => node.type === "function_definition" ? import_extractor7.SKIP_CHILDREN : null
|
|
6512
|
-
});
|
|
6513
|
-
return names;
|
|
6514
|
-
}
|
|
6515
|
-
function boundByBinder(node, body) {
|
|
6516
|
-
if (node.type !== "assignment") {
|
|
6517
|
-
return false;
|
|
6518
|
-
}
|
|
6519
|
-
const statement = node.parent;
|
|
6520
|
-
return field(node, "left")?.type === "identifier" && statement?.type === "expression_statement" && statement.parent?.id === body.id;
|
|
6521
|
-
}
|
|
6522
7041
|
function identifiersUnder(node, found = []) {
|
|
6523
7042
|
if (node.type === "identifier") {
|
|
6524
7043
|
found.push(node.text);
|
|
@@ -6531,10 +7050,6 @@ function identifiersUnder(node, found = []) {
|
|
|
6531
7050
|
}
|
|
6532
7051
|
return found;
|
|
6533
7052
|
}
|
|
6534
|
-
function lambdaParameters(lambda) {
|
|
6535
|
-
const parameters = field(lambda, "parameters");
|
|
6536
|
-
return parameters === null ? [] : identifiersUnder(parameters);
|
|
6537
|
-
}
|
|
6538
7053
|
function libraryUnit(target, options) {
|
|
6539
7054
|
const { file, node, name, exportPath } = target;
|
|
6540
7055
|
const body = field(node, "body");
|
|
@@ -6685,6 +7200,18 @@ var PythonWrapperIndex = class {
|
|
|
6685
7200
|
ownRoutes = /* @__PURE__ */ new Map();
|
|
6686
7201
|
unitsByKey = /* @__PURE__ */ new Map();
|
|
6687
7202
|
unitsByFile = /* @__PURE__ */ new Map();
|
|
7203
|
+
/** The project function a module-level name in this file refers to, or null for anything else. */
|
|
7204
|
+
functionCalled(file, name) {
|
|
7205
|
+
if (this.options.facts === void 0) {
|
|
7206
|
+
return null;
|
|
7207
|
+
}
|
|
7208
|
+
return functionNamed(nameKeyIn(file, null, name), {
|
|
7209
|
+
filesByPath: this.filesByPath,
|
|
7210
|
+
roots: this.options.roots,
|
|
7211
|
+
facts: this.options.facts,
|
|
7212
|
+
definitions: this.options.definitions
|
|
7213
|
+
});
|
|
7214
|
+
}
|
|
6688
7215
|
register(covers, target, declared) {
|
|
6689
7216
|
const registered = this.registered(target, declared);
|
|
6690
7217
|
const table = covers.kind === "everyRoute" ? this.everyRoute : this.ownRoutes;
|
|
@@ -6731,20 +7258,12 @@ var PythonWrapperIndex = class {
|
|
|
6731
7258
|
if (declared.form.type !== "dependency") {
|
|
6732
7259
|
continue;
|
|
6733
7260
|
}
|
|
6734
|
-
const site = {
|
|
6735
|
-
file,
|
|
6736
|
-
scope: query.module.moduleScope,
|
|
6737
|
-
rebound: /* @__PURE__ */ new Set()
|
|
6738
|
-
};
|
|
6739
7261
|
const targets = [
|
|
6740
7262
|
...decoratorDependencies(query.classification, declared.form),
|
|
6741
7263
|
...parameterDependencies(query.definitionNode, declared.form)
|
|
6742
7264
|
];
|
|
6743
7265
|
for (const name of targets) {
|
|
6744
|
-
const target =
|
|
6745
|
-
filesByPath: this.filesByPath,
|
|
6746
|
-
roots: this.options.roots
|
|
6747
|
-
});
|
|
7266
|
+
const target = this.functionCalled(file.file, name);
|
|
6748
7267
|
if (target !== null) {
|
|
6749
7268
|
found.push(this.registered(target, declared));
|
|
6750
7269
|
}
|
|
@@ -6886,12 +7405,8 @@ function registerConstructorDependencies(file, declared, form, index) {
|
|
|
6886
7405
|
if (listed === void 0) {
|
|
6887
7406
|
continue;
|
|
6888
7407
|
}
|
|
6889
|
-
const site = { file, scope, rebound: /* @__PURE__ */ new Set() };
|
|
6890
7408
|
for (const name of dependencyNamesIn(listed.node, form)) {
|
|
6891
|
-
const target =
|
|
6892
|
-
filesByPath: index.filesByPath,
|
|
6893
|
-
roots: index.options.roots
|
|
6894
|
-
});
|
|
7409
|
+
const target = index.functionCalled(file.file, name);
|
|
6895
7410
|
if (target !== null) {
|
|
6896
7411
|
index.register(
|
|
6897
7412
|
coverageOf(match, file, declared.pack),
|
|
@@ -7153,9 +7668,9 @@ async function extractPythonProject(options) {
|
|
|
7153
7668
|
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
7154
7669
|
if (lookup.kind === "hit") {
|
|
7155
7670
|
options.onTiming?.(timer.report());
|
|
7156
|
-
return { summaries: lookup.summaries, facts: new
|
|
7671
|
+
return { summaries: lookup.summaries, facts: new import_datalog2.Database() };
|
|
7157
7672
|
}
|
|
7158
|
-
const db = new
|
|
7673
|
+
const db = new import_datalog2.Database();
|
|
7159
7674
|
const summaries = [];
|
|
7160
7675
|
const gapHandling = options.gapHandling ?? "permissive";
|
|
7161
7676
|
const tallies = (0, import_extractor6.createPackTallies)(options.packs);
|
|
@@ -7219,9 +7734,11 @@ async function extractPythonProject(options) {
|
|
|
7219
7734
|
packs: options.packs,
|
|
7220
7735
|
roots: options.roots,
|
|
7221
7736
|
facts: needsValues ? db : void 0,
|
|
7737
|
+
definitions,
|
|
7222
7738
|
storageFor
|
|
7223
7739
|
})
|
|
7224
7740
|
);
|
|
7741
|
+
const importedDefinition = importedDefinitionLookup(db, bound);
|
|
7225
7742
|
const discovered = /* @__PURE__ */ new Map();
|
|
7226
7743
|
for (const boundFile of bound) {
|
|
7227
7744
|
const { file, root, module: moduleBinding } = boundFile;
|
|
@@ -7235,6 +7752,7 @@ async function extractPythonProject(options) {
|
|
|
7235
7752
|
routerIndex,
|
|
7236
7753
|
gapHandling,
|
|
7237
7754
|
wrappers: wrapperIndex,
|
|
7755
|
+
importedDefinition,
|
|
7238
7756
|
...needsValues ? { facts: db } : {},
|
|
7239
7757
|
...storage === void 0 ? {} : { storage }
|
|
7240
7758
|
})
|
|
@@ -7300,7 +7818,9 @@ async function extractPythonProject(options) {
|
|
|
7300
7818
|
files: bound,
|
|
7301
7819
|
roots: options.roots,
|
|
7302
7820
|
gapHandling,
|
|
7303
|
-
storageFor
|
|
7821
|
+
storageFor,
|
|
7822
|
+
facts: db,
|
|
7823
|
+
definitions
|
|
7304
7824
|
})
|
|
7305
7825
|
);
|
|
7306
7826
|
for (const [key, owners] of summariesBySeed) {
|
|
@@ -7491,7 +8011,7 @@ function width(node) {
|
|
|
7491
8011
|
}
|
|
7492
8012
|
var PythonWhySession = class {
|
|
7493
8013
|
root;
|
|
7494
|
-
db = new
|
|
8014
|
+
db = new import_datalog3.Database();
|
|
7495
8015
|
locations = /* @__PURE__ */ new Map();
|
|
7496
8016
|
trees = /* @__PURE__ */ new Map();
|
|
7497
8017
|
constructor(options) {
|
|
@@ -7560,9 +8080,9 @@ var PythonWhySession = class {
|
|
|
7560
8080
|
* which the caller says in its own words.
|
|
7561
8081
|
*/
|
|
7562
8082
|
explain(value, options = {}) {
|
|
7563
|
-
return (0,
|
|
8083
|
+
return (0, import_resolution6.explainResolvedKey)({
|
|
7564
8084
|
db: this.db,
|
|
7565
|
-
rules:
|
|
8085
|
+
rules: import_resolution6.RESOLUTION_RULES,
|
|
7566
8086
|
key: readKey(value.file, value.node, enclosingFunction(value.node)),
|
|
7567
8087
|
locate: (key) => this.locate(key),
|
|
7568
8088
|
displayPath: (key) => this.displayPath(key),
|
|
@@ -7693,6 +8213,7 @@ async function pythonImportEvidence(options) {
|
|
|
7693
8213
|
emitValueFacts,
|
|
7694
8214
|
extractPythonProject,
|
|
7695
8215
|
findPythonFiles,
|
|
8216
|
+
nameKeyIn,
|
|
7696
8217
|
nodeId,
|
|
7697
8218
|
objectReturnedBy,
|
|
7698
8219
|
parsePython,
|