@eagleoutice/flowr 2.8.13 → 2.8.15

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.
Files changed (32) hide show
  1. package/control-flow/extract-cfg.js +1 -1
  2. package/dataflow/environments/reference-to-maybe.js +1 -1
  3. package/dataflow/fn/exceptions-of-function.d.ts +3 -1
  4. package/dataflow/fn/exceptions-of-function.js +23 -6
  5. package/dataflow/fn/higher-order-function.js +3 -3
  6. package/dataflow/graph/call-graph.d.ts +13 -0
  7. package/dataflow/graph/call-graph.js +37 -13
  8. package/dataflow/graph/graph.d.ts +11 -2
  9. package/dataflow/graph/graph.js +29 -13
  10. package/dataflow/graph/vertex.d.ts +2 -0
  11. package/dataflow/internal/linker.js +2 -3
  12. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +1 -1
  13. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -1
  14. package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +1 -1
  15. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +4 -0
  16. package/documentation/wiki-dataflow-graph.js +1 -0
  17. package/linter/linter-rules.d.ts +3 -3
  18. package/linter/rules/deprecated-functions.d.ts +1 -1
  19. package/linter/rules/function-finder-util.d.ts +1 -1
  20. package/linter/rules/function-finder-util.js +1 -1
  21. package/linter/rules/network-functions.d.ts +1 -1
  22. package/linter/rules/seeded-randomness.d.ts +1 -1
  23. package/linter/rules/seeded-randomness.js +2 -1
  24. package/package.json +1 -1
  25. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
  26. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.d.ts +1 -1
  27. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.js +13 -3
  28. package/r-bridge/lang-4.x/ast/model/processing/stateful-fold.js +1 -1
  29. package/search/flowr-search-filters.d.ts +1 -1
  30. package/search/flowr-search-filters.js +36 -6
  31. package/search/search-executor/search-enrichers.js +7 -6
  32. package/util/version.js +1 -1
@@ -79,7 +79,7 @@ function extractCfgQuick(ast) {
79
79
  function getCallsInCfg(cfg, graph) {
80
80
  const calls = new Map();
81
81
  for (const vertexId of cfg.graph.vertices().keys()) {
82
- const vertex = graph.getVertex(vertexId, true);
82
+ const vertex = graph.getVertex(vertexId);
83
83
  if ((0, vertex_1.isFunctionCallVertex)(vertex)) {
84
84
  calls.set(vertexId, vertex);
85
85
  }
@@ -34,7 +34,7 @@ function makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd = u
34
34
  }
35
35
  }
36
36
  }
37
- const node = graph.getVertex(ref.nodeId, true);
37
+ const node = graph.getVertex(ref.nodeId);
38
38
  if (node) {
39
39
  if (node.cds) {
40
40
  appToCdsUnique(node.cds, defaultCd);
@@ -9,5 +9,7 @@ export interface ExceptionPoint {
9
9
  * Collect exception sources of a function in the call graph.
10
10
  * This returns the `NodeId`s of functions that may throw exceptions when called by the given function.
11
11
  * Please be aware, that these are restricted to functions known by flowR.
12
+ * With `knownThrower` you can provide additional functions that are known to throw exceptions.
13
+ * @returns A record mapping all `NodeId`s of functions that may throw exceptions to their exception points.
12
14
  */
13
- export declare function calculateExceptionsOfFunction(id: NodeId, graph: CallGraph): ExceptionPoint[];
15
+ export declare function calculateExceptionsOfFunction(id: NodeId, graph: CallGraph, knownThrower?: Record<NodeId, ExceptionPoint[]>): Record<NodeId, ExceptionPoint[]>;
@@ -8,9 +8,12 @@ const CatchHandlers = new Set([built_in_1.BuiltInProcName.Try]);
8
8
  * Collect exception sources of a function in the call graph.
9
9
  * This returns the `NodeId`s of functions that may throw exceptions when called by the given function.
10
10
  * Please be aware, that these are restricted to functions known by flowR.
11
+ * With `knownThrower` you can provide additional functions that are known to throw exceptions.
12
+ * @returns A record mapping all `NodeId`s of functions that may throw exceptions to their exception points.
11
13
  */
12
- function calculateExceptionsOfFunction(id, graph) {
13
- const collectedExceptions = [];
14
+ function calculateExceptionsOfFunction(id, graph, knownThrower = {}) {
15
+ const collectedExceptions = {};
16
+ const mine = [];
14
17
  const visited = new Set();
15
18
  const toVisit = [id];
16
19
  while (toVisit.length > 0) {
@@ -19,6 +22,15 @@ function calculateExceptionsOfFunction(id, graph) {
19
22
  continue;
20
23
  }
21
24
  visited.add(currentId);
25
+ const kt = knownThrower[currentId];
26
+ if (kt) {
27
+ for (const e of kt) {
28
+ if (!mine.includes(e)) {
29
+ mine.push(e);
30
+ }
31
+ }
32
+ continue;
33
+ }
22
34
  const vtx = graph.getVertex(currentId);
23
35
  if (!vtx) {
24
36
  continue;
@@ -27,11 +39,13 @@ function calculateExceptionsOfFunction(id, graph) {
27
39
  continue;
28
40
  }
29
41
  if (vtx.tag === vertex_1.VertexType.FunctionDefinition) {
30
- for (const e of vtx.exitPoints.filter(e => e.type === 4 /* ExitPointType.Error */)) {
31
- if (!collectedExceptions.some(x => x.id === e.nodeId)) {
32
- collectedExceptions.push({ id: e.nodeId, cds: e.cds });
42
+ const es = vtx.exitPoints.filter(e => e.type === 4 /* ExitPointType.Error */).map(e => ({ id: e.nodeId, cds: e.cds }));
43
+ for (const e of es) {
44
+ if (!mine.includes(e)) {
45
+ mine.push(e);
33
46
  }
34
47
  }
48
+ collectedExceptions[vtx.id] = es;
35
49
  }
36
50
  else if (vtx.tag === vertex_1.VertexType.FunctionCall && vtx.origin !== 'unnamed' && vtx.origin.some(c => CatchHandlers.has(c))) {
37
51
  // skip the try-catch handlers as they catch all exceptions within their body
@@ -39,9 +53,12 @@ function calculateExceptionsOfFunction(id, graph) {
39
53
  }
40
54
  const outEdges = graph.outgoingEdges(currentId) ?? [];
41
55
  for (const [out] of outEdges) {
42
- toVisit.push(out);
56
+ if (!visited.has(out)) {
57
+ toVisit.push(out);
58
+ }
43
59
  }
44
60
  }
61
+ collectedExceptions[id] = mine;
45
62
  return collectedExceptions;
46
63
  }
47
64
  //# sourceMappingURL=exceptions-of-function.js.map
@@ -9,7 +9,7 @@ const config_1 = require("../../config");
9
9
  const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
10
10
  const general_1 = require("../eval/values/general");
11
11
  function isAnyReturnAFunction(def, graph) {
12
- const workingQueue = def.exitPoints.map(d => graph.getVertex(d.nodeId, true)).filter(assert_1.isNotUndefined);
12
+ const workingQueue = def.exitPoints.map(d => graph.getVertex(d.nodeId)).filter(assert_1.isNotUndefined);
13
13
  const seen = new Set();
14
14
  while (workingQueue.length > 0) {
15
15
  const current = workingQueue.pop();
@@ -23,7 +23,7 @@ function isAnyReturnAFunction(def, graph) {
23
23
  const next = graph.outgoingEdges(current.id) ?? [];
24
24
  for (const [t, { types }] of next) {
25
25
  if ((0, edge_1.edgeIncludesType)(types, edge_1.EdgeType.Returns)) {
26
- const v = graph.getVertex(t, true);
26
+ const v = graph.getVertex(t);
27
27
  if (v) {
28
28
  workingQueue.push(v);
29
29
  }
@@ -38,7 +38,7 @@ function inspectCallSitesArgumentsFns(def, graph, ctx) {
38
38
  if (!(0, edge_1.edgeIncludesType)(types, edge_1.EdgeType.Calls)) {
39
39
  continue;
40
40
  }
41
- const caller = graph.getVertex(callerId, true);
41
+ const caller = graph.getVertex(callerId);
42
42
  if (!caller || !(0, vertex_1.isFunctionCallVertex)(caller)) {
43
43
  continue;
44
44
  }
@@ -1,17 +1,30 @@
1
1
  import { DataflowGraph } from './graph';
2
2
  import type { DataflowGraphVertexFunctionCall, DataflowGraphVertexFunctionDefinition } from './vertex';
3
3
  import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
4
+ import { DefaultMap } from '../../util/collections/defaultmap';
4
5
  /**
5
6
  * A call graph is a dataflow graph where all vertices are function calls.
6
7
  * You can create a call graph from a dataflow graph using {@link computeCallGraph}.
7
8
  * If you want to extract a sub call graph, use {@link getSubCallGraph}.
9
+ * @see {@link dropTransitiveEdges} - to reduce the call graph by dropping transitive edges
8
10
  */
9
11
  export type CallGraph = DataflowGraph<Required<DataflowGraphVertexFunctionCall | DataflowGraphVertexFunctionDefinition>>;
10
12
  /**
11
13
  * Extracts the sub call graph from the given call graph, starting from the given entry points.
12
14
  */
13
15
  export declare function getSubCallGraph(graph: CallGraph, entryPoints: Set<NodeId>): CallGraph;
16
+ /**
17
+ *
18
+ */
19
+ export declare function reaches(from: NodeId, to: NodeId, graph: DataflowGraph, knownReachability?: DefaultMap<NodeId, Set<NodeId>>): boolean;
20
+ /**
21
+ * Reduces the call graph by dropping all transitive edges.
22
+ */
23
+ export declare function dropTransitiveEdges(graph: CallGraph): CallGraph;
14
24
  /**
15
25
  * Computes the call graph from the given dataflow graph.
26
+ * @see {@link CallGraph} - for details
27
+ * @see {@link getSubCallGraph} - to extract sub call graphs
28
+ * @see {@link dropTransitiveEdges} - to reduce the call graph by dropping transitive edges
16
29
  */
17
30
  export declare function computeCallGraph(graph: DataflowGraph): CallGraph;
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getSubCallGraph = getSubCallGraph;
4
+ exports.reaches = reaches;
5
+ exports.dropTransitiveEdges = dropTransitiveEdges;
4
6
  exports.computeCallGraph = computeCallGraph;
5
7
  const graph_1 = require("./graph");
6
8
  const vertex_1 = require("./vertex");
@@ -21,7 +23,7 @@ function getSubCallGraph(graph, entryPoints) {
21
23
  continue;
22
24
  }
23
25
  visited.add(currentId);
24
- const currentVtx = graph.getVertex(currentId, true);
26
+ const currentVtx = graph.getVertex(currentId);
25
27
  if (!currentVtx) {
26
28
  continue;
27
29
  }
@@ -35,7 +37,10 @@ function getSubCallGraph(graph, entryPoints) {
35
37
  }
36
38
  return result;
37
39
  }
38
- function reaches(from, to, graph, knownReachability) {
40
+ /**
41
+ *
42
+ */
43
+ function reaches(from, to, graph, knownReachability = new defaultmap_1.DefaultMap(() => new Set())) {
39
44
  const visited = new Set();
40
45
  const toVisit = [from];
41
46
  while (toVisit.length > 0) {
@@ -58,15 +63,34 @@ function reaches(from, to, graph, knownReachability) {
58
63
  }
59
64
  return false;
60
65
  }
66
+ /**
67
+ * Reduces the call graph by dropping all transitive edges.
68
+ */
69
+ function dropTransitiveEdges(graph) {
70
+ const newCg = new graph_1.DataflowGraph(graph.idMap);
71
+ newCg.mergeVertices(graph);
72
+ const knownReachability = new defaultmap_1.DefaultMap(() => new Set());
73
+ // heuristically sort by dif in ids
74
+ const es = Array.from(graph.edges(), ([e, ts]) => ts.entries().map(([t, { types }]) => [e, t, types]).toArray()).flat()
75
+ .sort((a, b) => String(a[0]).localeCompare(String(a[1])) - String(b[0]).localeCompare(String(b[1])));
76
+ for (const [from, to, types] of es) {
77
+ if (!reaches(from, to, newCg, knownReachability)) {
78
+ newCg.addEdge(from, to, types);
79
+ }
80
+ }
81
+ return newCg;
82
+ }
61
83
  /**
62
84
  * Computes the call graph from the given dataflow graph.
85
+ * @see {@link CallGraph} - for details
86
+ * @see {@link getSubCallGraph} - to extract sub call graphs
87
+ * @see {@link dropTransitiveEdges} - to reduce the call graph by dropping transitive edges
63
88
  */
64
89
  function computeCallGraph(graph) {
65
90
  const result = new graph_1.DataflowGraph(graph.idMap);
66
91
  const state = {
67
92
  visited: new Set(),
68
- potentials: [],
69
- knownReachability: new defaultmap_1.DefaultMap(() => new Set())
93
+ potentials: []
70
94
  };
71
95
  for (const [, vert] of graph.vertices(false)) {
72
96
  if (vert.tag === vertex_1.VertexType.FunctionCall) {
@@ -79,7 +103,7 @@ function computeCallGraph(graph) {
79
103
  for (const [from, tos] of state.potentials) {
80
104
  for (const to of tos) {
81
105
  if (!result.hasVertex(to)) {
82
- const v = graph.getVertex(to, true);
106
+ const v = graph.getVertex(to);
83
107
  if (v) {
84
108
  processUnknown(v, from, graph, result, state);
85
109
  if (v.tag === vertex_1.VertexType.FunctionDefinition) {
@@ -87,7 +111,7 @@ function computeCallGraph(graph) {
87
111
  }
88
112
  }
89
113
  }
90
- else if (!reaches(from, to, result, state.knownReachability)) {
114
+ else {
91
115
  result.addEdge(from, to, edge_1.EdgeType.Calls);
92
116
  }
93
117
  }
@@ -96,7 +120,7 @@ function computeCallGraph(graph) {
96
120
  }
97
121
  function processCds(vtx, graph, result, state) {
98
122
  for (const tar of vtx.cds ?? []) {
99
- const targetVtx = graph.getVertex(tar.id, true);
123
+ const targetVtx = graph.getVertex(tar.id);
100
124
  if (targetVtx) {
101
125
  processUnknown(targetVtx, undefined, graph, result, state);
102
126
  }
@@ -118,7 +142,7 @@ function fallbackUntargetedCall(vtx, graph) {
118
142
  continue;
119
143
  }
120
144
  visited.add(currentId);
121
- const currentVtx = graph.getVertex(currentId, true);
145
+ const currentVtx = graph.getVertex(currentId);
122
146
  if (!currentVtx) {
123
147
  continue;
124
148
  }
@@ -138,7 +162,7 @@ function fallbackUntargetedCall(vtx, graph) {
138
162
  }
139
163
  function processCall(vtx, from, graph, result, state) {
140
164
  const vid = vtx.id;
141
- if (from && !reaches(from, vid, result, state.knownReachability)) {
165
+ if (from) {
142
166
  result.addEdge(from, vid, edge_1.EdgeType.Calls);
143
167
  }
144
168
  if (state.visited.has(vid)) {
@@ -156,7 +180,7 @@ function processCall(vtx, from, graph, result, state) {
156
180
  addedTarget = true;
157
181
  continue;
158
182
  }
159
- const targetVtx = graph.getVertex(tar, true);
183
+ const targetVtx = graph.getVertex(tar);
160
184
  if (targetVtx?.tag !== vertex_1.VertexType.FunctionDefinition) {
161
185
  continue;
162
186
  }
@@ -174,7 +198,7 @@ function processCall(vtx, from, graph, result, state) {
174
198
  if (!addedTarget) {
175
199
  const origs = fallbackUntargetedCall(vtx, graph);
176
200
  for (const ori of origs) {
177
- const oriVtx = graph.getVertex(ori, true);
201
+ const oriVtx = graph.getVertex(ori);
178
202
  if (!oriVtx) {
179
203
  continue;
180
204
  }
@@ -197,7 +221,7 @@ function processCall(vtx, from, graph, result, state) {
197
221
  if ((0, edge_1.edgeDoesNotIncludeType)(types, edge_1.EdgeType.Reads | edge_1.EdgeType.Returns | edge_1.EdgeType.Argument)) {
198
222
  continue;
199
223
  }
200
- const tVtx = graph.getVertex(tar, true);
224
+ const tVtx = graph.getVertex(tar);
201
225
  if (!tVtx) {
202
226
  continue;
203
227
  }
@@ -231,7 +255,7 @@ function processFunctionDefinition(vtx, from, graph, result, state) {
231
255
  const exits = new Set(vtx.exitPoints);
232
256
  state.potentials.push([vtx.id, vtx.subflow.graph.difference(exits)]);
233
257
  for (const { nodeId } of exits) {
234
- const v = graph.getVertex(nodeId, true);
258
+ const v = graph.getVertex(nodeId);
235
259
  if (v) {
236
260
  processUnknown(v, vtx.id, graph, result, state);
237
261
  }
@@ -118,11 +118,19 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
118
118
  /**
119
119
  * Get the {@link DataflowGraphVertexInfo} attached to a vertex.
120
120
  * @param id - The id of the node to get
121
- * @param includeDefinedFunctions - If true this will search function definitions as well and not just the toplevel
122
121
  * @returns the node info for the given id (if it exists)
123
122
  * @see #get
123
+ * @see #getRootVertex
124
+ */
125
+ getVertex(id: NodeId): Vertex | undefined;
126
+ /**
127
+ * Get the {@link DataflowGraphVertexInfo} attached to a root-level vertex.
128
+ * @param id - The id of the node to get
129
+ * @returns the node info for the given id (if it exists)
130
+ * @see #get
131
+ * @see #getVertex
124
132
  */
125
- getVertex(id: NodeId, includeDefinedFunctions?: boolean): Vertex | undefined;
133
+ getRootVertex(id: NodeId): Vertex | undefined;
126
134
  outgoingEdges(id: NodeId): OutgoingEdges | undefined;
127
135
  ingoingEdges(id: NodeId): IngoingEdges | undefined;
128
136
  /**
@@ -185,6 +193,7 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
185
193
  * in the context of function definitions
186
194
  */
187
195
  mergeWith(otherGraph: DataflowGraph<Vertex, Edge> | undefined, mergeRootVertices?: boolean): this;
196
+ mergeVertices(otherGraph: DataflowGraph<Vertex, Edge>, mergeRootVertices?: boolean): void;
188
197
  private mergeEdges;
189
198
  /**
190
199
  * Marks a vertex in the graph to be a definition
@@ -84,18 +84,31 @@ class DataflowGraph {
84
84
  */
85
85
  get(id, includeDefinedFunctions = true) {
86
86
  // if we do not want to include function definitions, only retrieve the value if the id is part of the root vertices
87
- const vertex = this.getVertex(id, includeDefinedFunctions);
87
+ const vertex = includeDefinedFunctions ? this.getVertex(id) : this.getRootVertex(id);
88
88
  return vertex === undefined ? undefined : [vertex, this.outgoingEdges(id) ?? new Map()];
89
89
  }
90
90
  /**
91
91
  * Get the {@link DataflowGraphVertexInfo} attached to a vertex.
92
92
  * @param id - The id of the node to get
93
- * @param includeDefinedFunctions - If true this will search function definitions as well and not just the toplevel
94
93
  * @returns the node info for the given id (if it exists)
95
94
  * @see #get
95
+ * @see #getRootVertex
96
96
  */
97
- getVertex(id, includeDefinedFunctions = true) {
98
- return includeDefinedFunctions || this.rootVertices.has(id) ? this.vertexInformation.get(id) : undefined;
97
+ getVertex(id) {
98
+ return this.vertexInformation.get(id);
99
+ }
100
+ /**
101
+ * Get the {@link DataflowGraphVertexInfo} attached to a root-level vertex.
102
+ * @param id - The id of the node to get
103
+ * @returns the node info for the given id (if it exists)
104
+ * @see #get
105
+ * @see #getVertex
106
+ */
107
+ getRootVertex(id) {
108
+ if (!this.rootVertices.has(id)) {
109
+ return undefined;
110
+ }
111
+ return this.vertexInformation.get(id);
99
112
  }
100
113
  outgoingEdges(id) {
101
114
  return this.edgeInformation.get(id);
@@ -254,6 +267,15 @@ class DataflowGraph {
254
267
  if (otherGraph === undefined) {
255
268
  return this;
256
269
  }
270
+ this.mergeVertices(otherGraph, mergeRootVertices);
271
+ for (const [type, ids] of otherGraph.types) {
272
+ const existing = this.types.get(type);
273
+ this.types.set(type, existing ? existing.concat(ids) : ids.slice());
274
+ }
275
+ this.mergeEdges(otherGraph);
276
+ return this;
277
+ }
278
+ mergeVertices(otherGraph, mergeRootVertices = true) {
257
279
  // merge root ids
258
280
  if (mergeRootVertices) {
259
281
  for (const root of otherGraph.rootVertices) {
@@ -267,12 +289,6 @@ class DataflowGraph {
267
289
  const currentInfo = this.vertexInformation.get(id);
268
290
  this.vertexInformation.set(id, currentInfo === undefined ? info : mergeNodeInfos(currentInfo, info));
269
291
  }
270
- for (const [type, ids] of otherGraph.types) {
271
- const existing = this.types.get(type);
272
- this.types.set(type, existing ? existing.concat(ids) : ids.slice());
273
- }
274
- this.mergeEdges(otherGraph);
275
- return this;
276
292
  }
277
293
  mergeEdges(otherGraph) {
278
294
  for (const [id, edges] of otherGraph.edgeInformation.entries()) {
@@ -298,7 +314,7 @@ class DataflowGraph {
298
314
  * @param reference - The reference to the vertex to mark as definition
299
315
  */
300
316
  setDefinitionOfVertex(reference) {
301
- const vertex = this.getVertex(reference.nodeId, true);
317
+ const vertex = this.getVertex(reference.nodeId);
302
318
  (0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${JSON.stringify(reference)} to set reference`);
303
319
  if (vertex.tag === vertex_1.VertexType.FunctionDefinition || vertex.tag === vertex_1.VertexType.VariableDefinition) {
304
320
  vertex.cds = reference.cds;
@@ -314,7 +330,7 @@ class DataflowGraph {
314
330
  * @param info - The information about the new function call node
315
331
  */
316
332
  updateToFunctionCall(info) {
317
- const vertex = this.getVertex(info.id, true);
333
+ const vertex = this.getVertex(info.id);
318
334
  (0, assert_1.guard)(vertex !== undefined && (vertex.tag === vertex_1.VertexType.Use || vertex.tag === vertex_1.VertexType.Value), () => `node must be a use or value node for ${JSON.stringify(info.id)} to update it to a function call but is ${vertex?.tag}`);
319
335
  const previousTag = vertex.tag;
320
336
  this.vertexInformation.set(info.id, { ...vertex, ...info, tag: vertex_1.VertexType.FunctionCall });
@@ -324,7 +340,7 @@ class DataflowGraph {
324
340
  /** If you do not pass the `to` node, this will just mark the node as maybe */
325
341
  addControlDependency(from, to, when) {
326
342
  to = to ? (0, node_id_1.normalizeIdToNumberIfPossible)(to) : undefined;
327
- const vertex = this.getVertex(from, true);
343
+ const vertex = this.getVertex(from);
328
344
  (0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${from} to add control dependency`);
329
345
  vertex.cds ??= [];
330
346
  if (to) {
@@ -218,6 +218,8 @@ export interface DataflowGraphVertexVariableDefinition extends DataflowGraphVert
218
218
  readonly tag: VertexType.VariableDefinition;
219
219
  /** Does not require an environment, those are attached to the call */
220
220
  readonly environment?: undefined;
221
+ /** Indicates whether the variable definition is a *partial* definition (e.g,. in `x[a] <- b`) */
222
+ readonly par?: true;
221
223
  }
222
224
  /**
223
225
  * Arguments required to construct a vertex which represents the definition of a function in the {@link DataflowGraph|dataflow graph}.
@@ -42,7 +42,7 @@ function findNonLocalReads(graph, ignore) {
42
42
  }
43
43
  const outgoing = graph.outgoingEdges(nodeId);
44
44
  const name = (0, node_id_1.recoverName)(nodeId, graph.idMap);
45
- const origin = graph.getVertex(nodeId, true);
45
+ const origin = graph.getVertex(nodeId);
46
46
  const type = origin?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Variable;
47
47
  if (outgoing === undefined) {
48
48
  nonLocalReads.push({ name, nodeId, type });
@@ -363,7 +363,6 @@ function getAllLinkedFunctionDefinitions(functionDefinitionReadIds, dataflowGrap
363
363
  const visited = new Set();
364
364
  while (potential.length !== 0) {
365
365
  const cid = potential.pop();
366
- // console.log(`visiting ${recoverName(cid, dataflowGraph.idMap)} ${cid}`);
367
366
  visited.add(cid);
368
367
  if ((0, built_in_1.isBuiltIn)(cid)) {
369
368
  builtIns.add(cid);
@@ -388,7 +387,7 @@ function getAllLinkedFunctionDefinitions(functionDefinitionReadIds, dataflowGrap
388
387
  }
389
388
  }
390
389
  }
391
- if (vertex.tag === vertex_1.VertexType.FunctionCall || hasReturnEdge) {
390
+ if (vertex.tag === vertex_1.VertexType.FunctionCall || hasReturnEdge || (vertex.tag === vertex_1.VertexType.VariableDefinition && vertex.par)) {
392
391
  continue;
393
392
  }
394
393
  for (const [target, { types }] of edges) {
@@ -271,7 +271,7 @@ function processAssignmentToString(target, args, name, rootId, data, config, sou
271
271
  });
272
272
  }
273
273
  function checkTargetReferenceType(source, sourceInfo) {
274
- const vert = sourceInfo.graph.getVertex(source.info.id, true);
274
+ const vert = sourceInfo.graph.getVertex(source.info.id);
275
275
  switch (vert?.tag) {
276
276
  case vertex_1.VertexType.FunctionDefinition:
277
277
  return identifier_1.ReferenceType.Function;
@@ -84,7 +84,7 @@ function updateSideEffectsForCalledFunctions(calledEnvs, inputEnvironment, nextG
84
84
  };
85
85
  }
86
86
  if (callDependencies === null) {
87
- callDependencies = nextGraph.getVertex(functionCall, true)?.cds;
87
+ callDependencies = nextGraph.getVertex(functionCall)?.cds;
88
88
  }
89
89
  inputEnvironment = (0, overwrite_1.overwriteEnvironment)(inputEnvironment, environment, callDependencies);
90
90
  }
@@ -22,7 +22,7 @@ function processPipe(name, args, rootId, data) {
22
22
  const [lhs, rhs] = args.map(e => (0, unpack_argument_1.unpackNonameArg)(e));
23
23
  (0, assert_1.guard)(lhs !== undefined && rhs !== undefined, () => `lhs and rhs must be present, but ${JSON.stringify(lhs)} and ${JSON.stringify(rhs)} were found instead.`);
24
24
  if (rhs.type === type_1.RType.FunctionCall) {
25
- const functionCallNode = information.graph.getVertex(rhs.info.id, true);
25
+ const functionCallNode = information.graph.getVertex(rhs.info.id);
26
26
  (0, assert_1.guard)(functionCallNode?.tag === vertex_1.VertexType.FunctionCall, () => `Expected function call node with id ${rhs.info.id} to be a function call node, but got ${functionCallNode?.tag} instead.`);
27
27
  // make the lhs an argument node:
28
28
  const argId = lhs.info.id;
@@ -45,6 +45,10 @@ args, rootId, data, config) {
45
45
  if (createdVert?.tag === vertex_1.VertexType.FunctionCall) {
46
46
  createdVert.origin = [built_in_1.BuiltInProcName.Replacement];
47
47
  }
48
+ const targetVert = res.graph.getVertex((0, unpack_argument_1.unpackArg)(args[0])?.info.id);
49
+ if (targetVert?.tag === vertex_1.VertexType.VariableDefinition) {
50
+ targetVert.par = true;
51
+ }
48
52
  const convertedArgs = config.readIndices ? args.slice(1, -1) : (0, built_in_access_1.symbolArgumentsToStrings)(args.slice(1, -1), 0);
49
53
  /* now, we soft-inject other arguments, so that calls like `x[y] <- 3` are linked correctly */
50
54
  const { callArgs } = (0, common_1.processAllArguments)({
@@ -392,6 +392,7 @@ ${(0, doc_structure_1.details)('Example: Super Definition (<code><<-</code>)', a
392
392
  The implementation is relatively sparse and similar to the other marker vertices:
393
393
 
394
394
  ${ctx.hierarchy('DataflowGraphVertexVariableDefinition')}
395
+ Of only interest is \`par\`, which signals that the definitions is partial (e.g., in the case of \`x[a] <- 1\`).
395
396
 
396
397
  Of course, there are not just operators that define variables, but also functions, like \`assign\`.
397
398
 
@@ -5,7 +5,7 @@ import type { LintingRule } from './linter-format';
5
5
  */
6
6
  export declare const LintingRules: {
7
7
  readonly 'deprecated-functions': {
8
- readonly createSearch: (config: import("./rules/function-finder-util").FunctionsToDetectConfig) => import("../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter"], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
8
+ readonly createSearch: (config: import("./rules/function-finder-util").FunctionsToDetectConfig) => import("../search/flowr-search-builder").FlowrSearchBuilder<"all", ["filter", "with", "filter"], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
9
9
  readonly processSearchResult: <T extends import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>(elements: import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, T>, _config: unknown, _data: unknown, refineSearch?: (elements: T) => T) => {
10
10
  results: {
11
11
  certainty: import("./linter-format").LintingResultCertainty;
@@ -57,7 +57,7 @@ export declare const LintingRules: {
57
57
  };
58
58
  };
59
59
  readonly 'seeded-randomness': {
60
- readonly createSearch: (config: import("./rules/seeded-randomness").SeededRandomnessConfig) => import("../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter", "with"], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
60
+ readonly createSearch: (config: import("./rules/seeded-randomness").SeededRandomnessConfig) => import("../search/flowr-search-builder").FlowrSearchBuilder<"all", ["filter", "with", "filter", "with"], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
61
61
  readonly processSearchResult: (elements: import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>, config: import("./rules/seeded-randomness").SeededRandomnessConfig, { dataflow, analyzer }: {
62
62
  normalize: import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
63
63
  dataflow: import("../dataflow/info").DataflowInformation;
@@ -186,7 +186,7 @@ export declare const LintingRules: {
186
186
  };
187
187
  };
188
188
  readonly 'network-functions': {
189
- readonly createSearch: (config: import("./rules/network-functions").NetworkFunctionsConfig) => import("../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter"], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
189
+ readonly createSearch: (config: import("./rules/network-functions").NetworkFunctionsConfig) => import("../search/flowr-search-builder").FlowrSearchBuilder<"all", ["filter", "with", "filter"], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
190
190
  readonly processSearchResult: (e: import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>, c: import("./rules/network-functions").NetworkFunctionsConfig, d: {
191
191
  normalize: import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
192
192
  dataflow: import("../dataflow/info").DataflowInformation;
@@ -2,7 +2,7 @@ import { LintingRuleCertainty } from '../linter-format';
2
2
  import { LintingRuleTag } from '../linter-tags';
3
3
  import { type FunctionsMetadata, type FunctionsResult, type FunctionsToDetectConfig } from './function-finder-util';
4
4
  export declare const DEPRECATED_FUNCTIONS: {
5
- readonly createSearch: (config: FunctionsToDetectConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter"], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
5
+ readonly createSearch: (config: FunctionsToDetectConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["filter", "with", "filter"], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
6
6
  readonly processSearchResult: <T extends import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>(elements: import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, T>, _config: unknown, _data: unknown, refineSearch?: (elements: T) => T) => {
7
7
  results: {
8
8
  certainty: import("../linter-format").LintingResultCertainty;
@@ -25,7 +25,7 @@ export interface FunctionsToDetectConfig extends MergeableRecord {
25
25
  * This helper object collects utility functions used to create linting rules that search for specific functions.
26
26
  */
27
27
  export declare const functionFinderUtil: {
28
- createSearch: (functions: readonly string[]) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter"], ParentInformation, Promise<FlowrSearchElements<ParentInformation, [] | FlowrSearchElement<ParentInformation>[]>>>;
28
+ createSearch: (functions: readonly string[]) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["filter", "with", "filter"], ParentInformation, Promise<FlowrSearchElements<ParentInformation, [] | FlowrSearchElement<ParentInformation>[]>>>;
29
29
  processSearchResult: <T extends FlowrSearchElement<ParentInformation>[]>(elements: FlowrSearchElements<ParentInformation, T>, _config: unknown, _data: unknown, refineSearch?: (elements: T) => T) => {
30
30
  results: {
31
31
  certainty: LintingResultCertainty;
@@ -15,7 +15,7 @@ const dependencies_query_format_1 = require("../../queries/catalog/dependencies-
15
15
  */
16
16
  exports.functionFinderUtil = {
17
17
  createSearch: (functions) => {
18
- return (flowr_search_builder_1.Q.all()
18
+ return (flowr_search_builder_1.Q.all().filter(vertex_1.VertexType.FunctionCall)
19
19
  .with(search_enrichers_1.Enrichment.CallTargets, { onlyBuiltin: true })
20
20
  .filter({
21
21
  name: flowr_search_filters_1.FlowrFilter.MatchesEnrichment,
@@ -9,7 +9,7 @@ export interface NetworkFunctionsConfig extends MergeableRecord {
9
9
  onlyTriggerWithArgument?: RegExp | string;
10
10
  }
11
11
  export declare const NETWORK_FUNCTIONS: {
12
- readonly createSearch: (config: NetworkFunctionsConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter"], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
12
+ readonly createSearch: (config: NetworkFunctionsConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["filter", "with", "filter"], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
13
13
  readonly processSearchResult: (e: import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>, c: NetworkFunctionsConfig, d: {
14
14
  normalize: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
15
15
  dataflow: import("../../dataflow/info").DataflowInformation;
@@ -30,7 +30,7 @@ export interface SeededRandomnessMeta extends MergeableRecord {
30
30
  callsWithOtherBranchProducers: number;
31
31
  }
32
32
  export declare const SEEDED_RANDOMNESS: {
33
- readonly createSearch: (config: SeededRandomnessConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter", "with"], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
33
+ readonly createSearch: (config: SeededRandomnessConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["filter", "with", "filter", "with"], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
34
34
  readonly processSearchResult: (elements: import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>, config: SeededRandomnessConfig, { dataflow, analyzer }: {
35
35
  normalize: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
36
36
  dataflow: import("../../dataflow/info").DataflowInformation;
@@ -14,12 +14,13 @@ const linter_tags_1 = require("../linter-tags");
14
14
  const alias_tracking_1 = require("../../dataflow/eval/resolve/alias-tracking");
15
15
  const general_1 = require("../../dataflow/eval/values/general");
16
16
  const config_1 = require("../../config");
17
+ const vertex_1 = require("../../dataflow/graph/vertex");
17
18
  const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
18
19
  const r_value_1 = require("../../dataflow/eval/values/r-value");
19
20
  const info_1 = require("../../dataflow/info");
20
21
  const built_in_1 = require("../../dataflow/environments/built-in");
21
22
  exports.SEEDED_RANDOMNESS = {
22
- createSearch: (config) => flowr_search_builder_1.Q.all()
23
+ createSearch: (config) => flowr_search_builder_1.Q.all().filter(vertex_1.VertexType.FunctionCall)
23
24
  .with(search_enrichers_1.Enrichment.CallTargets, { onlyBuiltin: true })
24
25
  .filter({
25
26
  name: flowr_search_filters_1.FlowrFilter.MatchesEnrichment,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.8.13",
3
+ "version": "2.8.15",
4
4
  "description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "repository": {
@@ -139,7 +139,7 @@ function identifyLinkToLastCallRelationSync(from, cfg, graph, { callName, cascad
139
139
  const getVertex = knownCalls ?
140
140
  (node) => knownCalls.get(node) :
141
141
  (node) => {
142
- const v = graph.getVertex(node, true);
142
+ const v = graph.getVertex(node);
143
143
  return (0, vertex_1.isFunctionCallVertex)(v) ? v : undefined;
144
144
  };
145
145
  (0, simple_visitor_1.visitCfgInReverseOrder)(cfg, [from], node => {
@@ -10,7 +10,7 @@ export declare function getFunctionsToConsiderInCallGraph(queries: readonly {
10
10
  filter?: readonly SingleSlicingCriterion[];
11
11
  }[], analyzer: ReadonlyFlowrAnalysisProvider, onlyDefinitions?: boolean): Promise<{
12
12
  cg: import("../../../dataflow/graph/call-graph").CallGraph;
13
- fns: IteratorObject<[NodeId, Required<import("../../../dataflow/graph/vertex").DataflowGraphVertexFunctionCall | import("../../../dataflow/graph/vertex").DataflowGraphVertexFunctionDefinition>], undefined, unknown>;
13
+ fns: MapIterator<[NodeId, Required<import("../../../dataflow/graph/vertex").DataflowGraphVertexFunctionCall | import("../../../dataflow/graph/vertex").DataflowGraphVertexFunctionDefinition>]>;
14
14
  }>;
15
15
  /**
16
16
  * Execute exception function inspection queries on the given analyzer.
@@ -32,8 +32,10 @@ async function getFunctionsToConsiderInCallGraph(queries, analyzer, onlyDefiniti
32
32
  }
33
33
  }
34
34
  const cg = await analyzer.callGraph();
35
- const fns = (onlyDefinitions || filterFor.size === 0 ? cg.verticesOfType(vertex_1.VertexType.FunctionDefinition) : cg.vertices(true))
36
- .filter(([, v]) => filterFor.size === 0 || filterFor.has(v.id));
35
+ let fns = (onlyDefinitions || filterFor.size === 0 ? cg.verticesOfType(vertex_1.VertexType.FunctionDefinition) : cg.vertices(true));
36
+ if (filterFor.size > 0) {
37
+ fns = fns.filter(([id,]) => filterFor.has(id));
38
+ }
37
39
  return { cg, fns };
38
40
  }
39
41
  /**
@@ -44,7 +46,15 @@ async function executeExceptionQuery({ analyzer }, queries) {
44
46
  const { cg, fns } = await getFunctionsToConsiderInCallGraph(queries, analyzer);
45
47
  const result = {};
46
48
  for (const [id,] of fns) {
47
- result[id] = (0, exceptions_of_function_1.calculateExceptionsOfFunction)(id, cg);
49
+ if (result[id]) {
50
+ continue;
51
+ }
52
+ const res = (0, exceptions_of_function_1.calculateExceptionsOfFunction)(id, cg, result);
53
+ for (const [k, v] of Object.entries(res)) {
54
+ if (!result[k]) {
55
+ result[k] = v;
56
+ }
57
+ }
48
58
  }
49
59
  return {
50
60
  '.meta': {
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.foldAstStateful = foldAstStateful;
4
- const assert_1 = require("../../../../../util/assert");
5
4
  const type_1 = require("../type");
6
5
  const r_function_call_1 = require("../nodes/r-function-call");
6
+ const assert_1 = require("../../../../../util/assert");
7
7
  /**
8
8
  * Folds in old functional-fashion over the AST structure but allowing for a down function which can pass context to child nodes.
9
9
  */
@@ -2,7 +2,7 @@ import { RType } from '../r-bridge/lang-4.x/ast/model/type';
2
2
  import { VertexType } from '../dataflow/graph/vertex';
3
3
  import type { ParentInformation } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
4
4
  import type { FlowrSearchElement } from './flowr-search';
5
- import { type Enrichment } from './search-executor/search-enrichers';
5
+ import { Enrichment } from './search-executor/search-enrichers';
6
6
  import type { BuiltInProcName } from '../dataflow/environments/built-in';
7
7
  import type { DataflowInformation } from '../dataflow/info';
8
8
  export type FlowrFilterName = keyof typeof FlowrFilters;
@@ -34,8 +34,25 @@ exports.FlowrFilters = {
34
34
  return e.node.type !== type_1.RType.Argument || e.node.name !== undefined;
35
35
  }),
36
36
  [FlowrFilter.MatchesEnrichment]: ((e, args) => {
37
- const content = JSON.stringify((0, search_enrichers_1.enrichmentContent)(e, args.enrichment));
38
- return content !== undefined && args.test.test(content);
37
+ if (args.enrichment === search_enrichers_1.Enrichment.CallTargets) {
38
+ const c = (0, search_enrichers_1.enrichmentContent)(e, search_enrichers_1.Enrichment.CallTargets);
39
+ if (c === undefined || c.targets === undefined) {
40
+ return false;
41
+ }
42
+ for (const fn of c.targets) {
43
+ if (typeof fn === 'string' && args.test.test(fn)) {
44
+ return true;
45
+ }
46
+ if (typeof fn === 'object' && 'node' in fn && fn.node.type === type_1.RType.FunctionCall && fn.node.named && args.test.test(fn.node.functionName.content)) {
47
+ return true;
48
+ }
49
+ }
50
+ return false;
51
+ }
52
+ else {
53
+ const content = JSON.stringify((0, search_enrichers_1.enrichmentContent)(e, args.enrichment));
54
+ return content !== undefined && args.test.test(content);
55
+ }
39
56
  }),
40
57
  [FlowrFilter.OriginKind]: ((e, args, data) => {
41
58
  const dfgNode = data.dataflow.graph.getVertex(e.node.info.id);
@@ -53,7 +70,7 @@ exports.FlowrFilters = {
53
70
  * Helper to create a regular expression that matches function names, ignoring their package.
54
71
  */
55
72
  function testFunctionsIgnoringPackage(functions) {
56
- return new RegExp(`"(.+:::?)?(${functions.join('|')})"`);
73
+ return new RegExp(`^(.+:::?)?(${functions.join('|')})$`);
57
74
  }
58
75
  /**
59
76
  * @see {@link FlowrFilterCombinator.is}
@@ -185,8 +202,21 @@ function evalTree(tree, data) {
185
202
  * Evaluates the given filter expression against the provided data.
186
203
  */
187
204
  function evalFilter(filter, data) {
188
- /* common lift, this can be improved easily :D */
189
- const tree = FlowrFilterCombinator.is(filter);
190
- return evalTree(tree.get(), data);
205
+ if (filter instanceof FlowrFilterCombinator) {
206
+ return evalTree(filter.get(), data);
207
+ }
208
+ else if (typeof filter === 'string' && exports.ValidFlowrFilters.has(filter)) {
209
+ const handler = exports.FlowrFilters[filter];
210
+ return handler(data.element, undefined, data.data);
211
+ }
212
+ else if (typeof filter === 'object' && 'name' in filter) {
213
+ const handler = exports.FlowrFilters[filter.name];
214
+ const args = ('args' in filter ? filter.args : undefined);
215
+ return handler(data.element, args, data.data);
216
+ }
217
+ else {
218
+ const tree = FlowrFilterCombinator.is(filter);
219
+ return evalTree(tree.get(), data);
220
+ }
191
221
  }
192
222
  //# sourceMappingURL=flowr-search-filters.js.map
@@ -11,7 +11,7 @@ const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id"
11
11
  const cfg_simplification_1 = require("../../control-flow/cfg-simplification");
12
12
  const call_context_query_executor_1 = require("../../queries/catalog/call-context-query/call-context-query-executor");
13
13
  const cfg_kind_1 = require("../../project/cfg-kind");
14
- const identify_link_to_relation_1 = require("../../queries/catalog/call-context-query/identify-link-to-relation");
14
+ const identify_link_to_last_call_relation_1 = require("../../queries/catalog/call-context-query/identify-link-to-last-call-relation");
15
15
  /**
16
16
  * An enumeration that stores the names of the available enrichments that can be applied to a set of search elements.
17
17
  * See {@link FlowrSearchBuilder.with} for more information on how to apply enrichments.
@@ -75,12 +75,13 @@ exports.Enrichments = {
75
75
  enrichElement: async (e, _s, analyzer, args, prev) => {
76
76
  (0, assert_1.guard)(args && args.length, `${Enrichment.LastCall} enrichment requires at least one argument`);
77
77
  const content = prev ?? { linkedIds: [] };
78
- const df = await analyzer.dataflow();
79
- const n = await analyzer.normalize();
80
- const vertex = df.graph.get(e.node.info.id);
81
- if (vertex !== undefined && vertex[0].tag === vertex_1.VertexType.FunctionCall) {
78
+ const df = (await analyzer.dataflow()).graph;
79
+ const vertex = df.getVertex(e.node.info.id);
80
+ if (vertex?.tag === vertex_1.VertexType.FunctionCall) {
81
+ const n = await analyzer.normalize();
82
+ const cfg = (await analyzer.controlflow(undefined, cfg_kind_1.CfgKind.Quick)).graph;
82
83
  for (const arg of args) {
83
- const lastCalls = await (0, identify_link_to_relation_1.identifyLinkToRelation)(vertex[0].id, analyzer, {
84
+ const lastCalls = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelationSync)(vertex.id, cfg, df, {
84
85
  ...arg,
85
86
  callName: (0, call_context_query_executor_1.promoteCallName)(arg.callName),
86
87
  type: 'link-to-last-call',
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.13';
9
+ const version = '2.8.15';
10
10
  /**
11
11
  * Retrieves the current flowR version as a new {@link SemVer} object.
12
12
  */