@abaplint/core 2.120.73 → 2.120.75
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/abaplint.d.ts +6 -1
- package/build/src/abap/2_statements/combi.js +143 -51
- package/build/src/abap/2_statements/expressions/method_param_optional.js +3 -1
- package/build/src/abap/5_syntax/basic_types.js +67 -23
- package/build/src/abap/5_syntax/statements/append.js +6 -0
- package/build/src/abap/types/method_definition.js +22 -0
- package/build/src/abap/types/method_parameters.js +57 -0
- package/build/src/ddic.js +1 -1
- package/build/src/objects/data_definition.js +9 -1
- package/build/src/objects/domain.js +4 -1
- package/build/src/registry.js +1 -1
- package/build/src/rules/abapdoc_html_tag.js +123 -0
- package/build/src/rules/abapdoc_leading_at.js +117 -0
- package/build/src/rules/abapdoc_parameter_names.js +149 -0
- package/build/src/rules/cds_check_syntax.js +4 -4
- package/build/src/rules/change_if_to_case.js +3 -2
- package/build/src/rules/changing_sorted_line.js +235 -0
- package/build/src/rules/class_attribute_names.js +15 -6
- package/build/src/rules/delete_index_in_loop.js +163 -0
- package/build/src/rules/final_newline.js +78 -0
- package/build/src/rules/forbidden_identifier.js +4 -3
- package/build/src/rules/forbidden_void_type.js +4 -9
- package/build/src/rules/index.js +11 -0
- package/build/src/rules/inline_packed_computation.js +220 -0
- package/build/src/rules/intf_referencing_clas.js +3 -1
- package/build/src/rules/line_only_punc.js +1 -1
- package/build/src/rules/local_class_naming.js +15 -2
- package/build/src/rules/local_variable_names.js +18 -9
- package/build/src/rules/macro_naming.js +3 -2
- package/build/src/rules/method_parameter_names.js +17 -7
- package/build/src/rules/modify_only_own_db_tables.js +3 -2
- package/build/src/rules/no_exclamation_escape.js +32 -2
- package/build/src/rules/no_prefixes.js +25 -12
- package/build/src/rules/object_naming.js +18 -3
- package/build/src/rules/prefer_inline_cast.js +276 -0
- package/build/src/rules/range_row_values.js +200 -0
- package/build/src/rules/selection_screen_naming.js +21 -2
- package/build/src/rules/sicf_consistency.js +1 -2
- package/build/src/rules/sort_empty_key.js +188 -0
- package/build/src/rules/subrc_after_assign.js +220 -0
- package/build/src/rules/types_naming.js +3 -2
- package/build/src/rules/wrong_abapdoc_position.js +58 -11
- package/build/src/rules/xml_consistency.js +6 -2
- package/build/src/utils/name_validator.js +7 -3
- package/package.json +1 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ChangingSortedLine = exports.ChangingSortedLineConf = void 0;
|
|
37
|
+
const Expressions = __importStar(require("../abap/2_statements/expressions"));
|
|
38
|
+
const Statements = __importStar(require("../abap/2_statements/statements"));
|
|
39
|
+
const Structures = __importStar(require("../abap/3_structures/structures"));
|
|
40
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
41
|
+
const issue_1 = require("../issue");
|
|
42
|
+
const _irule_1 = require("./_irule");
|
|
43
|
+
const syntax_1 = require("../abap/5_syntax/syntax");
|
|
44
|
+
const _abap_object_1 = require("../objects/_abap_object");
|
|
45
|
+
const basic_1 = require("../abap/types/basic");
|
|
46
|
+
const nodes_1 = require("../abap/nodes");
|
|
47
|
+
const _typed_identifier_1 = require("../abap/types/_typed_identifier");
|
|
48
|
+
const tokens_1 = require("../abap/1_lexer/tokens");
|
|
49
|
+
class ChangingSortedLineConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
50
|
+
}
|
|
51
|
+
exports.ChangingSortedLineConf = ChangingSortedLineConf;
|
|
52
|
+
class ChangingSortedLine {
|
|
53
|
+
constructor() {
|
|
54
|
+
this.conf = new ChangingSortedLineConf();
|
|
55
|
+
}
|
|
56
|
+
getMetadata() {
|
|
57
|
+
return {
|
|
58
|
+
key: "changing_sorted_line",
|
|
59
|
+
title: "Line of a sorted or hashed table passed to CHANGING",
|
|
60
|
+
shortDescription: `A field symbol on a whole line of a sorted or hashed table, passed to a CHANGING parameter of a method`,
|
|
61
|
+
extendedInformation: `The key fields of a sorted or hashed table line are write-protected, so the line as a whole is
|
|
62
|
+
write-protected. Binding it to a CHANGING parameter activates, but the call fails at runtime with
|
|
63
|
+
CX_SY_DYN_CALL_ILLEGAL_TYPE, "the actual parameter for ... is write-protected", even when the method does not
|
|
64
|
+
change the key.
|
|
65
|
+
|
|
66
|
+
Only field symbols assigned in the same method, form or function module are checked, via READ TABLE ... ASSIGNING,
|
|
67
|
+
LOOP AT ... ASSIGNING, INSERT ... INTO TABLE ... ASSIGNING and ASSIGN itab[ ... ] TO.
|
|
68
|
+
|
|
69
|
+
Fix: read the line into a work area, pass the work area and MODIFY TABLE ... FROM it afterwards,
|
|
70
|
+
or pass only the non-key fields the method needs.`,
|
|
71
|
+
tags: [_irule_1.RuleTag.SingleFile],
|
|
72
|
+
badExample: `READ TABLE lt_sum WITH TABLE KEY app = lv_app ASSIGNING FIELD-SYMBOL(<sum>).
|
|
73
|
+
add( CHANGING cs_sum = <sum> ).`,
|
|
74
|
+
goodExample: `READ TABLE lt_sum WITH TABLE KEY app = lv_app INTO DATA(ls_sum).
|
|
75
|
+
add( CHANGING cs_sum = ls_sum ).
|
|
76
|
+
MODIFY TABLE lt_sum FROM ls_sum.`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
getConfig() {
|
|
80
|
+
return this.conf;
|
|
81
|
+
}
|
|
82
|
+
initialize(reg) {
|
|
83
|
+
this.reg = reg;
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
setConfig(conf) {
|
|
87
|
+
this.conf = conf;
|
|
88
|
+
}
|
|
89
|
+
run(obj) {
|
|
90
|
+
if (!(obj instanceof _abap_object_1.ABAPObject) || obj.getType() === "INTF") {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
const issues = [];
|
|
94
|
+
let spaghetti = undefined;
|
|
95
|
+
for (const file of obj.getABAPFiles()) {
|
|
96
|
+
const stru = file.getStructure();
|
|
97
|
+
if (stru === undefined || stru.findFirstExpression(Expressions.MethodParameters) === undefined) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (spaghetti === undefined) {
|
|
101
|
+
spaghetti = new syntax_1.SyntaxLogic(this.reg, obj).run().spaghetti;
|
|
102
|
+
}
|
|
103
|
+
const blocks = [...stru.findAllStructures(Structures.Method),
|
|
104
|
+
...stru.findAllStructures(Structures.Form),
|
|
105
|
+
...stru.findAllStructures(Structures.FunctionModule)];
|
|
106
|
+
for (const block of blocks) {
|
|
107
|
+
// field symbol name -> name of the sorted or hashed table it points into
|
|
108
|
+
const lines = new Map();
|
|
109
|
+
for (const statement of block.findAllStatementNodes()) {
|
|
110
|
+
for (const p of statement.findAllExpressions(Expressions.MethodParameters)) {
|
|
111
|
+
this.checkChanging(p, lines, spaghetti, file, issues);
|
|
112
|
+
}
|
|
113
|
+
this.updateAssigned(statement, lines, spaghetti, file);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return issues;
|
|
118
|
+
}
|
|
119
|
+
////////////////
|
|
120
|
+
checkChanging(params, lines, spaghetti, file, issues) {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
let changing = false;
|
|
123
|
+
for (const child of params.getChildren()) {
|
|
124
|
+
const str = child.concatTokens().toUpperCase();
|
|
125
|
+
if (child instanceof nodes_1.ExpressionNode && changing === true && child.get() instanceof Expressions.ParameterListT) {
|
|
126
|
+
for (const p of child.findDirectExpressions(Expressions.ParameterT)) {
|
|
127
|
+
const target = p.findDirectExpression(Expressions.Target);
|
|
128
|
+
const fs = (target === null || target === void 0 ? void 0 : target.getChildren().length) === 1 ? target.findDirectExpression(Expressions.TargetFieldSymbol) : undefined;
|
|
129
|
+
if (fs === undefined) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const table = lines.get(fs.concatTokens().toUpperCase());
|
|
133
|
+
const type = (_a = this.findReference(fs.getFirstToken().getStart(), spaghetti, file)) === null || _a === void 0 ? void 0 : _a.getType();
|
|
134
|
+
if (table === undefined || type === undefined || type.isGeneric()) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const name = (_b = p.findDirectExpression(Expressions.ParameterName)) === null || _b === void 0 ? void 0 : _b.concatTokens();
|
|
138
|
+
const message = `Line of sorted or hashed table ${table} passed to CHANGING ${name} is write-protected, ` +
|
|
139
|
+
`the call fails at runtime. Use a work area and MODIFY TABLE ... FROM, or pass only non-key fields`;
|
|
140
|
+
issues.push(issue_1.Issue.atToken(file, fs.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
changing = str === "CHANGING";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** Tracks which field symbols the last assignment pointed to a whole line of a sorted or hashed table */
|
|
147
|
+
updateAssigned(statement, lines, spaghetti, file) {
|
|
148
|
+
var _a, _b, _c;
|
|
149
|
+
var _d;
|
|
150
|
+
const get = statement.get();
|
|
151
|
+
const fs = get instanceof Statements.Unassign
|
|
152
|
+
? statement.findDirectExpression(Expressions.TargetFieldSymbol)
|
|
153
|
+
: (_a = statement.findFirstExpression(Expressions.FSTarget)) === null || _a === void 0 ? void 0 : _a.findFirstExpression(Expressions.TargetFieldSymbol);
|
|
154
|
+
if (fs === undefined) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const name = fs.concatTokens().toUpperCase();
|
|
158
|
+
let table = undefined;
|
|
159
|
+
let isTableExpression = false;
|
|
160
|
+
if (get instanceof Statements.ReadTable) {
|
|
161
|
+
table = (_d = statement.findDirectExpression(Expressions.SimpleSource2)) !== null && _d !== void 0 ? _d : statement.findDirectExpression(Expressions.Source);
|
|
162
|
+
}
|
|
163
|
+
else if (get instanceof Statements.Loop) {
|
|
164
|
+
table = (_b = statement.findDirectExpression(Expressions.LoopSource)) === null || _b === void 0 ? void 0 : _b.getFirstChild();
|
|
165
|
+
}
|
|
166
|
+
else if (get instanceof Statements.InsertInternal && statement.findDirectTokenByText("TABLE") !== undefined) {
|
|
167
|
+
table = statement.findDirectExpression(Expressions.Target);
|
|
168
|
+
}
|
|
169
|
+
else if (get instanceof Statements.Assign) {
|
|
170
|
+
table = (_c = statement.findDirectExpression(Expressions.AssignSource)) === null || _c === void 0 ? void 0 : _c.getFirstChild();
|
|
171
|
+
isTableExpression = true;
|
|
172
|
+
}
|
|
173
|
+
const tableType = table instanceof nodes_1.ExpressionNode ? this.findTableType(table, isTableExpression, spaghetti, file) : undefined;
|
|
174
|
+
if (table instanceof nodes_1.ExpressionNode && tableType instanceof basic_1.TableType
|
|
175
|
+
&& (tableType.getAccessType() === basic_1.TableAccessType.sorted || tableType.getAccessType() === basic_1.TableAccessType.hashed)) {
|
|
176
|
+
lines.set(name, table.concatTokens().replace(/\[.*$/, "").trim());
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
lines.delete(name);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** The type of a table given by a plain field chain of names, components and attributes, else undefined.
|
|
183
|
+
* With tableExpression, the chain must end with a table expression, and the type of the chain before it is returned */
|
|
184
|
+
findTableType(node, tableExpression, spaghetti, file) {
|
|
185
|
+
var _a, _b;
|
|
186
|
+
if (!(node.get() instanceof Expressions.Target)) {
|
|
187
|
+
const chain = node.getChildren().length === 1 ? node.findDirectExpression(Expressions.FieldChain) : undefined;
|
|
188
|
+
if (chain === undefined) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
node = chain;
|
|
192
|
+
}
|
|
193
|
+
const children = [...node.getChildren()];
|
|
194
|
+
if (tableExpression === true) {
|
|
195
|
+
if (!(((_a = children.pop()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.TableExpression)) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
let type = undefined;
|
|
200
|
+
for (const child of children) {
|
|
201
|
+
const get = child.get();
|
|
202
|
+
if (get instanceof Expressions.SourceField
|
|
203
|
+
|| get instanceof Expressions.SourceFieldSymbol
|
|
204
|
+
|| get instanceof Expressions.TargetField
|
|
205
|
+
|| get instanceof Expressions.TargetFieldSymbol
|
|
206
|
+
|| get instanceof Expressions.AttributeName) {
|
|
207
|
+
type = (_b = this.findReference(child.getFirstToken().getStart(), spaghetti, file)) === null || _b === void 0 ? void 0 : _b.getType();
|
|
208
|
+
}
|
|
209
|
+
else if (get instanceof Expressions.ComponentName) {
|
|
210
|
+
type = type instanceof basic_1.StructureType ? type.getComponentByName(child.concatTokens()) : undefined;
|
|
211
|
+
}
|
|
212
|
+
else if (get instanceof Expressions.ClassName || get instanceof tokens_1.StaticArrow) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
else if (!(get instanceof tokens_1.Dash) && !(get instanceof tokens_1.InstanceArrow)) {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
if (type === undefined) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return type;
|
|
223
|
+
}
|
|
224
|
+
findReference(start, spaghetti, file) {
|
|
225
|
+
const scope = spaghetti.lookupPosition(start, file.getFilename());
|
|
226
|
+
for (const r of (scope === null || scope === void 0 ? void 0 : scope.getData().references) || []) {
|
|
227
|
+
if (r.position.getStart().equals(start) && r.resolved instanceof _typed_identifier_1.TypedIdentifier) {
|
|
228
|
+
return r.resolved;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
exports.ChangingSortedLine = ChangingSortedLine;
|
|
235
|
+
//# sourceMappingURL=changing_sorted_line.js.map
|
|
@@ -30,6 +30,7 @@ class ClassAttributeNames extends _abap_rule_1.ABAPRule {
|
|
|
30
30
|
constructor() {
|
|
31
31
|
super(...arguments);
|
|
32
32
|
this.conf = new ClassAttributeNamesConf();
|
|
33
|
+
this.regex = this.compile();
|
|
33
34
|
}
|
|
34
35
|
getMetadata() {
|
|
35
36
|
return {
|
|
@@ -57,6 +58,15 @@ ENDCLASS.`,
|
|
|
57
58
|
}
|
|
58
59
|
setConfig(conf) {
|
|
59
60
|
this.conf = conf;
|
|
61
|
+
this.regex = this.compile();
|
|
62
|
+
}
|
|
63
|
+
compile() {
|
|
64
|
+
return {
|
|
65
|
+
statics: new RegExp(this.conf.statics, "i"),
|
|
66
|
+
instance: new RegExp(this.conf.instance, "i"),
|
|
67
|
+
constants: new RegExp(this.conf.constants, "i"),
|
|
68
|
+
ignorePatterns: name_validator_1.NameValidator.compileIgnorePatterns(this.conf),
|
|
69
|
+
};
|
|
60
70
|
}
|
|
61
71
|
runParsed(file, obj) {
|
|
62
72
|
if (this.conf.patternKind === undefined) {
|
|
@@ -89,13 +99,13 @@ ENDCLASS.`,
|
|
|
89
99
|
for (const a of attr) {
|
|
90
100
|
switch (a.level) {
|
|
91
101
|
case _abap_file_information_1.AttributeLevel.Instance:
|
|
92
|
-
ret = ret.concat(this.checkName(a.identifier, this.conf.instance));
|
|
102
|
+
ret = ret.concat(this.checkName(a.identifier, this.conf.instance, this.regex.instance));
|
|
93
103
|
break;
|
|
94
104
|
case _abap_file_information_1.AttributeLevel.Static:
|
|
95
|
-
ret = ret.concat(this.checkName(a.identifier, this.conf.statics));
|
|
105
|
+
ret = ret.concat(this.checkName(a.identifier, this.conf.statics, this.regex.statics));
|
|
96
106
|
break;
|
|
97
107
|
case _abap_file_information_1.AttributeLevel.Constant:
|
|
98
|
-
ret = ret.concat(this.checkName(a.identifier, this.conf.constants));
|
|
108
|
+
ret = ret.concat(this.checkName(a.identifier, this.conf.constants, this.regex.constants));
|
|
99
109
|
break;
|
|
100
110
|
default:
|
|
101
111
|
break;
|
|
@@ -103,11 +113,10 @@ ENDCLASS.`,
|
|
|
103
113
|
}
|
|
104
114
|
return ret;
|
|
105
115
|
}
|
|
106
|
-
checkName(attr, expected) {
|
|
116
|
+
checkName(attr, expected, regex) {
|
|
107
117
|
const ret = [];
|
|
108
|
-
const regex = new RegExp(expected, "i");
|
|
109
118
|
const name = attr.getName();
|
|
110
|
-
if (name_validator_1.NameValidator.violatesRule(name, regex, this.conf)) {
|
|
119
|
+
if (name_validator_1.NameValidator.violatesRule(name, regex, this.conf, this.regex.ignorePatterns)) {
|
|
111
120
|
const issue = issue_1.Issue.atIdentifier(attr, this.getDescription(name, expected), this.getMetadata().key, this.conf.severity);
|
|
112
121
|
ret.push(issue);
|
|
113
122
|
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DeleteIndexInLoop = exports.DeleteIndexInLoopConf = void 0;
|
|
37
|
+
const Statements = __importStar(require("../abap/2_statements/statements"));
|
|
38
|
+
const Expressions = __importStar(require("../abap/2_statements/expressions"));
|
|
39
|
+
const issue_1 = require("../issue");
|
|
40
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
41
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
42
|
+
const _irule_1 = require("./_irule");
|
|
43
|
+
const token_node_1 = require("../abap/nodes/token_node");
|
|
44
|
+
const _statement_1 = require("../abap/2_statements/statements/_statement");
|
|
45
|
+
class DeleteIndexInLoopConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
46
|
+
}
|
|
47
|
+
exports.DeleteIndexInLoopConf = DeleteIndexInLoopConf;
|
|
48
|
+
class DeleteIndexInLoop extends _abap_rule_1.ABAPRule {
|
|
49
|
+
constructor() {
|
|
50
|
+
super(...arguments);
|
|
51
|
+
this.conf = new DeleteIndexInLoopConf();
|
|
52
|
+
}
|
|
53
|
+
getMetadata() {
|
|
54
|
+
return {
|
|
55
|
+
key: "delete_index_in_loop",
|
|
56
|
+
title: "DELETE INDEX sy-tabix inside a LOOP over the same table",
|
|
57
|
+
shortDescription: `Reports DELETE itab INDEX sy-tabix inside a LOOP AT the same table`,
|
|
58
|
+
extendedInformation: `sy-tabix is the index of the loop's current row only until another statement writes it.
|
|
59
|
+
READ TABLE, APPEND, INSERT, COLLECT, a nested LOOP and any method called in the loop body
|
|
60
|
+
all set sy-tabix. After that the DELETE removes a different row, and if sy-tabix is 0 it
|
|
61
|
+
raises the runtime error TABLE_INVALID_INDEX.
|
|
62
|
+
|
|
63
|
+
Use DELETE itab WHERE ..., or collect the rows to keep in a second table.
|
|
64
|
+
|
|
65
|
+
Not reported: DELETE itab INDEX sy-tabix directly after READ TABLE itab, where sy-tabix
|
|
66
|
+
is the index the READ just set.`,
|
|
67
|
+
tags: [_irule_1.RuleTag.SingleFile],
|
|
68
|
+
badExample: `LOOP AT tab INTO row.
|
|
69
|
+
IF row-flag = abap_true.
|
|
70
|
+
DELETE tab INDEX sy-tabix.
|
|
71
|
+
ENDIF.
|
|
72
|
+
ENDLOOP.`,
|
|
73
|
+
goodExample: `DELETE tab WHERE flag = abap_true.`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
getConfig() {
|
|
77
|
+
return this.conf;
|
|
78
|
+
}
|
|
79
|
+
setConfig(conf) {
|
|
80
|
+
this.conf = conf;
|
|
81
|
+
}
|
|
82
|
+
runParsed(file) {
|
|
83
|
+
const issues = [];
|
|
84
|
+
const statements = file.getStatements();
|
|
85
|
+
for (let i = 0; i < statements.length; i++) {
|
|
86
|
+
const statement = statements[i];
|
|
87
|
+
if (!(statement.get() instanceof Statements.DeleteInternal) || this.byTabix(statement) === false) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
// DELETE TABLE and DELETE ADJACENT DUPLICATES have a keyword before the target
|
|
91
|
+
const target = statement.findDirectExpression(Expressions.Target);
|
|
92
|
+
if (target === undefined || statement.getChildren()[1] !== target) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const table = target.concatTokens().toUpperCase();
|
|
96
|
+
if (this.previousReadsTable(i, statements, table) === true
|
|
97
|
+
|| this.enclosingLoopTables(i, statements).includes(table) === false) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const message = `DELETE ${target.concatTokens()} INDEX sy-tabix inside LOOP AT the same table,`
|
|
101
|
+
+ ` sy-tabix might not be the loop's current row`;
|
|
102
|
+
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
|
|
103
|
+
}
|
|
104
|
+
return issues;
|
|
105
|
+
}
|
|
106
|
+
////////////////
|
|
107
|
+
byTabix(statement) {
|
|
108
|
+
const children = statement.getChildren();
|
|
109
|
+
for (let i = 0; i < children.length - 1; i++) {
|
|
110
|
+
const child = children[i];
|
|
111
|
+
if (child instanceof token_node_1.TokenNode && child.getFirstToken().getStr().toUpperCase() === "INDEX") {
|
|
112
|
+
return children[i + 1].concatTokens().toUpperCase() === "SY-TABIX";
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
previousReadsTable(index, statements, table) {
|
|
118
|
+
var _a;
|
|
119
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
120
|
+
const statement = statements[i];
|
|
121
|
+
if (statement.get() instanceof _statement_1.Comment) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!(statement.get() instanceof Statements.ReadTable)) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
const read = (_a = statement.findDirectExpression(Expressions.SimpleSource2)) !== null && _a !== void 0 ? _a : statement.findDirectExpression(Expressions.Source);
|
|
128
|
+
return (read === null || read === void 0 ? void 0 : read.concatTokens().toUpperCase()) === table;
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
enclosingLoopTables(index, statements) {
|
|
133
|
+
const tables = [];
|
|
134
|
+
let depth = 0;
|
|
135
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
136
|
+
const statement = statements[i];
|
|
137
|
+
const s = statement.get();
|
|
138
|
+
if (s instanceof Statements.EndLoop) {
|
|
139
|
+
depth++;
|
|
140
|
+
}
|
|
141
|
+
else if (s instanceof Statements.Loop) {
|
|
142
|
+
if (depth === 0) {
|
|
143
|
+
const source = statement.findDirectExpression(Expressions.LoopSource);
|
|
144
|
+
if (source !== undefined) {
|
|
145
|
+
tables.push(source.concatTokens().toUpperCase());
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
depth--;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (s instanceof Statements.MethodImplementation
|
|
153
|
+
|| s instanceof Statements.Form
|
|
154
|
+
|| s instanceof Statements.FunctionModule
|
|
155
|
+
|| s instanceof Statements.Module) {
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return tables;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.DeleteIndexInLoop = DeleteIndexInLoop;
|
|
163
|
+
//# sourceMappingURL=delete_index_in_loop.js.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FinalNewline = exports.FinalNewlineConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const position_1 = require("../position");
|
|
6
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
7
|
+
const edit_helper_1 = require("../edit_helper");
|
|
8
|
+
const _irule_1 = require("./_irule");
|
|
9
|
+
const objects_1 = require("../objects");
|
|
10
|
+
class FinalNewlineConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
11
|
+
}
|
|
12
|
+
exports.FinalNewlineConf = FinalNewlineConf;
|
|
13
|
+
class FinalNewline {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.conf = new FinalNewlineConf();
|
|
16
|
+
}
|
|
17
|
+
getMetadata() {
|
|
18
|
+
return {
|
|
19
|
+
key: "final_newline",
|
|
20
|
+
title: "Final newline",
|
|
21
|
+
shortDescription: `Checks that ABAP and XML files end with exactly one newline`,
|
|
22
|
+
extendedInformation: `abapGit serializes every file with exactly one newline at the end. A file without it,
|
|
23
|
+
or with empty lines at the end, is changed again on the next pull and shows up in every diff.
|
|
24
|
+
|
|
25
|
+
Empty files and files containing only line breaks are not checked. A carriage return before the
|
|
26
|
+
newline is ignored, see rule line_break_style. SMIM and W3MI files and XSLT sources are not checked.`,
|
|
27
|
+
tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
|
|
28
|
+
badExample: `WRITE 'hello'.`,
|
|
29
|
+
goodExample: `WRITE 'hello'.\n`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
getConfig() {
|
|
33
|
+
return this.conf;
|
|
34
|
+
}
|
|
35
|
+
setConfig(conf) {
|
|
36
|
+
this.conf = conf;
|
|
37
|
+
}
|
|
38
|
+
initialize(_reg) {
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
run(obj) {
|
|
42
|
+
const issues = [];
|
|
43
|
+
if (obj instanceof objects_1.MIMEObject || obj instanceof objects_1.WebMIME) {
|
|
44
|
+
return issues;
|
|
45
|
+
}
|
|
46
|
+
for (const file of obj.getFiles()) {
|
|
47
|
+
const filename = file.getFilename();
|
|
48
|
+
if ((filename.endsWith(".abap") || filename.endsWith(".xml")) && !filename.endsWith(".xslt.source.xml")) {
|
|
49
|
+
const issue = this.checkFile(file);
|
|
50
|
+
if (issue) {
|
|
51
|
+
issues.push(issue);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return issues;
|
|
56
|
+
}
|
|
57
|
+
checkFile(file) {
|
|
58
|
+
const rows = file.getRawRows();
|
|
59
|
+
const last = rows[rows.length - 1];
|
|
60
|
+
if (last !== "") {
|
|
61
|
+
const end = new position_1.Position(rows.length, last.length + 1);
|
|
62
|
+
const fix = edit_helper_1.EditHelper.insertAt(file, end, "\n");
|
|
63
|
+
return issue_1.Issue.atPosition(file, end, "Add newline at end of file", this.getMetadata().key, this.conf.severity, fix);
|
|
64
|
+
}
|
|
65
|
+
let row = rows.length - 2;
|
|
66
|
+
while (row >= 0 && (rows[row] === "" || rows[row] === "\r")) {
|
|
67
|
+
row--;
|
|
68
|
+
}
|
|
69
|
+
if (row < 0 || row === rows.length - 2) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
const start = new position_1.Position(row + 2, 1);
|
|
73
|
+
const fix = edit_helper_1.EditHelper.deleteRange(file, start, new position_1.Position(rows.length, 1));
|
|
74
|
+
return issue_1.Issue.atPosition(file, start, "Remove empty lines at end of file", this.getMetadata().key, this.conf.severity, fix);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.FinalNewline = FinalNewline;
|
|
78
|
+
//# sourceMappingURL=final_newline.js.map
|
|
@@ -20,6 +20,7 @@ class ForbiddenIdentifier extends _abap_rule_1.ABAPRule {
|
|
|
20
20
|
constructor() {
|
|
21
21
|
super(...arguments);
|
|
22
22
|
this.conf = new ForbiddenIdentifierConf();
|
|
23
|
+
this.checks = [];
|
|
23
24
|
}
|
|
24
25
|
getMetadata() {
|
|
25
26
|
return {
|
|
@@ -39,9 +40,10 @@ https://github.com/abaplint/transpiler/blob/bda94b8b56e2b7f2f87be2168f12361aa530
|
|
|
39
40
|
if (this.conf.check === undefined) {
|
|
40
41
|
this.conf.check = [];
|
|
41
42
|
}
|
|
43
|
+
this.checks = this.conf.check.map(c => new RegExp(c, "i"));
|
|
42
44
|
}
|
|
43
45
|
runParsed(file) {
|
|
44
|
-
if (this.
|
|
46
|
+
if (this.checks.length === 0) {
|
|
45
47
|
return [];
|
|
46
48
|
}
|
|
47
49
|
let ret = [];
|
|
@@ -68,8 +70,7 @@ https://github.com/abaplint/transpiler/blob/bda94b8b56e2b7f2f87be2168f12361aa530
|
|
|
68
70
|
check(token, file) {
|
|
69
71
|
const str = token.getStr();
|
|
70
72
|
const ret = [];
|
|
71
|
-
for (const
|
|
72
|
-
const reg = new RegExp(c, "i");
|
|
73
|
+
for (const reg of this.checks) {
|
|
73
74
|
if (reg.exec(str)) {
|
|
74
75
|
const message = "Identifer \"" + str + "\" not allowed";
|
|
75
76
|
ret.push(issue_1.Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity));
|
|
@@ -22,6 +22,7 @@ exports.ForbiddenVoidTypeConf = ForbiddenVoidTypeConf;
|
|
|
22
22
|
class ForbiddenVoidType {
|
|
23
23
|
constructor() {
|
|
24
24
|
this.conf = new ForbiddenVoidTypeConf();
|
|
25
|
+
this.checks = [];
|
|
25
26
|
}
|
|
26
27
|
getMetadata() {
|
|
27
28
|
return {
|
|
@@ -41,13 +42,14 @@ DATS, TIMS, DATUM, FLAG, INT4, NUMC3, NUMC4, SAP_BOOL, TEXT25, TEXT80, X255, XFE
|
|
|
41
42
|
if (this.conf.check === undefined) {
|
|
42
43
|
this.conf.check = [];
|
|
43
44
|
}
|
|
45
|
+
this.checks = this.conf.check.map(c => new RegExp(c, "i"));
|
|
44
46
|
}
|
|
45
47
|
initialize(reg) {
|
|
46
48
|
this.reg = reg;
|
|
47
49
|
return this;
|
|
48
50
|
}
|
|
49
51
|
run(obj) {
|
|
50
|
-
if (!(obj instanceof _abap_object_1.ABAPObject) || this.
|
|
52
|
+
if (!(obj instanceof _abap_object_1.ABAPObject) || this.checks.length === 0) {
|
|
51
53
|
return [];
|
|
52
54
|
}
|
|
53
55
|
return this.traverse(new syntax_1.SyntaxLogic(this.reg, obj).run().spaghetti.getTop());
|
|
@@ -90,14 +92,7 @@ DATS, TIMS, DATUM, FLAG, INT4, NUMC3, NUMC4, SAP_BOOL, TEXT25, TEXT80, X255, XFE
|
|
|
90
92
|
if (name === undefined) {
|
|
91
93
|
return false;
|
|
92
94
|
}
|
|
93
|
-
|
|
94
|
-
const reg = new RegExp(c, "i");
|
|
95
|
-
const match = reg.test(name);
|
|
96
|
-
if (match === true) {
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return false;
|
|
95
|
+
return this.checks.some(reg => reg.test(name));
|
|
101
96
|
}
|
|
102
97
|
}
|
|
103
98
|
exports.ForbiddenVoidType = ForbiddenVoidType;
|
package/build/src/rules/index.js
CHANGED
|
@@ -16,6 +16,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./7bit_ascii"), exports);
|
|
18
18
|
__exportStar(require("./abapdoc"), exports);
|
|
19
|
+
__exportStar(require("./abapdoc_html_tag"), exports);
|
|
20
|
+
__exportStar(require("./abapdoc_leading_at"), exports);
|
|
21
|
+
__exportStar(require("./abapdoc_parameter_names"), exports);
|
|
19
22
|
__exportStar(require("./add_test_attributes"), exports);
|
|
20
23
|
__exportStar(require("./aff_and_xml"), exports);
|
|
21
24
|
__exportStar(require("./align_parameters"), exports);
|
|
@@ -38,6 +41,7 @@ __exportStar(require("./cds_naming"), exports);
|
|
|
38
41
|
__exportStar(require("./cds_parser_error"), exports);
|
|
39
42
|
__exportStar(require("./chain_mainly_declarations"), exports);
|
|
40
43
|
__exportStar(require("./change_if_to_case"), exports);
|
|
44
|
+
__exportStar(require("./changing_sorted_line"), exports);
|
|
41
45
|
__exportStar(require("./check_abstract"), exports);
|
|
42
46
|
__exportStar(require("./check_comments"), exports);
|
|
43
47
|
__exportStar(require("./check_ddic"), exports);
|
|
@@ -60,6 +64,7 @@ __exportStar(require("./cyclomatic_complexity"), exports);
|
|
|
60
64
|
__exportStar(require("./dangerous_statement"), exports);
|
|
61
65
|
__exportStar(require("./db_operation_in_loop"), exports);
|
|
62
66
|
__exportStar(require("./definitions_top"), exports);
|
|
67
|
+
__exportStar(require("./delete_index_in_loop"), exports);
|
|
63
68
|
__exportStar(require("./description_empty"), exports);
|
|
64
69
|
__exportStar(require("./double_space"), exports);
|
|
65
70
|
__exportStar(require("./downport"), exports);
|
|
@@ -73,6 +78,7 @@ __exportStar(require("./else_after_all_returns"), exports);
|
|
|
73
78
|
__exportStar(require("./exit_or_check"), exports);
|
|
74
79
|
__exportStar(require("./expand_macros"), exports);
|
|
75
80
|
__exportStar(require("./exporting"), exports);
|
|
81
|
+
__exportStar(require("./final_newline"), exports);
|
|
76
82
|
__exportStar(require("./fm_global_parameters_obsolete"), exports);
|
|
77
83
|
__exportStar(require("./forbidden_identifier"), exports);
|
|
78
84
|
__exportStar(require("./forbidden_pseudo_and_pragma"), exports);
|
|
@@ -96,6 +102,7 @@ __exportStar(require("./in_statement_indentation"), exports);
|
|
|
96
102
|
__exportStar(require("./indentation"), exports);
|
|
97
103
|
__exportStar(require("./index_completely_contained"), exports);
|
|
98
104
|
__exportStar(require("./inline_data_old_versions"), exports);
|
|
105
|
+
__exportStar(require("./inline_packed_computation"), exports);
|
|
99
106
|
__exportStar(require("./intf_referencing_clas"), exports);
|
|
100
107
|
__exportStar(require("./invalid_table_index"), exports);
|
|
101
108
|
__exportStar(require("./keep_single_parameter_on_one_line"), exports);
|
|
@@ -147,6 +154,7 @@ __exportStar(require("./parser_missing_space"), exports);
|
|
|
147
154
|
__exportStar(require("./pragma_style"), exports);
|
|
148
155
|
__exportStar(require("./prefer_corresponding"), exports);
|
|
149
156
|
__exportStar(require("./prefer_inline"), exports);
|
|
157
|
+
__exportStar(require("./prefer_inline_cast"), exports);
|
|
150
158
|
__exportStar(require("./prefer_insert_into_table"), exports);
|
|
151
159
|
__exportStar(require("./prefer_is_not"), exports);
|
|
152
160
|
__exportStar(require("./prefer_pragmas"), exports);
|
|
@@ -159,6 +167,7 @@ __exportStar(require("./prefer_xsdbool"), exports);
|
|
|
159
167
|
__exportStar(require("./preferred_compare_operator"), exports);
|
|
160
168
|
__exportStar(require("./preferred_parameter_ignored"), exports);
|
|
161
169
|
__exportStar(require("./prefix_is_current_class"), exports);
|
|
170
|
+
__exportStar(require("./range_row_values"), exports);
|
|
162
171
|
__exportStar(require("./reduce_procedural_code"), exports);
|
|
163
172
|
__exportStar(require("./reduce_string_templates"), exports);
|
|
164
173
|
__exportStar(require("./redundant_conversion"), exports);
|
|
@@ -175,6 +184,7 @@ __exportStar(require("./short_case"), exports);
|
|
|
175
184
|
__exportStar(require("./sicf_consistency"), exports);
|
|
176
185
|
__exportStar(require("./slow_parameter_passing"), exports);
|
|
177
186
|
__exportStar(require("./smim_consistency"), exports);
|
|
187
|
+
__exportStar(require("./sort_empty_key"), exports);
|
|
178
188
|
__exportStar(require("./space_before_colon"), exports);
|
|
179
189
|
__exportStar(require("./space_before_dot"), exports);
|
|
180
190
|
__exportStar(require("./sql_escape_host_variables"), exports);
|
|
@@ -182,6 +192,7 @@ __exportStar(require("./sql_value_conversion"), exports);
|
|
|
182
192
|
__exportStar(require("./start_at_tab"), exports);
|
|
183
193
|
__exportStar(require("./static_call_via_instance"), exports);
|
|
184
194
|
__exportStar(require("./strict_sql"), exports);
|
|
195
|
+
__exportStar(require("./subrc_after_assign"), exports);
|
|
185
196
|
__exportStar(require("./superclass_final"), exports);
|
|
186
197
|
__exportStar(require("./superfluous_value"), exports);
|
|
187
198
|
__exportStar(require("./sy_modification"), exports);
|