@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.js
CHANGED
|
@@ -24,6 +24,11 @@ function isType(node, ...types) {
|
|
|
24
24
|
function isFunction(node) {
|
|
25
25
|
return node.type === "function_definition" || node.type === "lambda";
|
|
26
26
|
}
|
|
27
|
+
var LATER_BODY_TYPES = /* @__PURE__ */ new Set([
|
|
28
|
+
"function_definition",
|
|
29
|
+
"lambda",
|
|
30
|
+
"class_definition"
|
|
31
|
+
]);
|
|
27
32
|
function enclosingFunction(node) {
|
|
28
33
|
let current = node.parent;
|
|
29
34
|
while (current !== null) {
|
|
@@ -1408,14 +1413,14 @@ function invocationEffects(definitionNode) {
|
|
|
1408
1413
|
if (calls.length === 0) {
|
|
1409
1414
|
return [];
|
|
1410
1415
|
}
|
|
1411
|
-
const
|
|
1416
|
+
const statementOf3 = /* @__PURE__ */ new Map();
|
|
1412
1417
|
const statements = [];
|
|
1413
1418
|
for (const call of calls) {
|
|
1414
1419
|
const statement = enclosingStatement(call, body);
|
|
1415
1420
|
if (statement === null) {
|
|
1416
1421
|
continue;
|
|
1417
1422
|
}
|
|
1418
|
-
|
|
1423
|
+
statementOf3.set(call.id, statement);
|
|
1419
1424
|
statements.push(statement);
|
|
1420
1425
|
}
|
|
1421
1426
|
const lowered = lowerPythonBody(body, statements);
|
|
@@ -1427,7 +1432,7 @@ function invocationEffects(definitionNode) {
|
|
|
1427
1432
|
statements
|
|
1428
1433
|
);
|
|
1429
1434
|
return calls.map((call) => {
|
|
1430
|
-
const statement =
|
|
1435
|
+
const statement = statementOf3.get(call.id);
|
|
1431
1436
|
const conditions = sharedGatingConditions(
|
|
1432
1437
|
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement),
|
|
1433
1438
|
predicateOf
|
|
@@ -1446,40 +1451,22 @@ function invocationEffects(definitionNode) {
|
|
|
1446
1451
|
import { mountPathsOf } from "@suss/resolution";
|
|
1447
1452
|
|
|
1448
1453
|
// src/facts/resolve.ts
|
|
1449
|
-
import { deriveOnDemand, evaluate } from "@suss/datalog";
|
|
1450
1454
|
import {
|
|
1451
|
-
|
|
1455
|
+
askResolution,
|
|
1452
1456
|
placeholderValues,
|
|
1453
|
-
RESOLUTION_QUESTIONS,
|
|
1454
|
-
RESOLUTION_RULES,
|
|
1455
1457
|
writtenValueOf as sharedWrittenValueOf,
|
|
1456
1458
|
singleAnswers
|
|
1457
1459
|
} from "@suss/resolution";
|
|
1458
|
-
var RESOLUTION_PROGRAM = deriveOnDemand(
|
|
1459
|
-
[...RESOLUTION_RULES, ...RESOLUTION_QUESTIONS],
|
|
1460
|
-
ANSWER_RELATIONS
|
|
1461
|
-
);
|
|
1462
1460
|
function resolveCalls(db, callKeys) {
|
|
1463
|
-
|
|
1464
|
-
const fresh = callKeys.filter((key) => !asked.has(key));
|
|
1465
|
-
if (fresh.length === 0) {
|
|
1466
|
-
return;
|
|
1467
|
-
}
|
|
1468
|
-
for (const callKey of fresh) {
|
|
1469
|
-
db.add("wanted", [callKey]);
|
|
1470
|
-
}
|
|
1471
|
-
evaluate(db, RESOLUTION_PROGRAM.rules);
|
|
1461
|
+
askResolution(db, callKeys);
|
|
1472
1462
|
}
|
|
1473
1463
|
function writtenValueOf(db, key) {
|
|
1474
1464
|
resolveCalls(db, [key]);
|
|
1475
1465
|
return sharedWrittenValueOf(db, key, (keys) => resolveCalls(db, keys));
|
|
1476
1466
|
}
|
|
1477
|
-
function originsOf(db,
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
evaluate(db, RESOLUTION_PROGRAM.rules);
|
|
1481
|
-
}
|
|
1482
|
-
return db.facts("wantedComesFrom").filter((row) => String(row[0]) === nameKey).map((row) => ({ module: String(row[1]), name: String(row[2]) }));
|
|
1467
|
+
function originsOf(db, nameKey2) {
|
|
1468
|
+
askResolution(db, [nameKey2], "wantedOrigin");
|
|
1469
|
+
return db.facts("wantedComesFrom").filter((row) => String(row[0]) === nameKey2).map((row) => ({ module: String(row[1]), name: String(row[2]) }));
|
|
1483
1470
|
}
|
|
1484
1471
|
function subjectConstructions(db, valueKeys) {
|
|
1485
1472
|
const found = /* @__PURE__ */ new Map();
|
|
@@ -1487,10 +1474,7 @@ function subjectConstructions(db, valueKeys) {
|
|
|
1487
1474
|
return found;
|
|
1488
1475
|
}
|
|
1489
1476
|
const askSubjects = (keys) => {
|
|
1490
|
-
|
|
1491
|
-
db.add("wantedSubject", [key]);
|
|
1492
|
-
}
|
|
1493
|
-
evaluate(db, RESOLUTION_PROGRAM.rules);
|
|
1477
|
+
askResolution(db, keys, "wantedSubject");
|
|
1494
1478
|
};
|
|
1495
1479
|
askSubjects(valueKeys);
|
|
1496
1480
|
const placeholders = placeholderValues(db);
|
|
@@ -1537,6 +1521,11 @@ function objectReturnedBy(db, callKey) {
|
|
|
1537
1521
|
}
|
|
1538
1522
|
|
|
1539
1523
|
// src/facts/values.ts
|
|
1524
|
+
import {
|
|
1525
|
+
startsAtName,
|
|
1526
|
+
valueLeftByWrites,
|
|
1527
|
+
writesRunInOrder
|
|
1528
|
+
} from "@suss/resolution";
|
|
1540
1529
|
function nodeId(filePath, node) {
|
|
1541
1530
|
return `${filePath}:${node.startIndex}-${node.endIndex}`;
|
|
1542
1531
|
}
|
|
@@ -1547,10 +1536,10 @@ function readKey(filePath, node, enclosing) {
|
|
|
1547
1536
|
if (node.type !== "identifier") {
|
|
1548
1537
|
return nodeId(filePath, node);
|
|
1549
1538
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
return
|
|
1539
|
+
return nameKeyIn(filePath, enclosing, node.text);
|
|
1540
|
+
}
|
|
1541
|
+
function nameKeyIn(filePath, enclosing, name) {
|
|
1542
|
+
return nameKey(filePath, scopeChainOf(filePath, enclosing), name);
|
|
1554
1543
|
}
|
|
1555
1544
|
var WRITTEN_VALUE_TYPES = /* @__PURE__ */ new Set([
|
|
1556
1545
|
"string",
|
|
@@ -1588,9 +1577,6 @@ function parameterName2(param) {
|
|
|
1588
1577
|
}
|
|
1589
1578
|
return children(param).find((child) => child.type === "identifier") ?? null;
|
|
1590
1579
|
}
|
|
1591
|
-
function parameterList(fn) {
|
|
1592
|
-
return parameterShapes(fn).map((parameter) => parameter.name);
|
|
1593
|
-
}
|
|
1594
1580
|
function parameterShapes(fn) {
|
|
1595
1581
|
const params = field(fn, "parameters");
|
|
1596
1582
|
const declared = [];
|
|
@@ -1605,24 +1591,52 @@ function parameterShapes(fn) {
|
|
|
1605
1591
|
}
|
|
1606
1592
|
return declared;
|
|
1607
1593
|
}
|
|
1608
|
-
function
|
|
1609
|
-
|
|
1594
|
+
function boundParameterNames(fn) {
|
|
1595
|
+
const params = field(fn, "parameters");
|
|
1596
|
+
const names = [];
|
|
1597
|
+
for (const param of params === null ? [] : children(params)) {
|
|
1598
|
+
const name = parameterName2(param);
|
|
1599
|
+
if (name !== null) {
|
|
1600
|
+
names.push(name.text);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
return names;
|
|
1610
1604
|
}
|
|
1611
1605
|
function add(emitter, relation, ...tuple) {
|
|
1612
1606
|
emitter.db.add(relation, tuple);
|
|
1613
1607
|
}
|
|
1608
|
+
function nameKey(filePath, scope, name) {
|
|
1609
|
+
for (let current = scope; current !== null; current = current.parent) {
|
|
1610
|
+
if (current.globals.has(name)) {
|
|
1611
|
+
return nameId(filePath, name);
|
|
1612
|
+
}
|
|
1613
|
+
if (current.locals.has(name)) {
|
|
1614
|
+
return `${current.funcKey}#${name}`;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
return nameId(filePath, name);
|
|
1618
|
+
}
|
|
1619
|
+
function scopeChainOf(filePath, fn) {
|
|
1620
|
+
if (fn === null) {
|
|
1621
|
+
return null;
|
|
1622
|
+
}
|
|
1623
|
+
const reading = scopeReadingOf(fn);
|
|
1624
|
+
return {
|
|
1625
|
+
funcKey: nodeId(filePath, fn),
|
|
1626
|
+
locals: reading.locals,
|
|
1627
|
+
globals: reading.globals,
|
|
1628
|
+
parent: scopeChainOf(filePath, enclosingFunction(fn))
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1614
1631
|
function emitCall(emitter, call) {
|
|
1615
1632
|
add(emitter, "writtenValue", nodeId(emitter.filePath, call));
|
|
1616
1633
|
const callee = field(call, "function");
|
|
1617
|
-
|
|
1634
|
+
const args = field(call, "arguments");
|
|
1635
|
+
if (callee === null || args === null) {
|
|
1618
1636
|
return;
|
|
1619
1637
|
}
|
|
1620
1638
|
const callKey = nodeId(emitter.filePath, call);
|
|
1621
1639
|
add(emitter, "call", callKey, valueKey(emitter, callee));
|
|
1622
|
-
const args = field(call, "arguments");
|
|
1623
|
-
if (args === null) {
|
|
1624
|
-
return;
|
|
1625
|
-
}
|
|
1626
1640
|
let position = 0;
|
|
1627
1641
|
for (const argument of children(args)) {
|
|
1628
1642
|
if (argument.type === "keyword_argument") {
|
|
@@ -1653,11 +1667,7 @@ function valueKey(emitter, value) {
|
|
|
1653
1667
|
if (value.type !== "identifier") {
|
|
1654
1668
|
return nodeId(emitter.filePath, value);
|
|
1655
1669
|
}
|
|
1656
|
-
|
|
1657
|
-
if (enclosing !== null && enclosing.params.has(value.text)) {
|
|
1658
|
-
return `${enclosing.funcKey}#${value.text}`;
|
|
1659
|
-
}
|
|
1660
|
-
return nameId(emitter.filePath, value.text);
|
|
1670
|
+
return nameKey(emitter.filePath, emitter.enclosing, value.text);
|
|
1661
1671
|
}
|
|
1662
1672
|
function emitSequence(emitter, sequence) {
|
|
1663
1673
|
const objectKey = nodeId(emitter.filePath, sequence);
|
|
@@ -1747,7 +1757,6 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1747
1757
|
const funcKey = nodeId(emitter.filePath, fn);
|
|
1748
1758
|
add(emitter, "func", funcKey);
|
|
1749
1759
|
const params = field(fn, "parameters");
|
|
1750
|
-
const declared = parameterNames(fn);
|
|
1751
1760
|
let position = classKey === void 0 ? 0 : -1;
|
|
1752
1761
|
let byPosition = true;
|
|
1753
1762
|
let receiver = null;
|
|
@@ -1770,24 +1779,22 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1770
1779
|
}
|
|
1771
1780
|
position += 1;
|
|
1772
1781
|
}
|
|
1782
|
+
const reading = scopeReadingOf(fn);
|
|
1773
1783
|
const inside = {
|
|
1774
1784
|
...emitter,
|
|
1775
|
-
enclosing: {
|
|
1785
|
+
enclosing: {
|
|
1786
|
+
funcKey,
|
|
1787
|
+
locals: reading.locals,
|
|
1788
|
+
globals: reading.globals,
|
|
1789
|
+
parent: emitter.enclosing
|
|
1790
|
+
}
|
|
1776
1791
|
};
|
|
1792
|
+
emitScopeWrites(inside, reading, false);
|
|
1777
1793
|
const body = field(fn, "body");
|
|
1778
1794
|
if (body === null) {
|
|
1779
1795
|
return funcKey;
|
|
1780
1796
|
}
|
|
1781
|
-
|
|
1782
|
-
for (const child of children(node)) {
|
|
1783
|
-
if (isFunction(child)) {
|
|
1784
|
-
add(emitter, "containsFn", funcKey, nodeId(emitter.filePath, child));
|
|
1785
|
-
continue;
|
|
1786
|
-
}
|
|
1787
|
-
recordNested(child);
|
|
1788
|
-
}
|
|
1789
|
-
};
|
|
1790
|
-
recordNested(body);
|
|
1797
|
+
emitNestedDefinitions(inside, body);
|
|
1791
1798
|
walkExpressions(inside, body, (child) => {
|
|
1792
1799
|
if (child.type === "return_statement") {
|
|
1793
1800
|
const returned = child.namedChildren[0];
|
|
@@ -1798,29 +1805,17 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1798
1805
|
if (child.type === "call") {
|
|
1799
1806
|
add(inside, "bodyCalls", funcKey, nodeId(inside.filePath, child));
|
|
1800
1807
|
}
|
|
1801
|
-
if (child.type === "assignment") {
|
|
1802
|
-
|
|
1808
|
+
if (child.type === "assignment" && receiver !== null) {
|
|
1809
|
+
emitReceiverProperty(inside, child, receiver);
|
|
1803
1810
|
}
|
|
1804
1811
|
emitExpressionFact(inside, child);
|
|
1805
1812
|
});
|
|
1806
1813
|
return funcKey;
|
|
1807
1814
|
}
|
|
1808
|
-
function
|
|
1815
|
+
function emitReceiverProperty(emitter, assignment2, receiver) {
|
|
1809
1816
|
const left = field(assignment2, "left");
|
|
1810
1817
|
const right = field(assignment2, "right");
|
|
1811
|
-
if (left === null || right === null) {
|
|
1812
|
-
return;
|
|
1813
|
-
}
|
|
1814
|
-
if (left.type === "identifier") {
|
|
1815
|
-
add(
|
|
1816
|
-
emitter,
|
|
1817
|
-
"binds",
|
|
1818
|
-
nameId(emitter.filePath, left.text),
|
|
1819
|
-
valueKey(emitter, assignedValue(right))
|
|
1820
|
-
);
|
|
1821
|
-
return;
|
|
1822
|
-
}
|
|
1823
|
-
if (receiver === null || left.type !== "attribute") {
|
|
1818
|
+
if (left === null || right === null || left.type !== "attribute") {
|
|
1824
1819
|
return;
|
|
1825
1820
|
}
|
|
1826
1821
|
const object = field(left, "object");
|
|
@@ -1836,21 +1831,6 @@ function emitBinding(emitter, assignment2, receiver) {
|
|
|
1836
1831
|
valueKey(emitter, right)
|
|
1837
1832
|
);
|
|
1838
1833
|
}
|
|
1839
|
-
function emitAssignment(emitter, assignment2) {
|
|
1840
|
-
emitBinding(emitter, assignment2, null);
|
|
1841
|
-
const left = field(assignment2, "left");
|
|
1842
|
-
const right = field(assignment2, "right");
|
|
1843
|
-
if (left === null || right === null || left.type !== "identifier") {
|
|
1844
|
-
return;
|
|
1845
|
-
}
|
|
1846
|
-
add(
|
|
1847
|
-
emitter,
|
|
1848
|
-
"exportsAs",
|
|
1849
|
-
emitter.filePath,
|
|
1850
|
-
left.text,
|
|
1851
|
-
valueKey(emitter, assignedValue(right))
|
|
1852
|
-
);
|
|
1853
|
-
}
|
|
1854
1834
|
function assignedValue(right) {
|
|
1855
1835
|
if (right.type !== "subscript") {
|
|
1856
1836
|
return right;
|
|
@@ -1901,40 +1881,361 @@ function emitClassFacts(emitter, cls) {
|
|
|
1901
1881
|
}
|
|
1902
1882
|
continue;
|
|
1903
1883
|
}
|
|
1904
|
-
const
|
|
1884
|
+
const memberKey2 = declaredMemberKey(emitter, member, classKey);
|
|
1905
1885
|
const name = field(member, "name");
|
|
1906
|
-
if (
|
|
1907
|
-
add(emitter, "holdsProperty", classKey, name.text,
|
|
1886
|
+
if (memberKey2 !== null && name !== null) {
|
|
1887
|
+
add(emitter, "holdsProperty", classKey, name.text, memberKey2);
|
|
1908
1888
|
}
|
|
1909
1889
|
}
|
|
1910
1890
|
return classKey;
|
|
1911
1891
|
}
|
|
1912
|
-
function
|
|
1913
|
-
const
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1892
|
+
function emitNestedDefinitions(emitter, node) {
|
|
1893
|
+
for (const child of children(node)) {
|
|
1894
|
+
if (isFunction(child)) {
|
|
1895
|
+
emitFunctionFacts(emitter, child);
|
|
1896
|
+
if (emitter.enclosing !== null) {
|
|
1897
|
+
add(
|
|
1898
|
+
emitter,
|
|
1899
|
+
"containsFn",
|
|
1900
|
+
emitter.enclosing.funcKey,
|
|
1901
|
+
nodeId(emitter.filePath, child)
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1904
|
+
continue;
|
|
1905
|
+
}
|
|
1906
|
+
if (child.type === "class_definition") {
|
|
1907
|
+
emitClassFacts(emitter, child);
|
|
1908
|
+
continue;
|
|
1909
|
+
}
|
|
1910
|
+
emitNestedDefinitions(emitter, child);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
var readingsByTree = /* @__PURE__ */ new WeakMap();
|
|
1914
|
+
function scopeReadingOf(fn) {
|
|
1915
|
+
const tree = fn.tree;
|
|
1916
|
+
let byNode = readingsByTree.get(tree);
|
|
1917
|
+
if (byNode === void 0) {
|
|
1918
|
+
byNode = /* @__PURE__ */ new Map();
|
|
1919
|
+
readingsByTree.set(tree, byNode);
|
|
1920
|
+
}
|
|
1921
|
+
const remembered = byNode.get(fn.id);
|
|
1922
|
+
if (remembered !== void 0) {
|
|
1923
|
+
return remembered;
|
|
1924
|
+
}
|
|
1925
|
+
const body = field(fn, "body");
|
|
1926
|
+
const reading = readScope(
|
|
1927
|
+
body !== null && body.type === "block" ? body : null,
|
|
1928
|
+
boundParameterNames(fn)
|
|
1929
|
+
);
|
|
1930
|
+
byNode.set(fn.id, reading);
|
|
1931
|
+
return reading;
|
|
1932
|
+
}
|
|
1933
|
+
var TARGET_PATTERN_TYPES = /* @__PURE__ */ new Set([
|
|
1934
|
+
"pattern_list",
|
|
1935
|
+
"tuple_pattern",
|
|
1936
|
+
"list_pattern"
|
|
1937
|
+
]);
|
|
1938
|
+
function targetNames(target, found = []) {
|
|
1939
|
+
if (target.type === "identifier") {
|
|
1940
|
+
found.push(target);
|
|
1941
|
+
return found;
|
|
1942
|
+
}
|
|
1943
|
+
if (TARGET_PATTERN_TYPES.has(target.type)) {
|
|
1944
|
+
for (const child of children(target)) {
|
|
1945
|
+
targetNames(child, found);
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
return found;
|
|
1949
|
+
}
|
|
1950
|
+
function readAssignment(node, sink) {
|
|
1951
|
+
const left = field(node, "left");
|
|
1952
|
+
const right = field(node, "right");
|
|
1953
|
+
if (left === null) {
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
const written = right === null ? null : assignedValue(right);
|
|
1957
|
+
const names = targetNames(left);
|
|
1958
|
+
for (const name of names) {
|
|
1959
|
+
sink.record(name.text, {
|
|
1960
|
+
// An unpacked target takes one piece of the value, and which piece
|
|
1961
|
+
// is not something the assignment says.
|
|
1962
|
+
value: names.length === 1 ? written : null,
|
|
1963
|
+
given: null,
|
|
1964
|
+
at: node,
|
|
1965
|
+
direct: isDirectStatement(node, sink.bodyOwner)
|
|
1966
|
+
});
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
function readAugmentedAssignment(node, sink) {
|
|
1970
|
+
const left = field(node, "left");
|
|
1971
|
+
if (left === null || left.type !== "identifier") {
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1974
|
+
sink.record(left.text, {
|
|
1975
|
+
value: null,
|
|
1976
|
+
given: null,
|
|
1977
|
+
at: node,
|
|
1978
|
+
direct: isDirectStatement(node, sink.bodyOwner)
|
|
1979
|
+
});
|
|
1980
|
+
}
|
|
1981
|
+
function readIterationTarget(node, sink) {
|
|
1982
|
+
const left = field(node, "left");
|
|
1983
|
+
if (left === null) {
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
for (const name of targetNames(left)) {
|
|
1987
|
+
sink.record(name.text, {
|
|
1988
|
+
value: null,
|
|
1989
|
+
given: null,
|
|
1990
|
+
at: node,
|
|
1991
|
+
direct: false
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
function identifierOf(node) {
|
|
1996
|
+
if (node.type === "identifier") {
|
|
1997
|
+
return node;
|
|
1998
|
+
}
|
|
1999
|
+
return children(node).find((child) => child.type === "identifier") ?? null;
|
|
2000
|
+
}
|
|
2001
|
+
function readAsPattern(node, sink) {
|
|
2002
|
+
const target = field(node, "alias") ?? children(node)[1];
|
|
2003
|
+
const name = target === void 0 ? null : identifierOf(target);
|
|
2004
|
+
if (name === null) {
|
|
2005
|
+
return;
|
|
2006
|
+
}
|
|
2007
|
+
sink.record(name.text, {
|
|
2008
|
+
value: null,
|
|
2009
|
+
given: null,
|
|
2010
|
+
at: node,
|
|
2011
|
+
direct: false
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
function readWalrus(node, sink) {
|
|
2015
|
+
const name = field(node, "name");
|
|
2016
|
+
if (name === null || name.type !== "identifier") {
|
|
2017
|
+
return;
|
|
2018
|
+
}
|
|
2019
|
+
sink.record(name.text, {
|
|
2020
|
+
value: field(node, "value"),
|
|
2021
|
+
given: null,
|
|
2022
|
+
at: node,
|
|
2023
|
+
direct: false
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
function readGlobalStatement(node, sink) {
|
|
2027
|
+
for (const child of children(node)) {
|
|
2028
|
+
if (child.type === "identifier") {
|
|
2029
|
+
sink.globals.add(child.text);
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
function readNonlocalStatement(node, sink) {
|
|
2034
|
+
for (const child of children(node)) {
|
|
2035
|
+
if (child.type === "identifier") {
|
|
2036
|
+
sink.nonlocals.add(child.text);
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
var WRITE_READERS = {
|
|
2041
|
+
assignment: readAssignment,
|
|
2042
|
+
augmented_assignment: readAugmentedAssignment,
|
|
2043
|
+
for_statement: readIterationTarget,
|
|
2044
|
+
for_in_clause: readIterationTarget,
|
|
2045
|
+
as_pattern: readAsPattern,
|
|
2046
|
+
named_expression: readWalrus,
|
|
2047
|
+
global_statement: readGlobalStatement,
|
|
2048
|
+
nonlocal_statement: readNonlocalStatement
|
|
2049
|
+
};
|
|
2050
|
+
function readScope(bodyOwner, parameterNames) {
|
|
2051
|
+
const writes = /* @__PURE__ */ new Map();
|
|
2052
|
+
const globals = /* @__PURE__ */ new Set();
|
|
2053
|
+
const nonlocals = /* @__PURE__ */ new Set();
|
|
2054
|
+
const record = (name, write) => {
|
|
2055
|
+
const existing = writes.get(name);
|
|
2056
|
+
if (existing === void 0) {
|
|
2057
|
+
writes.set(name, [write]);
|
|
1917
2058
|
return;
|
|
1918
2059
|
}
|
|
1919
|
-
|
|
1920
|
-
add(emitter, "exportsAs", filePath, name.text, key);
|
|
2060
|
+
existing.push(write);
|
|
1921
2061
|
};
|
|
1922
|
-
const
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
2062
|
+
const sink = { bodyOwner, globals, nonlocals, record };
|
|
2063
|
+
const visit = (node) => {
|
|
2064
|
+
if (isFunction(node) || node.type === "class_definition") {
|
|
2065
|
+
const name = field(node, "name");
|
|
2066
|
+
if (name !== null) {
|
|
2067
|
+
record(name.text, {
|
|
2068
|
+
value: node,
|
|
2069
|
+
given: null,
|
|
2070
|
+
at: node,
|
|
2071
|
+
direct: isDirectStatement(node, bodyOwner)
|
|
2072
|
+
});
|
|
1933
2073
|
}
|
|
1934
|
-
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
WRITE_READERS[node.type]?.(node, sink);
|
|
2077
|
+
for (const child of children(node)) {
|
|
2078
|
+
visit(child);
|
|
1935
2079
|
}
|
|
1936
2080
|
};
|
|
1937
|
-
|
|
2081
|
+
for (const statement of bodyOwner === null ? [] : children(bodyOwner)) {
|
|
2082
|
+
visit(statement);
|
|
2083
|
+
}
|
|
2084
|
+
const locals = new Set(writes.keys());
|
|
2085
|
+
for (const name of [...globals, ...nonlocals]) {
|
|
2086
|
+
locals.delete(name);
|
|
2087
|
+
}
|
|
2088
|
+
for (const name of parameterNames) {
|
|
2089
|
+
locals.add(name);
|
|
2090
|
+
addParameterWrite(writes.get(name), name);
|
|
2091
|
+
}
|
|
2092
|
+
return { bodyOwner, writes, locals, globals };
|
|
2093
|
+
}
|
|
2094
|
+
function addParameterWrite(later, name) {
|
|
2095
|
+
const first = later?.[0];
|
|
2096
|
+
if (later === void 0 || first === void 0) {
|
|
2097
|
+
return;
|
|
2098
|
+
}
|
|
2099
|
+
later.unshift({ value: null, given: name, at: first.at, direct: false });
|
|
2100
|
+
}
|
|
2101
|
+
function statementOf(node) {
|
|
2102
|
+
let current = node;
|
|
2103
|
+
while (current !== null) {
|
|
2104
|
+
const parent = current.parent;
|
|
2105
|
+
if (parent === null) {
|
|
2106
|
+
return null;
|
|
2107
|
+
}
|
|
2108
|
+
if (parent.type === "block" || parent.type === "module") {
|
|
2109
|
+
return current;
|
|
2110
|
+
}
|
|
2111
|
+
current = parent;
|
|
2112
|
+
}
|
|
2113
|
+
return null;
|
|
2114
|
+
}
|
|
2115
|
+
function isDirectStatement(node, bodyOwner) {
|
|
2116
|
+
if (bodyOwner === null) {
|
|
2117
|
+
return false;
|
|
2118
|
+
}
|
|
2119
|
+
const statement = statementOf(node);
|
|
2120
|
+
return statement !== null && statement.parent?.id === bodyOwner.id;
|
|
2121
|
+
}
|
|
2122
|
+
var UNREAD_PARENTS = /* @__PURE__ */ new Set([
|
|
2123
|
+
"as_pattern_target",
|
|
2124
|
+
"global_statement",
|
|
2125
|
+
"nonlocal_statement",
|
|
2126
|
+
"pattern_list",
|
|
2127
|
+
"tuple_pattern",
|
|
2128
|
+
"list_pattern",
|
|
2129
|
+
"dotted_name"
|
|
2130
|
+
]);
|
|
2131
|
+
var UNREAD_FIELDS = {
|
|
2132
|
+
assignment: "left",
|
|
2133
|
+
augmented_assignment: "left",
|
|
2134
|
+
for_statement: "left",
|
|
2135
|
+
for_in_clause: "left",
|
|
2136
|
+
named_expression: "name",
|
|
2137
|
+
function_definition: "name",
|
|
2138
|
+
class_definition: "name",
|
|
2139
|
+
attribute: "attribute",
|
|
2140
|
+
keyword_argument: "name"
|
|
2141
|
+
};
|
|
2142
|
+
function isNameRead(name) {
|
|
2143
|
+
const parent = name.parent;
|
|
2144
|
+
if (parent === null) {
|
|
2145
|
+
return true;
|
|
2146
|
+
}
|
|
2147
|
+
if (UNREAD_PARENTS.has(parent.type)) {
|
|
2148
|
+
return false;
|
|
2149
|
+
}
|
|
2150
|
+
const fieldName = UNREAD_FIELDS[parent.type];
|
|
2151
|
+
return fieldName === void 0 || field(parent, fieldName)?.id !== name.id;
|
|
2152
|
+
}
|
|
2153
|
+
var READ_FIRST = {
|
|
2154
|
+
call: "function",
|
|
2155
|
+
attribute: "object"
|
|
2156
|
+
};
|
|
2157
|
+
function readFirst(node) {
|
|
2158
|
+
if (node.type === "parenthesized_expression") {
|
|
2159
|
+
return children(node)[0] ?? null;
|
|
2160
|
+
}
|
|
2161
|
+
const fieldName = READ_FIRST[node.type];
|
|
2162
|
+
return fieldName === void 0 ? null : field(node, fieldName);
|
|
2163
|
+
}
|
|
2164
|
+
var NAME_READS = {
|
|
2165
|
+
nameTypes: /* @__PURE__ */ new Set(["identifier"]),
|
|
2166
|
+
laterBodies: LATER_BODY_TYPES,
|
|
2167
|
+
childrenOf: children,
|
|
2168
|
+
isRead: isNameRead,
|
|
2169
|
+
readFirst
|
|
2170
|
+
};
|
|
2171
|
+
var CONSTRUCTION_TYPES = /* @__PURE__ */ new Set([
|
|
2172
|
+
"call",
|
|
2173
|
+
"list",
|
|
2174
|
+
"dictionary",
|
|
2175
|
+
"set",
|
|
2176
|
+
"tuple",
|
|
2177
|
+
"list_comprehension",
|
|
2178
|
+
"dictionary_comprehension",
|
|
2179
|
+
"set_comprehension",
|
|
2180
|
+
"generator_expression"
|
|
2181
|
+
]);
|
|
2182
|
+
function describeWrite(emitter, write, name) {
|
|
2183
|
+
if (write.value === null) {
|
|
2184
|
+
return {
|
|
2185
|
+
value: write.given,
|
|
2186
|
+
placeholder: false,
|
|
2187
|
+
construction: null,
|
|
2188
|
+
narrowsName: false
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2191
|
+
return {
|
|
2192
|
+
value: valueKey(emitter, write.value),
|
|
2193
|
+
placeholder: write.value.type === "none",
|
|
2194
|
+
construction: CONSTRUCTION_TYPES.has(write.value.type) ? write.value.text.replace(/\s+/g, " ").trim() : null,
|
|
2195
|
+
narrowsName: write.value.type === "call" && startsAtName(write.value, name, NAME_READS)
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
function settledValue(emitter, reading, name, writes) {
|
|
2199
|
+
const only = writes.length === 1 ? writes[0] : void 0;
|
|
2200
|
+
if (only !== void 0) {
|
|
2201
|
+
return only.value === null ? only.given : valueKey(emitter, only.value);
|
|
2202
|
+
}
|
|
2203
|
+
return valueLeftByWrites(
|
|
2204
|
+
writes.map((write) => describeWrite(emitter, write, name)),
|
|
2205
|
+
writesRunInOrder(reading.bodyOwner, name, writes, NAME_READS)
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
function emitScopeWrites(emitter, reading, atModule) {
|
|
2209
|
+
for (const [name, writes] of reading.writes) {
|
|
2210
|
+
const settled = settledValue(emitter, reading, name, writes);
|
|
2211
|
+
const key = nameKey(emitter.filePath, emitter.enclosing, name);
|
|
2212
|
+
if (settled === null) {
|
|
2213
|
+
emitCandidates(emitter, key, name, writes);
|
|
2214
|
+
continue;
|
|
2215
|
+
}
|
|
2216
|
+
add(emitter, writes.length === 1 ? "binds" : "endsHolding", key, settled);
|
|
2217
|
+
if (atModule) {
|
|
2218
|
+
add(emitter, "exportsAs", emitter.filePath, name, settled);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
function emitCandidates(emitter, key, name, writes) {
|
|
2223
|
+
for (const write of writes) {
|
|
2224
|
+
if (write.value === null) {
|
|
2225
|
+
if (write.given === null) {
|
|
2226
|
+
add(emitter, "writesUnstated", key);
|
|
2227
|
+
}
|
|
2228
|
+
continue;
|
|
2229
|
+
}
|
|
2230
|
+
if (!describeWrite(emitter, write, name).narrowsName) {
|
|
2231
|
+
add(emitter, "mayHold", key, valueKey(emitter, write.value));
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
function emitValueFacts(db, filePath, root) {
|
|
2236
|
+
const emitter = { db, filePath, enclosing: null };
|
|
2237
|
+
emitNestedDefinitions(emitter, root);
|
|
2238
|
+
emitScopeWrites(emitter, readScope(root, []), true);
|
|
1938
2239
|
emitExpressionFacts(emitter, root);
|
|
1939
2240
|
}
|
|
1940
2241
|
|
|
@@ -2047,7 +2348,7 @@ function pythonLowering(options) {
|
|
|
2047
2348
|
return {
|
|
2048
2349
|
idOf: (node) => node.id,
|
|
2049
2350
|
expression: (node) => expressionOf(node, originOf2),
|
|
2050
|
-
statement:
|
|
2351
|
+
statement: statementOf2,
|
|
2051
2352
|
siteOf,
|
|
2052
2353
|
functionOf,
|
|
2053
2354
|
writtenTo: (node) => context === null ? null : context.writtenTo(node),
|
|
@@ -2311,7 +2612,7 @@ var STATEMENT_TYPES = {
|
|
|
2311
2612
|
body: blockStatements2(field(node, "body"))
|
|
2312
2613
|
})
|
|
2313
2614
|
};
|
|
2314
|
-
function
|
|
2615
|
+
function statementOf2(node) {
|
|
2315
2616
|
const lower = STATEMENT_TYPES[node.type];
|
|
2316
2617
|
return lower === void 0 ? { kind: "opaque" } : lower(node);
|
|
2317
2618
|
}
|
|
@@ -3381,9 +3682,13 @@ function constructionThroughFacts(name, scope, scan) {
|
|
|
3381
3682
|
if (binding.kind !== "assignment" && binding.kind !== "importFrom") {
|
|
3382
3683
|
return null;
|
|
3383
3684
|
}
|
|
3384
|
-
const
|
|
3385
|
-
|
|
3386
|
-
|
|
3685
|
+
const nameKey2 = nameKeyIn(
|
|
3686
|
+
scan.bound.file,
|
|
3687
|
+
scope.kind === "function" ? scope.node : enclosingFunction(scope.node),
|
|
3688
|
+
name
|
|
3689
|
+
);
|
|
3690
|
+
const constructionKey2 = subjectConstructions(facts, [nameKey2]).get(
|
|
3691
|
+
nameKey2
|
|
3387
3692
|
)?.constructionKey;
|
|
3388
3693
|
return constructionKey2 === void 0 ? null : scan.index.byValueKey.get(constructionKey2) ?? null;
|
|
3389
3694
|
}
|
|
@@ -3474,11 +3779,11 @@ function walkStatements(statements, position, scan, visit) {
|
|
|
3474
3779
|
visit(stmt, position, scan);
|
|
3475
3780
|
}
|
|
3476
3781
|
}
|
|
3477
|
-
function
|
|
3782
|
+
function targetNames2(node) {
|
|
3478
3783
|
if (node.type === "identifier") {
|
|
3479
3784
|
return [node.text];
|
|
3480
3785
|
}
|
|
3481
|
-
return bodyStatements(node).flatMap(
|
|
3786
|
+
return bodyStatements(node).flatMap(targetNames2);
|
|
3482
3787
|
}
|
|
3483
3788
|
function sequenceElementNames(node) {
|
|
3484
3789
|
if (node === null || node.type !== "list" && node.type !== "tuple") {
|
|
@@ -3515,7 +3820,7 @@ function loopBindingsOf(stmt, position, scan) {
|
|
|
3515
3820
|
});
|
|
3516
3821
|
return bindings;
|
|
3517
3822
|
}
|
|
3518
|
-
for (const name of
|
|
3823
|
+
for (const name of targetNames2(left)) {
|
|
3519
3824
|
bindings.set(name, { kind: "unenumerable", location });
|
|
3520
3825
|
}
|
|
3521
3826
|
return bindings;
|
|
@@ -4991,14 +5296,9 @@ function matchedChains(calls, options) {
|
|
|
4991
5296
|
if (chains.length === 0) {
|
|
4992
5297
|
return [];
|
|
4993
5298
|
}
|
|
4994
|
-
const alreadyAsked = new Set(
|
|
4995
|
-
options.facts.facts("wanted").map((row) => String(row[0]))
|
|
4996
|
-
);
|
|
4997
5299
|
resolveCalls(
|
|
4998
5300
|
options.facts,
|
|
4999
|
-
storageCallees(calls, options.filePath, options.couldMatch)
|
|
5000
|
-
(key) => !alreadyAsked.has(key)
|
|
5001
|
-
)
|
|
5301
|
+
storageCallees(calls, options.filePath, options.couldMatch)
|
|
5002
5302
|
);
|
|
5003
5303
|
const matched = [];
|
|
5004
5304
|
for (const chain of chains) {
|
|
@@ -6060,7 +6360,7 @@ function isInjectedParameter(param, injectedCallees, scope, ctx) {
|
|
|
6060
6360
|
import fs4 from "fs";
|
|
6061
6361
|
import path4 from "path";
|
|
6062
6362
|
import { Database as Database3 } from "@suss/datalog";
|
|
6063
|
-
import { explainResolvedKey, RESOLUTION_RULES
|
|
6363
|
+
import { explainResolvedKey, RESOLUTION_RULES } from "@suss/resolution";
|
|
6064
6364
|
|
|
6065
6365
|
// src/facts.ts
|
|
6066
6366
|
function unitKey(filePath, range, name) {
|
|
@@ -6078,7 +6378,7 @@ function emitModuleImportFacts(db, filePath, module, resolverOptions) {
|
|
|
6078
6378
|
if (binding.kind !== "import" && binding.kind !== "importFrom") {
|
|
6079
6379
|
continue;
|
|
6080
6380
|
}
|
|
6081
|
-
const
|
|
6381
|
+
const nameKey2 = `${filePath}#${localName}`;
|
|
6082
6382
|
const moduleText = importedModuleText(
|
|
6083
6383
|
binding.module,
|
|
6084
6384
|
binding.relativeLevel
|
|
@@ -6094,16 +6394,16 @@ function emitModuleImportFacts(db, filePath, module, resolverOptions) {
|
|
|
6094
6394
|
resolution.status === "resolved" ? "resolved" : resolution.reason
|
|
6095
6395
|
]);
|
|
6096
6396
|
const importedName = binding.kind === "import" ? binding.localName : binding.importedName;
|
|
6097
|
-
db.add("pyImportedName", [
|
|
6397
|
+
db.add("pyImportedName", [nameKey2, moduleText, importedName]);
|
|
6098
6398
|
if (scope.kind === "module") {
|
|
6099
|
-
db.add("exportsAs", [filePath, localName,
|
|
6399
|
+
db.add("exportsAs", [filePath, localName, nameKey2]);
|
|
6100
6400
|
}
|
|
6101
6401
|
if (resolution.status === "resolved") {
|
|
6102
6402
|
db.add("pyImportResolved", [filePath, moduleText, resolution.file]);
|
|
6103
|
-
db.add("imports", [
|
|
6403
|
+
db.add("imports", [nameKey2, resolution.file, importedName]);
|
|
6104
6404
|
continue;
|
|
6105
6405
|
}
|
|
6106
|
-
db.add("imports", [
|
|
6406
|
+
db.add("imports", [nameKey2, moduleText, importedName]);
|
|
6107
6407
|
}
|
|
6108
6408
|
}
|
|
6109
6409
|
for (const openModule of module.openImports) {
|
|
@@ -6274,7 +6574,7 @@ import {
|
|
|
6274
6574
|
unfollowedCallGap,
|
|
6275
6575
|
worthRecording
|
|
6276
6576
|
} from "@suss/behavioral-ir";
|
|
6277
|
-
import { Database, evaluate
|
|
6577
|
+
import { Database, evaluate, lit, rule, variable as v } from "@suss/datalog";
|
|
6278
6578
|
import {
|
|
6279
6579
|
assembleSummary,
|
|
6280
6580
|
SKIP_CHILDREN as SKIP_CHILDREN2,
|
|
@@ -6282,251 +6582,227 @@ import {
|
|
|
6282
6582
|
} from "@suss/extractor";
|
|
6283
6583
|
|
|
6284
6584
|
// src/reach/resolveCallee.ts
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6585
|
+
import {
|
|
6586
|
+
calleeOutcomeOf,
|
|
6587
|
+
calleeOutcomes,
|
|
6588
|
+
writtenSourcesOf
|
|
6589
|
+
} from "@suss/resolution";
|
|
6590
|
+
var STOP_FOR = {
|
|
6591
|
+
severalSources: "multipleSources",
|
|
6592
|
+
outsideRun: "outsideRun",
|
|
6593
|
+
unsettled: "unsettledValue",
|
|
6594
|
+
undeclared: "noDeclaration"
|
|
6289
6595
|
};
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6596
|
+
var NO_DECLARATION = {
|
|
6597
|
+
kind: "stopped",
|
|
6598
|
+
reason: "noDeclaration"
|
|
6599
|
+
};
|
|
6600
|
+
function calleeSpellings(calls, ctx) {
|
|
6601
|
+
const spellingOf = /* @__PURE__ */ new Map();
|
|
6602
|
+
const keys = /* @__PURE__ */ new Set();
|
|
6603
|
+
for (const { call, site } of calls) {
|
|
6604
|
+
const spelling = spellingFor(call, site, ctx);
|
|
6605
|
+
spellingOf.set(call.id, spelling);
|
|
6606
|
+
if (spelling.kind === "key") {
|
|
6607
|
+
keys.add(spelling.key);
|
|
6608
|
+
}
|
|
6294
6609
|
}
|
|
6295
|
-
return
|
|
6610
|
+
return { spellingOf, outcomes: calleeOutcomes(ctx.facts, [...keys]) };
|
|
6296
6611
|
}
|
|
6297
|
-
function
|
|
6298
|
-
|
|
6299
|
-
|
|
6612
|
+
function resolveCallee2(call, site, ctx, read) {
|
|
6613
|
+
const spelling = read?.spellingOf.get(call.id) ?? spellingFor(call, site, ctx);
|
|
6614
|
+
if (spelling.kind === "stopped") {
|
|
6615
|
+
return spelling;
|
|
6300
6616
|
}
|
|
6301
|
-
const
|
|
6302
|
-
|
|
6617
|
+
const outcome = read?.outcomes.get(spelling.key) ?? calleeOutcomeOf(ctx.facts, spelling.key);
|
|
6618
|
+
return asCallee(outcome, site.owner, ctx);
|
|
6619
|
+
}
|
|
6620
|
+
function functionNamed(nameKey2, ctx) {
|
|
6621
|
+
if (assignedElsewhere(ctx.facts, nameKey2)) {
|
|
6303
6622
|
return null;
|
|
6304
6623
|
}
|
|
6305
|
-
const
|
|
6306
|
-
return
|
|
6624
|
+
const outcome = calleeOutcomeOf(ctx.facts, nameKey2);
|
|
6625
|
+
return outcome.kind === "function" ? functionAt(outcome.key, ctx) : null;
|
|
6307
6626
|
}
|
|
6308
|
-
function
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
if (resolved.kind === "class") {
|
|
6313
|
-
return asCallee(
|
|
6314
|
-
memberOfClass(resolved.file, resolved.node, "__init__", ctx),
|
|
6315
|
-
ctx
|
|
6316
|
-
);
|
|
6317
|
-
}
|
|
6318
|
-
if (resolved.kind === "stop") {
|
|
6319
|
-
return { kind: "stopped", reason: resolved.reason };
|
|
6320
|
-
}
|
|
6321
|
-
if (resolved.kind === "package") {
|
|
6322
|
-
return { kind: "stopped", reason: "outsideRun" };
|
|
6323
|
-
}
|
|
6324
|
-
return { kind: "stopped", reason: "noDeclaration" };
|
|
6627
|
+
function assignedElsewhere(facts, nameKey2) {
|
|
6628
|
+
return writtenSourcesOf(facts, nameKey2).some(
|
|
6629
|
+
(source) => !facts.has("func", [source])
|
|
6630
|
+
);
|
|
6325
6631
|
}
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
const object = field(node, "object");
|
|
6330
|
-
const attribute = field(node, "attribute");
|
|
6331
|
-
if (object === null || attribute === null) {
|
|
6332
|
-
return stop("noDeclaration");
|
|
6333
|
-
}
|
|
6334
|
-
return memberOf(resolveExpression(object, site, ctx), attribute.text, ctx);
|
|
6335
|
-
},
|
|
6336
|
-
call: (node, site, ctx) => {
|
|
6337
|
-
const callee = field(node, "function");
|
|
6338
|
-
return callee === null ? stop("noDeclaration") : instanceBuiltBy(resolveExpression(callee, site, ctx), "noDeclaration");
|
|
6339
|
-
},
|
|
6340
|
-
parenthesized_expression: (node, site, ctx) => {
|
|
6341
|
-
const inner = node.namedChildren[0];
|
|
6342
|
-
return inner === null || inner === void 0 ? stop("noDeclaration") : resolveExpression(inner, site, ctx);
|
|
6632
|
+
function readThrough(node) {
|
|
6633
|
+
if (node?.type !== "parenthesized_expression") {
|
|
6634
|
+
return node;
|
|
6343
6635
|
}
|
|
6344
|
-
|
|
6345
|
-
function resolveExpression(node, site, ctx) {
|
|
6346
|
-
const resolver = EXPRESSION_RESOLVERS[node.type];
|
|
6347
|
-
return resolver === void 0 ? stop("noDeclaration") : resolver(node, site, ctx);
|
|
6636
|
+
return readThrough(children(node)[0] ?? null);
|
|
6348
6637
|
}
|
|
6349
|
-
function
|
|
6350
|
-
|
|
6351
|
-
|
|
6638
|
+
function spellingFor(call, site, ctx) {
|
|
6639
|
+
const callee = readThrough(field(call, "function"));
|
|
6640
|
+
if (callee === null) {
|
|
6641
|
+
return { kind: "stopped", reason: "noDeclaration" };
|
|
6352
6642
|
}
|
|
6353
|
-
return
|
|
6643
|
+
return throughModules(callee, site, ctx) ?? {
|
|
6644
|
+
kind: "key",
|
|
6645
|
+
key: readKey(site.file.file, callee, enclosingFunction(callee))
|
|
6646
|
+
};
|
|
6354
6647
|
}
|
|
6355
|
-
function
|
|
6356
|
-
if (
|
|
6357
|
-
return
|
|
6648
|
+
function asCallee(outcome, owner, ctx) {
|
|
6649
|
+
if (outcome.kind === "function") {
|
|
6650
|
+
return functionCallee(outcome.key, ctx);
|
|
6358
6651
|
}
|
|
6359
|
-
if (
|
|
6360
|
-
return
|
|
6652
|
+
if (outcome.kind === "object") {
|
|
6653
|
+
return constructorOf(outcome.key, ctx);
|
|
6361
6654
|
}
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
return throughOpenImports(site.file, name, ctx, /* @__PURE__ */ new Set());
|
|
6655
|
+
if (outcome.kind === "callerSupplied") {
|
|
6656
|
+
return outcome.key.startsWith(`${owner}#`) ? { kind: "stopped", reason: "callerSupplied" } : { kind: "stopped", reason: "unsettledValue" };
|
|
6365
6657
|
}
|
|
6366
|
-
return
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6658
|
+
return {
|
|
6659
|
+
kind: "stopped",
|
|
6660
|
+
reason: STOP_FOR[outcome.kind] ?? "noDeclaration"
|
|
6661
|
+
};
|
|
6370
6662
|
}
|
|
6371
|
-
function
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
return stop("noDeclaration");
|
|
6663
|
+
function functionCallee(key, ctx) {
|
|
6664
|
+
if (ctx.definitions.get(key)?.type === "lambda") {
|
|
6665
|
+
return { kind: "stopped", reason: "unsettledValue" };
|
|
6375
6666
|
}
|
|
6376
|
-
|
|
6667
|
+
const target = functionAt(key, ctx);
|
|
6668
|
+
return target === null ? NO_DECLARATION : { kind: "followed", target };
|
|
6377
6669
|
}
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
}),
|
|
6383
|
-
classDef: (binding, file) => ({ kind: "class", file, node: binding.node }),
|
|
6384
|
-
parameter: () => stop("callerSupplied"),
|
|
6385
|
-
// `import a.b.c` binds `a`, and `import a.b.c as m` binds `m` to `a.b.c`.
|
|
6386
|
-
import: (binding, file, _scope, ctx) => moduleNamed(
|
|
6387
|
-
file,
|
|
6388
|
-
binding.localName === binding.module.split(".")[0] ? binding.localName : binding.module,
|
|
6389
|
-
0,
|
|
6390
|
-
ctx
|
|
6391
|
-
),
|
|
6392
|
-
importFrom: (binding, file, _scope, ctx, visited) => memberOf(
|
|
6393
|
-
moduleNamed(file, binding.module, binding.relativeLevel, ctx),
|
|
6394
|
-
binding.importedName,
|
|
6395
|
-
ctx,
|
|
6396
|
-
visited
|
|
6397
|
-
),
|
|
6398
|
-
// `run = load` is an alias worth one hop; anything else is a value.
|
|
6399
|
-
assignment: (binding, file, scope, ctx, visited) => aliasedValue(binding.value, file, scope, ctx, visited),
|
|
6400
|
-
global: () => stop("unsettledValue"),
|
|
6401
|
-
nonlocal: () => stop("unsettledValue")
|
|
6402
|
-
};
|
|
6403
|
-
function resolveBinding(binding, file, scope, ctx, visited) {
|
|
6404
|
-
const resolver = BINDING_RESOLVERS[binding.kind];
|
|
6405
|
-
return resolver(binding, file, scope, ctx, visited);
|
|
6406
|
-
}
|
|
6407
|
-
function aliasedValue(value, file, scope, ctx, visited) {
|
|
6408
|
-
if (value === null) {
|
|
6409
|
-
return stop("unsettledValue");
|
|
6410
|
-
}
|
|
6411
|
-
if (value.type === "identifier") {
|
|
6412
|
-
const binding = resolveName(scope, value.text);
|
|
6413
|
-
if (binding === null || binding.kind === "assignment") {
|
|
6414
|
-
return stop("unsettledValue");
|
|
6415
|
-
}
|
|
6416
|
-
return resolveBinding(binding, file, scope, ctx, visited);
|
|
6417
|
-
}
|
|
6418
|
-
if (value.type === "call") {
|
|
6419
|
-
const callee = field(value, "function");
|
|
6420
|
-
return callee === null ? stop("unsettledValue") : instanceBuiltBy(
|
|
6421
|
-
aliasedValue(callee, file, scope, ctx, visited),
|
|
6422
|
-
"unsettledValue"
|
|
6423
|
-
);
|
|
6670
|
+
function constructorOf(classKey, ctx) {
|
|
6671
|
+
const declared = ctx.facts.lookup("holdsProperty", 0, classKey).find((row) => String(row[1]) === "__init__");
|
|
6672
|
+
if (declared === void 0) {
|
|
6673
|
+
return NO_DECLARATION;
|
|
6424
6674
|
}
|
|
6425
|
-
|
|
6426
|
-
const object = field(value, "object");
|
|
6427
|
-
const attribute = field(value, "attribute");
|
|
6428
|
-
if (object === null || attribute === null) {
|
|
6429
|
-
return stop("unsettledValue");
|
|
6430
|
-
}
|
|
6431
|
-
return memberOf(
|
|
6432
|
-
aliasedValue(object, file, scope, ctx, visited),
|
|
6433
|
-
attribute.text,
|
|
6434
|
-
ctx
|
|
6435
|
-
);
|
|
6436
|
-
}
|
|
6437
|
-
return stop("unsettledValue");
|
|
6675
|
+
return functionCallee(String(declared[2]), ctx);
|
|
6438
6676
|
}
|
|
6439
|
-
function
|
|
6677
|
+
function functionAt(key, ctx) {
|
|
6678
|
+
const node = ctx.definitions.get(key);
|
|
6679
|
+
const file = ctx.filesByPath.get(key.slice(0, key.lastIndexOf(":")));
|
|
6680
|
+
if (node === void 0 || file === void 0) {
|
|
6681
|
+
return null;
|
|
6682
|
+
}
|
|
6440
6683
|
const name = field(node, "name")?.text ?? "<anon>";
|
|
6441
|
-
const
|
|
6684
|
+
const owner = ownerClassOf(node);
|
|
6685
|
+
const ownerName = owner === null ? void 0 : field(owner, "name")?.text;
|
|
6442
6686
|
return {
|
|
6443
6687
|
file,
|
|
6444
6688
|
node,
|
|
6445
6689
|
name,
|
|
6446
|
-
exportPath: ownerName ===
|
|
6690
|
+
exportPath: ownerName === void 0 ? [name] : [ownerName, name]
|
|
6447
6691
|
};
|
|
6448
6692
|
}
|
|
6449
|
-
function
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6693
|
+
function ownerClassOf(node) {
|
|
6694
|
+
for (let up = node.parent; up !== null; up = up.parent) {
|
|
6695
|
+
if (isFunction(up)) {
|
|
6696
|
+
return null;
|
|
6697
|
+
}
|
|
6698
|
+
if (up.type === "class_definition") {
|
|
6699
|
+
return up;
|
|
6700
|
+
}
|
|
6457
6701
|
}
|
|
6458
|
-
|
|
6459
|
-
return file === void 0 ? stop("outsideRun") : { kind: "module", file };
|
|
6702
|
+
return null;
|
|
6460
6703
|
}
|
|
6461
|
-
function
|
|
6462
|
-
if (
|
|
6463
|
-
return
|
|
6704
|
+
function throughModules(callee, site, ctx) {
|
|
6705
|
+
if (callee.type === "identifier") {
|
|
6706
|
+
return resolveName(site.scope, callee.text) === null ? openImportMember(site.file, callee.text, ctx, /* @__PURE__ */ new Set()) : null;
|
|
6464
6707
|
}
|
|
6465
|
-
if (
|
|
6466
|
-
return
|
|
6467
|
-
base.from,
|
|
6468
|
-
base.dotted === "" ? name : `${base.dotted}.${name}`,
|
|
6469
|
-
base.relativeLevel,
|
|
6470
|
-
ctx
|
|
6471
|
-
);
|
|
6708
|
+
if (callee.type !== "attribute") {
|
|
6709
|
+
return null;
|
|
6472
6710
|
}
|
|
6473
|
-
|
|
6474
|
-
|
|
6711
|
+
const object = field(callee, "object");
|
|
6712
|
+
const attribute = field(callee, "attribute");
|
|
6713
|
+
if (object === null || attribute === null) {
|
|
6714
|
+
return null;
|
|
6475
6715
|
}
|
|
6476
|
-
|
|
6477
|
-
|
|
6716
|
+
const base = moduleAt(object, site, ctx);
|
|
6717
|
+
return base === null ? null : memberKey(base, attribute.text, ctx);
|
|
6718
|
+
}
|
|
6719
|
+
function openImportMember(file, name, ctx, visited) {
|
|
6720
|
+
if (visited.has(file.file)) {
|
|
6721
|
+
return null;
|
|
6478
6722
|
}
|
|
6479
|
-
|
|
6723
|
+
visited.add(file.file);
|
|
6724
|
+
const found = /* @__PURE__ */ new Set();
|
|
6725
|
+
for (const spec of file.module.openImports) {
|
|
6726
|
+
const dots = spec.length - spec.replace(/^\.+/, "").length;
|
|
6727
|
+
const opened = moduleNamed(file, spec.slice(dots), dots, ctx);
|
|
6728
|
+
if (opened === null || opened.kind !== "module") {
|
|
6729
|
+
continue;
|
|
6730
|
+
}
|
|
6731
|
+
const member = opened.file.module.moduleScope.bindings.has(name) ? { kind: "key", key: `${opened.file.file}#${name}` } : openImportMember(opened.file, name, ctx, visited);
|
|
6732
|
+
if (member?.kind === "key") {
|
|
6733
|
+
found.add(member.key);
|
|
6734
|
+
}
|
|
6735
|
+
}
|
|
6736
|
+
if (found.size > 1) {
|
|
6737
|
+
return { kind: "stopped", reason: "multipleSources" };
|
|
6738
|
+
}
|
|
6739
|
+
const only = [...found][0];
|
|
6740
|
+
return only === void 0 ? null : { kind: "key", key: only };
|
|
6480
6741
|
}
|
|
6481
|
-
function
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
if (binding === void 0) {
|
|
6485
|
-
return stop("noDeclaration");
|
|
6742
|
+
function moduleAt(node, site, ctx) {
|
|
6743
|
+
if (node.type === "identifier") {
|
|
6744
|
+
return importedModule(node.text, site, ctx);
|
|
6486
6745
|
}
|
|
6487
|
-
if (
|
|
6488
|
-
return
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6746
|
+
if (node.type !== "attribute") {
|
|
6747
|
+
return null;
|
|
6748
|
+
}
|
|
6749
|
+
const object = field(node, "object");
|
|
6750
|
+
const attribute = field(node, "attribute");
|
|
6751
|
+
if (object === null || attribute === null) {
|
|
6752
|
+
return null;
|
|
6492
6753
|
}
|
|
6493
|
-
|
|
6754
|
+
const base = moduleAt(object, site, ctx);
|
|
6755
|
+
return base === null ? null : submoduleOf(base, attribute.text, ctx);
|
|
6494
6756
|
}
|
|
6495
|
-
function
|
|
6496
|
-
const
|
|
6497
|
-
if (
|
|
6498
|
-
|
|
6757
|
+
function importedModule(name, site, ctx) {
|
|
6758
|
+
const binding = resolveName(site.scope, name);
|
|
6759
|
+
if (binding?.kind === "import") {
|
|
6760
|
+
const head = binding.module.split(".")[0];
|
|
6761
|
+
const dotted = binding.localName === head ? binding.localName : binding.module;
|
|
6762
|
+
return moduleNamed(site.file, dotted, 0, ctx);
|
|
6499
6763
|
}
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
if (binding !== void 0) {
|
|
6503
|
-
return resolveBinding(binding, file, file.module.moduleScope, ctx, visited);
|
|
6764
|
+
if (binding?.kind !== "importFrom") {
|
|
6765
|
+
return null;
|
|
6504
6766
|
}
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6767
|
+
const from = moduleNamed(
|
|
6768
|
+
site.file,
|
|
6769
|
+
binding.module,
|
|
6770
|
+
binding.relativeLevel,
|
|
6771
|
+
ctx
|
|
6772
|
+
);
|
|
6773
|
+
return from === null ? null : submoduleOf(from, binding.importedName, ctx);
|
|
6774
|
+
}
|
|
6775
|
+
function submoduleOf(base, name, ctx) {
|
|
6776
|
+
if (base.kind === "package") {
|
|
6777
|
+
return moduleNamed(
|
|
6778
|
+
base.from,
|
|
6779
|
+
base.dotted === "" ? name : `${base.dotted}.${name}`,
|
|
6780
|
+
base.relativeLevel,
|
|
6781
|
+
ctx
|
|
6782
|
+
);
|
|
6510
6783
|
}
|
|
6511
|
-
return
|
|
6784
|
+
return base.file.file.endsWith("__init__.py") ? moduleNamed(base.file, name, 1, ctx) : null;
|
|
6512
6785
|
}
|
|
6513
|
-
function
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
const dots = spec.length - spec.replace(/^\.+/, "").length;
|
|
6517
|
-
const opened = moduleNamed(file, spec.slice(dots), dots, ctx);
|
|
6518
|
-
if (opened.kind !== "module") {
|
|
6519
|
-
continue;
|
|
6520
|
-
}
|
|
6521
|
-
const member = memberOfModule(opened.file, name, ctx, visited);
|
|
6522
|
-
if (member.kind !== "stop") {
|
|
6523
|
-
found.push(member);
|
|
6524
|
-
}
|
|
6786
|
+
function memberKey(base, name, ctx) {
|
|
6787
|
+
if (base.kind === "package") {
|
|
6788
|
+
return null;
|
|
6525
6789
|
}
|
|
6526
|
-
if (
|
|
6527
|
-
return
|
|
6790
|
+
if (base.file.module.moduleScope.bindings.has(name)) {
|
|
6791
|
+
return { kind: "key", key: `${base.file.file}#${name}` };
|
|
6792
|
+
}
|
|
6793
|
+
return openImportMember(base.file, name, ctx, /* @__PURE__ */ new Set());
|
|
6794
|
+
}
|
|
6795
|
+
function moduleNamed(from, module, relativeLevel, ctx) {
|
|
6796
|
+
const resolution = resolveModule(
|
|
6797
|
+
from.file,
|
|
6798
|
+
{ module, relativeLevel },
|
|
6799
|
+
{ roots: ctx.roots }
|
|
6800
|
+
);
|
|
6801
|
+
if (resolution.status !== "resolved") {
|
|
6802
|
+
return resolution.reason === "external" ? { kind: "package", dotted: module, relativeLevel, from } : null;
|
|
6528
6803
|
}
|
|
6529
|
-
|
|
6804
|
+
const file = ctx.filesByPath.get(resolution.file);
|
|
6805
|
+
return file === void 0 ? null : { kind: "module", file };
|
|
6530
6806
|
}
|
|
6531
6807
|
|
|
6532
6808
|
// src/reach/closure.ts
|
|
@@ -6541,7 +6817,9 @@ var REACHABLE_RULES = [
|
|
|
6541
6817
|
function reachedFunctions(seeds, options) {
|
|
6542
6818
|
const ctx = {
|
|
6543
6819
|
filesByPath: new Map(options.files.map((file) => [file.file, file])),
|
|
6544
|
-
roots: options.roots
|
|
6820
|
+
roots: options.roots,
|
|
6821
|
+
facts: options.facts,
|
|
6822
|
+
definitions: options.definitions
|
|
6545
6823
|
};
|
|
6546
6824
|
const db = new Database();
|
|
6547
6825
|
const functionByKey = /* @__PURE__ */ new Map();
|
|
@@ -6563,21 +6841,26 @@ function reachedFunctions(seeds, options) {
|
|
|
6563
6841
|
db.add("entry", [seed.key]);
|
|
6564
6842
|
}
|
|
6565
6843
|
for (; ; ) {
|
|
6566
|
-
|
|
6844
|
+
evaluate(db, REACHABLE_RULES);
|
|
6567
6845
|
const frontier = db.facts("reachable").map(([key]) => String(key)).filter((key) => !scanned.has(key));
|
|
6568
6846
|
if (frontier.length === 0) {
|
|
6569
6847
|
break;
|
|
6570
6848
|
}
|
|
6571
|
-
|
|
6849
|
+
const bodies = frontier.flatMap((key) => {
|
|
6572
6850
|
scanned.add(key);
|
|
6573
6851
|
const source = functionByKey.get(key);
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6852
|
+
return source === void 0 ? [] : [{ key, source, ...bodyOf(source) }];
|
|
6853
|
+
});
|
|
6854
|
+
const spellings = calleeSpellings(
|
|
6855
|
+
bodies.flatMap((body) => body.written),
|
|
6856
|
+
ctx
|
|
6857
|
+
);
|
|
6858
|
+
for (const { key, source, body, written } of bodies) {
|
|
6577
6859
|
const scan = scanBody(
|
|
6578
6860
|
source,
|
|
6579
6861
|
ctx,
|
|
6580
|
-
recognizedCallIds(source.node, options.storageFor(source.file))
|
|
6862
|
+
recognizedCallIds(source.node, options.storageFor(source.file)),
|
|
6863
|
+
{ body, written, spellings }
|
|
6581
6864
|
);
|
|
6582
6865
|
if (scan.stops.length > 0) {
|
|
6583
6866
|
stopsByKey.set(key, scan.stops);
|
|
@@ -6643,7 +6926,18 @@ var EMPTY_SCAN = {
|
|
|
6643
6926
|
parameterCalls: [],
|
|
6644
6927
|
passedPositions: /* @__PURE__ */ new Set()
|
|
6645
6928
|
};
|
|
6646
|
-
function
|
|
6929
|
+
function bodyOf(source) {
|
|
6930
|
+
const { file, node } = source;
|
|
6931
|
+
const body = field(node, "body");
|
|
6932
|
+
if (body === null) {
|
|
6933
|
+
return { body, written: [] };
|
|
6934
|
+
}
|
|
6935
|
+
return {
|
|
6936
|
+
body,
|
|
6937
|
+
written: callsWritten(file, body, scopeAt2(file, node), keyOf(source))
|
|
6938
|
+
};
|
|
6939
|
+
}
|
|
6940
|
+
function scanBody(source, ctx, recognized, read) {
|
|
6647
6941
|
const followed = [];
|
|
6648
6942
|
const stops = [];
|
|
6649
6943
|
const placements = new TargetPlacements();
|
|
@@ -6652,12 +6946,12 @@ function scanBody(source, ctx, recognized) {
|
|
|
6652
6946
|
const seen = /* @__PURE__ */ new Set();
|
|
6653
6947
|
const parameterCallsSeen = /* @__PURE__ */ new Set();
|
|
6654
6948
|
const { file, node } = source;
|
|
6655
|
-
const
|
|
6656
|
-
if (body === null) {
|
|
6949
|
+
const { written, spellings } = read;
|
|
6950
|
+
if (read.body === null) {
|
|
6657
6951
|
return EMPTY_SCAN;
|
|
6658
6952
|
}
|
|
6659
6953
|
const ownParameters = callParameterNames(node, source.exportPath.length > 1);
|
|
6660
|
-
const recordPassedArgs = (call, callee, calleeKey
|
|
6954
|
+
const recordPassedArgs = (call, callee, calleeKey) => {
|
|
6661
6955
|
const args = field(call, "arguments");
|
|
6662
6956
|
if (args === null) {
|
|
6663
6957
|
return;
|
|
@@ -6666,9 +6960,8 @@ function scanBody(source, ctx, recognized) {
|
|
|
6666
6960
|
if (arg === null || arg.type !== "identifier") {
|
|
6667
6961
|
return;
|
|
6668
6962
|
}
|
|
6669
|
-
const resolved =
|
|
6670
|
-
|
|
6671
|
-
{ file, scope: where.scope, rebound: where.rebound },
|
|
6963
|
+
const resolved = functionNamed(
|
|
6964
|
+
readKey(file.file, arg, enclosingFunction(arg)),
|
|
6672
6965
|
ctx
|
|
6673
6966
|
);
|
|
6674
6967
|
if (resolved === null) {
|
|
@@ -6688,13 +6981,9 @@ function scanBody(source, ctx, recognized) {
|
|
|
6688
6981
|
}
|
|
6689
6982
|
});
|
|
6690
6983
|
};
|
|
6691
|
-
const record = (call,
|
|
6984
|
+
const record = (call, site) => {
|
|
6692
6985
|
const callee = calleeText(call);
|
|
6693
|
-
const outcome = resolveCallee2(
|
|
6694
|
-
call,
|
|
6695
|
-
{ file, scope: where.scope, rebound: where.rebound },
|
|
6696
|
-
ctx
|
|
6697
|
-
);
|
|
6986
|
+
const outcome = resolveCallee2(call, site, ctx, spellings);
|
|
6698
6987
|
const placed = outcome.kind === "followed" ? {
|
|
6699
6988
|
file: outcome.target.file.displayPath,
|
|
6700
6989
|
span: spanOf(outcome.target.node)
|
|
@@ -6703,8 +6992,7 @@ function scanBody(source, ctx, recognized) {
|
|
|
6703
6992
|
recordPassedArgs(
|
|
6704
6993
|
call,
|
|
6705
6994
|
callee,
|
|
6706
|
-
outcome.kind === "followed" ? keyOf(outcome.target) : null
|
|
6707
|
-
where
|
|
6995
|
+
outcome.kind === "followed" ? keyOf(outcome.target) : null
|
|
6708
6996
|
);
|
|
6709
6997
|
if (outcome.kind === "stopped") {
|
|
6710
6998
|
const stopKey = `${outcome.reason}:${callee}`;
|
|
@@ -6727,32 +7015,9 @@ function scanBody(source, ctx, recognized) {
|
|
|
6727
7015
|
followed.push(outcome.target);
|
|
6728
7016
|
}
|
|
6729
7017
|
};
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
{
|
|
6734
|
-
at: (child, where) => {
|
|
6735
|
-
if (child.type === "call") {
|
|
6736
|
-
record(child, where);
|
|
6737
|
-
}
|
|
6738
|
-
},
|
|
6739
|
-
into: (child, where) => {
|
|
6740
|
-
if (child.type === "function_definition") {
|
|
6741
|
-
return SKIP_CHILDREN2;
|
|
6742
|
-
}
|
|
6743
|
-
if (child.type === "lambda") {
|
|
6744
|
-
return {
|
|
6745
|
-
scope: where.scope,
|
|
6746
|
-
rebound: /* @__PURE__ */ new Set([...where.rebound, ...lambdaParameters(child)])
|
|
6747
|
-
};
|
|
6748
|
-
}
|
|
6749
|
-
return {
|
|
6750
|
-
scope: file.module.scopeFor.get(child.id) ?? where.scope,
|
|
6751
|
-
rebound: where.rebound
|
|
6752
|
-
};
|
|
6753
|
-
}
|
|
6754
|
-
}
|
|
6755
|
-
);
|
|
7018
|
+
for (const { call, site } of written) {
|
|
7019
|
+
record(call, site);
|
|
7020
|
+
}
|
|
6756
7021
|
return {
|
|
6757
7022
|
followed,
|
|
6758
7023
|
stops,
|
|
@@ -6762,6 +7027,18 @@ function scanBody(source, ctx, recognized) {
|
|
|
6762
7027
|
passedPositions
|
|
6763
7028
|
};
|
|
6764
7029
|
}
|
|
7030
|
+
function callsWritten(file, body, outer, owner) {
|
|
7031
|
+
const found = [];
|
|
7032
|
+
walkDescendants3(body, outer, {
|
|
7033
|
+
at: (child, scope) => {
|
|
7034
|
+
if (child.type === "call") {
|
|
7035
|
+
found.push({ call: child, site: { file, scope, owner } });
|
|
7036
|
+
}
|
|
7037
|
+
},
|
|
7038
|
+
into: (child, scope) => child.type === "function_definition" ? SKIP_CHILDREN2 : file.module.scopeFor.get(child.id) ?? scope
|
|
7039
|
+
});
|
|
7040
|
+
return found;
|
|
7041
|
+
}
|
|
6765
7042
|
function scopeAt2(file, node) {
|
|
6766
7043
|
let current = node;
|
|
6767
7044
|
while (current !== null) {
|
|
@@ -6773,40 +7050,6 @@ function scopeAt2(file, node) {
|
|
|
6773
7050
|
}
|
|
6774
7051
|
return file.module.moduleScope;
|
|
6775
7052
|
}
|
|
6776
|
-
var REBINDING_FIELDS = {
|
|
6777
|
-
assignment: "left",
|
|
6778
|
-
augmented_assignment: "left",
|
|
6779
|
-
named_expression: "name",
|
|
6780
|
-
for_statement: "left",
|
|
6781
|
-
for_in_clause: "left",
|
|
6782
|
-
as_pattern: "alias"
|
|
6783
|
-
};
|
|
6784
|
-
function reboundNames(body) {
|
|
6785
|
-
const names = /* @__PURE__ */ new Set();
|
|
6786
|
-
walkDescendants3(body, null, {
|
|
6787
|
-
at: (node) => {
|
|
6788
|
-
const target = REBINDING_FIELDS[node.type];
|
|
6789
|
-
if (target === void 0 || boundByBinder(node, body)) {
|
|
6790
|
-
return;
|
|
6791
|
-
}
|
|
6792
|
-
const written = field(node, target);
|
|
6793
|
-
if (written !== null) {
|
|
6794
|
-
for (const name of identifiersUnder(written)) {
|
|
6795
|
-
names.add(name);
|
|
6796
|
-
}
|
|
6797
|
-
}
|
|
6798
|
-
},
|
|
6799
|
-
into: (node) => node.type === "function_definition" ? SKIP_CHILDREN2 : null
|
|
6800
|
-
});
|
|
6801
|
-
return names;
|
|
6802
|
-
}
|
|
6803
|
-
function boundByBinder(node, body) {
|
|
6804
|
-
if (node.type !== "assignment") {
|
|
6805
|
-
return false;
|
|
6806
|
-
}
|
|
6807
|
-
const statement = node.parent;
|
|
6808
|
-
return field(node, "left")?.type === "identifier" && statement?.type === "expression_statement" && statement.parent?.id === body.id;
|
|
6809
|
-
}
|
|
6810
7053
|
function identifiersUnder(node, found = []) {
|
|
6811
7054
|
if (node.type === "identifier") {
|
|
6812
7055
|
found.push(node.text);
|
|
@@ -6819,10 +7062,6 @@ function identifiersUnder(node, found = []) {
|
|
|
6819
7062
|
}
|
|
6820
7063
|
return found;
|
|
6821
7064
|
}
|
|
6822
|
-
function lambdaParameters(lambda) {
|
|
6823
|
-
const parameters = field(lambda, "parameters");
|
|
6824
|
-
return parameters === null ? [] : identifiersUnder(parameters);
|
|
6825
|
-
}
|
|
6826
7065
|
function libraryUnit(target, options) {
|
|
6827
7066
|
const { file, node, name, exportPath } = target;
|
|
6828
7067
|
const body = field(node, "body");
|
|
@@ -6973,6 +7212,18 @@ var PythonWrapperIndex = class {
|
|
|
6973
7212
|
ownRoutes = /* @__PURE__ */ new Map();
|
|
6974
7213
|
unitsByKey = /* @__PURE__ */ new Map();
|
|
6975
7214
|
unitsByFile = /* @__PURE__ */ new Map();
|
|
7215
|
+
/** The project function a module-level name in this file refers to, or null for anything else. */
|
|
7216
|
+
functionCalled(file, name) {
|
|
7217
|
+
if (this.options.facts === void 0) {
|
|
7218
|
+
return null;
|
|
7219
|
+
}
|
|
7220
|
+
return functionNamed(nameKeyIn(file, null, name), {
|
|
7221
|
+
filesByPath: this.filesByPath,
|
|
7222
|
+
roots: this.options.roots,
|
|
7223
|
+
facts: this.options.facts,
|
|
7224
|
+
definitions: this.options.definitions
|
|
7225
|
+
});
|
|
7226
|
+
}
|
|
6976
7227
|
register(covers, target, declared) {
|
|
6977
7228
|
const registered = this.registered(target, declared);
|
|
6978
7229
|
const table = covers.kind === "everyRoute" ? this.everyRoute : this.ownRoutes;
|
|
@@ -7019,20 +7270,12 @@ var PythonWrapperIndex = class {
|
|
|
7019
7270
|
if (declared.form.type !== "dependency") {
|
|
7020
7271
|
continue;
|
|
7021
7272
|
}
|
|
7022
|
-
const site = {
|
|
7023
|
-
file,
|
|
7024
|
-
scope: query.module.moduleScope,
|
|
7025
|
-
rebound: /* @__PURE__ */ new Set()
|
|
7026
|
-
};
|
|
7027
7273
|
const targets = [
|
|
7028
7274
|
...decoratorDependencies(query.classification, declared.form),
|
|
7029
7275
|
...parameterDependencies(query.definitionNode, declared.form)
|
|
7030
7276
|
];
|
|
7031
7277
|
for (const name of targets) {
|
|
7032
|
-
const target =
|
|
7033
|
-
filesByPath: this.filesByPath,
|
|
7034
|
-
roots: this.options.roots
|
|
7035
|
-
});
|
|
7278
|
+
const target = this.functionCalled(file.file, name);
|
|
7036
7279
|
if (target !== null) {
|
|
7037
7280
|
found.push(this.registered(target, declared));
|
|
7038
7281
|
}
|
|
@@ -7174,12 +7417,8 @@ function registerConstructorDependencies(file, declared, form, index) {
|
|
|
7174
7417
|
if (listed === void 0) {
|
|
7175
7418
|
continue;
|
|
7176
7419
|
}
|
|
7177
|
-
const site = { file, scope, rebound: /* @__PURE__ */ new Set() };
|
|
7178
7420
|
for (const name of dependencyNamesIn(listed.node, form)) {
|
|
7179
|
-
const target =
|
|
7180
|
-
filesByPath: index.filesByPath,
|
|
7181
|
-
roots: index.options.roots
|
|
7182
|
-
});
|
|
7421
|
+
const target = index.functionCalled(file.file, name);
|
|
7183
7422
|
if (target !== null) {
|
|
7184
7423
|
index.register(
|
|
7185
7424
|
coverageOf(match, file, declared.pack),
|
|
@@ -7507,6 +7746,7 @@ async function extractPythonProject(options) {
|
|
|
7507
7746
|
packs: options.packs,
|
|
7508
7747
|
roots: options.roots,
|
|
7509
7748
|
facts: needsValues ? db : void 0,
|
|
7749
|
+
definitions,
|
|
7510
7750
|
storageFor
|
|
7511
7751
|
})
|
|
7512
7752
|
);
|
|
@@ -7590,7 +7830,9 @@ async function extractPythonProject(options) {
|
|
|
7590
7830
|
files: bound,
|
|
7591
7831
|
roots: options.roots,
|
|
7592
7832
|
gapHandling,
|
|
7593
|
-
storageFor
|
|
7833
|
+
storageFor,
|
|
7834
|
+
facts: db,
|
|
7835
|
+
definitions
|
|
7594
7836
|
})
|
|
7595
7837
|
);
|
|
7596
7838
|
for (const [key, owners] of summariesBySeed) {
|
|
@@ -7852,7 +8094,7 @@ var PythonWhySession = class {
|
|
|
7852
8094
|
explain(value, options = {}) {
|
|
7853
8095
|
return explainResolvedKey({
|
|
7854
8096
|
db: this.db,
|
|
7855
|
-
rules:
|
|
8097
|
+
rules: RESOLUTION_RULES,
|
|
7856
8098
|
key: readKey(value.file, value.node, enclosingFunction(value.node)),
|
|
7857
8099
|
locate: (key) => this.locate(key),
|
|
7858
8100
|
displayPath: (key) => this.displayPath(key),
|
|
@@ -7982,6 +8224,7 @@ export {
|
|
|
7982
8224
|
emitValueFacts,
|
|
7983
8225
|
extractPythonProject,
|
|
7984
8226
|
findPythonFiles,
|
|
8227
|
+
nameKeyIn,
|
|
7985
8228
|
nodeId,
|
|
7986
8229
|
objectReturnedBy,
|
|
7987
8230
|
parsePython,
|