@eagleoutice/flowr 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -30
- package/abstract-interpretation/data-frame/absint-visitor.d.ts +2 -3
- package/abstract-interpretation/data-frame/absint-visitor.js +14 -16
- package/abstract-interpretation/data-frame/mappers/function-mapper.js +3 -3
- package/abstract-interpretation/data-frame/semantics.d.ts +1 -1
- package/abstract-interpretation/data-frame/semantics.js +7 -10
- package/abstract-interpretation/data-frame/shape-inference.js +2 -8
- package/benchmark/slicer.js +7 -5
- package/benchmark/stats/size-of.js +3 -3
- package/benchmark/summarizer/second-phase/graph.js +1 -1
- package/benchmark/summarizer/second-phase/process.js +1 -1
- package/cli/benchmark-app.d.ts +1 -0
- package/cli/benchmark-app.js +1 -0
- package/cli/benchmark-helper-app.d.ts +1 -0
- package/cli/benchmark-helper-app.js +4 -3
- package/cli/common/options.js +2 -0
- package/cli/repl/commands/repl-query.js +1 -1
- package/cli/repl/server/connection.js +14 -5
- package/control-flow/basic-cfg-guided-visitor.d.ts +1 -2
- package/control-flow/basic-cfg-guided-visitor.js +0 -6
- package/control-flow/cfg-simplification.d.ts +6 -0
- package/control-flow/cfg-simplification.js +18 -9
- package/control-flow/control-flow-graph.d.ts +2 -8
- package/control-flow/control-flow-graph.js +1 -6
- package/control-flow/extract-cfg.d.ts +2 -2
- package/control-flow/extract-cfg.js +52 -63
- package/core/pipeline-executor.js +0 -8
- package/core/steps/all/static-slicing/00-slice.d.ts +7 -1
- package/core/steps/all/static-slicing/00-slice.js +9 -3
- package/core/steps/pipeline/default-pipelines.d.ts +74 -74
- package/dataflow/environments/append.js +1 -1
- package/dataflow/environments/built-in-config.d.ts +12 -4
- package/dataflow/environments/built-in-config.js +23 -82
- package/dataflow/environments/built-in.d.ts +40 -6
- package/dataflow/environments/built-in.js +119 -23
- package/dataflow/environments/clone.d.ts +3 -2
- package/dataflow/environments/clone.js +6 -5
- package/dataflow/environments/define.js +1 -2
- package/dataflow/environments/diff.js +1 -3
- package/dataflow/environments/environment.d.ts +18 -24
- package/dataflow/environments/environment.js +25 -37
- package/dataflow/environments/overwrite.d.ts +1 -1
- package/dataflow/environments/overwrite.js +1 -1
- package/dataflow/environments/remove.d.ts +2 -2
- package/dataflow/environments/remove.js +3 -4
- package/dataflow/environments/resolve-by-name.d.ts +3 -3
- package/dataflow/environments/resolve-by-name.js +4 -5
- package/dataflow/eval/resolve/alias-tracking.d.ts +12 -12
- package/dataflow/eval/resolve/alias-tracking.js +12 -12
- package/dataflow/eval/resolve/resolve.js +1 -1
- package/dataflow/extractor.js +6 -1
- package/dataflow/graph/dataflowgraph-builder.d.ts +3 -1
- package/dataflow/graph/dataflowgraph-builder.js +2 -2
- package/dataflow/graph/graph.d.ts +2 -1
- package/dataflow/graph/graph.js +6 -2
- package/dataflow/graph/invert-dfg.d.ts +2 -0
- package/dataflow/graph/invert-dfg.js +17 -0
- package/dataflow/info.d.ts +1 -1
- package/dataflow/internal/linker.js +9 -9
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -5
- 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-function-definition.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-rm.js +1 -1
- package/dataflow/processor.d.ts +5 -1
- package/documentation/doc-util/doc-env.js +1 -2
- package/documentation/doc-util/doc-query.js +1 -1
- package/documentation/doc-util/doc-search.js +2 -2
- package/documentation/print-cfg-wiki.js +3 -4
- package/documentation/print-core-wiki.js +2 -2
- package/documentation/print-dataflow-graph-wiki.js +7 -0
- package/documentation/print-faq-wiki.js +4 -0
- package/documentation/print-linter-wiki.js +32 -4
- package/documentation/print-linting-and-testing-wiki.js +13 -1
- package/documentation/print-onboarding-wiki.js +4 -0
- package/documentation/print-query-wiki.js +12 -3
- package/linter/linter-executor.js +1 -2
- package/linter/linter-format.d.ts +26 -4
- package/linter/linter-format.js +25 -6
- package/linter/linter-rules.d.ts +40 -12
- package/linter/linter-rules.js +3 -1
- package/linter/rules/absolute-path.d.ts +4 -7
- package/linter/rules/absolute-path.js +9 -6
- package/linter/rules/dataframe-access-validation.d.ts +3 -1
- package/linter/rules/dataframe-access-validation.js +3 -1
- package/linter/rules/dead-code.d.ts +43 -0
- package/linter/rules/dead-code.js +50 -0
- package/linter/rules/deprecated-functions.d.ts +3 -2
- package/linter/rules/deprecated-functions.js +3 -1
- package/linter/rules/file-path-validity.d.ts +4 -4
- package/linter/rules/file-path-validity.js +8 -6
- package/linter/rules/naming-convention.d.ts +4 -3
- package/linter/rules/naming-convention.js +3 -1
- package/linter/rules/seeded-randomness.d.ts +4 -3
- package/linter/rules/seeded-randomness.js +3 -1
- package/linter/rules/unused-definition.d.ts +2 -0
- package/linter/rules/unused-definition.js +3 -1
- package/package.json +1 -1
- package/queries/base-query-format.d.ts +2 -0
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +7 -7
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +24 -1
- package/queries/catalog/dependencies-query/function-info/function-info.d.ts +9 -5
- package/queries/catalog/dependencies-query/function-info/read-functions.js +5 -2
- package/queries/catalog/dependencies-query/function-info/write-functions.js +6 -0
- package/queries/catalog/linter-query/linter-query-format.js +1 -1
- package/queries/catalog/location-map-query/location-map-query-executor.js +7 -5
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +3 -0
- package/queries/catalog/location-map-query/location-map-query-format.js +1 -0
- package/queries/catalog/search-query/search-query-executor.js +1 -1
- package/queries/catalog/static-slice-query/static-slice-query-executor.d.ts +1 -1
- package/queries/catalog/static-slice-query/static-slice-query-executor.js +3 -2
- package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +3 -0
- package/queries/catalog/static-slice-query/static-slice-query-format.js +3 -1
- package/queries/query-print.d.ts +1 -1
- package/queries/query-print.js +0 -1
- package/queries/query.d.ts +16 -5
- package/queries/query.js +24 -11
- package/search/flowr-search-builder.d.ts +6 -6
- package/search/flowr-search-executor.d.ts +2 -2
- package/search/flowr-search-executor.js +1 -1
- package/search/flowr-search.d.ts +13 -8
- package/search/flowr-search.js +21 -0
- package/search/search-executor/search-enrichers.d.ts +87 -20
- package/search/search-executor/search-enrichers.js +44 -5
- package/search/search-executor/search-generators.d.ts +4 -4
- package/search/search-executor/search-generators.js +12 -7
- package/search/search-executor/search-mappers.js +3 -2
- package/search/search-executor/search-transformer.d.ts +3 -3
- package/search/search-executor/search-transformer.js +2 -2
- package/slicing/static/fingerprint.js +1 -2
- package/slicing/static/slice-call.d.ts +2 -1
- package/slicing/static/slice-call.js +3 -3
- package/slicing/static/static-slicer.d.ts +6 -5
- package/slicing/static/static-slicer.js +13 -7
- package/util/collections/arrays.d.ts +2 -0
- package/util/collections/arrays.js +9 -0
- package/util/containers.d.ts +1 -0
- package/util/containers.js +1 -0
- package/util/json.js +1 -4
- package/util/mermaid/dfg.js +5 -4
- package/util/prefix.d.ts +1 -1
- package/util/range.d.ts +1 -0
- package/util/range.js +5 -1
- package/util/version.js +1 -1
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Enrichments = exports.Enrichment = void 0;
|
|
4
4
|
exports.enrichmentContent = enrichmentContent;
|
|
5
|
-
exports.
|
|
5
|
+
exports.enrichElement = enrichElement;
|
|
6
|
+
const objects_1 = require("../../util/objects");
|
|
6
7
|
const vertex_1 = require("../../dataflow/graph/vertex");
|
|
7
8
|
const identify_link_to_last_call_relation_1 = require("../../queries/catalog/call-context-query/identify-link-to-last-call-relation");
|
|
8
9
|
const assert_1 = require("../../util/assert");
|
|
9
10
|
const extract_cfg_1 = require("../../control-flow/extract-cfg");
|
|
10
11
|
const dfg_get_origin_1 = require("../../dataflow/origin/dfg-get-origin");
|
|
11
12
|
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
13
|
+
const cfg_simplification_1 = require("../../control-flow/cfg-simplification");
|
|
12
14
|
/**
|
|
13
15
|
* An enumeration that stores the names of the available enrichments that can be applied to a set of search elements.
|
|
14
16
|
* See {@link FlowrSearchBuilder.with} for more information on how to apply enrichments.
|
|
@@ -17,6 +19,8 @@ var Enrichment;
|
|
|
17
19
|
(function (Enrichment) {
|
|
18
20
|
Enrichment["CallTargets"] = "call-targets";
|
|
19
21
|
Enrichment["LastCall"] = "last-call";
|
|
22
|
+
Enrichment["CfgInformation"] = "cfg-information";
|
|
23
|
+
Enrichment["QueryData"] = "query-data";
|
|
20
24
|
})(Enrichment || (exports.Enrichment = Enrichment = {}));
|
|
21
25
|
/**
|
|
22
26
|
* The registry of enrichments that are currently supported by the search.
|
|
@@ -24,7 +28,7 @@ var Enrichment;
|
|
|
24
28
|
*/
|
|
25
29
|
exports.Enrichments = {
|
|
26
30
|
[Enrichment.CallTargets]: {
|
|
27
|
-
|
|
31
|
+
enrichElement: (e, _s, data, args, prev) => {
|
|
28
32
|
// we don't resolve aliases here yet!
|
|
29
33
|
const content = { targets: [] };
|
|
30
34
|
const callVertex = data.dataflow.graph.getVertex(e.node.info.id);
|
|
@@ -65,7 +69,7 @@ exports.Enrichments = {
|
|
|
65
69
|
mapper: ({ targets }) => targets.map(t => t).filter(t => t.node !== undefined)
|
|
66
70
|
},
|
|
67
71
|
[Enrichment.LastCall]: {
|
|
68
|
-
|
|
72
|
+
enrichElement: (e, _s, data, args, prev) => {
|
|
69
73
|
(0, assert_1.guard)(args && args.length, `${Enrichment.LastCall} enrichment requires at least one argument`);
|
|
70
74
|
const content = prev ?? { linkedIds: [] };
|
|
71
75
|
const vertex = data.dataflow.graph.get(e.node.info.id);
|
|
@@ -86,6 +90,41 @@ exports.Enrichments = {
|
|
|
86
90
|
},
|
|
87
91
|
mapper: ({ linkedIds }) => linkedIds
|
|
88
92
|
},
|
|
93
|
+
[Enrichment.CfgInformation]: {
|
|
94
|
+
enrichElement: (e, search, _data, _args, prev) => {
|
|
95
|
+
const searchContent = search.enrichmentContent(Enrichment.CfgInformation);
|
|
96
|
+
return {
|
|
97
|
+
...prev,
|
|
98
|
+
isRoot: searchContent.cfg.graph.rootIds().has(e.node.info.id),
|
|
99
|
+
isReachable: searchContent.reachableNodes?.has(e.node.info.id)
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
enrichSearch: (_search, data, args, prev) => {
|
|
103
|
+
args = {
|
|
104
|
+
forceRefresh: false,
|
|
105
|
+
checkReachable: false,
|
|
106
|
+
simplificationPasses: cfg_simplification_1.DefaultCfgSimplificationOrder,
|
|
107
|
+
...args
|
|
108
|
+
};
|
|
109
|
+
// short-circuit if we already have a cfg stored
|
|
110
|
+
if (!args.forceRefresh && prev?.simpleCfg) {
|
|
111
|
+
return prev;
|
|
112
|
+
}
|
|
113
|
+
const content = {
|
|
114
|
+
...prev,
|
|
115
|
+
cfg: (0, extract_cfg_1.extractCfg)(data.normalize, data.config, data.dataflow.graph, args.simplificationPasses),
|
|
116
|
+
};
|
|
117
|
+
if (args.checkReachable) {
|
|
118
|
+
content.reachableNodes = (0, cfg_simplification_1.cfgFindAllReachable)(content.cfg);
|
|
119
|
+
}
|
|
120
|
+
return content;
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
[Enrichment.QueryData]: {
|
|
124
|
+
// the query data enrichment is just a "pass-through" that passes the query data to the underlying search
|
|
125
|
+
enrichElement: (_e, _search, _data, args, prev) => (args ?? prev),
|
|
126
|
+
enrichSearch: (_search, _data, args, prev) => (0, objects_1.deepMergeObject)(prev, args)
|
|
127
|
+
}
|
|
89
128
|
};
|
|
90
129
|
/**
|
|
91
130
|
* Returns the content of the given enrichment type from a {@link FlowrSearchElement}.
|
|
@@ -96,14 +135,14 @@ exports.Enrichments = {
|
|
|
96
135
|
function enrichmentContent(e, enrichment) {
|
|
97
136
|
return e?.enrichments?.[enrichment];
|
|
98
137
|
}
|
|
99
|
-
function
|
|
138
|
+
function enrichElement(e, s, data, enrichment, args) {
|
|
100
139
|
const enrichmentData = exports.Enrichments[enrichment];
|
|
101
140
|
const prev = e?.enrichments;
|
|
102
141
|
return {
|
|
103
142
|
...e,
|
|
104
143
|
enrichments: {
|
|
105
144
|
...prev ?? {},
|
|
106
|
-
[enrichment]: enrichmentData.
|
|
145
|
+
[enrichment]: enrichmentData.enrichElement?.(e, s, data, args, prev?.[enrichment])
|
|
107
146
|
}
|
|
108
147
|
};
|
|
109
148
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { FlowrSearchElement,
|
|
1
|
+
import type { FlowrSearchElement, FlowrSearchGeneratorNodeBase, FlowrSearchGetFilter, FlowrSearchInput } from '../flowr-search';
|
|
2
2
|
import { FlowrSearchElements } from '../flowr-search';
|
|
3
3
|
import type { Pipeline } from '../../core/steps/pipeline/pipeline';
|
|
4
4
|
import type { TailTypesOrUndefined } from '../../util/collections/arrays';
|
|
5
5
|
import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
6
6
|
import type { SlicingCriteria } from '../../slicing/criterion/parse';
|
|
7
|
-
import type {
|
|
7
|
+
import type { SynchronousQuery } from '../../queries/query';
|
|
8
8
|
/**
|
|
9
9
|
* This is a union of all possible generator node types
|
|
10
10
|
*/
|
|
@@ -33,8 +33,8 @@ declare function generateFrom(data: FlowrSearchInput<Pipeline>, args: {
|
|
|
33
33
|
from: FlowrSearchElement<ParentInformation> | FlowrSearchElement<ParentInformation>[];
|
|
34
34
|
}): FlowrSearchElements<ParentInformation>;
|
|
35
35
|
declare function generateFromQuery(data: FlowrSearchInput<Pipeline>, args: {
|
|
36
|
-
from: readonly
|
|
37
|
-
}): FlowrSearchElements<ParentInformation,
|
|
36
|
+
from: readonly SynchronousQuery[];
|
|
37
|
+
}): FlowrSearchElements<ParentInformation, FlowrSearchElement<ParentInformation>[]>;
|
|
38
38
|
declare function generateCriterion(data: FlowrSearchInput<Pipeline>, args: {
|
|
39
39
|
criterion: SlicingCriteria;
|
|
40
40
|
}): FlowrSearchElements<ParentInformation>;
|
|
@@ -6,6 +6,7 @@ const flowr_search_1 = require("../flowr-search");
|
|
|
6
6
|
const parse_1 = require("../../slicing/criterion/parse");
|
|
7
7
|
const assert_1 = require("../../util/assert");
|
|
8
8
|
const query_1 = require("../../queries/query");
|
|
9
|
+
const search_enrichers_1 = require("./search-enrichers");
|
|
9
10
|
/**
|
|
10
11
|
* All supported generators!
|
|
11
12
|
*/
|
|
@@ -55,22 +56,26 @@ function generateFrom(data, args) {
|
|
|
55
56
|
return new flowr_search_1.FlowrSearchElements(Array.isArray(args.from) ? args.from : [args.from]);
|
|
56
57
|
}
|
|
57
58
|
function generateFromQuery(data, args) {
|
|
58
|
-
const nodes = new Set();
|
|
59
59
|
const result = (0, query_1.executeQueries)({ ast: data.normalize, dataflow: data.dataflow, config: data.config }, args.from);
|
|
60
|
+
// collect involved nodes
|
|
61
|
+
const nodesByQuery = new Map();
|
|
60
62
|
for (const [query, content] of Object.entries(result)) {
|
|
61
63
|
if (query === '.meta') {
|
|
62
64
|
continue;
|
|
63
65
|
}
|
|
66
|
+
const nodes = new Set();
|
|
64
67
|
const queryDef = query_1.SupportedQueries[query];
|
|
65
68
|
for (const node of queryDef.flattenInvolvedNodes(content)) {
|
|
66
|
-
nodes.add({
|
|
67
|
-
node: data.normalize.idMap.get(node),
|
|
68
|
-
query: query,
|
|
69
|
-
queryResult: content
|
|
70
|
-
});
|
|
69
|
+
nodes.add({ node: data.normalize.idMap.get(node) });
|
|
71
70
|
}
|
|
71
|
+
nodesByQuery.set(query, nodes);
|
|
72
72
|
}
|
|
73
|
-
|
|
73
|
+
// enrich elements with query data
|
|
74
|
+
const elements = new flowr_search_1.FlowrSearchElements([...nodesByQuery].flatMap(([_, nodes]) => [...nodes])).enrich(data, search_enrichers_1.Enrichment.QueryData, { queries: result });
|
|
75
|
+
return elements.mutate(s => s.map(e => {
|
|
76
|
+
const [query, _] = [...nodesByQuery].find(([_, nodes]) => nodes.has(e));
|
|
77
|
+
return (0, search_enrichers_1.enrichElement)(e, elements, data, search_enrichers_1.Enrichment.QueryData, { query });
|
|
78
|
+
}));
|
|
74
79
|
}
|
|
75
80
|
function generateCriterion(data, args) {
|
|
76
81
|
return new flowr_search_1.FlowrSearchElements(args.criterion.map(c => ({ node: data.normalize.idMap.get((0, parse_1.slicingCriterionToId)(c, data.normalize.idMap)) })));
|
|
@@ -10,8 +10,9 @@ var Mapper;
|
|
|
10
10
|
const Mappers = {
|
|
11
11
|
[Mapper.Enrichment]: {
|
|
12
12
|
mapper: (e, _data, enrichment) => {
|
|
13
|
-
const
|
|
14
|
-
|
|
13
|
+
const enrichmentData = search_enrichers_1.Enrichments[enrichment];
|
|
14
|
+
const content = (0, search_enrichers_1.enrichmentContent)(e, enrichment);
|
|
15
|
+
return content !== undefined ? enrichmentData.mapper?.(content) ?? [] : [];
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
};
|
|
@@ -4,7 +4,7 @@ import type { LastOfArray, Tail2TypesOrUndefined, TailOfArray } from '../../util
|
|
|
4
4
|
import type { FlowrFilterExpression } from '../flowr-search-filters';
|
|
5
5
|
import type { FlowrSearchGeneratorNode } from './search-generators';
|
|
6
6
|
import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
7
|
-
import type {
|
|
7
|
+
import type { Enrichment, EnrichmentElementArguments } from './search-enrichers';
|
|
8
8
|
import type { Mapper, MapperArguments } from './search-mappers';
|
|
9
9
|
/**
|
|
10
10
|
* This is a union of all possible transformer node types
|
|
@@ -57,8 +57,8 @@ declare function getFilter<Elements extends FlowrSearchElement<ParentInformation
|
|
|
57
57
|
}): CascadeEmpty<Elements, Elements | []>;
|
|
58
58
|
declare function getWith<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { info, args }: {
|
|
59
59
|
info: Enrichment;
|
|
60
|
-
args?:
|
|
61
|
-
}): FlowrSearchElements<ParentInformation,
|
|
60
|
+
args?: EnrichmentElementArguments<Enrichment>;
|
|
61
|
+
}): FlowrSearchElements<ParentInformation, FlowrSearchElement<ParentInformation>[]>;
|
|
62
62
|
declare function getMap<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { mapper, args }: {
|
|
63
63
|
mapper: Mapper;
|
|
64
64
|
args: MapperArguments<Mapper>;
|
|
@@ -96,7 +96,7 @@ function getFilter(data, elements, { filter }) {
|
|
|
96
96
|
return elements.mutate(e => e.filter(e => (0, flowr_search_filters_1.evalFilter)(filter, { element: e, normalize: data.normalize, dataflow: data.dataflow })));
|
|
97
97
|
}
|
|
98
98
|
function getWith(data, elements, { info, args }) {
|
|
99
|
-
return elements.mutate(
|
|
99
|
+
return elements.enrich(data, info, args).mutate(s => s.map(e => (0, search_enrichers_1.enrichElement)(e, elements, data, info, args)));
|
|
100
100
|
}
|
|
101
101
|
function getMap(data, elements, { mapper, args }) {
|
|
102
102
|
return elements.mutate(elements => elements.flatMap(e => (0, search_mappers_1.map)(e, data, mapper, args)));
|
|
@@ -105,7 +105,7 @@ function getMerge(
|
|
|
105
105
|
/* search has to be unknown because it is a recursive type */
|
|
106
106
|
data, elements, other) {
|
|
107
107
|
const resultOther = (0, flowr_search_executor_1.runSearch)(other, data);
|
|
108
|
-
return elements.addAll(resultOther);
|
|
108
|
+
return elements.addAll([...resultOther.getElements()]);
|
|
109
109
|
}
|
|
110
110
|
function getUnique(data, elements) {
|
|
111
111
|
return elements.mutate(e => e.reduce((acc, cur) => {
|
|
@@ -7,7 +7,6 @@ exports.envFingerprint = envFingerprint;
|
|
|
7
7
|
exports.fingerprint = fingerprint;
|
|
8
8
|
const object_hash_1 = __importDefault(require("object-hash"));
|
|
9
9
|
const environment_1 = require("../../dataflow/environments/environment");
|
|
10
|
-
const built_in_1 = require("../../dataflow/environments/built-in");
|
|
11
10
|
function envFingerprint(env) {
|
|
12
11
|
return (0, object_hash_1.default)(env, {
|
|
13
12
|
algorithm: 'md5',
|
|
@@ -15,7 +14,7 @@ function envFingerprint(env) {
|
|
|
15
14
|
respectFunctionProperties: false,
|
|
16
15
|
respectFunctionNames: false,
|
|
17
16
|
ignoreUnknown: true,
|
|
18
|
-
replacer: (v) => (
|
|
17
|
+
replacer: (v) => (0, environment_1.isDefaultBuiltInEnvironment)(v) ? undefined : v
|
|
19
18
|
});
|
|
20
19
|
}
|
|
21
20
|
function fingerprint(id, envFingerprint, onlyForSideEffects) {
|
|
@@ -5,11 +5,12 @@ import type { DataflowGraphVertexFunctionCall, DataflowGraphVertexInfo } from '.
|
|
|
5
5
|
import type { REnvironmentInformation } from '../../dataflow/environments/environment';
|
|
6
6
|
import type { DataflowGraph, OutgoingEdges } from '../../dataflow/graph/graph';
|
|
7
7
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
|
+
import type { DataflowInformation } from '../../dataflow/info';
|
|
8
9
|
/**
|
|
9
10
|
* Returns the function call targets (definitions) by the given caller
|
|
10
11
|
*/
|
|
11
12
|
export declare function getAllFunctionCallTargets(dataflowGraph: DataflowGraph, callerInfo: DataflowGraphVertexFunctionCall, baseEnvironment: REnvironmentInformation, queue: VisitingQueue): [Set<DataflowGraphVertexInfo>, REnvironmentInformation];
|
|
12
13
|
/** returns the new threshold hit count */
|
|
13
|
-
export declare function sliceForCall(current: NodeToSlice, callerInfo: DataflowGraphVertexFunctionCall,
|
|
14
|
+
export declare function sliceForCall(current: NodeToSlice, callerInfo: DataflowGraphVertexFunctionCall, dataflowInformation: DataflowInformation, queue: VisitingQueue): void;
|
|
14
15
|
/** Returns true if we found at least one return edge */
|
|
15
16
|
export declare function handleReturns(from: NodeId, queue: VisitingQueue, currentEdges: OutgoingEdges, baseEnvFingerprint: Fingerprint, baseEnvironment: REnvironmentInformation): boolean;
|
|
@@ -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,
|
|
62
|
+
function sliceForCall(current, callerInfo, dataflowInformation, queue) {
|
|
63
63
|
const baseEnvironment = current.baseEnvironment;
|
|
64
|
-
const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(
|
|
64
|
+
const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(dataflowInformation.graph, callerInfo, current.baseEnvironment, queue);
|
|
65
65
|
const activeEnvironmentFingerprint = (0, fingerprint_1.envFingerprint)(activeEnvironment);
|
|
66
66
|
if (functionCallTargets.size === 0) {
|
|
67
67
|
/*
|
|
@@ -69,7 +69,7 @@ function sliceForCall(current, callerInfo, dataflowGraph, queue) {
|
|
|
69
69
|
* hence, we add a new flag and add all argument values to the queue causing directly
|
|
70
70
|
*/
|
|
71
71
|
for (const arg of callerInfo.args) {
|
|
72
|
-
includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironment, queue,
|
|
72
|
+
includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironment, queue, dataflowInformation.graph);
|
|
73
73
|
}
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import type { SliceResult } from './slicer-types';
|
|
2
2
|
import type { Fingerprint } from './fingerprint';
|
|
3
3
|
import { VisitingQueue } from './visiting-queue';
|
|
4
|
-
import type { DataflowGraph } from '../../dataflow/graph/graph';
|
|
5
4
|
import type { NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
6
5
|
import type { SlicingCriteria } from '../criterion/parse';
|
|
7
6
|
import type { REnvironmentInformation } from '../../dataflow/environments/environment';
|
|
8
7
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
|
+
import { SliceDirection } from '../../core/steps/all/static-slicing/00-slice';
|
|
9
|
+
import type { DataflowInformation } from '../../dataflow/info';
|
|
9
10
|
export declare const slicerLogger: import("tslog").Logger<import("tslog").ILogObj>;
|
|
10
11
|
/**
|
|
11
|
-
* This returns the ids to include in the static
|
|
12
|
+
* 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).
|
|
12
13
|
* <p>
|
|
13
14
|
* The returned ids can be used to {@link reconstructToCode|reconstruct the slice to R code}.
|
|
14
15
|
*
|
|
15
|
-
* @param
|
|
16
|
-
* @param ast - The normalized AST of the code (used to get static nesting information of the lexemes in case of control flow dependencies that may have no effect on the slicing scope).
|
|
16
|
+
* @param info - The dataflow information used for slicing.
|
|
17
17
|
* @param criteria - The criteria to slice on.
|
|
18
|
+
* @param direction - The direction to slice in.
|
|
18
19
|
* @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.
|
|
19
20
|
* @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.
|
|
20
21
|
*/
|
|
21
|
-
export declare function
|
|
22
|
+
export declare function staticSlice(info: DataflowInformation, { idMap }: NormalizedAst, criteria: SlicingCriteria, direction: SliceDirection, threshold?: number, cache?: Map<Fingerprint, Set<NodeId>>): Readonly<SliceResult>;
|
|
22
23
|
export declare function updatePotentialAddition(queue: VisitingQueue, id: NodeId, target: NodeId, baseEnvironment: REnvironmentInformation, envFingerprint: string): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.slicerLogger = void 0;
|
|
4
|
-
exports.
|
|
4
|
+
exports.staticSlice = staticSlice;
|
|
5
5
|
exports.updatePotentialAddition = updatePotentialAddition;
|
|
6
6
|
const assert_1 = require("../../util/assert");
|
|
7
7
|
const log_1 = require("../../util/log");
|
|
@@ -12,22 +12,28 @@ const parse_1 = require("../criterion/parse");
|
|
|
12
12
|
const environment_1 = require("../../dataflow/environments/environment");
|
|
13
13
|
const vertex_1 = require("../../dataflow/graph/vertex");
|
|
14
14
|
const edge_1 = require("../../dataflow/graph/edge");
|
|
15
|
+
const _00_slice_1 = require("../../core/steps/all/static-slicing/00-slice");
|
|
16
|
+
const invert_dfg_1 = require("../../dataflow/graph/invert-dfg");
|
|
15
17
|
exports.slicerLogger = log_1.log.getSubLogger({ name: 'slicer' });
|
|
16
18
|
/**
|
|
17
|
-
* This returns the ids to include in the static
|
|
19
|
+
* 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).
|
|
18
20
|
* <p>
|
|
19
21
|
* The returned ids can be used to {@link reconstructToCode|reconstruct the slice to R code}.
|
|
20
22
|
*
|
|
21
|
-
* @param
|
|
22
|
-
* @param ast - The normalized AST of the code (used to get static nesting information of the lexemes in case of control flow dependencies that may have no effect on the slicing scope).
|
|
23
|
+
* @param info - The dataflow information used for slicing.
|
|
23
24
|
* @param criteria - The criteria to slice on.
|
|
25
|
+
* @param direction - The direction to slice in.
|
|
24
26
|
* @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.
|
|
25
27
|
* @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.
|
|
26
28
|
*/
|
|
27
|
-
function
|
|
29
|
+
function staticSlice(info, { idMap }, criteria, direction, threshold = 75, cache) {
|
|
28
30
|
(0, assert_1.guard)(criteria.length > 0, 'must have at least one seed id to calculate slice');
|
|
29
31
|
const decodedCriteria = (0, parse_1.convertAllSlicingCriteriaToIds)(criteria, idMap);
|
|
30
|
-
(0, log_1.expensiveTrace)(exports.slicerLogger, () => `calculating slice for ${decodedCriteria.length} seed criteria: ${decodedCriteria.map(s => JSON.stringify(s)).join(', ')}`);
|
|
32
|
+
(0, log_1.expensiveTrace)(exports.slicerLogger, () => `calculating ${direction} slice for ${decodedCriteria.length} seed criteria: ${decodedCriteria.map(s => JSON.stringify(s)).join(', ')}`);
|
|
33
|
+
let { graph } = info;
|
|
34
|
+
if (direction === _00_slice_1.SliceDirection.Forward) {
|
|
35
|
+
graph = (0, invert_dfg_1.invertDfg)(graph);
|
|
36
|
+
}
|
|
31
37
|
const queue = new visiting_queue_1.VisitingQueue(threshold, cache);
|
|
32
38
|
let minNesting = Number.MAX_SAFE_INTEGER;
|
|
33
39
|
const sliceSeedIds = new Set();
|
|
@@ -71,7 +77,7 @@ function staticSlicing(graph, { idMap }, criteria, threshold = 75, cache) {
|
|
|
71
77
|
}
|
|
72
78
|
if (!onlyForSideEffects) {
|
|
73
79
|
if (currentVertex.tag === vertex_1.VertexType.FunctionCall && !currentVertex.onlyBuiltin) {
|
|
74
|
-
(0, slice_call_1.sliceForCall)(current, currentVertex,
|
|
80
|
+
(0, slice_call_1.sliceForCall)(current, currentVertex, info, queue);
|
|
75
81
|
}
|
|
76
82
|
const ret = (0, slice_call_1.handleReturns)(id, queue, currentEdges, baseEnvFingerprint, baseEnvironment);
|
|
77
83
|
if (ret) {
|
|
@@ -88,3 +88,5 @@ export declare function equidistantSampling<T>(list: readonly T[], sampleCount:
|
|
|
88
88
|
*
|
|
89
89
|
*/
|
|
90
90
|
export declare function cartesianProduct<T>(...arrays: T[][]): T[][];
|
|
91
|
+
/** merge two arrays, removing duplicates */
|
|
92
|
+
export declare function uniqueArrayMerge<T>(left: readonly T[], right: readonly T[]): T[];
|
|
@@ -10,6 +10,7 @@ exports.array2bag = array2bag;
|
|
|
10
10
|
exports.arrayEqual = arrayEqual;
|
|
11
11
|
exports.equidistantSampling = equidistantSampling;
|
|
12
12
|
exports.cartesianProduct = cartesianProduct;
|
|
13
|
+
exports.uniqueArrayMerge = uniqueArrayMerge;
|
|
13
14
|
const assert_1 = require("../assert");
|
|
14
15
|
/**
|
|
15
16
|
* Splits the array every time the given predicate fires.
|
|
@@ -215,4 +216,12 @@ function equidistantSampling(list, sampleCount, rounding = 'ceil') {
|
|
|
215
216
|
function cartesianProduct(...arrays) {
|
|
216
217
|
return arrays.reduce((a, b) => a.flatMap(x => b.map(y => x.concat(y))), [[]]);
|
|
217
218
|
}
|
|
219
|
+
/** merge two arrays, removing duplicates */
|
|
220
|
+
function uniqueArrayMerge(left, right) {
|
|
221
|
+
const result = new Set(left);
|
|
222
|
+
for (const elem of right) {
|
|
223
|
+
result.add(elem);
|
|
224
|
+
}
|
|
225
|
+
return Array.from(result);
|
|
226
|
+
}
|
|
218
227
|
//# sourceMappingURL=arrays.js.map
|
package/util/containers.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare function getAccessOperands<OtherInfo>(args: readonly RFunctionArg
|
|
|
17
17
|
*
|
|
18
18
|
* @param name - Name to resolve
|
|
19
19
|
* @param environment - Environment in which name is resolved
|
|
20
|
+
* @param builtInEnvironment - Built-in environment
|
|
20
21
|
* @returns The indicesCollection of the resolved definitions
|
|
21
22
|
*/
|
|
22
23
|
export declare function resolveIndicesByName(name: Identifier, environment: REnvironmentInformation): ContainerIndices[] | undefined;
|
package/util/containers.js
CHANGED
|
@@ -24,6 +24,7 @@ function getAccessOperands(args) {
|
|
|
24
24
|
*
|
|
25
25
|
* @param name - Name to resolve
|
|
26
26
|
* @param environment - Environment in which name is resolved
|
|
27
|
+
* @param builtInEnvironment - Built-in environment
|
|
27
28
|
* @returns The indicesCollection of the resolved definitions
|
|
28
29
|
*/
|
|
29
30
|
function resolveIndicesByName(name, environment) {
|
package/util/json.js
CHANGED
|
@@ -46,12 +46,9 @@ function bigStringify(obj, current, send) {
|
|
|
46
46
|
if (obj === undefined || obj === null) {
|
|
47
47
|
return current + 'null';
|
|
48
48
|
}
|
|
49
|
-
else if (
|
|
49
|
+
else if ((0, environment_1.isDefaultBuiltInEnvironment)(obj)) {
|
|
50
50
|
return current + '<BuiltInEnvironment>';
|
|
51
51
|
}
|
|
52
|
-
else if (obj === environment_1.EmptyBuiltInEnvironment) {
|
|
53
|
-
return current + '<EmptyBuiltInEnvironment>';
|
|
54
|
-
}
|
|
55
52
|
else if (Array.isArray(obj)) {
|
|
56
53
|
let str = current + '[';
|
|
57
54
|
for (let i = 0; i < obj.length; i++) {
|
package/util/mermaid/dfg.js
CHANGED
|
@@ -6,7 +6,6 @@ exports.graphToMermaid = graphToMermaid;
|
|
|
6
6
|
exports.graphToMermaidUrl = graphToMermaidUrl;
|
|
7
7
|
exports.diffGraphsToMermaid = diffGraphsToMermaid;
|
|
8
8
|
exports.diffGraphsToMermaidUrl = diffGraphsToMermaidUrl;
|
|
9
|
-
const assert_1 = require("../assert");
|
|
10
9
|
const mermaid_1 = require("./mermaid");
|
|
11
10
|
const graph_1 = require("../../dataflow/graph/graph");
|
|
12
11
|
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
@@ -14,7 +13,6 @@ const identifier_1 = require("../../dataflow/environments/identifier");
|
|
|
14
13
|
const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
15
14
|
const edge_1 = require("../../dataflow/graph/edge");
|
|
16
15
|
const vertex_1 = require("../../dataflow/graph/vertex");
|
|
17
|
-
const environment_1 = require("../../dataflow/environments/environment");
|
|
18
16
|
const type_1 = require("../../r-bridge/lang-4.x/ast/model/type");
|
|
19
17
|
const built_in_1 = require("../../dataflow/environments/built-in");
|
|
20
18
|
/**
|
|
@@ -135,7 +133,7 @@ function printEnvironmentToLines(env) {
|
|
|
135
133
|
if (env === undefined) {
|
|
136
134
|
return ['??'];
|
|
137
135
|
}
|
|
138
|
-
else if (env.
|
|
136
|
+
else if (env.builtInEnv) {
|
|
139
137
|
return ['Built-in'];
|
|
140
138
|
}
|
|
141
139
|
const lines = [...printEnvironmentToLines(env.parent), `${env.id}${'-'.repeat(40)}`];
|
|
@@ -176,7 +174,10 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
|
|
|
176
174
|
mermaid.nodeLines.push(` style ${idPrefix}${id} stroke:red,stroke-width:5px; `);
|
|
177
175
|
}
|
|
178
176
|
const edges = mermaid.rootGraph.get((0, node_id_1.normalizeIdToNumberIfPossible)(id), true);
|
|
179
|
-
|
|
177
|
+
if (edges === undefined) {
|
|
178
|
+
mermaid.nodeLines.push(' %% No edges found for ' + id);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
180
181
|
const artificialCdEdges = (info.cds ?? []).map(x => [x.id, { types: new Set([x.when ? 'CD-True' : 'CD-False']) }]);
|
|
181
182
|
// eslint-disable-next-line prefer-const
|
|
182
183
|
for (let [target, edge] of [...edges[1], ...artificialCdEdges]) {
|
package/util/prefix.d.ts
CHANGED
|
@@ -10,4 +10,4 @@
|
|
|
10
10
|
* findByPrefixIfUnique('', { 'hello', 'hell' }) // => undefined (empty prefix)
|
|
11
11
|
* ```
|
|
12
12
|
*/
|
|
13
|
-
export declare function findByPrefixIfUnique(prefix: string, keys: readonly string[]): string | undefined;
|
|
13
|
+
export declare function findByPrefixIfUnique(prefix: string, keys: readonly string[] | MapIterator<string>): string | undefined;
|
package/util/range.d.ts
CHANGED
|
@@ -68,3 +68,4 @@ export declare function rangeCompare([r1sl, r1sc, ,]: SourceRange, [r2sl, r2sc,
|
|
|
68
68
|
* Checks if the first range is a subset of the second range.
|
|
69
69
|
*/
|
|
70
70
|
export declare function rangeIsSubsetOf([r1sl, r1sc, r1el, r1ec]: SourceRange, [r2sl, r2sc, r2el, r2ec]: SourceRange): boolean;
|
|
71
|
+
export declare function combineRanges(...ranges: SourceRange[]): SourceRange[];
|
package/util/range.js
CHANGED
|
@@ -9,6 +9,7 @@ exports.rangesOverlap = rangesOverlap;
|
|
|
9
9
|
exports.addRanges = addRanges;
|
|
10
10
|
exports.rangeCompare = rangeCompare;
|
|
11
11
|
exports.rangeIsSubsetOf = rangeIsSubsetOf;
|
|
12
|
+
exports.combineRanges = combineRanges;
|
|
12
13
|
const assert_1 = require("./assert");
|
|
13
14
|
function getRangeStart(p) {
|
|
14
15
|
return p === undefined ? undefined : [p[0], p[1]];
|
|
@@ -70,6 +71,9 @@ function rangeCompare([r1sl, r1sc, ,], [r2sl, r2sc, ,]) {
|
|
|
70
71
|
* Checks if the first range is a subset of the second range.
|
|
71
72
|
*/
|
|
72
73
|
function rangeIsSubsetOf([r1sl, r1sc, r1el, r1ec], [r2sl, r2sc, r2el, r2ec]) {
|
|
73
|
-
return r1sl
|
|
74
|
+
return (r1sl > r2sl || r1sl === r2sl && r1sc >= r2sc) && (r1el < r2el || r1sl === r2sl && r1ec <= r2ec);
|
|
75
|
+
}
|
|
76
|
+
function combineRanges(...ranges) {
|
|
77
|
+
return ranges.filter(range => !ranges.some(other => range !== other && rangeIsSubsetOf(range, other)));
|
|
74
78
|
}
|
|
75
79
|
//# sourceMappingURL=range.js.map
|
package/util/version.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.flowrVersion = flowrVersion;
|
|
4
4
|
const semver_1 = require("semver");
|
|
5
5
|
// this is automatically replaced with the current version by release-it
|
|
6
|
-
const version = '2.
|
|
6
|
+
const version = '2.4.1';
|
|
7
7
|
function flowrVersion() {
|
|
8
8
|
return new semver_1.SemVer(version);
|
|
9
9
|
}
|