@eagleoutice/flowr 2.6.3 → 2.7.0
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 +13 -13
- package/abstract-interpretation/data-frame/absint-visitor.d.ts +1 -1
- package/abstract-interpretation/data-frame/absint-visitor.js +3 -3
- package/abstract-interpretation/data-frame/dataframe-domain.d.ts +4 -7
- package/abstract-interpretation/data-frame/dataframe-domain.js +5 -11
- package/abstract-interpretation/data-frame/mappers/access-mapper.d.ts +3 -1
- package/abstract-interpretation/data-frame/mappers/access-mapper.js +3 -2
- package/abstract-interpretation/data-frame/mappers/arguments.js +2 -2
- package/abstract-interpretation/data-frame/mappers/assignment-mapper.d.ts +3 -1
- package/abstract-interpretation/data-frame/mappers/assignment-mapper.js +3 -2
- package/abstract-interpretation/data-frame/mappers/function-mapper.d.ts +1 -1
- package/abstract-interpretation/data-frame/mappers/function-mapper.js +8 -8
- package/abstract-interpretation/data-frame/mappers/replacement-mapper.d.ts +3 -1
- package/abstract-interpretation/data-frame/mappers/replacement-mapper.js +3 -2
- package/abstract-interpretation/data-frame/semantics.js +47 -42
- package/abstract-interpretation/data-frame/shape-inference.d.ts +1 -1
- package/abstract-interpretation/domains/abstract-domain.d.ts +1 -0
- package/abstract-interpretation/domains/abstract-domain.js +3 -2
- package/abstract-interpretation/domains/bounded-set-domain.js +1 -1
- package/abstract-interpretation/domains/interval-domain.d.ts +2 -2
- package/abstract-interpretation/domains/interval-domain.js +3 -6
- package/abstract-interpretation/domains/lattice.d.ts +2 -0
- package/abstract-interpretation/domains/lattice.js +3 -1
- package/abstract-interpretation/domains/positive-interval-domain.d.ts +1 -1
- package/abstract-interpretation/domains/positive-interval-domain.js +1 -1
- package/abstract-interpretation/domains/satisfiable-domain.d.ts +2 -2
- package/abstract-interpretation/domains/satisfiable-domain.js +2 -2
- package/abstract-interpretation/domains/set-range-domain.d.ts +98 -0
- package/abstract-interpretation/domains/set-range-domain.js +400 -0
- package/abstract-interpretation/domains/set-upper-bound-domain.js +2 -2
- package/abstract-interpretation/domains/singleton-domain.js +2 -2
- package/benchmark/slicer.d.ts +2 -1
- package/benchmark/slicer.js +37 -15
- package/benchmark/stats/print.js +8 -5
- package/benchmark/stats/stats.d.ts +3 -2
- package/benchmark/summarizer/data.d.ts +11 -8
- package/benchmark/summarizer/first-phase/process.js +11 -8
- package/benchmark/summarizer/second-phase/process.js +24 -18
- package/control-flow/cfg-dead-code.js +3 -2
- package/control-flow/useless-loop.js +4 -2
- package/core/steps/all/static-slicing/00-slice.d.ts +3 -0
- package/core/steps/all/static-slicing/00-slice.js +2 -1
- package/core/steps/pipeline/default-pipelines.d.ts +42 -42
- package/dataflow/cluster.js +2 -2
- package/dataflow/environments/append.d.ts +5 -0
- package/dataflow/environments/append.js +6 -20
- package/dataflow/environments/built-in.d.ts +2 -1
- package/dataflow/environments/clone.d.ts +1 -1
- package/dataflow/environments/clone.js +3 -27
- package/dataflow/environments/define.d.ts +7 -3
- package/dataflow/environments/define.js +9 -56
- package/dataflow/environments/diff.js +1 -1
- package/dataflow/environments/environment.d.ts +48 -28
- package/dataflow/environments/environment.js +187 -62
- package/dataflow/environments/overwrite.js +2 -45
- package/dataflow/environments/reference-to-maybe.d.ts +13 -0
- package/dataflow/environments/reference-to-maybe.js +54 -0
- package/dataflow/environments/resolve-by-name.d.ts +6 -1
- package/dataflow/environments/resolve-by-name.js +56 -4
- package/dataflow/environments/scoping.d.ts +2 -2
- package/dataflow/environments/scoping.js +7 -7
- package/dataflow/eval/resolve/alias-tracking.d.ts +10 -4
- package/dataflow/eval/resolve/alias-tracking.js +15 -13
- package/dataflow/eval/resolve/resolve-argument.d.ts +2 -1
- package/dataflow/eval/resolve/resolve-argument.js +8 -8
- package/dataflow/eval/resolve/resolve.d.ts +13 -11
- package/dataflow/eval/resolve/resolve.js +16 -15
- package/dataflow/extractor.js +1 -7
- package/dataflow/fn/higher-order-function.d.ts +2 -1
- package/dataflow/fn/higher-order-function.js +4 -4
- package/dataflow/graph/dataflowgraph-builder.d.ts +9 -5
- package/dataflow/graph/dataflowgraph-builder.js +21 -11
- package/dataflow/graph/diff-dataflow-graph.js +2 -2
- package/dataflow/graph/graph.d.ts +10 -2
- package/dataflow/graph/graph.js +41 -12
- package/dataflow/graph/invert-dfg.d.ts +3 -2
- package/dataflow/graph/invert-dfg.js +3 -3
- package/dataflow/graph/resolve-graph.d.ts +2 -1
- package/dataflow/graph/resolve-graph.js +2 -2
- package/dataflow/graph/vertex.d.ts +3 -3
- package/dataflow/graph/vertex.js +3 -3
- package/dataflow/info.d.ts +1 -1
- package/dataflow/internal/linker.js +3 -7
- package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +7 -1
- package/dataflow/internal/process/functions/call/argument/unpack-argument.js +12 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +9 -9
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +9 -7
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +9 -13
- package/dataflow/internal/process/functions/call/built-in/built-in-get.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.d.ts +3 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +8 -6
- package/dataflow/internal/process/functions/call/built-in/built-in-library.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-rm.js +6 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +5 -5
- package/dataflow/internal/process/functions/call/common.js +2 -3
- package/dataflow/internal/process/functions/call/known-call-handling.js +1 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +1 -1
- package/dataflow/internal/process/functions/process-argument.js +1 -1
- package/dataflow/internal/process/process-symbol.js +1 -1
- package/dataflow/internal/process/process-value.d.ts +1 -1
- package/dataflow/internal/process/process-value.js +7 -7
- package/dataflow/processor.d.ts +1 -5
- package/documentation/doc-util/doc-dfg.js +3 -2
- package/documentation/doc-util/doc-normalized-ast.js +3 -2
- package/documentation/doc-util/doc-types.d.ts +1 -1
- package/documentation/doc-util/doc-types.js +2 -2
- package/documentation/wiki-analyzer.js +14 -1
- package/documentation/wiki-dataflow-graph.js +4 -5
- package/documentation/wiki-faq.js +0 -1
- package/documentation/wiki-linter.js +1 -1
- package/documentation/wiki-mk/doc-maker.js +2 -1
- package/linter/linter-rules.d.ts +2 -2
- package/linter/rules/absolute-path.js +4 -4
- package/linter/rules/dataframe-access-validation.d.ts +1 -1
- package/linter/rules/dataframe-access-validation.js +1 -1
- package/linter/rules/function-finder-util.d.ts +2 -2
- package/linter/rules/function-finder-util.js +1 -1
- package/linter/rules/network-functions.js +1 -1
- package/linter/rules/seeded-randomness.d.ts +1 -1
- package/linter/rules/seeded-randomness.js +5 -5
- package/package.json +1 -2
- package/project/context/flowr-analyzer-context.d.ts +7 -0
- package/project/context/flowr-analyzer-context.js +3 -0
- package/project/context/flowr-analyzer-environment-context.d.ts +47 -0
- package/project/context/flowr-analyzer-environment-context.js +50 -0
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -4
- package/queries/catalog/control-flow-query/control-flow-query-format.js +3 -2
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-executor.js +1 -1
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +4 -4
- package/queries/catalog/df-shape-query/df-shape-query-executor.d.ts +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-executor.js +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +4 -4
- package/queries/catalog/df-shape-query/df-shape-query-format.js +2 -2
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.js +3 -3
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +1 -1
- package/queries/catalog/static-slice-query/static-slice-query-executor.js +1 -1
- package/slicing/static/slice-call.d.ts +3 -2
- package/slicing/static/slice-call.js +4 -4
- package/slicing/static/static-slicer.d.ts +3 -1
- package/slicing/static/static-slicer.js +6 -7
- package/statistics/features/supported/control-flow/control-flow.js +1 -1
- package/statistics/features/supported/used-functions/used-functions.js +1 -1
- package/statistics/features/supported/variables/variables.js +2 -1
- package/util/containers.js +1 -1
- package/util/mermaid/dfg.d.ts +1 -0
- package/util/mermaid/dfg.js +3 -3
- package/util/simple-df/dfg-view.d.ts +2 -1
- package/util/simple-df/dfg-view.js +2 -2
- package/util/version.js +1 -1
- package/dataflow/environments/remove.d.ts +0 -12
- package/dataflow/environments/remove.js +0 -52
|
@@ -49,15 +49,15 @@ function buildQuickFix(str, filePath, wd) {
|
|
|
49
49
|
}
|
|
50
50
|
/** return all strings constructable by these functions */
|
|
51
51
|
const PathFunctions = {
|
|
52
|
-
'file.path': (df, vtx,
|
|
53
|
-
const fsep = (0, resolve_argument_1.getArgumentStringValue)(config.solver.variables, df, vtx, undefined, 'fsep', true);
|
|
52
|
+
'file.path': (df, vtx, ctx) => {
|
|
53
|
+
const fsep = (0, resolve_argument_1.getArgumentStringValue)(ctx.config.solver.variables, df, vtx, undefined, 'fsep', true, ctx);
|
|
54
54
|
// in the future we can access `.Platform$file.sep` here
|
|
55
55
|
const sepValues = fsep?.values()?.flatMap(s => s.values().filter(assert_1.isNotUndefined)).toArray() ?? [path_1.default.sep];
|
|
56
56
|
if (sepValues.some(s => s === dependencies_query_format_1.Unknown || (0, assert_1.isUndefined)(s))) {
|
|
57
57
|
// if we have no fsep, we cannot construct a path
|
|
58
58
|
return undefined;
|
|
59
59
|
}
|
|
60
|
-
const args = (0, resolve_argument_1.getArgumentStringValue)(config.solver.variables, df, vtx, 'unnamed', undefined, true);
|
|
60
|
+
const args = (0, resolve_argument_1.getArgumentStringValue)(ctx.config.solver.variables, df, vtx, 'unnamed', undefined, true, ctx);
|
|
61
61
|
const argValues = args ? Array.from(args.values()).flatMap(v => [...v]) : [];
|
|
62
62
|
if (!argValues || argValues.length === 0 || argValues.some(v => v === dependencies_query_format_1.Unknown || (0, assert_1.isUndefined)(v))) {
|
|
63
63
|
// if we have no arguments, we cannot construct a path
|
|
@@ -139,7 +139,7 @@ exports.ABSOLUTE_PATH = {
|
|
|
139
139
|
const dfNode = data.dataflow.graph.getVertex(node.info.id);
|
|
140
140
|
if ((0, vertex_1.isFunctionCallVertex)(dfNode)) {
|
|
141
141
|
const handler = PathFunctions[dfNode.name ?? ''];
|
|
142
|
-
const strings = handler ? handler(data.dataflow.graph, dfNode, data.analyzer.
|
|
142
|
+
const strings = handler ? handler(data.dataflow.graph, dfNode, data.analyzer.inspectContext()) : [];
|
|
143
143
|
if (strings) {
|
|
144
144
|
return strings.filter(s => (0, strings_1.isAbsolutePath)(s, regex)).map(str => ({
|
|
145
145
|
certainty: linter_format_1.LintingResultCertainty.Uncertain,
|
|
@@ -47,7 +47,7 @@ export declare const DATA_FRAME_ACCESS_VALIDATION: {
|
|
|
47
47
|
readonly name: "Dataframe Access Validation";
|
|
48
48
|
readonly tags: readonly [LintingRuleTag.Bug, LintingRuleTag.Usability, LintingRuleTag.Reproducibility];
|
|
49
49
|
readonly certainty: LintingRuleCertainty.BestEffort;
|
|
50
|
-
readonly description: "Validates the
|
|
50
|
+
readonly description: "Validates the existence of accessed columns and rows of dataframes.";
|
|
51
51
|
readonly defaultConfig: {
|
|
52
52
|
readonly readLoadedData: false;
|
|
53
53
|
};
|
|
@@ -85,7 +85,7 @@ exports.DATA_FRAME_ACCESS_VALIDATION = {
|
|
|
85
85
|
tags: [linter_tags_1.LintingRuleTag.Bug, linter_tags_1.LintingRuleTag.Usability, linter_tags_1.LintingRuleTag.Reproducibility],
|
|
86
86
|
// this rule is unable to detect all cases of dataframe access, but sufficiently ensures returned results are valid
|
|
87
87
|
certainty: linter_format_1.LintingRuleCertainty.BestEffort,
|
|
88
|
-
description: 'Validates the
|
|
88
|
+
description: 'Validates the existence of accessed columns and rows of dataframes.',
|
|
89
89
|
defaultConfig: { readLoadedData: false }
|
|
90
90
|
}
|
|
91
91
|
};
|
|
@@ -5,8 +5,8 @@ import type { FlowrSearchElement, FlowrSearchElements } from '../../search/flowr
|
|
|
5
5
|
import type { NormalizedAst, ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
6
6
|
import type { MergeableRecord } from '../../util/objects';
|
|
7
7
|
import type { DataflowInformation } from '../../dataflow/info';
|
|
8
|
-
import type { FlowrConfigOptions } from '../../config';
|
|
9
8
|
import type { FunctionInfo } from '../../queries/catalog/dependencies-query/function-info/function-info';
|
|
9
|
+
import type { ReadonlyFlowrAnalysisProvider } from '../../project/flowr-analyzer';
|
|
10
10
|
export interface FunctionsResult extends LintingResult {
|
|
11
11
|
function: string;
|
|
12
12
|
range: SourceRange;
|
|
@@ -41,6 +41,6 @@ export declare const functionFinderUtil: {
|
|
|
41
41
|
requireArgumentValue(element: FlowrSearchElement<ParentInformation>, pool: readonly FunctionInfo[], data: {
|
|
42
42
|
normalize: NormalizedAst;
|
|
43
43
|
dataflow: DataflowInformation;
|
|
44
|
-
|
|
44
|
+
analyzer: ReadonlyFlowrAnalysisProvider;
|
|
45
45
|
}, requireValue: RegExp | string | undefined): boolean;
|
|
46
46
|
};
|
|
@@ -65,7 +65,7 @@ exports.functionFinderUtil = {
|
|
|
65
65
|
}
|
|
66
66
|
const vert = data.dataflow.graph.getVertex(element.node.info.id);
|
|
67
67
|
if ((0, vertex_1.isFunctionCallVertex)(vert)) {
|
|
68
|
-
const args = (0, resolve_argument_1.getArgumentStringValue)(data.
|
|
68
|
+
const args = (0, resolve_argument_1.getArgumentStringValue)(data.analyzer.flowrConfig.solver.variables, data.dataflow.graph, vert, info.argIdx, info.argName, info.resolveValue, data.analyzer.inspectContext());
|
|
69
69
|
// we obtain all values, at least one of them has to trigger for the request
|
|
70
70
|
const argValues = args ? args.values().flatMap(v => [...v]).filter(assert_1.isNotUndefined).toArray() : [];
|
|
71
71
|
/* if there are no arguments we assume they may access the network, otherwise we check for the flag */
|
|
@@ -7,7 +7,7 @@ const linter_tags_1 = require("../linter-tags");
|
|
|
7
7
|
const read_functions_1 = require("../../queries/catalog/dependencies-query/function-info/read-functions");
|
|
8
8
|
exports.NETWORK_FUNCTIONS = {
|
|
9
9
|
createSearch: (config) => function_finder_util_1.functionFinderUtil.createSearch(config.fns),
|
|
10
|
-
processSearchResult: (e, c, d) => function_finder_util_1.functionFinderUtil.processSearchResult(e, c, d, es => es.filter(e => function_finder_util_1.functionFinderUtil.requireArgumentValue(e, read_functions_1.ReadFunctions, {
|
|
10
|
+
processSearchResult: (e, c, d) => function_finder_util_1.functionFinderUtil.processSearchResult(e, c, d, es => es.filter(e => function_finder_util_1.functionFinderUtil.requireArgumentValue(e, read_functions_1.ReadFunctions, { analyzer: d.analyzer, dataflow: d.dataflow, normalize: d.normalize }, c.onlyTriggerWithArgument))),
|
|
11
11
|
prettyPrint: function_finder_util_1.functionFinderUtil.prettyPrint('network operations'),
|
|
12
12
|
info: {
|
|
13
13
|
name: 'Network Functions',
|
|
@@ -31,7 +31,7 @@ export interface SeededRandomnessMeta extends MergeableRecord {
|
|
|
31
31
|
}
|
|
32
32
|
export declare const SEEDED_RANDOMNESS: {
|
|
33
33
|
readonly createSearch: (config: SeededRandomnessConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter", "with"], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, Promise<import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>>;
|
|
34
|
-
readonly processSearchResult: (elements: import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>, config: SeededRandomnessConfig, { dataflow }: {
|
|
34
|
+
readonly processSearchResult: (elements: import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>, config: SeededRandomnessConfig, { dataflow, analyzer }: {
|
|
35
35
|
normalize: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
36
36
|
dataflow: import("../../dataflow/info").DataflowInformation;
|
|
37
37
|
cfg: import("../../control-flow/control-flow-graph").ControlFlowInformation;
|
|
@@ -31,7 +31,7 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
31
31
|
{ callName: config.randomnessProducers.filter(p => p.type === 'function').map(p => p.name) },
|
|
32
32
|
{ callName: getDefaultAssignments().flatMap(b => b.names), cascadeIf: () => cascade_action_1.CascadeAction.Continue }
|
|
33
33
|
]),
|
|
34
|
-
processSearchResult: (elements, config, { dataflow }) => {
|
|
34
|
+
processSearchResult: (elements, config, { dataflow, analyzer }) => {
|
|
35
35
|
const assignmentProducers = new Set(config.randomnessProducers.filter(p => p.type == 'assignment').map(p => p.name));
|
|
36
36
|
const assignmentArgIndexes = new Map(getDefaultAssignments().flatMap(a => a.names.map(n => ([n, a.config?.swapSourceAndTarget ? 1 : 0]))));
|
|
37
37
|
const metadata = {
|
|
@@ -63,7 +63,7 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
63
63
|
let otherBranch = false;
|
|
64
64
|
// function calls are already taken care of through the LastCall enrichment itself
|
|
65
65
|
for (const f of func ?? []) {
|
|
66
|
-
if (isConstantArgument(dataflow.graph, f, 0)) {
|
|
66
|
+
if (isConstantArgument(dataflow.graph, f, 0, analyzer.inspectContext())) {
|
|
67
67
|
const fCds = new Set(f.cds).difference(cds);
|
|
68
68
|
if (fCds.size <= 0 || (0, info_1.happensInEveryBranchSet)(fCds)) {
|
|
69
69
|
metadata.callsWithFunctionProducers++;
|
|
@@ -83,7 +83,7 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
83
83
|
const dest = (0, graph_1.getReferenceOfArgument)(a.args[argIdx]);
|
|
84
84
|
if (dest !== undefined && assignmentProducers.has((0, node_id_1.recoverName)(dest, dataflow.graph.idMap))) {
|
|
85
85
|
// we either have arg index 0 or 1 for the assignmentProducers destination, so we select the assignment value as 1-argIdx here
|
|
86
|
-
if (isConstantArgument(dataflow.graph, a, 1 - argIdx)) {
|
|
86
|
+
if (isConstantArgument(dataflow.graph, a, 1 - argIdx, analyzer.inspectContext())) {
|
|
87
87
|
const aCds = new Set(a.cds).difference(cds);
|
|
88
88
|
if (aCds.size <= 0 || (0, info_1.happensInEveryBranchSet)(aCds)) {
|
|
89
89
|
metadata.callsWithAssignmentProducers++;
|
|
@@ -132,9 +132,9 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
132
132
|
function getDefaultAssignments() {
|
|
133
133
|
return default_builtin_config_1.DefaultBuiltinConfig.filter(b => b.type === 'function' && b.processor == 'builtin:assignment');
|
|
134
134
|
}
|
|
135
|
-
function isConstantArgument(graph, call, argIndex) {
|
|
135
|
+
function isConstantArgument(graph, call, argIndex, ctx) {
|
|
136
136
|
const args = call.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.getReferenceOfArgument);
|
|
137
|
-
const values = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(args[argIndex], { graph: graph, resolve: config_1.VariableResolve.Alias }));
|
|
137
|
+
const values = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(args[argIndex], { graph: graph, resolve: config_1.VariableResolve.Alias, ctx }));
|
|
138
138
|
return values?.elements.every(v => v.type === 'number' ||
|
|
139
139
|
v.type === 'logical' ||
|
|
140
140
|
v.type === 'string' ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eagleoutice/flowr",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
|
|
5
5
|
"types": "dist/src/index.d.ts",
|
|
6
6
|
"repository": {
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
"capabilities-markdown": "ts-node src/documentation/doc-capabilities.ts",
|
|
29
29
|
"wiki": "ts-node src/cli/wiki.ts",
|
|
30
30
|
"wiki:watch": "ts-node-dev src/cli/wiki.ts -- --keep-alive",
|
|
31
|
-
"wiki:linter": "ts-node src/documentation/wiki-linter.ts",
|
|
32
31
|
"build": "tsc --project .",
|
|
33
32
|
"build-dev": "npm run build && npm run build:copy-wasm",
|
|
34
33
|
"build:bundle-flowr": "npm run build && esbuild --bundle dist/src/cli/flowr.js --platform=node --tree-shaking=true --bundle --minify --external:clipboardy --target=node22 --outfile=dist/src/cli/flowr.min.js && npm run build:copy-wasm",
|
|
@@ -4,6 +4,8 @@ import { type FlowrAnalyzerPlugin, PluginType } from '../plugins/flowr-analyzer-
|
|
|
4
4
|
import type { fileProtocol, RParseRequestFromFile, RParseRequests } from '../../r-bridge/retriever';
|
|
5
5
|
import type { FlowrConfigOptions } from '../../config';
|
|
6
6
|
import type { FlowrFileProvider } from './flowr-file';
|
|
7
|
+
import type { ReadOnlyFlowrAnalyzerEnvironmentContext } from './flowr-analyzer-environment-context';
|
|
8
|
+
import { FlowrAnalyzerEnvironmentContext } from './flowr-analyzer-environment-context';
|
|
7
9
|
/**
|
|
8
10
|
* This is a read-only interface to the {@link FlowrAnalyzerContext}.
|
|
9
11
|
* It prevents you from modifying the context, but allows you to inspect it (which is probably what you want when using the {@link FlowrAnalyzer}).
|
|
@@ -18,6 +20,10 @@ export interface ReadOnlyFlowrAnalyzerContext {
|
|
|
18
20
|
* The dependencies context provides access to the identified dependencies and their versions.
|
|
19
21
|
*/
|
|
20
22
|
readonly deps: ReadOnlyFlowrAnalyzerDependenciesContext;
|
|
23
|
+
/**
|
|
24
|
+
* The environment context provides access to the environment information used during analysis.
|
|
25
|
+
*/
|
|
26
|
+
readonly env: ReadOnlyFlowrAnalyzerEnvironmentContext;
|
|
21
27
|
/**
|
|
22
28
|
* The configuration options used by the analyzer.
|
|
23
29
|
*/
|
|
@@ -38,6 +44,7 @@ export interface ReadOnlyFlowrAnalyzerContext {
|
|
|
38
44
|
export declare class FlowrAnalyzerContext implements ReadOnlyFlowrAnalyzerContext {
|
|
39
45
|
readonly files: FlowrAnalyzerFilesContext;
|
|
40
46
|
readonly deps: FlowrAnalyzerDependenciesContext;
|
|
47
|
+
readonly env: FlowrAnalyzerEnvironmentContext;
|
|
41
48
|
readonly config: FlowrConfigOptions;
|
|
42
49
|
constructor(config: FlowrConfigOptions, plugins: ReadonlyMap<PluginType, readonly FlowrAnalyzerPlugin[]>);
|
|
43
50
|
/** delegate request addition */
|
|
@@ -11,6 +11,7 @@ const arrays_1 = require("../../util/collections/arrays");
|
|
|
11
11
|
const retriever_1 = require("../../r-bridge/retriever");
|
|
12
12
|
const config_1 = require("../../config");
|
|
13
13
|
const flowr_file_1 = require("./flowr-file");
|
|
14
|
+
const flowr_analyzer_environment_context_1 = require("./flowr-analyzer-environment-context");
|
|
14
15
|
/**
|
|
15
16
|
* This summarizes the other context layers used by the {@link FlowrAnalyzer}.
|
|
16
17
|
* Have a look at the attributes and layers listed below (e.g., {@link files} and {@link deps})
|
|
@@ -26,12 +27,14 @@ const flowr_file_1 = require("./flowr-file");
|
|
|
26
27
|
class FlowrAnalyzerContext {
|
|
27
28
|
files;
|
|
28
29
|
deps;
|
|
30
|
+
env;
|
|
29
31
|
config;
|
|
30
32
|
constructor(config, plugins) {
|
|
31
33
|
this.config = config;
|
|
32
34
|
const loadingOrder = new flowr_analyzer_loading_order_context_1.FlowrAnalyzerLoadingOrderContext(this, plugins.get(flowr_analyzer_plugin_1.PluginType.LoadingOrder));
|
|
33
35
|
this.files = new flowr_analyzer_files_context_1.FlowrAnalyzerFilesContext(loadingOrder, (plugins.get(flowr_analyzer_plugin_1.PluginType.ProjectDiscovery) ?? []), (plugins.get(flowr_analyzer_plugin_1.PluginType.FileLoad) ?? []));
|
|
34
36
|
this.deps = new flowr_analyzer_dependencies_context_1.FlowrAnalyzerDependenciesContext(this, (plugins.get(flowr_analyzer_plugin_1.PluginType.DependencyIdentification) ?? []));
|
|
37
|
+
this.env = new flowr_analyzer_environment_context_1.FlowrAnalyzerEnvironmentContext(this);
|
|
35
38
|
}
|
|
36
39
|
/** delegate request addition */
|
|
37
40
|
addRequests(requests) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { FlowrAnalyzerContext } from './flowr-analyzer-context';
|
|
2
|
+
import type { IEnvironment, REnvironmentInformation } from '../../dataflow/environments/environment';
|
|
3
|
+
import type { DeepReadonly } from 'ts-essentials';
|
|
4
|
+
import type { Fingerprint } from '../../slicing/static/fingerprint';
|
|
5
|
+
/**
|
|
6
|
+
* This is the read-only interface to the {@link FlowrAnalyzerEnvironmentContext},
|
|
7
|
+
* which provides access to the built-in environment used during analysis.
|
|
8
|
+
*/
|
|
9
|
+
export interface ReadOnlyFlowrAnalyzerEnvironmentContext {
|
|
10
|
+
/**
|
|
11
|
+
* Get the built-in environment used during analysis.
|
|
12
|
+
*/
|
|
13
|
+
get builtInEnvironment(): DeepReadonly<IEnvironment>;
|
|
14
|
+
/**
|
|
15
|
+
* Get the empty built-in environment used during analysis.
|
|
16
|
+
* The empty built-in environment only contains primitive definitions.
|
|
17
|
+
*/
|
|
18
|
+
get emptyBuiltInEnvironment(): DeepReadonly<IEnvironment>;
|
|
19
|
+
/**
|
|
20
|
+
* Create a new {@link REnvironmentInformation|environment} with the configured built-in environment as base.
|
|
21
|
+
*/
|
|
22
|
+
makeCleanEnv(): REnvironmentInformation;
|
|
23
|
+
/**
|
|
24
|
+
* Get the fingerprint of the clean environment with the configured built-in environment as base.
|
|
25
|
+
*/
|
|
26
|
+
getCleanEnvFingerprint(): Fingerprint;
|
|
27
|
+
/**
|
|
28
|
+
* Create a new {@link REnvironmentInformation|environment} with an empty built-in environment as base.
|
|
29
|
+
*/
|
|
30
|
+
makeCleanEnvWithEmptyBuiltIns(): REnvironmentInformation;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* This context is responsible for providing the built-in environment.
|
|
34
|
+
* It creates the built-in environment based on the configuration provided in the {@link FlowrAnalyzerContext}.
|
|
35
|
+
*/
|
|
36
|
+
export declare class FlowrAnalyzerEnvironmentContext implements ReadOnlyFlowrAnalyzerEnvironmentContext {
|
|
37
|
+
readonly name = "flowr-analyzer-environment-context";
|
|
38
|
+
private readonly builtInEnv;
|
|
39
|
+
private readonly emptyBuiltInEnv;
|
|
40
|
+
private builtInEnvFingerprint;
|
|
41
|
+
constructor(ctx: FlowrAnalyzerContext);
|
|
42
|
+
get builtInEnvironment(): DeepReadonly<IEnvironment>;
|
|
43
|
+
get emptyBuiltInEnvironment(): DeepReadonly<IEnvironment>;
|
|
44
|
+
makeCleanEnv(): REnvironmentInformation;
|
|
45
|
+
getCleanEnvFingerprint(): Fingerprint;
|
|
46
|
+
makeCleanEnvWithEmptyBuiltIns(): REnvironmentInformation;
|
|
47
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FlowrAnalyzerEnvironmentContext = void 0;
|
|
4
|
+
const environment_1 = require("../../dataflow/environments/environment");
|
|
5
|
+
const built_in_config_1 = require("../../dataflow/environments/built-in-config");
|
|
6
|
+
const fingerprint_1 = require("../../slicing/static/fingerprint");
|
|
7
|
+
/**
|
|
8
|
+
* This context is responsible for providing the built-in environment.
|
|
9
|
+
* It creates the built-in environment based on the configuration provided in the {@link FlowrAnalyzerContext}.
|
|
10
|
+
*/
|
|
11
|
+
class FlowrAnalyzerEnvironmentContext {
|
|
12
|
+
name = 'flowr-analyzer-environment-context';
|
|
13
|
+
builtInEnv;
|
|
14
|
+
emptyBuiltInEnv;
|
|
15
|
+
builtInEnvFingerprint;
|
|
16
|
+
constructor(ctx) {
|
|
17
|
+
const builtInsConfig = ctx.config.semantics.environment.overwriteBuiltIns;
|
|
18
|
+
const builtIns = (0, built_in_config_1.getBuiltInDefinitions)(builtInsConfig.definitions, builtInsConfig.loadDefaults);
|
|
19
|
+
this.builtInEnv = new environment_1.Environment(undefined, true);
|
|
20
|
+
this.builtInEnv.memory = builtIns.builtInMemory;
|
|
21
|
+
this.emptyBuiltInEnv = new environment_1.Environment(undefined, true);
|
|
22
|
+
this.emptyBuiltInEnv.memory = builtIns.emptyBuiltInMemory;
|
|
23
|
+
}
|
|
24
|
+
get builtInEnvironment() {
|
|
25
|
+
return this.builtInEnv;
|
|
26
|
+
}
|
|
27
|
+
get emptyBuiltInEnvironment() {
|
|
28
|
+
return this.emptyBuiltInEnv;
|
|
29
|
+
}
|
|
30
|
+
makeCleanEnv() {
|
|
31
|
+
return {
|
|
32
|
+
current: new environment_1.Environment(this.builtInEnv),
|
|
33
|
+
level: 0
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
getCleanEnvFingerprint() {
|
|
37
|
+
if (!this.builtInEnvFingerprint) {
|
|
38
|
+
this.builtInEnvFingerprint = (0, fingerprint_1.envFingerprint)(this.makeCleanEnv());
|
|
39
|
+
}
|
|
40
|
+
return this.builtInEnvFingerprint;
|
|
41
|
+
}
|
|
42
|
+
makeCleanEnvWithEmptyBuiltIns() {
|
|
43
|
+
return {
|
|
44
|
+
current: new environment_1.Environment(this.emptyBuiltInEnv),
|
|
45
|
+
level: 0
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.FlowrAnalyzerEnvironmentContext = FlowrAnalyzerEnvironmentContext;
|
|
50
|
+
//# sourceMappingURL=flowr-analyzer-environment-context.js.map
|
|
@@ -192,10 +192,7 @@ async function executeCallContextQueries({ analyzer }, queries) {
|
|
|
192
192
|
cfg = await analyzer.controlflow([], cfg_kind_1.CfgKind.WithDataflow);
|
|
193
193
|
}
|
|
194
194
|
const queriesWhichWantAliases = promotedQueries.filter(q => q.includeAliases);
|
|
195
|
-
for (const [nodeId, info] of dataflow.graph.
|
|
196
|
-
if (info.tag !== vertex_1.VertexType.FunctionCall) {
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
195
|
+
for (const [nodeId, info] of dataflow.graph.verticesOfType(vertex_1.VertexType.FunctionCall)) {
|
|
199
196
|
/* if we have a vertex, and we check for aliased calls, we want to know if we define this as desired! */
|
|
200
197
|
if (queriesWhichWantAliases.length > 0) {
|
|
201
198
|
/*
|
|
@@ -26,9 +26,10 @@ exports.ControlFlowQueryDefinition = {
|
|
|
26
26
|
}).description('The control flow query provides the control flow graph of the analysis, optionally simplified.'),
|
|
27
27
|
flattenInvolvedNodes: (queryResults) => {
|
|
28
28
|
const out = queryResults;
|
|
29
|
-
return
|
|
29
|
+
return out.controlFlow.graph.vertices(true).entries()
|
|
30
30
|
.filter(([, v]) => v.type !== control_flow_graph_1.CfgVertexType.Block)
|
|
31
|
-
.map(v => v[0])
|
|
31
|
+
.map(v => v[0])
|
|
32
|
+
.toArray();
|
|
32
33
|
}
|
|
33
34
|
};
|
|
34
35
|
//# sourceMappingURL=control-flow-query-format.js.map
|
|
@@ -20,7 +20,7 @@ async function executeDataflowLensQuery({ analyzer }, queries) {
|
|
|
20
20
|
nameRegex: '<-|<<-|->|->>|=|+|-|*|/|\\|>|function|repeat|if|next|break',
|
|
21
21
|
blacklistWithName: true
|
|
22
22
|
}
|
|
23
|
-
});
|
|
23
|
+
}, analyzer.inspectContext().env.makeCleanEnv());
|
|
24
24
|
const timing = Date.now() - now;
|
|
25
25
|
return {
|
|
26
26
|
'.meta': {
|
|
@@ -76,8 +76,8 @@ function getResults(queries, { dataflow, config, normalize }, results, kind, fun
|
|
|
76
76
|
return kindEntries.flatMap(([name, results]) => results.flatMap(({ id, linkedIds }) => {
|
|
77
77
|
const vertex = dataflow.graph.getVertex(id);
|
|
78
78
|
const info = functionMap.get(name);
|
|
79
|
-
const args = (0, resolve_argument_1.getArgumentStringValue)(config.solver.variables, dataflow.graph, vertex, info.argIdx, info.argName, info.resolveValue);
|
|
80
|
-
const linkedArgs = collectValuesFromLinks(args, { dataflow, config }, linkedIds);
|
|
79
|
+
const args = (0, resolve_argument_1.getArgumentStringValue)(config.solver.variables, dataflow.graph, vertex, info.argIdx, info.argName, info.resolveValue, data.analyzer.inspectContext());
|
|
80
|
+
const linkedArgs = collectValuesFromLinks(args, { dataflow, config, ctx: data.analyzer.inspectContext() }, linkedIds);
|
|
81
81
|
const linked = dropInfoOnLinkedIds(linkedIds);
|
|
82
82
|
const foundValues = linkedArgs ?? args;
|
|
83
83
|
if (!foundValues) {
|
|
@@ -97,7 +97,7 @@ function getResults(queries, { dataflow, config, normalize }, results, kind, fun
|
|
|
97
97
|
(0, assert_1.guard)('mode' in (info.additionalArgs ?? {}), 'Need additional argument mode when checking for mode');
|
|
98
98
|
const margs = info.additionalArgs?.mode;
|
|
99
99
|
(0, assert_1.guard)(margs, 'Need additional argument mode when checking for mode');
|
|
100
|
-
const modeArgs = (0, resolve_argument_1.getArgumentStringValue)(config.solver.variables, dataflow.graph, vertex, margs.argIdx, margs.argName, margs.resolveValue);
|
|
100
|
+
const modeArgs = (0, resolve_argument_1.getArgumentStringValue)(config.solver.variables, dataflow.graph, vertex, margs.argIdx, margs.argName, margs.resolveValue, data?.analyzer.inspectContext());
|
|
101
101
|
const modeValues = modeArgs?.values().flatMap(v => [...v]) ?? [];
|
|
102
102
|
if (info.ignoreIf === 'mode-only-read' && modeValues.every(m => m && readOnlyModes.has(m))) {
|
|
103
103
|
// all modes are read-only, so we can ignore this
|
|
@@ -159,7 +159,7 @@ function collectValuesFromLinks(args, data, linkedIds) {
|
|
|
159
159
|
if (vertex === undefined || vertex.tag !== vertex_1.VertexType.FunctionCall) {
|
|
160
160
|
continue;
|
|
161
161
|
}
|
|
162
|
-
const args = (0, resolve_argument_1.getArgumentStringValue)(data.config.solver.variables, data.dataflow.graph, vertex, info.argIdx, info.argName, info.resolveValue);
|
|
162
|
+
const args = (0, resolve_argument_1.getArgumentStringValue)(data.config.solver.variables, data.dataflow.graph, vertex, info.argIdx, info.argName, info.resolveValue, data.ctx);
|
|
163
163
|
if (args === undefined) {
|
|
164
164
|
continue;
|
|
165
165
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BasicQueryData } from '../../base-query-format';
|
|
2
2
|
import type { DfShapeQuery, DfShapeQueryResult } from './df-shape-query-format';
|
|
3
3
|
/**
|
|
4
|
-
* Executes the given
|
|
4
|
+
* Executes the given data frame shape queries using the provided analyzer.
|
|
5
5
|
*/
|
|
6
6
|
export declare function executeDfShapeQuery({ analyzer }: BasicQueryData, queries: readonly DfShapeQuery[]): Promise<DfShapeQueryResult>;
|
|
@@ -5,7 +5,7 @@ const shape_inference_1 = require("../../../abstract-interpretation/data-frame/s
|
|
|
5
5
|
const parse_1 = require("../../../slicing/criterion/parse");
|
|
6
6
|
const log_1 = require("../../../util/log");
|
|
7
7
|
/**
|
|
8
|
-
* Executes the given
|
|
8
|
+
* Executes the given data frame shape queries using the provided analyzer.
|
|
9
9
|
*/
|
|
10
10
|
async function executeDfShapeQuery({ analyzer }, queries) {
|
|
11
11
|
if (queries.length !== 1 && queries.some(query => query.criterion === undefined)) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import Joi from 'joi';
|
|
1
2
|
import { type DataFrameDomain, DataFrameStateDomain } from '../../../abstract-interpretation/data-frame/dataframe-domain';
|
|
3
|
+
import type { ReplOutput } from '../../../cli/repl/commands/repl-main';
|
|
4
|
+
import type { FlowrConfigOptions } from '../../../config';
|
|
5
|
+
import type { SingleSlicingCriterion } from '../../../slicing/criterion/parse';
|
|
2
6
|
import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
|
|
3
7
|
import type { ParsedQueryLine } from '../../query';
|
|
4
8
|
import { executeDfShapeQuery } from './df-shape-query-executor';
|
|
5
|
-
import type { SingleSlicingCriterion } from '../../../slicing/criterion/parse';
|
|
6
|
-
import type { ReplOutput } from '../../../cli/repl/commands/repl-main';
|
|
7
|
-
import type { FlowrConfigOptions } from '../../../config';
|
|
8
|
-
import Joi from 'joi';
|
|
9
9
|
/** Infer the shape of data frames using abstract interpretation. */
|
|
10
10
|
export interface DfShapeQuery extends BaseQueryFormat {
|
|
11
11
|
readonly type: 'df-shape';
|
|
@@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.DfShapeQueryDefinition = void 0;
|
|
7
|
+
const joi_1 = __importDefault(require("joi"));
|
|
7
8
|
const dataframe_domain_1 = require("../../../abstract-interpretation/data-frame/dataframe-domain");
|
|
9
|
+
const slice_query_parser_1 = require("../../../cli/repl/parser/slice-query-parser");
|
|
8
10
|
const ansi_1 = require("../../../util/text/ansi");
|
|
9
11
|
const time_1 = require("../../../util/text/time");
|
|
10
12
|
const df_shape_query_executor_1 = require("./df-shape-query-executor");
|
|
11
|
-
const slice_query_parser_1 = require("../../../cli/repl/parser/slice-query-parser");
|
|
12
|
-
const joi_1 = __importDefault(require("joi"));
|
|
13
13
|
function dfShapeQueryLineParser(_output, line, _config) {
|
|
14
14
|
const criterion = (0, slice_query_parser_1.sliceCriterionParser)(line[0]);
|
|
15
15
|
return {
|
|
@@ -32,11 +32,11 @@ async function executeHigherOrderQuery({ analyzer }, queries) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
const graph = (await analyzer.dataflow()).graph;
|
|
35
|
-
const fns = graph.
|
|
36
|
-
.filter(([, v]) =>
|
|
35
|
+
const fns = graph.verticesOfType(vertex_1.VertexType.FunctionDefinition)
|
|
36
|
+
.filter(([, v]) => filterFor.size === 0 || filterFor.has(v.id));
|
|
37
37
|
const result = {};
|
|
38
38
|
for (const [id,] of fns) {
|
|
39
|
-
result[id] = (0, higher_order_function_1.isHigherOrder)(id, graph);
|
|
39
|
+
result[id] = (0, higher_order_function_1.isHigherOrder)(id, graph, analyzer.inspectContext());
|
|
40
40
|
}
|
|
41
41
|
return {
|
|
42
42
|
'.meta': {
|
|
@@ -26,7 +26,7 @@ async function executeResolveValueQuery({ analyzer }, queries) {
|
|
|
26
26
|
}
|
|
27
27
|
const values = query.criteria
|
|
28
28
|
.map(criteria => (0, parse_1.slicingCriterionToId)(criteria, ast.idMap))
|
|
29
|
-
.flatMap(ident => (0, alias_tracking_1.resolveIdToValue)(ident, { graph, full: true, idMap: ast.idMap, resolve: analyzer.flowrConfig.solver.variables }));
|
|
29
|
+
.flatMap(ident => (0, alias_tracking_1.resolveIdToValue)(ident, { graph, full: true, idMap: ast.idMap, resolve: analyzer.flowrConfig.solver.variables, ctx: analyzer.inspectContext() }));
|
|
30
30
|
results[key] = {
|
|
31
31
|
values: values
|
|
32
32
|
};
|
|
@@ -30,7 +30,7 @@ async function executeStaticSliceQuery({ analyzer }, queries) {
|
|
|
30
30
|
}
|
|
31
31
|
const { criteria, noReconstruction, noMagicComments } = query;
|
|
32
32
|
const sliceStart = Date.now();
|
|
33
|
-
const slice = (0, static_slicer_1.staticSlice)(await analyzer.dataflow(), await analyzer.normalize(), criteria, query.direction ?? _00_slice_1.SliceDirection.Backward, analyzer.flowrConfig.solver.slicer?.threshold);
|
|
33
|
+
const slice = (0, static_slicer_1.staticSlice)(analyzer.inspectContext(), await analyzer.dataflow(), await analyzer.normalize(), criteria, query.direction ?? _00_slice_1.SliceDirection.Backward, analyzer.flowrConfig.solver.slicer?.threshold);
|
|
34
34
|
const sliceEnd = Date.now();
|
|
35
35
|
if (noReconstruction) {
|
|
36
36
|
results[key] = { slice: { ...slice, '.meta': { timing: sliceEnd - sliceStart } } };
|
|
@@ -6,11 +6,12 @@ import type { REnvironmentInformation } from '../../dataflow/environments/enviro
|
|
|
6
6
|
import { type DataflowGraph, type OutgoingEdges } from '../../dataflow/graph/graph';
|
|
7
7
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
8
|
import type { DataflowInformation } from '../../dataflow/info';
|
|
9
|
+
import type { ReadOnlyFlowrAnalyzerContext } from '../../project/context/flowr-analyzer-context';
|
|
9
10
|
/**
|
|
10
11
|
* Returns the function call targets (definitions) by the given caller
|
|
11
12
|
*/
|
|
12
|
-
export declare function getAllFunctionCallTargets(dataflowGraph: DataflowGraph, callerInfo: DataflowGraphVertexFunctionCall, baseEnvironment: REnvironmentInformation, queue: VisitingQueue): [Set<DataflowGraphVertexInfo>, REnvironmentInformation];
|
|
13
|
+
export declare function getAllFunctionCallTargets(dataflowGraph: DataflowGraph, callerInfo: DataflowGraphVertexFunctionCall, baseEnvironment: REnvironmentInformation, queue: VisitingQueue, ctx: ReadOnlyFlowrAnalyzerContext): [Set<DataflowGraphVertexInfo>, REnvironmentInformation];
|
|
13
14
|
/** returns the new threshold hit count */
|
|
14
|
-
export declare function sliceForCall(current: NodeToSlice, callerInfo: DataflowGraphVertexFunctionCall, dataflowInformation: DataflowInformation, queue: VisitingQueue): void;
|
|
15
|
+
export declare function sliceForCall(current: NodeToSlice, callerInfo: DataflowGraphVertexFunctionCall, dataflowInformation: DataflowInformation, queue: VisitingQueue, ctx: ReadOnlyFlowrAnalyzerContext): void;
|
|
15
16
|
/** Returns true if we found at least one return edge */
|
|
16
17
|
export declare function handleReturns(from: NodeId, queue: VisitingQueue, currentEdges: OutgoingEdges, baseEnvFingerprint: Fingerprint, baseEnvironment: REnvironmentInformation): boolean;
|
|
@@ -16,12 +16,12 @@ const static_slicer_1 = require("./static-slicer");
|
|
|
16
16
|
/**
|
|
17
17
|
* Returns the function call targets (definitions) by the given caller
|
|
18
18
|
*/
|
|
19
|
-
function getAllFunctionCallTargets(dataflowGraph, callerInfo, baseEnvironment, queue) {
|
|
19
|
+
function getAllFunctionCallTargets(dataflowGraph, callerInfo, baseEnvironment, queue, ctx) {
|
|
20
20
|
// bind with call-local environments during slicing
|
|
21
21
|
const outgoingEdges = dataflowGraph.get(callerInfo.id, true);
|
|
22
22
|
(0, assert_1.guard)(outgoingEdges !== undefined, () => `outgoing edges of id: ${callerInfo.id} must be in graph but can not be found, keep in slice to be sure`);
|
|
23
23
|
// lift baseEnv on the same level
|
|
24
|
-
const activeEnvironment = (0, built_in_function_definition_1.retrieveActiveEnvironment)(callerInfo.environment, baseEnvironment);
|
|
24
|
+
const activeEnvironment = (0, built_in_function_definition_1.retrieveActiveEnvironment)(callerInfo.environment, baseEnvironment, ctx);
|
|
25
25
|
const name = callerInfo.name;
|
|
26
26
|
(0, assert_1.guard)(name !== undefined, () => `name of id: ${callerInfo.id} can not be found in id map`);
|
|
27
27
|
const functionCallDefs = (0, resolve_by_name_1.resolveByName)(name, activeEnvironment, identifier_1.ReferenceType.Unknown)?.filter(d => !(0, built_in_1.isBuiltIn)(d.definedAt))?.map(d => d.nodeId) ?? [];
|
|
@@ -59,9 +59,9 @@ function linkCallTargets(onlyForSideEffects, functionCallTargets, activeEnvironm
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
/** returns the new threshold hit count */
|
|
62
|
-
function sliceForCall(current, callerInfo, dataflowInformation, queue) {
|
|
62
|
+
function sliceForCall(current, callerInfo, dataflowInformation, queue, ctx) {
|
|
63
63
|
const baseEnvironment = current.baseEnvironment;
|
|
64
|
-
const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(dataflowInformation.graph, callerInfo, current.baseEnvironment, queue);
|
|
64
|
+
const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(dataflowInformation.graph, callerInfo, current.baseEnvironment, queue, ctx);
|
|
65
65
|
const activeEnvironmentFingerprint = (0, fingerprint_1.envFingerprint)(activeEnvironment);
|
|
66
66
|
if (functionCallTargets.size === 0) {
|
|
67
67
|
/*
|
|
@@ -7,11 +7,13 @@ import { type REnvironmentInformation } from '../../dataflow/environments/enviro
|
|
|
7
7
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
8
|
import { SliceDirection } from '../../core/steps/all/static-slicing/00-slice';
|
|
9
9
|
import type { DataflowInformation } from '../../dataflow/info';
|
|
10
|
+
import type { ReadOnlyFlowrAnalyzerContext } from '../../project/context/flowr-analyzer-context';
|
|
10
11
|
export declare const slicerLogger: import("tslog").Logger<import("tslog").ILogObj>;
|
|
11
12
|
/**
|
|
12
13
|
* This returns the ids to include in the static slice of the given type, when slicing with the given seed id's (must be at least one).
|
|
13
14
|
* <p>
|
|
14
15
|
* The returned ids can be used to {@link reconstructToCode|reconstruct the slice to R code}.
|
|
16
|
+
* @param ctx - The analyzer context used for slicing.
|
|
15
17
|
* @param info - The dataflow information used for slicing.
|
|
16
18
|
* @param idMap - The mapping from node ids to their information in the AST.
|
|
17
19
|
* @param criteria - The criteria to slice on.
|
|
@@ -19,7 +21,7 @@ export declare const slicerLogger: import("tslog").Logger<import("tslog").ILogOb
|
|
|
19
21
|
* @param threshold - The maximum number of nodes to visit in the graph. If the threshold is reached, the slice will side with inclusion and drop its minimal guarantee. The limit ensures that the algorithm halts.
|
|
20
22
|
* @param cache - A cache to store the results of the slice. If provided, the slice may use this cache to speed up the slicing process.
|
|
21
23
|
*/
|
|
22
|
-
export declare function staticSlice(info: DataflowInformation, { idMap }: NormalizedAst, criteria: SlicingCriteria, direction: SliceDirection, threshold?: number, cache?: Map<Fingerprint, Set<NodeId>>): Readonly<SliceResult>;
|
|
24
|
+
export declare function staticSlice(ctx: ReadOnlyFlowrAnalyzerContext, info: DataflowInformation, { idMap }: NormalizedAst, criteria: SlicingCriteria, direction: SliceDirection, threshold?: number, cache?: Map<Fingerprint, Set<NodeId>>): Readonly<SliceResult>;
|
|
23
25
|
/**
|
|
24
26
|
* Updates the potential addition for the given target node in the visiting queue.
|
|
25
27
|
* This describes vertices that might be added *if* another path reaches them.
|
|
@@ -5,11 +5,9 @@ exports.staticSlice = staticSlice;
|
|
|
5
5
|
exports.updatePotentialAddition = updatePotentialAddition;
|
|
6
6
|
const assert_1 = require("../../util/assert");
|
|
7
7
|
const log_1 = require("../../util/log");
|
|
8
|
-
const fingerprint_1 = require("./fingerprint");
|
|
9
8
|
const visiting_queue_1 = require("./visiting-queue");
|
|
10
9
|
const slice_call_1 = require("./slice-call");
|
|
11
10
|
const parse_1 = require("../criterion/parse");
|
|
12
|
-
const environment_1 = require("../../dataflow/environments/environment");
|
|
13
11
|
const vertex_1 = require("../../dataflow/graph/vertex");
|
|
14
12
|
const edge_1 = require("../../dataflow/graph/edge");
|
|
15
13
|
const _00_slice_1 = require("../../core/steps/all/static-slicing/00-slice");
|
|
@@ -19,6 +17,7 @@ exports.slicerLogger = log_1.log.getSubLogger({ name: 'slicer' });
|
|
|
19
17
|
* This returns the ids to include in the static slice of the given type, when slicing with the given seed id's (must be at least one).
|
|
20
18
|
* <p>
|
|
21
19
|
* The returned ids can be used to {@link reconstructToCode|reconstruct the slice to R code}.
|
|
20
|
+
* @param ctx - The analyzer context used for slicing.
|
|
22
21
|
* @param info - The dataflow information used for slicing.
|
|
23
22
|
* @param idMap - The mapping from node ids to their information in the AST.
|
|
24
23
|
* @param criteria - The criteria to slice on.
|
|
@@ -26,21 +25,21 @@ exports.slicerLogger = log_1.log.getSubLogger({ name: 'slicer' });
|
|
|
26
25
|
* @param threshold - The maximum number of nodes to visit in the graph. If the threshold is reached, the slice will side with inclusion and drop its minimal guarantee. The limit ensures that the algorithm halts.
|
|
27
26
|
* @param cache - A cache to store the results of the slice. If provided, the slice may use this cache to speed up the slicing process.
|
|
28
27
|
*/
|
|
29
|
-
function staticSlice(info, { idMap }, criteria, direction, threshold = 75, cache) {
|
|
28
|
+
function staticSlice(ctx, info, { idMap }, criteria, direction, threshold = 75, cache) {
|
|
30
29
|
(0, assert_1.guard)(criteria.length > 0, 'must have at least one seed id to calculate slice');
|
|
31
30
|
const decodedCriteria = (0, parse_1.convertAllSlicingCriteriaToIds)(criteria, idMap);
|
|
32
31
|
(0, log_1.expensiveTrace)(exports.slicerLogger, () => `calculating ${direction} slice for ${decodedCriteria.length} seed criteria: ${decodedCriteria.map(s => JSON.stringify(s)).join(', ')}`);
|
|
33
32
|
let { graph } = info;
|
|
34
33
|
if (direction === _00_slice_1.SliceDirection.Forward) {
|
|
35
|
-
graph = (0, invert_dfg_1.invertDfg)(graph);
|
|
34
|
+
graph = (0, invert_dfg_1.invertDfg)(graph, ctx.env.makeCleanEnv());
|
|
36
35
|
}
|
|
37
36
|
const queue = new visiting_queue_1.VisitingQueue(threshold, cache);
|
|
38
37
|
let minNesting = Number.MAX_SAFE_INTEGER;
|
|
39
38
|
const sliceSeedIds = new Set();
|
|
40
39
|
// every node ships the call environment which registers the calling environment
|
|
41
40
|
{
|
|
42
|
-
const emptyEnv =
|
|
43
|
-
const basePrint =
|
|
41
|
+
const emptyEnv = ctx.env.makeCleanEnv();
|
|
42
|
+
const basePrint = ctx.env.getCleanEnvFingerprint();
|
|
44
43
|
for (const { id: startId } of decodedCriteria) {
|
|
45
44
|
queue.add(startId, emptyEnv, basePrint, false);
|
|
46
45
|
// retrieve the minimum nesting of all nodes to only add control dependencies if they are "part" of the current execution
|
|
@@ -77,7 +76,7 @@ function staticSlice(info, { idMap }, criteria, direction, threshold = 75, cache
|
|
|
77
76
|
}
|
|
78
77
|
if (!onlyForSideEffects) {
|
|
79
78
|
if (currentVertex.tag === vertex_1.VertexType.FunctionCall && !currentVertex.onlyBuiltin) {
|
|
80
|
-
(0, slice_call_1.sliceForCall)(current, currentVertex, info, queue);
|
|
79
|
+
(0, slice_call_1.sliceForCall)(current, currentVertex, info, queue, ctx);
|
|
81
80
|
}
|
|
82
81
|
const ret = (0, slice_call_1.handleReturns)(id, queue, currentEdges, baseEnvFingerprint, baseEnvironment);
|
|
83
82
|
if (ret) {
|
|
@@ -23,7 +23,7 @@ function visitIfThenElse(info, input) {
|
|
|
23
23
|
(0, visitor_1.visitAst)(input.normalizedRAst.ast.files.map(f => f.root), node => {
|
|
24
24
|
if (node.type !== type_1.RType.IfThenElse) {
|
|
25
25
|
if (node.type === type_1.RType.FunctionCall && node.named && node.functionName.content === 'switch') {
|
|
26
|
-
const initialArg = (0, unpack_argument_1.
|
|
26
|
+
const initialArg = (0, unpack_argument_1.unpackNonameArg)(node.arguments[0]);
|
|
27
27
|
if (initialArg) {
|
|
28
28
|
info.switchCase = (0, common_syntax_probability_1.updateCommonSyntaxTypeCounts)(info.switchCase, initialArg);
|
|
29
29
|
}
|
|
@@ -84,7 +84,7 @@ function visitCalls(info, input) {
|
|
|
84
84
|
hasCallsEdge ? 1 : 0
|
|
85
85
|
]);
|
|
86
86
|
}
|
|
87
|
-
classifyArguments(node.arguments.map(e => (0, unpack_argument_1.
|
|
87
|
+
classifyArguments(node.arguments.map(e => (0, unpack_argument_1.unpackNonameArg)(e)), info.args);
|
|
88
88
|
calls.push(node);
|
|
89
89
|
}, node => {
|
|
90
90
|
// drop again :D
|