@eagleoutice/flowr 2.10.3 → 2.10.5

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.
Files changed (94) hide show
  1. package/README.md +43 -26
  2. package/abstract-interpretation/absint-visitor.d.ts +17 -21
  3. package/abstract-interpretation/absint-visitor.js +47 -48
  4. package/abstract-interpretation/data-frame/dataframe-domain.d.ts +0 -3
  5. package/abstract-interpretation/data-frame/shape-inference.d.ts +2 -1
  6. package/abstract-interpretation/data-frame/shape-inference.js +5 -4
  7. package/abstract-interpretation/domains/abstract-domain.d.ts +17 -16
  8. package/abstract-interpretation/domains/abstract-domain.js +25 -27
  9. package/abstract-interpretation/domains/bounded-set-domain.js +1 -1
  10. package/abstract-interpretation/domains/multi-value-state-domain.d.ts +32 -0
  11. package/abstract-interpretation/domains/multi-value-state-domain.js +60 -0
  12. package/abstract-interpretation/domains/partial-product-domain.d.ts +43 -0
  13. package/abstract-interpretation/domains/partial-product-domain.js +163 -0
  14. package/abstract-interpretation/domains/product-domain.d.ts +2 -29
  15. package/abstract-interpretation/domains/product-domain.js +6 -123
  16. package/abstract-interpretation/domains/set-range-domain.js +3 -3
  17. package/abstract-interpretation/domains/set-upper-bound-domain.js +1 -1
  18. package/abstract-interpretation/domains/singleton-domain.js +1 -1
  19. package/abstract-interpretation/domains/state-abstract-domain.d.ts +13 -28
  20. package/abstract-interpretation/domains/state-abstract-domain.js +16 -38
  21. package/abstract-interpretation/domains/state-domain-like.d.ts +36 -0
  22. package/abstract-interpretation/domains/state-domain-like.js +3 -0
  23. package/cli/flowr.js +11 -1
  24. package/config.d.ts +7 -0
  25. package/config.js +22 -3
  26. package/control-flow/semantic-cfg-guided-visitor.d.ts +4 -0
  27. package/control-flow/semantic-cfg-guided-visitor.js +20 -32
  28. package/dataflow/environments/default-builtin-config.d.ts +10 -0
  29. package/dataflow/environments/default-builtin-config.js +2 -1
  30. package/dataflow/internal/process/functions/call/built-in/built-in-eval.d.ts +2 -0
  31. package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +38 -21
  32. package/documentation/doc-readme.js +13 -2
  33. package/documentation/wiki-absint.d.ts +1 -2
  34. package/documentation/wiki-absint.js +34 -10
  35. package/documentation/wiki-analyzer.js +3 -4
  36. package/documentation/wiki-interface.js +21 -16
  37. package/documentation/wiki-linter.js +1 -1
  38. package/linter/linter-rules.d.ts +12 -12
  39. package/linter/linter-rules.js +2 -2
  40. package/linter/rules/network-functions.d.ts +1 -1
  41. package/linter/rules/network-functions.js +8 -2
  42. package/linter/rules/problematic-inputs.d.ts +43 -0
  43. package/linter/rules/problematic-inputs.js +110 -0
  44. package/linter/rules/seeded-randomness.d.ts +1 -1
  45. package/linter/rules/seeded-randomness.js +8 -1
  46. package/package.json +4 -4
  47. package/project/flowr-analyzer-builder.d.ts +6 -3
  48. package/project/flowr-analyzer-builder.js +12 -5
  49. package/project/plugins/file-plugins/files/flowr-rmarkdown-file.d.ts +4 -3
  50. package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +17 -4
  51. package/project/plugins/flowr-analyzer-plugin.d.ts +1 -1
  52. package/project/plugins/flowr-analyzer-plugin.js +1 -1
  53. package/queries/catalog/call-context-query/call-context-query-executor.js +2 -2
  54. package/queries/catalog/call-context-query/call-context-query-format.d.ts +1 -1
  55. package/queries/catalog/call-context-query/call-context-query-format.js +1 -2
  56. package/queries/catalog/dependencies-query/function-info/read-functions.js +6 -0
  57. package/queries/catalog/dependencies-query/function-info/write-functions.js +7 -0
  58. package/queries/catalog/input-sources-query/input-source-functions.d.ts +6 -0
  59. package/queries/catalog/input-sources-query/input-source-functions.js +50 -0
  60. package/queries/catalog/input-sources-query/input-sources-query-executor.d.ts +1 -1
  61. package/queries/catalog/input-sources-query/input-sources-query-executor.js +19 -31
  62. package/queries/catalog/input-sources-query/input-sources-query-format.d.ts +2 -1
  63. package/queries/catalog/input-sources-query/input-sources-query-format.js +26 -8
  64. package/queries/catalog/input-sources-query/simple-input-classifier.d.ts +33 -28
  65. package/queries/catalog/input-sources-query/simple-input-classifier.js +192 -99
  66. package/r-bridge/lang-4.x/ast/model/model.d.ts +4 -4
  67. package/r-bridge/lang-4.x/ast/model/nodes/r-access.d.ts +3 -3
  68. package/r-bridge/lang-4.x/ast/model/nodes/r-argument.d.ts +3 -3
  69. package/r-bridge/lang-4.x/ast/model/nodes/r-binary-op.d.ts +3 -3
  70. package/r-bridge/lang-4.x/ast/model/nodes/r-break.d.ts +3 -3
  71. package/r-bridge/lang-4.x/ast/model/nodes/r-comment.d.ts +3 -3
  72. package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.d.ts +3 -3
  73. package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.d.ts +3 -3
  74. package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.d.ts +3 -3
  75. package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.d.ts +3 -3
  76. package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.d.ts +3 -3
  77. package/r-bridge/lang-4.x/ast/model/nodes/r-line-directive.d.ts +3 -3
  78. package/r-bridge/lang-4.x/ast/model/nodes/r-logical.d.ts +3 -3
  79. package/r-bridge/lang-4.x/ast/model/nodes/r-next.d.ts +3 -3
  80. package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +3 -3
  81. package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.d.ts +3 -3
  82. package/r-bridge/lang-4.x/ast/model/nodes/r-pipe.d.ts +3 -3
  83. package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.d.ts +3 -3
  84. package/r-bridge/lang-4.x/ast/model/nodes/r-string.d.ts +3 -3
  85. package/r-bridge/lang-4.x/ast/model/nodes/r-symbol.d.ts +3 -3
  86. package/r-bridge/lang-4.x/ast/model/nodes/r-unary-op.d.ts +3 -3
  87. package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.d.ts +3 -3
  88. package/util/record.d.ts +18 -3
  89. package/util/record.js +22 -1
  90. package/util/version.js +1 -1
  91. package/linter/rules/problematic-eval.d.ts +0 -44
  92. package/linter/rules/problematic-eval.js +0 -83
  93. package/project/plugins/flowr-analyzer-plugin-defaults.d.ts +0 -5
  94. package/project/plugins/flowr-analyzer-plugin-defaults.js +0 -37
package/README.md CHANGED
@@ -24,7 +24,7 @@ It offers a wide variety of features, for example:
24
24
 
25
25
  ```shell
26
26
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
27
- flowR repl using flowR v2.10.2, R grammar v14 (tree-sitter engine)
27
+ flowR repl using flowR v2.10.4, R grammar v14 (tree-sitter engine)
28
28
  R> :query @linter "read.csv(\"/root/x.txt\")"
29
29
  ```
30
30
 
@@ -39,13 +39,13 @@ It offers a wide variety of features, for example:
39
39
  ╰ File Path Validity (file-path-validity):
40
40
  ╰ certain:
41
41
  ╰ Path `/root/x.txt` at 1.1-23
42
- ╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 1, processTimeMs: 0
42
+ ╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 0, processTimeMs: 0
43
43
  ╰ Seeded Randomness (seeded-randomness):
44
44
  ╰ Metadata: consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 0, processTimeMs: 0
45
45
  ╰ Absolute Paths (absolute-file-paths):
46
46
  ╰ certain:
47
47
  ╰ Path `/root/x.txt` at 1.1-23
48
- ╰ Metadata: totalConsidered: 1, totalUnknown: 0, searchTimeMs: 0, processTimeMs: 0
48
+ ╰ Metadata: totalConsidered: 1, totalUnknown: 0, searchTimeMs: 1, processTimeMs: 0
49
49
  ╰ Unused Definitions (unused-definitions):
50
50
  ╰ Metadata: totalConsidered: 0, searchTimeMs: 0, processTimeMs: 0
51
51
  ╰ Naming Convention (naming-convention):
@@ -53,18 +53,18 @@ It offers a wide variety of features, for example:
53
53
  ╰ Network Functions (network-functions):
54
54
  ╰ Metadata: totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0
55
55
  ╰ Dataframe Access Validation (dataframe-access-validation):
56
- ╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 1
56
+ ╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 0
57
57
  ╰ Dead Code (dead-code):
58
58
  ╰ Metadata: consideredNodes: 5, searchTimeMs: 0, processTimeMs: 0
59
59
  ╰ Useless Loops (useless-loop):
60
60
  ╰ Metadata: numOfUselessLoops: 0, searchTimeMs: 0, processTimeMs: 0
61
- ╰ Problematic eval (problematic-eval):
61
+ ╰ Problematic inputs (problematic-inputs):
62
62
  ╰ Metadata: searchTimeMs: 0, processTimeMs: 0
63
63
  ╰ Stop without call.=False argument (stop-call):
64
- ╰ Metadata: consideredNodes: 0, searchTimeMs: 0, processTimeMs: 0
64
+ ╰ Metadata: consideredNodes: 0, searchTimeMs: 1, processTimeMs: 0
65
65
  ╰ Roxygen Arguments (roxygen-arguments):
66
66
  ╰ Metadata: searchTimeMs: 0, processTimeMs: 0
67
- All queries together required ≈2 ms (1ms accuracy, total 2 ms)
67
+ All queries together required ≈2 ms (1ms accuracy, total 3 ms)
68
68
  ```
69
69
 
70
70
 
@@ -86,7 +86,7 @@ It offers a wide variety of features, for example:
86
86
 
87
87
  _Results (prettified and summarized):_
88
88
 
89
- Query: **linter** (3 ms)\
89
+ Query: **linter** (2 ms)\
90
90
     ╰ **Deprecated Functions** (deprecated-functions):\
91
91
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 1, processTimeMs: 0</code>\
92
92
  &nbsp;&nbsp;&nbsp;╰ **File Path Validity** (file-path-validity):\
@@ -94,11 +94,11 @@ It offers a wide variety of features, for example:
94
94
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ Path `/root/x.txt` at 1.1-23\
95
95
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 0, processTimeMs: 0</code>\
96
96
  &nbsp;&nbsp;&nbsp;╰ **Seeded Randomness** (seeded-randomness):\
97
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 1, processTimeMs: 0</code>\
97
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 0, processTimeMs: 0</code>\
98
98
  &nbsp;&nbsp;&nbsp;╰ **Absolute Paths** (absolute-file-paths):\
99
99
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ certain:\
100
100
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ Path `/root/x.txt` at 1.1-23\
101
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalConsidered: 1, totalUnknown: 0, searchTimeMs: 0, processTimeMs: 0</code>\
101
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalConsidered: 1, totalUnknown: 0, searchTimeMs: 1, processTimeMs: 0</code>\
102
102
  &nbsp;&nbsp;&nbsp;╰ **Unused Definitions** (unused-definitions):\
103
103
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalConsidered: 0, searchTimeMs: 0, processTimeMs: 0</code>\
104
104
  &nbsp;&nbsp;&nbsp;╰ **Naming Convention** (naming-convention):\
@@ -108,20 +108,20 @@ It offers a wide variety of features, for example:
108
108
  &nbsp;&nbsp;&nbsp;╰ **Dataframe Access Validation** (dataframe-access-validation):\
109
109
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 0</code>\
110
110
  &nbsp;&nbsp;&nbsp;╰ **Dead Code** (dead-code):\
111
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>consideredNodes: 5, searchTimeMs: 1, processTimeMs: 0</code>\
111
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>consideredNodes: 5, searchTimeMs: 0, processTimeMs: 0</code>\
112
112
  &nbsp;&nbsp;&nbsp;╰ **Useless Loops** (useless-loop):\
113
113
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>numOfUselessLoops: 0, searchTimeMs: 0, processTimeMs: 0</code>\
114
- &nbsp;&nbsp;&nbsp;╰ **Problematic eval** (problematic-eval):\
114
+ &nbsp;&nbsp;&nbsp;╰ **Problematic inputs** (problematic-inputs):\
115
115
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>searchTimeMs: 0, processTimeMs: 0</code>\
116
116
  &nbsp;&nbsp;&nbsp;╰ **Stop without call.=False argument** (stop-call):\
117
117
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>consideredNodes: 0, searchTimeMs: 0, processTimeMs: 0</code>\
118
118
  &nbsp;&nbsp;&nbsp;╰ **Roxygen Arguments** (roxygen-arguments):\
119
119
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>searchTimeMs: 0, processTimeMs: 0</code>\
120
- _All queries together required ≈3 ms (1ms accuracy, total 3 ms)_
120
+ _All queries together required ≈2 ms (1ms accuracy, total 2 ms)_
121
121
 
122
122
  <details> <summary style="color:gray">Show Detailed Results as Json</summary>
123
123
 
124
- The analysis required _2.5 ms_ (including parsing and normalization and the query) within the generation environment.
124
+ The analysis required _2.4 ms_ (including parsing and normalization and the query) within the generation environment.
125
125
 
126
126
  In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
127
127
  Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki/Interface) wiki page for more information on how to get those.
@@ -173,7 +173,7 @@ It offers a wide variety of features, for example:
173
173
  "callsWithAssignmentProducers": 0,
174
174
  "callsWithNonConstantProducers": 0,
175
175
  "callsWithOtherBranchProducers": 0,
176
- "searchTimeMs": 1,
176
+ "searchTimeMs": 0,
177
177
  "processTimeMs": 0
178
178
  }
179
179
  },
@@ -193,7 +193,7 @@ It offers a wide variety of features, for example:
193
193
  ".meta": {
194
194
  "totalConsidered": 1,
195
195
  "totalUnknown": 0,
196
- "searchTimeMs": 0,
196
+ "searchTimeMs": 1,
197
197
  "processTimeMs": 0
198
198
  }
199
199
  },
@@ -237,7 +237,7 @@ It offers a wide variety of features, for example:
237
237
  "results": [],
238
238
  ".meta": {
239
239
  "consideredNodes": 5,
240
- "searchTimeMs": 1,
240
+ "searchTimeMs": 0,
241
241
  "processTimeMs": 0
242
242
  }
243
243
  },
@@ -249,7 +249,7 @@ It offers a wide variety of features, for example:
249
249
  "processTimeMs": 0
250
250
  }
251
251
  },
252
- "problematic-eval": {
252
+ "problematic-inputs": {
253
253
  "results": [],
254
254
  ".meta": {
255
255
  "searchTimeMs": 0,
@@ -273,11 +273,11 @@ It offers a wide variety of features, for example:
273
273
  }
274
274
  },
275
275
  ".meta": {
276
- "timing": 3
276
+ "timing": 2
277
277
  }
278
278
  },
279
279
  ".meta": {
280
- "timing": 3
280
+ "timing": 2
281
281
  }
282
282
  }
283
283
  ```
@@ -342,7 +342,7 @@ It offers a wide variety of features, for example:
342
342
 
343
343
  ```shell
344
344
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
345
- flowR repl using flowR v2.10.2, R grammar v14 (tree-sitter engine)
345
+ flowR repl using flowR v2.10.4, R grammar v14 (tree-sitter engine)
346
346
  R> :query @static-slice (11@sum) file://test/testfiles/example.R
347
347
  ```
348
348
 
@@ -390,7 +390,7 @@ It offers a wide variety of features, for example:
390
390
 
391
391
 
392
392
  * 🚀 **fast call-graph, data-, and control-flow graphs**\
393
- Within just [<i><span title="This measurement is automatically fetched from the latest benchmark!">100.4 ms</span></i> (as of Apr 2, 2026)](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark),
393
+ Within just [<i><span title="This measurement is automatically fetched from the latest benchmark!">100.2 ms</span></i> (as of Apr 8, 2026)](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark),
394
394
  _flowR_ can analyze the data- and control-flow of the average real-world R&nbsp;script. See the [benchmarks](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark) for more information,
395
395
  and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/dataflow-graph) for more details on the [dataflow graphs](https://github.com/flowr-analysis/flowr/wiki/dataflow-graph) as well as [call graphs](https://github.com/flowr-analysis/flowr/wiki/dataflow-graph#perspectives-cg).
396
396
 
@@ -426,7 +426,7 @@ It offers a wide variety of features, for example:
426
426
 
427
427
  ```shell
428
428
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
429
- flowR repl using flowR v2.10.2, R grammar v14 (tree-sitter engine)
429
+ flowR repl using flowR v2.10.4, R grammar v14 (tree-sitter engine)
430
430
  R> :dataflow* test/testfiles/example.R
431
431
  ```
432
432
 
@@ -734,7 +734,7 @@ It offers a wide variety of features, for example:
734
734
  ```
735
735
 
736
736
 
737
- (The analysis required _1.6 ms_ (including parse and normalize, using the [tree-sitter](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
737
+ (The analysis required _1.8 ms_ (including parse and normalize, using the [tree-sitter](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
738
738
 
739
739
 
740
740
 
@@ -799,8 +799,25 @@ please check out flowR's [Zenodo archive](https://zenodo.org/doi/10.5281/zenodo.
799
799
  If you are interested in the theoretical background of _flowR_,
800
800
  please check out the following publications (if you find that a paper is missing here, please open [a new issue](https://github.com/flowr-analysis/flowr/issues/new/choose)):
801
801
 
802
+ * [Supporting the Comprehension of Data Analysis Scripts (FSE '25, Tool)](https://doi.org/10.1145/3803437.3806402)
803
+ This refers to an updated tool demonstration of the framework. Preprint available at <a href="https://doi.org/10.48550/arXiv.2604.15963" target="_blank">arXiv:2604.15963</a>.
804
+ <details><summary>BibTeX</summary>
805
+
806
+
807
+ ```bibtex
808
+ @article{10.1145/3803437.3806402,
809
+ author = {Sihler, Florian and Gerstl, Oliver and Pfrenger, Lars and Schubert, Julian and Tichy, Matthias},
810
+ title = {Supporting the Comprehension of Data Analysis Scripts},
811
+ year = {2026},
812
+ doi = {10.1145/3803437.3806402}
813
+ }
814
+ ```
815
+
816
+
817
+ </details>
818
+
802
819
  * [Statically Analyzing the Dataflow of R Programs (OOPSLA '25)](https://doi.org/10.1145/3763087)
803
- Please cite this paper if you are using flowR in your research.
820
+ **Please cite this paper if you are using flowR in your research.**
804
821
  <details><summary>BibTeX</summary>
805
822
 
806
823
 
@@ -829,7 +846,7 @@ please check out the following publications (if you find that a paper is missing
829
846
  </details>
830
847
 
831
848
  * [flowR: A Static Program Slicer for R (ASE '24, Tool)](https://doi.org/10.1145/3691620.3695359)
832
- This refers to the tool-demonstration of the <a href="https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr">VS Code Extension</a>.
849
+ This refers to the tool-demonstration of the <a href="https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr" target="_blank">VS Code Extension</a>.
833
850
  <details><summary>BibTeX</summary>
834
851
 
835
852
 
@@ -1,37 +1,31 @@
1
- import type { ControlFlowInformation } from '../control-flow/control-flow-graph';
2
- import { CfgVertex } from '../control-flow/control-flow-graph';
3
- import type { SemanticCfgGuidedVisitorConfiguration } from '../control-flow/semantic-cfg-guided-visitor';
4
- import { SemanticCfgGuidedVisitor } from '../control-flow/semantic-cfg-guided-visitor';
1
+ import { type CfgExpressionVertex, type CfgStatementVertex, CfgVertex, type ControlFlowInformation } from '../control-flow/control-flow-graph';
2
+ import { SemanticCfgGuidedVisitor, type SemanticCfgGuidedVisitorConfiguration } from '../control-flow/semantic-cfg-guided-visitor';
5
3
  import { BuiltInProcName } from '../dataflow/environments/built-in-proc-name';
6
4
  import type { DataflowGraph } from '../dataflow/graph/graph';
7
5
  import { type DataflowGraphVertexFunctionCall, type DataflowGraphVertexVariableDefinition } from '../dataflow/graph/vertex';
8
- import type { NoInfo, RNode } from '../r-bridge/lang-4.x/ast/model/model';
6
+ import { type NoInfo, RNode } from '../r-bridge/lang-4.x/ast/model/model';
9
7
  import type { NormalizedAst, ParentInformation } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
10
8
  import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
11
9
  import { type AnyAbstractDomain } from './domains/abstract-domain';
12
- import type { StateAbstractDomain } from './domains/state-abstract-domain';
10
+ import type { AnyStateDomain, ValueDomain } from './domains/state-domain-like';
13
11
  export type AbsintVisitorConfiguration = Omit<SemanticCfgGuidedVisitorConfiguration<NoInfo, ControlFlowInformation, NormalizedAst>, 'defaultVisitingOrder' | 'defaultVisitingType'>;
14
12
  /**
15
13
  * A control flow graph visitor to perform abstract interpretation.
16
14
  *
17
15
  * However, the visitor does not yet support inter-procedural abstract interpretation and abstract condition semantics.
18
16
  */
19
- export declare abstract class AbstractInterpretationVisitor<Domain extends AnyAbstractDomain, Config extends AbsintVisitorConfiguration = AbsintVisitorConfiguration> extends SemanticCfgGuidedVisitor<NoInfo, ControlFlowInformation, NormalizedAst, DataflowGraph, Config & {
17
+ export declare abstract class AbstractInterpretationVisitor<StateDomain extends AnyStateDomain<AnyAbstractDomain>, Config extends AbsintVisitorConfiguration = AbsintVisitorConfiguration> extends SemanticCfgGuidedVisitor<NoInfo, ControlFlowInformation, NormalizedAst, DataflowGraph, Config & {
20
18
  defaultVisitingOrder: 'forward';
21
19
  defaultVisitingType: 'exit';
22
20
  }> {
23
21
  /**
24
22
  * The abstract trace of the abstract interpretation visitor mapping node IDs to the abstract state at the respective node.
25
23
  */
26
- private readonly trace;
24
+ protected readonly trace: Map<NodeId, StateDomain>;
27
25
  /**
28
26
  * The current abstract state domain at the currently processed AST node.
29
27
  */
30
- private _currentState;
31
- /**
32
- * Whether the current abstract state has been copied/cloned and is save to modify in place.
33
- */
34
- private stateCopied;
28
+ protected currentState: StateDomain;
35
29
  /**
36
30
  * The current worklist stack of next vertex IDs to visit.
37
31
  */
@@ -40,10 +34,11 @@ export declare abstract class AbstractInterpretationVisitor<Domain extends AnyAb
40
34
  * A set of nodes representing variable definitions that have already been visited but whose assignment has not yet been processed.
41
35
  */
42
36
  private readonly unassigned;
43
- constructor(config: Config, domain: Domain);
44
- get currentState(): StateAbstractDomain<Domain>;
45
- removeState(node: NodeId): void;
46
- updateState(node: NodeId, value: Domain): void;
37
+ /**
38
+ * A map mapping assignments of replacement calls to their replacement calls for replacement calls that have already been visited but whose assignment has not yet been processed.
39
+ */
40
+ private readonly replacements;
41
+ constructor(config: Config, stateDomain: StateDomain);
47
42
  /**
48
43
  * Resolves the inferred abstract value of an AST node.
49
44
  * This requires that the abstract interpretation visitor has been completed, or at least started.
@@ -51,28 +46,29 @@ export declare abstract class AbstractInterpretationVisitor<Domain extends AnyAb
51
46
  * @param state - An optional state abstract domain used to resolve the inferred abstract value (defaults to the state at the requested node)
52
47
  * @returns The inferred abstract value of the node, or `undefined` if no value was inferred for the node
53
48
  */
54
- getAbstractValue(id: RNode<ParentInformation> | NodeId | undefined, state?: StateAbstractDomain<Domain>): Domain | undefined;
49
+ getAbstractValue(id: RNode<ParentInformation> | NodeId | undefined, state?: StateDomain): ValueDomain<StateDomain> | undefined;
55
50
  /**
56
51
  * Gets the inferred abstract state at the location of a specific AST node.
57
52
  * This requires that the abstract interpretation visitor has been completed, or at least started.
58
53
  * @param id - The ID of the node to get the abstract state at
59
54
  * @returns The abstract state at the node, or `undefined` if the node has no abstract state (i.e. the node has not been visited or is unreachable).
60
55
  */
61
- getAbstractState(id: NodeId | undefined): StateAbstractDomain<Domain> | undefined;
56
+ getAbstractState(id: NodeId | undefined): StateDomain | undefined;
62
57
  /**
63
58
  * Gets the inferred abstract state at the end of the program (exit nodes of the control flow graph).
64
59
  * This requires that the abstract interpretation visitor has been completed, or at least started.
65
60
  * @returns The inferred abstract state at the end of the program
66
61
  */
67
- getEndState(): StateAbstractDomain<Domain>;
62
+ getEndState(): StateDomain;
68
63
  /**
69
64
  * Gets the inferred abstract trace mapping AST nodes to the inferred abstract state at the respective node.
70
65
  * @returns The inferred abstract trace of the program
71
66
  */
72
- getAbstractTrace(): ReadonlyMap<NodeId, StateAbstractDomain<Domain>>;
67
+ getAbstractTrace(): ReadonlyMap<NodeId, StateDomain>;
73
68
  start(): void;
74
69
  protected startVisitor(start: readonly NodeId[]): void;
75
70
  protected visitNode(vertexId: NodeId): boolean;
71
+ protected visitUnknown(vertex: CfgStatementVertex | CfgExpressionVertex): void;
76
72
  protected onDispatchFunctionCallOrigin(call: DataflowGraphVertexFunctionCall, origin: BuiltInProcName): void;
77
73
  protected onVariableDefinition({ vertex }: {
78
74
  vertex: DataflowGraphVertexVariableDefinition;
@@ -11,7 +11,6 @@ const r_function_call_1 = require("../r-bridge/lang-4.x/ast/model/nodes/r-functi
11
11
  const type_1 = require("../r-bridge/lang-4.x/ast/model/type");
12
12
  const assert_1 = require("../util/assert");
13
13
  const abstract_domain_1 = require("./domains/abstract-domain");
14
- const state_abstract_domain_1 = require("./domains/state-abstract-domain");
15
14
  const unsupported_functions_1 = require("./unsupported-functions");
16
15
  /**
17
16
  * A control flow graph visitor to perform abstract interpretation.
@@ -26,11 +25,7 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
26
25
  /**
27
26
  * The current abstract state domain at the currently processed AST node.
28
27
  */
29
- _currentState;
30
- /**
31
- * Whether the current abstract state has been copied/cloned and is save to modify in place.
32
- */
33
- stateCopied = false;
28
+ currentState;
34
29
  /**
35
30
  * The current worklist stack of next vertex IDs to visit.
36
31
  */
@@ -39,26 +34,13 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
39
34
  * A set of nodes representing variable definitions that have already been visited but whose assignment has not yet been processed.
40
35
  */
41
36
  unassigned = new Set();
42
- constructor(config, domain) {
37
+ /**
38
+ * A map mapping assignments of replacement calls to their replacement calls for replacement calls that have already been visited but whose assignment has not yet been processed.
39
+ */
40
+ replacements = new Map();
41
+ constructor(config, stateDomain) {
43
42
  super({ ...config, defaultVisitingOrder: 'forward', defaultVisitingType: 'exit' });
44
- this._currentState = state_abstract_domain_1.MutableStateAbstractDomain.top(domain);
45
- }
46
- get currentState() {
47
- return this._currentState;
48
- }
49
- removeState(node) {
50
- if (!this.stateCopied) {
51
- this._currentState = this._currentState.create(this.currentState.value);
52
- this.stateCopied = true;
53
- }
54
- this._currentState.remove(node);
55
- }
56
- updateState(node, value) {
57
- if (!this.stateCopied) {
58
- this._currentState = this._currentState.create(this.currentState.value);
59
- this.stateCopied = true;
60
- }
61
- this._currentState.set(node, value);
43
+ this.currentState = stateDomain.top();
62
44
  }
63
45
  /**
64
46
  * Resolves the inferred abstract value of an AST node.
@@ -70,7 +52,10 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
70
52
  getAbstractValue(id, state) {
71
53
  const node = (id === undefined || typeof id === 'object') ? id : this.getNormalizedAst(id);
72
54
  state ??= node !== undefined ? this.getAbstractState(node.info.id) : undefined;
73
- if (node === undefined) {
55
+ if (state?.isBottom()) {
56
+ return this.currentState.domain.bottom();
57
+ }
58
+ else if (node === undefined) {
74
59
  return;
75
60
  }
76
61
  else if (state?.has(node.info.id)) {
@@ -80,7 +65,8 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
80
65
  const call = (0, vertex_1.isFunctionCallVertex)(vertex) ? vertex : undefined;
81
66
  const origins = Array.isArray(call?.origin) ? call.origin : [];
82
67
  if (node.type === type_1.RType.Symbol) {
83
- const values = this.getVariableOrigins(node.info.id).map(origin => state?.get(origin));
68
+ const values = this.getVariableOrigins(node.info.id)
69
+ .map(origin => (this.getAbstractState(origin)?.isBottom() ? this.currentState.domain.bottom() : state?.get(origin)));
84
70
  if (values.length > 0 && values.every(assert_1.isNotUndefined)) {
85
71
  return abstract_domain_1.AbstractDomain.joinAll(values);
86
72
  }
@@ -130,7 +116,7 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
130
116
  const exitPoints = this.config.controlFlow.exitPoints.map(id => this.getCfgVertex(id)).filter(assert_1.isNotUndefined);
131
117
  const exitNodes = exitPoints.map(control_flow_graph_1.CfgVertex.getRootId).filter(assert_1.isNotUndefined);
132
118
  const states = exitNodes.map(node => this.trace.get(node)).filter(assert_1.isNotUndefined);
133
- return abstract_domain_1.AbstractDomain.joinAll(states, this._currentState.bottom());
119
+ return abstract_domain_1.AbstractDomain.joinAll(states, this.currentState.bottom());
134
120
  }
135
121
  /**
136
122
  * Gets the inferred abstract trace mapping AST nodes to the inferred abstract state at the respective node.
@@ -165,40 +151,30 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
165
151
  if (vertex === undefined || this.shouldSkipVertex(vertex)) {
166
152
  return true;
167
153
  }
154
+ // retrieve new abstract state by joining states of predecessor nodes
168
155
  const predecessors = this.getPredecessorNodes(control_flow_graph_1.CfgVertex.getId(vertex));
169
156
  const predecessorStates = predecessors.map(pred => this.trace.get(pred)).filter(assert_1.isNotUndefined);
170
- // retrieve new abstract state by joining states of predecessor nodes
171
- if (predecessorStates.length <= 1) {
172
- this._currentState = predecessorStates[0] ?? this._currentState.top();
173
- }
174
- else {
175
- this._currentState = abstract_domain_1.AbstractDomain.joinAll(predecessorStates);
176
- this.stateCopied = true;
177
- }
157
+ this.currentState = abstract_domain_1.AbstractDomain.joinAll(predecessorStates, this.currentState.top());
178
158
  const nodeId = control_flow_graph_1.CfgVertex.getRootId(vertex);
179
159
  // differentiate between widening points and other vertices
180
160
  if (this.isWideningPoint(nodeId)) {
181
161
  const oldState = this.trace.get(nodeId);
182
162
  if (oldState !== undefined && this.shouldWiden(vertex)) {
183
- this._currentState = oldState.widen(this._currentState);
184
- this.stateCopied = true;
163
+ this.currentState = oldState.widen(this.currentState);
185
164
  }
186
- this.trace.set(nodeId, this._currentState);
187
- this.stateCopied = false;
165
+ this.trace.set(nodeId, this.currentState);
188
166
  const visitedCount = this.visited.get(nodeId) ?? 0;
189
167
  this.visited.set(nodeId, visitedCount + 1);
190
168
  // continue visiting after widening point if visited for the first time or the state changed
191
- return visitedCount === 0 || !oldState?.equals(this._currentState);
169
+ return visitedCount === 0 || !oldState?.equals(this.currentState);
192
170
  }
193
171
  else {
194
172
  this.onVisitNode(vertexId);
195
173
  // discard the inferred abstract state when encountering unsupported function calls
196
174
  if (this.isUnsupportedFunctionCall(nodeId)) {
197
- this._currentState = this._currentState.top();
198
- this.stateCopied = true;
175
+ this.currentState = this.currentState.top();
199
176
  }
200
- this.trace.set(nodeId, this._currentState);
201
- this.stateCopied = false;
177
+ this.trace.set(nodeId, this.currentState);
202
178
  const predecessorVisits = predecessors.map(pred => this.visited.get(pred) ?? 0);
203
179
  const visitedCount = this.visited.get(nodeId) ?? 0;
204
180
  this.visited.set(nodeId, visitedCount + 1);
@@ -206,7 +182,31 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
206
182
  return predecessors.length <= 1 || this.stack.length === 0 || predecessorVisits.every(visits => visits === predecessorVisits[0]);
207
183
  }
208
184
  }
185
+ visitUnknown(vertex) {
186
+ const nodeId = control_flow_graph_1.CfgVertex.getRootId(vertex);
187
+ const replacements = this.replacements.get(nodeId);
188
+ if (replacements !== undefined) {
189
+ this.replacements.delete(nodeId);
190
+ for (const replacement of replacements) {
191
+ const call = this.getDataflowGraph(replacement);
192
+ if ((0, vertex_1.isFunctionCallVertex)(call)) {
193
+ this.onReplacementCall({ call, ...this.getSourceAndTarget(call) });
194
+ }
195
+ }
196
+ }
197
+ }
209
198
  onDispatchFunctionCallOrigin(call, origin) {
199
+ if (origin === built_in_proc_name_1.BuiltInProcName.Replacement) {
200
+ const node = this.getNormalizedAst(call.id);
201
+ const assignment = model_1.RNode.iterateParents(node, this.config.normalizedAst.idMap)
202
+ .find(parent => this.getDataflowGraph(parent.info.id) === undefined);
203
+ if (node !== undefined && assignment !== undefined) {
204
+ const replacements = this.replacements.get(assignment.info.id) ?? [];
205
+ replacements.push(node.info.id);
206
+ this.replacements.set(assignment.info.id, replacements);
207
+ return;
208
+ }
209
+ }
210
210
  super.onDispatchFunctionCallOrigin(call, origin);
211
211
  switch (origin) {
212
212
  case built_in_proc_name_1.BuiltInProcName.ExpressionList:
@@ -240,9 +240,8 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
240
240
  const value = this.getAbstractValue(source);
241
241
  this.unassigned.delete(target);
242
242
  if (value !== undefined) {
243
- this.updateState(target, value);
244
- this.trace.set(target, this._currentState);
245
- this.stateCopied = false;
243
+ this.currentState.set(target, value);
244
+ this.trace.set(target, this.currentState);
246
245
  }
247
246
  }
248
247
  onReplacementCall({ target }) {
@@ -1,4 +1,3 @@
1
- import type { AbstractDomainValue } from '../domains/abstract-domain';
2
1
  import { PosIntervalDomain } from '../domains/positive-interval-domain';
3
2
  import { ProductDomain } from '../domains/product-domain';
4
3
  import { SetRangeDomain } from '../domains/set-range-domain';
@@ -8,8 +7,6 @@ export type AbstractDataFrameShape = {
8
7
  cols: PosIntervalDomain;
9
8
  rows: PosIntervalDomain;
10
9
  };
11
- /** The type of abstract values of a sub abstract domain (shape property) of the data frame shape product domain */
12
- export type DataFrameShapeProperty<Property extends keyof AbstractDataFrameShape> = AbstractDomainValue<AbstractDataFrameShape[Property]>;
13
10
  /**
14
11
  * The data frame abstract domain as product domain of a column names domain, column count domain, and row count domain.
15
12
  */
@@ -1,6 +1,7 @@
1
1
  import type { DataflowGraphVertexFunctionCall } from '../../dataflow/graph/vertex';
2
2
  import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
3
3
  import { AbstractInterpretationVisitor, type AbsintVisitorConfiguration } from '../absint-visitor';
4
+ import { StateAbstractDomain } from '../domains/state-abstract-domain';
4
5
  import { DataFrameDomain } from './dataframe-domain';
5
6
  import { ConstraintType, type DataFrameOperationArgs, type DataFrameOperationName, type DataFrameOperationOptions } from './semantics';
6
7
  interface Operation<Name extends DataFrameOperationName> {
@@ -35,7 +36,7 @@ interface DataFrameShapeInferenceConfiguration extends AbsintVisitorConfiguratio
35
36
  /**
36
37
  * The control flow graph visitor to infer the shape of data frames using abstract interpretation
37
38
  */
38
- export declare class DataFrameShapeInferenceVisitor extends AbstractInterpretationVisitor<DataFrameDomain, DataFrameShapeInferenceConfiguration> {
39
+ export declare class DataFrameShapeInferenceVisitor extends AbstractInterpretationVisitor<StateAbstractDomain<DataFrameDomain>, DataFrameShapeInferenceConfiguration> {
39
40
  /**
40
41
  * The abstract data frame operations the function call nodes are mapped to.
41
42
  */
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DataFrameShapeInferenceVisitor = void 0;
4
4
  const absint_visitor_1 = require("../absint-visitor");
5
+ const state_abstract_domain_1 = require("../domains/state-abstract-domain");
5
6
  const dataframe_domain_1 = require("./dataframe-domain");
6
7
  const access_mapper_1 = require("./mappers/access-mapper");
7
8
  const function_mapper_1 = require("./mappers/function-mapper");
@@ -16,7 +17,7 @@ class DataFrameShapeInferenceVisitor extends absint_visitor_1.AbstractInterpreta
16
17
  */
17
18
  operations;
18
19
  constructor({ trackOperations = true, ...config }) {
19
- super(config, dataframe_domain_1.DataFrameDomain.top());
20
+ super(config, state_abstract_domain_1.StateAbstractDomain.top(dataframe_domain_1.DataFrameDomain.top()));
20
21
  if (trackOperations) {
21
22
  this.operations = new Map();
22
23
  }
@@ -73,13 +74,13 @@ class DataFrameShapeInferenceVisitor extends absint_visitor_1.AbstractInterpreta
73
74
  value = (0, semantics_1.applyDataFrameSemantics)(operation, operandValue ?? dataframe_domain_1.DataFrameDomain.top(maxColNames), args, options);
74
75
  const constraintType = type ?? (0, semantics_1.getConstraintType)(operation);
75
76
  if (operand !== undefined && constraintType === semantics_1.ConstraintType.OperandModification) {
76
- this.updateState(operand, value);
77
+ this.currentState.set(operand, value);
77
78
  for (const origin of this.getVariableOrigins(operand)) {
78
- this.updateState(origin, value);
79
+ this.currentState.set(origin, value);
79
80
  }
80
81
  }
81
82
  else if (constraintType === semantics_1.ConstraintType.ResultPostcondition) {
82
- this.updateState(node.info.id, value);
83
+ this.currentState.set(node.info.id, value);
83
84
  }
84
85
  }
85
86
  }
@@ -63,36 +63,37 @@ export declare abstract class AbstractDomain<Concrete, Abstract, Top, Bot, Value
63
63
  * The provided array of abstract values must not be empty or a default value must be provided!
64
64
  */
65
65
  static meetAll<Domain extends AnyAbstractDomain>(values: Domain[], defaultValue?: Domain): Domain;
66
+ /**
67
+ * Converts an element of an abstract domain into a string.
68
+ */
69
+ static toString(this: void, value: AnyAbstractDomain | unknown): string;
66
70
  }
67
71
  /**
68
72
  * A type representing any abstract domain without additional information.
69
73
  */
70
74
  export type AnyAbstractDomain = AbstractDomain<unknown, unknown, unknown, unknown>;
71
- /**
72
- * The type of the concrete domain of an abstract domain.
73
- * @template Domain - The abstract domain to get the concrete domain type for
74
- */
75
- export type ConcreteDomain<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<infer Concrete, unknown, unknown, unknown> ? Concrete : never;
76
75
  /**
77
76
  * The type of the abstract values of an abstract domain (including the Top and Bottom element).
78
77
  * @template Domain - The abstract domain to get the abstract value type for
79
78
  */
80
- export type AbstractDomainValue<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<unknown, infer Value, infer Top, infer Bot> ? Value | Top | Bot : never;
79
+ export type AbstractValue<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<unknown, infer Value, infer Top, infer Bot> ? Value | Top | Bot : never;
81
80
  /**
82
- * The type of the Top element (greatest element) of an abstract domain.
83
- * @template Domain - The abstract domain to get the Top element type for
81
+ * The type of the concrete domain of an abstract domain.
82
+ * @template Domain - The abstract domain to get the concrete domain type for
84
83
  */
85
- export type AbstractDomainTop<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<unknown, unknown, infer Top, unknown> ? Top : never;
84
+ export type ConcreteDomain<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<infer Concrete, unknown, unknown, unknown> ? Concrete : never;
86
85
  /**
87
- * The type of the Bottom element (least element) of an abstract domain.
88
- * @template Domain - The abstract domain to get the Bottom element type for
86
+ * The type of an abstract domain holding an abstract value of the domain.
87
+ * @template Domain - The abstract domain abstract domain value type for
89
88
  */
90
- export type AbstractDomainBottom<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<unknown, unknown, unknown, infer Bot> ? Bot : never;
89
+ export type AbstractDomainValue<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<infer Concrete, infer Value, infer Top, infer Bot> ? Domain & AbstractDomain<Concrete, Value, Top, Bot, Value> : never;
91
90
  /**
92
- * Converts an element of an abstract domain into a string.
91
+ * The type an abstract domain holding the Top element (greatest element) of the domain.
92
+ * @template Domain - The abstract domain to get the abstract domain top for
93
93
  */
94
- export declare function domainElementToString(value: AnyAbstractDomain | unknown): string;
94
+ export type AbstractDomainTop<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<infer Concrete, infer Value, infer Top, infer Bot> ? Domain & AbstractDomain<Concrete, Value, Top, Bot, Top> : never;
95
95
  /**
96
- * Checks whether a value is an abstract domain.
96
+ * The type an abstract domain holding the Bottom element (least element) of the domain.
97
+ * @template Domain - The abstract domain to get the abstract domain bottom for
97
98
  */
98
- export declare function isAbstractDomain(value: unknown): value is AnyAbstractDomain;
99
+ export type AbstractDomainBottom<Domain extends AnyAbstractDomain> = Domain extends AbstractDomain<infer Concrete, infer Value, infer Top, infer Bot> ? Domain & AbstractDomain<Concrete, Value, Top, Bot, Bot> : never;