@eagleoutice/flowr 2.2.14 → 2.2.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 (83) hide show
  1. package/README.md +4 -4
  2. package/cli/repl/commands/repl-commands.js +1 -1
  3. package/cli/repl/commands/repl-execute.js +2 -1
  4. package/config.js +1 -1
  5. package/control-flow/basic-cfg-guided-visitor.d.ts +3 -3
  6. package/control-flow/cfg-dead-code.d.ts +4 -0
  7. package/control-flow/cfg-dead-code.js +81 -0
  8. package/control-flow/cfg-simplification.d.ts +17 -6
  9. package/control-flow/cfg-simplification.js +23 -19
  10. package/control-flow/control-flow-graph.d.ts +2 -1
  11. package/control-flow/control-flow-graph.js +1 -0
  12. package/control-flow/dfg-cfg-guided-visitor.d.ts +4 -4
  13. package/control-flow/dfg-cfg-guided-visitor.js +1 -1
  14. package/control-flow/extract-cfg.d.ts +1 -1
  15. package/control-flow/extract-cfg.js +60 -57
  16. package/control-flow/semantic-cfg-guided-visitor.d.ts +17 -8
  17. package/control-flow/semantic-cfg-guided-visitor.js +50 -17
  18. package/control-flow/simple-visitor.d.ts +4 -0
  19. package/control-flow/simple-visitor.js +14 -0
  20. package/control-flow/syntax-cfg-guided-visitor.d.ts +2 -2
  21. package/dataflow/environments/built-in-config.d.ts +1 -0
  22. package/dataflow/environments/built-in.d.ts +10 -1
  23. package/dataflow/environments/built-in.js +9 -3
  24. package/dataflow/environments/default-builtin-config.js +1 -1
  25. package/dataflow/environments/resolve-by-name.d.ts +0 -36
  26. package/dataflow/environments/resolve-by-name.js +0 -240
  27. package/dataflow/eval/resolve/alias-tracking.d.ts +87 -0
  28. package/dataflow/eval/resolve/alias-tracking.js +349 -0
  29. package/dataflow/eval/resolve/resolve.d.ts +34 -0
  30. package/dataflow/eval/resolve/resolve.js +93 -0
  31. package/dataflow/eval/values/general.d.ts +27 -0
  32. package/dataflow/eval/values/general.js +73 -0
  33. package/dataflow/eval/values/intervals/interval-constants.d.ts +4 -0
  34. package/dataflow/eval/values/intervals/interval-constants.js +27 -0
  35. package/dataflow/eval/values/logical/logical-constants.d.ts +7 -0
  36. package/dataflow/eval/values/logical/logical-constants.js +31 -0
  37. package/dataflow/eval/values/r-value.d.ts +58 -0
  38. package/dataflow/eval/values/r-value.js +90 -0
  39. package/dataflow/eval/values/scalar/scalar-consatnts.d.ts +15 -0
  40. package/dataflow/eval/values/scalar/scalar-consatnts.js +35 -0
  41. package/dataflow/eval/values/sets/set-constants.d.ts +7 -0
  42. package/dataflow/eval/values/sets/set-constants.js +34 -0
  43. package/dataflow/eval/values/string/string-constants.d.ts +8 -0
  44. package/dataflow/eval/values/string/string-constants.js +40 -0
  45. package/dataflow/eval/values/vectors/vector-constants.d.ts +14 -0
  46. package/dataflow/eval/values/vectors/vector-constants.js +35 -0
  47. package/dataflow/graph/unknown-replacement.d.ts +11 -0
  48. package/dataflow/graph/unknown-replacement.js +12 -0
  49. package/dataflow/graph/unknown-side-effect.d.ts +7 -0
  50. package/dataflow/graph/unknown-side-effect.js +13 -0
  51. package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +8 -5
  52. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +4 -2
  53. package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +12 -9
  54. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +5 -4
  55. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +9 -2
  56. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +12 -15
  57. package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +23 -0
  58. package/dataflow/internal/process/functions/call/known-call-handling.js +2 -1
  59. package/documentation/doc-util/doc-query.d.ts +6 -3
  60. package/documentation/doc-util/doc-query.js +3 -1
  61. package/documentation/print-cfg-wiki.js +6 -6
  62. package/documentation/print-dataflow-graph-wiki.js +4 -3
  63. package/documentation/print-engines-wiki.js +1 -1
  64. package/documentation/print-query-wiki.js +80 -0
  65. package/linter/rules/1-deprecated-functions.js +1 -1
  66. package/linter/rules/2-file-path-validity.js +1 -1
  67. package/package.json +1 -1
  68. package/queries/catalog/control-flow-query/control-flow-query-executor.d.ts +3 -0
  69. package/queries/catalog/control-flow-query/control-flow-query-executor.js +20 -0
  70. package/queries/catalog/control-flow-query/control-flow-query-format.d.ts +81 -0
  71. package/queries/catalog/control-flow-query/control-flow-query-format.js +34 -0
  72. package/queries/catalog/dependencies-query/dependencies-query-executor.js +33 -32
  73. package/queries/catalog/linter-query/linter-query-format.js +2 -1
  74. package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +3 -3
  75. package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +2 -1
  76. package/queries/catalog/resolve-value-query/resolve-value-query-format.js +2 -22
  77. package/queries/query.d.ts +61 -1
  78. package/queries/query.js +2 -0
  79. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +11 -4
  80. package/search/search-executor/search-enrichers.js +5 -2
  81. package/slicing/criterion/parse.d.ts +8 -0
  82. package/slicing/criterion/parse.js +20 -0
  83. package/util/version.js +1 -1
@@ -2,24 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveByName = resolveByName;
4
4
  exports.resolvesToBuiltInConstant = resolvesToBuiltInConstant;
5
- exports.resolveToConstants = resolveToConstants;
6
- exports.getAliases = getAliases;
7
- exports.trackAliasInEnvironments = trackAliasInEnvironments;
8
- exports.trackAliasesInGraph = trackAliasesInGraph;
9
- exports.resolveValueOfVariable = resolveValueOfVariable;
10
- exports.resolveIdToValue = resolveIdToValue;
11
5
  const environment_1 = require("./environment");
12
6
  const logic_1 = require("../../util/logic");
13
7
  const identifier_1 = require("./identifier");
14
8
  const info_1 = require("../info");
15
- const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
16
- const vertex_1 = require("../graph/vertex");
17
- const config_1 = require("../../config");
18
- const assert_1 = require("../../util/assert");
19
- const type_1 = require("../../r-bridge/lang-4.x/ast/model/type");
20
- const visiting_queue_1 = require("../../slicing/static/visiting-queue");
21
- const fingerprint_1 = require("../../slicing/static/fingerprint");
22
- const edge_1 = require("../graph/edge");
23
9
  const FunctionTargetTypes = identifier_1.ReferenceType.Function | identifier_1.ReferenceType.BuiltInFunction | identifier_1.ReferenceType.Unknown | identifier_1.ReferenceType.Argument | identifier_1.ReferenceType.Parameter;
24
10
  const VariableTargetTypes = identifier_1.ReferenceType.Variable | identifier_1.ReferenceType.Parameter | identifier_1.ReferenceType.Argument | identifier_1.ReferenceType.Unknown;
25
11
  const ConstantTargetTypes = identifier_1.ReferenceType.Constant | identifier_1.ReferenceType.BuiltInConstant | identifier_1.ReferenceType.Unknown;
@@ -96,230 +82,4 @@ function resolvesToBuiltInConstant(name, environment, wantedValue) {
96
82
  return some ? logic_1.Ternary.Maybe : logic_1.Ternary.Never;
97
83
  }
98
84
  }
99
- /** Please use {@link resolveValueOfVariable} */
100
- function resolveToConstants(name, environment) {
101
- if (name === undefined) {
102
- return undefined;
103
- }
104
- const definitions = resolveByName(name, environment, identifier_1.ReferenceType.Constant);
105
- return definitions?.map(def => def.value);
106
- }
107
- const AliasHandler = {
108
- [vertex_1.VertexType.Value]: (sourceId) => [sourceId],
109
- [vertex_1.VertexType.Use]: getUseAlias,
110
- [vertex_1.VertexType.FunctionCall]: () => undefined,
111
- [vertex_1.VertexType.FunctionDefinition]: () => undefined,
112
- [vertex_1.VertexType.VariableDefinition]: () => undefined
113
- };
114
- function getUseAlias(sourceId, dataflow, environment) {
115
- let definitions = [];
116
- // Source is Symbol -> resolve definitions of symbol
117
- const identifier = (0, node_id_1.recoverName)(sourceId, dataflow.idMap);
118
- if (identifier === undefined) {
119
- return undefined;
120
- }
121
- const defs = resolveByName(identifier, environment);
122
- if (defs === undefined) {
123
- return undefined;
124
- }
125
- for (const def of defs) {
126
- // If one definition is not constant (or a variable aliasing a constant)
127
- // we can't say for sure what value the source has
128
- if (def.type === identifier_1.ReferenceType.Variable) {
129
- if (def.value === undefined) {
130
- return undefined;
131
- }
132
- definitions = definitions.concat(def.value);
133
- }
134
- else if (def.type === identifier_1.ReferenceType.Constant || def.type === identifier_1.ReferenceType.BuiltInConstant) {
135
- definitions.push(def.nodeId);
136
- }
137
- else {
138
- return undefined;
139
- }
140
- }
141
- return definitions;
142
- }
143
- function getAliases(sourceIds, dataflow, environment) {
144
- const definitions = new Set();
145
- for (const sourceId of sourceIds) {
146
- const info = dataflow.getVertex(sourceId);
147
- if (info === undefined) {
148
- return undefined;
149
- }
150
- const defs = AliasHandler[info.tag](sourceId, dataflow, environment);
151
- for (const def of defs ?? []) {
152
- definitions.add(def);
153
- }
154
- }
155
- return [...definitions];
156
- }
157
- /** Please use {@link resolveValueOfVariable} */
158
- function trackAliasInEnvironments(identifier, use, idMap) {
159
- if (identifier === undefined) {
160
- return undefined;
161
- }
162
- const defs = resolveByName(identifier, use);
163
- if (defs === undefined) {
164
- return undefined;
165
- }
166
- const values = [];
167
- for (const def of defs) {
168
- if (def.type === identifier_1.ReferenceType.BuiltInConstant) {
169
- values.push(def.value);
170
- }
171
- else if (def.type === identifier_1.ReferenceType.BuiltInFunction) {
172
- // Tracked in #1207
173
- }
174
- else if (def.value !== undefined) {
175
- /* if there is at least one location for which we have no idea, we have to give up for now! */
176
- if (def.value.length === 0) {
177
- return undefined;
178
- }
179
- for (const id of def.value) {
180
- const value = idMap?.get(id)?.content;
181
- if (value !== undefined) {
182
- values.push(value);
183
- }
184
- }
185
- }
186
- }
187
- if (values.length == 0) {
188
- return undefined;
189
- }
190
- return values;
191
- }
192
- function isNestedInLoop(node, ast) {
193
- const parent = node?.info.parent;
194
- if (node === undefined || !parent) {
195
- return false;
196
- }
197
- const parentNode = ast.get(parent);
198
- if (parentNode === undefined) {
199
- return false;
200
- }
201
- if (parentNode.type === type_1.RType.WhileLoop || parentNode.type === type_1.RType.RepeatLoop) {
202
- return true;
203
- }
204
- return isNestedInLoop(parentNode, ast);
205
- }
206
- function trackAliasesInGraph(id, graph, idMap) {
207
- idMap ??= graph.idMap;
208
- (0, assert_1.guard)(idMap !== undefined, 'The ID map is required to get the lineage of a node');
209
- const start = graph.getVertex(id);
210
- (0, assert_1.guard)(start !== undefined, 'Unable to find start for alias tracking');
211
- const queue = new visiting_queue_1.VisitingQueue(25);
212
- const clean = (0, environment_1.initializeCleanEnvironments)();
213
- const cleanFingerprint = (0, fingerprint_1.envFingerprint)(clean);
214
- queue.add(id, clean, cleanFingerprint, false);
215
- let forceBot = false;
216
- const resultIds = [];
217
- while (queue.nonEmpty()) {
218
- const { id, baseEnvironment } = queue.next();
219
- const res = graph.get(id);
220
- if (!res) {
221
- continue;
222
- }
223
- const [vertex, outgoingEdges] = res;
224
- const cds = vertex.cds;
225
- for (const cd of cds ?? []) {
226
- const target = graph.idMap?.get(cd.id);
227
- if (target === undefined) {
228
- continue;
229
- }
230
- if (target.type === type_1.RType.WhileLoop || target.type === type_1.RType.RepeatLoop) {
231
- forceBot = true;
232
- break;
233
- }
234
- }
235
- if (!forceBot && (cds?.length === 0 && isNestedInLoop(idMap.get(id), idMap))) {
236
- forceBot = true;
237
- }
238
- if (forceBot) {
239
- break;
240
- }
241
- if (vertex.tag === vertex_1.VertexType.Value) {
242
- resultIds.push(id);
243
- continue;
244
- }
245
- else if (vertex.tag === vertex_1.VertexType.FunctionDefinition) {
246
- resultIds.push(id);
247
- continue;
248
- }
249
- const isFn = vertex.tag === vertex_1.VertexType.FunctionCall;
250
- // travel all read and defined-by edges
251
- for (const [targetId, edge] of outgoingEdges) {
252
- if (isFn) {
253
- if (edge.types === edge_1.EdgeType.Returns || edge.types === edge_1.EdgeType.DefinedByOnCall || edge.types === edge_1.EdgeType.DefinedBy) {
254
- queue.add(targetId, baseEnvironment, cleanFingerprint, false);
255
- }
256
- continue;
257
- }
258
- // currently, they have to be exact!
259
- if (edge.types === edge_1.EdgeType.Reads || edge.types === edge_1.EdgeType.DefinedBy || edge.types === edge_1.EdgeType.DefinedByOnCall) {
260
- queue.add(targetId, baseEnvironment, cleanFingerprint, false);
261
- }
262
- }
263
- }
264
- if (forceBot || resultIds.length === 0) {
265
- return undefined;
266
- }
267
- const values = [];
268
- for (const id of resultIds) {
269
- const node = idMap.get(id);
270
- if (node !== undefined) {
271
- values.push(node.content);
272
- }
273
- }
274
- return values;
275
- }
276
- /**
277
- * Convenience function using the variable resolver as specified within the configuration file
278
- * In the future we may want to have this set once at the start of the analysis
279
- *
280
- * @see {@link resolveIdToValue} - for a more general approach which "evaluates" a node based on value resolve
281
- */
282
- function resolveValueOfVariable(identifier, environment, idMap) {
283
- const resolve = (0, config_1.getConfig)().solver.variables;
284
- switch (resolve) {
285
- case config_1.VariableResolve.Alias: return trackAliasInEnvironments(identifier, environment, idMap);
286
- case config_1.VariableResolve.Builtin: return resolveToConstants(identifier, environment);
287
- case config_1.VariableResolve.Disabled: return [];
288
- default: (0, assert_1.assertUnreachable)(resolve);
289
- }
290
- }
291
- /**
292
- * Generalized {@link resolveValueOfVariable} function which evaluates a node based on the value resolve
293
- *
294
- * @param id - The node id or node to resolve
295
- * @param environment - The current environment used for name resolution
296
- * @param graph - The graph to resolve in
297
- * @param idMap - The id map to resolve the node if given as an id
298
- * @param full - Whether to track variables
299
- */
300
- function resolveIdToValue(id, { environment, graph, idMap, full }) {
301
- idMap ??= graph?.idMap;
302
- const node = typeof id === 'object' ? id : idMap?.get(id);
303
- if (node === undefined) {
304
- return undefined;
305
- }
306
- switch (node.type) {
307
- case type_1.RType.Symbol:
308
- if (environment) {
309
- return full ? resolveValueOfVariable(node.lexeme, environment, idMap) : undefined;
310
- }
311
- else if (graph && (0, config_1.getConfig)().solver.variables === config_1.VariableResolve.Alias) {
312
- return full ? trackAliasesInGraph(node.info.id, graph, idMap) : undefined;
313
- }
314
- else {
315
- return undefined;
316
- }
317
- case type_1.RType.String:
318
- case type_1.RType.Number:
319
- case type_1.RType.Logical:
320
- return [node.content];
321
- default:
322
- return undefined;
323
- }
324
- }
325
85
  //# sourceMappingURL=resolve-by-name.js.map
@@ -0,0 +1,87 @@
1
+ import type { AstIdMap, RNodeWithParent } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
2
+ import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
3
+ import type { REnvironmentInformation } from '../../environments/environment';
4
+ import type { Identifier } from '../../environments/identifier';
5
+ import type { DataflowGraph } from '../../graph/graph';
6
+ import type { Lift, Value, ValueSet } from '../values/r-value';
7
+ export type ResolveResult = Lift<ValueSet<Value[]>>;
8
+ export interface ResolveInfo {
9
+ /** The current environment used for name resolution */
10
+ environment?: REnvironmentInformation;
11
+ /** The id map to resolve the node if given as an id */
12
+ idMap?: AstIdMap;
13
+ /** The graph to resolve in */
14
+ graph?: DataflowGraph;
15
+ /** Whether to track variables */
16
+ full?: boolean;
17
+ }
18
+ /**
19
+ * Gets the definitions / aliases of a node
20
+ *
21
+ * This function is called by the built-in-assignment processor so that we can
22
+ * track assignments inside the environment. The returned ids are stored in
23
+ * the sourceIds value field of their InGraphIdentifierDefinition. This enables
24
+ * us later, in the {@link trackAliasInEnvironments} function, to get all the
25
+ * aliases of an identifier.
26
+ *
27
+ * @param sourceIds - node ids to get the definitions for
28
+ * @param dataflow - dataflow graph
29
+ * @param environment - environment
30
+ * @returns node id of alias
31
+ */
32
+ export declare function getAliases(sourceIds: readonly NodeId[], dataflow: DataflowGraph, environment: REnvironmentInformation): NodeId[] | undefined;
33
+ /**
34
+ * Evaluates the value of a node in the set domain.
35
+ *
36
+ * resolveIdToValue tries to resolve the value using the data it has been given.
37
+ * If the environment is provided the approximation is more precise, as we can
38
+ * track aliases in the environment.
39
+ * Otherwise, the graph is used to try and resolve the nodes value.
40
+ * If neither is provided the value cannot be resolved.
41
+ *
42
+ * This function is also used by the Resolve Value Query and the Dependency Query
43
+ * to resolve values. For e.g. in the Dependency Query it is used to resolve calls
44
+ * like `lapply(c("a", "b", "c"), library, character.only = TRUE)`
45
+ *
46
+ * @param id - The node id or node to resolve
47
+ * @param environment - The current environment used for name resolution
48
+ * @param graph - The graph to resolve in
49
+ * @param idMap - The id map to resolve the node if given as an id
50
+ * @param full - Whether to track aliases on resolve
51
+ */
52
+ export declare function resolveIdToValue(id: NodeId | RNodeWithParent | undefined, { environment, graph, idMap, full }: ResolveInfo): ResolveResult;
53
+ /**
54
+ * Please use {@link resolveIdToValue}
55
+ *
56
+ * Uses the aliases that were tracked in the environments (by the
57
+ * {@link getAliases} function) to resolve a node to a value.
58
+ *
59
+ *
60
+ * @param identifier - Identifier to resolve
61
+ * @param use - Environment to use
62
+ * @param graph - Dataflow graph
63
+ * @param idMap - id map of Dataflow graph
64
+ * @returns Value of Identifier or Top
65
+ */
66
+ export declare function trackAliasInEnvironments(identifier: Identifier | undefined, use: REnvironmentInformation, graph?: DataflowGraph, idMap?: AstIdMap): ResolveResult;
67
+ /**
68
+ * Please use {@link resolveIdToValue}
69
+ *
70
+ * Tries to resolve the value of a node by traversing the dataflow graph
71
+ *
72
+ * @param id - node to resolve
73
+ * @param graph - dataflow graph
74
+ * @param idMap - idmap of dataflow graph
75
+ * @returns Value of node or Top/Bottom
76
+ */
77
+ export declare function trackAliasesInGraph(id: NodeId, graph: DataflowGraph, idMap?: AstIdMap): ResolveResult;
78
+ /**
79
+ * Please use {@link resolveIdToValue}
80
+ *
81
+ * Resolve an Identifier to a constant, if the identifier is a constant
82
+ *
83
+ * @param name - Identifier to resolve
84
+ * @param environment - Environment to use
85
+ * @returns Value of Constant or Top
86
+ */
87
+ export declare function resolveToConstants(name: Identifier | undefined, environment: REnvironmentInformation): ResolveResult;
@@ -0,0 +1,349 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAliases = getAliases;
4
+ exports.resolveIdToValue = resolveIdToValue;
5
+ exports.trackAliasInEnvironments = trackAliasInEnvironments;
6
+ exports.trackAliasesInGraph = trackAliasesInGraph;
7
+ exports.resolveToConstants = resolveToConstants;
8
+ const config_1 = require("../../../config");
9
+ const node_id_1 = require("../../../r-bridge/lang-4.x/ast/model/processing/node-id");
10
+ const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
11
+ const fingerprint_1 = require("../../../slicing/static/fingerprint");
12
+ const visiting_queue_1 = require("../../../slicing/static/visiting-queue");
13
+ const assert_1 = require("../../../util/assert");
14
+ const environment_1 = require("../../environments/environment");
15
+ const identifier_1 = require("../../environments/identifier");
16
+ const resolve_by_name_1 = require("../../environments/resolve-by-name");
17
+ const edge_1 = require("../../graph/edge");
18
+ const unknown_replacement_1 = require("../../graph/unknown-replacement");
19
+ const unknown_side_effect_1 = require("../../graph/unknown-side-effect");
20
+ const vertex_1 = require("../../graph/vertex");
21
+ const general_1 = require("../values/general");
22
+ const r_value_1 = require("../values/r-value");
23
+ const set_constants_1 = require("../values/sets/set-constants");
24
+ const resolve_1 = require("./resolve");
25
+ const AliasHandler = {
26
+ [vertex_1.VertexType.Value]: (sourceId) => [sourceId],
27
+ [vertex_1.VertexType.Use]: getUseAlias,
28
+ [vertex_1.VertexType.FunctionCall]: getFunctionCallAlias,
29
+ [vertex_1.VertexType.FunctionDefinition]: () => undefined,
30
+ [vertex_1.VertexType.VariableDefinition]: () => undefined
31
+ };
32
+ function getFunctionCallAlias(sourceId, dataflow, environment) {
33
+ const identifier = (0, node_id_1.recoverName)(sourceId, dataflow.idMap);
34
+ if (identifier === undefined) {
35
+ return undefined;
36
+ }
37
+ const defs = (0, resolve_by_name_1.resolveByName)(identifier, environment, identifier_1.ReferenceType.Function);
38
+ if (defs === undefined || defs.length !== 1) {
39
+ return undefined;
40
+ }
41
+ return [sourceId];
42
+ }
43
+ function getUseAlias(sourceId, dataflow, environment) {
44
+ const definitions = [];
45
+ // Source is Symbol -> resolve definitions of symbol
46
+ const identifier = (0, node_id_1.recoverName)(sourceId, dataflow.idMap);
47
+ if (identifier === undefined) {
48
+ return undefined;
49
+ }
50
+ const defs = (0, resolve_by_name_1.resolveByName)(identifier, environment);
51
+ if (defs === undefined) {
52
+ return undefined;
53
+ }
54
+ for (const def of defs) {
55
+ // If one definition is not constant (or a variable aliasing a constant)
56
+ // we can't say for sure what value the source has
57
+ if (def.type === identifier_1.ReferenceType.Variable) {
58
+ if (def.value === undefined) {
59
+ return undefined;
60
+ }
61
+ definitions.push(...def.value);
62
+ }
63
+ else if (def.type === identifier_1.ReferenceType.Constant || def.type === identifier_1.ReferenceType.BuiltInConstant) {
64
+ definitions.push(def.nodeId);
65
+ }
66
+ else {
67
+ return undefined;
68
+ }
69
+ }
70
+ return definitions;
71
+ }
72
+ /**
73
+ * Gets the definitions / aliases of a node
74
+ *
75
+ * This function is called by the built-in-assignment processor so that we can
76
+ * track assignments inside the environment. The returned ids are stored in
77
+ * the sourceIds value field of their InGraphIdentifierDefinition. This enables
78
+ * us later, in the {@link trackAliasInEnvironments} function, to get all the
79
+ * aliases of an identifier.
80
+ *
81
+ * @param sourceIds - node ids to get the definitions for
82
+ * @param dataflow - dataflow graph
83
+ * @param environment - environment
84
+ * @returns node id of alias
85
+ */
86
+ function getAliases(sourceIds, dataflow, environment) {
87
+ const definitions = new Set();
88
+ for (const sourceId of sourceIds) {
89
+ const info = dataflow.getVertex(sourceId);
90
+ if (info === undefined) {
91
+ return undefined;
92
+ }
93
+ const defs = AliasHandler[info.tag](sourceId, dataflow, environment);
94
+ for (const def of defs ?? []) {
95
+ definitions.add(def);
96
+ }
97
+ }
98
+ return [...definitions];
99
+ }
100
+ /**
101
+ * Evaluates the value of a node in the set domain.
102
+ *
103
+ * resolveIdToValue tries to resolve the value using the data it has been given.
104
+ * If the environment is provided the approximation is more precise, as we can
105
+ * track aliases in the environment.
106
+ * Otherwise, the graph is used to try and resolve the nodes value.
107
+ * If neither is provided the value cannot be resolved.
108
+ *
109
+ * This function is also used by the Resolve Value Query and the Dependency Query
110
+ * to resolve values. For e.g. in the Dependency Query it is used to resolve calls
111
+ * like `lapply(c("a", "b", "c"), library, character.only = TRUE)`
112
+ *
113
+ * @param id - The node id or node to resolve
114
+ * @param environment - The current environment used for name resolution
115
+ * @param graph - The graph to resolve in
116
+ * @param idMap - The id map to resolve the node if given as an id
117
+ * @param full - Whether to track aliases on resolve
118
+ */
119
+ function resolveIdToValue(id, { environment, graph, idMap, full = true }) {
120
+ if (id === undefined) {
121
+ return r_value_1.Top;
122
+ }
123
+ idMap ??= graph?.idMap;
124
+ const node = typeof id === 'object' ? id : idMap?.get(id);
125
+ if (node === undefined) {
126
+ return r_value_1.Top;
127
+ }
128
+ switch (node.type) {
129
+ case type_1.RType.Argument:
130
+ case type_1.RType.Symbol:
131
+ if (environment) {
132
+ return full ? trackAliasInEnvironments(node.lexeme, environment, graph, idMap) : r_value_1.Top;
133
+ }
134
+ else if (graph && (0, config_1.getConfig)().solver.variables === config_1.VariableResolve.Alias) {
135
+ return full ? trackAliasesInGraph(node.info.id, graph, idMap) : r_value_1.Top;
136
+ }
137
+ else {
138
+ return r_value_1.Top;
139
+ }
140
+ case type_1.RType.FunctionCall:
141
+ return (0, set_constants_1.setFrom)((0, resolve_1.resolveNode)(node, environment, graph, idMap));
142
+ case type_1.RType.String:
143
+ case type_1.RType.Number:
144
+ case type_1.RType.Logical:
145
+ return (0, set_constants_1.setFrom)((0, general_1.valueFromRNodeConstant)(node));
146
+ default:
147
+ return r_value_1.Top;
148
+ }
149
+ }
150
+ /**
151
+ * Please use {@link resolveIdToValue}
152
+ *
153
+ * Uses the aliases that were tracked in the environments (by the
154
+ * {@link getAliases} function) to resolve a node to a value.
155
+ *
156
+ *
157
+ * @param identifier - Identifier to resolve
158
+ * @param use - Environment to use
159
+ * @param graph - Dataflow graph
160
+ * @param idMap - id map of Dataflow graph
161
+ * @returns Value of Identifier or Top
162
+ */
163
+ function trackAliasInEnvironments(identifier, use, graph, idMap) {
164
+ if (identifier === undefined) {
165
+ return r_value_1.Top;
166
+ }
167
+ const defs = (0, resolve_by_name_1.resolveByName)(identifier, use);
168
+ if (defs === undefined) {
169
+ return r_value_1.Top;
170
+ }
171
+ const values = new Set();
172
+ for (const def of defs) {
173
+ if (def.type === identifier_1.ReferenceType.BuiltInConstant) {
174
+ values.add((0, general_1.valueFromTsValue)(def.value));
175
+ }
176
+ else if (def.type === identifier_1.ReferenceType.BuiltInFunction) {
177
+ // Tracked in #1207
178
+ }
179
+ else if (def.value !== undefined) {
180
+ /* if there is at least one location for which we have no idea, we have to give up for now! */
181
+ if (def.value.length === 0) {
182
+ return r_value_1.Top;
183
+ }
184
+ for (const alias of def.value) {
185
+ const definitionOfAlias = idMap?.get(alias);
186
+ if (definitionOfAlias !== undefined) {
187
+ const value = (0, resolve_1.resolveNode)(definitionOfAlias, use, graph, idMap);
188
+ if ((0, r_value_1.isTop)(value)) {
189
+ return r_value_1.Top;
190
+ }
191
+ values.add(value);
192
+ }
193
+ }
194
+ }
195
+ }
196
+ if (values.size == 0) {
197
+ return r_value_1.Top;
198
+ }
199
+ return (0, set_constants_1.setFrom)(...values);
200
+ }
201
+ (0, unknown_side_effect_1.onUnknownSideEffect)((_graph, env, _id, target) => {
202
+ if (target) {
203
+ return;
204
+ }
205
+ let current = env.current;
206
+ while (current) {
207
+ current.memory.forEach(mem => mem.forEach((def) => {
208
+ if (def.type !== identifier_1.ReferenceType.BuiltInConstant
209
+ && def.type !== identifier_1.ReferenceType.BuiltInFunction
210
+ && def.value !== undefined) {
211
+ def.value.length = 0;
212
+ }
213
+ }));
214
+ current = current.parent;
215
+ }
216
+ });
217
+ (0, unknown_replacement_1.onReplacementOperator)((args) => {
218
+ if (!args.target) {
219
+ return;
220
+ }
221
+ let current = args.env.current;
222
+ while (current) {
223
+ const defs = current.memory.get(args.target);
224
+ defs?.forEach(def => {
225
+ if (def.type !== identifier_1.ReferenceType.BuiltInConstant
226
+ && def.type !== identifier_1.ReferenceType.BuiltInFunction
227
+ && def.value !== undefined) {
228
+ def.value.length = 0;
229
+ }
230
+ });
231
+ current = current.parent;
232
+ }
233
+ });
234
+ function isNestedInLoop(node, ast) {
235
+ const parent = node?.info.parent;
236
+ if (node === undefined || !parent) {
237
+ return false;
238
+ }
239
+ const parentNode = ast.get(parent);
240
+ if (parentNode === undefined) {
241
+ return false;
242
+ }
243
+ if (parentNode.type === type_1.RType.WhileLoop || parentNode.type === type_1.RType.RepeatLoop) {
244
+ return true;
245
+ }
246
+ return isNestedInLoop(parentNode, ast);
247
+ }
248
+ /**
249
+ * Please use {@link resolveIdToValue}
250
+ *
251
+ * Tries to resolve the value of a node by traversing the dataflow graph
252
+ *
253
+ * @param id - node to resolve
254
+ * @param graph - dataflow graph
255
+ * @param idMap - idmap of dataflow graph
256
+ * @returns Value of node or Top/Bottom
257
+ */
258
+ function trackAliasesInGraph(id, graph, idMap) {
259
+ idMap ??= graph.idMap;
260
+ (0, assert_1.guard)(idMap !== undefined, 'The ID map is required to get the lineage of a node');
261
+ const start = graph.getVertex(id);
262
+ (0, assert_1.guard)(start !== undefined, 'Unable to find start for alias tracking');
263
+ const queue = new visiting_queue_1.VisitingQueue(25);
264
+ const clean = (0, environment_1.initializeCleanEnvironments)();
265
+ const cleanFingerprint = (0, fingerprint_1.envFingerprint)(clean);
266
+ queue.add(id, clean, cleanFingerprint, false);
267
+ let forceBot = false;
268
+ const resultIds = [];
269
+ while (queue.nonEmpty()) {
270
+ const { id, baseEnvironment } = queue.next();
271
+ const res = graph.get(id);
272
+ if (!res) {
273
+ continue;
274
+ }
275
+ const [vertex, outgoingEdges] = res;
276
+ const cds = vertex.cds;
277
+ for (const cd of cds ?? []) {
278
+ const target = graph.idMap?.get(cd.id);
279
+ if (target === undefined) {
280
+ continue;
281
+ }
282
+ if (target.type === type_1.RType.WhileLoop || target.type === type_1.RType.RepeatLoop) {
283
+ forceBot = true;
284
+ break;
285
+ }
286
+ }
287
+ if (!forceBot && (cds?.length === 0 && isNestedInLoop(idMap.get(id), idMap))) {
288
+ forceBot = true;
289
+ }
290
+ if (forceBot) {
291
+ break;
292
+ }
293
+ if (vertex.tag === vertex_1.VertexType.Value) {
294
+ resultIds.push(id);
295
+ continue;
296
+ }
297
+ else if (vertex.tag === vertex_1.VertexType.FunctionDefinition) {
298
+ resultIds.push(id);
299
+ continue;
300
+ }
301
+ const isFn = vertex.tag === vertex_1.VertexType.FunctionCall;
302
+ // travel all read and defined-by edges
303
+ for (const [targetId, edge] of outgoingEdges) {
304
+ if (isFn) {
305
+ if (edge.types === edge_1.EdgeType.Returns || edge.types === edge_1.EdgeType.DefinedByOnCall || edge.types === edge_1.EdgeType.DefinedBy) {
306
+ queue.add(targetId, baseEnvironment, cleanFingerprint, false);
307
+ }
308
+ continue;
309
+ }
310
+ // currently, they have to be exact!
311
+ if (edge.types === edge_1.EdgeType.Reads || edge.types === edge_1.EdgeType.DefinedBy || edge.types === edge_1.EdgeType.DefinedByOnCall) {
312
+ queue.add(targetId, baseEnvironment, cleanFingerprint, false);
313
+ }
314
+ }
315
+ }
316
+ if (forceBot || resultIds.length === 0) {
317
+ return r_value_1.Bottom;
318
+ }
319
+ const values = new Set();
320
+ for (const id of resultIds) {
321
+ const node = idMap.get(id);
322
+ if (node !== undefined) {
323
+ values.add((0, general_1.valueFromRNodeConstant)(node));
324
+ }
325
+ }
326
+ return (0, set_constants_1.setFrom)(...values);
327
+ }
328
+ /**
329
+ * Please use {@link resolveIdToValue}
330
+ *
331
+ * Resolve an Identifier to a constant, if the identifier is a constant
332
+ *
333
+ * @param name - Identifier to resolve
334
+ * @param environment - Environment to use
335
+ * @returns Value of Constant or Top
336
+ */
337
+ function resolveToConstants(name, environment) {
338
+ if (name === undefined) {
339
+ return r_value_1.Top;
340
+ }
341
+ const definitions = (0, resolve_by_name_1.resolveByName)(name, environment, identifier_1.ReferenceType.Constant);
342
+ if (definitions === undefined) {
343
+ return r_value_1.Top;
344
+ }
345
+ const values = new Set();
346
+ definitions.forEach(def => values.add((0, general_1.valueFromTsValue)(def.value ?? r_value_1.Top)));
347
+ return (0, set_constants_1.setFrom)(...values);
348
+ }
349
+ //# sourceMappingURL=alias-tracking.js.map