@suss/adapter-python 0.27.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 +690 -452
- package/dist/index.d.cts +33 -12
- package/dist/index.d.ts +33 -12
- package/dist/index.js +683 -440
- 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) {
|
|
@@ -1464,14 +1470,14 @@ function invocationEffects(definitionNode) {
|
|
|
1464
1470
|
if (calls.length === 0) {
|
|
1465
1471
|
return [];
|
|
1466
1472
|
}
|
|
1467
|
-
const
|
|
1473
|
+
const statementOf3 = /* @__PURE__ */ new Map();
|
|
1468
1474
|
const statements = [];
|
|
1469
1475
|
for (const call of calls) {
|
|
1470
1476
|
const statement = enclosingStatement(call, body);
|
|
1471
1477
|
if (statement === null) {
|
|
1472
1478
|
continue;
|
|
1473
1479
|
}
|
|
1474
|
-
|
|
1480
|
+
statementOf3.set(call.id, statement);
|
|
1475
1481
|
statements.push(statement);
|
|
1476
1482
|
}
|
|
1477
1483
|
const lowered = lowerPythonBody(body, statements);
|
|
@@ -1483,7 +1489,7 @@ function invocationEffects(definitionNode) {
|
|
|
1483
1489
|
statements
|
|
1484
1490
|
);
|
|
1485
1491
|
return calls.map((call) => {
|
|
1486
|
-
const statement =
|
|
1492
|
+
const statement = statementOf3.get(call.id);
|
|
1487
1493
|
const conditions = (0, import_extractor3.sharedGatingConditions)(
|
|
1488
1494
|
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement),
|
|
1489
1495
|
predicateOf
|
|
@@ -1499,36 +1505,20 @@ function invocationEffects(definitionNode) {
|
|
|
1499
1505
|
}
|
|
1500
1506
|
|
|
1501
1507
|
// src/routers.ts
|
|
1502
|
-
var
|
|
1508
|
+
var import_resolution4 = require("@suss/resolution");
|
|
1503
1509
|
|
|
1504
1510
|
// src/facts/resolve.ts
|
|
1505
|
-
var import_datalog = require("@suss/datalog");
|
|
1506
1511
|
var import_resolution = require("@suss/resolution");
|
|
1507
|
-
var RESOLUTION_PROGRAM = (0, import_datalog.deriveOnDemand)(
|
|
1508
|
-
[...import_resolution.RESOLUTION_RULES, ...import_resolution.RESOLUTION_QUESTIONS],
|
|
1509
|
-
import_resolution.ANSWER_RELATIONS
|
|
1510
|
-
);
|
|
1511
1512
|
function resolveCalls(db, callKeys) {
|
|
1512
|
-
|
|
1513
|
-
const fresh = callKeys.filter((key) => !asked.has(key));
|
|
1514
|
-
if (fresh.length === 0) {
|
|
1515
|
-
return;
|
|
1516
|
-
}
|
|
1517
|
-
for (const callKey of fresh) {
|
|
1518
|
-
db.add("wanted", [callKey]);
|
|
1519
|
-
}
|
|
1520
|
-
(0, import_datalog.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
1513
|
+
(0, import_resolution.askResolution)(db, callKeys);
|
|
1521
1514
|
}
|
|
1522
1515
|
function writtenValueOf(db, key) {
|
|
1523
1516
|
resolveCalls(db, [key]);
|
|
1524
1517
|
return (0, import_resolution.writtenValueOf)(db, key, (keys) => resolveCalls(db, keys));
|
|
1525
1518
|
}
|
|
1526
|
-
function originsOf(db,
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
(0, import_datalog.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
1530
|
-
}
|
|
1531
|
-
return db.facts("wantedComesFrom").filter((row) => String(row[0]) === nameKey).map((row) => ({ module: String(row[1]), name: String(row[2]) }));
|
|
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]) }));
|
|
1532
1522
|
}
|
|
1533
1523
|
function subjectConstructions(db, valueKeys) {
|
|
1534
1524
|
const found = /* @__PURE__ */ new Map();
|
|
@@ -1536,10 +1526,7 @@ function subjectConstructions(db, valueKeys) {
|
|
|
1536
1526
|
return found;
|
|
1537
1527
|
}
|
|
1538
1528
|
const askSubjects = (keys) => {
|
|
1539
|
-
|
|
1540
|
-
db.add("wantedSubject", [key]);
|
|
1541
|
-
}
|
|
1542
|
-
(0, import_datalog.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
1529
|
+
(0, import_resolution.askResolution)(db, keys, "wantedSubject");
|
|
1543
1530
|
};
|
|
1544
1531
|
askSubjects(valueKeys);
|
|
1545
1532
|
const placeholders = (0, import_resolution.placeholderValues)(db);
|
|
@@ -1586,6 +1573,7 @@ function objectReturnedBy(db, callKey) {
|
|
|
1586
1573
|
}
|
|
1587
1574
|
|
|
1588
1575
|
// src/facts/values.ts
|
|
1576
|
+
var import_resolution2 = require("@suss/resolution");
|
|
1589
1577
|
function nodeId(filePath, node) {
|
|
1590
1578
|
return `${filePath}:${node.startIndex}-${node.endIndex}`;
|
|
1591
1579
|
}
|
|
@@ -1596,10 +1584,10 @@ function readKey(filePath, node, enclosing) {
|
|
|
1596
1584
|
if (node.type !== "identifier") {
|
|
1597
1585
|
return nodeId(filePath, node);
|
|
1598
1586
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
return
|
|
1587
|
+
return nameKeyIn(filePath, enclosing, node.text);
|
|
1588
|
+
}
|
|
1589
|
+
function nameKeyIn(filePath, enclosing, name) {
|
|
1590
|
+
return nameKey(filePath, scopeChainOf(filePath, enclosing), name);
|
|
1603
1591
|
}
|
|
1604
1592
|
var WRITTEN_VALUE_TYPES = /* @__PURE__ */ new Set([
|
|
1605
1593
|
"string",
|
|
@@ -1637,9 +1625,6 @@ function parameterName2(param) {
|
|
|
1637
1625
|
}
|
|
1638
1626
|
return children(param).find((child) => child.type === "identifier") ?? null;
|
|
1639
1627
|
}
|
|
1640
|
-
function parameterList(fn) {
|
|
1641
|
-
return parameterShapes(fn).map((parameter) => parameter.name);
|
|
1642
|
-
}
|
|
1643
1628
|
function parameterShapes(fn) {
|
|
1644
1629
|
const params = field(fn, "parameters");
|
|
1645
1630
|
const declared = [];
|
|
@@ -1654,24 +1639,52 @@ function parameterShapes(fn) {
|
|
|
1654
1639
|
}
|
|
1655
1640
|
return declared;
|
|
1656
1641
|
}
|
|
1657
|
-
function
|
|
1658
|
-
|
|
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;
|
|
1659
1652
|
}
|
|
1660
1653
|
function add(emitter, relation, ...tuple) {
|
|
1661
1654
|
emitter.db.add(relation, tuple);
|
|
1662
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
|
+
}
|
|
1663
1679
|
function emitCall(emitter, call) {
|
|
1664
1680
|
add(emitter, "writtenValue", nodeId(emitter.filePath, call));
|
|
1665
1681
|
const callee = field(call, "function");
|
|
1666
|
-
|
|
1682
|
+
const args = field(call, "arguments");
|
|
1683
|
+
if (callee === null || args === null) {
|
|
1667
1684
|
return;
|
|
1668
1685
|
}
|
|
1669
1686
|
const callKey = nodeId(emitter.filePath, call);
|
|
1670
1687
|
add(emitter, "call", callKey, valueKey(emitter, callee));
|
|
1671
|
-
const args = field(call, "arguments");
|
|
1672
|
-
if (args === null) {
|
|
1673
|
-
return;
|
|
1674
|
-
}
|
|
1675
1688
|
let position = 0;
|
|
1676
1689
|
for (const argument of children(args)) {
|
|
1677
1690
|
if (argument.type === "keyword_argument") {
|
|
@@ -1702,11 +1715,7 @@ function valueKey(emitter, value) {
|
|
|
1702
1715
|
if (value.type !== "identifier") {
|
|
1703
1716
|
return nodeId(emitter.filePath, value);
|
|
1704
1717
|
}
|
|
1705
|
-
|
|
1706
|
-
if (enclosing !== null && enclosing.params.has(value.text)) {
|
|
1707
|
-
return `${enclosing.funcKey}#${value.text}`;
|
|
1708
|
-
}
|
|
1709
|
-
return nameId(emitter.filePath, value.text);
|
|
1718
|
+
return nameKey(emitter.filePath, emitter.enclosing, value.text);
|
|
1710
1719
|
}
|
|
1711
1720
|
function emitSequence(emitter, sequence) {
|
|
1712
1721
|
const objectKey = nodeId(emitter.filePath, sequence);
|
|
@@ -1796,7 +1805,6 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1796
1805
|
const funcKey = nodeId(emitter.filePath, fn);
|
|
1797
1806
|
add(emitter, "func", funcKey);
|
|
1798
1807
|
const params = field(fn, "parameters");
|
|
1799
|
-
const declared = parameterNames(fn);
|
|
1800
1808
|
let position = classKey === void 0 ? 0 : -1;
|
|
1801
1809
|
let byPosition = true;
|
|
1802
1810
|
let receiver = null;
|
|
@@ -1819,24 +1827,22 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1819
1827
|
}
|
|
1820
1828
|
position += 1;
|
|
1821
1829
|
}
|
|
1830
|
+
const reading = scopeReadingOf(fn);
|
|
1822
1831
|
const inside = {
|
|
1823
1832
|
...emitter,
|
|
1824
|
-
enclosing: {
|
|
1833
|
+
enclosing: {
|
|
1834
|
+
funcKey,
|
|
1835
|
+
locals: reading.locals,
|
|
1836
|
+
globals: reading.globals,
|
|
1837
|
+
parent: emitter.enclosing
|
|
1838
|
+
}
|
|
1825
1839
|
};
|
|
1840
|
+
emitScopeWrites(inside, reading, false);
|
|
1826
1841
|
const body = field(fn, "body");
|
|
1827
1842
|
if (body === null) {
|
|
1828
1843
|
return funcKey;
|
|
1829
1844
|
}
|
|
1830
|
-
|
|
1831
|
-
for (const child of children(node)) {
|
|
1832
|
-
if (isFunction(child)) {
|
|
1833
|
-
add(emitter, "containsFn", funcKey, nodeId(emitter.filePath, child));
|
|
1834
|
-
continue;
|
|
1835
|
-
}
|
|
1836
|
-
recordNested(child);
|
|
1837
|
-
}
|
|
1838
|
-
};
|
|
1839
|
-
recordNested(body);
|
|
1845
|
+
emitNestedDefinitions(inside, body);
|
|
1840
1846
|
walkExpressions(inside, body, (child) => {
|
|
1841
1847
|
if (child.type === "return_statement") {
|
|
1842
1848
|
const returned = child.namedChildren[0];
|
|
@@ -1847,29 +1853,17 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1847
1853
|
if (child.type === "call") {
|
|
1848
1854
|
add(inside, "bodyCalls", funcKey, nodeId(inside.filePath, child));
|
|
1849
1855
|
}
|
|
1850
|
-
if (child.type === "assignment") {
|
|
1851
|
-
|
|
1856
|
+
if (child.type === "assignment" && receiver !== null) {
|
|
1857
|
+
emitReceiverProperty(inside, child, receiver);
|
|
1852
1858
|
}
|
|
1853
1859
|
emitExpressionFact(inside, child);
|
|
1854
1860
|
});
|
|
1855
1861
|
return funcKey;
|
|
1856
1862
|
}
|
|
1857
|
-
function
|
|
1863
|
+
function emitReceiverProperty(emitter, assignment2, receiver) {
|
|
1858
1864
|
const left = field(assignment2, "left");
|
|
1859
1865
|
const right = field(assignment2, "right");
|
|
1860
|
-
if (left === null || right === null) {
|
|
1861
|
-
return;
|
|
1862
|
-
}
|
|
1863
|
-
if (left.type === "identifier") {
|
|
1864
|
-
add(
|
|
1865
|
-
emitter,
|
|
1866
|
-
"binds",
|
|
1867
|
-
nameId(emitter.filePath, left.text),
|
|
1868
|
-
valueKey(emitter, assignedValue(right))
|
|
1869
|
-
);
|
|
1870
|
-
return;
|
|
1871
|
-
}
|
|
1872
|
-
if (receiver === null || left.type !== "attribute") {
|
|
1866
|
+
if (left === null || right === null || left.type !== "attribute") {
|
|
1873
1867
|
return;
|
|
1874
1868
|
}
|
|
1875
1869
|
const object = field(left, "object");
|
|
@@ -1885,21 +1879,6 @@ function emitBinding(emitter, assignment2, receiver) {
|
|
|
1885
1879
|
valueKey(emitter, right)
|
|
1886
1880
|
);
|
|
1887
1881
|
}
|
|
1888
|
-
function emitAssignment(emitter, assignment2) {
|
|
1889
|
-
emitBinding(emitter, assignment2, null);
|
|
1890
|
-
const left = field(assignment2, "left");
|
|
1891
|
-
const right = field(assignment2, "right");
|
|
1892
|
-
if (left === null || right === null || left.type !== "identifier") {
|
|
1893
|
-
return;
|
|
1894
|
-
}
|
|
1895
|
-
add(
|
|
1896
|
-
emitter,
|
|
1897
|
-
"exportsAs",
|
|
1898
|
-
emitter.filePath,
|
|
1899
|
-
left.text,
|
|
1900
|
-
valueKey(emitter, assignedValue(right))
|
|
1901
|
-
);
|
|
1902
|
-
}
|
|
1903
1882
|
function assignedValue(right) {
|
|
1904
1883
|
if (right.type !== "subscript") {
|
|
1905
1884
|
return right;
|
|
@@ -1950,40 +1929,361 @@ function emitClassFacts(emitter, cls) {
|
|
|
1950
1929
|
}
|
|
1951
1930
|
continue;
|
|
1952
1931
|
}
|
|
1953
|
-
const
|
|
1932
|
+
const memberKey2 = declaredMemberKey(emitter, member, classKey);
|
|
1954
1933
|
const name = field(member, "name");
|
|
1955
|
-
if (
|
|
1956
|
-
add(emitter, "holdsProperty", classKey, name.text,
|
|
1934
|
+
if (memberKey2 !== null && name !== null) {
|
|
1935
|
+
add(emitter, "holdsProperty", classKey, name.text, memberKey2);
|
|
1957
1936
|
}
|
|
1958
1937
|
}
|
|
1959
1938
|
return classKey;
|
|
1960
1939
|
}
|
|
1961
|
-
function
|
|
1962
|
-
const
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
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]);
|
|
1966
2106
|
return;
|
|
1967
2107
|
}
|
|
1968
|
-
|
|
1969
|
-
add(emitter, "exportsAs", filePath, name.text, key);
|
|
2108
|
+
existing.push(write);
|
|
1970
2109
|
};
|
|
1971
|
-
const
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
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
|
+
});
|
|
1982
2121
|
}
|
|
1983
|
-
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
WRITE_READERS[node.type]?.(node, sink);
|
|
2125
|
+
for (const child of children(node)) {
|
|
2126
|
+
visit(child);
|
|
1984
2127
|
}
|
|
1985
2128
|
};
|
|
1986
|
-
|
|
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);
|
|
1987
2287
|
emitExpressionFacts(emitter, root);
|
|
1988
2288
|
}
|
|
1989
2289
|
|
|
@@ -2069,7 +2369,7 @@ function resolveModule(importingFile, spec, options) {
|
|
|
2069
2369
|
}
|
|
2070
2370
|
|
|
2071
2371
|
// src/values/evaluator.ts
|
|
2072
|
-
var
|
|
2372
|
+
var import_resolution3 = require("@suss/resolution");
|
|
2073
2373
|
var import_values3 = require("@suss/values");
|
|
2074
2374
|
|
|
2075
2375
|
// src/values/lowering.ts
|
|
@@ -2096,7 +2396,7 @@ function pythonLowering(options) {
|
|
|
2096
2396
|
return {
|
|
2097
2397
|
idOf: (node) => node.id,
|
|
2098
2398
|
expression: (node) => expressionOf(node, originOf2),
|
|
2099
|
-
statement:
|
|
2399
|
+
statement: statementOf2,
|
|
2100
2400
|
siteOf,
|
|
2101
2401
|
functionOf,
|
|
2102
2402
|
writtenTo: (node) => context === null ? null : context.writtenTo(node),
|
|
@@ -2360,7 +2660,7 @@ var STATEMENT_TYPES = {
|
|
|
2360
2660
|
body: blockStatements2(field(node, "body"))
|
|
2361
2661
|
})
|
|
2362
2662
|
};
|
|
2363
|
-
function
|
|
2663
|
+
function statementOf2(node) {
|
|
2364
2664
|
const lower = STATEMENT_TYPES[node.type];
|
|
2365
2665
|
return lower === void 0 ? { kind: "opaque" } : lower(node);
|
|
2366
2666
|
}
|
|
@@ -2857,7 +3157,7 @@ function contextOver(db, nodes) {
|
|
|
2857
3157
|
return null;
|
|
2858
3158
|
}
|
|
2859
3159
|
const answer = writtenValueOf(db, key);
|
|
2860
|
-
return answer === null ? null : (0,
|
|
3160
|
+
return answer === null ? null : (0, import_resolution3.nodeOfKey)(rootsByFile, answer);
|
|
2861
3161
|
},
|
|
2862
3162
|
callable: (call) => {
|
|
2863
3163
|
const callee = field(call, "function");
|
|
@@ -2986,7 +3286,7 @@ function composedPrefixOf(index, construction, routerPath) {
|
|
|
2986
3286
|
return { kind: "composed", value: composed.value + ownPrefix.value };
|
|
2987
3287
|
}
|
|
2988
3288
|
function composedMountPrefix(index, construction) {
|
|
2989
|
-
const paths = (0,
|
|
3289
|
+
const paths = (0, import_resolution4.mountPathsOf)(mountEdgesOf(index), construction.valueKey);
|
|
2990
3290
|
if (paths === null) {
|
|
2991
3291
|
return {
|
|
2992
3292
|
kind: "abstain",
|
|
@@ -3409,9 +3709,13 @@ function constructionThroughFacts(name, scope, scan) {
|
|
|
3409
3709
|
if (binding.kind !== "assignment" && binding.kind !== "importFrom") {
|
|
3410
3710
|
return null;
|
|
3411
3711
|
}
|
|
3412
|
-
const
|
|
3413
|
-
|
|
3414
|
-
|
|
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
|
|
3415
3719
|
)?.constructionKey;
|
|
3416
3720
|
return constructionKey2 === void 0 ? null : scan.index.byValueKey.get(constructionKey2) ?? null;
|
|
3417
3721
|
}
|
|
@@ -3502,11 +3806,11 @@ function walkStatements(statements, position, scan, visit) {
|
|
|
3502
3806
|
visit(stmt, position, scan);
|
|
3503
3807
|
}
|
|
3504
3808
|
}
|
|
3505
|
-
function
|
|
3809
|
+
function targetNames2(node) {
|
|
3506
3810
|
if (node.type === "identifier") {
|
|
3507
3811
|
return [node.text];
|
|
3508
3812
|
}
|
|
3509
|
-
return bodyStatements(node).flatMap(
|
|
3813
|
+
return bodyStatements(node).flatMap(targetNames2);
|
|
3510
3814
|
}
|
|
3511
3815
|
function sequenceElementNames(node) {
|
|
3512
3816
|
if (node === null || node.type !== "list" && node.type !== "tuple") {
|
|
@@ -3543,7 +3847,7 @@ function loopBindingsOf(stmt, position, scan) {
|
|
|
3543
3847
|
});
|
|
3544
3848
|
return bindings;
|
|
3545
3849
|
}
|
|
3546
|
-
for (const name of
|
|
3850
|
+
for (const name of targetNames2(left)) {
|
|
3547
3851
|
bindings.set(name, { kind: "unenumerable", location });
|
|
3548
3852
|
}
|
|
3549
3853
|
return bindings;
|
|
@@ -5019,14 +5323,9 @@ function matchedChains(calls, options) {
|
|
|
5019
5323
|
if (chains.length === 0) {
|
|
5020
5324
|
return [];
|
|
5021
5325
|
}
|
|
5022
|
-
const alreadyAsked = new Set(
|
|
5023
|
-
options.facts.facts("wanted").map((row) => String(row[0]))
|
|
5024
|
-
);
|
|
5025
5326
|
resolveCalls(
|
|
5026
5327
|
options.facts,
|
|
5027
|
-
storageCallees(calls, options.filePath, options.couldMatch)
|
|
5028
|
-
(key) => !alreadyAsked.has(key)
|
|
5029
|
-
)
|
|
5328
|
+
storageCallees(calls, options.filePath, options.couldMatch)
|
|
5030
5329
|
);
|
|
5031
5330
|
const matched = [];
|
|
5032
5331
|
for (const chain of chains) {
|
|
@@ -6087,8 +6386,8 @@ function isInjectedParameter(param, injectedCallees, scope, ctx) {
|
|
|
6087
6386
|
// src/facts/why.ts
|
|
6088
6387
|
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
6089
6388
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
6090
|
-
var
|
|
6091
|
-
var
|
|
6389
|
+
var import_datalog3 = require("@suss/datalog");
|
|
6390
|
+
var import_resolution6 = require("@suss/resolution");
|
|
6092
6391
|
|
|
6093
6392
|
// src/facts.ts
|
|
6094
6393
|
function unitKey(filePath, range, name) {
|
|
@@ -6106,7 +6405,7 @@ function emitModuleImportFacts(db, filePath, module2, resolverOptions) {
|
|
|
6106
6405
|
if (binding.kind !== "import" && binding.kind !== "importFrom") {
|
|
6107
6406
|
continue;
|
|
6108
6407
|
}
|
|
6109
|
-
const
|
|
6408
|
+
const nameKey2 = `${filePath}#${localName}`;
|
|
6110
6409
|
const moduleText = importedModuleText(
|
|
6111
6410
|
binding.module,
|
|
6112
6411
|
binding.relativeLevel
|
|
@@ -6122,16 +6421,16 @@ function emitModuleImportFacts(db, filePath, module2, resolverOptions) {
|
|
|
6122
6421
|
resolution.status === "resolved" ? "resolved" : resolution.reason
|
|
6123
6422
|
]);
|
|
6124
6423
|
const importedName = binding.kind === "import" ? binding.localName : binding.importedName;
|
|
6125
|
-
db.add("pyImportedName", [
|
|
6424
|
+
db.add("pyImportedName", [nameKey2, moduleText, importedName]);
|
|
6126
6425
|
if (scope.kind === "module") {
|
|
6127
|
-
db.add("exportsAs", [filePath, localName,
|
|
6426
|
+
db.add("exportsAs", [filePath, localName, nameKey2]);
|
|
6128
6427
|
}
|
|
6129
6428
|
if (resolution.status === "resolved") {
|
|
6130
6429
|
db.add("pyImportResolved", [filePath, moduleText, resolution.file]);
|
|
6131
|
-
db.add("imports", [
|
|
6430
|
+
db.add("imports", [nameKey2, resolution.file, importedName]);
|
|
6132
6431
|
continue;
|
|
6133
6432
|
}
|
|
6134
|
-
db.add("imports", [
|
|
6433
|
+
db.add("imports", [nameKey2, moduleText, importedName]);
|
|
6135
6434
|
}
|
|
6136
6435
|
}
|
|
6137
6436
|
for (const openModule of module2.openImports) {
|
|
@@ -6199,7 +6498,7 @@ function parseWith(language, source) {
|
|
|
6199
6498
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
6200
6499
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
6201
6500
|
var import_behavioral_ir5 = require("@suss/behavioral-ir");
|
|
6202
|
-
var
|
|
6501
|
+
var import_datalog2 = require("@suss/datalog");
|
|
6203
6502
|
var import_extractor10 = require("@suss/extractor");
|
|
6204
6503
|
|
|
6205
6504
|
// src/diagnostics.ts
|
|
@@ -6271,272 +6570,246 @@ function definedNodeOf(binding) {
|
|
|
6271
6570
|
|
|
6272
6571
|
// src/reach/closure.ts
|
|
6273
6572
|
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
6274
|
-
var
|
|
6573
|
+
var import_datalog = require("@suss/datalog");
|
|
6275
6574
|
var import_extractor7 = require("@suss/extractor");
|
|
6276
6575
|
|
|
6277
6576
|
// src/reach/resolveCallee.ts
|
|
6278
|
-
var
|
|
6279
|
-
var
|
|
6280
|
-
|
|
6281
|
-
|
|
6577
|
+
var import_resolution5 = require("@suss/resolution");
|
|
6578
|
+
var STOP_FOR = {
|
|
6579
|
+
severalSources: "multipleSources",
|
|
6580
|
+
outsideRun: "outsideRun",
|
|
6581
|
+
unsettled: "unsettledValue",
|
|
6582
|
+
undeclared: "noDeclaration"
|
|
6282
6583
|
};
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
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
|
+
}
|
|
6287
6597
|
}
|
|
6288
|
-
return
|
|
6598
|
+
return { spellingOf, outcomes: (0, import_resolution5.calleeOutcomes)(ctx.facts, [...keys]) };
|
|
6289
6599
|
}
|
|
6290
|
-
function
|
|
6291
|
-
|
|
6292
|
-
|
|
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;
|
|
6293
6604
|
}
|
|
6294
|
-
const
|
|
6295
|
-
|
|
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)) {
|
|
6296
6610
|
return null;
|
|
6297
6611
|
}
|
|
6298
|
-
const
|
|
6299
|
-
return
|
|
6612
|
+
const outcome = (0, import_resolution5.calleeOutcomeOf)(ctx.facts, nameKey2);
|
|
6613
|
+
return outcome.kind === "function" ? functionAt(outcome.key, ctx) : null;
|
|
6300
6614
|
}
|
|
6301
|
-
function
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
if (resolved.kind === "class") {
|
|
6306
|
-
return asCallee(
|
|
6307
|
-
memberOfClass(resolved.file, resolved.node, "__init__", ctx),
|
|
6308
|
-
ctx
|
|
6309
|
-
);
|
|
6310
|
-
}
|
|
6311
|
-
if (resolved.kind === "stop") {
|
|
6312
|
-
return { kind: "stopped", reason: resolved.reason };
|
|
6313
|
-
}
|
|
6314
|
-
if (resolved.kind === "package") {
|
|
6315
|
-
return { kind: "stopped", reason: "outsideRun" };
|
|
6316
|
-
}
|
|
6317
|
-
return { kind: "stopped", reason: "noDeclaration" };
|
|
6615
|
+
function assignedElsewhere(facts, nameKey2) {
|
|
6616
|
+
return (0, import_resolution5.writtenSourcesOf)(facts, nameKey2).some(
|
|
6617
|
+
(source) => !facts.has("func", [source])
|
|
6618
|
+
);
|
|
6318
6619
|
}
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
const object = field(node, "object");
|
|
6323
|
-
const attribute = field(node, "attribute");
|
|
6324
|
-
if (object === null || attribute === null) {
|
|
6325
|
-
return stop("noDeclaration");
|
|
6326
|
-
}
|
|
6327
|
-
return memberOf(resolveExpression(object, site, ctx), attribute.text, ctx);
|
|
6328
|
-
},
|
|
6329
|
-
call: (node, site, ctx) => {
|
|
6330
|
-
const callee = field(node, "function");
|
|
6331
|
-
return callee === null ? stop("noDeclaration") : instanceBuiltBy(resolveExpression(callee, site, ctx), "noDeclaration");
|
|
6332
|
-
},
|
|
6333
|
-
parenthesized_expression: (node, site, ctx) => {
|
|
6334
|
-
const inner = node.namedChildren[0];
|
|
6335
|
-
return inner === null || inner === void 0 ? stop("noDeclaration") : resolveExpression(inner, site, ctx);
|
|
6620
|
+
function readThrough(node) {
|
|
6621
|
+
if (node?.type !== "parenthesized_expression") {
|
|
6622
|
+
return node;
|
|
6336
6623
|
}
|
|
6337
|
-
|
|
6338
|
-
function resolveExpression(node, site, ctx) {
|
|
6339
|
-
const resolver = EXPRESSION_RESOLVERS[node.type];
|
|
6340
|
-
return resolver === void 0 ? stop("noDeclaration") : resolver(node, site, ctx);
|
|
6624
|
+
return readThrough(children(node)[0] ?? null);
|
|
6341
6625
|
}
|
|
6342
|
-
function
|
|
6343
|
-
|
|
6344
|
-
|
|
6626
|
+
function spellingFor(call, site, ctx) {
|
|
6627
|
+
const callee = readThrough(field(call, "function"));
|
|
6628
|
+
if (callee === null) {
|
|
6629
|
+
return { kind: "stopped", reason: "noDeclaration" };
|
|
6345
6630
|
}
|
|
6346
|
-
return
|
|
6631
|
+
return throughModules(callee, site, ctx) ?? {
|
|
6632
|
+
kind: "key",
|
|
6633
|
+
key: readKey(site.file.file, callee, enclosingFunction(callee))
|
|
6634
|
+
};
|
|
6347
6635
|
}
|
|
6348
|
-
function
|
|
6349
|
-
if (
|
|
6350
|
-
return
|
|
6636
|
+
function asCallee(outcome, owner, ctx) {
|
|
6637
|
+
if (outcome.kind === "function") {
|
|
6638
|
+
return functionCallee(outcome.key, ctx);
|
|
6351
6639
|
}
|
|
6352
|
-
if (
|
|
6353
|
-
return
|
|
6640
|
+
if (outcome.kind === "object") {
|
|
6641
|
+
return constructorOf(outcome.key, ctx);
|
|
6354
6642
|
}
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
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" };
|
|
6358
6645
|
}
|
|
6359
|
-
return
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6646
|
+
return {
|
|
6647
|
+
kind: "stopped",
|
|
6648
|
+
reason: STOP_FOR[outcome.kind] ?? "noDeclaration"
|
|
6649
|
+
};
|
|
6363
6650
|
}
|
|
6364
|
-
function
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
return stop("noDeclaration");
|
|
6651
|
+
function functionCallee(key, ctx) {
|
|
6652
|
+
if (ctx.definitions.get(key)?.type === "lambda") {
|
|
6653
|
+
return { kind: "stopped", reason: "unsettledValue" };
|
|
6368
6654
|
}
|
|
6369
|
-
|
|
6655
|
+
const target = functionAt(key, ctx);
|
|
6656
|
+
return target === null ? NO_DECLARATION : { kind: "followed", target };
|
|
6370
6657
|
}
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
}),
|
|
6376
|
-
classDef: (binding, file) => ({ kind: "class", file, node: binding.node }),
|
|
6377
|
-
parameter: () => stop("callerSupplied"),
|
|
6378
|
-
// `import a.b.c` binds `a`, and `import a.b.c as m` binds `m` to `a.b.c`.
|
|
6379
|
-
import: (binding, file, _scope, ctx) => moduleNamed(
|
|
6380
|
-
file,
|
|
6381
|
-
binding.localName === binding.module.split(".")[0] ? binding.localName : binding.module,
|
|
6382
|
-
0,
|
|
6383
|
-
ctx
|
|
6384
|
-
),
|
|
6385
|
-
importFrom: (binding, file, _scope, ctx, visited) => memberOf(
|
|
6386
|
-
moduleNamed(file, binding.module, binding.relativeLevel, ctx),
|
|
6387
|
-
binding.importedName,
|
|
6388
|
-
ctx,
|
|
6389
|
-
visited
|
|
6390
|
-
),
|
|
6391
|
-
// `run = load` is an alias worth one hop; anything else is a value.
|
|
6392
|
-
assignment: (binding, file, scope, ctx, visited) => aliasedValue(binding.value, file, scope, ctx, visited),
|
|
6393
|
-
global: () => stop("unsettledValue"),
|
|
6394
|
-
nonlocal: () => stop("unsettledValue")
|
|
6395
|
-
};
|
|
6396
|
-
function resolveBinding(binding, file, scope, ctx, visited) {
|
|
6397
|
-
const resolver = BINDING_RESOLVERS[binding.kind];
|
|
6398
|
-
return resolver(binding, file, scope, ctx, visited);
|
|
6399
|
-
}
|
|
6400
|
-
function aliasedValue(value, file, scope, ctx, visited) {
|
|
6401
|
-
if (value === null) {
|
|
6402
|
-
return stop("unsettledValue");
|
|
6403
|
-
}
|
|
6404
|
-
if (value.type === "identifier") {
|
|
6405
|
-
const binding = resolveName(scope, value.text);
|
|
6406
|
-
if (binding === null || binding.kind === "assignment") {
|
|
6407
|
-
return stop("unsettledValue");
|
|
6408
|
-
}
|
|
6409
|
-
return resolveBinding(binding, file, scope, ctx, visited);
|
|
6410
|
-
}
|
|
6411
|
-
if (value.type === "call") {
|
|
6412
|
-
const callee = field(value, "function");
|
|
6413
|
-
return callee === null ? stop("unsettledValue") : instanceBuiltBy(
|
|
6414
|
-
aliasedValue(callee, file, scope, ctx, visited),
|
|
6415
|
-
"unsettledValue"
|
|
6416
|
-
);
|
|
6417
|
-
}
|
|
6418
|
-
if (value.type === "attribute") {
|
|
6419
|
-
const object = field(value, "object");
|
|
6420
|
-
const attribute = field(value, "attribute");
|
|
6421
|
-
if (object === null || attribute === null) {
|
|
6422
|
-
return stop("unsettledValue");
|
|
6423
|
-
}
|
|
6424
|
-
return memberOf(
|
|
6425
|
-
aliasedValue(object, file, scope, ctx, visited),
|
|
6426
|
-
attribute.text,
|
|
6427
|
-
ctx
|
|
6428
|
-
);
|
|
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;
|
|
6429
6662
|
}
|
|
6430
|
-
return
|
|
6663
|
+
return functionCallee(String(declared[2]), ctx);
|
|
6431
6664
|
}
|
|
6432
|
-
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
|
+
}
|
|
6433
6671
|
const name = field(node, "name")?.text ?? "<anon>";
|
|
6434
|
-
const
|
|
6672
|
+
const owner = ownerClassOf(node);
|
|
6673
|
+
const ownerName = owner === null ? void 0 : field(owner, "name")?.text;
|
|
6435
6674
|
return {
|
|
6436
6675
|
file,
|
|
6437
6676
|
node,
|
|
6438
6677
|
name,
|
|
6439
|
-
exportPath: ownerName ===
|
|
6678
|
+
exportPath: ownerName === void 0 ? [name] : [ownerName, name]
|
|
6440
6679
|
};
|
|
6441
6680
|
}
|
|
6442
|
-
function
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
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
|
+
}
|
|
6450
6689
|
}
|
|
6451
|
-
|
|
6452
|
-
return file === void 0 ? stop("outsideRun") : { kind: "module", file };
|
|
6690
|
+
return null;
|
|
6453
6691
|
}
|
|
6454
|
-
function
|
|
6455
|
-
if (
|
|
6456
|
-
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;
|
|
6457
6695
|
}
|
|
6458
|
-
if (
|
|
6459
|
-
return
|
|
6460
|
-
base.from,
|
|
6461
|
-
base.dotted === "" ? name : `${base.dotted}.${name}`,
|
|
6462
|
-
base.relativeLevel,
|
|
6463
|
-
ctx
|
|
6464
|
-
);
|
|
6696
|
+
if (callee.type !== "attribute") {
|
|
6697
|
+
return null;
|
|
6465
6698
|
}
|
|
6466
|
-
|
|
6467
|
-
|
|
6699
|
+
const object = field(callee, "object");
|
|
6700
|
+
const attribute = field(callee, "attribute");
|
|
6701
|
+
if (object === null || attribute === null) {
|
|
6702
|
+
return null;
|
|
6468
6703
|
}
|
|
6469
|
-
|
|
6470
|
-
|
|
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;
|
|
6471
6710
|
}
|
|
6472
|
-
|
|
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
|
+
}
|
|
6723
|
+
}
|
|
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 };
|
|
6473
6729
|
}
|
|
6474
|
-
function
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
if (binding === void 0) {
|
|
6478
|
-
return stop("noDeclaration");
|
|
6730
|
+
function moduleAt(node, site, ctx) {
|
|
6731
|
+
if (node.type === "identifier") {
|
|
6732
|
+
return importedModule(node.text, site, ctx);
|
|
6479
6733
|
}
|
|
6480
|
-
if (
|
|
6481
|
-
return
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6734
|
+
if (node.type !== "attribute") {
|
|
6735
|
+
return null;
|
|
6736
|
+
}
|
|
6737
|
+
const object = field(node, "object");
|
|
6738
|
+
const attribute = field(node, "attribute");
|
|
6739
|
+
if (object === null || attribute === null) {
|
|
6740
|
+
return null;
|
|
6485
6741
|
}
|
|
6486
|
-
|
|
6742
|
+
const base = moduleAt(object, site, ctx);
|
|
6743
|
+
return base === null ? null : submoduleOf(base, attribute.text, ctx);
|
|
6487
6744
|
}
|
|
6488
|
-
function
|
|
6489
|
-
const
|
|
6490
|
-
if (
|
|
6491
|
-
|
|
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);
|
|
6492
6751
|
}
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
if (binding !== void 0) {
|
|
6496
|
-
return resolveBinding(binding, file, file.module.moduleScope, ctx, visited);
|
|
6752
|
+
if (binding?.kind !== "importFrom") {
|
|
6753
|
+
return null;
|
|
6497
6754
|
}
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
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
|
+
);
|
|
6503
6771
|
}
|
|
6504
|
-
return
|
|
6772
|
+
return base.file.file.endsWith("__init__.py") ? moduleNamed(base.file, name, 1, ctx) : null;
|
|
6505
6773
|
}
|
|
6506
|
-
function
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
const dots = spec.length - spec.replace(/^\.+/, "").length;
|
|
6510
|
-
const opened = moduleNamed(file, spec.slice(dots), dots, ctx);
|
|
6511
|
-
if (opened.kind !== "module") {
|
|
6512
|
-
continue;
|
|
6513
|
-
}
|
|
6514
|
-
const member = memberOfModule(opened.file, name, ctx, visited);
|
|
6515
|
-
if (member.kind !== "stop") {
|
|
6516
|
-
found.push(member);
|
|
6517
|
-
}
|
|
6774
|
+
function memberKey(base, name, ctx) {
|
|
6775
|
+
if (base.kind === "package") {
|
|
6776
|
+
return null;
|
|
6518
6777
|
}
|
|
6519
|
-
if (
|
|
6520
|
-
return
|
|
6778
|
+
if (base.file.module.moduleScope.bindings.has(name)) {
|
|
6779
|
+
return { kind: "key", key: `${base.file.file}#${name}` };
|
|
6521
6780
|
}
|
|
6522
|
-
return
|
|
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;
|
|
6791
|
+
}
|
|
6792
|
+
const file = ctx.filesByPath.get(resolution.file);
|
|
6793
|
+
return file === void 0 ? null : { kind: "module", file };
|
|
6523
6794
|
}
|
|
6524
6795
|
|
|
6525
6796
|
// src/reach/closure.ts
|
|
6526
6797
|
var REACHABLE_RULES = [
|
|
6527
|
-
(0,
|
|
6528
|
-
(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)(
|
|
6529
6800
|
"reachable",
|
|
6530
|
-
[(0,
|
|
6531
|
-
[(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"))]
|
|
6532
6803
|
)
|
|
6533
6804
|
];
|
|
6534
6805
|
function reachedFunctions(seeds, options) {
|
|
6535
6806
|
const ctx = {
|
|
6536
6807
|
filesByPath: new Map(options.files.map((file) => [file.file, file])),
|
|
6537
|
-
roots: options.roots
|
|
6808
|
+
roots: options.roots,
|
|
6809
|
+
facts: options.facts,
|
|
6810
|
+
definitions: options.definitions
|
|
6538
6811
|
};
|
|
6539
|
-
const db = new
|
|
6812
|
+
const db = new import_datalog.Database();
|
|
6540
6813
|
const functionByKey = /* @__PURE__ */ new Map();
|
|
6541
6814
|
const seedKeys = /* @__PURE__ */ new Set();
|
|
6542
6815
|
const scanned = /* @__PURE__ */ new Set();
|
|
@@ -6556,21 +6829,26 @@ function reachedFunctions(seeds, options) {
|
|
|
6556
6829
|
db.add("entry", [seed.key]);
|
|
6557
6830
|
}
|
|
6558
6831
|
for (; ; ) {
|
|
6559
|
-
(0,
|
|
6832
|
+
(0, import_datalog.evaluate)(db, REACHABLE_RULES);
|
|
6560
6833
|
const frontier = db.facts("reachable").map(([key]) => String(key)).filter((key) => !scanned.has(key));
|
|
6561
6834
|
if (frontier.length === 0) {
|
|
6562
6835
|
break;
|
|
6563
6836
|
}
|
|
6564
|
-
|
|
6837
|
+
const bodies = frontier.flatMap((key) => {
|
|
6565
6838
|
scanned.add(key);
|
|
6566
6839
|
const source = functionByKey.get(key);
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
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) {
|
|
6570
6847
|
const scan = scanBody(
|
|
6571
6848
|
source,
|
|
6572
6849
|
ctx,
|
|
6573
|
-
recognizedCallIds(source.node, options.storageFor(source.file))
|
|
6850
|
+
recognizedCallIds(source.node, options.storageFor(source.file)),
|
|
6851
|
+
{ body, written, spellings }
|
|
6574
6852
|
);
|
|
6575
6853
|
if (scan.stops.length > 0) {
|
|
6576
6854
|
stopsByKey.set(key, scan.stops);
|
|
@@ -6636,7 +6914,18 @@ var EMPTY_SCAN = {
|
|
|
6636
6914
|
parameterCalls: [],
|
|
6637
6915
|
passedPositions: /* @__PURE__ */ new Set()
|
|
6638
6916
|
};
|
|
6639
|
-
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) {
|
|
6640
6929
|
const followed = [];
|
|
6641
6930
|
const stops = [];
|
|
6642
6931
|
const placements = new import_behavioral_ir4.TargetPlacements();
|
|
@@ -6645,12 +6934,12 @@ function scanBody(source, ctx, recognized) {
|
|
|
6645
6934
|
const seen = /* @__PURE__ */ new Set();
|
|
6646
6935
|
const parameterCallsSeen = /* @__PURE__ */ new Set();
|
|
6647
6936
|
const { file, node } = source;
|
|
6648
|
-
const
|
|
6649
|
-
if (body === null) {
|
|
6937
|
+
const { written, spellings } = read;
|
|
6938
|
+
if (read.body === null) {
|
|
6650
6939
|
return EMPTY_SCAN;
|
|
6651
6940
|
}
|
|
6652
6941
|
const ownParameters = callParameterNames(node, source.exportPath.length > 1);
|
|
6653
|
-
const recordPassedArgs = (call, callee, calleeKey
|
|
6942
|
+
const recordPassedArgs = (call, callee, calleeKey) => {
|
|
6654
6943
|
const args = field(call, "arguments");
|
|
6655
6944
|
if (args === null) {
|
|
6656
6945
|
return;
|
|
@@ -6659,9 +6948,8 @@ function scanBody(source, ctx, recognized) {
|
|
|
6659
6948
|
if (arg === null || arg.type !== "identifier") {
|
|
6660
6949
|
return;
|
|
6661
6950
|
}
|
|
6662
|
-
const resolved =
|
|
6663
|
-
|
|
6664
|
-
{ file, scope: where.scope, rebound: where.rebound },
|
|
6951
|
+
const resolved = functionNamed(
|
|
6952
|
+
readKey(file.file, arg, enclosingFunction(arg)),
|
|
6665
6953
|
ctx
|
|
6666
6954
|
);
|
|
6667
6955
|
if (resolved === null) {
|
|
@@ -6681,13 +6969,9 @@ function scanBody(source, ctx, recognized) {
|
|
|
6681
6969
|
}
|
|
6682
6970
|
});
|
|
6683
6971
|
};
|
|
6684
|
-
const record = (call,
|
|
6972
|
+
const record = (call, site) => {
|
|
6685
6973
|
const callee = calleeText(call);
|
|
6686
|
-
const outcome = resolveCallee2(
|
|
6687
|
-
call,
|
|
6688
|
-
{ file, scope: where.scope, rebound: where.rebound },
|
|
6689
|
-
ctx
|
|
6690
|
-
);
|
|
6974
|
+
const outcome = resolveCallee2(call, site, ctx, spellings);
|
|
6691
6975
|
const placed = outcome.kind === "followed" ? {
|
|
6692
6976
|
file: outcome.target.file.displayPath,
|
|
6693
6977
|
span: spanOf(outcome.target.node)
|
|
@@ -6696,8 +6980,7 @@ function scanBody(source, ctx, recognized) {
|
|
|
6696
6980
|
recordPassedArgs(
|
|
6697
6981
|
call,
|
|
6698
6982
|
callee,
|
|
6699
|
-
outcome.kind === "followed" ? keyOf(outcome.target) : null
|
|
6700
|
-
where
|
|
6983
|
+
outcome.kind === "followed" ? keyOf(outcome.target) : null
|
|
6701
6984
|
);
|
|
6702
6985
|
if (outcome.kind === "stopped") {
|
|
6703
6986
|
const stopKey = `${outcome.reason}:${callee}`;
|
|
@@ -6720,32 +7003,9 @@ function scanBody(source, ctx, recognized) {
|
|
|
6720
7003
|
followed.push(outcome.target);
|
|
6721
7004
|
}
|
|
6722
7005
|
};
|
|
6723
|
-
(
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
{
|
|
6727
|
-
at: (child, where) => {
|
|
6728
|
-
if (child.type === "call") {
|
|
6729
|
-
record(child, where);
|
|
6730
|
-
}
|
|
6731
|
-
},
|
|
6732
|
-
into: (child, where) => {
|
|
6733
|
-
if (child.type === "function_definition") {
|
|
6734
|
-
return import_extractor7.SKIP_CHILDREN;
|
|
6735
|
-
}
|
|
6736
|
-
if (child.type === "lambda") {
|
|
6737
|
-
return {
|
|
6738
|
-
scope: where.scope,
|
|
6739
|
-
rebound: /* @__PURE__ */ new Set([...where.rebound, ...lambdaParameters(child)])
|
|
6740
|
-
};
|
|
6741
|
-
}
|
|
6742
|
-
return {
|
|
6743
|
-
scope: file.module.scopeFor.get(child.id) ?? where.scope,
|
|
6744
|
-
rebound: where.rebound
|
|
6745
|
-
};
|
|
6746
|
-
}
|
|
6747
|
-
}
|
|
6748
|
-
);
|
|
7006
|
+
for (const { call, site } of written) {
|
|
7007
|
+
record(call, site);
|
|
7008
|
+
}
|
|
6749
7009
|
return {
|
|
6750
7010
|
followed,
|
|
6751
7011
|
stops,
|
|
@@ -6755,6 +7015,18 @@ function scanBody(source, ctx, recognized) {
|
|
|
6755
7015
|
passedPositions
|
|
6756
7016
|
};
|
|
6757
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
|
+
}
|
|
6758
7030
|
function scopeAt2(file, node) {
|
|
6759
7031
|
let current = node;
|
|
6760
7032
|
while (current !== null) {
|
|
@@ -6766,40 +7038,6 @@ function scopeAt2(file, node) {
|
|
|
6766
7038
|
}
|
|
6767
7039
|
return file.module.moduleScope;
|
|
6768
7040
|
}
|
|
6769
|
-
var REBINDING_FIELDS = {
|
|
6770
|
-
assignment: "left",
|
|
6771
|
-
augmented_assignment: "left",
|
|
6772
|
-
named_expression: "name",
|
|
6773
|
-
for_statement: "left",
|
|
6774
|
-
for_in_clause: "left",
|
|
6775
|
-
as_pattern: "alias"
|
|
6776
|
-
};
|
|
6777
|
-
function reboundNames(body) {
|
|
6778
|
-
const names = /* @__PURE__ */ new Set();
|
|
6779
|
-
(0, import_extractor7.walkDescendants)(body, null, {
|
|
6780
|
-
at: (node) => {
|
|
6781
|
-
const target = REBINDING_FIELDS[node.type];
|
|
6782
|
-
if (target === void 0 || boundByBinder(node, body)) {
|
|
6783
|
-
return;
|
|
6784
|
-
}
|
|
6785
|
-
const written = field(node, target);
|
|
6786
|
-
if (written !== null) {
|
|
6787
|
-
for (const name of identifiersUnder(written)) {
|
|
6788
|
-
names.add(name);
|
|
6789
|
-
}
|
|
6790
|
-
}
|
|
6791
|
-
},
|
|
6792
|
-
into: (node) => node.type === "function_definition" ? import_extractor7.SKIP_CHILDREN : null
|
|
6793
|
-
});
|
|
6794
|
-
return names;
|
|
6795
|
-
}
|
|
6796
|
-
function boundByBinder(node, body) {
|
|
6797
|
-
if (node.type !== "assignment") {
|
|
6798
|
-
return false;
|
|
6799
|
-
}
|
|
6800
|
-
const statement = node.parent;
|
|
6801
|
-
return field(node, "left")?.type === "identifier" && statement?.type === "expression_statement" && statement.parent?.id === body.id;
|
|
6802
|
-
}
|
|
6803
7041
|
function identifiersUnder(node, found = []) {
|
|
6804
7042
|
if (node.type === "identifier") {
|
|
6805
7043
|
found.push(node.text);
|
|
@@ -6812,10 +7050,6 @@ function identifiersUnder(node, found = []) {
|
|
|
6812
7050
|
}
|
|
6813
7051
|
return found;
|
|
6814
7052
|
}
|
|
6815
|
-
function lambdaParameters(lambda) {
|
|
6816
|
-
const parameters = field(lambda, "parameters");
|
|
6817
|
-
return parameters === null ? [] : identifiersUnder(parameters);
|
|
6818
|
-
}
|
|
6819
7053
|
function libraryUnit(target, options) {
|
|
6820
7054
|
const { file, node, name, exportPath } = target;
|
|
6821
7055
|
const body = field(node, "body");
|
|
@@ -6966,6 +7200,18 @@ var PythonWrapperIndex = class {
|
|
|
6966
7200
|
ownRoutes = /* @__PURE__ */ new Map();
|
|
6967
7201
|
unitsByKey = /* @__PURE__ */ new Map();
|
|
6968
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
|
+
}
|
|
6969
7215
|
register(covers, target, declared) {
|
|
6970
7216
|
const registered = this.registered(target, declared);
|
|
6971
7217
|
const table = covers.kind === "everyRoute" ? this.everyRoute : this.ownRoutes;
|
|
@@ -7012,20 +7258,12 @@ var PythonWrapperIndex = class {
|
|
|
7012
7258
|
if (declared.form.type !== "dependency") {
|
|
7013
7259
|
continue;
|
|
7014
7260
|
}
|
|
7015
|
-
const site = {
|
|
7016
|
-
file,
|
|
7017
|
-
scope: query.module.moduleScope,
|
|
7018
|
-
rebound: /* @__PURE__ */ new Set()
|
|
7019
|
-
};
|
|
7020
7261
|
const targets = [
|
|
7021
7262
|
...decoratorDependencies(query.classification, declared.form),
|
|
7022
7263
|
...parameterDependencies(query.definitionNode, declared.form)
|
|
7023
7264
|
];
|
|
7024
7265
|
for (const name of targets) {
|
|
7025
|
-
const target =
|
|
7026
|
-
filesByPath: this.filesByPath,
|
|
7027
|
-
roots: this.options.roots
|
|
7028
|
-
});
|
|
7266
|
+
const target = this.functionCalled(file.file, name);
|
|
7029
7267
|
if (target !== null) {
|
|
7030
7268
|
found.push(this.registered(target, declared));
|
|
7031
7269
|
}
|
|
@@ -7167,12 +7405,8 @@ function registerConstructorDependencies(file, declared, form, index) {
|
|
|
7167
7405
|
if (listed === void 0) {
|
|
7168
7406
|
continue;
|
|
7169
7407
|
}
|
|
7170
|
-
const site = { file, scope, rebound: /* @__PURE__ */ new Set() };
|
|
7171
7408
|
for (const name of dependencyNamesIn(listed.node, form)) {
|
|
7172
|
-
const target =
|
|
7173
|
-
filesByPath: index.filesByPath,
|
|
7174
|
-
roots: index.options.roots
|
|
7175
|
-
});
|
|
7409
|
+
const target = index.functionCalled(file.file, name);
|
|
7176
7410
|
if (target !== null) {
|
|
7177
7411
|
index.register(
|
|
7178
7412
|
coverageOf(match, file, declared.pack),
|
|
@@ -7434,9 +7668,9 @@ async function extractPythonProject(options) {
|
|
|
7434
7668
|
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
7435
7669
|
if (lookup.kind === "hit") {
|
|
7436
7670
|
options.onTiming?.(timer.report());
|
|
7437
|
-
return { summaries: lookup.summaries, facts: new
|
|
7671
|
+
return { summaries: lookup.summaries, facts: new import_datalog2.Database() };
|
|
7438
7672
|
}
|
|
7439
|
-
const db = new
|
|
7673
|
+
const db = new import_datalog2.Database();
|
|
7440
7674
|
const summaries = [];
|
|
7441
7675
|
const gapHandling = options.gapHandling ?? "permissive";
|
|
7442
7676
|
const tallies = (0, import_extractor6.createPackTallies)(options.packs);
|
|
@@ -7500,6 +7734,7 @@ async function extractPythonProject(options) {
|
|
|
7500
7734
|
packs: options.packs,
|
|
7501
7735
|
roots: options.roots,
|
|
7502
7736
|
facts: needsValues ? db : void 0,
|
|
7737
|
+
definitions,
|
|
7503
7738
|
storageFor
|
|
7504
7739
|
})
|
|
7505
7740
|
);
|
|
@@ -7583,7 +7818,9 @@ async function extractPythonProject(options) {
|
|
|
7583
7818
|
files: bound,
|
|
7584
7819
|
roots: options.roots,
|
|
7585
7820
|
gapHandling,
|
|
7586
|
-
storageFor
|
|
7821
|
+
storageFor,
|
|
7822
|
+
facts: db,
|
|
7823
|
+
definitions
|
|
7587
7824
|
})
|
|
7588
7825
|
);
|
|
7589
7826
|
for (const [key, owners] of summariesBySeed) {
|
|
@@ -7774,7 +8011,7 @@ function width(node) {
|
|
|
7774
8011
|
}
|
|
7775
8012
|
var PythonWhySession = class {
|
|
7776
8013
|
root;
|
|
7777
|
-
db = new
|
|
8014
|
+
db = new import_datalog3.Database();
|
|
7778
8015
|
locations = /* @__PURE__ */ new Map();
|
|
7779
8016
|
trees = /* @__PURE__ */ new Map();
|
|
7780
8017
|
constructor(options) {
|
|
@@ -7843,9 +8080,9 @@ var PythonWhySession = class {
|
|
|
7843
8080
|
* which the caller says in its own words.
|
|
7844
8081
|
*/
|
|
7845
8082
|
explain(value, options = {}) {
|
|
7846
|
-
return (0,
|
|
8083
|
+
return (0, import_resolution6.explainResolvedKey)({
|
|
7847
8084
|
db: this.db,
|
|
7848
|
-
rules:
|
|
8085
|
+
rules: import_resolution6.RESOLUTION_RULES,
|
|
7849
8086
|
key: readKey(value.file, value.node, enclosingFunction(value.node)),
|
|
7850
8087
|
locate: (key) => this.locate(key),
|
|
7851
8088
|
displayPath: (key) => this.displayPath(key),
|
|
@@ -7976,6 +8213,7 @@ async function pythonImportEvidence(options) {
|
|
|
7976
8213
|
emitValueFacts,
|
|
7977
8214
|
extractPythonProject,
|
|
7978
8215
|
findPythonFiles,
|
|
8216
|
+
nameKeyIn,
|
|
7979
8217
|
nodeId,
|
|
7980
8218
|
objectReturnedBy,
|
|
7981
8219
|
parsePython,
|