@abaplint/core 2.105.26 → 2.106.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/build/src/abap/2_statements/statements/concatenate.js +2 -2
- package/build/src/abap/5_syntax/_procedural.js +11 -2
- package/build/src/abap/5_syntax/expressions/source.js +21 -0
- package/build/src/abap/5_syntax/statements/concatenate.js +12 -9
- package/build/src/registry.js +1 -1
- package/build/src/rules/identical_conditions.js +12 -0
- package/build/src/rules/index.js +1 -0
- package/build/src/rules/invalid_table_index.js +73 -0
- package/build/src/rules/slow_parameter_passing.js +18 -0
- package/build/src/rules/strict_sql.js +2 -0
- package/package.json +4 -4
|
@@ -7,9 +7,9 @@ class Concatenate {
|
|
|
7
7
|
getMatcher() {
|
|
8
8
|
const mode = (0, combi_1.seq)("IN", (0, combi_1.altPrio)("BYTE", "CHARACTER"), "MODE");
|
|
9
9
|
const blanks = (0, combi_1.str)("RESPECTING BLANKS");
|
|
10
|
-
const sep = (0, combi_1.seq)("SEPARATED BY", expressions_1.
|
|
10
|
+
const sep = (0, combi_1.seq)("SEPARATED BY", expressions_1.SimpleSource3);
|
|
11
11
|
const options = (0, combi_1.per)(mode, blanks, sep);
|
|
12
|
-
const sourc = (0, combi_1.seq)(expressions_1.
|
|
12
|
+
const sourc = (0, combi_1.seq)(expressions_1.SimpleSource3, (0, combi_1.plus)(expressions_1.SimpleSource3));
|
|
13
13
|
const lines = (0, combi_1.seq)("LINES OF", expressions_1.Source);
|
|
14
14
|
return (0, combi_1.seq)("CONCATENATE", (0, combi_1.altPrio)(lines, sourc), "INTO", expressions_1.Target, (0, combi_1.optPrio)(options));
|
|
15
15
|
}
|
|
@@ -81,6 +81,7 @@ class Procedural {
|
|
|
81
81
|
throw new Error("Function module definition \"" + name + "\" not found");
|
|
82
82
|
}
|
|
83
83
|
const ddic = new ddic_1.DDIC(this.reg);
|
|
84
|
+
const allNames = new Set();
|
|
84
85
|
for (const param of definition.getParameters()) {
|
|
85
86
|
let found = undefined;
|
|
86
87
|
if (param.type === undefined || param.type === "") {
|
|
@@ -157,8 +158,16 @@ class Procedural {
|
|
|
157
158
|
if (found instanceof basic_1.UnknownType && new ddic_1.DDIC(this.reg).inErrorNamespace(param.type) === false) {
|
|
158
159
|
found = new basic_1.VoidType(param.type);
|
|
159
160
|
}
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
if (allNames.has(param.name.toUpperCase())) {
|
|
162
|
+
// yea, IMPORTING and EXPORTING can have the same name
|
|
163
|
+
// workaround to avoid false postivies, can be improved
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const type = new _typed_identifier_1.TypedIdentifier(nameToken, filename, found);
|
|
168
|
+
this.scope.addNamedIdentifier(param.name, type);
|
|
169
|
+
allNames.add(param.name.toUpperCase());
|
|
170
|
+
}
|
|
162
171
|
}
|
|
163
172
|
}
|
|
164
173
|
}
|
|
@@ -176,6 +176,8 @@ class Source {
|
|
|
176
176
|
if (writeReference) {
|
|
177
177
|
type.push(_reference_1.ReferenceType.DataWriteReference);
|
|
178
178
|
}
|
|
179
|
+
let hexExpected = false;
|
|
180
|
+
let hexNext = false;
|
|
179
181
|
while (children.length >= 0) {
|
|
180
182
|
if (first instanceof nodes_1.ExpressionNode && first.get() instanceof Expressions.MethodCallChain) {
|
|
181
183
|
context = new method_call_chain_1.MethodCallChain().runSyntax(first, scope, filename, targetType);
|
|
@@ -207,10 +209,29 @@ class Source {
|
|
|
207
209
|
if (first.concatTokens() === "**") {
|
|
208
210
|
context = new basic_1.FloatType();
|
|
209
211
|
}
|
|
212
|
+
const operator = first.concatTokens().toUpperCase();
|
|
213
|
+
if (operator === "BIT-OR" || operator === "BIT-AND" || operator === "BIT-XOR") {
|
|
214
|
+
hexExpected = true;
|
|
215
|
+
hexNext = true;
|
|
216
|
+
}
|
|
210
217
|
}
|
|
211
218
|
else if (first instanceof nodes_1.ExpressionNode && first.get() instanceof Expressions.AttributeChain) {
|
|
212
219
|
context = new attribute_chain_1.AttributeChain().runSyntax(context, first, scope, filename, type);
|
|
213
220
|
}
|
|
221
|
+
if (hexExpected === true) {
|
|
222
|
+
if (!(context instanceof basic_1.VoidType)
|
|
223
|
+
&& !(context instanceof basic_1.XStringType)
|
|
224
|
+
&& !(context instanceof basic_1.HexType)
|
|
225
|
+
&& !(context instanceof basic_1.XGenericType)
|
|
226
|
+
&& !(context instanceof basic_1.XSequenceType)
|
|
227
|
+
&& !(context instanceof unknown_type_1.UnknownType)) {
|
|
228
|
+
throw new Error("Operator only valid for XSTRING or HEX");
|
|
229
|
+
}
|
|
230
|
+
if (hexNext === false) {
|
|
231
|
+
hexExpected = false;
|
|
232
|
+
}
|
|
233
|
+
hexNext = false;
|
|
234
|
+
}
|
|
214
235
|
first = children.shift();
|
|
215
236
|
if (first === undefined) {
|
|
216
237
|
break;
|
|
@@ -10,7 +10,7 @@ const _type_utils_1 = require("../_type_utils");
|
|
|
10
10
|
class Concatenate {
|
|
11
11
|
runSyntax(node, scope, filename) {
|
|
12
12
|
const byteMode = node.findDirectTokenByText("BYTE") !== undefined;
|
|
13
|
-
|
|
13
|
+
const linesMode = node.findDirectTokenByText("LINES") !== undefined;
|
|
14
14
|
const target = node.findFirstExpression(Expressions.Target);
|
|
15
15
|
const inline = target === null || target === void 0 ? void 0 : target.findDirectExpression(Expressions.InlineData);
|
|
16
16
|
if (inline) {
|
|
@@ -28,18 +28,21 @@ class Concatenate {
|
|
|
28
28
|
throw new Error("Target type not compatible");
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
31
|
+
if (linesMode) {
|
|
32
|
+
for (const s of node.findDirectExpressions(Expressions.Source)) {
|
|
33
|
+
const type = new source_1.Source().runSyntax(s, scope, filename);
|
|
34
34
|
if (!(type instanceof basic_1.UnknownType) && !(type instanceof basic_1.VoidType) && !(type instanceof basic_1.TableType)) {
|
|
35
35
|
throw new Error("Source must be an internal table");
|
|
36
36
|
}
|
|
37
|
-
linesMode = false;
|
|
38
|
-
continue;
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
for (const s of node.findDirectExpressions(Expressions.SimpleSource3)) {
|
|
41
|
+
const type = new source_1.Source().runSyntax(s, scope, filename);
|
|
42
|
+
const compatible = byteMode ? new _type_utils_1.TypeUtils(scope).isHexLike(type) : new _type_utils_1.TypeUtils(scope).isCharLikeStrict(type);
|
|
43
|
+
if (compatible === false) {
|
|
44
|
+
throw new Error("Source type not compatible");
|
|
45
|
+
}
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
48
|
}
|
package/build/src/registry.js
CHANGED
|
@@ -37,6 +37,18 @@ class IdenticalConditions extends _abap_rule_1.ABAPRule {
|
|
|
37
37
|
|
|
38
38
|
Prerequsites: code is pretty printed with identical cAsE`,
|
|
39
39
|
tags: [_irule_1.RuleTag.SingleFile],
|
|
40
|
+
badExample: `IF foo = bar OR 1 = a OR foo = bar.
|
|
41
|
+
ENDIF.
|
|
42
|
+
CASE bar.
|
|
43
|
+
WHEN '1'.
|
|
44
|
+
WHEN 'A' OR '1'.
|
|
45
|
+
ENDCASE.`,
|
|
46
|
+
goodExample: `IF foo = bar OR 1 = a.
|
|
47
|
+
ENDIF.
|
|
48
|
+
CASE bar.
|
|
49
|
+
WHEN '1'.
|
|
50
|
+
WHEN 'A'.
|
|
51
|
+
ENDCASE.`,
|
|
40
52
|
};
|
|
41
53
|
}
|
|
42
54
|
getConfig() {
|
package/build/src/rules/index.js
CHANGED
|
@@ -80,6 +80,7 @@ __exportStar(require("./in_statement_indentation"), exports);
|
|
|
80
80
|
__exportStar(require("./indentation"), exports);
|
|
81
81
|
__exportStar(require("./inline_data_old_versions"), exports);
|
|
82
82
|
__exportStar(require("./intf_referencing_clas"), exports);
|
|
83
|
+
__exportStar(require("./invalid_table_index"), exports);
|
|
83
84
|
__exportStar(require("./keep_single_parameter_on_one_line"), exports);
|
|
84
85
|
__exportStar(require("./keyword_case"), exports);
|
|
85
86
|
__exportStar(require("./line_break_multiple_parameters"), exports);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidTableIndex = exports.InvalidTableIndexConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const Expressions = require("../abap/2_statements/expressions");
|
|
6
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
7
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
8
|
+
const _irule_1 = require("./_irule");
|
|
9
|
+
const edit_helper_1 = require("../edit_helper");
|
|
10
|
+
const statements_1 = require("../abap/2_statements/statements");
|
|
11
|
+
class InvalidTableIndexConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
12
|
+
}
|
|
13
|
+
exports.InvalidTableIndexConf = InvalidTableIndexConf;
|
|
14
|
+
class InvalidTableIndex extends _abap_rule_1.ABAPRule {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.conf = new InvalidTableIndexConf();
|
|
18
|
+
}
|
|
19
|
+
getMetadata() {
|
|
20
|
+
return {
|
|
21
|
+
key: "invalid_table_index",
|
|
22
|
+
title: "Invalid Table Index",
|
|
23
|
+
shortDescription: `Issues error for constant table index zero, as ABAP starts from 1`,
|
|
24
|
+
tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
|
|
25
|
+
badExample: `DATA(first) = table[ 0 ].
|
|
26
|
+
READ TABLE gt_stack ASSIGNING <ls_stack> INDEX 0.`,
|
|
27
|
+
goodExample: `DATA(first) = table[ 1 ].
|
|
28
|
+
READ TABLE gt_stack ASSIGNING <ls_stack> INDEX 1.`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
getConfig() {
|
|
32
|
+
return this.conf;
|
|
33
|
+
}
|
|
34
|
+
setConfig(conf) {
|
|
35
|
+
this.conf = conf;
|
|
36
|
+
}
|
|
37
|
+
runParsed(file) {
|
|
38
|
+
var _a, _b, _c, _d, _e, _f;
|
|
39
|
+
const issues = [];
|
|
40
|
+
const stru = file.getStructure();
|
|
41
|
+
if (stru === undefined) {
|
|
42
|
+
return issues; // parser error
|
|
43
|
+
}
|
|
44
|
+
const expr = stru.findAllExpressionsRecursive(Expressions.TableExpression);
|
|
45
|
+
for (const e of expr) {
|
|
46
|
+
const token = (_c = (_b = (_a = e.findDirectExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Constant)) === null || _b === void 0 ? void 0 : _b.findFirstExpression(Expressions.Integer)) === null || _c === void 0 ? void 0 : _c.getFirstToken();
|
|
47
|
+
if (token === undefined) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (token.getStr() === "0") {
|
|
51
|
+
const message = "Table index starts from 1";
|
|
52
|
+
const fix = edit_helper_1.EditHelper.replaceToken(file, token, "1");
|
|
53
|
+
const issue = issue_1.Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity, fix);
|
|
54
|
+
issues.push(issue);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const rt of stru.findAllStatements(statements_1.ReadTable)) {
|
|
58
|
+
const token = (_f = (_e = (_d = rt.findExpressionAfterToken("INDEX")) === null || _d === void 0 ? void 0 : _d.findDirectExpression(Expressions.Constant)) === null || _e === void 0 ? void 0 : _e.findFirstExpression(Expressions.Integer)) === null || _f === void 0 ? void 0 : _f.getFirstToken();
|
|
59
|
+
if (token === undefined) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (token.getStr() === "0") {
|
|
63
|
+
const message = "Table index starts from 1";
|
|
64
|
+
const fix = edit_helper_1.EditHelper.replaceToken(file, token, "1");
|
|
65
|
+
const issue = issue_1.Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity, fix);
|
|
66
|
+
issues.push(issue);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return issues;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.InvalidTableIndex = InvalidTableIndex;
|
|
73
|
+
//# sourceMappingURL=invalid_table_index.js.map
|
|
@@ -22,6 +22,24 @@ class SlowParameterPassing {
|
|
|
22
22
|
shortDescription: `Detects slow pass by value passing for methods where parameter is not changed`,
|
|
23
23
|
extendedInformation: `Method parameters defined in interfaces is not checked`,
|
|
24
24
|
tags: [_irule_1.RuleTag.Performance],
|
|
25
|
+
badExample: `CLASS lcl DEFINITION.
|
|
26
|
+
PUBLIC SECTION.
|
|
27
|
+
METHODS bar IMPORTING VALUE(sdf) TYPE string.
|
|
28
|
+
ENDCLASS.
|
|
29
|
+
CLASS lcl IMPLEMENTATION.
|
|
30
|
+
METHOD bar.
|
|
31
|
+
WRITE sdf.
|
|
32
|
+
ENDMETHOD.
|
|
33
|
+
ENDCLASS.`,
|
|
34
|
+
goodExample: `CLASS lcl DEFINITION.
|
|
35
|
+
PUBLIC SECTION.
|
|
36
|
+
METHODS bar IMPORTING sdf TYPE string.
|
|
37
|
+
ENDCLASS.
|
|
38
|
+
CLASS lcl IMPLEMENTATION.
|
|
39
|
+
METHOD bar.
|
|
40
|
+
WRITE sdf.
|
|
41
|
+
ENDMETHOD.
|
|
42
|
+
ENDCLASS.`,
|
|
25
43
|
};
|
|
26
44
|
}
|
|
27
45
|
getConfig() {
|
|
@@ -30,6 +30,8 @@ Also see separate rule sql_escape_host_variables
|
|
|
30
30
|
|
|
31
31
|
Activates from v750 and up`,
|
|
32
32
|
tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Quickfix],
|
|
33
|
+
badExample: `SELECT * FROM ztabl INTO TABLE @rt_content WHERE type = @iv_type ORDER BY PRIMARY KEY.`,
|
|
34
|
+
goodExample: `SELECT * FROM ztabl WHERE type = @iv_type ORDER BY PRIMARY KEY INTO TABLE @rt_content.`,
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
37
|
getConfig() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.106.0",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
@@ -50,17 +50,17 @@
|
|
|
50
50
|
},
|
|
51
51
|
"homepage": "https://abaplint.org",
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@microsoft/api-extractor": "^7.
|
|
53
|
+
"@microsoft/api-extractor": "^7.42.3",
|
|
54
54
|
"@types/chai": "^4.3.12",
|
|
55
55
|
"@types/mocha": "^10.0.6",
|
|
56
|
-
"@types/node": "^20.11.
|
|
56
|
+
"@types/node": "^20.11.25",
|
|
57
57
|
"chai": "^4.4.1",
|
|
58
58
|
"eslint": "^8.57.0",
|
|
59
59
|
"mocha": "^10.3.0",
|
|
60
60
|
"c8": "^9.1.0",
|
|
61
61
|
"source-map-support": "^0.5.21",
|
|
62
62
|
"ts-json-schema-generator": "^1.5.0",
|
|
63
|
-
"typescript": "^5.
|
|
63
|
+
"typescript": "^5.4.2"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"fast-xml-parser": "^4.3.5",
|