@eagleoutice/flowr 2.8.0 → 2.8.1
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/dataflow/environments/default-builtin-config.d.ts +1 -0
- package/dataflow/environments/default-builtin-config.js +1 -1
- package/dataflow/graph/call-graph.js +16 -13
- package/dataflow/internal/linker.js +8 -20
- package/package.json +1 -1
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.js +28 -3
- package/util/version.js +1 -1
|
@@ -247,7 +247,7 @@ exports.DefaultBuiltinConfig = [
|
|
|
247
247
|
{ type: 'function', names: ['library', 'require'], processor: 'builtin:library', config: {}, assumePrimitive: false },
|
|
248
248
|
{ type: 'function', names: ['<-', '='], processor: 'builtin:assignment', config: { canBeReplacement: true }, assumePrimitive: true },
|
|
249
249
|
{ type: 'function', names: [':='], processor: 'builtin:assignment', config: {}, assumePrimitive: true },
|
|
250
|
-
{ type: 'function', names: ['assign', 'setGeneric', 'setValidity'], processor: 'builtin:assignment', config: { targetVariable: true }, assumePrimitive: true },
|
|
250
|
+
{ type: 'function', names: ['assign', 'setGeneric', 'setValidity'], processor: 'builtin:assignment', config: { targetVariable: true, mayHaveMoreArgs: true }, assumePrimitive: true },
|
|
251
251
|
{ type: 'function', names: ['setMethod'], processor: 'builtin:assignment-like', config: { targetVariable: true, canBeReplacement: false, target: { idx: 0, name: 'f' }, source: { idx: 2, name: 'definition' } }, assumePrimitive: true },
|
|
252
252
|
{ type: 'function', names: ['delayedAssign'], processor: 'builtin:assignment', config: { quoteSource: true, targetVariable: true }, assumePrimitive: true },
|
|
253
253
|
{ type: 'function', names: ['<<-'], processor: 'builtin:assignment', config: { superAssignment: true, canBeReplacement: true }, assumePrimitive: true },
|
|
@@ -41,10 +41,10 @@ function computeCallGraph(graph) {
|
|
|
41
41
|
knownReachability: new defaultmap_1.DefaultMap(() => new Set())
|
|
42
42
|
};
|
|
43
43
|
for (const [, vert] of graph.vertices(false)) {
|
|
44
|
-
if (vert
|
|
44
|
+
if (vert.tag === vertex_1.VertexType.FunctionCall) {
|
|
45
45
|
processCall(vert, undefined, graph, result, state);
|
|
46
46
|
}
|
|
47
|
-
else if (vert
|
|
47
|
+
else if (vert.tag === vertex_1.VertexType.FunctionDefinition) {
|
|
48
48
|
processFunctionDefinition(vert, undefined, graph, result, state);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -74,6 +74,8 @@ function processCds(vtx, graph, result, state) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
+
const UntargetedCallFollow = edge_1.EdgeType.Reads | edge_1.EdgeType.DefinedByOnCall | edge_1.EdgeType.DefinedBy | edge_1.EdgeType.Returns;
|
|
78
|
+
const UntargetedCallAvoid = edge_1.EdgeType.NonStandardEvaluation | edge_1.EdgeType.Argument;
|
|
77
79
|
/**
|
|
78
80
|
* This tracks the known symbol origins for a function call for which we know that flowr found no targets!
|
|
79
81
|
*/
|
|
@@ -94,7 +96,7 @@ function fallbackUntargetedCall(vtx, graph) {
|
|
|
94
96
|
}
|
|
95
97
|
let addedNew = false;
|
|
96
98
|
for (const [tar, { types }] of graph.outgoingEdges(currentId) ?? []) {
|
|
97
|
-
if ((0, edge_1.edgeIncludesType)(types,
|
|
99
|
+
if ((0, edge_1.edgeIncludesType)(types, UntargetedCallFollow) && (0, edge_1.edgeDoesNotIncludeType)(types, UntargetedCallAvoid)) {
|
|
98
100
|
addedNew = true;
|
|
99
101
|
toVisit.push(tar);
|
|
100
102
|
}
|
|
@@ -107,21 +109,22 @@ function fallbackUntargetedCall(vtx, graph) {
|
|
|
107
109
|
return collected;
|
|
108
110
|
}
|
|
109
111
|
function processCall(vtx, from, graph, result, state) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
const vid = vtx.id;
|
|
113
|
+
if (from && !reaches(from, vid, result, state.knownReachability)) {
|
|
114
|
+
result.addEdge(from, vid, edge_1.EdgeType.Calls);
|
|
112
115
|
}
|
|
113
|
-
if (state.visited.has(
|
|
116
|
+
if (state.visited.has(vid)) {
|
|
114
117
|
return;
|
|
115
118
|
}
|
|
119
|
+
state.visited.add(vid);
|
|
116
120
|
result.addVertex(vtx, undefined, true);
|
|
117
121
|
processCds(vtx, graph, result, state);
|
|
118
|
-
state.visited.add(vtx.id);
|
|
119
122
|
// for each call, resolve the targets
|
|
120
|
-
const tars = (0, linker_1.getAllFunctionCallTargets)(
|
|
123
|
+
const tars = (0, linker_1.getAllFunctionCallTargets)(vid, graph, vtx.environment);
|
|
121
124
|
let addedTarget = false;
|
|
122
125
|
for (const tar of tars) {
|
|
123
126
|
if ((0, built_in_1.isBuiltIn)(tar)) {
|
|
124
|
-
result.addEdge(
|
|
127
|
+
result.addEdge(vid, tar, edge_1.EdgeType.Calls);
|
|
125
128
|
addedTarget = true;
|
|
126
129
|
continue;
|
|
127
130
|
}
|
|
@@ -130,13 +133,13 @@ function processCall(vtx, from, graph, result, state) {
|
|
|
130
133
|
continue;
|
|
131
134
|
}
|
|
132
135
|
addedTarget = true;
|
|
133
|
-
processFunctionDefinition(targetVtx,
|
|
136
|
+
processFunctionDefinition(targetVtx, vid, graph, result, state);
|
|
134
137
|
}
|
|
135
138
|
if (vtx.origin !== 'unnamed') {
|
|
136
139
|
for (const origs of vtx.origin) {
|
|
137
140
|
if (origs.startsWith('builtin:')) {
|
|
138
141
|
addedTarget = true;
|
|
139
|
-
result.addEdge(
|
|
142
|
+
result.addEdge(vid, (0, built_in_1.builtInId)(origs.substring('builtin:'.length)), edge_1.EdgeType.Calls);
|
|
140
143
|
}
|
|
141
144
|
}
|
|
142
145
|
}
|
|
@@ -147,7 +150,7 @@ function processCall(vtx, from, graph, result, state) {
|
|
|
147
150
|
if (!oriVtx) {
|
|
148
151
|
continue;
|
|
149
152
|
}
|
|
150
|
-
result.addEdge(
|
|
153
|
+
result.addEdge(vid, ori, edge_1.EdgeType.Calls);
|
|
151
154
|
const name = graph.idMap?.get(ori);
|
|
152
155
|
if (name?.lexeme && oriVtx.tag === vertex_1.VertexType.Use) {
|
|
153
156
|
result.addVertex({
|
|
@@ -198,12 +201,12 @@ function processFunctionDefinition(vtx, from, graph, result, state) {
|
|
|
198
201
|
result.addVertex(vtx, undefined, true);
|
|
199
202
|
processCds(vtx, graph, result, state);
|
|
200
203
|
const exits = new Set(vtx.exitPoints);
|
|
204
|
+
state.potentials.push([vtx.id, vtx.subflow.graph.difference(exits)]);
|
|
201
205
|
for (const { nodeId } of exits) {
|
|
202
206
|
const v = graph.getVertex(nodeId, true);
|
|
203
207
|
if (v) {
|
|
204
208
|
processUnknown(v, vtx.id, graph, result, state);
|
|
205
209
|
}
|
|
206
210
|
}
|
|
207
|
-
state.potentials.push([vtx.id, vtx.subflow.graph.difference(exits)]);
|
|
208
211
|
}
|
|
209
212
|
//# sourceMappingURL=call-graph.js.map
|
|
@@ -34,33 +34,21 @@ function findNonLocalReads(graph, ignore) {
|
|
|
34
34
|
const ids = new Set(graph.vertexIdsOfType(vertex_1.VertexType.Use).concat(graph.vertexIdsOfType(vertex_1.VertexType.FunctionCall)));
|
|
35
35
|
/* find all variable use ids which do not link to a given id */
|
|
36
36
|
const nonLocalReads = [];
|
|
37
|
-
for (const
|
|
38
|
-
if (ignores.has(
|
|
37
|
+
for (const nodeId of ids) {
|
|
38
|
+
if (ignores.has(nodeId)) {
|
|
39
39
|
continue;
|
|
40
40
|
}
|
|
41
|
-
const outgoing = graph.outgoingEdges(
|
|
42
|
-
const name = (0, node_id_1.recoverName)(
|
|
43
|
-
const origin = graph.getVertex(
|
|
41
|
+
const outgoing = graph.outgoingEdges(nodeId);
|
|
42
|
+
const name = (0, node_id_1.recoverName)(nodeId, graph.idMap);
|
|
43
|
+
const origin = graph.getVertex(nodeId, true);
|
|
44
|
+
const type = origin?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Variable;
|
|
44
45
|
if (outgoing === undefined) {
|
|
45
|
-
nonLocalReads.push({
|
|
46
|
-
name: (0, node_id_1.recoverName)(id, graph.idMap),
|
|
47
|
-
nodeId: id,
|
|
48
|
-
controlDependencies: undefined,
|
|
49
|
-
type: origin?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Variable
|
|
50
|
-
});
|
|
46
|
+
nonLocalReads.push({ name, nodeId, type });
|
|
51
47
|
continue;
|
|
52
48
|
}
|
|
53
49
|
for (const [target, { types }] of outgoing) {
|
|
54
50
|
if ((0, edge_1.edgeIncludesType)(types, edge_1.EdgeType.Reads) && !ids.has(target)) {
|
|
55
|
-
|
|
56
|
-
logger_1.dataflowLogger.warn('found non-local read without name for id ' + id);
|
|
57
|
-
}
|
|
58
|
-
nonLocalReads.push({
|
|
59
|
-
name: (0, node_id_1.recoverName)(id, graph.idMap),
|
|
60
|
-
nodeId: id,
|
|
61
|
-
controlDependencies: undefined,
|
|
62
|
-
type: origin?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Variable
|
|
63
|
-
});
|
|
51
|
+
nonLocalReads.push({ name, nodeId, type });
|
|
64
52
|
break;
|
|
65
53
|
}
|
|
66
54
|
}
|
package/package.json
CHANGED
|
@@ -2,16 +2,41 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.executeHigherOrderQuery = executeHigherOrderQuery;
|
|
4
4
|
const higher_order_function_1 = require("../../../dataflow/fn/higher-order-function");
|
|
5
|
-
const
|
|
5
|
+
const parse_1 = require("../../../slicing/criterion/parse");
|
|
6
|
+
const vertex_1 = require("../../../dataflow/graph/vertex");
|
|
6
7
|
/**
|
|
7
8
|
* Execute higher-order function inspection queries on the given analyzer.
|
|
8
9
|
*/
|
|
9
10
|
async function executeHigherOrderQuery({ analyzer }, queries) {
|
|
10
11
|
const start = Date.now();
|
|
11
|
-
|
|
12
|
+
let filters = undefined;
|
|
13
|
+
// filter will remain undefined if at least one of the queries wants all functions
|
|
14
|
+
for (const q of queries) {
|
|
15
|
+
if (q.filter === undefined) {
|
|
16
|
+
filters = undefined;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
filters ??= [];
|
|
21
|
+
filters = filters.concat(q.filter);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const ast = await analyzer.normalize();
|
|
25
|
+
const filterFor = new Set();
|
|
26
|
+
if (filters) {
|
|
27
|
+
for (const f of filters) {
|
|
28
|
+
const i = (0, parse_1.tryResolveSliceCriterionToId)(f, ast.idMap);
|
|
29
|
+
if (i !== undefined) {
|
|
30
|
+
filterFor.add(i);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const graph = (await analyzer.dataflow()).graph;
|
|
35
|
+
const fns = graph.verticesOfType(vertex_1.VertexType.FunctionDefinition)
|
|
36
|
+
.filter(([, v]) => filterFor.size === 0 || filterFor.has(v.id));
|
|
12
37
|
const result = {};
|
|
13
38
|
for (const [id,] of fns) {
|
|
14
|
-
result[id] = (0, higher_order_function_1.isFunctionHigherOrder)(id,
|
|
39
|
+
result[id] = (0, higher_order_function_1.isFunctionHigherOrder)(id, graph, analyzer.inspectContext());
|
|
15
40
|
}
|
|
16
41
|
return {
|
|
17
42
|
'.meta': {
|
package/util/version.js
CHANGED
|
@@ -6,7 +6,7 @@ exports.printVersionInformation = printVersionInformation;
|
|
|
6
6
|
const semver_1 = require("semver");
|
|
7
7
|
const assert_1 = require("./assert");
|
|
8
8
|
// this is automatically replaced with the current version by release-it
|
|
9
|
-
const version = '2.8.
|
|
9
|
+
const version = '2.8.1';
|
|
10
10
|
/**
|
|
11
11
|
* Retrieves the current flowR version as a new {@link SemVer} object.
|
|
12
12
|
*/
|