@eagleoutice/flowr 2.2.16 → 2.3.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 +35 -19
- package/abstract-interpretation/data-frame/absint-info.d.ts +109 -0
- package/abstract-interpretation/data-frame/absint-info.js +31 -0
- package/abstract-interpretation/data-frame/absint-visitor.d.ts +59 -0
- package/abstract-interpretation/data-frame/absint-visitor.js +173 -0
- package/abstract-interpretation/data-frame/domain.d.ts +107 -0
- package/abstract-interpretation/data-frame/domain.js +315 -0
- package/abstract-interpretation/data-frame/mappers/access-mapper.d.ts +17 -0
- package/abstract-interpretation/data-frame/mappers/access-mapper.js +166 -0
- package/abstract-interpretation/data-frame/mappers/arguments.d.ts +117 -0
- package/abstract-interpretation/data-frame/mappers/arguments.js +188 -0
- package/abstract-interpretation/data-frame/mappers/assignment-mapper.d.ts +20 -0
- package/abstract-interpretation/data-frame/mappers/assignment-mapper.js +34 -0
- package/abstract-interpretation/data-frame/mappers/function-mapper.d.ts +261 -0
- package/abstract-interpretation/data-frame/mappers/function-mapper.js +1219 -0
- package/abstract-interpretation/data-frame/mappers/replacement-mapper.d.ts +12 -0
- package/abstract-interpretation/data-frame/mappers/replacement-mapper.js +206 -0
- package/abstract-interpretation/data-frame/resolve-args.d.ts +42 -0
- package/abstract-interpretation/data-frame/resolve-args.js +118 -0
- package/abstract-interpretation/data-frame/semantics.d.ts +213 -0
- package/abstract-interpretation/data-frame/semantics.js +366 -0
- package/abstract-interpretation/data-frame/shape-inference.d.ts +38 -0
- package/abstract-interpretation/data-frame/shape-inference.js +117 -0
- package/benchmark/slicer.d.ts +15 -1
- package/benchmark/slicer.js +135 -0
- package/benchmark/stats/print.js +123 -45
- package/benchmark/stats/size-of.d.ts +7 -0
- package/benchmark/stats/size-of.js +1 -0
- package/benchmark/stats/stats.d.ts +30 -1
- package/benchmark/stats/stats.js +4 -2
- package/benchmark/summarizer/data.d.ts +33 -2
- package/benchmark/summarizer/first-phase/input.js +5 -1
- package/benchmark/summarizer/first-phase/process.js +47 -1
- package/benchmark/summarizer/second-phase/process.js +101 -3
- package/cli/benchmark-app.d.ts +1 -0
- package/cli/benchmark-app.js +1 -0
- package/cli/benchmark-helper-app.d.ts +1 -0
- package/cli/benchmark-helper-app.js +8 -2
- package/cli/common/options.js +2 -0
- package/config.d.ts +31 -0
- package/config.js +21 -1
- package/control-flow/control-flow-graph.d.ts +1 -0
- package/control-flow/control-flow-graph.js +4 -0
- package/control-flow/dfg-cfg-guided-visitor.js +1 -1
- package/control-flow/semantic-cfg-guided-visitor.d.ts +1 -1
- package/control-flow/semantic-cfg-guided-visitor.js +1 -1
- package/dataflow/environments/built-in.d.ts +5 -3
- package/dataflow/environments/built-in.js +3 -1
- package/dataflow/eval/resolve/alias-tracking.js +2 -2
- package/dataflow/eval/resolve/resolve.d.ts +53 -9
- package/dataflow/eval/resolve/resolve.js +132 -38
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +4 -0
- package/documentation/doc-util/doc-query.js +10 -0
- package/documentation/print-interface-wiki.js +11 -0
- package/documentation/print-linter-wiki.js +4 -0
- package/documentation/print-query-wiki.js +17 -0
- package/linter/linter-rules.d.ts +25 -2
- package/linter/linter-rules.js +3 -1
- package/linter/rules/absolute-path.d.ts +1 -1
- package/linter/rules/dataframe-access-validation.d.ts +53 -0
- package/linter/rules/dataframe-access-validation.js +116 -0
- package/linter/rules/naming-convention.d.ts +1 -1
- package/linter/rules/naming-convention.js +5 -1
- package/package.json +2 -2
- package/queries/catalog/df-shape-query/df-shape-query-executor.d.ts +3 -0
- package/queries/catalog/df-shape-query/df-shape-query-executor.js +46 -0
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +72 -0
- package/queries/catalog/df-shape-query/df-shape-query-format.js +31 -0
- package/queries/query.d.ts +61 -1
- package/queries/query.js +2 -0
- package/util/files.d.ts +8 -2
- package/util/files.js +22 -4
- package/util/r-value.d.ts +23 -0
- package/util/r-value.js +113 -0
- package/util/version.js +1 -1
- package/util/cfg/cfg.d.ts +0 -0
- package/util/cfg/cfg.js +0 -2
|
@@ -2,17 +2,21 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveNode = resolveNode;
|
|
4
4
|
exports.resolveAsVector = resolveAsVector;
|
|
5
|
+
exports.resolveAsSeq = resolveAsSeq;
|
|
6
|
+
exports.resolveAsPlus = resolveAsPlus;
|
|
7
|
+
exports.resolveAsMinus = resolveAsMinus;
|
|
5
8
|
const r_function_call_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
6
9
|
const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
|
|
7
|
-
const
|
|
10
|
+
const r_value_1 = require("../../../util/r-value");
|
|
8
11
|
const built_in_1 = require("../../environments/built-in");
|
|
9
12
|
const dfg_get_origin_1 = require("../../origin/dfg-get-origin");
|
|
10
13
|
const interval_constants_1 = require("../values/intervals/interval-constants");
|
|
11
14
|
const logical_constants_1 = require("../values/logical/logical-constants");
|
|
12
|
-
const
|
|
15
|
+
const r_value_2 = require("../values/r-value");
|
|
13
16
|
const string_constants_1 = require("../values/string/string-constants");
|
|
14
17
|
const vector_constants_1 = require("../values/vectors/vector-constants");
|
|
15
18
|
const alias_tracking_1 = require("./alias-tracking");
|
|
19
|
+
const scalar_consatnts_1 = require("../values/scalar/scalar-consatnts");
|
|
16
20
|
/**
|
|
17
21
|
* Helper function used by {@link resolveIdToValue}, please use that instead, if
|
|
18
22
|
* you want to resolve the value of an identifier / node
|
|
@@ -37,59 +41,149 @@ function resolveNode(resolve, a, env, graph, map) {
|
|
|
37
41
|
else if (a.type === type_1.RType.Logical) {
|
|
38
42
|
return a.content.valueOf() ? logical_constants_1.ValueLogicalTrue : logical_constants_1.ValueLogicalFalse;
|
|
39
43
|
}
|
|
40
|
-
else if (a.type === type_1.RType.FunctionCall
|
|
44
|
+
else if ((a.type === type_1.RType.FunctionCall || a.type === type_1.RType.BinaryOp || a.type === type_1.RType.UnaryOp) && graph) {
|
|
41
45
|
const origin = (0, dfg_get_origin_1.getOriginInDfg)(graph, a.info.id)?.[0];
|
|
42
46
|
if (origin === undefined || origin.type !== 3 /* OriginType.BuiltInFunctionOrigin */) {
|
|
43
|
-
return
|
|
47
|
+
return r_value_2.Top;
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
let builtInName;
|
|
50
|
+
if ((0, built_in_1.isBuiltIn)(origin.proc)) {
|
|
51
|
+
builtInName = origin.proc;
|
|
52
|
+
}
|
|
53
|
+
else if (a.type === type_1.RType.FunctionCall && a.named) {
|
|
54
|
+
builtInName = (0, built_in_1.builtInId)(a.functionName.content);
|
|
55
|
+
}
|
|
56
|
+
else if (a.type === type_1.RType.BinaryOp || a.type === type_1.RType.UnaryOp) {
|
|
57
|
+
builtInName = (0, built_in_1.builtInId)(a.operator);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
return r_value_2.Top;
|
|
61
|
+
}
|
|
62
|
+
if (Object.prototype.hasOwnProperty.call(built_in_1.BuiltInEvalHandlerMapper, builtInName)) {
|
|
63
|
+
const handler = built_in_1.BuiltInEvalHandlerMapper[builtInName];
|
|
47
64
|
return handler(resolve, a, env, graph, map);
|
|
48
65
|
}
|
|
49
66
|
}
|
|
50
|
-
return
|
|
67
|
+
return r_value_2.Top;
|
|
51
68
|
}
|
|
52
69
|
/**
|
|
53
70
|
* Helper function used by {@link resolveIdToValue}, please use that instead, if
|
|
54
71
|
* you want to resolve the value of an identifier / node
|
|
55
72
|
*
|
|
56
|
-
* This function
|
|
57
|
-
*
|
|
58
|
-
* order to construct the value of the vector to resolve by calling {@link resolveIdToValue}
|
|
59
|
-
* or {@link resolveNode}
|
|
73
|
+
* This function resolves a vector function call `c` to a {@link ValueVector}
|
|
74
|
+
* by recursively resolving the values of the arguments by calling {@link resolveIdToValue}
|
|
60
75
|
*
|
|
61
|
-
* @param a - Node of the vector to resolve
|
|
62
|
-
* @param env - Environment to use
|
|
63
76
|
* @param resolve - Variable resolve mode
|
|
77
|
+
* @param node - Node of the vector function to resolve
|
|
78
|
+
* @param env - Environment to use
|
|
64
79
|
* @param graph - Dataflow graph
|
|
65
|
-
* @param map -
|
|
80
|
+
* @param map - Id map of the dataflow graph
|
|
66
81
|
* @returns ValueVector or Top
|
|
67
82
|
*/
|
|
68
|
-
function resolveAsVector(resolve,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
for (const arg of a.arguments) {
|
|
72
|
-
if (arg === r_function_call_1.EmptyArgument) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (arg.value === undefined) {
|
|
76
|
-
return r_value_1.Top;
|
|
77
|
-
}
|
|
78
|
-
if (arg.value.type === type_1.RType.Symbol) {
|
|
79
|
-
const value = (0, alias_tracking_1.resolveIdToValue)(arg.info.id, { environment: env, idMap: map, graph: graph, full: true, resolve });
|
|
80
|
-
if ((0, r_value_1.isTop)(value)) {
|
|
81
|
-
return r_value_1.Top;
|
|
82
|
-
}
|
|
83
|
-
values.push(value);
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
const val = resolveNode(resolve, arg.value, env, graph, map);
|
|
87
|
-
if ((0, r_value_1.isTop)(val)) {
|
|
88
|
-
return r_value_1.Top;
|
|
89
|
-
}
|
|
90
|
-
values.push(val);
|
|
91
|
-
}
|
|
83
|
+
function resolveAsVector(resolve, node, environment, graph, idMap) {
|
|
84
|
+
if (node.type !== type_1.RType.FunctionCall) {
|
|
85
|
+
return r_value_2.Top;
|
|
92
86
|
}
|
|
87
|
+
const resolveInfo = { environment, graph, idMap, full: true, resolve };
|
|
88
|
+
const values = node.arguments.map(arg => arg !== r_function_call_1.EmptyArgument ? (0, alias_tracking_1.resolveIdToValue)(arg.value, resolveInfo) : r_value_2.Top);
|
|
93
89
|
return (0, vector_constants_1.vectorFrom)((0, vector_constants_1.flattenVectorElements)(values));
|
|
94
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Helper function used by {@link resolveIdToValue}, please use that instead, if
|
|
93
|
+
* you want to resolve the value of an identifier / node
|
|
94
|
+
*
|
|
95
|
+
* This function resolves a binary sequence operator `:` to a {@link ValueVector} of {@link ValueNumber}s
|
|
96
|
+
* by recursively resolving the values of the arguments by calling {@link resolveIdToValue}
|
|
97
|
+
*
|
|
98
|
+
* @param resolve - Variable resolve mode
|
|
99
|
+
* @param operator - Node of the sequence operator to resolve
|
|
100
|
+
* @param env - Environment to use
|
|
101
|
+
* @param graph - Dataflow graph
|
|
102
|
+
* @param map - Id map of the dataflow graph
|
|
103
|
+
* @returns ValueVector of ValueNumbers or Top
|
|
104
|
+
*/
|
|
105
|
+
function resolveAsSeq(resolve, operator, environment, graph, idMap) {
|
|
106
|
+
if (operator.type !== type_1.RType.BinaryOp) {
|
|
107
|
+
return r_value_2.Top;
|
|
108
|
+
}
|
|
109
|
+
const resolveInfo = { environment, graph, idMap, full: true, resolve };
|
|
110
|
+
const leftArg = (0, alias_tracking_1.resolveIdToValue)(operator.lhs, resolveInfo);
|
|
111
|
+
const rightArg = (0, alias_tracking_1.resolveIdToValue)(operator.rhs, resolveInfo);
|
|
112
|
+
const leftValue = (0, r_value_1.unliftRValue)(leftArg);
|
|
113
|
+
const rightValue = (0, r_value_1.unliftRValue)(rightArg);
|
|
114
|
+
if ((0, r_value_1.isRNumberValue)(leftValue) && (0, r_value_1.isRNumberValue)(rightValue)) {
|
|
115
|
+
return (0, vector_constants_1.vectorFrom)(createNumberSequence(leftValue, rightValue).map(scalar_consatnts_1.liftScalar));
|
|
116
|
+
}
|
|
117
|
+
return r_value_2.Top;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Helper function used by {@link resolveIdToValue}, please use that instead, if
|
|
121
|
+
* you want to resolve the value of an identifier / node
|
|
122
|
+
*
|
|
123
|
+
* This function resolves a unary plus operator `+` to a {@link ValueNumber} or {@link ValueVector} of ValueNumbers
|
|
124
|
+
* by recursively resolving the values of the arguments by calling {@link resolveIdToValue}
|
|
125
|
+
*
|
|
126
|
+
* @param resolve - Variable resolve mode
|
|
127
|
+
* @param operator - Node of the plus operator to resolve
|
|
128
|
+
* @param env - Environment to use
|
|
129
|
+
* @param graph - Dataflow graph
|
|
130
|
+
* @param map - Id map of the dataflow graph
|
|
131
|
+
* @returns ValueNumber, ValueVector of ValueNumbers, or Top
|
|
132
|
+
*/
|
|
133
|
+
function resolveAsPlus(resolve, operator, environment, graph, idMap) {
|
|
134
|
+
if (operator.type !== type_1.RType.UnaryOp) {
|
|
135
|
+
return r_value_2.Top;
|
|
136
|
+
}
|
|
137
|
+
const resolveInfo = { environment, graph, idMap, full: true, resolve };
|
|
138
|
+
const arg = (0, alias_tracking_1.resolveIdToValue)(operator.operand, resolveInfo);
|
|
139
|
+
const argValue = (0, r_value_1.unliftRValue)(arg);
|
|
140
|
+
if ((0, r_value_1.isRNumberValue)(argValue)) {
|
|
141
|
+
return (0, scalar_consatnts_1.liftScalar)(argValue);
|
|
142
|
+
}
|
|
143
|
+
else if (Array.isArray(argValue) && argValue.every(r_value_1.isRNumberValue)) {
|
|
144
|
+
return (0, vector_constants_1.vectorFrom)(argValue.map(scalar_consatnts_1.liftScalar));
|
|
145
|
+
}
|
|
146
|
+
return r_value_2.Top;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Helper function used by {@link resolveIdToValue}, please use that instead, if
|
|
150
|
+
* you want to resolve the value of an identifier / node
|
|
151
|
+
*
|
|
152
|
+
* This function resolves a unary minus operator `-` to a {@link ValueNumber} or {@link ValueVector} of ValueNumbers
|
|
153
|
+
* by recursively resolving the values of the arguments by calling {@link resolveIdToValue}
|
|
154
|
+
*
|
|
155
|
+
* @param resolve - Variable resolve mode
|
|
156
|
+
* @param operator - Node of the minus operator to resolve
|
|
157
|
+
* @param env - Environment to use
|
|
158
|
+
* @param graph - Dataflow graph
|
|
159
|
+
* @param map - Id map of the dataflow graph
|
|
160
|
+
* @returns ValueNumber, ValueVector of ValueNumbers, or Top
|
|
161
|
+
*/
|
|
162
|
+
function resolveAsMinus(resolve, operator, environment, graph, idMap) {
|
|
163
|
+
if (operator.type !== type_1.RType.UnaryOp) {
|
|
164
|
+
return r_value_2.Top;
|
|
165
|
+
}
|
|
166
|
+
const resolveInfo = { environment, graph, idMap, full: true, resolve };
|
|
167
|
+
const arg = (0, alias_tracking_1.resolveIdToValue)(operator.operand, resolveInfo);
|
|
168
|
+
const argValue = (0, r_value_1.unliftRValue)(arg);
|
|
169
|
+
if ((0, r_value_1.isRNumberValue)(argValue)) {
|
|
170
|
+
return (0, scalar_consatnts_1.liftScalar)({ ...argValue, num: -argValue.num });
|
|
171
|
+
}
|
|
172
|
+
else if (Array.isArray(argValue) && argValue.every(r_value_1.isRNumberValue)) {
|
|
173
|
+
return (0, vector_constants_1.vectorFrom)(argValue.map(element => (0, scalar_consatnts_1.liftScalar)({ ...element, num: -element.num })));
|
|
174
|
+
}
|
|
175
|
+
return r_value_2.Top;
|
|
176
|
+
}
|
|
177
|
+
function createNumberSequence(start, end) {
|
|
178
|
+
const sequence = [];
|
|
179
|
+
const min = Math.min(start.num, end.num);
|
|
180
|
+
const max = Math.max(start.num, end.num);
|
|
181
|
+
for (let i = min; i <= max; i++) {
|
|
182
|
+
sequence.push({ ...start, num: i });
|
|
183
|
+
}
|
|
184
|
+
if (start > end) {
|
|
185
|
+
sequence.reverse();
|
|
186
|
+
}
|
|
187
|
+
return sequence;
|
|
188
|
+
}
|
|
95
189
|
//# sourceMappingURL=resolve.js.map
|
|
@@ -8,6 +8,7 @@ import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/
|
|
|
8
8
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
9
9
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
10
10
|
import type { NoInfo } from '../../../../../../r-bridge/lang-4.x/ast/model/model';
|
|
11
|
+
export declare function getSourceProvider(): RParseRequestProvider;
|
|
11
12
|
export declare function setSourceProvider(provider: RParseRequestProvider): void;
|
|
12
13
|
export declare function inferWdFromScript(option: InferWorkingDirectory, referenceChain: readonly RParseRequest[]): string[];
|
|
13
14
|
/**
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getSourceProvider = getSourceProvider;
|
|
6
7
|
exports.setSourceProvider = setSourceProvider;
|
|
7
8
|
exports.inferWdFromScript = inferWdFromScript;
|
|
8
9
|
exports.findSource = findSource;
|
|
@@ -30,6 +31,9 @@ const r_value_1 = require("../../../../../eval/values/r-value");
|
|
|
30
31
|
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
|
|
31
32
|
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
32
33
|
let sourceProvider = (0, retriever_1.requestProviderFromFile)();
|
|
34
|
+
function getSourceProvider() {
|
|
35
|
+
return sourceProvider;
|
|
36
|
+
}
|
|
33
37
|
function setSourceProvider(provider) {
|
|
34
38
|
sourceProvider = provider;
|
|
35
39
|
}
|
|
@@ -17,6 +17,7 @@ const doc_dfg_1 = require("./doc-dfg");
|
|
|
17
17
|
const doc_code_1 = require("./doc-code");
|
|
18
18
|
const time_1 = require("../../util/text/time");
|
|
19
19
|
const query_print_1 = require("../../queries/query-print");
|
|
20
|
+
const doc_cli_option_1 = require("./doc-cli-option");
|
|
20
21
|
const config_1 = require("../../config");
|
|
21
22
|
async function showQuery(shell, code, queries, { showCode, collapseResult, collapseQuery, addOutput = () => '' } = {}) {
|
|
22
23
|
const now = performance.now();
|
|
@@ -34,6 +35,15 @@ The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parsing an
|
|
|
34
35
|
|
|
35
36
|
${(0, doc_code_1.codeBlock)('json', collapseQuery ? str.split('\n').join(' ').replace(/([{[])\s{2,}/g, '$1 ').replace(/\s{2,}([\]}])/g, ' $1') : str)}
|
|
36
37
|
|
|
38
|
+
${(function () {
|
|
39
|
+
if (queries.length === 1 && Object.keys(queries[0]).length === 1) {
|
|
40
|
+
return `(This query can be shortened to \`@${queries[0].type}\` when used within the REPL command ${(0, doc_cli_option_1.getReplCommand)('query')}).`;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
45
|
+
})()}
|
|
46
|
+
|
|
37
47
|
${collapseResult ? ' <details> <summary style="color:gray">Show Results</summary>' : ''}
|
|
38
48
|
|
|
39
49
|
_Results (prettified and summarized):_
|
|
@@ -182,6 +182,7 @@ The following summarizes the configuration options:
|
|
|
182
182
|
- \`solver\`: allows to configure how _flowR_ resolves variables and their values (currently we support: ${Object.values(config_1.VariableResolve).map(v => `\`${v}\``).join(', ')}), as well as if pointer analysis should be active.
|
|
183
183
|
- \`engines\`: allows to configure the engines used by _flowR_ to interact with R code. See the [Engines wiki page](${doc_files_1.FlowrWikiBaseRef}/Engines) for more information.
|
|
184
184
|
- \`defaultEngine\`: allows to specify the default engine to use for interacting with R code. If not set, an arbitrary engine from the specified list will be used.
|
|
185
|
+
- \`abstractInterpretation\`: allows to configure how _flowR_ performs abstract interpretation, although we currently only support data frame shape inference through abstract interpretation.
|
|
185
186
|
|
|
186
187
|
So you can configure _flowR_ by adding a file like the following:
|
|
187
188
|
|
|
@@ -214,6 +215,16 @@ ${(0, doc_code_1.codeBlock)('json', JSON.stringify({
|
|
|
214
215
|
slicer: {
|
|
215
216
|
threshold: 50
|
|
216
217
|
}
|
|
218
|
+
},
|
|
219
|
+
abstractInterpretation: {
|
|
220
|
+
dataFrame: {
|
|
221
|
+
maxColNames: 20,
|
|
222
|
+
wideningThreshold: 4,
|
|
223
|
+
readLoadedData: {
|
|
224
|
+
readExternalFiles: true,
|
|
225
|
+
maxReadLines: 1_000_000
|
|
226
|
+
}
|
|
227
|
+
}
|
|
217
228
|
}
|
|
218
229
|
}, null, 2))}
|
|
219
230
|
|
|
@@ -107,6 +107,10 @@ print(x)
|
|
|
107
107
|
rule(shell, 'naming-convention', 'NamingConventionConfig', 'NAMING_CONVENTION', 'lint-naming-convention', `
|
|
108
108
|
myVar <- 42
|
|
109
109
|
print(myVar)
|
|
110
|
+
`, tagTypes);
|
|
111
|
+
rule(shell, 'dataframe-access-validation', 'DataFrameAccessValidationConfig', 'DATA_FRAME_ACCESS_VALIDATION', 'lint-dataframe-access-validation', `
|
|
112
|
+
df <- data.frame(id = 1:5, name = 6:10)
|
|
113
|
+
df[6, "value"]
|
|
110
114
|
`, tagTypes);
|
|
111
115
|
function rule(shell, name, configType, ruleType, testfile, example, types) {
|
|
112
116
|
const rule = linter_rules_1.LintingRules[name];
|
|
@@ -36,6 +36,7 @@ const doc_types_1 = require("./doc-util/doc-types");
|
|
|
36
36
|
const path_1 = __importDefault(require("path"));
|
|
37
37
|
const control_flow_query_executor_1 = require("../queries/catalog/control-flow-query/control-flow-query-executor");
|
|
38
38
|
const doc_cfg_1 = require("./doc-util/doc-cfg");
|
|
39
|
+
const df_shape_query_executor_1 = require("../queries/catalog/df-shape-query/df-shape-query-executor");
|
|
39
40
|
(0, doc_query_1.registerQueryDocumentation)('call-context', {
|
|
40
41
|
name: 'Call-Context Query',
|
|
41
42
|
type: 'active',
|
|
@@ -333,6 +334,22 @@ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
|
333
334
|
This query provides access to the current configuration of the flowR instance. See the [Interface](${doc_files_1.FlowrWikiBaseRef}/Interface) wiki page for more information on what the configuration represents.`;
|
|
334
335
|
}
|
|
335
336
|
});
|
|
337
|
+
(0, doc_query_1.registerQueryDocumentation)('df-shape', {
|
|
338
|
+
name: 'Dataframe Shape Inference Query',
|
|
339
|
+
type: 'active',
|
|
340
|
+
shortDescription: 'Returns the shapes inferred for all dataframes in the code.',
|
|
341
|
+
functionName: df_shape_query_executor_1.executeDfShapeQuery.name,
|
|
342
|
+
functionFile: '../queries/catalog/df-shape-query/df-shape-query-format.ts',
|
|
343
|
+
buildExplanation: async (shell) => {
|
|
344
|
+
const exampleCode = 'x <- data.frame(a=1:3)\nfilter(x, FALSE)';
|
|
345
|
+
return `
|
|
346
|
+
This query infers all shapes of dataframes within the code. For example, you can use:
|
|
347
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
348
|
+
type: 'df-shape'
|
|
349
|
+
}], { showCode: true, collapseQuery: true })}
|
|
350
|
+
`;
|
|
351
|
+
}
|
|
352
|
+
});
|
|
336
353
|
(0, doc_query_1.registerQueryDocumentation)('compound', {
|
|
337
354
|
name: 'Compound Query',
|
|
338
355
|
type: 'virtual',
|
package/linter/linter-rules.d.ts
CHANGED
|
@@ -89,7 +89,7 @@ export declare const LintingRules: {
|
|
|
89
89
|
readonly 'absolute-file-paths': {
|
|
90
90
|
readonly createSearch: (config: import("./rules/absolute-path").AbsoluteFilePathConfig) => import("../search/flowr-search-builder").FlowrSearchBuilder<"from-query", ["unique"], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>;
|
|
91
91
|
readonly processSearchResult: (elements: import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, {
|
|
92
|
-
readonly query?: "config" | "origin" | "dataflow" | "search" | "call-context" | "control-flow" | "dataflow-lens" | "normalized-ast" | "id-map" | "dataflow-cluster" | "static-slice" | "lineage" | "dependencies" | "location-map" | "happens-before" | "resolve-value" | "project" | "linter" | undefined;
|
|
92
|
+
readonly query?: "config" | "origin" | "dataflow" | "search" | "call-context" | "control-flow" | "dataflow-lens" | "df-shape" | "normalized-ast" | "id-map" | "dataflow-cluster" | "static-slice" | "lineage" | "dependencies" | "location-map" | "happens-before" | "resolve-value" | "project" | "linter" | undefined;
|
|
93
93
|
readonly queryResult?: import("../queries/base-query-format").BaseQueryResult | undefined;
|
|
94
94
|
readonly node: import("../r-bridge/lang-4.x/ast/model/nodes/r-expression-list").RExpressionList<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-function-definition").RFunctionDefinition<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-function-call").RNamedFunctionCall<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-function-call").RUnnamedFunctionCall<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-parameter").RParameter<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-argument").RArgument<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-comment").RComment<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-line-directive").RLineDirective<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-for-loop").RForLoop<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop").RRepeatLoop<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-while-loop").RWhileLoop<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-if-then-else").RIfThenElse<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-access").RNamedAccess<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-access").RIndexAccess<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-unary-op").RUnaryOp<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-binary-op").RBinaryOp<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-symbol").RSymbol<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, string> | import("../r-bridge/lang-4.x/ast/model/nodes/r-number").RNumber<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-string").RString<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-logical").RLogical<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-break").RBreak<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-next").RNext<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation> | import("../r-bridge/lang-4.x/ast/model/nodes/r-pipe").RPipe<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>;
|
|
95
95
|
}[]>, config: import("./rules/absolute-path").AbsoluteFilePathConfig, data: {
|
|
@@ -170,7 +170,30 @@ export declare const LintingRules: {
|
|
|
170
170
|
readonly description: "Checks wether the symbols conform to a certain naming convention";
|
|
171
171
|
readonly tags: readonly [import("./linter-tags").LintingRuleTag.Style, import("./linter-tags").LintingRuleTag.QuickFix];
|
|
172
172
|
readonly defaultConfig: {
|
|
173
|
-
readonly caseing:
|
|
173
|
+
readonly caseing: "auto";
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
readonly 'dataframe-access-validation': {
|
|
178
|
+
readonly createSearch: () => import("../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with"], import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/search-executor/search-enrichers").EnrichedFlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>;
|
|
179
|
+
readonly processSearchResult: (elements: import("../search/flowr-search").FlowrSearchElements<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../search/flowr-search").FlowrSearchElement<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>, config: import("./rules/dataframe-access-validation").DataFrameAccessValidationConfig, data: {
|
|
180
|
+
normalize: import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
181
|
+
dataflow: import("../dataflow/info").DataflowInformation;
|
|
182
|
+
config: import("../config").FlowrConfigOptions;
|
|
183
|
+
}) => {
|
|
184
|
+
results: import("./rules/dataframe-access-validation").DataFrameAccessValidationResult[];
|
|
185
|
+
'.meta': import("./rules/dataframe-access-validation").DataFrameAccessValidationMetadata;
|
|
186
|
+
};
|
|
187
|
+
readonly prettyPrint: {
|
|
188
|
+
readonly query: (result: import("./rules/dataframe-access-validation").DataFrameAccessValidationResult) => string;
|
|
189
|
+
readonly full: (result: import("./rules/dataframe-access-validation").DataFrameAccessValidationResult) => string;
|
|
190
|
+
};
|
|
191
|
+
readonly info: {
|
|
192
|
+
readonly name: "Dataframe Access Validation";
|
|
193
|
+
readonly tags: readonly [import("./linter-tags").LintingRuleTag.Bug, import("./linter-tags").LintingRuleTag.Usability, import("./linter-tags").LintingRuleTag.Reproducibility];
|
|
194
|
+
readonly description: "Validates the existance of accessed columns and rows of dataframes.";
|
|
195
|
+
readonly defaultConfig: {
|
|
196
|
+
readonly readLoadedData: false;
|
|
174
197
|
};
|
|
175
198
|
};
|
|
176
199
|
};
|
package/linter/linter-rules.js
CHANGED
|
@@ -7,6 +7,7 @@ const absolute_path_1 = require("./rules/absolute-path");
|
|
|
7
7
|
const unused_definition_1 = require("./rules/unused-definition");
|
|
8
8
|
const seeded_randomness_1 = require("./rules/seeded-randomness");
|
|
9
9
|
const naming_convention_1 = require("./rules/naming-convention");
|
|
10
|
+
const dataframe_access_validation_1 = require("./rules/dataframe-access-validation");
|
|
10
11
|
/**
|
|
11
12
|
* The registry of currently supported linting rules.
|
|
12
13
|
* A linting rule can be executed on a dataflow pipeline result using {@link executeLintingRule}.
|
|
@@ -17,6 +18,7 @@ exports.LintingRules = {
|
|
|
17
18
|
'seeded-randomness': seeded_randomness_1.SEEDED_RANDOMNESS,
|
|
18
19
|
'absolute-file-paths': absolute_path_1.ABSOLUTE_PATH,
|
|
19
20
|
'unused-definitions': unused_definition_1.UNUSED_DEFINITION,
|
|
20
|
-
'naming-convention': naming_convention_1.NAMING_CONVENTION
|
|
21
|
+
'naming-convention': naming_convention_1.NAMING_CONVENTION,
|
|
22
|
+
'dataframe-access-validation': dataframe_access_validation_1.DATA_FRAME_ACCESS_VALIDATION
|
|
21
23
|
};
|
|
22
24
|
//# sourceMappingURL=linter-rules.js.map
|
|
@@ -38,7 +38,7 @@ export interface AbsoluteFilePathMetadata extends MergeableRecord {
|
|
|
38
38
|
export declare const ABSOLUTE_PATH: {
|
|
39
39
|
readonly createSearch: (config: AbsoluteFilePathConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"from-query", ["unique"], ParentInformation, import("../../search/flowr-search").FlowrSearchElements<ParentInformation, import("../../search/flowr-search").FlowrSearchElement<ParentInformation>[]>>;
|
|
40
40
|
readonly processSearchResult: (elements: import("../../search/flowr-search").FlowrSearchElements<ParentInformation, {
|
|
41
|
-
readonly query?: "config" | "origin" | "dataflow" | "search" | "call-context" | "control-flow" | "dataflow-lens" | "normalized-ast" | "id-map" | "dataflow-cluster" | "static-slice" | "lineage" | "dependencies" | "location-map" | "happens-before" | "resolve-value" | "project" | "linter" | undefined;
|
|
41
|
+
readonly query?: "config" | "origin" | "dataflow" | "search" | "call-context" | "control-flow" | "dataflow-lens" | "df-shape" | "normalized-ast" | "id-map" | "dataflow-cluster" | "static-slice" | "lineage" | "dependencies" | "location-map" | "happens-before" | "resolve-value" | "project" | "linter" | undefined;
|
|
42
42
|
readonly queryResult?: import("../../queries/base-query-format").BaseQueryResult | undefined;
|
|
43
43
|
readonly node: import("../../r-bridge/lang-4.x/ast/model/nodes/r-expression-list").RExpressionList<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-function-definition").RFunctionDefinition<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call").RNamedFunctionCall<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call").RUnnamedFunctionCall<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-parameter").RParameter<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-argument").RArgument<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-comment").RComment<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-line-directive").RLineDirective<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-for-loop").RForLoop<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop").RRepeatLoop<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-while-loop").RWhileLoop<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-if-then-else").RIfThenElse<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-access").RNamedAccess<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-access").RIndexAccess<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-unary-op").RUnaryOp<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-binary-op").RBinaryOp<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-symbol").RSymbol<ParentInformation, string> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-number").RNumber<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-string").RString<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-logical").RLogical<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-break").RBreak<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-next").RNext<ParentInformation> | import("../../r-bridge/lang-4.x/ast/model/nodes/r-pipe").RPipe<ParentInformation>;
|
|
44
44
|
}[]>, config: AbsoluteFilePathConfig, data: {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
2
|
+
import type { FlowrSearchElements } from '../../search/flowr-search';
|
|
3
|
+
import { type MergeableRecord } from '../../util/objects';
|
|
4
|
+
import { type SourceRange } from '../../util/range';
|
|
5
|
+
import type { LintingResult } from '../linter-format';
|
|
6
|
+
import { LintingRuleTag } from '../linter-tags';
|
|
7
|
+
export interface DataFrameAccessValidationResult extends LintingResult {
|
|
8
|
+
/** The type of the data frame access ("column" or "row") */
|
|
9
|
+
type: 'column' | 'row';
|
|
10
|
+
/** The name or index of the column or row being accessed in the data frame */
|
|
11
|
+
accessed: string | number;
|
|
12
|
+
/** The name of the function/operation used for the access (e.g. `$`, `[`, `[[`, but also `filter`, `select`, ...) */
|
|
13
|
+
access: string;
|
|
14
|
+
/** The variable/symbol name of the accessed data frame operand (`undefined` if operand is no symbol) */
|
|
15
|
+
operand?: string;
|
|
16
|
+
/** The source range in the code where the access occurs */
|
|
17
|
+
range: SourceRange;
|
|
18
|
+
}
|
|
19
|
+
export interface DataFrameAccessValidationConfig extends MergeableRecord {
|
|
20
|
+
/** Whether data frame shapes should be extracted from loaded external data files, such as CSV files (defaults to the option in the flowR config if `undefined`) */
|
|
21
|
+
readLoadedData?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface DataFrameAccessValidationMetadata extends MergeableRecord {
|
|
24
|
+
/** The number of data frame functions and operations containing inferred column or row accesses */
|
|
25
|
+
numOperations: number;
|
|
26
|
+
/** The number of inferred abstract column or row access operations */
|
|
27
|
+
numAccesses: number;
|
|
28
|
+
/** The total number of inferred accessed columns and rows */
|
|
29
|
+
totalAccessed: number;
|
|
30
|
+
}
|
|
31
|
+
export declare const DATA_FRAME_ACCESS_VALIDATION: {
|
|
32
|
+
readonly createSearch: () => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with"], ParentInformation, FlowrSearchElements<ParentInformation, import("../../search/search-executor/search-enrichers").EnrichedFlowrSearchElement<ParentInformation>[]>>;
|
|
33
|
+
readonly processSearchResult: (elements: FlowrSearchElements<ParentInformation, import("../../search/flowr-search").FlowrSearchElement<ParentInformation>[]>, config: DataFrameAccessValidationConfig, data: {
|
|
34
|
+
normalize: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
35
|
+
dataflow: import("../../dataflow/info").DataflowInformation;
|
|
36
|
+
config: import("../../config").FlowrConfigOptions;
|
|
37
|
+
}) => {
|
|
38
|
+
results: DataFrameAccessValidationResult[];
|
|
39
|
+
'.meta': DataFrameAccessValidationMetadata;
|
|
40
|
+
};
|
|
41
|
+
readonly prettyPrint: {
|
|
42
|
+
readonly query: (result: DataFrameAccessValidationResult) => string;
|
|
43
|
+
readonly full: (result: DataFrameAccessValidationResult) => string;
|
|
44
|
+
};
|
|
45
|
+
readonly info: {
|
|
46
|
+
readonly name: "Dataframe Access Validation";
|
|
47
|
+
readonly tags: readonly [LintingRuleTag.Bug, LintingRuleTag.Usability, LintingRuleTag.Reproducibility];
|
|
48
|
+
readonly description: "Validates the existance of accessed columns and rows of dataframes.";
|
|
49
|
+
readonly defaultConfig: {
|
|
50
|
+
readonly readLoadedData: false;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DATA_FRAME_ACCESS_VALIDATION = void 0;
|
|
4
|
+
const absint_info_1 = require("../../abstract-interpretation/data-frame/absint-info");
|
|
5
|
+
const domain_1 = require("../../abstract-interpretation/data-frame/domain");
|
|
6
|
+
const shape_inference_1 = require("../../abstract-interpretation/data-frame/shape-inference");
|
|
7
|
+
const config_1 = require("../../config");
|
|
8
|
+
const extract_cfg_1 = require("../../control-flow/extract-cfg");
|
|
9
|
+
const type_1 = require("../../r-bridge/lang-4.x/ast/model/type");
|
|
10
|
+
const flowr_search_builder_1 = require("../../search/flowr-search-builder");
|
|
11
|
+
const search_enrichers_1 = require("../../search/search-executor/search-enrichers");
|
|
12
|
+
const dfg_1 = require("../../util/mermaid/dfg");
|
|
13
|
+
const range_1 = require("../../util/range");
|
|
14
|
+
const linter_format_1 = require("../linter-format");
|
|
15
|
+
const linter_tags_1 = require("../linter-tags");
|
|
16
|
+
;
|
|
17
|
+
;
|
|
18
|
+
exports.DATA_FRAME_ACCESS_VALIDATION = {
|
|
19
|
+
createSearch: () => flowr_search_builder_1.Q.all().with(search_enrichers_1.Enrichment.CallTargets, { onlyBuiltin: true }),
|
|
20
|
+
processSearchResult: (elements, config, data) => {
|
|
21
|
+
const flowrConfig = (0, config_1.amendConfig)(data.config, flowrConfig => {
|
|
22
|
+
if (config.readLoadedData !== undefined) {
|
|
23
|
+
flowrConfig.abstractInterpretation.dataFrame.readLoadedData.readExternalFiles = config.readLoadedData;
|
|
24
|
+
}
|
|
25
|
+
return flowrConfig;
|
|
26
|
+
});
|
|
27
|
+
const cfg = (0, extract_cfg_1.extractCfg)(data.normalize, flowrConfig, data.dataflow.graph);
|
|
28
|
+
(0, shape_inference_1.inferDataFrameShapes)(cfg, data.dataflow.graph, data.normalize, flowrConfig);
|
|
29
|
+
const accessOperations = getAccessOperations(elements);
|
|
30
|
+
const accesses = [];
|
|
31
|
+
for (const [nodeId, operations] of accessOperations) {
|
|
32
|
+
const access = { nodeId };
|
|
33
|
+
for (const operation of operations) {
|
|
34
|
+
access.operand ??= operation.operand;
|
|
35
|
+
access.operandShape ??= (0, shape_inference_1.resolveIdToDataFrameShape)(operation.operand, data.dataflow.graph);
|
|
36
|
+
if (operation.operation === 'accessCols' && operation.columns !== undefined) {
|
|
37
|
+
access.accessedCols ??= [];
|
|
38
|
+
access.accessedCols.push(...operation.columns);
|
|
39
|
+
}
|
|
40
|
+
else if (operation.operation === 'accessRows' && operation.rows !== undefined) {
|
|
41
|
+
access.accessedRows ??= [];
|
|
42
|
+
access.accessedRows.push(...operation.rows);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
accesses.push(access);
|
|
46
|
+
}
|
|
47
|
+
const operations = accessOperations.entries().flatMap(([, operations]) => operations).toArray();
|
|
48
|
+
const metadata = {
|
|
49
|
+
numOperations: accessOperations.size,
|
|
50
|
+
numAccesses: operations.length,
|
|
51
|
+
totalAccessed: operations
|
|
52
|
+
.map(operation => operation.operation === 'accessCols' ? operation.columns?.length ?? 0 : operation.rows?.length ?? 0)
|
|
53
|
+
.reduce((a, b) => a + b, 0)
|
|
54
|
+
};
|
|
55
|
+
const results = accesses
|
|
56
|
+
.flatMap(access => findInvalidDataFrameAccesses(access)
|
|
57
|
+
.map(accessed => ({ nodeId: access.nodeId, operand: access.operand, ...accessed })))
|
|
58
|
+
.map(({ nodeId, operand, ...accessed }) => ({
|
|
59
|
+
...accessed,
|
|
60
|
+
node: data.normalize.idMap.get(nodeId),
|
|
61
|
+
operand: operand !== undefined ? data.normalize.idMap.get(operand) : undefined,
|
|
62
|
+
}))
|
|
63
|
+
.map(({ node, operand, ...accessed }) => ({
|
|
64
|
+
...accessed,
|
|
65
|
+
access: node?.lexeme ?? '???',
|
|
66
|
+
...(operand?.type === type_1.RType.Symbol ? { operand: operand.content } : {}),
|
|
67
|
+
range: node?.info.fullRange ?? node?.location ?? (0, range_1.rangeFrom)(-1, -1, -1, -1),
|
|
68
|
+
certainty: linter_format_1.LintingCertainty.Definitely
|
|
69
|
+
}));
|
|
70
|
+
return { results, '.meta': metadata };
|
|
71
|
+
},
|
|
72
|
+
prettyPrint: {
|
|
73
|
+
[linter_format_1.LintingPrettyPrintContext.Query]: result => `Access of ${result.type} ` +
|
|
74
|
+
(typeof result.accessed === 'string' ? `"${result.accessed}"` : result.accessed) + ' ' +
|
|
75
|
+
(result.operand !== undefined ? `of \`${result.operand}\`` : `at \`${result.access}\``) + ` at ${(0, dfg_1.formatRange)(result.range)}`,
|
|
76
|
+
[linter_format_1.LintingPrettyPrintContext.Full]: result => `Accessed ${result.type} ` +
|
|
77
|
+
(typeof result.accessed === 'string' ? `"${result.accessed}"` : result.accessed) + ' does not exist ' +
|
|
78
|
+
(result.operand !== undefined ? `in \`${result.operand}\`` : `at \`${result.access}\``) + ` at ${(0, dfg_1.formatRange)(result.range)}`
|
|
79
|
+
},
|
|
80
|
+
info: {
|
|
81
|
+
name: 'Dataframe Access Validation',
|
|
82
|
+
tags: [linter_tags_1.LintingRuleTag.Bug, linter_tags_1.LintingRuleTag.Usability, linter_tags_1.LintingRuleTag.Reproducibility],
|
|
83
|
+
description: 'Validates the existance of accessed columns and rows of dataframes.',
|
|
84
|
+
defaultConfig: { readLoadedData: false }
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
function getAccessOperations(elements) {
|
|
88
|
+
return new Map(elements.getElements()
|
|
89
|
+
.map(element => element.node)
|
|
90
|
+
.filter(absint_info_1.hasDataFrameExpressionInfo)
|
|
91
|
+
.map(node => [node.info.id, node.info.dataFrame.operations
|
|
92
|
+
.filter(({ operation }) => operation === 'accessCols' || operation === 'accessRows')
|
|
93
|
+
.map(({ operation, operand, type: _type, options: _options, ...args }) => ({ operation, operand, ...args }))
|
|
94
|
+
])
|
|
95
|
+
.filter(([, operations]) => operations.length > 0));
|
|
96
|
+
}
|
|
97
|
+
function findInvalidDataFrameAccesses({ operandShape, accessedCols, accessedRows }) {
|
|
98
|
+
const invalidAccesses = [];
|
|
99
|
+
if (operandShape !== undefined) {
|
|
100
|
+
for (const row of accessedRows ?? []) {
|
|
101
|
+
if (!(0, domain_1.satisfiesLeqInterval)(operandShape.rows, row)) {
|
|
102
|
+
invalidAccesses.push({ type: 'row', accessed: row });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
for (const col of accessedCols ?? []) {
|
|
106
|
+
if (typeof col === 'string' && !(0, domain_1.satisfiesColsNames)(operandShape.colnames, col)) {
|
|
107
|
+
invalidAccesses.push({ type: 'column', accessed: col });
|
|
108
|
+
}
|
|
109
|
+
else if (typeof col === 'number' && !(0, domain_1.satisfiesLeqInterval)(operandShape.cols, col)) {
|
|
110
|
+
invalidAccesses.push({ type: 'column', accessed: col });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return invalidAccesses;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=dataframe-access-validation.js.map
|
|
@@ -65,7 +65,7 @@ export declare const NAMING_CONVENTION: {
|
|
|
65
65
|
readonly description: "Checks wether the symbols conform to a certain naming convention";
|
|
66
66
|
readonly tags: readonly [LintingRuleTag.Style, LintingRuleTag.QuickFix];
|
|
67
67
|
readonly defaultConfig: {
|
|
68
|
-
readonly caseing:
|
|
68
|
+
readonly caseing: "auto";
|
|
69
69
|
};
|
|
70
70
|
};
|
|
71
71
|
};
|
|
@@ -66,11 +66,15 @@ function detectCasing(identifier) {
|
|
|
66
66
|
return CasingConvention.Unknown;
|
|
67
67
|
}
|
|
68
68
|
function getMostUsedCasing(symbols) {
|
|
69
|
+
if (symbols.length === 0) {
|
|
70
|
+
return CasingConvention.Unknown;
|
|
71
|
+
}
|
|
69
72
|
const map = new Map();
|
|
70
73
|
for (const symbol of symbols) {
|
|
71
74
|
const o = map.get(symbol.detectedCasing) ?? 0;
|
|
72
75
|
map.set(symbol.detectedCasing, o + 1);
|
|
73
76
|
}
|
|
77
|
+
// Return element with most occurances
|
|
74
78
|
return [...map].reduce((p, c) => p[1] > c[1] ? p : c)[0];
|
|
75
79
|
}
|
|
76
80
|
function fixCasing(identifier, convention) {
|
|
@@ -157,7 +161,7 @@ exports.NAMING_CONVENTION = {
|
|
|
157
161
|
description: 'Checks wether the symbols conform to a certain naming convention',
|
|
158
162
|
tags: [linter_tags_1.LintingRuleTag.Style, linter_tags_1.LintingRuleTag.QuickFix],
|
|
159
163
|
defaultConfig: {
|
|
160
|
-
caseing:
|
|
164
|
+
caseing: 'auto'
|
|
161
165
|
}
|
|
162
166
|
}
|
|
163
167
|
};
|