@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.
- package/README.md +4 -4
- package/cli/repl/commands/repl-commands.js +1 -1
- package/cli/repl/commands/repl-execute.js +2 -1
- package/config.js +1 -1
- package/control-flow/basic-cfg-guided-visitor.d.ts +3 -3
- package/control-flow/cfg-dead-code.d.ts +4 -0
- package/control-flow/cfg-dead-code.js +81 -0
- package/control-flow/cfg-simplification.d.ts +17 -6
- package/control-flow/cfg-simplification.js +23 -19
- package/control-flow/control-flow-graph.d.ts +2 -1
- package/control-flow/control-flow-graph.js +1 -0
- package/control-flow/dfg-cfg-guided-visitor.d.ts +4 -4
- package/control-flow/dfg-cfg-guided-visitor.js +1 -1
- package/control-flow/extract-cfg.d.ts +1 -1
- package/control-flow/extract-cfg.js +60 -57
- package/control-flow/semantic-cfg-guided-visitor.d.ts +17 -8
- package/control-flow/semantic-cfg-guided-visitor.js +50 -17
- package/control-flow/simple-visitor.d.ts +4 -0
- package/control-flow/simple-visitor.js +14 -0
- package/control-flow/syntax-cfg-guided-visitor.d.ts +2 -2
- package/dataflow/environments/built-in-config.d.ts +1 -0
- package/dataflow/environments/built-in.d.ts +10 -1
- package/dataflow/environments/built-in.js +9 -3
- package/dataflow/environments/default-builtin-config.js +1 -1
- package/dataflow/environments/resolve-by-name.d.ts +0 -36
- package/dataflow/environments/resolve-by-name.js +0 -240
- package/dataflow/eval/resolve/alias-tracking.d.ts +87 -0
- package/dataflow/eval/resolve/alias-tracking.js +349 -0
- package/dataflow/eval/resolve/resolve.d.ts +34 -0
- package/dataflow/eval/resolve/resolve.js +93 -0
- package/dataflow/eval/values/general.d.ts +27 -0
- package/dataflow/eval/values/general.js +73 -0
- package/dataflow/eval/values/intervals/interval-constants.d.ts +4 -0
- package/dataflow/eval/values/intervals/interval-constants.js +27 -0
- package/dataflow/eval/values/logical/logical-constants.d.ts +7 -0
- package/dataflow/eval/values/logical/logical-constants.js +31 -0
- package/dataflow/eval/values/r-value.d.ts +58 -0
- package/dataflow/eval/values/r-value.js +90 -0
- package/dataflow/eval/values/scalar/scalar-consatnts.d.ts +15 -0
- package/dataflow/eval/values/scalar/scalar-consatnts.js +35 -0
- package/dataflow/eval/values/sets/set-constants.d.ts +7 -0
- package/dataflow/eval/values/sets/set-constants.js +34 -0
- package/dataflow/eval/values/string/string-constants.d.ts +8 -0
- package/dataflow/eval/values/string/string-constants.js +40 -0
- package/dataflow/eval/values/vectors/vector-constants.d.ts +14 -0
- package/dataflow/eval/values/vectors/vector-constants.js +35 -0
- package/dataflow/graph/unknown-replacement.d.ts +11 -0
- package/dataflow/graph/unknown-replacement.js +12 -0
- package/dataflow/graph/unknown-side-effect.d.ts +7 -0
- package/dataflow/graph/unknown-side-effect.js +13 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +8 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +4 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +12 -9
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +5 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +9 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +12 -15
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +23 -0
- package/dataflow/internal/process/functions/call/known-call-handling.js +2 -1
- package/documentation/doc-util/doc-query.d.ts +6 -3
- package/documentation/doc-util/doc-query.js +3 -1
- package/documentation/print-cfg-wiki.js +6 -6
- package/documentation/print-dataflow-graph-wiki.js +4 -3
- package/documentation/print-engines-wiki.js +1 -1
- package/documentation/print-query-wiki.js +80 -0
- package/linter/rules/1-deprecated-functions.js +1 -1
- package/linter/rules/2-file-path-validity.js +1 -1
- package/package.json +1 -1
- package/queries/catalog/control-flow-query/control-flow-query-executor.d.ts +3 -0
- package/queries/catalog/control-flow-query/control-flow-query-executor.js +20 -0
- package/queries/catalog/control-flow-query/control-flow-query-format.d.ts +81 -0
- package/queries/catalog/control-flow-query/control-flow-query-format.js +34 -0
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +33 -32
- package/queries/catalog/linter-query/linter-query-format.js +2 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +3 -3
- package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +2 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +2 -22
- package/queries/query.d.ts +61 -1
- package/queries/query.js +2 -0
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +11 -4
- package/search/search-executor/search-enrichers.js +5 -2
- package/slicing/criterion/parse.d.ts +8 -0
- package/slicing/criterion/parse.js +20 -0
- package/util/version.js +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.onReplacementOperator = onReplacementOperator;
|
|
4
|
+
exports.handleReplacementOperator = handleReplacementOperator;
|
|
5
|
+
const handlers = [];
|
|
6
|
+
function onReplacementOperator(handler) {
|
|
7
|
+
handlers.push(handler);
|
|
8
|
+
}
|
|
9
|
+
function handleReplacementOperator(args) {
|
|
10
|
+
handlers.forEach(handler => handler(args));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=unknown-replacement.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LinkTo } from '../../queries/catalog/call-context-query/call-context-query-format';
|
|
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 { DataflowGraph } from './graph';
|
|
5
|
+
export type UnknownSideEffectHandler = (graph: DataflowGraph, env: REnvironmentInformation, id: NodeId, target?: LinkTo<RegExp | string>) => void;
|
|
6
|
+
export declare function onUnknownSideEffect(handler: UnknownSideEffectHandler): void;
|
|
7
|
+
export declare function handleUnknownSideEffect(graph: DataflowGraph, env: REnvironmentInformation, id: NodeId, target?: LinkTo<RegExp | string>): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.onUnknownSideEffect = onUnknownSideEffect;
|
|
4
|
+
exports.handleUnknownSideEffect = handleUnknownSideEffect;
|
|
5
|
+
const handlers = [];
|
|
6
|
+
function onUnknownSideEffect(handler) {
|
|
7
|
+
handlers.push(handler);
|
|
8
|
+
}
|
|
9
|
+
function handleUnknownSideEffect(graph, env, id, target) {
|
|
10
|
+
graph.markIdForUnknownSideEffects(id, target);
|
|
11
|
+
handlers.forEach(handler => handler(graph, env, id, target));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=unknown-side-effect.js.map
|
|
@@ -10,7 +10,10 @@ const edge_1 = require("../../../../../graph/edge");
|
|
|
10
10
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
11
11
|
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
12
12
|
const unnamed_call_handling_1 = require("../unnamed-call-handling");
|
|
13
|
+
const general_1 = require("../../../../../eval/values/general");
|
|
14
|
+
const r_value_1 = require("../../../../../eval/values/r-value");
|
|
13
15
|
const log_1 = require("../../../../../../util/log");
|
|
16
|
+
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
14
17
|
function processApply(name, args, rootId, data, config) {
|
|
15
18
|
const { indexOfFunction = 1, nameOfFunctionArgument, unquoteFunction, resolveInEnvironment, resolveValue } = config;
|
|
16
19
|
/* as the length is one-based and the argument filter mapping is zero-based, we do not have to subtract 1 */
|
|
@@ -54,9 +57,9 @@ function processApply(name, args, rootId, data, config) {
|
|
|
54
57
|
else if (val.type === type_1.RType.Symbol) {
|
|
55
58
|
functionId = val.info.id;
|
|
56
59
|
if (resolveValue) {
|
|
57
|
-
const resolved = (0,
|
|
58
|
-
if (resolved?.length === 1 &&
|
|
59
|
-
functionName = resolved[0];
|
|
60
|
+
const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(val.info.id, { environment: data.environment, idMap: data.completeAst.idMap }));
|
|
61
|
+
if (resolved?.elements.length === 1 && resolved.elements[0].type === 'string') {
|
|
62
|
+
functionName = (0, r_value_1.isValue)(resolved.elements[0].value) ? resolved.elements[0].value.str : undefined;
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
else {
|
|
@@ -72,7 +75,7 @@ function processApply(name, args, rootId, data, config) {
|
|
|
72
75
|
logger_1.dataflowLogger.warn(`Expected symbol or string as function argument at index ${index}, but got ${JSON.stringify(val)} instead.`);
|
|
73
76
|
return information;
|
|
74
77
|
}
|
|
75
|
-
const allOtherArguments = processedArguments.
|
|
78
|
+
const allOtherArguments = processedArguments.map((arg, i) => {
|
|
76
79
|
const counterpart = args[i];
|
|
77
80
|
if (arg && counterpart !== r_function_call_1.EmptyArgument) {
|
|
78
81
|
return {
|
|
@@ -85,7 +88,7 @@ function processApply(name, args, rootId, data, config) {
|
|
|
85
88
|
else {
|
|
86
89
|
return r_function_call_1.EmptyArgument;
|
|
87
90
|
}
|
|
88
|
-
});
|
|
91
|
+
}).filter((_, i) => i !== index);
|
|
89
92
|
if (anonymous) {
|
|
90
93
|
const rootFnId = functionId;
|
|
91
94
|
functionId = 'anon-' + rootFnId;
|
|
@@ -20,6 +20,8 @@ const containers_1 = require("../../../../../../util/containers");
|
|
|
20
20
|
const config_1 = require("../../../../../../config");
|
|
21
21
|
const named_call_handling_1 = require("../named-call-handling");
|
|
22
22
|
const built_in_1 = require("../../../../../environments/built-in");
|
|
23
|
+
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
|
|
24
|
+
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
23
25
|
function toReplacementSymbol(target, prefix, superAssignment) {
|
|
24
26
|
return {
|
|
25
27
|
type: type_1.RType.Symbol,
|
|
@@ -142,7 +144,7 @@ args, rootId, data, config) {
|
|
|
142
144
|
name, args: effectiveArgs, rootId, data, forceArgs: config.forceArgs,
|
|
143
145
|
origin: 'builtin:assignment'
|
|
144
146
|
}).information;
|
|
145
|
-
info.graph.
|
|
147
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(info.graph, info.environment, rootId);
|
|
146
148
|
return info;
|
|
147
149
|
}
|
|
148
150
|
function extractSourceAndTarget(args) {
|
|
@@ -269,7 +271,7 @@ function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignme
|
|
|
269
271
|
function processAssignmentToSymbol(config) {
|
|
270
272
|
const { nameOfAssignmentFunction, source, args: [targetArg, sourceArg], target, rootId, data, information, makeMaybe, quoteSource } = config;
|
|
271
273
|
const referenceType = checkTargetReferenceType(source, sourceArg);
|
|
272
|
-
const aliases = (0,
|
|
274
|
+
const aliases = (0, alias_tracking_1.getAliases)([source.info.id], information.graph, information.environment);
|
|
273
275
|
const writeNodes = produceWrittenNodes(rootId, targetArg, referenceType, data, makeMaybe ?? false, aliases);
|
|
274
276
|
if (writeNodes.length !== 1 && log_1.log.settings.minLevel <= 4 /* LogLevel.Warn */) {
|
|
275
277
|
log_1.log.warn(`Unexpected write number in assignment: ${JSON.stringify(writeNodes)}`);
|
|
@@ -12,9 +12,12 @@ const log_1 = require("../../../../../../util/log");
|
|
|
12
12
|
const built_in_source_1 = require("./built-in-source");
|
|
13
13
|
const edge_1 = require("../../../../../graph/edge");
|
|
14
14
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
15
|
-
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
16
15
|
const append_1 = require("../../../../../environments/append");
|
|
17
16
|
const assert_1 = require("../../../../../../util/assert");
|
|
17
|
+
const general_1 = require("../../../../../eval/values/general");
|
|
18
|
+
const string_constants_1 = require("../../../../../eval/values/string/string-constants");
|
|
19
|
+
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
|
|
20
|
+
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
18
21
|
const arrays_1 = require("../../../../../../util/collections/arrays");
|
|
19
22
|
function processEvalCall(name, args, rootId, data, config) {
|
|
20
23
|
if (args.length !== 1 || args[0] === r_function_call_1.EmptyArgument || !args[0].value) {
|
|
@@ -30,7 +33,7 @@ function processEvalCall(name, args, rootId, data, config) {
|
|
|
30
33
|
}
|
|
31
34
|
if (!(0, config_1.getConfig)().solver.evalStrings) {
|
|
32
35
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Skipping eval call ${JSON.stringify(evalArgument)} (disabled in config file)`);
|
|
33
|
-
information.graph.
|
|
36
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
|
|
34
37
|
return information;
|
|
35
38
|
}
|
|
36
39
|
const code = resolveEvalToCode(evalArgument.value, data.environment, data.completeAst.idMap);
|
|
@@ -62,7 +65,7 @@ function processEvalCall(name, args, rootId, data, config) {
|
|
|
62
65
|
};
|
|
63
66
|
}
|
|
64
67
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(args)} for eval is currently not supported, skipping`);
|
|
65
|
-
information.graph.
|
|
68
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
|
|
66
69
|
return information;
|
|
67
70
|
}
|
|
68
71
|
function resolveEvalToCode(evalArgument, env, idMap) {
|
|
@@ -77,9 +80,9 @@ function resolveEvalToCode(evalArgument, env, idMap) {
|
|
|
77
80
|
return [arg.value.content.str];
|
|
78
81
|
}
|
|
79
82
|
else if (arg.value?.type === type_1.RType.Symbol) {
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
82
|
-
return
|
|
83
|
+
const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(arg.value.info.id, { environment: env, idMap: idMap }));
|
|
84
|
+
if (resolved) {
|
|
85
|
+
return (0, string_constants_1.collectStrings)(resolved.elements);
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
else if (arg.value?.type === type_1.RType.FunctionCall && arg.value.named && ['paste', 'paste0'].includes(arg.value.functionName.content)) {
|
|
@@ -104,9 +107,9 @@ function getAsString(val, env, idMap) {
|
|
|
104
107
|
return [val.content.str];
|
|
105
108
|
}
|
|
106
109
|
else if (val.type === type_1.RType.Symbol) {
|
|
107
|
-
const resolved = (0,
|
|
108
|
-
if (resolved
|
|
109
|
-
return
|
|
110
|
+
const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(val.info.id, { environment: env, idMap: idMap }));
|
|
111
|
+
if (resolved) {
|
|
112
|
+
return (0, string_constants_1.collectStrings)(resolved.elements);
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
return undefined;
|
|
@@ -7,11 +7,12 @@ const known_call_handling_1 = require("../known-call-handling");
|
|
|
7
7
|
const common_1 = require("../common");
|
|
8
8
|
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
9
9
|
const logger_1 = require("../../../../../logger");
|
|
10
|
-
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
11
10
|
const edge_1 = require("../../../../../graph/edge");
|
|
12
11
|
const append_1 = require("../../../../../environments/append");
|
|
13
12
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
14
13
|
const environment_1 = require("../../../../../environments/environment");
|
|
14
|
+
const general_1 = require("../../../../../eval/values/general");
|
|
15
|
+
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
15
16
|
function processIfThenElse(name, args, rootId, data) {
|
|
16
17
|
if (args.length !== 2 && args.length !== 3) {
|
|
17
18
|
logger_1.dataflowLogger.warn(`If-then-else ${name.content} has something different from 2 or 3 arguments, skipping`);
|
|
@@ -33,9 +34,9 @@ function processIfThenElse(name, args, rootId, data) {
|
|
|
33
34
|
let then;
|
|
34
35
|
let makeThenMaybe = false;
|
|
35
36
|
// we should defer this to the abstract interpretation
|
|
36
|
-
const values = (0,
|
|
37
|
-
const conditionIsAlwaysFalse = values?.every(d => d === false) ?? false;
|
|
38
|
-
const conditionIsAlwaysTrue = values?.every(d => d === true) ?? false;
|
|
37
|
+
const values = (0, alias_tracking_1.resolveIdToValue)(condArg?.info.id, { environment: data.environment, idMap: data.completeAst.idMap });
|
|
38
|
+
const conditionIsAlwaysFalse = (0, general_1.valueSetGuard)(values)?.elements.every(d => d.type === 'logical' && d.value === false) ?? false;
|
|
39
|
+
const conditionIsAlwaysTrue = (0, general_1.valueSetGuard)(values)?.elements.every(d => d.type === 'logical' && d.value === true) ?? false;
|
|
39
40
|
if (!conditionIsAlwaysFalse) {
|
|
40
41
|
then = (0, processor_1.processDataflowFor)(thenArg, data);
|
|
41
42
|
if (then.entryPoint) {
|
|
@@ -17,6 +17,7 @@ const unpack_argument_1 = require("../argument/unpack-argument");
|
|
|
17
17
|
const built_in_access_1 = require("./built-in-access");
|
|
18
18
|
const built_in_1 = require("../../../../../environments/built-in");
|
|
19
19
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
20
|
+
const unknown_replacement_1 = require("../../../../../graph/unknown-replacement");
|
|
20
21
|
function processReplacementFunction(name,
|
|
21
22
|
/** The last one has to be the value */
|
|
22
23
|
args, rootId, data, config) {
|
|
@@ -60,9 +61,15 @@ args, rootId, data, config) {
|
|
|
60
61
|
origin: 'builtin:replacement',
|
|
61
62
|
link: config.assignRootId ? { origin: [config.assignRootId] } : undefined
|
|
62
63
|
});
|
|
63
|
-
const firstArg = (0, unpack_argument_1.unpackArgument)(args[0])
|
|
64
|
+
const firstArg = (0, unpack_argument_1.unpackArgument)(args[0]);
|
|
65
|
+
(0, unknown_replacement_1.handleReplacementOperator)({
|
|
66
|
+
operator: name.content,
|
|
67
|
+
target: firstArg?.lexeme,
|
|
68
|
+
env: res.environment,
|
|
69
|
+
id: rootId
|
|
70
|
+
});
|
|
64
71
|
if (firstArg) {
|
|
65
|
-
res.graph.addEdge(firstArg, rootId, edge_1.EdgeType.DefinedBy | edge_1.EdgeType.Reads);
|
|
72
|
+
res.graph.addEdge(firstArg.info.id, rootId, edge_1.EdgeType.DefinedBy | edge_1.EdgeType.Reads);
|
|
66
73
|
}
|
|
67
74
|
/* a replacement reads all of its call args as well, at least as far as I am aware of */
|
|
68
75
|
for (const arg of callArgs) {
|
|
@@ -23,9 +23,12 @@ const log_1 = require("../../../../../../util/log");
|
|
|
23
23
|
const fs_1 = __importDefault(require("fs"));
|
|
24
24
|
const parser_1 = require("../../../../../../r-bridge/lang-4.x/ast/parser/json/parser");
|
|
25
25
|
const shell_executor_1 = require("../../../../../../r-bridge/shell-executor");
|
|
26
|
-
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
27
26
|
const assert_1 = require("../../../../../../util/assert");
|
|
28
27
|
const path_1 = __importDefault(require("path"));
|
|
28
|
+
const general_1 = require("../../../../../eval/values/general");
|
|
29
|
+
const r_value_1 = require("../../../../../eval/values/r-value");
|
|
30
|
+
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
|
|
31
|
+
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
29
32
|
let sourceProvider = (0, retriever_1.requestProviderFromFile)();
|
|
30
33
|
function setSourceProvider(provider) {
|
|
31
34
|
sourceProvider = provider;
|
|
@@ -128,7 +131,7 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
128
131
|
const sourceFileArgument = args[0];
|
|
129
132
|
if (!config.forceFollow && (0, config_1.getConfig)().ignoreSourceCalls) {
|
|
130
133
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Skipping source call ${JSON.stringify(sourceFileArgument)} (disabled in config file)`);
|
|
131
|
-
information.graph.
|
|
134
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
|
|
132
135
|
return information;
|
|
133
136
|
}
|
|
134
137
|
let sourceFile;
|
|
@@ -136,14 +139,8 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
136
139
|
sourceFile = [(0, retriever_1.removeRQuotes)(sourceFileArgument.lexeme)];
|
|
137
140
|
}
|
|
138
141
|
else if (sourceFileArgument !== r_function_call_1.EmptyArgument) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return x.str;
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
return undefined;
|
|
145
|
-
}
|
|
146
|
-
}).filter(assert_1.isNotUndefined);
|
|
142
|
+
const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(sourceFileArgument.info.id, { environment: data.environment, idMap: data.completeAst.idMap }));
|
|
143
|
+
sourceFile = resolved?.elements.map(r => r.type === 'string' && (0, r_value_1.isValue)(r.value) ? r.value.str : undefined).filter(assert_1.isNotUndefined);
|
|
147
144
|
}
|
|
148
145
|
if (sourceFile && sourceFile.length === 1) {
|
|
149
146
|
const path = (0, retriever_1.removeRQuotes)(sourceFile[0]);
|
|
@@ -158,14 +155,14 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
158
155
|
const findCount = data.referenceChain.filter(e => e.request === request.request && e.content === request.content).length;
|
|
159
156
|
if (findCount > limit) {
|
|
160
157
|
logger_1.dataflowLogger.warn(`Found cycle (>=${limit + 1}) in dataflow analysis for ${JSON.stringify(request)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
|
|
161
|
-
information.graph.
|
|
158
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
|
|
162
159
|
return information;
|
|
163
160
|
}
|
|
164
161
|
return sourceRequest(rootId, request, data, information, (0, decorate_1.sourcedDeterministicCountingIdGenerator)((findCount > 0 ? findCount + '::' : '') + path, name.location));
|
|
165
162
|
}
|
|
166
163
|
}
|
|
167
164
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(sourceFile)} for source is currently not supported, skipping`);
|
|
168
|
-
information.graph.
|
|
165
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
|
|
169
166
|
return information;
|
|
170
167
|
}
|
|
171
168
|
function sourceRequest(rootId, request, data, information, getId) {
|
|
@@ -173,7 +170,7 @@ function sourceRequest(rootId, request, data, information, getId) {
|
|
|
173
170
|
/* check if the file exists and if not, fail */
|
|
174
171
|
if (!fs_1.default.existsSync(request.content)) {
|
|
175
172
|
logger_1.dataflowLogger.warn(`Failed to analyze sourced file ${JSON.stringify(request)}: file does not exist`);
|
|
176
|
-
information.graph.
|
|
173
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
|
|
177
174
|
return information;
|
|
178
175
|
}
|
|
179
176
|
}
|
|
@@ -195,7 +192,7 @@ function sourceRequest(rootId, request, data, information, getId) {
|
|
|
195
192
|
catch (e) {
|
|
196
193
|
logger_1.dataflowLogger.error(`Failed to analyze sourced file ${JSON.stringify(request)}, skipping: ${e.message}`);
|
|
197
194
|
logger_1.dataflowLogger.error(e.stack);
|
|
198
|
-
information.graph.
|
|
195
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
|
|
199
196
|
return information;
|
|
200
197
|
}
|
|
201
198
|
// take the entry point as well as all the written references, and give them a control dependency to the source call to show that they are conditional
|
|
@@ -229,7 +226,7 @@ function standaloneSourceFile(inputRequest, data, uniqueSourceId, information) {
|
|
|
229
226
|
// check if the sourced file has already been dataflow analyzed, and if so, skip it
|
|
230
227
|
if (data.referenceChain.find(e => e.request === request.request && e.content === request.content)) {
|
|
231
228
|
logger_1.dataflowLogger.info(`Found loop in dataflow analysis for ${JSON.stringify(request)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
|
|
232
|
-
information.graph.
|
|
229
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, uniqueSourceId);
|
|
233
230
|
return information;
|
|
234
231
|
}
|
|
235
232
|
return sourceRequest(uniqueSourceId, request, {
|
|
@@ -11,6 +11,8 @@ const logger_1 = require("../../../../../logger");
|
|
|
11
11
|
const environment_1 = require("../../../../../environments/environment");
|
|
12
12
|
const edge_1 = require("../../../../../graph/edge");
|
|
13
13
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
14
|
+
const general_1 = require("../../../../../eval/values/general");
|
|
15
|
+
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
14
16
|
function processWhileLoop(name, args, rootId, data) {
|
|
15
17
|
if (args.length !== 2 || args[1] === r_function_call_1.EmptyArgument) {
|
|
16
18
|
logger_1.dataflowLogger.warn(`While-Loop ${name.content} does not have 2 arguments, skipping`);
|
|
@@ -21,6 +23,13 @@ function processWhileLoop(name, args, rootId, data) {
|
|
|
21
23
|
logger_1.dataflowLogger.warn(`While-Loop ${name.content} has empty arguments in ${JSON.stringify(args)}, skipping`);
|
|
22
24
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
|
|
23
25
|
}
|
|
26
|
+
// we should defer this to the abstract interpretation
|
|
27
|
+
const values = (0, alias_tracking_1.resolveIdToValue)(unpackedArgs[0]?.info.id, { environment: data.environment, idMap: data.completeAst.idMap });
|
|
28
|
+
const conditionIsAlwaysFalse = (0, general_1.valueSetGuard)(values)?.elements.every(d => d.type === 'logical' && d.value === false) ?? false;
|
|
29
|
+
//We don't care about the body if it never executes
|
|
30
|
+
if (conditionIsAlwaysFalse) {
|
|
31
|
+
unpackedArgs.pop();
|
|
32
|
+
}
|
|
24
33
|
/* we inject the cf-dependency of the while-loop after the condition */
|
|
25
34
|
const { information, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({
|
|
26
35
|
name,
|
|
@@ -36,10 +45,24 @@ function processWhileLoop(name, args, rootId, data) {
|
|
|
36
45
|
}, origin: 'builtin:while-loop'
|
|
37
46
|
});
|
|
38
47
|
const [condition, body] = processedArguments;
|
|
48
|
+
// If the condition is always false, we don't include the body
|
|
49
|
+
if (condition !== undefined && conditionIsAlwaysFalse) {
|
|
50
|
+
information.graph.addEdge(name.info.id, condition.entryPoint, edge_1.EdgeType.Reads);
|
|
51
|
+
return {
|
|
52
|
+
unknownReferences: [],
|
|
53
|
+
in: [{ nodeId: name.info.id, name: name.lexeme, controlDependencies: data.controlDependencies, type: identifier_1.ReferenceType.Function }],
|
|
54
|
+
out: condition.out,
|
|
55
|
+
entryPoint: name.info.id,
|
|
56
|
+
exitPoints: [],
|
|
57
|
+
graph: information.graph,
|
|
58
|
+
environment: information.environment
|
|
59
|
+
};
|
|
60
|
+
}
|
|
39
61
|
(0, assert_1.guard)(condition !== undefined && body !== undefined, () => `While-Loop ${name.content} has no condition or body, impossible!`);
|
|
40
62
|
const originalDependency = data.controlDependencies;
|
|
41
63
|
if ((0, info_1.alwaysExits)(condition)) {
|
|
42
64
|
logger_1.dataflowLogger.warn(`While-Loop ${rootId} forces exit in condition, skipping rest`);
|
|
65
|
+
information.graph.addEdge(name.info.id, condition.entryPoint, edge_1.EdgeType.Reads);
|
|
43
66
|
return condition;
|
|
44
67
|
}
|
|
45
68
|
const remainingInputs = (0, linker_1.linkInputs)([
|
|
@@ -10,6 +10,7 @@ const edge_1 = require("../../../../graph/edge");
|
|
|
10
10
|
const logger_1 = require("../../../../logger");
|
|
11
11
|
const vertex_1 = require("../../../../graph/vertex");
|
|
12
12
|
const log_1 = require("../../../../../util/log");
|
|
13
|
+
const unknown_side_effect_1 = require("../../../../graph/unknown-side-effect");
|
|
13
14
|
function markNonStandardEvaluationEdges(markAsNSE, callArgs, finalGraph, rootId) {
|
|
14
15
|
for (const nse of markAsNSE) {
|
|
15
16
|
if (nse < callArgs.length) {
|
|
@@ -46,7 +47,7 @@ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = fal
|
|
|
46
47
|
origin: origin === 'default' ? ['function'] : [origin]
|
|
47
48
|
});
|
|
48
49
|
if (hasUnknownSideEffect) {
|
|
49
|
-
finalGraph.
|
|
50
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(finalGraph, data.environment, rootId);
|
|
50
51
|
}
|
|
51
52
|
const inIds = remainingReadInArgs;
|
|
52
53
|
const fnRef = { nodeId: rootId, name: functionCallName, controlDependencies: data.controlDependencies, type: identifier_1.ReferenceType.Function };
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import type { RShell } from '../../r-bridge/shell';
|
|
2
|
-
import type { Queries, SupportedQueryTypes } from '../../queries/query';
|
|
2
|
+
import type { Queries, QueryResults, SupportedQueryTypes } from '../../queries/query';
|
|
3
|
+
import { DEFAULT_DATAFLOW_PIPELINE } from '../../core/steps/pipeline/default-pipelines';
|
|
3
4
|
import type { SupportedVirtualQueryTypes } from '../../queries/virtual-query/virtual-queries';
|
|
4
5
|
import type { VirtualCompoundConstraint } from '../../queries/virtual-query/compound-query';
|
|
5
|
-
|
|
6
|
+
import type { PipelineOutput } from '../../core/steps/pipeline/pipeline';
|
|
7
|
+
export interface ShowQueryOptions<Base extends SupportedQueryTypes> {
|
|
6
8
|
readonly showCode?: boolean;
|
|
7
9
|
readonly collapseResult?: boolean;
|
|
8
10
|
readonly collapseQuery?: boolean;
|
|
11
|
+
readonly addOutput?: (result: QueryResults<Base>, pipeline: PipelineOutput<typeof DEFAULT_DATAFLOW_PIPELINE>) => string;
|
|
9
12
|
}
|
|
10
|
-
export declare function showQuery<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(shell: RShell, code: string, queries: Queries<Base, VirtualArguments>, { showCode, collapseResult, collapseQuery }?: ShowQueryOptions): Promise<string>;
|
|
13
|
+
export declare function showQuery<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(shell: RShell, code: string, queries: Queries<Base, VirtualArguments>, { showCode, collapseResult, collapseQuery, addOutput }?: ShowQueryOptions<Base>): Promise<string>;
|
|
11
14
|
export interface QueryDocumentation {
|
|
12
15
|
readonly name: string;
|
|
13
16
|
readonly type: 'virtual' | 'active';
|
|
@@ -17,7 +17,7 @@ const doc_dfg_1 = require("./doc-dfg");
|
|
|
17
17
|
const doc_code_1 = require("./doc-code");
|
|
18
18
|
const time_1 = require("../../util/text/time");
|
|
19
19
|
const query_print_1 = require("../../queries/query-print");
|
|
20
|
-
async function showQuery(shell, code, queries, { showCode, collapseResult, collapseQuery } = {}) {
|
|
20
|
+
async function showQuery(shell, code, queries, { showCode, collapseResult, collapseQuery, addOutput = () => '' } = {}) {
|
|
21
21
|
const now = performance.now();
|
|
22
22
|
const analysis = await new pipeline_executor_1.PipelineExecutor(default_pipelines_1.DEFAULT_DATAFLOW_PIPELINE, {
|
|
23
23
|
parser: shell,
|
|
@@ -60,6 +60,8 @@ ${await (0, doc_dfg_1.printDfGraphForCode)(shell, code, { switchCodeAndGraph: tr
|
|
|
60
60
|
|
|
61
61
|
${collapseResult ? '</details>' : ''}
|
|
62
62
|
|
|
63
|
+
${addOutput(results, analysis)}
|
|
64
|
+
|
|
63
65
|
`;
|
|
64
66
|
}
|
|
65
67
|
exports.RegisteredQueries = {
|
|
@@ -89,10 +89,10 @@ class CollectNumbersSyntaxVisitor extends syntax_cfg_guided_visitor_1.SyntaxAwar
|
|
|
89
89
|
class CollectNumbersDataflowVisitor extends dfg_cfg_guided_visitor_1.DataflowAwareCfgGuidedVisitor {
|
|
90
90
|
numbers = [];
|
|
91
91
|
constructor(controlFlow, dataflow) {
|
|
92
|
-
super({ controlFlow, dataflow, defaultVisitingOrder: 'forward' });
|
|
92
|
+
super({ controlFlow, dfg: dataflow, defaultVisitingOrder: 'forward' });
|
|
93
93
|
}
|
|
94
94
|
visitValue(node) {
|
|
95
|
-
const astNode = this.config.
|
|
95
|
+
const astNode = this.config.dfg.idMap?.get(node.id);
|
|
96
96
|
if ((0, r_number_1.isRNumber)(astNode)) {
|
|
97
97
|
this.numbers.push(astNode.content);
|
|
98
98
|
}
|
|
@@ -104,7 +104,7 @@ class CollectNumbersDataflowVisitor extends dfg_cfg_guided_visitor_1.DataflowAwa
|
|
|
104
104
|
class CollectSourcesSemanticVisitor extends semantic_cfg_guided_visitor_1.SemanticCfgGuidedVisitor {
|
|
105
105
|
sources = [];
|
|
106
106
|
constructor(controlFlow, normalizedAst, dataflow) {
|
|
107
|
-
super({ controlFlow, normalizedAst, dataflow, defaultVisitingOrder: 'forward' });
|
|
107
|
+
super({ controlFlow, normalizedAst, dfg: dataflow, defaultVisitingOrder: 'forward' });
|
|
108
108
|
}
|
|
109
109
|
onAssignmentCall({ source }) {
|
|
110
110
|
if (source) {
|
|
@@ -206,7 +206,7 @@ ${(0, doc_structure_1.section)('Structure of the Control Flow Graph', 2, 'cfg-st
|
|
|
206
206
|
You can produce your very own control flow graph with ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCfg.name, types.info)}.
|
|
207
207
|
The ${(0, doc_types_1.shortLink)(control_flow_graph_1.ControlFlowGraph.name, types.info)} class describes everything required to model the control flow graph, with its edge types described by
|
|
208
208
|
${(0, doc_types_1.shortLink)('CfgEdge', types.info)} and its vertices by ${(0, doc_types_1.shortLink)('CfgSimpleVertex', types.info)}.
|
|
209
|
-
However, you should be aware of the ${(0, doc_types_1.shortLink)('ControlFlowInformation', types.info)} interface which adds some additional information the
|
|
209
|
+
However, you should be aware of the ${(0, doc_types_1.shortLink)('ControlFlowInformation', types.info)} interface which adds some additional information the CFG
|
|
210
210
|
(and is used during the construction of the CFG as well):
|
|
211
211
|
|
|
212
212
|
${(0, doc_types_1.printHierarchy)({ info: types.info, root: 'ControlFlowInformation', program: types.program, openTop: true })}
|
|
@@ -475,7 +475,7 @@ Again, executing it with the CFG and Dataflow of the expression \`x - 1 + 2L * 3
|
|
|
475
475
|
|
|
476
476
|
${await (async () => {
|
|
477
477
|
const res = await (0, doc_cfg_1.getCfg)(shell, 'x - 1 + 2L * 3');
|
|
478
|
-
const visitor = new CollectNumbersDataflowVisitor(res.info, res.dataflow);
|
|
478
|
+
const visitor = new CollectNumbersDataflowVisitor(res.info, res.dataflow.graph);
|
|
479
479
|
visitor.start();
|
|
480
480
|
const collected = visitor.getNumbers();
|
|
481
481
|
return collected.map(n => '\n- `' + JSON.stringify(n) + '`').join('');
|
|
@@ -500,7 +500,7 @@ Executing it with the CFG and Dataflow of the expression \`x <- 2; 3 -> x; assig
|
|
|
500
500
|
|
|
501
501
|
${await (async () => {
|
|
502
502
|
const res = await (0, doc_cfg_1.getCfg)(shell, 'x <- 2; 3 -> x; assign("x", 42 + 21)');
|
|
503
|
-
const visitor = new CollectSourcesSemanticVisitor(res.info, res.ast, res.dataflow);
|
|
503
|
+
const visitor = new CollectSourcesSemanticVisitor(res.info, res.ast, res.dataflow.graph);
|
|
504
504
|
visitor.start();
|
|
505
505
|
const collected = visitor.getSources();
|
|
506
506
|
return collected.map(n => '\n- `' + n + '`').join('');
|
|
@@ -34,6 +34,7 @@ const linker_1 = require("../dataflow/internal/linker");
|
|
|
34
34
|
const doc_normalized_ast_1 = require("./doc-util/doc-normalized-ast");
|
|
35
35
|
const dfg_get_origin_1 = require("../dataflow/origin/dfg-get-origin");
|
|
36
36
|
const identify_link_to_last_call_relation_1 = require("../queries/catalog/call-context-query/identify-link-to-last-call-relation");
|
|
37
|
+
const alias_tracking_1 = require("../dataflow/eval/resolve/alias-tracking");
|
|
37
38
|
const doc_issue_1 = require("./doc-util/doc-issue");
|
|
38
39
|
const unnamed_call_handling_1 = require("../dataflow/internal/process/functions/call/unnamed-call-handling");
|
|
39
40
|
const environment_builder_1 = require("../../test/functionality/_helper/dataflow/environment-builder");
|
|
@@ -977,7 +978,7 @@ Depending on what you are interested in, there exists a plethora of functions an
|
|
|
977
978
|
* The **[Query API](${doc_files_1.FlowrWikiBaseRef}/Query%20API)** provides many functions to query the dataflow graph for specific information (dependencies, calls, slices, clusters, ...)
|
|
978
979
|
* The **[Search API](${doc_files_1.FlowrWikiBaseRef}/Search%20API)** allows you to search for specific vertices or edges in the dataflow graph or the original program
|
|
979
980
|
* ${(0, doc_types_1.shortLink)(node_id_1.recoverName.name, vertexType.info)} and ${(0, doc_types_1.shortLink)(node_id_1.recoverContent.name, vertexType.info)} to get the name or content of a vertex in the dataflow graph
|
|
980
|
-
* ${(0, doc_types_1.shortLink)(
|
|
981
|
+
* ${(0, doc_types_1.shortLink)(alias_tracking_1.resolveIdToValue.name, vertexType.info)} to resolve the value of a variable or id (if possible, see [below](#dfg-resolving-values))
|
|
981
982
|
* ${(0, doc_types_1.shortLink)(edge_1.edgeIncludesType.name, vertexType.info)} to check if an edge includes a specific type and ${(0, doc_types_1.shortLink)(edge_1.splitEdgeTypes.name, vertexType.info)} to split the bitmask of edges into its types (see [below](#dfg-resolving-values))
|
|
982
983
|
* ${(0, doc_types_1.shortLink)(identify_link_to_last_call_relation_1.getValueOfArgument.name, vertexType.info)} to get the (syntactical) value of an argument in a function call
|
|
983
984
|
* ${(0, doc_types_1.shortLink)(dfg_get_origin_1.getOriginInDfg.name, vertexType.info)} to get information about where a read, call, ... comes from (see [below](#dfg-resolving-values))
|
|
@@ -989,8 +990,8 @@ ${(0, doc_structure_1.section)('Resolving Values', 3, 'dfg-resolving-values')}
|
|
|
989
990
|
FlowR supports a [configurable](${doc_files_1.FlowrWikiBaseRef}/Interface#configuring-flowr) level of value tracking—all with the goal of knowing the static value domain of a variable.
|
|
990
991
|
These capabilities are exposed by the [resolve value Query](${doc_files_1.FlowrWikiBaseRef}/Query-API#resolve-value-query) and backed by two important functions:
|
|
991
992
|
|
|
992
|
-
${(0, doc_types_1.shortLink)(
|
|
993
|
-
value resolution
|
|
993
|
+
${(0, doc_types_1.shortLink)(alias_tracking_1.resolveIdToValue.name, vertexType.info)} provides an environment-sensitive (see ${(0, doc_types_1.shortLink)('REnvironmentInformation', vertexType.info)})
|
|
994
|
+
value resolution depending on if the environment is provided.
|
|
994
995
|
|
|
995
996
|
${(0, doc_structure_1.section)('Assessing Edges', 3, 'dfg-assess-edge')}
|
|
996
997
|
|
|
@@ -49,7 +49,7 @@ are exposed with some command line options (e.g., when using the docker image of
|
|
|
49
49
|
|
|
50
50
|
${(0, doc_structure_1.block)({
|
|
51
51
|
type: 'WARNING',
|
|
52
|
-
content: 'As the tree-sitter engine is only for parsing, it cannot execute R code.'
|
|
52
|
+
content: 'As the tree-sitter engine is only for parsing, it cannot execute R code. This engine is now the default.'
|
|
53
53
|
})}
|
|
54
54
|
|
|
55
55
|
In general, there is no need for you to pass custom paths using either
|
|
@@ -34,6 +34,8 @@ const flowr_search_builder_1 = require("../search/flowr-search-builder");
|
|
|
34
34
|
const vertex_1 = require("../dataflow/graph/vertex");
|
|
35
35
|
const doc_types_1 = require("./doc-util/doc-types");
|
|
36
36
|
const path_1 = __importDefault(require("path"));
|
|
37
|
+
const control_flow_query_executor_1 = require("../queries/catalog/control-flow-query/control-flow-query-executor");
|
|
38
|
+
const doc_cfg_1 = require("./doc-util/doc-cfg");
|
|
37
39
|
(0, doc_query_1.registerQueryDocumentation)('call-context', {
|
|
38
40
|
name: 'Call-Context Query',
|
|
39
41
|
type: 'active',
|
|
@@ -477,6 +479,84 @@ Here, \`resolveValue\` tells the dependency query to resolve the value of this a
|
|
|
477
479
|
`;
|
|
478
480
|
}
|
|
479
481
|
});
|
|
482
|
+
(0, doc_query_1.registerQueryDocumentation)('linter', {
|
|
483
|
+
name: 'Linter Query',
|
|
484
|
+
type: 'active',
|
|
485
|
+
shortDescription: 'Lints a given R script for common issues.',
|
|
486
|
+
functionName: dependencies_query_executor_1.executeDependenciesQuery.name,
|
|
487
|
+
functionFile: '../queries/catalog/linter-query/linter-query-executor.ts',
|
|
488
|
+
buildExplanation: async (shell) => {
|
|
489
|
+
const exampleCode = 'read.csv("i_do_not_exist.csv")';
|
|
490
|
+
return `
|
|
491
|
+
This query lints a given R script for common issues, such as missing files, unused variables, and more.
|
|
492
|
+
|
|
493
|
+
In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns all smells detected:
|
|
494
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
495
|
+
type: 'linter'
|
|
496
|
+
}], { showCode: false, collapseQuery: true })}
|
|
497
|
+
|
|
498
|
+
You can also configure which rules to apply and what settings to use for these rules.
|
|
499
|
+
We welcome any feedback and suggestions for new rules on this (consider opening a [new issue](${doc_issue_1.NewIssueUrl})).
|
|
500
|
+
`;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
(0, doc_query_1.registerQueryDocumentation)('control-flow', {
|
|
504
|
+
name: 'Control-Flow Query',
|
|
505
|
+
type: 'active',
|
|
506
|
+
shortDescription: 'Provides the control-flow of the program.',
|
|
507
|
+
functionName: control_flow_query_executor_1.executeControlFlowQuery.name,
|
|
508
|
+
functionFile: '../queries/catalog/control-flow-query/control-flow-query-executor.ts',
|
|
509
|
+
buildExplanation: async (shell) => {
|
|
510
|
+
const exampleCode = 'if(TRUE) 1 else 2';
|
|
511
|
+
return `
|
|
512
|
+
This control-flow query provides you access to the control flow graph.
|
|
513
|
+
|
|
514
|
+
In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns the CFG:
|
|
515
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
516
|
+
type: 'control-flow'
|
|
517
|
+
}], { showCode: false, collapseQuery: true, collapseResult: true })}
|
|
518
|
+
|
|
519
|
+
You can also overwrite the simplification passes to tune the perspective. for example, if you want to have basic blocks:
|
|
520
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
521
|
+
type: 'control-flow',
|
|
522
|
+
config: {
|
|
523
|
+
simplificationPasses: ['unique-cf-sets', 'to-basic-blocks']
|
|
524
|
+
}
|
|
525
|
+
}], { showCode: false, collapseResult: true })}
|
|
526
|
+
|
|
527
|
+
this produces:
|
|
528
|
+
|
|
529
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'] })}
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
If, on the other hand, you want to prune dead code edges:
|
|
533
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
534
|
+
type: 'control-flow',
|
|
535
|
+
config: {
|
|
536
|
+
simplificationPasses: ['unique-cf-sets', 'analyze-dead-code']
|
|
537
|
+
}
|
|
538
|
+
}], { showCode: false, collapseResult: true })}
|
|
539
|
+
|
|
540
|
+
this produces:
|
|
541
|
+
|
|
542
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['analyze-dead-code'] })}
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
Or, completely remove dead code:
|
|
546
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
547
|
+
type: 'control-flow',
|
|
548
|
+
config: {
|
|
549
|
+
simplificationPasses: ['unique-cf-sets', 'analyze-dead-code', 'remove-dead-code']
|
|
550
|
+
}
|
|
551
|
+
}], { showCode: false, collapseResult: true })}
|
|
552
|
+
|
|
553
|
+
this produces:
|
|
554
|
+
|
|
555
|
+
${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['analyze-dead-code', 'remove-dead-code'] })}
|
|
556
|
+
|
|
557
|
+
`;
|
|
558
|
+
}
|
|
559
|
+
});
|
|
480
560
|
(0, doc_query_1.registerQueryDocumentation)('location-map', {
|
|
481
561
|
name: 'Location Map Query',
|
|
482
562
|
type: 'active',
|
|
@@ -46,7 +46,7 @@ exports.R1_DEPRECATED_FUNCTIONS = {
|
|
|
46
46
|
'.meta': metadata
|
|
47
47
|
};
|
|
48
48
|
},
|
|
49
|
-
prettyPrint: result => `Function
|
|
49
|
+
prettyPrint: result => `Function \`${result.function}\` at ${(0, dfg_1.formatRange)(result.range)}`,
|
|
50
50
|
defaultConfig: {
|
|
51
51
|
deprecatedFunctions: ['all_equal', 'arrange_all', 'distinct_all', 'filter_all', 'group_by_all', 'summarise_all', 'mutate_all', 'select_all', 'vars', 'all_vars', 'id', 'failwith', 'select_vars', 'rename_vars', 'select_var', 'current_vars', 'bench_tbls', 'compare_tbls', 'compare_tbls2', 'eval_tbls', 'eval_tbls2', 'location', 'changes', 'combine', 'do', 'funs', 'add_count_', 'add_tally_', 'arrange_', 'count_', 'distinct_', 'do_', 'filter_', 'funs_', 'group_by_', 'group_indices_', 'mutate_', 'tally_', 'transmute_', 'rename_', 'rename_vars_', 'select_', 'select_vars_', 'slice_', 'summarise_', 'summarize_', 'summarise_each', 'src_local', 'tbl_df', 'add_rownames', 'group_nest', 'group_split', 'with_groups', 'nest_by', 'progress_estimated', 'recode', 'sample_n', 'top_n', 'transmute', 'fct_explicit_na', 'aes_', 'aes_auto', 'annotation_logticks', 'is.Coord', 'coord_flip', 'coord_map', 'is.facet', 'fortify', 'is.ggproto', 'guide_train', 'is.ggplot', 'qplot', 'is.theme', 'gg_dep', 'liply', 'isplit2', 'list_along', 'cross', 'invoke', 'at_depth', 'prepend', 'rerun', 'splice', '`%@%`', 'rbernoulli', 'rdunif', 'when', 'update_list', 'map_raw', 'accumulate', 'reduce_right', 'flatten', 'map_dfr', 'as_vector', 'transpose', 'melt_delim', 'melt_fwf', 'melt_table', 'read_table2', 'str_interp', 'as_tibble', 'data_frame', 'tibble_', 'data_frame_', 'lst_', 'as_data_frame', 'as.tibble', 'frame_data', 'trunc_mat', 'is.tibble', 'tidy_names', 'set_tidy_names', 'repair_names', 'extract_numeric', 'complete_', 'drop_na_', 'expand_', 'crossing_', 'nesting_', 'extract_', 'fill_', 'gather_', 'nest_', 'separate_rows_', 'separate_', 'spread_', 'unite_', 'unnest_', 'extract', 'gather', 'nest_legacy', 'separate_rows', 'separate', 'spread',]
|
|
52
52
|
}
|
|
@@ -76,7 +76,7 @@ exports.R2_FILE_PATH_VALIDITY = {
|
|
|
76
76
|
'.meta': metadata
|
|
77
77
|
};
|
|
78
78
|
},
|
|
79
|
-
prettyPrint: result => `Path
|
|
79
|
+
prettyPrint: result => `Path \`${result.filePath}\` at ${(0, dfg_1.formatRange)(result.range)}`,
|
|
80
80
|
defaultConfig: {
|
|
81
81
|
additionalReadFunctions: [],
|
|
82
82
|
additionalWriteFunctions: [],
|