@eagleoutice/flowr 2.9.14 → 2.10.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/README.md +37 -25
- package/benchmark/stats/stats.d.ts +2 -2
- package/cli/repl/parser/slice-query-parser.d.ts +2 -2
- package/config.d.ts +4 -0
- package/config.js +5 -3
- package/dataflow/environments/identifier.d.ts +4 -0
- package/dataflow/environments/identifier.js +17 -0
- package/dataflow/graph/call-graph.d.ts +4 -7
- package/dataflow/graph/call-graph.js +0 -22
- package/dataflow/graph/df-helper.d.ts +9 -8
- package/dataflow/graph/df-helper.js +9 -2
- package/dataflow/graph/graph-helper.d.ts +9 -4
- package/dataflow/graph/graph-helper.js +26 -3
- package/dataflow/graph/graph.d.ts +13 -2
- package/dataflow/graph/graph.js +26 -4
- package/dataflow/graph/vertex.d.ts +2 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +2 -2
- package/dataflow/internal/process/functions/call/common.js +2 -1
- package/dataflow/internal/process/functions/process-parameter.js +1 -1
- package/documentation/doc-readme.js +2 -1
- package/documentation/wiki-linter.js +5 -0
- package/linter/linter-rules.d.ts +25 -0
- package/linter/linter-rules.js +2 -0
- package/linter/rules/problematic-eval.d.ts +44 -0
- package/linter/rules/problematic-eval.js +83 -0
- package/package.json +7 -7
- package/queries/catalog/df-shape-query/df-shape-query-executor.js +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +3 -3
- package/queries/catalog/does-call-query/does-call-query-executor.js +1 -1
- package/queries/catalog/does-call-query/does-call-query-format.d.ts +2 -2
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +2 -2
- package/queries/catalog/happens-before-query/happens-before-query-format.d.ts +3 -3
- package/queries/catalog/input-sources-query/input-sources-query-executor.d.ts +6 -0
- package/queries/catalog/input-sources-query/input-sources-query-executor.js +66 -0
- package/queries/catalog/input-sources-query/input-sources-query-format.d.ts +36 -0
- package/queries/catalog/input-sources-query/input-sources-query-format.js +63 -0
- package/queries/catalog/input-sources-query/simple-input-classifier.d.ts +90 -0
- package/queries/catalog/input-sources-query/simple-input-classifier.js +308 -0
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.d.ts +2 -2
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.js +1 -1
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +2 -2
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.js +1 -1
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +2 -2
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +2 -2
- package/queries/catalog/location-map-query/location-map-query-executor.js +1 -1
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +2 -2
- package/queries/catalog/origin-query/origin-query-executor.d.ts +2 -2
- package/queries/catalog/origin-query/origin-query-executor.js +1 -1
- package/queries/catalog/origin-query/origin-query-format.d.ts +3 -3
- package/queries/catalog/provenance-query/provenance-query-executor.d.ts +1 -4
- package/queries/catalog/provenance-query/provenance-query-executor.js +3 -6
- package/queries/catalog/provenance-query/provenance-query-format.d.ts +2 -2
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +1 -1
- package/queries/query.d.ts +9 -1
- package/queries/query.js +2 -0
- package/r-bridge/lang-4.x/ast/model/model.d.ts +3 -0
- package/r-bridge/lang-4.x/ast/model/model.js +3 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-access.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-access.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-argument.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-argument.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-binary-op.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-binary-op.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-break.d.ts +15 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-break.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-comment.d.ts +15 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-comment.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.d.ts +21 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.js +16 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-line-directive.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-line-directive.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-logical.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-logical.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-next.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-next.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-number.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-pipe.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-pipe.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-string.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-string.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-symbol.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-symbol.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-unary-op.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-unary-op.js +2 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.d.ts +16 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.js +2 -0
- package/search/search-executor/search-generators.js +1 -1
- package/slicing/criterion/parse.d.ts +11 -10
- package/slicing/criterion/parse.js +9 -8
- package/slicing/static/static-slicer.js +24 -1
- package/util/collections/arrays.d.ts +4 -0
- package/util/collections/arrays.js +7 -0
- package/util/mermaid/dfg.js +2 -1
- package/util/version.js +1 -1
package/dataflow/graph/graph.js
CHANGED
|
@@ -68,18 +68,36 @@ exports.FunctionArgument = {
|
|
|
68
68
|
return arg !== r_function_call_1.EmptyArgument;
|
|
69
69
|
},
|
|
70
70
|
/**
|
|
71
|
-
* Returns the
|
|
71
|
+
* Returns the id of a non-empty argument.
|
|
72
72
|
* @example
|
|
73
73
|
* ```r
|
|
74
|
-
* foo(a=3, 2) # returns the node id of either `
|
|
74
|
+
* foo(a=3, 2) # returns the node id of either `a` or `2`
|
|
75
75
|
* ```
|
|
76
|
+
* @see {@link FunctionArgument.getReference}
|
|
76
77
|
*/
|
|
77
|
-
|
|
78
|
+
getId(arg) {
|
|
78
79
|
if (arg !== r_function_call_1.EmptyArgument) {
|
|
79
80
|
return arg?.nodeId;
|
|
80
81
|
}
|
|
81
82
|
return undefined;
|
|
82
83
|
},
|
|
84
|
+
/**
|
|
85
|
+
* Returns the reference of a non-empty argument.
|
|
86
|
+
* @example
|
|
87
|
+
* ```r
|
|
88
|
+
* foo(a=3, 2) # returns the node id of either `3` or `2`, but skips a
|
|
89
|
+
* ```
|
|
90
|
+
* @see {@link FunctionArgument.getId}
|
|
91
|
+
*/
|
|
92
|
+
getReference(arg) {
|
|
93
|
+
if (arg === r_function_call_1.EmptyArgument) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
else if (arg.name === undefined) {
|
|
97
|
+
return arg.nodeId;
|
|
98
|
+
}
|
|
99
|
+
return arg.valueId;
|
|
100
|
+
},
|
|
83
101
|
/**
|
|
84
102
|
* Checks whether the given argument is a named argument with the specified name.
|
|
85
103
|
* Please note that this only checks whether the name is exactly identical and not whether
|
|
@@ -369,8 +387,9 @@ class DataflowGraph {
|
|
|
369
387
|
/**
|
|
370
388
|
* Marks a vertex in the graph to be a definition
|
|
371
389
|
* @param reference - The reference to the vertex to mark as definition
|
|
390
|
+
* @param sourceIds - The id of the source vertex of the def, if available
|
|
372
391
|
*/
|
|
373
|
-
setDefinitionOfVertex(reference) {
|
|
392
|
+
setDefinitionOfVertex(reference, sourceIds) {
|
|
374
393
|
const vertex = this.getVertex(reference.nodeId);
|
|
375
394
|
(0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${JSON.stringify(reference)} to set reference`);
|
|
376
395
|
if (vertex.tag === vertex_1.VertexType.FunctionDefinition || vertex.tag === vertex_1.VertexType.VariableDefinition) {
|
|
@@ -379,6 +398,9 @@ class DataflowGraph {
|
|
|
379
398
|
else {
|
|
380
399
|
const oldTag = vertex.tag;
|
|
381
400
|
vertex.tag = vertex_1.VertexType.VariableDefinition;
|
|
401
|
+
if (sourceIds) {
|
|
402
|
+
vertex.source = sourceIds;
|
|
403
|
+
}
|
|
382
404
|
this.types.set(oldTag, (this.types.get(oldTag) ?? []).filter(id => id !== reference.nodeId));
|
|
383
405
|
this.types.set(vertex_1.VertexType.VariableDefinition, (this.types.get(vertex_1.VertexType.VariableDefinition) ?? []).concat([reference.nodeId]));
|
|
384
406
|
}
|
|
@@ -123,6 +123,8 @@ export interface DataflowGraphVertexVariableDefinition extends DataflowGraphVert
|
|
|
123
123
|
readonly environment?: undefined;
|
|
124
124
|
/** Indicates whether the variable definition is a *partial* definition (e.g,. in `x[a] <- b`) */
|
|
125
125
|
readonly par?: true;
|
|
126
|
+
/** Points to the source ids of the "value" if there is one, this is more of a best-effort flag and not guaranteed to be there */
|
|
127
|
+
readonly source?: readonly NodeId[];
|
|
126
128
|
}
|
|
127
129
|
/**
|
|
128
130
|
* Arguments required to construct a vertex which represents the definition of a function in the {@link DataflowGraph|dataflow graph}.
|
|
@@ -98,6 +98,7 @@ function processApply(name, args, rootId, data, config) {
|
|
|
98
98
|
if (arg && counterpart !== r_function_call_1.EmptyArgument) {
|
|
99
99
|
return {
|
|
100
100
|
name: counterpart.name?.content,
|
|
101
|
+
valueId: counterpart.value?.info.id,
|
|
101
102
|
cds: data.cds,
|
|
102
103
|
type: identifier_1.ReferenceType.Argument,
|
|
103
104
|
nodeId: arg.entryPoint
|
|
@@ -297,7 +297,7 @@ function checkTargetReferenceType(sourceInfo, fnModes) {
|
|
|
297
297
|
*/
|
|
298
298
|
function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignment, data, assignmentConfig) {
|
|
299
299
|
information.environment = (0, define_1.define)(nodeToDefine, assignmentConfig?.superAssignment, information.environment);
|
|
300
|
-
information.graph.setDefinitionOfVertex(nodeToDefine);
|
|
300
|
+
information.graph.setDefinitionOfVertex(nodeToDefine, sourceIds);
|
|
301
301
|
const nid = nodeToDefine.nodeId;
|
|
302
302
|
if (!assignmentConfig?.quoteSource) {
|
|
303
303
|
for (const sourceId of sourceIds) {
|
|
@@ -60,7 +60,7 @@ function processForLoop(name, args, rootId, data) {
|
|
|
60
60
|
const nameIdShares = (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(nextGraph, writtenIds));
|
|
61
61
|
for (const write of writtenVariable) {
|
|
62
62
|
nextGraph.addEdge(write.nodeId, vector.entryPoint, edge_1.EdgeType.DefinedBy);
|
|
63
|
-
nextGraph.setDefinitionOfVertex(write);
|
|
63
|
+
nextGraph.setDefinitionOfVertex(write, [vector.entryPoint]);
|
|
64
64
|
}
|
|
65
65
|
(0, reference_to_maybe_1.applyCdToReferences)(body.out, cd);
|
|
66
66
|
const outgoing = variable.out.concat(writtenVariable, body.out);
|
|
@@ -99,10 +99,10 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
99
99
|
return r_function_call_1.EmptyArgument;
|
|
100
100
|
}
|
|
101
101
|
else if (!p.name && p.value && p.value.type === type_1.RType.Parameter) {
|
|
102
|
-
return { type: identifier_1.ReferenceType.Argument, cds: data.cds, nodeId: p.value.name.info.id, name: p.value.name.content };
|
|
102
|
+
return { type: identifier_1.ReferenceType.Argument, cds: data.cds, nodeId: p.value.name.info.id, name: p.value.name.content, valueId: p.value.defaultValue?.info.id };
|
|
103
103
|
}
|
|
104
104
|
else if (p.name) {
|
|
105
|
-
return { type: identifier_1.ReferenceType.Argument, cds: data.cds, nodeId: p.name.info.id, name: p.name.content };
|
|
105
|
+
return { type: identifier_1.ReferenceType.Argument, valueId: p.value?.info.id, cds: data.cds, nodeId: p.name.info.id, name: p.name.content };
|
|
106
106
|
}
|
|
107
107
|
else {
|
|
108
108
|
return r_function_call_1.EmptyArgument;
|
|
@@ -69,6 +69,7 @@ function convertFnArgument(arg) {
|
|
|
69
69
|
else {
|
|
70
70
|
return {
|
|
71
71
|
nodeId: arg.info.id,
|
|
72
|
+
valueId: arg.value?.info.id,
|
|
72
73
|
name: arg.name.content,
|
|
73
74
|
cds: undefined,
|
|
74
75
|
type: identifier_1.ReferenceType.Argument
|
|
@@ -134,7 +135,7 @@ function processAllArguments({ functionName, args, data, finalGraph, functionRoo
|
|
|
134
135
|
callArgs.push({ nodeId: processed.entryPoint, cds: undefined, type: identifier_1.ReferenceType.Argument });
|
|
135
136
|
}
|
|
136
137
|
else {
|
|
137
|
-
callArgs.push({ nodeId: processed.entryPoint, name: arg.name.content, cds: undefined, type: identifier_1.ReferenceType.Argument });
|
|
138
|
+
callArgs.push({ nodeId: processed.entryPoint, valueId: arg.value?.info.id, name: arg.name.content, cds: undefined, type: identifier_1.ReferenceType.Argument });
|
|
138
139
|
}
|
|
139
140
|
finalGraph.addEdge(functionRootId, processed.entryPoint, edge_1.EdgeType.Argument);
|
|
140
141
|
}
|
|
@@ -23,7 +23,7 @@ function processFunctionParameter(parameter, data) {
|
|
|
23
23
|
for (const writtenNode of writtenNodes) {
|
|
24
24
|
const wid = writtenNode.nodeId;
|
|
25
25
|
(0, log_1.expensiveTrace)(log_1.log, () => `parameter ${writtenNode.name} (${wid}) is defined at id ${writtenNode.definedAt} with ${defaultValue === undefined ? 'no default value' : ' a default value'}`);
|
|
26
|
-
graph.setDefinitionOfVertex(writtenNode);
|
|
26
|
+
graph.setDefinitionOfVertex(writtenNode, defaultValue?.entryPoint ? [defaultValue?.entryPoint] : []);
|
|
27
27
|
environment = (0, define_1.define)(writtenNode, false, environment);
|
|
28
28
|
if (defaultValue !== undefined) {
|
|
29
29
|
if (r_function_definition_1.RFunctionDefinition.is(parameter.defaultValue)) {
|
|
@@ -282,7 +282,8 @@ We welcome every contribution! Please check out the ${ctx.linkPage('wiki/Onboard
|
|
|
282
282
|
|
|
283
283
|
*flowr* is actively developed by [Florian Sihler](https://eagleoutice.github.io/portfolio/) and (since October 1st 2025) [Oliver Gerstl](https://www.linkedin.com/in/oliver-gerstl) under the
|
|
284
284
|
[GPLv3 License](LICENSE).\\
|
|
285
|
-
It is partially supported by the German Research Foundation (DFG) under the grant [504226141](https://gepris.dfg.de/gepris/projekt/504226141) ("CodeInspector")
|
|
285
|
+
It is partially supported by the German Research Foundation (DFG) under the grant [504226141](https://gepris.dfg.de/gepris/projekt/504226141) ("CodeInspector")
|
|
286
|
+
and received an unrestricted gift from [Posit](https://posit.co/), the open-source data science company.
|
|
286
287
|
|
|
287
288
|
----
|
|
288
289
|
|
|
@@ -123,6 +123,11 @@ df[6, "value"]
|
|
|
123
123
|
rule(knownParser, 'dead-code', 'DeadCodeConfig', 'DEAD_CODE', 'lint-dead-code', 'if(TRUE) 1 else 2', tagTypes);
|
|
124
124
|
rule(knownParser, 'useless-loop', 'UselessLoopConfig', 'USELESS_LOOP', 'lint-useless-loop', 'for(i in c(1)) { print(i) }', tagTypes);
|
|
125
125
|
rule(knownParser, 'stop-call', 'StopWithCallConfig', 'STOP_WITH_CALL_ARG', 'lint-stop-call', 'stop(42)', tagTypes);
|
|
126
|
+
rule(knownParser, 'problematic-eval', 'ProblematicEvalConfig', 'PROBLEMATIC_EVAL', 'lint-problematic-eval', `
|
|
127
|
+
function(x) {
|
|
128
|
+
eval(x)
|
|
129
|
+
}
|
|
130
|
+
`, tagTypes);
|
|
126
131
|
function rule(parser, name, configType, ruleType, testfile, example, types) {
|
|
127
132
|
const rule = linter_rules_1.LintingRules[name];
|
|
128
133
|
const tags = rule.info.tags.toSorted((a, b) => {
|
package/linter/linter-rules.d.ts
CHANGED
|
@@ -281,6 +281,31 @@ export declare const LintingRules: {
|
|
|
281
281
|
};
|
|
282
282
|
};
|
|
283
283
|
};
|
|
284
|
+
readonly 'problematic-eval': {
|
|
285
|
+
readonly createSearch: (config: import("./rules/problematic-eval").ProblematicEvalConfig) => import("../search/flowr-search-builder").FlowrSearchBuilder<"from-query", [], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, 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>[]>>;
|
|
286
|
+
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/problematic-eval").ProblematicEvalConfig, data: {
|
|
287
|
+
normalize: import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
288
|
+
dataflow: import("../dataflow/info").DataflowInformation;
|
|
289
|
+
cfg: import("../control-flow/control-flow-graph").ControlFlowInformation;
|
|
290
|
+
analyzer: import("../project/flowr-analyzer").ReadonlyFlowrAnalysisProvider;
|
|
291
|
+
}) => Promise<{
|
|
292
|
+
results: import("./rules/problematic-eval").ProblematicEvalResult[];
|
|
293
|
+
".meta": import("./rules/problematic-eval").ProblematicEvalMetadata;
|
|
294
|
+
}>;
|
|
295
|
+
readonly prettyPrint: {
|
|
296
|
+
readonly query: (result: import("./rules/problematic-eval").ProblematicEvalResult) => string;
|
|
297
|
+
readonly full: (result: import("./rules/problematic-eval").ProblematicEvalResult) => string;
|
|
298
|
+
};
|
|
299
|
+
readonly info: {
|
|
300
|
+
readonly name: "Problematic eval";
|
|
301
|
+
readonly description: "Detects uses of eval-like functions whose inputs are not statically constant. Prints the computed input-sources for the eval and flags usages that depend on non-constant/trusted inputs.";
|
|
302
|
+
readonly tags: readonly [import("./linter-tags").LintingRuleTag.Security, import("./linter-tags").LintingRuleTag.Smell, import("./linter-tags").LintingRuleTag.Readability, import("./linter-tags").LintingRuleTag.Performance];
|
|
303
|
+
readonly certainty: import("./linter-format").LintingRuleCertainty.BestEffort;
|
|
304
|
+
readonly defaultConfig: {
|
|
305
|
+
readonly considerAsEval: "^eval$";
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
};
|
|
284
309
|
readonly 'stop-call': {
|
|
285
310
|
readonly createSearch: () => import("../search/flowr-search-builder").FlowrSearchBuilder<"get", ["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>[]>>>;
|
|
286
311
|
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("../util/objects").MergeableRecord, { dataflow, analyzer }: {
|
package/linter/linter-rules.js
CHANGED
|
@@ -12,6 +12,7 @@ const dataframe_access_validation_1 = require("./rules/dataframe-access-validati
|
|
|
12
12
|
const useless_loop_1 = require("./rules/useless-loop");
|
|
13
13
|
const network_functions_1 = require("./rules/network-functions");
|
|
14
14
|
const stop_with_call_arg_1 = require("./rules/stop-with-call-arg");
|
|
15
|
+
const problematic_eval_1 = require("./rules/problematic-eval");
|
|
15
16
|
/**
|
|
16
17
|
* The registry of currently supported linting rules.
|
|
17
18
|
* A linting rule can be executed on a dataflow pipeline result using {@link executeLintingRule}.
|
|
@@ -27,6 +28,7 @@ exports.LintingRules = {
|
|
|
27
28
|
'dataframe-access-validation': dataframe_access_validation_1.DATA_FRAME_ACCESS_VALIDATION,
|
|
28
29
|
'dead-code': dead_code_1.DEAD_CODE,
|
|
29
30
|
'useless-loop': useless_loop_1.USELESS_LOOP,
|
|
31
|
+
'problematic-eval': problematic_eval_1.PROBLEMATIC_EVAL,
|
|
30
32
|
'stop-call': stop_with_call_arg_1.STOP_WITH_CALL_ARG
|
|
31
33
|
};
|
|
32
34
|
//# sourceMappingURL=linter-rules.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type LintingResult, LintingRuleCertainty } from '../linter-format';
|
|
2
|
+
import type { MergeableRecord } from '../../util/objects';
|
|
3
|
+
import { SourceLocation } from '../../util/range';
|
|
4
|
+
import { LintingRuleTag } from '../linter-tags';
|
|
5
|
+
import type { InputSources } from '../../queries/catalog/input-sources-query/simple-input-classifier';
|
|
6
|
+
/**
|
|
7
|
+
* Describes a linting result for a problematic eval usage, including the location of the eval call and the computed input sources that lead to it.
|
|
8
|
+
*/
|
|
9
|
+
export interface ProblematicEvalResult extends LintingResult {
|
|
10
|
+
loc: SourceLocation;
|
|
11
|
+
sources: InputSources;
|
|
12
|
+
}
|
|
13
|
+
export interface ProblematicEvalConfig extends MergeableRecord {
|
|
14
|
+
/**
|
|
15
|
+
* All calls that should be considered to be valid eval entry points, this will be interpreted as a Regex!
|
|
16
|
+
*/
|
|
17
|
+
considerAsEval: string;
|
|
18
|
+
}
|
|
19
|
+
export type ProblematicEvalMetadata = MergeableRecord;
|
|
20
|
+
export declare const PROBLEMATIC_EVAL: {
|
|
21
|
+
readonly createSearch: (config: ProblematicEvalConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"from-query", [], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, 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>[]>>;
|
|
22
|
+
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: ProblematicEvalConfig, data: {
|
|
23
|
+
normalize: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
24
|
+
dataflow: import("../../dataflow/info").DataflowInformation;
|
|
25
|
+
cfg: import("../../control-flow/control-flow-graph").ControlFlowInformation;
|
|
26
|
+
analyzer: import("../../project/flowr-analyzer").ReadonlyFlowrAnalysisProvider;
|
|
27
|
+
}) => Promise<{
|
|
28
|
+
results: ProblematicEvalResult[];
|
|
29
|
+
".meta": ProblematicEvalMetadata;
|
|
30
|
+
}>;
|
|
31
|
+
readonly prettyPrint: {
|
|
32
|
+
readonly query: (result: ProblematicEvalResult) => string;
|
|
33
|
+
readonly full: (result: ProblematicEvalResult) => string;
|
|
34
|
+
};
|
|
35
|
+
readonly info: {
|
|
36
|
+
readonly name: "Problematic eval";
|
|
37
|
+
readonly description: "Detects uses of eval-like functions whose inputs are not statically constant. Prints the computed input-sources for the eval and flags usages that depend on non-constant/trusted inputs.";
|
|
38
|
+
readonly tags: readonly [LintingRuleTag.Security, LintingRuleTag.Smell, LintingRuleTag.Readability, LintingRuleTag.Performance];
|
|
39
|
+
readonly certainty: LintingRuleCertainty.BestEffort;
|
|
40
|
+
readonly defaultConfig: {
|
|
41
|
+
readonly considerAsEval: "^eval$";
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROBLEMATIC_EVAL = void 0;
|
|
4
|
+
const linter_format_1 = require("../linter-format");
|
|
5
|
+
const flowr_search_builder_1 = require("../../search/flowr-search-builder");
|
|
6
|
+
const range_1 = require("../../util/range");
|
|
7
|
+
const linter_tags_1 = require("../linter-tags");
|
|
8
|
+
const simple_input_classifier_1 = require("../../queries/catalog/input-sources-query/simple-input-classifier");
|
|
9
|
+
const query_1 = require("../../queries/query");
|
|
10
|
+
const parse_1 = require("../../slicing/criterion/parse");
|
|
11
|
+
/**
|
|
12
|
+
* Format a list of input sources either as a single-line string (inline) or a block.
|
|
13
|
+
* - inline: returns a semicolon-separated single-line summary
|
|
14
|
+
* - block: returns an array of lines (to be joined with newlines by the caller)
|
|
15
|
+
*/
|
|
16
|
+
function formatInputSources(inputs, inline = true) {
|
|
17
|
+
if (!inputs || inputs.length === 0) {
|
|
18
|
+
return inline ? '' : [];
|
|
19
|
+
}
|
|
20
|
+
if (inline) {
|
|
21
|
+
return inputs.map(s => `${s.id} (type: ${Array.isArray(s.type) ? '[' + s.type.join(',') + ']' : s.type}, trace: ${s.trace}${s.cds ? ', cds: [' + s.cds.join(',') + ']' : ''})`).join('; ');
|
|
22
|
+
}
|
|
23
|
+
return inputs.map(s => `- ${s.id}: type=${Array.isArray(s.type) ? '[' + s.type.join(',') + ']' : s.type}, trace=${s.trace}${s.cds ? ', cds=[' + s.cds.join(',') + ']' : ''}`);
|
|
24
|
+
}
|
|
25
|
+
exports.PROBLEMATIC_EVAL = {
|
|
26
|
+
/* create a search that finds calls that look like eval-like functions */
|
|
27
|
+
createSearch: config => flowr_search_builder_1.Q.fromQuery({
|
|
28
|
+
type: 'call-context',
|
|
29
|
+
callName: config.considerAsEval,
|
|
30
|
+
callNameExact: false
|
|
31
|
+
}),
|
|
32
|
+
processSearchResult: async (elements, _config, data) => {
|
|
33
|
+
const results = [];
|
|
34
|
+
for (const element of elements.getElements()) {
|
|
35
|
+
const nid = element.node.info.id;
|
|
36
|
+
// run an input-sources query for this eval-like call
|
|
37
|
+
const criterion = parse_1.SlicingCriterion.fromId(nid);
|
|
38
|
+
const q = { type: 'input-sources', criterion };
|
|
39
|
+
const all = await (0, query_1.executeQueries)({ analyzer: data.analyzer }, [q]);
|
|
40
|
+
const inputSourcesResult = all['input-sources'];
|
|
41
|
+
const sources = inputSourcesResult?.results?.[criterion] ?? [];
|
|
42
|
+
// if any input is not a constant or derived constant, flag it
|
|
43
|
+
const problematic = sources.some(s => Array.isArray(s.type)
|
|
44
|
+
? s.type.some(t => t !== simple_input_classifier_1.InputType.Constant && t !== simple_input_classifier_1.InputType.DerivedConstant)
|
|
45
|
+
: (s.type !== simple_input_classifier_1.InputType.Constant && s.type !== simple_input_classifier_1.InputType.DerivedConstant));
|
|
46
|
+
if (problematic) {
|
|
47
|
+
results.push({
|
|
48
|
+
involvedId: nid,
|
|
49
|
+
certainty: sources.some(s => Array.isArray(s.type) ? s.type.includes(simple_input_classifier_1.InputType.Unknown) : s.type === simple_input_classifier_1.InputType.Unknown) ? linter_format_1.LintingResultCertainty.Uncertain : linter_format_1.LintingResultCertainty.Certain,
|
|
50
|
+
loc: range_1.SourceLocation.fromNode(element.node) ?? range_1.SourceLocation.invalid(),
|
|
51
|
+
sources
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
results,
|
|
57
|
+
'.meta': {}
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
/* helper to format input sources for pretty printing */
|
|
61
|
+
prettyPrint: {
|
|
62
|
+
[linter_format_1.LintingPrettyPrintContext.Query]: result => {
|
|
63
|
+
const inputs = result.sources ?? [];
|
|
64
|
+
const srcStr = formatInputSources(inputs, true);
|
|
65
|
+
return `Use of eval-like function at ${range_1.SourceLocation.format(result.loc)}${srcStr ? `; inputs: ${srcStr}` : ''}`;
|
|
66
|
+
},
|
|
67
|
+
[linter_format_1.LintingPrettyPrintContext.Full]: result => {
|
|
68
|
+
const inputs = result.sources ?? [];
|
|
69
|
+
const srcLines = formatInputSources(inputs, false);
|
|
70
|
+
return `Use of eval-like function at ${range_1.SourceLocation.format(result.loc)} is potentially problematic${srcLines.length ? '\nInputs:\n' + srcLines.join('\n') : ''}`;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
info: {
|
|
74
|
+
name: 'Problematic eval',
|
|
75
|
+
description: 'Detects uses of eval-like functions whose inputs are not statically constant. Prints the computed input-sources for the eval and flags usages that depend on non-constant/trusted inputs.',
|
|
76
|
+
tags: [linter_tags_1.LintingRuleTag.Security, linter_tags_1.LintingRuleTag.Smell, linter_tags_1.LintingRuleTag.Readability, linter_tags_1.LintingRuleTag.Performance],
|
|
77
|
+
certainty: linter_format_1.LintingRuleCertainty.BestEffort,
|
|
78
|
+
defaultConfig: {
|
|
79
|
+
considerAsEval: '^eval$'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=problematic-eval.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eagleoutice/flowr",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.1",
|
|
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": {
|
|
@@ -165,8 +165,8 @@
|
|
|
165
165
|
}
|
|
166
166
|
},
|
|
167
167
|
"devDependencies": {
|
|
168
|
-
"@commitlint/cli": "^
|
|
169
|
-
"@commitlint/config-angular": "^
|
|
168
|
+
"@commitlint/cli": "^20.5.0",
|
|
169
|
+
"@commitlint/config-angular": "^20.5.0",
|
|
170
170
|
"@eagleoutice/eslint-config-flowr": "^1.0.36",
|
|
171
171
|
"@eslint/eslintrc": "^3.3.3",
|
|
172
172
|
"@eslint/js": "^9.39.2",
|
|
@@ -191,11 +191,11 @@
|
|
|
191
191
|
"npm-run-all": "^4.1.5",
|
|
192
192
|
"release-it": "^19.2.3",
|
|
193
193
|
"ts-node": "^10.9.2",
|
|
194
|
-
"typedoc": "^0.
|
|
195
|
-
"typedoc-plugin-missing-exports": "^
|
|
196
|
-
"typedoc-theme-hierarchy": "^
|
|
194
|
+
"typedoc": "^0.28.17",
|
|
195
|
+
"typedoc-plugin-missing-exports": "^4.1.2",
|
|
196
|
+
"typedoc-theme-hierarchy": "^6.0.0",
|
|
197
197
|
"typedoc-umlclass": "^0.10.2",
|
|
198
|
-
"typescript": "^5.
|
|
198
|
+
"typescript": "^5.9.3",
|
|
199
199
|
"vitest": "^3.2.4"
|
|
200
200
|
},
|
|
201
201
|
"dependencies": {
|
|
@@ -39,7 +39,7 @@ async function executeDfShapeQuery({ analyzer }, queries) {
|
|
|
39
39
|
continue;
|
|
40
40
|
}
|
|
41
41
|
try {
|
|
42
|
-
const nodeId = parse_1.
|
|
42
|
+
const nodeId = parse_1.SlicingCriterion.parse(query.criterion, ast.idMap);
|
|
43
43
|
const node = ast.idMap.get(nodeId);
|
|
44
44
|
const value = inference.getAbstractValue(node?.info.id);
|
|
45
45
|
result.set(query.criterion, value);
|
|
@@ -3,17 +3,17 @@ import type { DataFrameDomain } from '../../../abstract-interpretation/data-fram
|
|
|
3
3
|
import type { StateAbstractDomain } from '../../../abstract-interpretation/domains/state-abstract-domain';
|
|
4
4
|
import type { ReplOutput } from '../../../cli/repl/commands/repl-main';
|
|
5
5
|
import type { FlowrConfig } from '../../../config';
|
|
6
|
-
import type {
|
|
6
|
+
import type { SlicingCriterion } from '../../../slicing/criterion/parse';
|
|
7
7
|
import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
|
|
8
8
|
import type { ParsedQueryLine } from '../../query';
|
|
9
9
|
import { executeDfShapeQuery } from './df-shape-query-executor';
|
|
10
10
|
/** Infer the shape of data frames using abstract interpretation. */
|
|
11
11
|
export interface DfShapeQuery extends BaseQueryFormat {
|
|
12
12
|
readonly type: 'df-shape';
|
|
13
|
-
readonly criterion?:
|
|
13
|
+
readonly criterion?: SlicingCriterion;
|
|
14
14
|
}
|
|
15
15
|
export interface DfShapeQueryResult extends BaseQueryResult {
|
|
16
|
-
domains: StateAbstractDomain<DataFrameDomain> | Map<
|
|
16
|
+
domains: StateAbstractDomain<DataFrameDomain> | Map<SlicingCriterion, DataFrameDomain | undefined>;
|
|
17
17
|
}
|
|
18
18
|
declare function dfShapeQueryLineParser(_output: ReplOutput, line: readonly string[], _config: FlowrConfig): ParsedQueryLine<'df-shape'>;
|
|
19
19
|
export declare const DfShapeQueryDefinition: {
|
|
@@ -19,7 +19,7 @@ async function executeDoesCallQuery({ analyzer }, queries) {
|
|
|
19
19
|
log_1.log.warn(`Duplicate query id '${id}' in does-call queries, SKIP.`);
|
|
20
20
|
continue;
|
|
21
21
|
}
|
|
22
|
-
const nodeId = parse_1.
|
|
22
|
+
const nodeId = parse_1.SlicingCriterion.tryParse(query.call, idMap);
|
|
23
23
|
if (!nodeId) {
|
|
24
24
|
results[id] = false;
|
|
25
25
|
continue;
|
|
@@ -3,7 +3,7 @@ import Joi from 'joi';
|
|
|
3
3
|
import type { ParsedQueryLine } from '../../query';
|
|
4
4
|
import { executeDoesCallQuery } from './does-call-query-executor';
|
|
5
5
|
import { type NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
6
|
-
import type {
|
|
6
|
+
import type { SlicingCriterion } from '../../../slicing/criterion/parse';
|
|
7
7
|
import type { ReplOutput } from '../../../cli/repl/commands/repl-main';
|
|
8
8
|
import type { FlowrConfig } from '../../../config';
|
|
9
9
|
interface CallsIdConstraint {
|
|
@@ -30,7 +30,7 @@ export type CallsConstraint = CallsIdConstraint | CallsWithNameConstraint | Call
|
|
|
30
30
|
export interface DoesCallQuery extends BaseQueryFormat {
|
|
31
31
|
readonly type: 'does-call';
|
|
32
32
|
readonly queryId?: string;
|
|
33
|
-
readonly call:
|
|
33
|
+
readonly call: SlicingCriterion;
|
|
34
34
|
readonly calls: CallsConstraint;
|
|
35
35
|
}
|
|
36
36
|
export interface FindAllCallsResult {
|
|
@@ -22,8 +22,8 @@ async function executeHappensBefore({ analyzer }, queries) {
|
|
|
22
22
|
log_1.log.warn('Duplicate happens-before query', query, 'ignoring');
|
|
23
23
|
}
|
|
24
24
|
try {
|
|
25
|
-
const resolvedA = parse_1.
|
|
26
|
-
const resolvedB = parse_1.
|
|
25
|
+
const resolvedA = parse_1.SlicingCriterion.parse(a, ast.idMap);
|
|
26
|
+
const resolvedB = parse_1.SlicingCriterion.parse(b, ast.idMap);
|
|
27
27
|
results[fingerprint] = (0, happens_before_1.happensBefore)(cfg.graph, resolvedA, resolvedB);
|
|
28
28
|
}
|
|
29
29
|
catch (e) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
|
|
2
2
|
import Joi from 'joi';
|
|
3
3
|
import { executeHappensBefore } from './happens-before-query-executor';
|
|
4
|
-
import type {
|
|
4
|
+
import type { SlicingCriterion } from '../../../slicing/criterion/parse';
|
|
5
5
|
import type { Ternary } from '../../../util/logic';
|
|
6
6
|
export interface HappensBeforeQuery extends BaseQueryFormat {
|
|
7
7
|
readonly type: 'happens-before';
|
|
8
|
-
readonly a:
|
|
9
|
-
readonly b:
|
|
8
|
+
readonly a: SlicingCriterion;
|
|
9
|
+
readonly b: SlicingCriterion;
|
|
10
10
|
}
|
|
11
11
|
export interface HappensBeforeQueryResult extends BaseQueryResult {
|
|
12
12
|
readonly results: Record<string, Ternary>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BasicQueryData } from '../../base-query-format';
|
|
2
|
+
import type { InputSourcesQuery, InputSourcesQueryResult } from './input-sources-query-format';
|
|
3
|
+
/**
|
|
4
|
+
* Execute an input sources query
|
|
5
|
+
*/
|
|
6
|
+
export declare function executeInputSourcesQuery({ analyzer }: BasicQueryData, queries: readonly InputSourcesQuery[]): Promise<InputSourcesQueryResult>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeInputSourcesQuery = executeInputSourcesQuery;
|
|
4
|
+
const log_1 = require("../../../util/log");
|
|
5
|
+
const parse_1 = require("../../../slicing/criterion/parse");
|
|
6
|
+
const r_function_definition_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-definition");
|
|
7
|
+
const model_1 = require("../../../r-bridge/lang-4.x/ast/model/model");
|
|
8
|
+
const df_helper_1 = require("../../../dataflow/graph/df-helper");
|
|
9
|
+
const simple_input_classifier_1 = require("./simple-input-classifier");
|
|
10
|
+
const network_functions_1 = require("../../../linter/rules/network-functions");
|
|
11
|
+
const seeded_randomness_1 = require("../../../linter/rules/seeded-randomness");
|
|
12
|
+
const read_functions_1 = require("../dependencies-query/function-info/read-functions");
|
|
13
|
+
/**
|
|
14
|
+
* Execute an input sources query
|
|
15
|
+
*/
|
|
16
|
+
async function executeInputSourcesQuery({ analyzer }, queries) {
|
|
17
|
+
const start = Date.now();
|
|
18
|
+
const results = {};
|
|
19
|
+
const nast = await analyzer.normalize();
|
|
20
|
+
const df = await analyzer.dataflow();
|
|
21
|
+
for (const query of queries) {
|
|
22
|
+
const key = query.criterion;
|
|
23
|
+
if (results[key]) {
|
|
24
|
+
log_1.log.warn(`Duplicate key for input-sources query: ${key}, skipping...`);
|
|
25
|
+
}
|
|
26
|
+
const criterionId = parse_1.SlicingCriterion.tryParse(key, nast.idMap) ?? key;
|
|
27
|
+
const provenanceNode = nast.idMap.get(criterionId);
|
|
28
|
+
const fdef = r_function_definition_1.RFunctionDefinition.rootFunctionDefinition(provenanceNode, nast.idMap);
|
|
29
|
+
const provenance = df_helper_1.Dataflow.provenanceGraph(criterionId, df.graph, fdef ? model_1.RNode.collectAllIds(fdef) : undefined);
|
|
30
|
+
results[key] = (0, simple_input_classifier_1.classifyInput)(criterionId, provenance, {
|
|
31
|
+
networkFns: query.config?.networkFns ?? network_functions_1.NETWORK_FUNCTIONS.info.defaultConfig.fns,
|
|
32
|
+
randomFns: query.config?.randomFns ?? seeded_randomness_1.SEEDED_RANDOMNESS.info.defaultConfig.randomnessConsumers,
|
|
33
|
+
pureFns: query.config?.pureFns ?? ['paste', 'paste0', 'parse', '+', '-', '*',
|
|
34
|
+
'/', '^', '%%', '%/%', '&', '|', '!', '&&', '||',
|
|
35
|
+
'<', '>', '<=', '>=', '==', '!=', ':',
|
|
36
|
+
'abs', 'sign', 'sqrt', 'exp', 'log', 'log10', 'log2',
|
|
37
|
+
'sin', 'cos', 'tan', 'asin', 'acos', 'atan',
|
|
38
|
+
'length', 'nchar', 'dim', 'nrow', 'ncol',
|
|
39
|
+
'c', 'list', 'data.frame',
|
|
40
|
+
'ifelse', 'switch', 'factor', 'as.factor',
|
|
41
|
+
'round', 'floor', 'ceiling', 'trunc',
|
|
42
|
+
'substr', 'substring', 'strsplit',
|
|
43
|
+
'min', 'max', 'range', 'sum', 'prod', 'mean', 'median', 'var', 'sd',
|
|
44
|
+
'head', 'tail', 'seq', 'rep',
|
|
45
|
+
'apply', 'lapply', 'sapply', 'vapply', 'tapply',
|
|
46
|
+
'matrix', 'array', 'substitute', 'quote', 'bquote', 'enquote', 'enexpr', 'enexprs', 'enquo', 'enquos',
|
|
47
|
+
'expression', 'call', 'as.call', 'as.expression',
|
|
48
|
+
'rownames', 'colnames',
|
|
49
|
+
'list.files', 'tolower', 'toupper', 'printf',
|
|
50
|
+
'<-', '->', '=', '<<-', '->>', 'assign', 'get',
|
|
51
|
+
'[', '[[', '$', 'length<-', 'dim<-', 'names<-', 'colnames<-', 'rownames<-',
|
|
52
|
+
'as.character', 'as.numeric', 'as.logical', 'as.list', 'as.data.frame', 'as.matrix', 'as.array',
|
|
53
|
+
'identity', 'invisible', 'return', 'force', 'missing',
|
|
54
|
+
'print', 'cat', 'message', 'warning', 'stop'
|
|
55
|
+
],
|
|
56
|
+
readFileFns: query.config?.readFileFns ?? read_functions_1.ReadFunctions.map(f => f.name)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
'.meta': {
|
|
61
|
+
timing: Date.now() - start
|
|
62
|
+
},
|
|
63
|
+
results
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=input-sources-query-executor.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
|
|
2
|
+
import type { SlicingCriterion } from '../../../slicing/criterion/parse';
|
|
3
|
+
import type { ParsedQueryLine } from '../../query';
|
|
4
|
+
import Joi from 'joi';
|
|
5
|
+
import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
6
|
+
import type { InputClassifierConfig, InputSources } from './simple-input-classifier';
|
|
7
|
+
import type { ReplOutput } from '../../../cli/repl/commands/repl-main';
|
|
8
|
+
import type { FlowrConfig } from '../../../config';
|
|
9
|
+
import { executeInputSourcesQuery } from './input-sources-query-executor';
|
|
10
|
+
export type InputSourcesQueryConfig = InputClassifierConfig;
|
|
11
|
+
/**
|
|
12
|
+
* Calculates provenance for all inputs and their transformations
|
|
13
|
+
* based on the `provenance` of a given function.
|
|
14
|
+
*/
|
|
15
|
+
export interface InputSourcesQuery extends BaseQueryFormat {
|
|
16
|
+
readonly type: 'input-sources';
|
|
17
|
+
/**
|
|
18
|
+
* This takes a criterion (or a numerical id works too)
|
|
19
|
+
* {@link SlicingCriterion.fromId}
|
|
20
|
+
*/
|
|
21
|
+
readonly criterion: SlicingCriterion;
|
|
22
|
+
readonly config?: InputSourcesQueryConfig;
|
|
23
|
+
}
|
|
24
|
+
export interface InputSourcesQueryResult extends BaseQueryResult {
|
|
25
|
+
/** For each query key, a list of classified input sources (each with id and all traces) */
|
|
26
|
+
results: Record<string, InputSources>;
|
|
27
|
+
}
|
|
28
|
+
declare function inputSourcesQueryLineParser(output: ReplOutput, line: readonly string[], _config: FlowrConfig): ParsedQueryLine<'input-sources'>;
|
|
29
|
+
export declare const InputSourcesDefinition: {
|
|
30
|
+
readonly executor: typeof executeInputSourcesQuery;
|
|
31
|
+
readonly asciiSummarizer: (formatter: import("../../../util/text/ansi").OutputFormatter, analyzer: import("../../../project/flowr-analyzer").ReadonlyFlowrAnalysisProvider<import("../../../r-bridge/parser").KnownParser>, queryResults: BaseQueryResult, result: string[]) => Promise<boolean>;
|
|
32
|
+
readonly fromLine: typeof inputSourcesQueryLineParser;
|
|
33
|
+
readonly schema: Joi.ObjectSchema<any>;
|
|
34
|
+
readonly flattenInvolvedNodes: (queryResults: BaseQueryResult) => NodeId[];
|
|
35
|
+
};
|
|
36
|
+
export {};
|