@eagleoutice/flowr 2.7.6 → 2.8.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 +67 -64
- package/cli/wiki.js +1 -1
- package/control-flow/extract-cfg.js +3 -3
- package/control-flow/useless-loop.d.ts +1 -1
- package/control-flow/useless-loop.js +2 -2
- package/dataflow/cluster.js +3 -3
- package/dataflow/environments/built-in-config.d.ts +8 -4
- package/dataflow/environments/built-in.d.ts +27 -14
- package/dataflow/environments/built-in.js +27 -12
- package/dataflow/environments/default-builtin-config.d.ts +614 -3
- package/dataflow/environments/default-builtin-config.js +50 -15
- package/dataflow/environments/environment.js +3 -2
- package/dataflow/environments/identifier.d.ts +5 -1
- package/dataflow/environments/reference-to-maybe.d.ts +2 -2
- package/dataflow/environments/reference-to-maybe.js +23 -14
- package/dataflow/environments/resolve-by-name.d.ts +6 -2
- package/dataflow/environments/resolve-by-name.js +5 -1
- package/dataflow/environments/scoping.js +1 -3
- package/dataflow/eval/resolve/alias-tracking.js +5 -1
- package/dataflow/extractor.js +3 -3
- package/dataflow/fn/exceptions-of-function.d.ts +13 -0
- package/dataflow/fn/exceptions-of-function.js +47 -0
- package/dataflow/fn/higher-order-function.d.ts +1 -1
- package/dataflow/fn/higher-order-function.js +3 -3
- package/dataflow/fn/recursive-function.d.ts +6 -0
- package/dataflow/fn/recursive-function.js +32 -0
- package/dataflow/graph/call-graph.d.ts +10 -0
- package/dataflow/graph/call-graph.js +209 -0
- package/dataflow/graph/dataflowgraph-builder.d.ts +7 -2
- package/dataflow/graph/dataflowgraph-builder.js +14 -9
- package/dataflow/graph/diff-dataflow-graph.js +96 -2
- package/dataflow/graph/graph.d.ts +10 -7
- package/dataflow/graph/graph.js +7 -8
- package/dataflow/graph/vertex.d.ts +6 -3
- package/dataflow/hooks.d.ts +30 -0
- package/dataflow/hooks.js +38 -0
- package/dataflow/info.d.ts +28 -5
- package/dataflow/info.js +66 -31
- package/dataflow/internal/linker.d.ts +13 -3
- package/dataflow/internal/linker.js +155 -53
- package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +4 -0
- package/dataflow/internal/process/functions/call/argument/unpack-argument.js +7 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +19 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +14 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +30 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +24 -17
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +5 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +59 -21
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.d.ts +34 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.js +92 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.d.ts +21 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.js +129 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.d.ts +16 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.js +127 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +5 -3
- package/dataflow/internal/process/functions/call/common.d.ts +13 -1
- package/dataflow/internal/process/functions/call/common.js +33 -2
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +13 -1
- package/dataflow/internal/process/functions/call/known-call-handling.js +29 -3
- package/dataflow/internal/process/functions/call/named-call-handling.js +2 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +6 -4
- package/dataflow/internal/process/functions/process-argument.js +7 -6
- package/dataflow/internal/process/functions/process-parameter.js +2 -1
- package/dataflow/internal/process/process-named-call.d.ts +2 -2
- package/dataflow/internal/process/process-symbol.js +3 -2
- package/dataflow/internal/process/process-value.d.ts +3 -2
- package/dataflow/internal/process/process-value.js +8 -6
- package/dataflow/origin/dfg-get-origin.js +2 -1
- package/dataflow/origin/dfg-get-symbol-refs.js +1 -1
- package/documentation/doc-readme.d.ts +1 -1
- package/documentation/doc-readme.js +6 -6
- package/documentation/doc-util/doc-code.js +1 -1
- package/documentation/doc-util/doc-dfg.d.ts +1 -0
- package/documentation/doc-util/doc-dfg.js +7 -4
- package/documentation/doc-util/doc-query.d.ts +1 -0
- package/documentation/doc-util/doc-query.js +1 -1
- package/documentation/doc-util/doc-repl.d.ts +2 -1
- package/documentation/doc-util/doc-repl.js +11 -3
- package/documentation/wiki-analyzer.js +2 -0
- package/documentation/wiki-dataflow-graph.js +59 -16
- package/documentation/wiki-interface.js +33 -5
- package/documentation/wiki-mk/doc-context.d.ts +2 -1
- package/documentation/wiki-mk/doc-context.js +2 -2
- package/documentation/wiki-mk/doc-maker.js +4 -3
- package/documentation/wiki-normalized-ast.js +6 -0
- package/documentation/wiki-query.js +109 -1
- package/linter/linter-rules.d.ts +1 -1
- package/linter/rules/seeded-randomness.js +17 -12
- package/linter/rules/useless-loop.d.ts +1 -1
- package/package.json +9 -9
- package/project/cache/flowr-analyzer-cache.d.ts +11 -0
- package/project/cache/flowr-analyzer-cache.js +19 -0
- package/project/context/flowr-analyzer-dependencies-context.d.ts +6 -1
- package/project/context/flowr-analyzer-dependencies-context.js +6 -0
- package/project/context/flowr-analyzer-files-context.d.ts +5 -2
- package/project/context/flowr-analyzer-files-context.js +24 -17
- package/project/context/flowr-file.d.ts +9 -4
- package/project/context/flowr-file.js +20 -6
- package/project/flowr-analyzer.d.ts +11 -0
- package/project/flowr-analyzer.js +6 -0
- package/project/plugins/file-plugins/files/flowr-description-file.d.ts +8 -0
- package/project/plugins/file-plugins/files/flowr-description-file.js +36 -3
- package/project/plugins/file-plugins/files/flowr-jupyter-file.js +1 -1
- package/project/plugins/file-plugins/files/flowr-namespace-file.js +1 -1
- package/project/plugins/file-plugins/files/flowr-news-file.js +1 -1
- package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +1 -1
- package/project/plugins/file-plugins/flowr-analyzer-description-file-plugin.js +1 -1
- package/project/plugins/file-plugins/flowr-analyzer-file-plugin.d.ts +4 -1
- package/project/plugins/file-plugins/flowr-analyzer-file-plugin.js +3 -0
- package/project/plugins/file-plugins/{flowr-analyzer-namespace-file-plugin.d.ts → flowr-analyzer-namespace-files-plugin.d.ts} +1 -1
- package/project/plugins/file-plugins/{flowr-analyzer-namespace-file-plugin.js → flowr-analyzer-namespace-files-plugin.js} +4 -4
- package/project/plugins/file-plugins/flowr-analyzer-test-file-plugin.d.ts +26 -0
- package/project/plugins/file-plugins/flowr-analyzer-test-file-plugin.js +39 -0
- package/project/plugins/file-plugins/flowr-analyzer-vignette-file-plugin.d.ts +26 -0
- package/project/plugins/file-plugins/flowr-analyzer-vignette-file-plugin.js +39 -0
- package/project/plugins/flowr-analyzer-plugin-defaults.js +6 -2
- package/project/plugins/package-version-plugins/flowr-analyzer-package-versions-description-file-plugin.js +3 -13
- package/project/plugins/package-version-plugins/package.d.ts +1 -1
- package/project/plugins/package-version-plugins/package.js +3 -3
- package/project/plugins/plugin-registry.d.ts +4 -2
- package/project/plugins/plugin-registry.js +6 -2
- package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.d.ts +11 -0
- package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.js +5 -2
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +4 -12
- package/queries/catalog/call-graph-query/call-graph-query-executor.d.ts +6 -0
- package/queries/catalog/call-graph-query/call-graph-query-executor.js +21 -0
- package/queries/catalog/call-graph-query/call-graph-query-format.d.ts +21 -0
- package/queries/catalog/call-graph-query/call-graph-query-format.js +32 -0
- package/queries/catalog/dataflow-query/dataflow-query-executor.js +4 -3
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +29 -3
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +1 -0
- package/queries/catalog/dependencies-query/function-info/function-info.d.ts +8 -1
- package/queries/catalog/dependencies-query/function-info/write-functions.js +13 -0
- package/queries/catalog/does-call-query/does-call-query-executor.d.ts +6 -0
- package/queries/catalog/does-call-query/does-call-query-executor.js +100 -0
- package/queries/catalog/does-call-query/does-call-query-format.d.ts +51 -0
- package/queries/catalog/does-call-query/does-call-query-format.js +102 -0
- package/queries/catalog/files-query/files-query-executor.js +4 -4
- package/queries/catalog/files-query/files-query-format.d.ts +2 -1
- package/queries/catalog/files-query/files-query-format.js +18 -2
- package/queries/catalog/id-map-query/id-map-query-executor.js +4 -3
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.d.ts +18 -0
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.js +56 -0
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +34 -0
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.js +54 -0
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.js +3 -28
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +6 -0
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.js +12 -0
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.d.ts +6 -0
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.js +23 -0
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +28 -0
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.js +44 -0
- package/queries/catalog/linter-query/linter-query-format.js +4 -1
- package/queries/catalog/location-map-query/location-map-query-executor.js +1 -1
- package/queries/catalog/normalized-ast-query/normalized-ast-query-executor.js +4 -3
- package/queries/catalog/project-query/project-query-executor.js +9 -3
- package/queries/catalog/project-query/project-query-format.d.ts +6 -1
- package/queries/catalog/project-query/project-query-format.js +35 -9
- package/queries/query.d.ts +34 -2
- package/queries/query.js +9 -0
- package/r-bridge/data/data.d.ts +10 -5
- package/r-bridge/data/data.js +11 -5
- package/r-bridge/lang-4.x/ast/model/model.d.ts +7 -7
- package/r-bridge/lang-4.x/ast/model/nodes/r-access.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-argument.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-binary-op.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-comment.d.ts +5 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-comment.js +8 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.d.ts +3 -3
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-pipe.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-unary-op.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/parser/main/internal/other/normalize-comment.js +0 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +0 -2
- package/r-bridge/roxygen2/roxygen-ast.d.ts +218 -0
- package/r-bridge/roxygen2/roxygen-ast.js +82 -0
- package/r-bridge/roxygen2/roxygen-parse.d.ts +24 -0
- package/r-bridge/roxygen2/roxygen-parse.js +214 -0
- package/reconstruct/auto-select/magic-comments.js +4 -4
- package/slicing/static/slice-call.js +3 -4
- package/slicing/static/static-slicer.js +2 -2
- package/statistics/features/supported/defined-functions/defined-functions.js +1 -1
- package/util/collections/defaultmap.d.ts +3 -3
- package/util/mermaid/dfg.js +5 -5
- package/util/objects.js +1 -1
- package/util/r-author.d.ts +5 -0
- package/util/r-author.js +110 -0
- package/util/r-license.d.ts +10 -1
- package/util/r-license.js +27 -6
- package/util/r-version.d.ts +19 -0
- package/util/r-version.js +106 -0
- package/util/range.d.ts +6 -0
- package/util/range.js +7 -0
- package/util/simple-df/dfg-ascii.js +2 -2
- package/util/text/args.d.ts +9 -0
- package/util/text/args.js +65 -0
- package/util/version.js +1 -1
|
@@ -35,6 +35,10 @@ const inspect_higher_order_query_executor_1 = require("../queries/catalog/inspec
|
|
|
35
35
|
const doc_escape_1 = require("./doc-util/doc-escape");
|
|
36
36
|
const doc_maker_1 = require("./wiki-mk/doc-maker");
|
|
37
37
|
const files_query_executor_1 = require("../queries/catalog/files-query/files-query-executor");
|
|
38
|
+
const call_graph_query_executor_1 = require("../queries/catalog/call-graph-query/call-graph-query-executor");
|
|
39
|
+
const inspect_recursion_query_executor_1 = require("../queries/catalog/inspect-recursion-query/inspect-recursion-query-executor");
|
|
40
|
+
const does_call_query_executor_1 = require("../queries/catalog/does-call-query/does-call-query-executor");
|
|
41
|
+
const inspect_exception_query_executor_1 = require("../queries/catalog/inspect-exceptions-query/inspect-exception-query-executor");
|
|
38
42
|
(0, doc_query_1.registerQueryDocumentation)('call-context', {
|
|
39
43
|
name: 'Call-Context Query',
|
|
40
44
|
type: 'active',
|
|
@@ -124,6 +128,47 @@ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
|
124
128
|
`;
|
|
125
129
|
}
|
|
126
130
|
});
|
|
131
|
+
(0, doc_query_1.registerQueryDocumentation)('call-graph', {
|
|
132
|
+
name: 'Call-Graph Query',
|
|
133
|
+
type: 'active',
|
|
134
|
+
shortDescription: 'Returns the call graph of the given code.',
|
|
135
|
+
functionName: call_graph_query_executor_1.executeCallGraphQuery.name,
|
|
136
|
+
functionFile: '../queries/catalog/call-graph-query/call-graph-query-executor.ts',
|
|
137
|
+
buildExplanation: async (shell, ctx) => {
|
|
138
|
+
const exampleCode = 'x + 1';
|
|
139
|
+
return `
|
|
140
|
+
This query calculates and returns the ${ctx.linkPage('wiki/Dataflow Graph', 'call graph', 'perspectives-cg')} of the given code.
|
|
141
|
+
|
|
142
|
+
Using the example code \`${exampleCode}\`, the following query returns the dataflow graph of the code:
|
|
143
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
144
|
+
type: 'call-graph'
|
|
145
|
+
}], { showCode: true, collapseQuery: true })}
|
|
146
|
+
`;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
(0, doc_query_1.registerQueryDocumentation)('does-call', {
|
|
150
|
+
name: 'Does-Call Query',
|
|
151
|
+
type: 'active',
|
|
152
|
+
shortDescription: 'Checks whether a function calls another function matching given constraints.',
|
|
153
|
+
functionName: does_call_query_executor_1.executeDoesCallQuery.name,
|
|
154
|
+
functionFile: '../queries/catalog/does-call-query/does-call-query-executor.ts',
|
|
155
|
+
buildExplanation: async (shell) => {
|
|
156
|
+
const exampleCode = 'f <- function(x) { eval(x) };\nf("1 + 1")';
|
|
157
|
+
return `
|
|
158
|
+
This query checks whether a function calls another function matching given constraints.
|
|
159
|
+
|
|
160
|
+
Using the example code:
|
|
161
|
+
${(0, doc_code_1.codeBlock)('r', exampleCode)}
|
|
162
|
+
the following query checks whether the call to \`f\` calls \`eval\`:
|
|
163
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
164
|
+
type: 'does-call',
|
|
165
|
+
queryId: 'calls-eval',
|
|
166
|
+
call: '2@f',
|
|
167
|
+
calls: { type: 'name', name: 'eval', nameExact: true }
|
|
168
|
+
}], { showCode: true, collapseQuery: false, shorthand: '(2@f:"eval")' })}
|
|
169
|
+
`;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
127
172
|
(0, doc_query_1.registerQueryDocumentation)('files', {
|
|
128
173
|
name: 'Files Query',
|
|
129
174
|
type: 'active',
|
|
@@ -239,7 +284,67 @@ Please note, that functions that are just identities (e.g., \`function(x) x\`) a
|
|
|
239
284
|
Using the example code \`${exampleCode}\` the following query returns the information for all identified function definitions whether they are higher-order functions:
|
|
240
285
|
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
241
286
|
type: 'inspect-higher-order',
|
|
242
|
-
}], { showCode: true })}
|
|
287
|
+
}], { showCode: true, collapseQuery: true })}
|
|
288
|
+
|
|
289
|
+
This query also supports a slicing criterion based query mode that only returns information for functions matching the given criteria:
|
|
290
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
291
|
+
type: 'inspect-higher-order',
|
|
292
|
+
filter: ['1@function']
|
|
293
|
+
}], { showCode: false, shorthand: (0, doc_query_1.sliceQueryShorthand)(['1@function'], (0, doc_escape_1.escapeNewline)(exampleCode)) })}
|
|
294
|
+
`;
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
(0, doc_query_1.registerQueryDocumentation)('inspect-recursion', {
|
|
298
|
+
name: 'Inspect Recursive Functions Query',
|
|
299
|
+
type: 'active',
|
|
300
|
+
shortDescription: 'Determine whether functions are recursive',
|
|
301
|
+
functionName: inspect_recursion_query_executor_1.executeRecursionQuery.name,
|
|
302
|
+
functionFile: '../queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.ts',
|
|
303
|
+
buildExplanation: async (shell) => {
|
|
304
|
+
const exampleCode = 'fact <- function(n) { if(n <= 1) 1 else n * fact(n - 1) }';
|
|
305
|
+
return `
|
|
306
|
+
With this query you can identify which functions in the code are recursive.
|
|
307
|
+
Please note, that functions that *may* be recursive due to indirect calls are also considered recursive.
|
|
308
|
+
|
|
309
|
+
Using the example code \`${exampleCode}\` the following query returns the information for all identified function definitions whether they are recursive:
|
|
310
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
311
|
+
type: 'inspect-recursion',
|
|
312
|
+
}], { showCode: true, collapseQuery: true })}
|
|
313
|
+
|
|
314
|
+
This query also supports a slicing criterion based query mode that only returns information for functions matching the given criteria:
|
|
315
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
316
|
+
type: 'inspect-recursion',
|
|
317
|
+
filter: ['1@function']
|
|
318
|
+
}], { showCode: true, shorthand: (0, doc_query_1.sliceQueryShorthand)(['1@function'], (0, doc_escape_1.escapeNewline)(exampleCode)) })}
|
|
319
|
+
`;
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
(0, doc_query_1.registerQueryDocumentation)('inspect-exception', {
|
|
323
|
+
name: 'Inspect Exceptions of Functions Query',
|
|
324
|
+
type: 'active',
|
|
325
|
+
shortDescription: 'Determine whether functions throw exceptions (known to flowR)',
|
|
326
|
+
functionName: inspect_exception_query_executor_1.executeExceptionQuery.name,
|
|
327
|
+
functionFile: '../queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.ts',
|
|
328
|
+
buildExplanation: async (shell) => {
|
|
329
|
+
const exampleCode = `mayFail <- function(x) {
|
|
330
|
+
if(x < 0) stop("Negative value!")
|
|
331
|
+
else sqrt(x)
|
|
332
|
+
}
|
|
333
|
+
safeFail <- function(x) {
|
|
334
|
+
tryCatch(
|
|
335
|
+
mayFail(x),
|
|
336
|
+
error = function(e) { NA }
|
|
337
|
+
)
|
|
338
|
+
}`;
|
|
339
|
+
return `
|
|
340
|
+
With this query you can identify which functions in the code throw exceptions (known to flowR).
|
|
341
|
+
|
|
342
|
+
Using the following example code:
|
|
343
|
+
${(0, doc_code_1.codeBlock)('r', exampleCode)}
|
|
344
|
+
the following query returns the information for all identified function definitions whether they throw exceptions:
|
|
345
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
346
|
+
type: 'inspect-exception',
|
|
347
|
+
}], { showCode: true, collapseQuery: true })}
|
|
243
348
|
`;
|
|
244
349
|
}
|
|
245
350
|
});
|
|
@@ -350,6 +455,9 @@ ${await (0, doc_repl_1.documentReplSession)(shell, [
|
|
|
350
455
|
description: 'Set the slicing threshold to 10,000.'
|
|
351
456
|
}
|
|
352
457
|
])}
|
|
458
|
+
|
|
459
|
+
One of the most useful options to change on-the-fly are probably those under \`repl\`. For example, setting \`repl.quickStats=true\`
|
|
460
|
+
enables quick statistics after each REPL command.
|
|
353
461
|
`;
|
|
354
462
|
}
|
|
355
463
|
});
|
package/linter/linter-rules.d.ts
CHANGED
|
@@ -290,7 +290,7 @@ export declare const LintingRules: {
|
|
|
290
290
|
readonly certainty: import("./linter-format").LintingRuleCertainty.BestEffort;
|
|
291
291
|
readonly tags: readonly [import("./linter-tags").LintingRuleTag.Smell, import("./linter-tags").LintingRuleTag.Readability];
|
|
292
292
|
readonly defaultConfig: {
|
|
293
|
-
readonly loopyFunctions: Set<"builtin:
|
|
293
|
+
readonly loopyFunctions: Set<"builtin:access" | "builtin:apply" | "builtin:assignment" | "builtin:assignment-like" | "builtin:default" | "builtin:eval" | "builtin:expression-list" | "builtin:for-loop" | "builtin:function-definition" | "builtin:get" | "builtin:if-then-else" | "builtin:library" | "builtin:list" | "builtin:pipe" | "builtin:quote" | "builtin:register-hook" | "builtin:repeat-loop" | "builtin:replacement" | "builtin:rm" | "builtin:source" | "builtin:special-bin-op" | "builtin:stopifnot" | "builtin:try" | "builtin:vector" | "builtin:while-loop">;
|
|
294
294
|
};
|
|
295
295
|
};
|
|
296
296
|
};
|
|
@@ -55,22 +55,24 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
55
55
|
// filter by calls that aren't preceded by a randomness producer
|
|
56
56
|
.flatMap(element => {
|
|
57
57
|
const dfgElement = dataflow.graph.getVertex(element.searchElement.node.info.id);
|
|
58
|
-
const cds = dfgElement ? new Set(dfgElement.
|
|
58
|
+
const cds = dfgElement ? new Set(dfgElement.controlDependencies) : new Set();
|
|
59
59
|
const producers = (0, search_enrichers_1.enrichmentContent)(element.searchElement, search_enrichers_1.Enrichment.LastCall).linkedIds
|
|
60
60
|
.map(e => dataflow.graph.getVertex(e.node.info.id));
|
|
61
61
|
const { assignment, func } = Object.groupBy(producers, f => assignmentArgIndexes.has(f.name) ? 'assignment' : 'func');
|
|
62
62
|
let nonConstant = false;
|
|
63
|
-
|
|
63
|
+
const cdsOfProduces = new Set();
|
|
64
64
|
// function calls are already taken care of through the LastCall enrichment itself
|
|
65
65
|
for (const f of func ?? []) {
|
|
66
66
|
if (isConstantArgument(dataflow.graph, f, 0, analyzer.inspectContext())) {
|
|
67
|
-
const fCds = new Set(f.
|
|
67
|
+
const fCds = new Set(f.controlDependencies).difference(cds);
|
|
68
|
+
metadata.callsWithFunctionProducers++;
|
|
68
69
|
if (fCds.size <= 0 || (0, info_1.happensInEveryBranchSet)(fCds)) {
|
|
69
|
-
metadata.callsWithFunctionProducers++;
|
|
70
70
|
return [];
|
|
71
71
|
}
|
|
72
72
|
else {
|
|
73
|
-
|
|
73
|
+
for (const f of fCds) {
|
|
74
|
+
cdsOfProduces.add(f);
|
|
75
|
+
}
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
78
|
else {
|
|
@@ -84,28 +86,31 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
84
86
|
if (dest !== undefined && assignmentProducers.has((0, node_id_1.recoverName)(dest, dataflow.graph.idMap))) {
|
|
85
87
|
// we either have arg index 0 or 1 for the assignmentProducers destination, so we select the assignment value as 1-argIdx here
|
|
86
88
|
if (isConstantArgument(dataflow.graph, a, 1 - argIdx, analyzer.inspectContext())) {
|
|
87
|
-
const aCds = new Set(a.
|
|
89
|
+
const aCds = new Set(a.controlDependencies).difference(cds);
|
|
88
90
|
if (aCds.size <= 0 || (0, info_1.happensInEveryBranchSet)(aCds)) {
|
|
89
91
|
metadata.callsWithAssignmentProducers++;
|
|
90
92
|
return [];
|
|
91
93
|
}
|
|
92
94
|
else {
|
|
93
|
-
|
|
95
|
+
for (const f of aCds) {
|
|
96
|
+
cdsOfProduces.add(f);
|
|
97
|
+
}
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
|
-
else {
|
|
97
|
-
nonConstant = true;
|
|
98
|
-
}
|
|
99
100
|
}
|
|
100
101
|
}
|
|
102
|
+
if ((0, info_1.happensInEveryBranchSet)(cdsOfProduces)) {
|
|
103
|
+
// all producers happen in every branch, so we are good
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
101
106
|
if (nonConstant) {
|
|
102
107
|
metadata.callsWithNonConstantProducers++;
|
|
103
108
|
}
|
|
104
|
-
if (
|
|
109
|
+
if (cdsOfProduces.size > 0) {
|
|
105
110
|
metadata.callsWithOtherBranchProducers++;
|
|
106
111
|
}
|
|
107
112
|
return [{
|
|
108
|
-
certainty:
|
|
113
|
+
certainty: cdsOfProduces.size > 0 ? linter_format_1.LintingResultCertainty.Uncertain : linter_format_1.LintingResultCertainty.Certain,
|
|
109
114
|
function: element.target,
|
|
110
115
|
range: element.range
|
|
111
116
|
}];
|
|
@@ -41,7 +41,7 @@ export declare const USELESS_LOOP: {
|
|
|
41
41
|
readonly certainty: LintingRuleCertainty.BestEffort;
|
|
42
42
|
readonly tags: readonly [LintingRuleTag.Smell, LintingRuleTag.Readability];
|
|
43
43
|
readonly defaultConfig: {
|
|
44
|
-
readonly loopyFunctions: Set<"builtin:
|
|
44
|
+
readonly loopyFunctions: Set<"builtin:access" | "builtin:apply" | "builtin:assignment" | "builtin:assignment-like" | "builtin:default" | "builtin:eval" | "builtin:expression-list" | "builtin:for-loop" | "builtin:function-definition" | "builtin:get" | "builtin:if-then-else" | "builtin:library" | "builtin:list" | "builtin:pipe" | "builtin:quote" | "builtin:register-hook" | "builtin:repeat-loop" | "builtin:replacement" | "builtin:rm" | "builtin:source" | "builtin:special-bin-op" | "builtin:stopifnot" | "builtin:try" | "builtin:vector" | "builtin:while-loop">;
|
|
45
45
|
};
|
|
46
46
|
};
|
|
47
47
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eagleoutice/flowr",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.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": {
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"setup:dev": "git lfs fetch && npm ci && git config --local core.hooksPath .githooks/ && git push --dry-run",
|
|
16
16
|
"main": "npm run build:bundle-flowr && node dist/src/cli/flowr.min.js",
|
|
17
17
|
"flowr": "npm run main --",
|
|
18
|
-
"
|
|
18
|
+
"flowr:dev": "npm run main-dev --",
|
|
19
|
+
"main-dev": "node -r ts-node/register --watch src/cli/flowr.ts",
|
|
19
20
|
"publish-library": "cp .npmignore package.json README.md LICENSE dist/src/ && cd dist/src && npm publish --access public",
|
|
20
21
|
"release": "npx release-it --ci",
|
|
21
22
|
"stats": "ts-node src/cli/statistics-app.ts",
|
|
@@ -27,14 +28,14 @@
|
|
|
27
28
|
"export-quads": "ts-node src/cli/export-quads-app.ts",
|
|
28
29
|
"capabilities-markdown": "ts-node src/documentation/doc-capabilities.ts",
|
|
29
30
|
"wiki": "ts-node src/cli/wiki.ts",
|
|
30
|
-
"wiki:watch": "ts-node
|
|
31
|
+
"wiki:watch": "node -r ts-node/register --watch src/cli/wiki.ts --keep-alive",
|
|
31
32
|
"build": "tsc --project .",
|
|
32
33
|
"build-dev": "npm run build && npm run build:copy-wasm",
|
|
33
34
|
"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",
|
|
34
35
|
"build:copy-wasm": "mkdir -p dist/node_modules/@eagleoutice/tree-sitter-r/ && mkdir -p dist/node_modules/web-tree-sitter && cp node_modules/@eagleoutice/tree-sitter-r/tree-sitter-r.wasm dist/node_modules/@eagleoutice/tree-sitter-r/ && cp node_modules/web-tree-sitter/tree-sitter.wasm dist/node_modules/web-tree-sitter/",
|
|
35
36
|
"lint-local": "npx eslint --version && npx eslint src/ test/ --rule \"no-warning-comments: off\"",
|
|
36
37
|
"lint": "npm run license-compat -- --summary && npx eslint --version && npx eslint src/ test/",
|
|
37
|
-
"license-compat": "license-checker --onlyAllow 'MIT;MIT OR X11;GPLv2;LGPL;GNUGPL;ISC;Apache-2.0;FreeBSD;BSD-2-Clause;clearbsd;ModifiedBSD;BSD-3-Clause;Python-2.0;Unlicense;WTFPL;BlueOak-1.0.0;CC-BY-4.0;CC-BY-3.0;CC0-1.0;0BSD'",
|
|
38
|
+
"license-compat": "license-checker-rseidelsohn --onlyAllow 'MIT;MIT OR X11;GPLv2;LGPL;GNUGPL;ISC;Apache-2.0;FreeBSD;BSD-2-Clause;clearbsd;ModifiedBSD;BSD-3-Clause;Python-2.0;Unlicense;WTFPL;BlueOak-1.0.0;CC-BY-4.0;CC-BY-3.0;CC0-1.0;0BSD'",
|
|
38
39
|
"doc": "typedoc",
|
|
39
40
|
"test": "vitest --exclude \"test/system-tests/**\" --config test/vitest.config.mts",
|
|
40
41
|
"test:system": "vitest --dir test/system-tests --config test/system-tests/vitest.config.mts",
|
|
@@ -182,17 +183,16 @@
|
|
|
182
183
|
"@types/ws": "^8.18.1",
|
|
183
184
|
"@typescript-eslint/eslint-plugin": "^8.40.0",
|
|
184
185
|
"@vitest/coverage-v8": "^3.2.4",
|
|
185
|
-
"esbuild": "^0.
|
|
186
|
+
"esbuild": "^0.27.2",
|
|
186
187
|
"eslint": "^9.34.0",
|
|
187
|
-
"license-checker": "^
|
|
188
|
+
"license-checker-rseidelsohn": "^4.4.2",
|
|
188
189
|
"npm-run-all": "^4.1.5",
|
|
189
|
-
"release-it": "^19.
|
|
190
|
+
"release-it": "^19.2.2",
|
|
190
191
|
"ts-node": "^10.9.2",
|
|
191
|
-
"ts-node-dev": "^2.0.0",
|
|
192
192
|
"typedoc": "^0.27.7",
|
|
193
193
|
"typedoc-plugin-missing-exports": "^3.1.0",
|
|
194
194
|
"typedoc-theme-hierarchy": "^5.0.4",
|
|
195
|
-
"typedoc-umlclass": "^0.10.
|
|
195
|
+
"typedoc-umlclass": "^0.10.2",
|
|
196
196
|
"typescript": "^5.7.3",
|
|
197
197
|
"vitest": "^3.2.4"
|
|
198
198
|
},
|
|
@@ -9,6 +9,7 @@ import type { CfgSimplificationPassName } from '../../control-flow/cfg-simplific
|
|
|
9
9
|
import type { ControlFlowInformation } from '../../control-flow/control-flow-graph';
|
|
10
10
|
import type { CfgKind } from '../cfg-kind';
|
|
11
11
|
import type { FlowrAnalyzerContext } from '../context/flowr-analyzer-context';
|
|
12
|
+
import type { CallGraph } from '../../dataflow/graph/call-graph';
|
|
12
13
|
interface FlowrAnalyzerCacheOptions<Parser extends KnownParser> {
|
|
13
14
|
parser: Parser;
|
|
14
15
|
context: FlowrAnalyzerContext;
|
|
@@ -23,6 +24,7 @@ export declare class FlowrAnalyzerCache<Parser extends KnownParser> extends Flow
|
|
|
23
24
|
private args;
|
|
24
25
|
private pipeline;
|
|
25
26
|
private controlFlowCache;
|
|
27
|
+
private callGraphCache;
|
|
26
28
|
protected constructor(args: FlowrAnalyzerCacheOptions<Parser>);
|
|
27
29
|
private initCacheProviders;
|
|
28
30
|
static create<Parser extends KnownParser>(data: FlowrAnalyzerCacheOptions<Parser>): FlowrAnalyzerCache<Parser>;
|
|
@@ -80,5 +82,14 @@ export declare class FlowrAnalyzerCache<Parser extends KnownParser> extends Flow
|
|
|
80
82
|
* @see {@link FlowrAnalyzerCache#controlflow} - to get the control flow graph, computing if necessary.
|
|
81
83
|
*/
|
|
82
84
|
peekControlflow(kind: CfgKind, simplifications: readonly CfgSimplificationPassName[] | undefined): ControlFlowInformation | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Get the call graph for the request, computing if necessary.
|
|
87
|
+
* @param force - Do not use the cache, instead force new analyses.
|
|
88
|
+
*/
|
|
89
|
+
callGraph(force?: boolean): Promise<CallGraph>;
|
|
90
|
+
/**
|
|
91
|
+
* Get the call graph for the request if already available, otherwise return `undefined`.
|
|
92
|
+
*/
|
|
93
|
+
peekCallGraph(): CallGraph | undefined;
|
|
83
94
|
}
|
|
84
95
|
export {};
|
|
@@ -5,6 +5,7 @@ const flowr_cache_1 = require("./flowr-cache");
|
|
|
5
5
|
const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
|
|
6
6
|
const assert_1 = require("../../util/assert");
|
|
7
7
|
const flowr_analyzer_controlflow_cache_1 = require("./flowr-analyzer-controlflow-cache");
|
|
8
|
+
const call_graph_1 = require("../../dataflow/graph/call-graph");
|
|
8
9
|
/**
|
|
9
10
|
* This provides the full analyzer caching layer, please avoid using this directly
|
|
10
11
|
* and prefer the {@link FlowrAnalyzer}.
|
|
@@ -13,6 +14,7 @@ class FlowrAnalyzerCache extends flowr_cache_1.FlowrCache {
|
|
|
13
14
|
args;
|
|
14
15
|
pipeline = undefined;
|
|
15
16
|
controlFlowCache = undefined;
|
|
17
|
+
callGraphCache = undefined;
|
|
16
18
|
constructor(args) {
|
|
17
19
|
super();
|
|
18
20
|
this.args = args;
|
|
@@ -24,6 +26,7 @@ class FlowrAnalyzerCache extends flowr_cache_1.FlowrCache {
|
|
|
24
26
|
getId: this.args.getId
|
|
25
27
|
});
|
|
26
28
|
this.controlFlowCache = new flowr_analyzer_controlflow_cache_1.FlowrAnalyzerControlFlowCache();
|
|
29
|
+
this.callGraphCache = undefined;
|
|
27
30
|
}
|
|
28
31
|
static create(data) {
|
|
29
32
|
return new FlowrAnalyzerCache(data);
|
|
@@ -132,6 +135,22 @@ class FlowrAnalyzerCache extends flowr_cache_1.FlowrCache {
|
|
|
132
135
|
peekControlflow(kind, simplifications) {
|
|
133
136
|
return this.controlFlowCache.peek(kind, simplifications);
|
|
134
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Get the call graph for the request, computing if necessary.
|
|
140
|
+
* @param force - Do not use the cache, instead force new analyses.
|
|
141
|
+
*/
|
|
142
|
+
async callGraph(force) {
|
|
143
|
+
if (!this.callGraphCache || force) {
|
|
144
|
+
this.callGraphCache = (0, call_graph_1.computeCallGraph)((await this.dataflow(force)).graph);
|
|
145
|
+
}
|
|
146
|
+
return this.callGraphCache;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get the call graph for the request if already available, otherwise return `undefined`.
|
|
150
|
+
*/
|
|
151
|
+
peekCallGraph() {
|
|
152
|
+
return this.callGraphCache;
|
|
153
|
+
}
|
|
135
154
|
}
|
|
136
155
|
exports.FlowrAnalyzerCache = FlowrAnalyzerCache;
|
|
137
156
|
//# sourceMappingURL=flowr-analyzer-cache.js.map
|
|
@@ -23,7 +23,11 @@ export interface ReadOnlyFlowrAnalyzerDependenciesContext {
|
|
|
23
23
|
* @param name - The name of the dependency to get.
|
|
24
24
|
* @returns The dependency with the given name, or undefined if it does not exist.
|
|
25
25
|
*/
|
|
26
|
-
getDependency(name: string): Package | undefined;
|
|
26
|
+
getDependency(name: string): Readonly<Package> | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Get all dependencies known to this context.
|
|
29
|
+
*/
|
|
30
|
+
getDependencies(): readonly Readonly<Package>[];
|
|
27
31
|
}
|
|
28
32
|
/**
|
|
29
33
|
* This context is responsible for managing the dependencies of the project, including their versions and interplays with {@link FlowrAnalyzerPackageVersionsPlugin}s.
|
|
@@ -40,4 +44,5 @@ export declare class FlowrAnalyzerDependenciesContext extends AbstractFlowrAnaly
|
|
|
40
44
|
resolveStaticDependencies(): void;
|
|
41
45
|
addDependency(pkg: Package): void;
|
|
42
46
|
getDependency(name: string): Package | undefined;
|
|
47
|
+
getDependencies(): Package[];
|
|
43
48
|
}
|
|
@@ -40,6 +40,12 @@ class FlowrAnalyzerDependenciesContext extends abstract_flowr_analyzer_context_1
|
|
|
40
40
|
}
|
|
41
41
|
return this.dependencies.get(name);
|
|
42
42
|
}
|
|
43
|
+
getDependencies() {
|
|
44
|
+
if (!this.staticsLoaded) {
|
|
45
|
+
this.resolveStaticDependencies();
|
|
46
|
+
}
|
|
47
|
+
return Array.from(this.dependencies.values());
|
|
48
|
+
}
|
|
43
49
|
}
|
|
44
50
|
exports.FlowrAnalyzerDependenciesContext = FlowrAnalyzerDependenciesContext;
|
|
45
51
|
//# sourceMappingURL=flowr-analyzer-dependencies-context.js.map
|
|
@@ -6,6 +6,7 @@ import { FlowrAnalyzerFilePlugin } from '../plugins/file-plugins/flowr-analyzer-
|
|
|
6
6
|
import { FlowrFile, type FlowrFileProvider, FileRole } from './flowr-file';
|
|
7
7
|
import type { FlowrDescriptionFile } from '../plugins/file-plugins/files/flowr-description-file';
|
|
8
8
|
import type { FlowrNewsFile } from '../plugins/file-plugins/files/flowr-news-file';
|
|
9
|
+
import type { FlowrNamespaceFile } from '../plugins/file-plugins/files/flowr-namespace-file';
|
|
9
10
|
/**
|
|
10
11
|
* This is a request to process a folder as a project, which will be expanded by the registered {@link FlowrAnalyzerProjectDiscoveryPlugin}s.
|
|
11
12
|
*/
|
|
@@ -20,7 +21,9 @@ export type RAnalysisRequest = RParseRequest | RProjectAnalysisRequest;
|
|
|
20
21
|
export type RoleBasedFiles = {
|
|
21
22
|
[FileRole.Description]: FlowrDescriptionFile[];
|
|
22
23
|
[FileRole.News]: FlowrNewsFile[];
|
|
23
|
-
[FileRole.Namespace]:
|
|
24
|
+
[FileRole.Namespace]: FlowrNamespaceFile[];
|
|
25
|
+
[FileRole.Vignette]: FlowrFileProvider[];
|
|
26
|
+
[FileRole.Test]: FlowrFileProvider[];
|
|
24
27
|
[FileRole.Source]: FlowrFileProvider[];
|
|
25
28
|
[FileRole.Data]: FlowrFileProvider[];
|
|
26
29
|
[FileRole.Other]: FlowrFileProvider[];
|
|
@@ -123,7 +126,7 @@ export declare class FlowrAnalyzerFilesContext extends AbstractFlowrAnalyzerCont
|
|
|
123
126
|
* Add a file to the context. If the file has a special role, it will be added to the corresponding list of special files.
|
|
124
127
|
* This method also applies any registered {@link FlowrAnalyzerFilePlugin}s to the file before adding it to the context.
|
|
125
128
|
*/
|
|
126
|
-
addFile(file: string | FlowrFileProvider | RParseRequestFromFile,
|
|
129
|
+
addFile(file: string | FlowrFileProvider | RParseRequestFromFile, roles?: readonly FileRole[]): FlowrFileProvider<{
|
|
127
130
|
toString(): string;
|
|
128
131
|
}>;
|
|
129
132
|
hasFile(path: string): boolean;
|
|
@@ -14,9 +14,9 @@ const log_1 = require("../../util/log");
|
|
|
14
14
|
const fs_1 = __importDefault(require("fs"));
|
|
15
15
|
const path_1 = __importDefault(require("path"));
|
|
16
16
|
const fileLog = log_1.log.getSubLogger({ name: 'flowr-analyzer-files-context' });
|
|
17
|
-
function wrapFile(file,
|
|
17
|
+
function wrapFile(file, roles) {
|
|
18
18
|
if (typeof file === 'string') {
|
|
19
|
-
return new flowr_file_1.FlowrTextFile(file,
|
|
19
|
+
return new flowr_file_1.FlowrTextFile(file, roles);
|
|
20
20
|
}
|
|
21
21
|
else if ('request' in file) {
|
|
22
22
|
return flowr_file_1.FlowrFile.fromRequest(file);
|
|
@@ -40,14 +40,7 @@ class FlowrAnalyzerFilesContext extends abstract_flowr_analyzer_context_1.Abstra
|
|
|
40
40
|
/** these are all the paths of files that have been considered by the dataflow graph (even if not added) */
|
|
41
41
|
consideredFiles = [];
|
|
42
42
|
/* files that are part of the analysis, e.g. source files */
|
|
43
|
-
byRole =
|
|
44
|
-
[flowr_file_1.FileRole.Description]: [],
|
|
45
|
-
[flowr_file_1.FileRole.News]: [],
|
|
46
|
-
[flowr_file_1.FileRole.Namespace]: [],
|
|
47
|
-
[flowr_file_1.FileRole.Source]: [],
|
|
48
|
-
[flowr_file_1.FileRole.Data]: [],
|
|
49
|
-
[flowr_file_1.FileRole.Other]: []
|
|
50
|
-
};
|
|
43
|
+
byRole = Object.fromEntries(Object.values(flowr_file_1.FileRole).map(k => [k, []]));
|
|
51
44
|
constructor(loadingOrder, plugins, fileLoaders) {
|
|
52
45
|
super(loadingOrder.getAttachedContext(), flowr_analyzer_project_discovery_plugin_1.FlowrAnalyzerProjectDiscoveryPlugin.defaultPlugin(), plugins);
|
|
53
46
|
this.fileLoaders = [...fileLoaders, flowr_analyzer_file_plugin_1.FlowrAnalyzerFilePlugin.defaultPlugin()];
|
|
@@ -56,6 +49,9 @@ class FlowrAnalyzerFilesContext extends abstract_flowr_analyzer_context_1.Abstra
|
|
|
56
49
|
reset() {
|
|
57
50
|
this.loadingOrder.reset();
|
|
58
51
|
this.files = new Map();
|
|
52
|
+
this.consideredFiles.length = 0;
|
|
53
|
+
this.inlineFiles.length = 0;
|
|
54
|
+
this.byRole = Object.fromEntries(Object.values(flowr_file_1.FileRole).map(k => [k, []]));
|
|
59
55
|
}
|
|
60
56
|
/**
|
|
61
57
|
* Record that a file has been considered during dataflow analysis.
|
|
@@ -91,7 +87,7 @@ class FlowrAnalyzerFilesContext extends abstract_flowr_analyzer_context_1.Abstra
|
|
|
91
87
|
this.addRequest(req);
|
|
92
88
|
}
|
|
93
89
|
else {
|
|
94
|
-
this.addFile(req, req.
|
|
90
|
+
this.addFile(req, req.roles);
|
|
95
91
|
}
|
|
96
92
|
}
|
|
97
93
|
}
|
|
@@ -107,8 +103,8 @@ class FlowrAnalyzerFilesContext extends abstract_flowr_analyzer_context_1.Abstra
|
|
|
107
103
|
* Add a file to the context. If the file has a special role, it will be added to the corresponding list of special files.
|
|
108
104
|
* This method also applies any registered {@link FlowrAnalyzerFilePlugin}s to the file before adding it to the context.
|
|
109
105
|
*/
|
|
110
|
-
addFile(file,
|
|
111
|
-
const f = this.fileLoadPlugins(wrapFile(file,
|
|
106
|
+
addFile(file, roles) {
|
|
107
|
+
const f = this.fileLoadPlugins(wrapFile(file, roles));
|
|
112
108
|
if (f.path() === flowr_file_1.FlowrFile.INLINE_PATH) {
|
|
113
109
|
this.inlineFiles.push(f);
|
|
114
110
|
}
|
|
@@ -117,8 +113,10 @@ class FlowrAnalyzerFilesContext extends abstract_flowr_analyzer_context_1.Abstra
|
|
|
117
113
|
(0, assert_1.guard)(exist === undefined || exist === f, `File ${f.path()} already added to the context.`);
|
|
118
114
|
this.files.set(f.path(), f);
|
|
119
115
|
}
|
|
120
|
-
if (f.
|
|
121
|
-
|
|
116
|
+
if (f.roles) {
|
|
117
|
+
for (const r of f.roles) {
|
|
118
|
+
this.byRole[r].push(f);
|
|
119
|
+
}
|
|
122
120
|
}
|
|
123
121
|
return f;
|
|
124
122
|
}
|
|
@@ -157,8 +155,17 @@ class FlowrAnalyzerFilesContext extends abstract_flowr_analyzer_context_1.Abstra
|
|
|
157
155
|
for (const loader of this.fileLoaders) {
|
|
158
156
|
if (loader.applies(f.path())) {
|
|
159
157
|
fileLog.debug(`Applying file loader ${loader.name} to file ${f.path()}`);
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
const res = loader.processor(this.ctx, fFinal);
|
|
159
|
+
if (Array.isArray(res)) {
|
|
160
|
+
fFinal = res[0];
|
|
161
|
+
if (!res[1]) {
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
fFinal = res;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
162
169
|
}
|
|
163
170
|
}
|
|
164
171
|
return fFinal;
|
|
@@ -17,6 +17,10 @@ export declare enum FileRole {
|
|
|
17
17
|
Namespace = "namespace",
|
|
18
18
|
/** The `NEWS` file in R packages */
|
|
19
19
|
News = "news",
|
|
20
|
+
/** Vignette files, e.g., R Markdown files in the `vignettes/` folder */
|
|
21
|
+
Vignette = "vignette",
|
|
22
|
+
/** Test source files, e.g., files in the `tests/` folder */
|
|
23
|
+
Test = "test",
|
|
20
24
|
/** Data files, e.g., `R/sysdata.rda`, currently not specially supported. */
|
|
21
25
|
Data = "data",
|
|
22
26
|
/**
|
|
@@ -49,11 +53,11 @@ export interface FlowrFileProvider<Content extends {
|
|
|
49
53
|
toString(): string;
|
|
50
54
|
}> {
|
|
51
55
|
/**
|
|
52
|
-
* The role of this file, if any, in general your file should _not_ decide for itself what role it has in the project context,
|
|
56
|
+
* The role(s) of this file, if any, in general your file should _not_ decide for itself what role it has in the project context,
|
|
53
57
|
* this is for the loaders plugins to decide (cf. {@link PluginType}) as they can, e.g., respect ignore files, updated mappings, etc.
|
|
54
58
|
* However, they will 1) set this role as soon as they decide on it (using {@link assignRole}) and 2) try to respect an already assigned role (however, user configurations may override this).
|
|
55
59
|
*/
|
|
56
|
-
|
|
60
|
+
roles?: readonly FileRole[];
|
|
57
61
|
/**
|
|
58
62
|
* The path to the file, this is used for identification and logging purposes.
|
|
59
63
|
* If the file does not exist on disk, this can be a virtual path (e.g. for inline files).
|
|
@@ -80,9 +84,10 @@ export interface FlowrFileProvider<Content extends {
|
|
|
80
84
|
export declare abstract class FlowrFile<Content extends StringableContent = StringableContent> implements FlowrFileProvider<Content> {
|
|
81
85
|
private contentCache;
|
|
82
86
|
protected filePath: PathLike;
|
|
83
|
-
|
|
87
|
+
private _roles?;
|
|
84
88
|
static readonly INLINE_PATH = "@inline";
|
|
85
|
-
constructor(filePath: PathLike,
|
|
89
|
+
constructor(filePath: PathLike, roles?: readonly FileRole[]);
|
|
90
|
+
get roles(): readonly FileRole[] | undefined;
|
|
86
91
|
path(): string;
|
|
87
92
|
content(): Content;
|
|
88
93
|
protected abstract loadContent(): Content;
|
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.FlowrInlineTextFile = exports.FlowrTextFile = exports.FlowrFile = exports.FileRole = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const assert_1 = require("../../util/assert");
|
|
9
8
|
/**
|
|
10
9
|
* Some files have a special meaning in R projects, e.g., the `DESCRIPTION` file in R packages.
|
|
11
10
|
* This list may be extended in the future and reflects files that the {@link FlowrAnalyzer} can do something interesting with.
|
|
@@ -19,6 +18,10 @@ var FileRole;
|
|
|
19
18
|
FileRole["Namespace"] = "namespace";
|
|
20
19
|
/** The `NEWS` file in R packages */
|
|
21
20
|
FileRole["News"] = "news";
|
|
21
|
+
/** Vignette files, e.g., R Markdown files in the `vignettes/` folder */
|
|
22
|
+
FileRole["Vignette"] = "vignette";
|
|
23
|
+
/** Test source files, e.g., files in the `tests/` folder */
|
|
24
|
+
FileRole["Test"] = "test";
|
|
22
25
|
/** Data files, e.g., `R/sysdata.rda`, currently not specially supported. */
|
|
23
26
|
FileRole["Data"] = "data";
|
|
24
27
|
/**
|
|
@@ -39,11 +42,14 @@ var FileRole;
|
|
|
39
42
|
class FlowrFile {
|
|
40
43
|
contentCache;
|
|
41
44
|
filePath;
|
|
42
|
-
|
|
45
|
+
_roles;
|
|
43
46
|
static INLINE_PATH = '@inline';
|
|
44
|
-
constructor(filePath,
|
|
47
|
+
constructor(filePath, roles) {
|
|
45
48
|
this.filePath = filePath;
|
|
46
|
-
this.
|
|
49
|
+
this._roles = roles ? Array.from(roles) : undefined;
|
|
50
|
+
}
|
|
51
|
+
get roles() {
|
|
52
|
+
return this._roles;
|
|
47
53
|
}
|
|
48
54
|
path() {
|
|
49
55
|
return this.filePath.toString();
|
|
@@ -55,8 +61,16 @@ class FlowrFile {
|
|
|
55
61
|
return this.contentCache;
|
|
56
62
|
}
|
|
57
63
|
assignRole(role) {
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
if (this._roles === undefined) {
|
|
65
|
+
this._roles = [role];
|
|
66
|
+
}
|
|
67
|
+
else if (this._roles.includes(role)) {
|
|
68
|
+
// already assigned
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this._roles.push(role);
|
|
73
|
+
}
|
|
60
74
|
}
|
|
61
75
|
/**
|
|
62
76
|
* Creates a {@link FlowrFile} from a given {@link RParseRequest}.
|
|
@@ -15,6 +15,7 @@ import type { RAnalysisRequest } from './context/flowr-analyzer-files-context';
|
|
|
15
15
|
import type { RParseRequestFromFile } from '../r-bridge/retriever';
|
|
16
16
|
import { fileProtocol } from '../r-bridge/retriever';
|
|
17
17
|
import type { FlowrFileProvider } from './context/flowr-file';
|
|
18
|
+
import type { CallGraph } from '../dataflow/graph/call-graph';
|
|
18
19
|
/**
|
|
19
20
|
* Extends the {@link ReadonlyFlowrAnalysisProvider} with methods that allow modifying the analyzer state.
|
|
20
21
|
*/
|
|
@@ -102,6 +103,14 @@ export interface ReadonlyFlowrAnalysisProvider<Parser extends KnownParser = Know
|
|
|
102
103
|
* Peek at the control flow graph (CFG) for the request, if it was already computed.
|
|
103
104
|
*/
|
|
104
105
|
peekControlflow(simplifications?: readonly CfgSimplificationPassName[], kind?: CfgKind): ControlFlowInformation | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Calculate the call graph for the request.
|
|
108
|
+
*/
|
|
109
|
+
callGraph(force?: boolean): Promise<CallGraph>;
|
|
110
|
+
/**
|
|
111
|
+
* Peek at the call graph for the request, if it was already computed.
|
|
112
|
+
*/
|
|
113
|
+
peekCallGraph(): CallGraph | undefined;
|
|
105
114
|
/**
|
|
106
115
|
* Access the query API for the request.
|
|
107
116
|
* @param query - The list of queries.
|
|
@@ -167,6 +176,8 @@ export declare class FlowrAnalyzer<Parser extends KnownParser = KnownParser> imp
|
|
|
167
176
|
runFull(force?: boolean): Promise<void>;
|
|
168
177
|
controlflow(simplifications?: readonly CfgSimplificationPassName[], kind?: CfgKind, force?: boolean): Promise<ControlFlowInformation>;
|
|
169
178
|
peekControlflow(simplifications?: readonly CfgSimplificationPassName[], kind?: CfgKind): ControlFlowInformation | undefined;
|
|
179
|
+
callGraph(force?: boolean): Promise<CallGraph>;
|
|
180
|
+
peekCallGraph(): CallGraph | undefined;
|
|
170
181
|
query<Types extends SupportedQueryTypes = SupportedQueryTypes>(query: Queries<Types>): Promise<QueryResults<Types>>;
|
|
171
182
|
runSearch<Search extends FlowrSearchLike>(search: Search): Promise<GetSearchElements<SearchOutput<Search>>>;
|
|
172
183
|
/**
|