@eagleoutice/flowr 2.8.11 → 2.8.13
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 +23 -22
- package/control-flow/simple-visitor.js +3 -1
- package/dataflow/environments/default-builtin-config.d.ts +1 -1
- package/dataflow/environments/default-builtin-config.js +1 -1
- package/dataflow/extractor.js +1 -1
- package/dataflow/graph/graph.d.ts +1 -14
- package/dataflow/graph/graph.js +1 -10
- package/dataflow/internal/linker.d.ts +12 -0
- package/dataflow/internal/linker.js +24 -11
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +5 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +3 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +7 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +16 -10
- package/dataflow/internal/process/functions/call/built-in/built-in-get.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.js +3 -2
- package/dataflow/internal/process/functions/process-argument.js +2 -1
- package/dataflow/internal/process/functions/process-parameter.js +4 -3
- package/documentation/wiki-query.js +2 -3
- package/package.json +1 -1
- package/project/plugins/file-plugins/files/flowr-description-file.d.ts +19 -0
- package/project/plugins/file-plugins/files/flowr-description-file.js +43 -12
- package/project/plugins/loading-order-plugins/flowr-analyzer-loading-order-description-file-plugin.js +2 -5
- package/project/plugins/package-version-plugins/flowr-analyzer-package-versions-description-file-plugin.js +5 -6
- package/queries/catalog/call-context-query/call-context-query-executor.d.ts +1 -1
- package/queries/catalog/call-context-query/call-context-query-executor.js +4 -3
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +21 -1
- package/queries/catalog/call-context-query/call-context-query-format.js +15 -7
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +11 -3
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +14 -1
- package/queries/catalog/call-context-query/identify-link-to-nested-call-relation.d.ts +12 -0
- package/queries/catalog/call-context-query/identify-link-to-nested-call-relation.js +30 -0
- package/queries/catalog/call-context-query/identify-link-to-relation.d.ts +10 -0
- package/queries/catalog/call-context-query/identify-link-to-relation.js +21 -0
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +2 -1
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +11 -2
- package/queries/catalog/dependencies-query/dependencies-query-format.js +1 -1
- package/queries/catalog/dependencies-query/function-info/test-functions.js +146 -12
- package/queries/query.js +1 -1
- package/search/search-executor/search-enrichers.d.ts +8 -40
- package/search/search-executor/search-enrichers.js +17 -13
- package/search/search-executor/search-generators.js +5 -7
- package/search/search-executor/search-transformer.js +1 -7
- package/util/schema.js +6 -8
- package/util/version.js +1 -1
|
@@ -8,8 +8,13 @@ const r_author_1 = require("../../../../util/r-author");
|
|
|
8
8
|
const args_1 = require("../../../../util/text/args");
|
|
9
9
|
const r_license_1 = require("../../../../util/r-license");
|
|
10
10
|
const package_1 = require("../../package-version-plugins/package");
|
|
11
|
+
const retriever_1 = require("../../../../r-bridge/retriever");
|
|
11
12
|
/**
|
|
12
13
|
* This decorates a text file and provides access to its content as a DCF (Debian Control File)-like structure.
|
|
14
|
+
* Please use the static {@link FlowrDescriptionFile.from} method to create instances of this class.
|
|
15
|
+
* To access description specific fields, use the provided methods like {@link license}, {@link authors}, {@link suggests}, and {@link collate}.
|
|
16
|
+
* These methods parse and return the relevant information in structured formats.
|
|
17
|
+
* To access raw fields, use the {@link content} method inherited from {@link FlowrFile}.
|
|
13
18
|
*/
|
|
14
19
|
class FlowrDescriptionFile extends flowr_file_1.FlowrFile {
|
|
15
20
|
wrapped;
|
|
@@ -59,10 +64,35 @@ class FlowrDescriptionFile extends flowr_file_1.FlowrFile {
|
|
|
59
64
|
const parsedAuthors = authors?.flatMap(a => (0, r_author_1.parseTextualAuthorString)(a, [r_author_1.AuthorRole.Author])) ?? [];
|
|
60
65
|
return parsedAuthors.concat(this.content().get('Maintainer')?.flatMap(m => (0, r_author_1.parseTextualAuthorString)(m, [r_author_1.AuthorRole.Creator])) ?? []);
|
|
61
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns the parsed suggested packages from the 'Suggests' field in the DESCRIPTION file.
|
|
69
|
+
*/
|
|
62
70
|
suggests() {
|
|
63
71
|
const suggests = this.content().get('Suggests');
|
|
64
72
|
return suggests ? parsePackagesWithVersions(suggests, 'package') : undefined;
|
|
65
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns the 'Collate' field from the DESCRIPTION file.
|
|
76
|
+
*/
|
|
77
|
+
collate() {
|
|
78
|
+
const c = this.content().get('Collate');
|
|
79
|
+
// we join newlines, and then split quote sensitive:
|
|
80
|
+
return c ? (0, args_1.splitAtEscapeSensitive)(c.join(' '), true, ' ').map(s => (0, retriever_1.removeRQuotes)(s).trim()).filter(s => s.length > 0) : undefined;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns the parsed dependencies from the 'Depends' field in the DESCRIPTION file.
|
|
84
|
+
*/
|
|
85
|
+
depends() {
|
|
86
|
+
const deps = this.content().get('Depends');
|
|
87
|
+
return deps ? parsePackagesWithVersions(deps, 'r') : undefined;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns the parsed imports from the 'Imports' field in the DESCRIPTION file.
|
|
91
|
+
*/
|
|
92
|
+
imports() {
|
|
93
|
+
const imps = this.content().get('Imports');
|
|
94
|
+
return imps ? parsePackagesWithVersions(imps, 'package') : undefined;
|
|
95
|
+
}
|
|
66
96
|
}
|
|
67
97
|
exports.FlowrDescriptionFile = FlowrDescriptionFile;
|
|
68
98
|
/**
|
|
@@ -117,25 +147,26 @@ function cleanValues(values) {
|
|
|
117
147
|
.map(s => s.trim())
|
|
118
148
|
.filter(s => s.length > 0);
|
|
119
149
|
}
|
|
120
|
-
const VersionRegex =
|
|
150
|
+
const VersionRegex = /([a-zA-Z0-9.]+)(?:\s*\(([><=~!]+)\s*([^)]+)\))?\s*/;
|
|
121
151
|
/**
|
|
122
152
|
* Parses package strings with optional version constraints into Package objects.
|
|
123
153
|
* @param packageStrings - The package strings to parse
|
|
124
154
|
* @param type - The type of the packages (e.g., 'r' or 'package')
|
|
125
155
|
*/
|
|
126
156
|
function parsePackagesWithVersions(packageStrings, type) {
|
|
157
|
+
let str = packageStrings.join(' ');
|
|
158
|
+
let match;
|
|
127
159
|
const packages = [];
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
160
|
+
// match until exhaustion
|
|
161
|
+
while ((match = VersionRegex.exec(str)) !== null) {
|
|
162
|
+
const [, name, operator, version] = match;
|
|
163
|
+
const range = package_1.Package.parsePackageVersionRange(operator, version);
|
|
164
|
+
packages.push(new package_1.Package({
|
|
165
|
+
name: name,
|
|
166
|
+
type: type,
|
|
167
|
+
versionConstraints: range ? [range] : undefined
|
|
168
|
+
}));
|
|
169
|
+
str = str.slice(match.index + match[0].length);
|
|
139
170
|
}
|
|
140
171
|
return packages;
|
|
141
172
|
}
|
|
@@ -5,7 +5,6 @@ const flowr_analyzer_description_file_plugin_1 = require("../file-plugins/flowr-
|
|
|
5
5
|
const semver_1 = require("semver");
|
|
6
6
|
const flowr_analyzer_loading_order_plugin_1 = require("./flowr-analyzer-loading-order-plugin");
|
|
7
7
|
const flowr_file_1 = require("../../context/flowr-file");
|
|
8
|
-
const retriever_1 = require("../../../r-bridge/retriever");
|
|
9
8
|
/**
|
|
10
9
|
* This plugin extracts loading order information from R `DESCRIPTION` files.
|
|
11
10
|
* It looks at the `Collate` field to determine the order in which files should be loaded.
|
|
@@ -25,10 +24,8 @@ class FlowrAnalyzerLoadingOrderDescriptionFilePlugin extends flowr_analyzer_load
|
|
|
25
24
|
flowr_analyzer_description_file_plugin_1.descriptionFileLog.warn(`Found ${descFiles.length} description files, expected exactly one.`);
|
|
26
25
|
}
|
|
27
26
|
/** this will do the caching etc. for me */
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
30
|
-
const collate = deps.get('Collate')?.map(f => (0, retriever_1.removeRQuotes)(f))
|
|
31
|
-
?? [];
|
|
27
|
+
const collate = descFiles[0].collate();
|
|
28
|
+
if (collate) {
|
|
32
29
|
/* we probably have to do some more guesswork here */
|
|
33
30
|
const unordered = ctx.files.loadingOrder.getUnorderedRequests();
|
|
34
31
|
// sort them by their path index in the Collate field
|
|
@@ -5,7 +5,6 @@ const flowr_analyzer_package_versions_plugin_1 = require("./flowr-analyzer-packa
|
|
|
5
5
|
const flowr_analyzer_description_file_plugin_1 = require("../file-plugins/flowr-analyzer-description-file-plugin");
|
|
6
6
|
const semver_1 = require("semver");
|
|
7
7
|
const flowr_file_1 = require("../../context/flowr-file");
|
|
8
|
-
const flowr_description_file_1 = require("../file-plugins/files/flowr-description-file");
|
|
9
8
|
/**
|
|
10
9
|
* This plugin extracts package versions from R `DESCRIPTION` files.
|
|
11
10
|
* It looks at the `Depends` and `Imports` fields to find package names and their version constraints.
|
|
@@ -24,12 +23,12 @@ class FlowrAnalyzerPackageVersionsDescriptionFilePlugin extends flowr_analyzer_p
|
|
|
24
23
|
flowr_analyzer_description_file_plugin_1.descriptionFileLog.warn(`Found ${descFiles.length} description files, expected exactly one.`);
|
|
25
24
|
}
|
|
26
25
|
/** this will do the caching etc. for me */
|
|
27
|
-
const deps = descFiles[0]
|
|
28
|
-
this.retrieveVersionsFromField(ctx, deps
|
|
29
|
-
this.retrieveVersionsFromField(ctx, deps
|
|
26
|
+
const deps = descFiles[0];
|
|
27
|
+
this.retrieveVersionsFromField(ctx, deps.depends() ?? []);
|
|
28
|
+
this.retrieveVersionsFromField(ctx, deps.imports() ?? []);
|
|
30
29
|
}
|
|
31
|
-
retrieveVersionsFromField(ctx,
|
|
32
|
-
for (const pkg of
|
|
30
|
+
retrieveVersionsFromField(ctx, pkgs) {
|
|
31
|
+
for (const pkg of pkgs) {
|
|
33
32
|
ctx.deps.addDependency(pkg);
|
|
34
33
|
}
|
|
35
34
|
}
|
|
@@ -4,7 +4,7 @@ import type { BasicQueryData } from '../../base-query-format';
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
export declare function promoteCallName(callName: CallNameTypes, exact?: boolean): RegExp | Set<string>;
|
|
7
|
-
export type PromotedLinkTo = Omit<
|
|
7
|
+
export type PromotedLinkTo<LT = LinkTo> = Omit<LT, 'callName'> & {
|
|
8
8
|
callName: RegExp | Set<string>;
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
@@ -10,6 +10,7 @@ const objects_1 = require("../../../util/objects");
|
|
|
10
10
|
const identify_link_to_last_call_relation_1 = require("./identify-link-to-last-call-relation");
|
|
11
11
|
const cfg_kind_1 = require("../../../project/cfg-kind");
|
|
12
12
|
const extract_cfg_1 = require("../../../control-flow/extract-cfg");
|
|
13
|
+
const identify_link_to_relation_1 = require("./identify-link-to-relation");
|
|
13
14
|
/* if the node is effected by nse, we have an ingoing nse edge */
|
|
14
15
|
function isQuoted(node, graph) {
|
|
15
16
|
const vertex = graph.ingoingEdges(node);
|
|
@@ -239,10 +240,10 @@ async function executeCallContextQueries({ analyzer }, queries) {
|
|
|
239
240
|
const linked = Array.isArray(query.linkTo) ? query.linkTo : [query.linkTo];
|
|
240
241
|
for (const link of linked) {
|
|
241
242
|
/* if we have a linkTo query, we have to find the last call */
|
|
242
|
-
const
|
|
243
|
-
if (
|
|
243
|
+
const linkTos = await (0, identify_link_to_relation_1.identifyLinkToRelation)(nodeId, analyzer, link, calls);
|
|
244
|
+
if (linkTos) {
|
|
244
245
|
linkedIds ??= new Set();
|
|
245
|
-
for (const l of
|
|
246
|
+
for (const l of linkTos) {
|
|
246
247
|
if (link.attachLinkInfo) {
|
|
247
248
|
linkedIds.add({ id: l, info: link.attachLinkInfo });
|
|
248
249
|
}
|
|
@@ -47,6 +47,7 @@ export type CallNameTypes = RegExp | string | string[];
|
|
|
47
47
|
* This way, you can link a call like `points` to the latest graphics plot etc.
|
|
48
48
|
* For now, this uses the static Control-Flow-Graph produced by flowR as the FD over-approximation is still not stable (see #1005).
|
|
49
49
|
* In short, this means that we are unable to detect origins over function call boundaries but plan on being more precise in the future.
|
|
50
|
+
* @see LinkToNestedCall
|
|
50
51
|
*/
|
|
51
52
|
export interface LinkToLastCall<CallName extends CallNameTypes = CallNameTypes> extends BaseQueryFormat {
|
|
52
53
|
readonly type: 'link-to-last-call';
|
|
@@ -63,7 +64,26 @@ export interface LinkToLastCall<CallName extends CallNameTypes = CallNameTypes>
|
|
|
63
64
|
*/
|
|
64
65
|
readonly cascadeIf?: (target: DataflowGraphVertexInfo, from: NodeId, graph: DataflowGraph) => CascadeAction;
|
|
65
66
|
}
|
|
66
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Allows to link nested calls to their parent calls.
|
|
69
|
+
* This way, you can link an `assert_equal` call to the parent `test_that` call etc:
|
|
70
|
+
* ```r
|
|
71
|
+
* test_that("my test", {
|
|
72
|
+
* assert_equal(1 + 1, 2)
|
|
73
|
+
* })
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export interface LinkToNestedCall<CallName extends CallNameTypes = CallNameTypes> extends BaseQueryFormat {
|
|
77
|
+
readonly type: 'link-to-nested-call';
|
|
78
|
+
/** Regex regarding the function name of the last call. Similar to {@link DefaultCallContextQueryFormat#callName}, strings are interpreted as a `RegExp`. */
|
|
79
|
+
readonly callName: CallName;
|
|
80
|
+
/**
|
|
81
|
+
* Should we ignore this (source) call?
|
|
82
|
+
* Currently, there is no well working serialization for this.
|
|
83
|
+
*/
|
|
84
|
+
readonly ignoreIf?: (id: NodeId, graph: DataflowGraph) => boolean;
|
|
85
|
+
}
|
|
86
|
+
export type LinkTo<CallName extends CallNameTypes = CallNameTypes, AttachLinkInfo = NoInfo> = (LinkToLastCall<CallName> | LinkToNestedCall<CallName>) & {
|
|
67
87
|
attachLinkInfo?: AttachLinkInfo;
|
|
68
88
|
};
|
|
69
89
|
export interface SubCallContextQueryFormat<CallName extends CallNameTypes = CallNameTypes, AttachLinkInfo = NoInfo> extends DefaultCallContextQueryFormat<CallName> {
|
|
@@ -10,13 +10,21 @@ const time_1 = require("../../../util/text/time");
|
|
|
10
10
|
const joi_1 = __importDefault(require("joi"));
|
|
11
11
|
const query_print_1 = require("../../query-print");
|
|
12
12
|
const identify_link_to_last_call_relation_1 = require("./identify-link-to-last-call-relation");
|
|
13
|
-
const CallContextQueryLinkTo = joi_1.default.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
const CallContextQueryLinkTo = joi_1.default.alternatives([
|
|
14
|
+
joi_1.default.object({
|
|
15
|
+
type: joi_1.default.string().valid('link-to-last-call').required().description('The type of the linkTo sub-query.'),
|
|
16
|
+
callName: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.array().items(joi_1.default.string())).required().description('Test regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression, and string arrays are checked for containment.'),
|
|
17
|
+
ignoreIf: joi_1.default.function().optional().description('Should we ignore this (source) call? Currently, there is no well working serialization for this.'),
|
|
18
|
+
cascadeIf: joi_1.default.function().optional().description('Should we continue searching after the link was created? Currently, there is no well working serialization for this.'),
|
|
19
|
+
attachLinkInfo: joi_1.default.object().optional().description('Additional information to attach to the link.')
|
|
20
|
+
}).description('Links the current call to the last call of the given kind. This way, you can link a call like `points` to the latest graphics plot etc.'),
|
|
21
|
+
joi_1.default.object({
|
|
22
|
+
type: joi_1.default.string().valid('link-to-nested-call').required().description('The type of the linkTo sub-query.'),
|
|
23
|
+
callName: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.array().items(joi_1.default.string())).required().description('Test regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression, and string arrays are checked for containment.'),
|
|
24
|
+
ignoreIf: joi_1.default.function().optional().description('Should we ignore this (source) call? Currently, there is no well working serialization for this.'),
|
|
25
|
+
attachLinkInfo: joi_1.default.object().optional().description('Additional information to attach to the link.')
|
|
26
|
+
}).description('Allows to link nested calls to their parent calls. This way, you can link an `assert_equal` call to the parent `test_that` call etc.')
|
|
27
|
+
]);
|
|
20
28
|
exports.CallContextQueryDefinition = {
|
|
21
29
|
executor: call_context_query_executor_1.executeCallContextQueries,
|
|
22
30
|
asciiSummarizer: async (formatter, analyzer, queryResults, result) => {
|
|
@@ -3,9 +3,10 @@ import { type DataflowGraph } from '../../../dataflow/graph/graph';
|
|
|
3
3
|
import { type DataflowGraphVertexFunctionCall } from '../../../dataflow/graph/vertex';
|
|
4
4
|
import { RType } from '../../../r-bridge/lang-4.x/ast/model/type';
|
|
5
5
|
import type { RNodeWithParent } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
6
|
-
import type {
|
|
7
|
-
import type { ControlFlowGraph } from '../../../control-flow/control-flow-graph';
|
|
6
|
+
import type { LinkToLastCall } from './call-context-query-format';
|
|
8
7
|
import type { PromotedLinkTo } from './call-context-query-executor';
|
|
8
|
+
import type { ReadonlyFlowrAnalysisProvider } from '../../../project/flowr-analyzer';
|
|
9
|
+
import type { ControlFlowGraph } from '../../../control-flow/control-flow-graph';
|
|
9
10
|
export declare enum CallTargets {
|
|
10
11
|
/** call targets a function that is not defined locally in the script (e.g., the call targets a library function) */
|
|
11
12
|
OnlyGlobal = "global",
|
|
@@ -32,9 +33,16 @@ export declare function getValueOfArgument<Types extends readonly RType[] = read
|
|
|
32
33
|
type: Types[number];
|
|
33
34
|
}) | undefined;
|
|
34
35
|
/**
|
|
36
|
+
* **Please refer to {@link identifyLinkToRelation}.**
|
|
37
|
+
*
|
|
35
38
|
* Identifies nodes that link to the last call of a specified function from a given starting node in the control flow graph.
|
|
36
39
|
* If you pass on `knownCalls` (e.g., produced by {@link getCallsInCfg}), this will only respect the functions
|
|
37
40
|
* listed there and ignore any other calls. This can be also used to speed up the process if you already have
|
|
38
41
|
* the known calls available.
|
|
42
|
+
* @see {@link identifyLinkToLastCallRelationSync} for the synchronous version.
|
|
43
|
+
*/
|
|
44
|
+
export declare function identifyLinkToLastCallRelation(from: NodeId, analyzer: ReadonlyFlowrAnalysisProvider, l: LinkToLastCall<RegExp> | PromotedLinkTo<LinkToLastCall<RegExp>>, knownCalls?: Map<NodeId, Required<DataflowGraphVertexFunctionCall>>): Promise<NodeId[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Synchronous version of {@link identifyLinkToLastCallRelation}.
|
|
39
47
|
*/
|
|
40
|
-
export declare function
|
|
48
|
+
export declare function identifyLinkToLastCallRelationSync(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, { callName, cascadeIf, ignoreIf }: LinkToLastCall<RegExp> | PromotedLinkTo<LinkToLastCall<RegExp>>, knownCalls?: Map<NodeId, Required<DataflowGraphVertexFunctionCall>>): NodeId[];
|
|
@@ -4,6 +4,7 @@ exports.CallTargets = void 0;
|
|
|
4
4
|
exports.satisfiesCallTargets = satisfiesCallTargets;
|
|
5
5
|
exports.getValueOfArgument = getValueOfArgument;
|
|
6
6
|
exports.identifyLinkToLastCallRelation = identifyLinkToLastCallRelation;
|
|
7
|
+
exports.identifyLinkToLastCallRelationSync = identifyLinkToLastCallRelationSync;
|
|
7
8
|
const graph_1 = require("../../../dataflow/graph/graph");
|
|
8
9
|
const simple_visitor_1 = require("../../../control-flow/simple-visitor");
|
|
9
10
|
const vertex_1 = require("../../../dataflow/graph/vertex");
|
|
@@ -15,6 +16,7 @@ const assert_1 = require("../../../util/assert");
|
|
|
15
16
|
const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
|
|
16
17
|
const r_function_call_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
17
18
|
const cascade_action_1 = require("./cascade-action");
|
|
19
|
+
const cfg_kind_1 = require("../../../project/cfg-kind");
|
|
18
20
|
var CallTargets;
|
|
19
21
|
(function (CallTargets) {
|
|
20
22
|
/** call targets a function that is not defined locally in the script (e.g., the call targets a library function) */
|
|
@@ -111,12 +113,23 @@ function getValueOfArgument(graph, call, argument, additionalAllowedTypes) {
|
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
/**
|
|
116
|
+
* **Please refer to {@link identifyLinkToRelation}.**
|
|
117
|
+
*
|
|
114
118
|
* Identifies nodes that link to the last call of a specified function from a given starting node in the control flow graph.
|
|
115
119
|
* If you pass on `knownCalls` (e.g., produced by {@link getCallsInCfg}), this will only respect the functions
|
|
116
120
|
* listed there and ignore any other calls. This can be also used to speed up the process if you already have
|
|
117
121
|
* the known calls available.
|
|
122
|
+
* @see {@link identifyLinkToLastCallRelationSync} for the synchronous version.
|
|
118
123
|
*/
|
|
119
|
-
function identifyLinkToLastCallRelation(from,
|
|
124
|
+
async function identifyLinkToLastCallRelation(from, analyzer, l, knownCalls) {
|
|
125
|
+
const graph = (await analyzer.dataflow()).graph;
|
|
126
|
+
const cfg = (await analyzer.controlflow([], cfg_kind_1.CfgKind.WithDataflow)).graph;
|
|
127
|
+
return identifyLinkToLastCallRelationSync(from, cfg, graph, l, knownCalls);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Synchronous version of {@link identifyLinkToLastCallRelation}.
|
|
131
|
+
*/
|
|
132
|
+
function identifyLinkToLastCallRelationSync(from, cfg, graph, { callName, cascadeIf, ignoreIf }, knownCalls) {
|
|
120
133
|
if (ignoreIf?.(from, graph)) {
|
|
121
134
|
return [];
|
|
122
135
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
2
|
+
import type { LinkToNestedCall } from './call-context-query-format';
|
|
3
|
+
import type { PromotedLinkTo } from './call-context-query-executor';
|
|
4
|
+
import type { ReadonlyFlowrAnalysisProvider } from '../../../project/flowr-analyzer';
|
|
5
|
+
/**
|
|
6
|
+
* **Please refer to {@link identifyLinkToRelation}.**
|
|
7
|
+
*
|
|
8
|
+
* Links to the nested call context of the current function call.
|
|
9
|
+
* This is useful for identifying calls made within nested functions
|
|
10
|
+
* that should be associated with their parent function's call context.
|
|
11
|
+
*/
|
|
12
|
+
export declare function identifyLinkToNestedRelation(from: NodeId, analyzer: ReadonlyFlowrAnalysisProvider, { callName, ignoreIf }: LinkToNestedCall<RegExp> | PromotedLinkTo<LinkToNestedCall<RegExp>>): Promise<NodeId[]>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.identifyLinkToNestedRelation = identifyLinkToNestedRelation;
|
|
4
|
+
const call_graph_1 = require("../../../dataflow/graph/call-graph");
|
|
5
|
+
/**
|
|
6
|
+
* **Please refer to {@link identifyLinkToRelation}.**
|
|
7
|
+
*
|
|
8
|
+
* Links to the nested call context of the current function call.
|
|
9
|
+
* This is useful for identifying calls made within nested functions
|
|
10
|
+
* that should be associated with their parent function's call context.
|
|
11
|
+
*/
|
|
12
|
+
async function identifyLinkToNestedRelation(from, analyzer, { callName, ignoreIf }) {
|
|
13
|
+
const df = await analyzer.dataflow();
|
|
14
|
+
if (ignoreIf?.(from, df.graph)) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const found = [];
|
|
18
|
+
const cg = await analyzer.callGraph();
|
|
19
|
+
const subCg = (0, call_graph_1.getSubCallGraph)(cg, new Set([from]));
|
|
20
|
+
for (const [, { id, name }] of subCg.vertices(true)) {
|
|
21
|
+
if (typeof name !== 'string') {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (callName instanceof RegExp ? callName.test(name) : callName.has(name)) {
|
|
25
|
+
found.push(id);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return found;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=identify-link-to-nested-call-relation.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
2
|
+
import type { LinkTo } from './call-context-query-format';
|
|
3
|
+
import type { PromotedLinkTo } from './call-context-query-executor';
|
|
4
|
+
import type { DataflowGraphVertexFunctionCall } from '../../../dataflow/graph/vertex';
|
|
5
|
+
import type { ReadonlyFlowrAnalysisProvider } from '../../../project/flowr-analyzer';
|
|
6
|
+
/**
|
|
7
|
+
* This facade selects the appropriate link-to relation identification function
|
|
8
|
+
* based on the type of link-to relation specified.
|
|
9
|
+
*/
|
|
10
|
+
export declare function identifyLinkToRelation(from: NodeId, analyzer: ReadonlyFlowrAnalysisProvider, l: LinkTo | PromotedLinkTo, knownCalls?: Map<NodeId, Required<DataflowGraphVertexFunctionCall>>): Promise<NodeId[]>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.identifyLinkToRelation = identifyLinkToRelation;
|
|
4
|
+
const identify_link_to_last_call_relation_1 = require("./identify-link-to-last-call-relation");
|
|
5
|
+
const identify_link_to_nested_call_relation_1 = require("./identify-link-to-nested-call-relation");
|
|
6
|
+
const assert_1 = require("../../../util/assert");
|
|
7
|
+
/**
|
|
8
|
+
* This facade selects the appropriate link-to relation identification function
|
|
9
|
+
* based on the type of link-to relation specified.
|
|
10
|
+
*/
|
|
11
|
+
async function identifyLinkToRelation(from, analyzer, l, knownCalls) {
|
|
12
|
+
switch (l.type) {
|
|
13
|
+
case 'link-to-last-call':
|
|
14
|
+
return (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(from, analyzer, l, knownCalls);
|
|
15
|
+
case 'link-to-nested-call':
|
|
16
|
+
return (0, identify_link_to_nested_call_relation_1.identifyLinkToNestedRelation)(from, analyzer, l);
|
|
17
|
+
default:
|
|
18
|
+
(0, assert_1.assertUnreachable)(l);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=identify-link-to-relation.js.map
|
|
@@ -36,12 +36,13 @@ async function executeDependenciesQuery({ analyzer, }, queries) {
|
|
|
36
36
|
}
|
|
37
37
|
const queryResults = functions.values().toArray().flat().length === 0 ? { kinds: {}, '.meta': { timing: 0 } } :
|
|
38
38
|
await (0, query_1.executeQueriesOfSameType)(data, functions.entries().map(([c, f]) => makeCallContextQuery(f, c)).toArray().flat());
|
|
39
|
+
const g = (0, dependencies_query_format_1.getAllCategories)(queries);
|
|
39
40
|
const results = Object.fromEntries(await Promise.all(functions.entries().map(async ([c, f]) => {
|
|
40
41
|
const results = getResults(queries, { dataflow, config, normalize }, queryResults, c, f, data);
|
|
41
42
|
// only default categories allow additional analyses, so we null-coalesce here!
|
|
42
43
|
const enabled = query.enabledCategories;
|
|
43
44
|
if (enabled === undefined || (enabled?.length > 0 && enabled.includes(c))) {
|
|
44
|
-
await
|
|
45
|
+
await g[c]?.additionalAnalysis?.(data, ignoreDefault, f, queryResults, results);
|
|
45
46
|
}
|
|
46
47
|
return [c, results];
|
|
47
48
|
})));
|
|
@@ -5,7 +5,7 @@ import { executeDependenciesQuery } from './dependencies-query-executor';
|
|
|
5
5
|
import type { FunctionInfo } from './function-info/function-info';
|
|
6
6
|
import type { CallContextQueryResult } from '../call-context-query/call-context-query-format';
|
|
7
7
|
import type { Range } from 'semver';
|
|
8
|
-
import type { AsyncOrSync } from 'ts-essentials';
|
|
8
|
+
import type { AsyncOrSync, MarkOptional } from 'ts-essentials';
|
|
9
9
|
import type { NamespaceInfo } from '../../../project/plugins/file-plugins/files/flowr-namespace-file';
|
|
10
10
|
export declare const Unknown = "unknown";
|
|
11
11
|
export interface DependencyCategorySettings {
|
|
@@ -13,6 +13,15 @@ export interface DependencyCategorySettings {
|
|
|
13
13
|
functions: FunctionInfo[];
|
|
14
14
|
/** this describes the global default value for this category, e.g., 'stdout' for write operations, please be aware, that this can be overwritten by a by-function default value */
|
|
15
15
|
defaultValue?: string;
|
|
16
|
+
/**
|
|
17
|
+
* An optional additional analysis step that is executed after the main function-based analysis has been performed.
|
|
18
|
+
* To add or modify dependency info entries, simply modify the `result` array.
|
|
19
|
+
* @param data - The basic query data.
|
|
20
|
+
* @param ignoreDefault - Whether the default functions were ignored.
|
|
21
|
+
* @param functions - The functions used for this category.
|
|
22
|
+
* @param queryResults - The results of the call context query.
|
|
23
|
+
* @param result - The current result array to which additional dependency info can be added.
|
|
24
|
+
*/
|
|
16
25
|
additionalAnalysis?: (data: BasicQueryData, ignoreDefault: boolean, functions: FunctionInfo[], queryResults: CallContextQueryResult, result: DependencyInfo[]) => AsyncOrSync<void>;
|
|
17
26
|
}
|
|
18
27
|
export declare const DefaultDependencyCategories: {
|
|
@@ -52,7 +61,7 @@ export interface DependenciesQuery extends BaseQueryFormat, Partial<Record<`${De
|
|
|
52
61
|
readonly type: 'dependencies';
|
|
53
62
|
readonly enabledCategories?: DependencyCategoryName[];
|
|
54
63
|
readonly ignoreDefaultFunctions?: boolean;
|
|
55
|
-
readonly additionalCategories?: Record<string,
|
|
64
|
+
readonly additionalCategories?: Record<string, MarkOptional<DependencyCategorySettings, 'additionalAnalysis'>>;
|
|
56
65
|
}
|
|
57
66
|
export type DependenciesQueryResult = BaseQueryResult & {
|
|
58
67
|
[C in DefaultDependencyCategoryName]: DependencyInfo[];
|
|
@@ -84,7 +84,7 @@ function printResultSection(title, infos, result) {
|
|
|
84
84
|
}, new Map());
|
|
85
85
|
for (const [functionName, infos] of grouped) {
|
|
86
86
|
result.push(` ╰ \`${functionName}\``);
|
|
87
|
-
result.push(infos.map(i => ` ╰ Node Id: ${i.nodeId}${i.value !== undefined ? `, \`${i.value}\`` : ''}${i.derivedVersion !== undefined ? `, Version: \`${i.derivedVersion.format()}\`` : ''}`).join('\n'));
|
|
87
|
+
result.push(infos.map(i => ` ╰ Node Id: ${i.nodeId}${i.value !== undefined ? `, \`${i.value}\`` : ''}${i.derivedVersion !== undefined ? `, Version: \`${i.derivedVersion.format()}\`` : ''}${i.linkedIds ? `, linked: [${i.linkedIds.join(', ')}]` : ''}`).join('\n'));
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
/**
|