@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.
Files changed (45) hide show
  1. package/build/abaplint.d.ts +6 -1
  2. package/build/src/abap/2_statements/combi.js +143 -51
  3. package/build/src/abap/2_statements/expressions/method_param_optional.js +3 -1
  4. package/build/src/abap/5_syntax/basic_types.js +67 -23
  5. package/build/src/abap/5_syntax/statements/append.js +6 -0
  6. package/build/src/abap/types/method_definition.js +22 -0
  7. package/build/src/abap/types/method_parameters.js +57 -0
  8. package/build/src/ddic.js +1 -1
  9. package/build/src/objects/data_definition.js +9 -1
  10. package/build/src/objects/domain.js +4 -1
  11. package/build/src/registry.js +1 -1
  12. package/build/src/rules/abapdoc_html_tag.js +123 -0
  13. package/build/src/rules/abapdoc_leading_at.js +117 -0
  14. package/build/src/rules/abapdoc_parameter_names.js +149 -0
  15. package/build/src/rules/cds_check_syntax.js +4 -4
  16. package/build/src/rules/change_if_to_case.js +3 -2
  17. package/build/src/rules/changing_sorted_line.js +235 -0
  18. package/build/src/rules/class_attribute_names.js +15 -6
  19. package/build/src/rules/delete_index_in_loop.js +163 -0
  20. package/build/src/rules/final_newline.js +78 -0
  21. package/build/src/rules/forbidden_identifier.js +4 -3
  22. package/build/src/rules/forbidden_void_type.js +4 -9
  23. package/build/src/rules/index.js +11 -0
  24. package/build/src/rules/inline_packed_computation.js +220 -0
  25. package/build/src/rules/intf_referencing_clas.js +3 -1
  26. package/build/src/rules/line_only_punc.js +1 -1
  27. package/build/src/rules/local_class_naming.js +15 -2
  28. package/build/src/rules/local_variable_names.js +18 -9
  29. package/build/src/rules/macro_naming.js +3 -2
  30. package/build/src/rules/method_parameter_names.js +17 -7
  31. package/build/src/rules/modify_only_own_db_tables.js +3 -2
  32. package/build/src/rules/no_exclamation_escape.js +32 -2
  33. package/build/src/rules/no_prefixes.js +25 -12
  34. package/build/src/rules/object_naming.js +18 -3
  35. package/build/src/rules/prefer_inline_cast.js +276 -0
  36. package/build/src/rules/range_row_values.js +200 -0
  37. package/build/src/rules/selection_screen_naming.js +21 -2
  38. package/build/src/rules/sicf_consistency.js +1 -2
  39. package/build/src/rules/sort_empty_key.js +188 -0
  40. package/build/src/rules/subrc_after_assign.js +220 -0
  41. package/build/src/rules/types_naming.js +3 -2
  42. package/build/src/rules/wrong_abapdoc_position.js +58 -11
  43. package/build/src/rules/xml_consistency.js +6 -2
  44. package/build/src/utils/name_validator.js +7 -3
  45. package/package.json +1 -1
@@ -0,0 +1,220 @@
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.InlinePackedComputation = exports.InlinePackedComputationConf = void 0;
37
+ const Expressions = __importStar(require("../abap/2_statements/expressions"));
38
+ const Statements = __importStar(require("../abap/2_statements/statements"));
39
+ const _reference_1 = require("../abap/5_syntax/_reference");
40
+ const constant_1 = require("../abap/5_syntax/expressions/constant");
41
+ const syntax_1 = require("../abap/5_syntax/syntax");
42
+ const nodes_1 = require("../abap/nodes");
43
+ const types_1 = require("../abap/types");
44
+ const _typed_identifier_1 = require("../abap/types/_typed_identifier");
45
+ const basic_1 = require("../abap/types/basic");
46
+ const issue_1 = require("../issue");
47
+ const _abap_object_1 = require("../objects/_abap_object");
48
+ const _basic_rule_config_1 = require("./_basic_rule_config");
49
+ class InlinePackedComputationConf extends _basic_rule_config_1.BasicRuleConfig {
50
+ }
51
+ exports.InlinePackedComputationConf = InlinePackedComputationConf;
52
+ class InlinePackedComputation {
53
+ constructor() {
54
+ this.conf = new InlinePackedComputationConf();
55
+ }
56
+ getMetadata() {
57
+ return {
58
+ key: "inline_packed_computation",
59
+ title: "Inline declaration from a packed computation",
60
+ shortDescription: `Finds inline declarations whose value is an arithmetic expression with calculation type p`,
61
+ extendedInformation: `The result of a computation with calculation type p has no length and number of decimals
62
+ that a declaration could take over, so DATA( ) or FINAL( ) gets the type p LENGTH 8 DECIMALS 0 and the
63
+ syntax check warns "For the result of a computation with type P, the type P(8,0) is used here implicitly".
64
+ Decimals of the operands are lost, and so are digits beyond the length.
65
+
66
+ Reported when at least one operand is packed and all other operands are of type i, int8 or p. Operands
67
+ of other types, generic or unknown types, and the operator ** are not reported.
68
+
69
+ Declare the variable with the operands' type, or name the type with CONV.`,
70
+ tags: [],
71
+ badExample: `DATA a TYPE p LENGTH 8 DECIMALS 2.
72
+ DATA b TYPE p LENGTH 8 DECIMALS 2.
73
+ DATA(diff) = a - b.`,
74
+ goodExample: `DATA a TYPE p LENGTH 8 DECIMALS 2.
75
+ DATA b TYPE p LENGTH 8 DECIMALS 2.
76
+ DATA diff LIKE a.
77
+ diff = a - b.`,
78
+ };
79
+ }
80
+ getConfig() {
81
+ return this.conf;
82
+ }
83
+ setConfig(conf) {
84
+ this.conf = conf;
85
+ }
86
+ initialize(reg) {
87
+ this.reg = reg;
88
+ return this;
89
+ }
90
+ run(obj) {
91
+ var _a, _b;
92
+ if (!(obj instanceof _abap_object_1.ABAPObject)) {
93
+ return [];
94
+ }
95
+ const syntax = new syntax_1.SyntaxLogic(this.reg, obj).run();
96
+ if (syntax.issues.length > 0) {
97
+ return [];
98
+ }
99
+ const issues = [];
100
+ for (const file of obj.getABAPFiles()) {
101
+ for (const statement of file.getStatements()) {
102
+ if (!(statement.get() instanceof Statements.Move)) {
103
+ continue;
104
+ }
105
+ const inline = (_a = statement.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.InlineData);
106
+ const name = (_b = inline === null || inline === void 0 ? void 0 : inline.findDirectExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.getFirstToken();
107
+ const source = statement.findDirectExpression(Expressions.Source);
108
+ if (name === undefined
109
+ || source === undefined
110
+ || source.findDirectExpression(Expressions.ArithOperator) === undefined) {
111
+ continue;
112
+ }
113
+ const scope = syntax.spaghetti.lookupPosition(name.getStart(), file.getFilename());
114
+ if (scope === undefined) {
115
+ continue;
116
+ }
117
+ const operands = this.operandTypes(source, scope);
118
+ if (operands === undefined || operands.some(t => t instanceof basic_1.PackedType) === false) {
119
+ continue;
120
+ }
121
+ const message = `"${name.getStr()}" gets type p LENGTH 8 DECIMALS 0 from this packed computation, ` +
122
+ `declare it with the operands' type or use CONV`;
123
+ issues.push(issue_1.Issue.atToken(file, name, message, this.getMetadata().key, this.conf.severity));
124
+ }
125
+ }
126
+ return issues;
127
+ }
128
+ /** The types of the operands of an arithmetic expression, undefined when an operand is not of type
129
+ * i, int8 or p, or is not known */
130
+ operandTypes(source, scope) {
131
+ const ret = [];
132
+ for (const child of source.getChildren()) {
133
+ let found = undefined;
134
+ if (child instanceof nodes_1.TokenNode) {
135
+ // parentheses and a sign, anything else is a constructor expression or a string operator
136
+ if (["(", ")", "+", "-"].includes(child.getFirstToken().getStr()) === false) {
137
+ return undefined;
138
+ }
139
+ continue;
140
+ }
141
+ else if (child.get() instanceof Expressions.ArithOperator) {
142
+ if (["+", "-", "*", "/", "DIV", "MOD"].includes(child.concatTokens().toUpperCase()) === false) {
143
+ return undefined;
144
+ }
145
+ continue;
146
+ }
147
+ else if (child.get() instanceof Expressions.Source) {
148
+ const nested = this.operandTypes(child, scope);
149
+ if (nested === undefined) {
150
+ return undefined;
151
+ }
152
+ ret.push(...nested);
153
+ continue;
154
+ }
155
+ else if (child.get() instanceof Expressions.FieldChain) {
156
+ found = this.fieldChainType(child, scope);
157
+ }
158
+ else if (child.get() instanceof Expressions.MethodCallChain) {
159
+ found = this.methodCallType(child, scope);
160
+ }
161
+ else if (child.get() instanceof Expressions.Constant) {
162
+ found = constant_1.Constant.runSyntax(child);
163
+ }
164
+ if (found === undefined
165
+ || found.isGeneric()
166
+ || !(found instanceof basic_1.PackedType || found instanceof basic_1.IntegerType || found instanceof basic_1.Integer8Type)) {
167
+ return undefined;
168
+ }
169
+ ret.push(found);
170
+ }
171
+ return ret;
172
+ }
173
+ methodCallType(chain, scope) {
174
+ var _a, _b, _c;
175
+ const last = chain.getLastChild();
176
+ if (!(last instanceof nodes_1.ExpressionNode) || !(last.get() instanceof Expressions.MethodCall)) {
177
+ return undefined;
178
+ }
179
+ const name = (_a = last.findDirectExpression(Expressions.MethodName)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
180
+ if (name === undefined) {
181
+ return undefined;
182
+ }
183
+ const method = (_b = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.MethodReference
184
+ && reference.position.getStart().equals(name.getStart()))) === null || _b === void 0 ? void 0 : _b.resolved;
185
+ if (!(method instanceof types_1.MethodDefinition)) {
186
+ return undefined;
187
+ }
188
+ return (_c = method.getParameters().getReturning()) === null || _c === void 0 ? void 0 : _c.getType();
189
+ }
190
+ fieldChainType(fieldChain, scope) {
191
+ var _a;
192
+ const operand = (_a = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.DataReadReference
193
+ && reference.position.getStart().equals(fieldChain.getFirstToken().getStart()))) === null || _a === void 0 ? void 0 : _a.resolved;
194
+ if (!(operand instanceof _typed_identifier_1.TypedIdentifier)) {
195
+ return undefined;
196
+ }
197
+ let type = operand.getType();
198
+ for (const child of fieldChain.getChildren()) {
199
+ if (!(child instanceof nodes_1.ExpressionNode)
200
+ || child.get() instanceof Expressions.SourceField) {
201
+ continue;
202
+ }
203
+ else if (child.get() instanceof Expressions.ComponentName) {
204
+ if (type instanceof basic_1.TableType) {
205
+ type = type.getRowType();
206
+ }
207
+ if (!(type instanceof basic_1.StructureType)) {
208
+ return undefined;
209
+ }
210
+ type = type.getComponentByName(child.concatTokens());
211
+ }
212
+ else {
213
+ return undefined;
214
+ }
215
+ }
216
+ return type;
217
+ }
218
+ }
219
+ exports.InlinePackedComputation = InlinePackedComputation;
220
+ //# sourceMappingURL=inline_packed_computation.js.map
@@ -20,6 +20,7 @@ exports.IntfReferencingClasConf = IntfReferencingClasConf;
20
20
  class IntfReferencingClas {
21
21
  constructor() {
22
22
  this.conf = new IntfReferencingClasConf();
23
+ this.allow = [];
23
24
  }
24
25
  getMetadata() {
25
26
  return {
@@ -40,6 +41,7 @@ class IntfReferencingClas {
40
41
  }
41
42
  setConfig(conf) {
42
43
  this.conf = conf;
44
+ this.allow = (this.conf.allow || []).map(reg => new RegExp(reg, "i"));
43
45
  }
44
46
  initialize(reg) {
45
47
  this.reg = reg;
@@ -65,7 +67,7 @@ class IntfReferencingClas {
65
67
  if (found && ddic.isException(found.getClassDefinition(), found)) {
66
68
  continue;
67
69
  }
68
- else if (this.getConfig().allow.some(reg => new RegExp(reg, "i").test(r.extra.ooName))) {
70
+ else if (this.allow.some(reg => reg.test(r.extra.ooName))) {
69
71
  continue;
70
72
  }
71
73
  ret.push(issue_1.Issue.atIdentifier(r.position, message + r.extra.ooName, this.getMetadata().key, this.conf.severity));
@@ -57,7 +57,7 @@ https://docs.abapopenchecks.org/checks/16/`,
57
57
  }
58
58
  }
59
59
  const rows = file.getRawRows();
60
- const reg = new RegExp("^\\)?\\. *(\\\".*)?$");
60
+ const reg = /^\)?\. *(".*)?$/;
61
61
  for (let i = 0; i < rows.length; i++) {
62
62
  if (reg.exec(rows[i].trim())) {
63
63
  const column = rows[i].indexOf(")") >= 0 ? rows[i].indexOf(")") + 1 : rows[i].indexOf(".") + 1;
@@ -23,6 +23,7 @@ class LocalClassNaming extends _abap_rule_1.ABAPRule {
23
23
  constructor() {
24
24
  super(...arguments);
25
25
  this.conf = new LocalClassNamingConf();
26
+ this.regex = this.compile();
26
27
  }
27
28
  getMetadata() {
28
29
  return {
@@ -46,6 +47,15 @@ ENDCLASS.`,
46
47
  }
47
48
  setConfig(conf) {
48
49
  this.conf = conf;
50
+ this.regex = this.compile();
51
+ }
52
+ compile() {
53
+ return {
54
+ local: new RegExp(this.conf.local, "i"),
55
+ exception: new RegExp(this.conf.exception, "i"),
56
+ test: new RegExp(this.conf.test, "i"),
57
+ ignorePatterns: name_validator_1.NameValidator.compileIgnorePatterns(this.conf),
58
+ };
49
59
  }
50
60
  runParsed(file, obj) {
51
61
  const issues = [];
@@ -59,20 +69,23 @@ ENDCLASS.`,
59
69
  }
60
70
  const className = classDef.name;
61
71
  let expected;
72
+ let regex;
62
73
  if (classDef.isForTesting) {
63
74
  expected = this.conf.test;
75
+ regex = this.regex.test;
64
76
  }
65
77
  else if (ddic.isException(classDef, obj)) {
66
78
  expected = this.conf.exception;
79
+ regex = this.regex.exception;
67
80
  }
68
81
  else {
69
82
  expected = this.conf.local;
83
+ regex = this.regex.local;
70
84
  }
71
85
  if (expected === undefined || expected.length === 0) {
72
86
  continue;
73
87
  }
74
- const regex = new RegExp(expected, "i");
75
- if (name_validator_1.NameValidator.violatesRule(className, regex, this.conf)) {
88
+ if (name_validator_1.NameValidator.violatesRule(className, regex, this.conf, this.regex.ignorePatterns)) {
76
89
  issues.push(issue_1.Issue.atIdentifier(classDef.identifier, this.getDescription(expected, className), this.getMetadata().key, this.conf.severity));
77
90
  }
78
91
  }
@@ -58,6 +58,7 @@ class LocalVariableNames extends _abap_rule_1.ABAPRule {
58
58
  constructor() {
59
59
  super(...arguments);
60
60
  this.conf = new LocalVariableNamesConf();
61
+ this.regex = this.compile();
61
62
  }
62
63
  getMetadata() {
63
64
  return {
@@ -85,6 +86,15 @@ ENDFORM.`,
85
86
  }
86
87
  setConfig(conf) {
87
88
  this.conf = conf;
89
+ this.regex = this.compile();
90
+ }
91
+ compile() {
92
+ return {
93
+ expectedData: new RegExp(this.conf.expectedData, "i"),
94
+ expectedConstant: new RegExp(this.conf.expectedConstant, "i"),
95
+ expectedFS: new RegExp(this.conf.expectedFS, "i"),
96
+ ignorePatterns: name_validator_1.NameValidator.compileIgnorePatterns(this.conf),
97
+ };
88
98
  }
89
99
  runParsed(file) {
90
100
  const ret = [];
@@ -118,7 +128,7 @@ ENDFORM.`,
118
128
  const found = dat.findFirstExpression(Expressions.DefinitionName);
119
129
  if (found) {
120
130
  const token = found.getFirstToken();
121
- ret = ret.concat(this.checkName(token, file, this.conf.expectedData));
131
+ ret = ret.concat(this.checkName(token, file, this.conf.expectedData, this.regex.expectedData));
122
132
  }
123
133
  }
124
134
  // inline data
@@ -126,7 +136,7 @@ ENDFORM.`,
126
136
  const found = dat.findFirstExpression(Expressions.TargetField);
127
137
  if (found) {
128
138
  const token = found.getFirstToken();
129
- ret = ret.concat(this.checkName(token, file, this.conf.expectedData));
139
+ ret = ret.concat(this.checkName(token, file, this.conf.expectedData, this.regex.expectedData));
130
140
  }
131
141
  }
132
142
  // data structures, data begin of, first level
@@ -137,14 +147,14 @@ ENDFORM.`,
137
147
  const found = stat === null || stat === void 0 ? void 0 : stat.findFirstExpression(Expressions.DefinitionName);
138
148
  if (found) {
139
149
  const token = found.getFirstToken();
140
- ret = ret.concat(this.checkName(token, file, this.conf.expectedData));
150
+ ret = ret.concat(this.checkName(token, file, this.conf.expectedData, this.regex.expectedData));
141
151
  }
142
152
  }
143
153
  for (const fieldsymbol of structure.findAllStatements(Statements.FieldSymbol)) {
144
154
  const found = fieldsymbol.findFirstExpression(Expressions.FieldSymbol);
145
155
  if (found) {
146
156
  const token = found.getFirstToken();
147
- ret = ret.concat(this.checkName(token, file, this.conf.expectedFS));
157
+ ret = ret.concat(this.checkName(token, file, this.conf.expectedFS, this.regex.expectedFS));
148
158
  }
149
159
  }
150
160
  // inline field symbols
@@ -152,7 +162,7 @@ ENDFORM.`,
152
162
  const found = fieldsymbol.findFirstExpression(Expressions.TargetFieldSymbol);
153
163
  if (found) {
154
164
  const token = found.getFirstToken();
155
- ret = ret.concat(this.checkName(token, file, this.conf.expectedFS));
165
+ ret = ret.concat(this.checkName(token, file, this.conf.expectedFS, this.regex.expectedFS));
156
166
  }
157
167
  }
158
168
  const constants = structure.findAllStatements(Statements.Constant);
@@ -164,16 +174,15 @@ ENDFORM.`,
164
174
  const found = constant.findFirstExpression(Expressions.DefinitionName);
165
175
  if (found) {
166
176
  const token = found.getFirstToken();
167
- ret = ret.concat(this.checkName(token, file, this.conf.expectedConstant));
177
+ ret = ret.concat(this.checkName(token, file, this.conf.expectedConstant, this.regex.expectedConstant));
168
178
  }
169
179
  }
170
180
  return ret;
171
181
  }
172
- checkName(token, file, expected) {
182
+ checkName(token, file, expected, regex) {
173
183
  const ret = [];
174
- const regex = new RegExp(expected, "i");
175
184
  const name = token.getStr();
176
- if (name_validator_1.NameValidator.violatesRule(name, regex, this.conf)) {
185
+ if (name_validator_1.NameValidator.violatesRule(name, regex, this.conf, this.regex.ignorePatterns)) {
177
186
  const message = this.getDescription(expected, name);
178
187
  const issue = issue_1.Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity);
179
188
  ret.push(issue);
@@ -53,6 +53,7 @@ class MacroNaming extends _abap_rule_1.ABAPRule {
53
53
  constructor() {
54
54
  super(...arguments);
55
55
  this.conf = new MacroNamingConf();
56
+ this.regex = new RegExp(this.conf.pattern, "i");
56
57
  }
57
58
  getMetadata() {
58
59
  return {
@@ -72,10 +73,10 @@ END-OF-DEFINITION.`,
72
73
  }
73
74
  setConfig(conf) {
74
75
  this.conf = conf;
76
+ this.regex = new RegExp(this.conf.pattern, "i");
75
77
  }
76
78
  runParsed(file, obj) {
77
79
  const issues = [];
78
- const testRegex = new RegExp(this.conf.pattern, "i");
79
80
  if (obj instanceof objects_1.TypePool) {
80
81
  return [];
81
82
  }
@@ -88,7 +89,7 @@ END-OF-DEFINITION.`,
88
89
  continue;
89
90
  }
90
91
  const token = expr.getFirstToken();
91
- if (testRegex.exec(token.getStr())) {
92
+ if (this.regex.exec(token.getStr())) {
92
93
  continue;
93
94
  }
94
95
  else {
@@ -27,6 +27,7 @@ exports.MethodParameterNamesConf = MethodParameterNamesConf;
27
27
  class MethodParameterNames {
28
28
  constructor() {
29
29
  this.conf = new MethodParameterNamesConf();
30
+ this.regex = this.compile();
30
31
  }
31
32
  getMetadata() {
32
33
  return {
@@ -52,6 +53,16 @@ class MethodParameterNames {
52
53
  }
53
54
  setConfig(conf) {
54
55
  this.conf = conf;
56
+ this.regex = this.compile();
57
+ }
58
+ compile() {
59
+ return {
60
+ importing: new RegExp(this.conf.importing, "i"),
61
+ returning: new RegExp(this.conf.returning, "i"),
62
+ changing: new RegExp(this.conf.changing, "i"),
63
+ exporting: new RegExp(this.conf.exporting, "i"),
64
+ ignorePatterns: name_validator_1.NameValidator.compileIgnorePatterns(this.conf),
65
+ };
55
66
  }
56
67
  initialize(reg) {
57
68
  this.reg = reg;
@@ -91,16 +102,16 @@ class MethodParameterNames {
91
102
  for (const p of method.parameters) {
92
103
  switch (p.direction) {
93
104
  case _abap_file_information_1.MethodParameterDirection.Importing:
94
- ret = ret.concat(this.checkParameter(p, this.conf.importing));
105
+ ret = ret.concat(this.checkParameter(p, this.conf.importing, this.regex.importing));
95
106
  break;
96
107
  case _abap_file_information_1.MethodParameterDirection.Exporting:
97
- ret = ret.concat(this.checkParameter(p, this.conf.exporting));
108
+ ret = ret.concat(this.checkParameter(p, this.conf.exporting, this.regex.exporting));
98
109
  break;
99
110
  case _abap_file_information_1.MethodParameterDirection.Changing:
100
- ret = ret.concat(this.checkParameter(p, this.conf.changing));
111
+ ret = ret.concat(this.checkParameter(p, this.conf.changing, this.regex.changing));
101
112
  break;
102
113
  case _abap_file_information_1.MethodParameterDirection.Returning:
103
- ret = ret.concat(this.checkParameter(p, this.conf.returning));
114
+ ret = ret.concat(this.checkParameter(p, this.conf.returning, this.regex.returning));
104
115
  break;
105
116
  default:
106
117
  break;
@@ -108,11 +119,10 @@ class MethodParameterNames {
108
119
  }
109
120
  return ret;
110
121
  }
111
- checkParameter(param, expected) {
122
+ checkParameter(param, expected, regex) {
112
123
  const ret = [];
113
- const regex = new RegExp(expected, "i");
114
124
  const name = param.name;
115
- if (name_validator_1.NameValidator.violatesRule(name, regex, this.conf)) {
125
+ if (name_validator_1.NameValidator.violatesRule(name, regex, this.conf, this.regex.ignorePatterns)) {
116
126
  const message = this.getDescription(expected, name);
117
127
  const issue = issue_1.Issue.atIdentifier(param.identifier, message, this.getMetadata().key, this.conf.severity);
118
128
  ret.push(issue);
@@ -53,6 +53,7 @@ exports.ModifyOnlyOwnDBTablesConf = ModifyOnlyOwnDBTablesConf;
53
53
  class ModifyOnlyOwnDBTables {
54
54
  constructor() {
55
55
  this.conf = new ModifyOnlyOwnDBTablesConf();
56
+ this.ownTables = new RegExp(this.conf.ownTables, "i");
56
57
  }
57
58
  getMetadata() {
58
59
  return {
@@ -70,6 +71,7 @@ class ModifyOnlyOwnDBTables {
70
71
  }
71
72
  setConfig(conf) {
72
73
  this.conf = conf;
74
+ this.ownTables = new RegExp(this.conf.ownTables, "i");
73
75
  }
74
76
  initialize(reg) {
75
77
  this.reg = reg;
@@ -87,7 +89,6 @@ class ModifyOnlyOwnDBTables {
87
89
  if (struc === undefined) {
88
90
  return [];
89
91
  }
90
- const regExp = new RegExp(this.getConfig().ownTables, "i");
91
92
  for (const s of file.getStatements()) {
92
93
  const g = s.get();
93
94
  if (g instanceof Statements.DeleteDatabase
@@ -105,7 +106,7 @@ class ModifyOnlyOwnDBTables {
105
106
  continue;
106
107
  }
107
108
  const concat = databaseTable.concatTokens().toUpperCase();
108
- if (regExp.test(concat) === false) {
109
+ if (this.ownTables.test(concat) === false) {
109
110
  // must contain a ReferenceType.TableVoidReference or a ReferenceType.TableReference if its a dependency
110
111
  if (spaghetti === undefined) {
111
112
  spaghetti = new syntax_1.SyntaxLogic(this.reg, obj).run().spaghetti;
@@ -7,6 +7,31 @@ const _basic_rule_config_1 = require("./_basic_rule_config");
7
7
  const _irule_1 = require("./_irule");
8
8
  const edit_helper_1 = require("../edit_helper");
9
9
  const tokens_1 = require("../abap/1_lexer/tokens");
10
+ const artifacts_1 = require("../abap/artifacts");
11
+ const combi_1 = require("../abap/2_statements/combi");
12
+ let keywords = undefined;
13
+ /** every word of the statement and expression grammar, upper case */
14
+ function getKeywords() {
15
+ if (keywords === undefined) {
16
+ const list = [];
17
+ for (const stat of artifacts_1.ArtifactsABAP.getStatements()) {
18
+ list.push(...combi_1.Combi.listKeywords(stat.getMatcher()));
19
+ }
20
+ for (const expr of artifacts_1.ArtifactsABAP.getExpressions()) {
21
+ list.push(...combi_1.Combi.listKeywords(new expr().getRunnable()));
22
+ }
23
+ keywords = new Set();
24
+ for (const words of list) {
25
+ // a WordSequence lists eg. "PREFERRED PARAMETER" or "IS-INITIAL" as one entry
26
+ for (const word of words.replace(/-/g, " ").split(" ")) {
27
+ if (word !== "") {
28
+ keywords.add(word.toUpperCase());
29
+ }
30
+ }
31
+ }
32
+ }
33
+ return keywords;
34
+ }
10
35
  class NoExclamationEscapeConf extends _basic_rule_config_1.BasicRuleConfig {
11
36
  }
12
37
  exports.NoExclamationEscapeConf = NoExclamationEscapeConf;
@@ -20,8 +45,10 @@ class NoExclamationEscape extends _abap_rule_1.ABAPRule {
20
45
  key: "no_exclamation_escape",
21
46
  title: "No exclamation escape",
22
47
  shortDescription: `Detects and removes exclamation marks (!) used to escape identifiers`,
23
- // eslint-disable-next-line max-len
24
- extendedInformation: `Exclamation marks are not needed when the identifier is not a reserved keyword, or could be avoided by renaming.`,
48
+ extendedInformation: `Exclamation marks are not needed when the identifier is not a keyword, or could be avoided by renaming.
49
+
50
+ An identifier named like an ABAP keyword is allowed to be escaped, eg. a method parameter "!default",
51
+ which the system otherwise reads as the DEFAULT addition of the parameter before it.`,
25
52
  tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
26
53
  badExample: "methods CONVERT changing !CO_sdf type ref to ZCL_sdf optional.",
27
54
  goodExample: "methods CONVERT changing CO_sdf type ref to ZCL_sdf optional.",
@@ -40,6 +67,9 @@ class NoExclamationEscape extends _abap_rule_1.ABAPRule {
40
67
  const str = token.getStr();
41
68
  if (str.startsWith("!")) {
42
69
  const replacement = str.substring(1);
70
+ if (getKeywords().has(replacement.toUpperCase())) {
71
+ continue;
72
+ }
43
73
  const fix = edit_helper_1.EditHelper.replaceToken(file, token, replacement);
44
74
  issues.push(issue_1.Issue.atToken(file, token, "Do not use exclamation mark to escape identifiers", this.getMetadata().key, this.conf.severity, fix));
45
75
  }
@@ -71,6 +71,7 @@ class NoPrefixes extends _abap_rule_1.ABAPRule {
71
71
  constructor() {
72
72
  super(...arguments);
73
73
  this.conf = new NoPrefixesConf();
74
+ this.regex = this.compile();
74
75
  }
75
76
  getMetadata() {
76
77
  return {
@@ -94,6 +95,18 @@ https://github.com/SAP/styleguides/blob/main/clean-abap/sub-sections/AvoidEncodi
94
95
  }
95
96
  setConfig(conf) {
96
97
  this.conf = conf;
98
+ this.regex = this.compile();
99
+ }
100
+ compile() {
101
+ const compile = (pattern) => pattern !== undefined && pattern !== "" ? new RegExp(pattern, "i") : undefined;
102
+ return {
103
+ data: compile(this.conf.data),
104
+ statics: compile(this.conf.statics),
105
+ fieldSymbols: compile(this.conf.fieldSymbols),
106
+ constants: compile(this.conf.constants),
107
+ types: compile(this.conf.types),
108
+ methodParameters: compile(this.conf.methodParameters),
109
+ };
97
110
  }
98
111
  runParsed(file) {
99
112
  const ret = [];
@@ -107,38 +120,38 @@ https://github.com/SAP/styleguides/blob/main/clean-abap/sub-sections/AvoidEncodi
107
120
  if (max === undefined || max < 1) {
108
121
  max = 10;
109
122
  }
110
- if (config.data !== undefined && config.data !== "") {
111
- ret.push(...this.checkData(structure, new RegExp(config.data, "i"), file));
123
+ if (this.regex.data !== undefined) {
124
+ ret.push(...this.checkData(structure, this.regex.data, file));
112
125
  }
113
126
  if (ret.length >= max) {
114
127
  return ret;
115
128
  }
116
- if (config.statics !== undefined && config.statics !== "") {
117
- ret.push(...this.checkStatics(structure, new RegExp(config.statics, "i"), file));
129
+ if (this.regex.statics !== undefined) {
130
+ ret.push(...this.checkStatics(structure, this.regex.statics, file));
118
131
  }
119
132
  if (ret.length >= max) {
120
133
  return ret;
121
134
  }
122
- if (config.fieldSymbols !== undefined && config.fieldSymbols !== "") {
123
- ret.push(...this.checkFieldSymbols(structure, new RegExp(config.fieldSymbols, "i"), file));
135
+ if (this.regex.fieldSymbols !== undefined) {
136
+ ret.push(...this.checkFieldSymbols(structure, this.regex.fieldSymbols, file));
124
137
  }
125
138
  if (ret.length >= max) {
126
139
  return ret;
127
140
  }
128
- if (config.constants !== undefined && config.constants !== "") {
129
- ret.push(...this.checkConstants(structure, new RegExp(config.constants, "i"), file));
141
+ if (this.regex.constants !== undefined) {
142
+ ret.push(...this.checkConstants(structure, this.regex.constants, file));
130
143
  }
131
144
  if (ret.length >= max) {
132
145
  return ret;
133
146
  }
134
- if (config.types !== undefined && config.types !== "") {
135
- ret.push(...this.checkTypes(structure, new RegExp(config.types, "i"), file));
147
+ if (this.regex.types !== undefined) {
148
+ ret.push(...this.checkTypes(structure, this.regex.types, file));
136
149
  }
137
150
  if (ret.length >= max) {
138
151
  return ret;
139
152
  }
140
- if (config.methodParameters !== undefined && config.methodParameters !== "") {
141
- ret.push(...this.checkMethodParameters(structure, new RegExp(config.methodParameters, "i"), file));
153
+ if (this.regex.methodParameters !== undefined) {
154
+ ret.push(...this.checkMethodParameters(structure, this.regex.methodParameters, file));
142
155
  }
143
156
  return ret;
144
157
  }