@eagleoutice/flowr 2.9.9 → 2.9.11
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 +57 -54
- package/abstract-interpretation/absint-visitor.d.ts +16 -14
- package/abstract-interpretation/absint-visitor.js +93 -47
- package/abstract-interpretation/data-frame/mappers/arguments.d.ts +1 -1
- package/abstract-interpretation/data-frame/mappers/arguments.js +2 -2
- package/abstract-interpretation/data-frame/shape-inference.d.ts +2 -5
- package/abstract-interpretation/data-frame/shape-inference.js +4 -5
- package/abstract-interpretation/domains/abstract-domain.d.ts +4 -4
- package/abstract-interpretation/domains/abstract-domain.js +8 -8
- package/abstract-interpretation/domains/mapped-abstract-domain.d.ts +12 -5
- package/abstract-interpretation/domains/mapped-abstract-domain.js +47 -23
- package/abstract-interpretation/domains/set-range-domain.js +1 -1
- package/abstract-interpretation/domains/state-abstract-domain.d.ts +30 -1
- package/abstract-interpretation/domains/state-abstract-domain.js +130 -4
- package/abstract-interpretation/normalized-ast-fold.d.ts +2 -2
- package/abstract-interpretation/normalized-ast-fold.js +4 -3
- package/benchmark/slicer.js +5 -5
- package/benchmark/summarizer/first-phase/process.js +4 -4
- package/cli/repl/commands/repl-normalize.js +2 -2
- package/cli/repl/core.js +2 -2
- package/config.js +1 -1
- package/control-flow/cfg-simplification.d.ts +1 -0
- package/control-flow/cfg-simplification.js +1 -0
- package/control-flow/control-flow-graph.d.ts +1 -1
- package/control-flow/control-flow-graph.js +1 -2
- package/control-flow/extract-cfg.js +34 -15
- package/control-flow/semantic-cfg-guided-visitor.js +1 -0
- package/dataflow/cluster.js +1 -1
- package/dataflow/environments/built-in.d.ts +6 -15
- package/dataflow/environments/built-in.js +25 -33
- package/dataflow/environments/default-builtin-config.d.ts +4 -8
- package/dataflow/environments/default-builtin-config.js +8 -5
- package/dataflow/environments/reference-to-maybe.d.ts +8 -0
- package/dataflow/environments/reference-to-maybe.js +46 -3
- package/dataflow/eval/resolve/alias-tracking.d.ts +2 -2
- package/dataflow/eval/resolve/alias-tracking.js +6 -6
- package/dataflow/eval/resolve/resolve.js +12 -10
- package/dataflow/fn/exceptions-of-function.d.ts +1 -1
- package/dataflow/fn/exceptions-of-function.js +2 -1
- package/dataflow/graph/call-graph.d.ts +1 -1
- package/dataflow/graph/call-graph.js +4 -3
- package/dataflow/graph/dataflowgraph-builder.d.ts +1 -1
- package/dataflow/graph/dataflowgraph-builder.js +21 -21
- package/dataflow/graph/graph.d.ts +5 -5
- package/dataflow/graph/graph.js +36 -32
- package/dataflow/graph/unknown-side-effect.js +3 -1
- package/dataflow/info.d.ts +4 -0
- package/dataflow/info.js +2 -2
- package/dataflow/internal/linker.d.ts +4 -4
- package/dataflow/internal/linker.js +59 -33
- package/dataflow/internal/process/functions/call/argument/make-argument.d.ts +2 -1
- package/dataflow/internal/process/functions/call/argument/make-argument.js +3 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +3 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +6 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +15 -6
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +3 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-local.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-new-generic.js +7 -7
- package/dataflow/internal/process/functions/call/built-in/built-in-s-three-dispatch.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +22 -11
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +22 -19
- package/dataflow/internal/process/functions/call/common.d.ts +1 -1
- package/dataflow/internal/process/functions/call/common.js +43 -35
- package/dataflow/internal/process/functions/call/known-call-handling.js +0 -2
- package/dataflow/internal/process/functions/process-argument.d.ts +1 -1
- package/dataflow/internal/process/functions/process-argument.js +3 -3
- package/dataflow/internal/process/functions/process-parameter.js +2 -2
- package/dataflow/origin/dfg-get-origin.d.ts +1 -1
- package/dataflow/origin/dfg-get-origin.js +2 -2
- package/documentation/doc-util/doc-types.js +1 -1
- package/documentation/wiki-absint.js +7 -8
- package/documentation/wiki-cfg.js +3 -3
- package/documentation/wiki-mk/doc-context.d.ts +8 -0
- package/documentation/wiki-mk/doc-context.js +4 -0
- package/documentation/wiki-normalized-ast.d.ts +1 -1
- package/documentation/wiki-normalized-ast.js +9 -6
- package/linter/linter-format.d.ts +10 -0
- package/linter/linter-format.js +15 -0
- package/linter/rules/absolute-path.js +3 -3
- package/linter/rules/dead-code.js +1 -1
- package/linter/rules/file-path-validity.js +1 -1
- package/linter/rules/seeded-randomness.js +1 -1
- package/linter/rules/unused-definition.js +1 -1
- package/package.json +7 -7
- package/project/plugins/file-plugins/files/flowr-description-file.d.ts +9 -0
- package/project/plugins/file-plugins/files/flowr-description-file.js +12 -0
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +1 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +4 -5
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +2 -1
- package/queries/catalog/dependencies-query/dependencies-query-format.js +6 -5
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-format.js +3 -3
- package/queries/catalog/does-call-query/does-call-query-executor.js +3 -3
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +1 -1
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.js +2 -2
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +1 -1
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.js +1 -1
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +1 -1
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.js +1 -1
- package/queries/query-print.d.ts +1 -1
- package/queries/query-print.js +4 -3
- package/r-bridge/lang-4.x/ast/model/model.d.ts +151 -4
- package/r-bridge/lang-4.x/ast/model/model.js +249 -0
- package/r-bridge/lang-4.x/ast/model/nodes/info/r-delimiter.d.ts +11 -1
- package/r-bridge/lang-4.x/ast/model/nodes/info/r-delimiter.js +13 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-access.d.ts +19 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-access.js +26 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-argument.d.ts +36 -3
- package/r-bridge/lang-4.x/ast/model/nodes/r-argument.js +48 -13
- 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 +21 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-break.d.ts +11 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-break.js +14 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-comment.d.ts +8 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-comment.js +11 -5
- package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.d.ts +23 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.js +32 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.d.ts +11 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.js +14 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.d.ts +19 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.js +26 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.d.ts +11 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.js +14 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.d.ts +11 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.js +14 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-line-directive.d.ts +12 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-line-directive.js +14 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-logical.d.ts +20 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-logical.js +26 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-next.d.ts +12 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-next.js +14 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +8 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-number.js +11 -5
- package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.d.ts +17 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.js +22 -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 +22 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-project.d.ts +45 -8
- package/r-bridge/lang-4.x/ast/model/nodes/r-project.js +57 -16
- package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.d.ts +12 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.js +14 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-string.d.ts +15 -3
- package/r-bridge/lang-4.x/ast/model/nodes/r-string.js +21 -6
- package/r-bridge/lang-4.x/ast/model/nodes/r-symbol.d.ts +21 -6
- package/r-bridge/lang-4.x/ast/model/nodes/r-symbol.js +22 -5
- 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 +21 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.d.ts +11 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.js +14 -0
- package/r-bridge/lang-4.x/ast/model/processing/decorate.js +23 -17
- package/r-bridge/lang-4.x/ast/model/processing/node-id.d.ts +39 -2
- package/r-bridge/lang-4.x/ast/model/processing/node-id.js +52 -9
- package/r-bridge/lang-4.x/ast/model/processing/role.d.ts +18 -17
- package/r-bridge/lang-4.x/ast/model/processing/visitor.d.ts +8 -7
- package/r-bridge/lang-4.x/ast/model/processing/visitor.js +6 -13
- package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +1 -1
- package/r-bridge/lang-4.x/ast/parser/json/parser.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/expression/normalize-expression.js +4 -2
- package/r-bridge/lang-4.x/ast/parser/main/internal/values/normalize-number.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/values/normalize-string.js +2 -2
- package/r-bridge/lang-4.x/convert-values.d.ts +14 -5
- package/r-bridge/lang-4.x/convert-values.js +76 -72
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +33 -15
- package/r-bridge/roxygen2/roxygen-parse.js +1 -1
- package/r-bridge/shell-executor.js +1 -1
- package/reconstruct/auto-select/magic-comments.js +4 -4
- package/reconstruct/reconstruct.js +2 -1
- package/search/search-executor/search-generators.js +2 -2
- package/slicing/criterion/filters/all-variables.js +1 -1
- package/slicing/criterion/parse.d.ts +1 -1
- package/slicing/criterion/parse.js +5 -3
- package/slicing/static/slice-call.d.ts +1 -1
- package/slicing/static/slice-call.js +2 -2
- package/statistics/features/supported/assignments/assignments.js +2 -2
- package/statistics/features/supported/control-flow/control-flow.js +2 -2
- package/statistics/features/supported/data-access/data-access.js +6 -5
- package/statistics/features/supported/defined-functions/defined-functions.js +9 -8
- package/statistics/features/supported/expression-list/statistics-expression-list.js +2 -2
- package/statistics/features/supported/loops/loops.js +6 -5
- package/statistics/features/supported/used-functions/used-functions.js +2 -2
- package/statistics/features/supported/variables/variables.js +8 -8
- package/util/mermaid/ast.js +3 -3
- package/util/mermaid/cfg.js +3 -4
- package/util/mermaid/dfg.d.ts +1 -1
- package/util/mermaid/dfg.js +13 -12
- package/util/simple-df/dfg-ascii.js +1 -1
- package/util/version.js +1 -1
- package/r-bridge/lang-4.x/ast/model/collect.d.ts +0 -10
- package/r-bridge/lang-4.x/ast/model/collect.js +0 -25
|
@@ -7,10 +7,10 @@ const known_call_handling_1 = require("../known-call-handling");
|
|
|
7
7
|
const linker_1 = require("../../../../linker");
|
|
8
8
|
const common_1 = require("../common");
|
|
9
9
|
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
10
|
-
const r_argument_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument");
|
|
11
10
|
const scoping_1 = require("../../../../../environments/scoping");
|
|
12
11
|
const built_in_1 = require("../../../../../environments/built-in");
|
|
13
12
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
13
|
+
const r_argument_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument");
|
|
14
14
|
/**
|
|
15
15
|
* Processes a built-in 'local' function call.
|
|
16
16
|
*/
|
|
@@ -24,8 +24,8 @@ function processLocal(name, args, rootId, data, config) {
|
|
|
24
24
|
'...': '...'
|
|
25
25
|
};
|
|
26
26
|
const argMaps = (0, linker_1.invertArgumentMap)((0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params));
|
|
27
|
-
const env = (0, unpack_argument_1.unpackArg)(
|
|
28
|
-
const expr = (0, unpack_argument_1.unpackArg)(
|
|
27
|
+
const env = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('env')?.[0]));
|
|
28
|
+
const expr = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('expr')?.[0]));
|
|
29
29
|
if (!expr) {
|
|
30
30
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
|
|
31
31
|
}
|
|
@@ -41,8 +41,8 @@ function processRepeatLoop(name, args, rootId, data) {
|
|
|
41
41
|
});
|
|
42
42
|
const body = processedArguments[0];
|
|
43
43
|
(0, assert_1.guard)(body !== undefined, () => `Repeat-Loop ${identifier_1.Identifier.toString(name.content)} has no body, impossible!`);
|
|
44
|
-
(0, linker_1.linkCircularRedefinitionsWithinALoop)(information.graph, (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(information.graph
|
|
45
|
-
(0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences));
|
|
44
|
+
(0, linker_1.linkCircularRedefinitionsWithinALoop)(information.graph, (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(information.graph)), body.out);
|
|
45
|
+
(0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences), information.graph);
|
|
46
46
|
information.exitPoints = (0, info_1.filterOutLoopExitPoints)(information.exitPoints);
|
|
47
47
|
return information;
|
|
48
48
|
}
|
|
@@ -4,7 +4,7 @@ import { type ForceArguments } from '../common';
|
|
|
4
4
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import { type RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
7
|
-
import
|
|
7
|
+
import { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
8
|
/**
|
|
9
9
|
* Process a replacement function call like `<-`, `[[<-`, `$<-`, etc.
|
|
10
10
|
* These are automatically created when doing assignments like `x[y] <- value` or in general `fun(x) <- value` will call `fun<- (x, value)`.
|
|
@@ -6,6 +6,7 @@ const known_call_handling_1 = require("../known-call-handling");
|
|
|
6
6
|
const log_1 = require("../../../../../../util/log");
|
|
7
7
|
const common_1 = require("../common");
|
|
8
8
|
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
9
|
+
const node_id_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
9
10
|
const logger_1 = require("../../../../../logger");
|
|
10
11
|
const vertex_1 = require("../../../../../graph/vertex");
|
|
11
12
|
const edge_1 = require("../../../../../graph/edge");
|
|
@@ -110,7 +111,7 @@ args, rootId, data, config) {
|
|
|
110
111
|
fn.type = identifier_1.ReferenceType.S3MethodPrefix;
|
|
111
112
|
}
|
|
112
113
|
// link the built-in replacement op
|
|
113
|
-
res.graph.addEdge(rootId,
|
|
114
|
+
res.graph.addEdge(rootId, node_id_1.NodeId.toBuiltIn(identifier_1.Identifier.getName(name.content)), edge_1.EdgeType.Calls | edge_1.EdgeType.Reads);
|
|
114
115
|
return res;
|
|
115
116
|
}
|
|
116
117
|
//# sourceMappingURL=built-in-replacement.js.map
|
|
@@ -33,7 +33,7 @@ function processS7NewGeneric(name, args, rootId, data, config) {
|
|
|
33
33
|
params[config.args.fun] = 'fun';
|
|
34
34
|
params['...'] = '...';
|
|
35
35
|
const argMaps = (0, linker_1.invertArgumentMap)((0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params));
|
|
36
|
-
const genName = (0, unpack_argument_1.unpackArg)(
|
|
36
|
+
const genName = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('name')?.[0]));
|
|
37
37
|
if (!genName) {
|
|
38
38
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
|
|
39
39
|
}
|
|
@@ -51,10 +51,10 @@ function processS7NewGeneric(name, args, rootId, data, config) {
|
|
|
51
51
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
|
|
52
52
|
}
|
|
53
53
|
data = { ...data, currentS7name: accessedIdentifiers };
|
|
54
|
-
let funArg = (0, unpack_argument_1.unpackArg)(
|
|
54
|
+
let funArg = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('fun')?.[0]))?.info.id;
|
|
55
55
|
const effectiveArgs = args.slice();
|
|
56
56
|
if (!funArg) {
|
|
57
|
-
const dispatchArg = (0, unpack_argument_1.unpackArg)(
|
|
57
|
+
const dispatchArg = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('dispatchArg')?.[0]));
|
|
58
58
|
const newFun = makeS7DispatchFDef(name, [dispatchArg?.lexeme ?? undefined], rootId, args.length, data.completeAst.idMap);
|
|
59
59
|
// fake it 'function([dispatch_args],...) S7_dispatch()'
|
|
60
60
|
effectiveArgs.push(newFun[0]);
|
|
@@ -80,7 +80,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
80
80
|
info: {
|
|
81
81
|
id: argNameId,
|
|
82
82
|
nesting: name.info.nesting,
|
|
83
|
-
role: "arg-
|
|
83
|
+
role: "arg-n" /* RoleInParent.ArgumentName */,
|
|
84
84
|
fullRange: r,
|
|
85
85
|
adToks: undefined,
|
|
86
86
|
file: name.info.file,
|
|
@@ -117,7 +117,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
117
117
|
info: {
|
|
118
118
|
id: rootId + '-s7-new-generic-fun-body',
|
|
119
119
|
nesting: name.info.nesting,
|
|
120
|
-
role: "fun-
|
|
120
|
+
role: "fun-b" /* RoleInParent.FunctionDefinitionBody */,
|
|
121
121
|
fullRange: r,
|
|
122
122
|
adToks: undefined,
|
|
123
123
|
file: name.info.file,
|
|
@@ -132,7 +132,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
132
132
|
file: name.info.file,
|
|
133
133
|
id: fdefId,
|
|
134
134
|
nesting: name.info.nesting,
|
|
135
|
-
role: "arg-
|
|
135
|
+
role: "arg-v" /* RoleInParent.ArgumentValue */,
|
|
136
136
|
parent: rootId,
|
|
137
137
|
index: args + 1,
|
|
138
138
|
adToks: undefined,
|
|
@@ -150,7 +150,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
150
150
|
info: {
|
|
151
151
|
id: paramNameId,
|
|
152
152
|
nesting: name.info.nesting,
|
|
153
|
-
role: "param-
|
|
153
|
+
role: "param-n" /* RoleInParent.ParameterName */,
|
|
154
154
|
fullRange: r,
|
|
155
155
|
adToks: undefined,
|
|
156
156
|
file: name.info.file,
|
|
@@ -8,13 +8,13 @@ const logger_1 = require("../../../../../logger");
|
|
|
8
8
|
const built_in_1 = require("../../../../../environments/built-in");
|
|
9
9
|
const linker_1 = require("../../../../linker");
|
|
10
10
|
const common_1 = require("../common");
|
|
11
|
-
const r_argument_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument");
|
|
12
11
|
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
13
12
|
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
14
13
|
const r_value_1 = require("../../../../../eval/values/r-value");
|
|
15
14
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
16
15
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
17
16
|
const range_1 = require("../../../../../../util/range");
|
|
17
|
+
const r_argument_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument");
|
|
18
18
|
/**
|
|
19
19
|
* Process an S3 dispatch call like `UseMethod`.
|
|
20
20
|
*/
|
|
@@ -29,11 +29,11 @@ function processS3Dispatch(name, args, rootId, data, config) {
|
|
|
29
29
|
'...': '...'
|
|
30
30
|
};
|
|
31
31
|
const argMaps = (0, linker_1.invertArgumentMap)((0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params));
|
|
32
|
-
const generic = (0, unpack_argument_1.unpackArg)(
|
|
32
|
+
const generic = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('generic')?.[0]));
|
|
33
33
|
if (!generic && !config.inferFromClosure) {
|
|
34
34
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
|
|
35
35
|
}
|
|
36
|
-
const obj = (0, unpack_argument_1.unpackArg)(
|
|
36
|
+
const obj = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('object')?.[0]));
|
|
37
37
|
const dfObj = obj ? (0, processor_1.processDataflowFor)(obj, data) : (0, info_1.initializeCleanDataflowInformation)(rootId, data);
|
|
38
38
|
if ((0, info_1.alwaysExits)(dfObj)) {
|
|
39
39
|
(0, common_1.patchFunctionCall)({
|
|
@@ -155,19 +155,30 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
155
155
|
if (sourceFile?.length === 1) {
|
|
156
156
|
const path = (0, retriever_1.removeRQuotes)(sourceFile[0]);
|
|
157
157
|
let filepath = path ? findSource(data.ctx.config.solver.resolveSource, path, data) : path;
|
|
158
|
-
if (Array.isArray(filepath)) {
|
|
159
|
-
filepath = filepath
|
|
158
|
+
if (!Array.isArray(filepath)) {
|
|
159
|
+
filepath = filepath ? [filepath] : undefined;
|
|
160
160
|
}
|
|
161
|
-
if (filepath !== undefined) {
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
161
|
+
if (filepath !== undefined && filepath.length > 0) {
|
|
162
|
+
let result = information;
|
|
163
|
+
const origCds = data.cds?.slice() ?? [];
|
|
164
|
+
for (const f of filepath) {
|
|
165
|
+
// check if the sourced file has already been dataflow analyzed, and if so, skip it
|
|
166
|
+
const limit = data.ctx.config.solver.resolveSource?.repeatedSourceLimit ?? 0;
|
|
167
|
+
const findCount = data.referenceChain.filter(e => e !== undefined && f === e).length;
|
|
168
|
+
if (findCount > limit) {
|
|
169
|
+
logger_1.dataflowLogger.warn(`Found cycle (>=${limit + 1}) in dataflow analysis for ${JSON.stringify(filepath)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
|
|
170
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(result.graph, result.environment, rootId);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (filepath.length > 1) {
|
|
174
|
+
data = { ...data, cds: [...origCds, { id: rootId, when: true, file: f }] };
|
|
175
|
+
}
|
|
176
|
+
result = sourceRequest(rootId, {
|
|
177
|
+
request: 'file',
|
|
178
|
+
content: f
|
|
179
|
+
}, data, result, (0, decorate_1.sourcedDeterministicCountingIdGenerator)((findCount > 0 ? findCount + '::' : '') + f, name.location));
|
|
169
180
|
}
|
|
170
|
-
return
|
|
181
|
+
return result;
|
|
171
182
|
}
|
|
172
183
|
}
|
|
173
184
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(sourceFile)} for source is currently not supported, skipping`);
|
|
@@ -14,6 +14,7 @@ const general_1 = require("../../../../../eval/values/general");
|
|
|
14
14
|
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
15
15
|
const reference_to_maybe_1 = require("../../../../../environments/reference-to-maybe");
|
|
16
16
|
const built_in_1 = require("../../../../../environments/built-in");
|
|
17
|
+
const append_1 = require("../../../../../environments/append");
|
|
17
18
|
/**
|
|
18
19
|
* Process a while loop like `while(cond) { ... }`.
|
|
19
20
|
*/
|
|
@@ -27,6 +28,8 @@ function processWhileLoop(name, args, rootId, data) {
|
|
|
27
28
|
logger_1.dataflowLogger.warn(`While-Loop ${identifier_1.Identifier.toString(name.content)} has empty arguments in ${JSON.stringify(args)}, skipping`);
|
|
28
29
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
|
|
29
30
|
}
|
|
31
|
+
const nameId = name.info.id;
|
|
32
|
+
const origEnv = data.environment;
|
|
30
33
|
// we should defer this to the abstract interpretation
|
|
31
34
|
const values = (0, alias_tracking_1.resolveIdToValue)(unpackedArgs[0]?.info.id, { environment: data.environment, idMap: data.completeAst.idMap, resolve: data.ctx.config.solver.variables, ctx: data.ctx });
|
|
32
35
|
const conditionIsAlwaysFalse = (0, general_1.valueSetGuard)(values)?.elements.every(d => d.type === 'logical' && d.value === false) ?? false;
|
|
@@ -41,49 +44,49 @@ function processWhileLoop(name, args, rootId, data) {
|
|
|
41
44
|
rootId,
|
|
42
45
|
data,
|
|
43
46
|
markAsNSE: [1],
|
|
44
|
-
|
|
45
|
-
if (i === 1) {
|
|
46
|
-
return { ...d, cds: [...d.cds ?? [], { id: name.info.id, when: true }] };
|
|
47
|
-
}
|
|
48
|
-
return d;
|
|
49
|
-
}, origin: built_in_1.BuiltInProcName.WhileLoop
|
|
47
|
+
origin: built_in_1.BuiltInProcName.WhileLoop
|
|
50
48
|
});
|
|
51
49
|
const [condition, body] = processedArguments;
|
|
52
50
|
// If the condition is always false, we don't include the body
|
|
53
51
|
if (condition !== undefined && conditionIsAlwaysFalse) {
|
|
54
|
-
information.graph.addEdge(
|
|
52
|
+
information.graph.addEdge(nameId, condition.entryPoint, edge_1.EdgeType.Reads);
|
|
55
53
|
return {
|
|
56
54
|
unknownReferences: [],
|
|
57
|
-
in: [{ nodeId:
|
|
55
|
+
in: [{ nodeId: nameId, name: name.lexeme, cds: data.cds, type: identifier_1.ReferenceType.Function }],
|
|
58
56
|
out: condition.out,
|
|
59
|
-
entryPoint:
|
|
57
|
+
entryPoint: nameId,
|
|
60
58
|
exitPoints: [],
|
|
61
59
|
graph: information.graph,
|
|
62
60
|
environment: information.environment,
|
|
63
61
|
hooks: condition.hooks
|
|
64
62
|
};
|
|
65
63
|
}
|
|
64
|
+
const conditionIsAlwaysTrue = (0, general_1.valueSetGuard)(values)?.elements.every(d => d.type === 'logical' && d.value === true) ?? false;
|
|
66
65
|
(0, assert_1.guard)(condition !== undefined && body !== undefined, () => `While-Loop ${identifier_1.Identifier.toString(name.content)} has no condition or body, impossible!`);
|
|
67
66
|
const originalDependency = data.cds;
|
|
68
67
|
if ((0, info_1.alwaysExits)(condition)) {
|
|
69
68
|
logger_1.dataflowLogger.warn(`While-Loop ${rootId} forces exit in condition, skipping rest`);
|
|
70
|
-
information.graph.addEdge(
|
|
69
|
+
information.graph.addEdge(nameId, condition.entryPoint, edge_1.EdgeType.Reads);
|
|
71
70
|
return condition;
|
|
72
71
|
}
|
|
73
|
-
const cdTrue = [{ id:
|
|
74
|
-
const
|
|
75
|
-
(0,
|
|
76
|
-
(0, linker_1.
|
|
72
|
+
const cdTrue = [{ id: nameId, when: true }];
|
|
73
|
+
const bodyRead = body.in.concat(body.unknownReferences);
|
|
74
|
+
(0, reference_to_maybe_1.applyCdsToAllInGraphButConstants)(body.graph, bodyRead, cdTrue);
|
|
75
|
+
const remainingInputs = (0, linker_1.linkInputs)(bodyRead, information.environment, condition.in.concat(condition.unknownReferences), information.graph, true);
|
|
76
|
+
(0, reference_to_maybe_1.applyCdToReferences)(body.out, cdTrue);
|
|
77
|
+
(0, linker_1.linkCircularRedefinitionsWithinALoop)(information.graph, (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(information.graph, new Set(condition.in.map(i => i.nodeId)))), body.out);
|
|
78
|
+
(0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences), information.graph);
|
|
77
79
|
// as the while-loop always evaluates its condition
|
|
78
|
-
information.graph.addEdge(
|
|
80
|
+
information.graph.addEdge(nameId, condition.entryPoint, edge_1.EdgeType.Reads);
|
|
79
81
|
return {
|
|
80
82
|
unknownReferences: [],
|
|
81
|
-
in: [{ nodeId:
|
|
82
|
-
out: condition.out.concat(
|
|
83
|
-
entryPoint:
|
|
83
|
+
in: [{ nodeId: nameId, name: name.lexeme, cds: originalDependency, type: identifier_1.ReferenceType.Function }, ...remainingInputs],
|
|
84
|
+
out: condition.out.concat(body.out),
|
|
85
|
+
entryPoint: nameId,
|
|
84
86
|
exitPoints: (0, info_1.filterOutLoopExitPoints)(body.exitPoints),
|
|
85
87
|
graph: information.graph,
|
|
86
|
-
|
|
88
|
+
// as we do not know whether the loop executes at all, we have to merge the environments of the condition and the body, as both may be relevant
|
|
89
|
+
environment: conditionIsAlwaysTrue ? information.environment : (0, append_1.appendEnvironment)(origEnv, information.environment),
|
|
87
90
|
hooks: condition.hooks.concat(body.hooks)
|
|
88
91
|
};
|
|
89
92
|
}
|
|
@@ -40,7 +40,7 @@ export declare function convertFnArguments<OtherInfo>(args: readonly (typeof Emp
|
|
|
40
40
|
* Transforms a function argument into a function argument reference for a function call vertex.
|
|
41
41
|
* Please be aware, that the ids here are those inferred from the AST, not from the dataflow graph!
|
|
42
42
|
*/
|
|
43
|
-
export declare function convertFnArgument<OtherInfo>(arg: typeof EmptyArgument | RNode<OtherInfo & ParentInformation>): FunctionArgument;
|
|
43
|
+
export declare function convertFnArgument<OtherInfo>(this: void, arg: typeof EmptyArgument | RNode<OtherInfo & ParentInformation>): FunctionArgument;
|
|
44
44
|
/**
|
|
45
45
|
* Processes all arguments for a function call, updating the given final graph and environment.
|
|
46
46
|
*/
|
|
@@ -6,6 +6,7 @@ exports.processAllArguments = processAllArguments;
|
|
|
6
6
|
exports.patchFunctionCall = patchFunctionCall;
|
|
7
7
|
const info_1 = require("../../../../info");
|
|
8
8
|
const processor_1 = require("../../../../processor");
|
|
9
|
+
const model_1 = require("../../../../../r-bridge/lang-4.x/ast/model/model");
|
|
9
10
|
const r_function_call_1 = require("../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
10
11
|
const identifier_1 = require("../../../../environments/identifier");
|
|
11
12
|
const overwrite_1 = require("../../../../environments/overwrite");
|
|
@@ -13,33 +14,34 @@ const resolve_by_name_1 = require("../../../../environments/resolve-by-name");
|
|
|
13
14
|
const type_1 = require("../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
14
15
|
const vertex_1 = require("../../../../graph/vertex");
|
|
15
16
|
const edge_1 = require("../../../../graph/edge");
|
|
17
|
+
const r_argument_1 = require("../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument");
|
|
16
18
|
function forceVertexArgumentValueReferences(rootId, value, graph, env) {
|
|
17
19
|
const valueVertex = graph.getVertex(value.entryPoint);
|
|
18
20
|
if (!valueVertex) {
|
|
19
21
|
return;
|
|
20
22
|
}
|
|
21
23
|
// link read if it is function definition directly and reference the exit point
|
|
22
|
-
if (valueVertex.tag
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
graph.addEdge(rootId, exit.nodeId, edge_1.EdgeType.Reads);
|
|
26
|
-
}
|
|
24
|
+
if (valueVertex.tag === vertex_1.VertexType.FunctionDefinition) {
|
|
25
|
+
for (const exit of valueVertex.exitPoints) {
|
|
26
|
+
graph.addEdge(rootId, exit.nodeId, edge_1.EdgeType.Reads);
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
}
|
|
29
|
+
else if (valueVertex.tag !== vertex_1.VertexType.Value) {
|
|
30
|
+
for (const exit of value.exitPoints) {
|
|
31
|
+
graph.addEdge(rootId, exit.nodeId, edge_1.EdgeType.Reads);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
const containedSubflowIn = graph.verticesOfType(vertex_1.VertexType.FunctionDefinition)
|
|
35
|
-
.flatMap(([, info]) => info.subflow.in)
|
|
36
|
-
.toArray();
|
|
35
|
+
.flatMap(([, info]) => info.subflow.in);
|
|
37
36
|
// try to resolve them against the current environment
|
|
38
|
-
for (const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
for (const l of [value.in, containedSubflowIn]) {
|
|
38
|
+
for (const ref of l) {
|
|
39
|
+
if (ref.name) {
|
|
40
|
+
const refId = ref.nodeId;
|
|
41
|
+
const resolved = (0, resolve_by_name_1.resolveByName)(ref.name, env, ref.type) ?? [];
|
|
42
|
+
for (const resolve of resolved) {
|
|
43
|
+
graph.addEdge(refId, resolve.nodeId, edge_1.EdgeType.Reads);
|
|
44
|
+
}
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
}
|
|
@@ -51,7 +53,7 @@ function forceVertexArgumentValueReferences(rootId, value, graph, env) {
|
|
|
51
53
|
* @see convertFnArgument
|
|
52
54
|
*/
|
|
53
55
|
function convertFnArguments(args) {
|
|
54
|
-
return args.map(
|
|
56
|
+
return args.map(convertFnArgument);
|
|
55
57
|
}
|
|
56
58
|
/**
|
|
57
59
|
* Transforms a function argument into a function argument reference for a function call vertex.
|
|
@@ -93,32 +95,38 @@ function processAllArguments({ functionName, args, data, finalGraph, functionRoo
|
|
|
93
95
|
continue;
|
|
94
96
|
}
|
|
95
97
|
const processed = (0, processor_1.processDataflowFor)(arg, { ...data, environment: argEnv });
|
|
96
|
-
if (
|
|
98
|
+
if (r_argument_1.RArgument.isWithValue(arg) && (forceArgs === 'all' || forceArgs[i]) && !model_1.RConstant.is(arg.value)) {
|
|
97
99
|
forceVertexArgumentValueReferences(functionRootId, processed, processed.graph, argEnv);
|
|
98
100
|
}
|
|
99
101
|
processedArguments.push(processed);
|
|
100
102
|
finalEnv = (0, overwrite_1.overwriteEnvironment)(finalEnv, processed.environment);
|
|
101
103
|
finalGraph.mergeWith(processed.graph);
|
|
102
104
|
// resolve reads within argument, we resolve before adding the `processed.environment` to avoid cyclic dependencies
|
|
103
|
-
for (const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
else {
|
|
111
|
-
/* maybe all targets are not definitely of the current scope and should be still kept */
|
|
112
|
-
let assumeItMayHaveAHigherTarget = true;
|
|
113
|
-
for (const resolved of tryToResolve) {
|
|
114
|
-
if ((0, info_1.happensInEveryBranch)(resolved.cds) && !(0, identifier_1.isReferenceType)(resolved.type, identifier_1.ReferenceType.BuiltInFunction | identifier_1.ReferenceType.BuiltInConstant)) {
|
|
115
|
-
assumeItMayHaveAHigherTarget = false;
|
|
116
|
-
}
|
|
117
|
-
finalGraph.addEdge(ingoing.nodeId, resolved.nodeId, edge_1.EdgeType.Reads);
|
|
118
|
-
}
|
|
119
|
-
if (assumeItMayHaveAHigherTarget) {
|
|
105
|
+
for (const l of [processed.in, processed.unknownReferences]) {
|
|
106
|
+
for (const ingoing of l) {
|
|
107
|
+
// check if it is called directly
|
|
108
|
+
const inId = ingoing.nodeId;
|
|
109
|
+
const refType = finalGraph.getVertex(inId)?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Unknown;
|
|
110
|
+
const tryToResolve = ingoing.name ? (0, resolve_by_name_1.resolveByName)(ingoing.name, argEnv, refType) : undefined;
|
|
111
|
+
if (tryToResolve === undefined) {
|
|
120
112
|
remainingReadInArgs.push(ingoing);
|
|
121
113
|
}
|
|
114
|
+
else {
|
|
115
|
+
/* maybe all targets are not definitely of the current scope and should be still kept */
|
|
116
|
+
let assumeItMayHaveAHigherTarget = true;
|
|
117
|
+
for (const resolved of tryToResolve) {
|
|
118
|
+
if ((0, identifier_1.isReferenceType)(resolved.type, identifier_1.ReferenceType.BuiltInFunction | identifier_1.ReferenceType.BuiltInConstant)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
else if ((0, info_1.happensInEveryBranch)(resolved.cds)) {
|
|
122
|
+
assumeItMayHaveAHigherTarget = false;
|
|
123
|
+
}
|
|
124
|
+
finalGraph.addEdge(inId, resolved.nodeId, edge_1.EdgeType.Reads);
|
|
125
|
+
}
|
|
126
|
+
if (assumeItMayHaveAHigherTarget) {
|
|
127
|
+
remainingReadInArgs.push(ingoing);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
122
130
|
}
|
|
123
131
|
}
|
|
124
132
|
argEnv = (0, overwrite_1.overwriteEnvironment)(argEnv, processed.environment);
|
|
@@ -9,7 +9,6 @@ const graph_1 = require("../../../../graph/graph");
|
|
|
9
9
|
const edge_1 = require("../../../../graph/edge");
|
|
10
10
|
const logger_1 = require("../../../../logger");
|
|
11
11
|
const vertex_1 = require("../../../../graph/vertex");
|
|
12
|
-
const log_1 = require("../../../../../util/log");
|
|
13
12
|
const unknown_side_effect_1 = require("../../../../graph/unknown-side-effect");
|
|
14
13
|
const built_in_1 = require("../../../../environments/built-in");
|
|
15
14
|
/**
|
|
@@ -36,7 +35,6 @@ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = fal
|
|
|
36
35
|
const functionName = (0, processor_1.processDataflowFor)(name, data);
|
|
37
36
|
const finalGraph = new graph_1.DataflowGraph(data.completeAst.idMap);
|
|
38
37
|
const functionCallName = name.content;
|
|
39
|
-
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Processing known function call ${identifier_1.Identifier.toString(functionCallName)} with ${args.length} arguments`);
|
|
40
38
|
const processArgs = reverseOrder ? args.toReversed() : args;
|
|
41
39
|
const { finalEnv, callArgs, remainingReadInArgs, processedArguments } = (0, common_1.processAllArguments)({ functionName, args: processArgs, data, finalGraph, functionRootId: rootId, patchData, forceArgs });
|
|
42
40
|
if (markAsNSE) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type DataflowProcessorInformation } from '../../../processor';
|
|
2
2
|
import { type DataflowInformation } from '../../../info';
|
|
3
3
|
import type { ParentInformation } from '../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
-
import
|
|
4
|
+
import { RNode } from '../../../../r-bridge/lang-4.x/ast/model/model';
|
|
5
5
|
import type { IdentifierReference } from '../../../environments/identifier';
|
|
6
6
|
import { DataflowGraph } from '../../../graph/graph';
|
|
7
7
|
import type { RArgument } from '../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument';
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.linkReadsForArgument = linkReadsForArgument;
|
|
4
4
|
exports.processFunctionArgument = processFunctionArgument;
|
|
5
5
|
const processor_1 = require("../../../processor");
|
|
6
|
-
const
|
|
6
|
+
const model_1 = require("../../../../r-bridge/lang-4.x/ast/model/model");
|
|
7
7
|
const graph_1 = require("../../../graph/graph");
|
|
8
8
|
const type_1 = require("../../../../r-bridge/lang-4.x/ast/model/type");
|
|
9
9
|
const edge_1 = require("../../../graph/edge");
|
|
@@ -12,9 +12,9 @@ const vertex_1 = require("../../../graph/vertex");
|
|
|
12
12
|
* Links all reads that occur before the argument to the argument root node.
|
|
13
13
|
*/
|
|
14
14
|
function linkReadsForArgument(root, ingoingRefs, graph) {
|
|
15
|
-
const allIdsBeforeArguments = new Set((0, collect_1.collectAllIds)(root, n => n.type === type_1.RType.Argument && n.info.id !== root.info.id));
|
|
16
|
-
const ingoingBeforeArgs = ingoingRefs.filter(r => allIdsBeforeArguments.has(r.nodeId));
|
|
17
15
|
const rid = root.info.id;
|
|
16
|
+
const allIdsBeforeArguments = new Set(model_1.RNode.collectAllIdsWithStop(root, n => n.type === type_1.RType.Argument && n.info.id !== rid));
|
|
17
|
+
const ingoingBeforeArgs = ingoingRefs.filter(r => allIdsBeforeArguments.has(r.nodeId));
|
|
18
18
|
for (const ref of ingoingBeforeArgs) {
|
|
19
19
|
// link against the root reference currently I do not know how to deal with nested function calls otherwise
|
|
20
20
|
graph.addEdge(rid, ref.nodeId, edge_1.EdgeType.Reads);
|
|
@@ -5,8 +5,8 @@ const processor_1 = require("../../../processor");
|
|
|
5
5
|
const log_1 = require("../../../../util/log");
|
|
6
6
|
const identifier_1 = require("../../../environments/identifier");
|
|
7
7
|
const define_1 = require("../../../environments/define");
|
|
8
|
-
const type_1 = require("../../../../r-bridge/lang-4.x/ast/model/type");
|
|
9
8
|
const edge_1 = require("../../../graph/edge");
|
|
9
|
+
const r_function_definition_1 = require("../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-definition");
|
|
10
10
|
/**
|
|
11
11
|
*
|
|
12
12
|
*/
|
|
@@ -26,7 +26,7 @@ function processFunctionParameter(parameter, data) {
|
|
|
26
26
|
graph.setDefinitionOfVertex(writtenNode);
|
|
27
27
|
environment = (0, define_1.define)(writtenNode, false, environment);
|
|
28
28
|
if (defaultValue !== undefined) {
|
|
29
|
-
if (parameter.defaultValue
|
|
29
|
+
if (r_function_definition_1.RFunctionDefinition.is(parameter.defaultValue)) {
|
|
30
30
|
graph.addEdge(wid, parameter.defaultValue.info.id, edge_1.EdgeType.DefinedBy);
|
|
31
31
|
}
|
|
32
32
|
else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
2
2
|
import type { DataflowGraph } from '../graph/graph';
|
|
3
3
|
import type { Identifier } from '../environments/identifier';
|
|
4
4
|
export declare const enum OriginType {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getOriginInDfg = getOriginInDfg;
|
|
4
|
+
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
4
5
|
const vertex_1 = require("../graph/vertex");
|
|
5
6
|
const edge_1 = require("../graph/edge");
|
|
6
7
|
const linker_1 = require("../internal/linker");
|
|
7
8
|
const assert_1 = require("../../util/assert");
|
|
8
|
-
const built_in_1 = require("../environments/built-in");
|
|
9
9
|
/**
|
|
10
10
|
* Obtain the (dataflow) origin of a given node in the dfg.
|
|
11
11
|
* @example consider the following code:
|
|
@@ -95,7 +95,7 @@ function getCallTarget(dfg, call) {
|
|
|
95
95
|
return origins?.length === 0 ? getVariableUseOrigin(dfg, call) : origins;
|
|
96
96
|
}
|
|
97
97
|
origins = (origins ?? []).concat([...targets].map(target => {
|
|
98
|
-
if (
|
|
98
|
+
if (node_id_1.NodeId.isBuiltIn(target)) {
|
|
99
99
|
return {
|
|
100
100
|
type: 3 /* OriginType.BuiltInFunctionOrigin */,
|
|
101
101
|
fn: { name: call.name },
|
|
@@ -517,7 +517,7 @@ function printHierarchy({ program, info, root, ignoredTypes, collapseFromNesting
|
|
|
517
517
|
if (exports.mermaidHide.includes(baseType) || ignoredTypes?.includes(baseType)) {
|
|
518
518
|
continue;
|
|
519
519
|
}
|
|
520
|
-
const res = printHierarchy({ program, info, root: baseType, collapseFromNesting, initialNesting: initialNesting + 1, maxDepth, skipNesting, showImplSnippet, reverse });
|
|
520
|
+
const res = printHierarchy({ program, info, root: baseType, ignoredTypes, collapseFromNesting, initialNesting: initialNesting + 1, maxDepth, skipNesting, showImplSnippet, reverse });
|
|
521
521
|
result.push(res);
|
|
522
522
|
}
|
|
523
523
|
const out = result.join('\n');
|
|
@@ -17,7 +17,7 @@ class IntervalInferenceVisitor extends absint_visitor_1.AbstractInterpretationVi
|
|
|
17
17
|
onNumberConstant({ vertex, node }) {
|
|
18
18
|
super.onNumberConstant({ vertex, node });
|
|
19
19
|
const interval = new interval_domain_1.IntervalDomain([node.content.num, node.content.num]);
|
|
20
|
-
this.
|
|
20
|
+
this.updateState(node.info.id, interval);
|
|
21
21
|
}
|
|
22
22
|
onFunctionCall({ call }) {
|
|
23
23
|
super.onFunctionCall({ call });
|
|
@@ -31,9 +31,9 @@ class IntervalInferenceVisitor extends absint_visitor_1.AbstractInterpretationVi
|
|
|
31
31
|
// We map the numerical operation to the resulting interval after applying the abstract semantics of the operation
|
|
32
32
|
switch (identifier_1.Identifier.getName(call.name)) {
|
|
33
33
|
case '+':
|
|
34
|
-
return this.
|
|
34
|
+
return this.updateState(call.id, left.add(right));
|
|
35
35
|
case '-':
|
|
36
|
-
return this.
|
|
36
|
+
return this.updateState(call.id, left.subtract(right));
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -51,8 +51,7 @@ async function inferIntervals() {
|
|
|
51
51
|
const dfg = (await analyzer.dataflow()).graph;
|
|
52
52
|
const cfg = await analyzer.controlflow(undefined, cfg_kind_1.CfgKind.NoFunctionDefs);
|
|
53
53
|
const ctx = analyzer.inspectContext();
|
|
54
|
-
const
|
|
55
|
-
const inference = new IntervalInferenceVisitor({ controlFlow: cfg, dfg: dfg, normalizedAst: ast, ctx: ctx, domain: domain });
|
|
54
|
+
const inference = new IntervalInferenceVisitor({ controlFlow: cfg, dfg: dfg, normalizedAst: ast, ctx: ctx });
|
|
56
55
|
inference.start();
|
|
57
56
|
const result = inference.getEndState();
|
|
58
57
|
return result.value.entries().toArray()
|
|
@@ -128,15 +127,15 @@ For example, if we want to perform a (very basic) interval analysis using abstra
|
|
|
128
127
|
|
|
129
128
|
${ctx.code(IntervalInferenceVisitor)}
|
|
130
129
|
|
|
131
|
-
The interval inference visitor first overrides the ${ctx.link(`${semantic_cfg_guided_visitor_1.SemanticCfgGuidedVisitor.name}:::onNumberConstant`)} function to infer intervals for visited control flow vertices that represent numeric constants. For numeric constants, the resulting interval consists just of the number value of the constant. We then update the current abstract state of the visitor by setting the inferred abstract value of the currently visited control flow vertex to the new interval.
|
|
130
|
+
The interval inference visitor first overrides the ${ctx.link(`${semantic_cfg_guided_visitor_1.SemanticCfgGuidedVisitor.name}:::onNumberConstant`)} function to infer intervals for visited control flow vertices that represent numeric constants. For numeric constants, the resulting interval consists just of the number value of the constant. We then update the current abstract state of the visitor via ${ctx.linkM(absint_visitor_1.AbstractInterpretationVisitor, 'updateState', { hideClass: true })} by setting the inferred abstract value of the currently visited control flow vertex to the new interval.
|
|
132
131
|
|
|
133
|
-
In this simple example, we only want to support the addition and subtraction of numeric values. Therefore, we override the ${ctx.link(`${absint_visitor_1.AbstractInterpretationVisitor.name}:::onFunctionCall`)} function to apply the abstract semantics of additions and subtraction with resprect to the interval domain. For the addition and subtraction, we are only interested in function calls with exactly two non-empty arguments. We first resolve the currently inferred abstract value for the left and right operand of the function call. If we have no inferred value for one of the operands, this function call might not be a numeric function call and we ignore it. Otherwise, we check whether the function call represents an addition or subtraction and apply the abstract semantics of the operation to the left and right operand. We then again update the current abstract state of the visitor by setting the inferred abstract value of the currently visited function call vertex to the abstract value resulting from applying the abstract semantics of the operation to the operands.
|
|
132
|
+
In this simple example, we only want to support the addition and subtraction of numeric values. Therefore, we override the ${ctx.link(`${absint_visitor_1.AbstractInterpretationVisitor.name}:::onFunctionCall`)} function to apply the abstract semantics of additions and subtraction with resprect to the interval domain. For the addition and subtraction, we are only interested in function calls with exactly two non-empty arguments. We first resolve the currently inferred abstract value for the left and right operand of the function call. If we have no inferred value for one of the operands, this function call might not be a numeric function call and we ignore it. Otherwise, we check whether the function call represents an addition or subtraction and apply the abstract semantics of the operation to the left and right operand. We then again update the current abstract state of the visitor via ${ctx.linkM(absint_visitor_1.AbstractInterpretationVisitor, 'updateState', { hideClass: true })} by setting the inferred abstract value of the currently visited function call vertex to the abstract value resulting from applying the abstract semantics of the operation to the operands.
|
|
134
133
|
|
|
135
134
|
If we now want to run the interval inference, we can write the following code:
|
|
136
135
|
|
|
137
136
|
${ctx.code(inferIntervals, { dropLinesStart: 1, dropLinesEnd: 5 })}
|
|
138
137
|
|
|
139
|
-
We first need a ${ctx.linkPage('wiki/Analyzer', 'flowR analyzer')} (in this case, using the ${ctx.linkPage('wiki/Engines', 'tree-sitter engine')}). In this example, we want to analyze a small example code that assigns \`42\` to the variable \`x\`, randomly assigns \`6\` or \`12\` to the variable \`y\`, and assignes the sum of \`x\` and \`y\` to the variable \`z\`. For the abstract interpretation visitor, we need to retrieve the ${ctx.linkPage('wiki/Normalized AST', 'normalized AST')}, ${ctx.linkPage('wiki/Dataflow Graph', 'dataflow graph')}, ${ctx.linkPage('wiki/Control Flow Graph', 'control flow graph')}, and context of the flowR anaylzer.
|
|
138
|
+
We first need a ${ctx.linkPage('wiki/Analyzer', 'flowR analyzer')} (in this case, using the ${ctx.linkPage('wiki/Engines', 'tree-sitter engine')}). In this example, we want to analyze a small example code that assigns \`42\` to the variable \`x\`, randomly assigns \`6\` or \`12\` to the variable \`y\`, and assignes the sum of \`x\` and \`y\` to the variable \`z\`. For the abstract interpretation visitor, we need to retrieve the ${ctx.linkPage('wiki/Normalized AST', 'normalized AST')}, ${ctx.linkPage('wiki/Dataflow Graph', 'dataflow graph')}, ${ctx.linkPage('wiki/Control Flow Graph', 'control flow graph')}, and context of the flowR anaylzer. For performance reasons, we construct the control flow graph without simplification passes, data flow information, and function definitions. We then create a new ${ctx.link(IntervalInferenceVisitor)} using the control flow graph, dataflow graph, normalized AST, and analyzer context, and start the visitor using ${ctx.linkM(absint_visitor_1.AbstractInterpretationVisitor, 'start', { hideClass: true })}. After the visitor is finished, we retrieve the inferred abstract state at the end of the program using ${ctx.linkM(absint_visitor_1.AbstractInterpretationVisitor, 'getEndState', { hideClass: true })}.
|
|
140
139
|
|
|
141
140
|
If we now print the inferred abstract state at the end of the program, we get the following output:
|
|
142
141
|
|