@abaplint/core 2.120.74 → 2.120.76

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 (53) hide show
  1. package/build/abaplint.d.ts +5 -1
  2. package/build/src/abap/2_statements/combi.js +143 -51
  3. package/build/src/abap/5_syntax/_builtin.js +8 -0
  4. package/build/src/abap/5_syntax/_loop_table_change.js +126 -0
  5. package/build/src/abap/5_syntax/expressions/_substring.js +83 -0
  6. package/build/src/abap/5_syntax/expressions/attribute_chain.js +3 -16
  7. package/build/src/abap/5_syntax/expressions/compare.js +33 -8
  8. package/build/src/abap/5_syntax/expressions/field_chain.js +5 -14
  9. package/build/src/abap/5_syntax/expressions/method_call_chain.js +16 -1
  10. package/build/src/abap/5_syntax/expressions/method_call_param.js +3 -0
  11. package/build/src/abap/5_syntax/expressions/target.js +14 -2
  12. package/build/src/abap/5_syntax/statements/append.js +6 -0
  13. package/build/src/abap/5_syntax/statements/read_table.js +39 -0
  14. package/build/src/abap/5_syntax/structures/cleanup.js +105 -0
  15. package/build/src/abap/5_syntax/syntax.js +13 -0
  16. package/build/src/ddic.js +1 -1
  17. package/build/src/objects/domain.js +4 -1
  18. package/build/src/registry.js +1 -1
  19. package/build/src/rules/abapdoc_html_tag.js +123 -0
  20. package/build/src/rules/abapdoc_leading_at.js +117 -0
  21. package/build/src/rules/abapdoc_parameter_names.js +149 -0
  22. package/build/src/rules/cds_check_syntax.js +4 -4
  23. package/build/src/rules/change_if_to_case.js +3 -2
  24. package/build/src/rules/changing_sorted_line.js +235 -0
  25. package/build/src/rules/class_attribute_names.js +15 -6
  26. package/build/src/rules/delete_index_in_loop.js +163 -0
  27. package/build/src/rules/final_newline.js +78 -0
  28. package/build/src/rules/forbidden_identifier.js +4 -3
  29. package/build/src/rules/forbidden_void_type.js +4 -9
  30. package/build/src/rules/index.js +11 -0
  31. package/build/src/rules/inline_packed_computation.js +220 -0
  32. package/build/src/rules/intf_referencing_clas.js +3 -1
  33. package/build/src/rules/line_only_punc.js +1 -1
  34. package/build/src/rules/local_class_naming.js +15 -2
  35. package/build/src/rules/local_variable_names.js +18 -9
  36. package/build/src/rules/macro_naming.js +3 -2
  37. package/build/src/rules/method_parameter_names.js +17 -7
  38. package/build/src/rules/modify_only_own_db_tables.js +3 -2
  39. package/build/src/rules/no_prefixes.js +25 -12
  40. package/build/src/rules/object_naming.js +18 -3
  41. package/build/src/rules/prefer_inline_cast.js +276 -0
  42. package/build/src/rules/range_row_values.js +200 -0
  43. package/build/src/rules/redundant_conversion.js +3 -0
  44. package/build/src/rules/selection_screen_naming.js +21 -2
  45. package/build/src/rules/sicf_consistency.js +1 -2
  46. package/build/src/rules/sort_empty_key.js +188 -0
  47. package/build/src/rules/subrc_after_assign.js +220 -0
  48. package/build/src/rules/types_naming.js +3 -2
  49. package/build/src/rules/use_message_class.js +64 -1
  50. package/build/src/rules/wrong_abapdoc_position.js +58 -11
  51. package/build/src/rules/xml_consistency.js +6 -2
  52. package/build/src/utils/name_validator.js +7 -3
  53. package/package.json +1 -1
@@ -63,6 +63,11 @@ class Compare {
63
63
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), initialMessage));
64
64
  return;
65
65
  }
66
+ const predicateMessage = this.checkPredicateOperand(sources, input);
67
+ if (predicateMessage !== undefined) {
68
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), predicateMessage));
69
+ return;
70
+ }
66
71
  const typeUtils = new _type_utils_1.TypeUtils(input.scope);
67
72
  const compareOperator = (_a = node.findDirectExpression(Expressions.CompareOperator)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
68
73
  if (compareOperator === "CS"
@@ -103,6 +108,31 @@ class Compare {
103
108
  if ((chain === null || chain === void 0 ? void 0 : chain.length) === 4 && chain[0] instanceof nodes_1.TokenNode && (first === "XSDBOOL" || first === "BOOLC")) {
104
109
  return `Built-in function "${chain[0].getFirstToken().getStr()}" cannot be the operand of IS INITIAL`;
105
110
  }
111
+ const name = this.builtinCallName(node.findDirectExpression(Expressions.Source), input);
112
+ const returning = (_d = (_c = _builtin_1.BuiltIn.searchBuiltin(name)) === null || _c === void 0 ? void 0 : _c.getParameters().getReturning()) === null || _d === void 0 ? void 0 : _d.getType();
113
+ if (returning instanceof basic_1.StringType || returning instanceof basic_1.CharacterType) {
114
+ return `Built-in function "${name}" cannot be the operand of IS INITIAL`;
115
+ }
116
+ return undefined;
117
+ }
118
+ // a predicate function, contains( ) or line_exists( ), is a relational expression and not a value,
119
+ // it can stand alone as a condition or inside boolc( ) or xsdbool( ), but cannot be an operand of a comparison
120
+ static checkPredicateOperand(sources, input) {
121
+ if (input.scope.getOpenABAP()) {
122
+ return undefined;
123
+ }
124
+ for (const source of sources) {
125
+ const name = this.builtinCallName(source, input);
126
+ if (_builtin_1.BuiltIn.isPredicate(name) === true) {
127
+ return `Predicate function "${name}" cannot be the operand of a comparison`;
128
+ }
129
+ }
130
+ return undefined;
131
+ }
132
+ // the name of the built-in function when the source is exactly one call of it, not hidden by a method of the same name
133
+ static builtinCallName(source, input) {
134
+ var _a;
135
+ const chain = source === null || source === void 0 ? void 0 : source.getChildren();
106
136
  if ((chain === null || chain === void 0 ? void 0 : chain.length) !== 1 || !(chain[0] instanceof nodes_1.ExpressionNode) || !(chain[0].get() instanceof Expressions.MethodCallChain)) {
107
137
  return undefined;
108
138
  }
@@ -110,9 +140,8 @@ class Compare {
110
140
  if (calls.length !== 1 || !(calls[0] instanceof nodes_1.ExpressionNode) || !(calls[0].get() instanceof Expressions.MethodCall)) {
111
141
  return undefined;
112
142
  }
113
- const name = (_c = calls[0].findDirectExpression(Expressions.MethodName)) === null || _c === void 0 ? void 0 : _c.concatTokens();
114
- const builtin = _builtin_1.BuiltIn.searchBuiltin(name);
115
- if (name === undefined || builtin === undefined) {
143
+ const name = (_a = calls[0].findDirectExpression(Expressions.MethodName)) === null || _a === void 0 ? void 0 : _a.concatTokens();
144
+ if (name === undefined || _builtin_1.BuiltIn.searchBuiltin(name) === undefined) {
116
145
  return undefined;
117
146
  }
118
147
  // a method of the same name hides the built-in function
@@ -120,11 +149,7 @@ class Compare {
120
149
  if (enclosing !== undefined && new _object_oriented_1.ObjectOriented(input.scope).searchMethodName(enclosing, name).method !== undefined) {
121
150
  return undefined;
122
151
  }
123
- const returning = (_d = builtin.getParameters().getReturning()) === null || _d === void 0 ? void 0 : _d.getType();
124
- if (returning instanceof basic_1.StringType || returning instanceof basic_1.CharacterType) {
125
- return `Built-in function "${name}" cannot be the operand of IS INITIAL`;
126
- }
127
- return undefined;
152
+ return name;
128
153
  }
129
154
  }
130
155
  exports.Compare = Compare;
@@ -48,6 +48,7 @@ const expressions_1 = require("../../2_statements/expressions");
48
48
  const dereference_1 = require("./dereference");
49
49
  const source_field_symbol_1 = require("./source_field_symbol");
50
50
  const source_field_1 = require("./source_field");
51
+ const _substring_1 = require("./_substring");
51
52
  const _syntax_input_1 = require("../_syntax_input");
52
53
  const version_1 = require("../../../version");
53
54
  class FieldChain {
@@ -160,24 +161,14 @@ class FieldChain {
160
161
  }
161
162
  else if (current.get() instanceof Expressions.FieldOffset && current instanceof nodes_1.ExpressionNode) {
162
163
  const offset = field_offset_1.FieldOffset.runSyntax(current, input);
163
- if (offset) {
164
- if (context instanceof basic_1.CharacterType) {
165
- context = new basic_1.CharacterType(context.getLength() - offset);
166
- }
167
- else if (context instanceof basic_1.HexType) {
168
- context = new basic_1.HexType(context.getLength() - offset);
169
- }
164
+ if (!(0, _substring_1.isFieldSymbolItself)(children, i)) {
165
+ context = (0, _substring_1.substringType)(context, offset, undefined, current, input);
170
166
  }
171
167
  }
172
168
  else if (current.get() instanceof Expressions.FieldLength && current instanceof nodes_1.ExpressionNode) {
173
169
  const length = field_length_1.FieldLength.runSyntax(current, input);
174
- if (length) {
175
- if (context instanceof basic_1.CharacterType) {
176
- context = new basic_1.CharacterType(length);
177
- }
178
- else if (context instanceof basic_1.HexType) {
179
- context = new basic_1.HexType(length);
180
- }
170
+ if (!(0, _substring_1.isFieldSymbolItself)(children, i)) {
171
+ context = (0, _substring_1.substringType)(context, undefined, length, current, input);
181
172
  }
182
173
  }
183
174
  prev = current.concatTokens();
@@ -141,7 +141,12 @@ class MethodCallChain {
141
141
  }
142
142
  const param = current.findDirectExpression(Expressions.MethodCallParam);
143
143
  if (param && method) {
144
- method_call_param_1.MethodCallParam.runSyntax(param, input, method);
144
+ const argumentType = method_call_param_1.MethodCallParam.runSyntax(param, input, method);
145
+ if (method instanceof _builtin_1.BuiltInMethod
146
+ && _builtin_1.BuiltIn.returnsArgumentType(methodName)
147
+ && this.isNumeric(argumentType)) {
148
+ context = argumentType;
149
+ }
145
150
  }
146
151
  else if (param && context instanceof basic_1.VoidType) {
147
152
  method_call_param_1.MethodCallParam.runSyntax(param, input, context);
@@ -158,6 +163,16 @@ class MethodCallChain {
158
163
  return context;
159
164
  }
160
165
  //////////////////////////////////////
166
+ static isNumeric(type) {
167
+ return type instanceof basic_1.IntegerType
168
+ || type instanceof basic_1.Integer8Type
169
+ || type instanceof basic_1.PackedType
170
+ || type instanceof basic_1.FloatType
171
+ || type instanceof basic_1.FloatingPointType
172
+ || type instanceof basic_1.DecFloatType
173
+ || type instanceof basic_1.DecFloat16Type
174
+ || type instanceof basic_1.DecFloat34Type;
175
+ }
161
176
  static findTop(first, input, targetType) {
162
177
  var _a;
163
178
  if (first.get() instanceof Expressions.ClassName) {
@@ -46,6 +46,7 @@ const constant_1 = require("./constant");
46
46
  const _check_offset_length_1 = require("./_check_offset_length");
47
47
  const _check_text_symbol_1 = require("./_check_text_symbol");
48
48
  class MethodCallParam {
49
+ /** returns the type of the unnamed argument, if any */
49
50
  static runSyntax(node, input, method) {
50
51
  if (!(node.get() instanceof Expressions.MethodCallParam)) {
51
52
  const message = "MethodCallParam, unexpected input";
@@ -125,6 +126,7 @@ class MethodCallParam {
125
126
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
126
127
  return;
127
128
  }
129
+ return sourceType;
128
130
  }
129
131
  else if (child instanceof nodes_1.ExpressionNode && child.get() instanceof Expressions.ParameterListS) {
130
132
  new method_parameters_1.MethodParameters().checkExporting(child, input, method);
@@ -137,6 +139,7 @@ class MethodCallParam {
137
139
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
138
140
  return;
139
141
  }
142
+ return undefined;
140
143
  }
141
144
  }
142
145
  exports.MethodCallParam = MethodCallParam;
@@ -47,6 +47,7 @@ const table_expression_1 = require("./table_expression");
47
47
  const expressions_1 = require("../../2_statements/expressions");
48
48
  const field_length_1 = require("./field_length");
49
49
  const cast_1 = require("./cast");
50
+ const _substring_1 = require("./_substring");
50
51
  const _syntax_input_1 = require("../_syntax_input");
51
52
  const version_1 = require("../../../version");
52
53
  class Target {
@@ -154,6 +155,8 @@ class Target {
154
155
  context = attribute_name_1.AttributeName.runSyntax(context, current, input, type);
155
156
  }
156
157
  }
158
+ // the substring is checked, but the type of the whole field is returned
159
+ let substring = context;
157
160
  const offset = node.findDirectExpression(Expressions.FieldOffset);
158
161
  if (offset) {
159
162
  if (context instanceof basic_1.XStringType || context instanceof basic_1.StringType) {
@@ -161,7 +164,10 @@ class Target {
161
164
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
162
165
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
163
166
  }
164
- field_offset_1.FieldOffset.runSyntax(offset, input);
167
+ const value = field_offset_1.FieldOffset.runSyntax(offset, input);
168
+ if (!(0, _substring_1.isFieldSymbolItself)(children, children.indexOf(offset))) {
169
+ substring = (0, _substring_1.substringType)(substring, value, undefined, offset, input);
170
+ }
165
171
  }
166
172
  const length = node.findDirectExpression(Expressions.FieldLength);
167
173
  if (length) {
@@ -170,7 +176,13 @@ class Target {
170
176
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
171
177
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
172
178
  }
173
- field_length_1.FieldLength.runSyntax(length, input);
179
+ const value = field_length_1.FieldLength.runSyntax(length, input);
180
+ if (!(0, _substring_1.isFieldSymbolItself)(children, children.indexOf(length))) {
181
+ substring = (0, _substring_1.substringType)(substring, undefined, value, length, input);
182
+ }
183
+ }
184
+ if (substring instanceof basic_1.VoidType && !(context instanceof basic_1.VoidType)) {
185
+ return substring;
174
186
  }
175
187
  return context;
176
188
  }
@@ -50,6 +50,12 @@ class Append {
50
50
  if (target) {
51
51
  targetType = target_1.Target.runSyntax(target, input);
52
52
  }
53
+ // a hashed table has no index, APPEND adds at the end
54
+ if (targetType instanceof basic_1.TableType && targetType.getAccessType() === basic_1.TableAccessType.hashed) {
55
+ const message = "Implicit or explicit index operation on hashed table is not possible";
56
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
57
+ return;
58
+ }
53
59
  const fsTarget = node.findExpressionAfterToken("ASSIGNING");
54
60
  if (fsTarget && fsTarget.get() instanceof Expressions.FSTarget) {
55
61
  if (!(targetType instanceof basic_1.TableType) && !(targetType instanceof basic_1.VoidType) && !(targetType instanceof basic_1.UnknownType)) {
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ReadTable = void 0;
37
37
  const Expressions = __importStar(require("../../2_statements/expressions"));
38
+ const nodes_1 = require("../../nodes");
38
39
  const basic_1 = require("../../types/basic");
39
40
  const source_1 = require("../expressions/source");
40
41
  const inline_data_1 = require("../expressions/inline_data");
@@ -43,6 +44,9 @@ const fstarget_1 = require("../expressions/fstarget");
43
44
  const component_compare_simple_1 = require("../expressions/component_compare_simple");
44
45
  const _type_utils_1 = require("../_type_utils");
45
46
  const _syntax_input_1 = require("../_syntax_input");
47
+ const _builtin_1 = require("../_builtin");
48
+ const _object_oriented_1 = require("../_object_oriented");
49
+ const version_1 = require("../../../version");
46
50
  class ReadTable {
47
51
  runSyntax(node, input) {
48
52
  const concat = node.concatTokens().toUpperCase();
@@ -69,6 +73,11 @@ class ReadTable {
69
73
  const components = node.findDirectExpression(Expressions.ComponentCompareSimple);
70
74
  if (components !== undefined) {
71
75
  component_compare_simple_1.ComponentCompareSimple.runSyntax(components, input, rowType);
76
+ const keyMessage = this.checkKeyOperands(components, input);
77
+ if (keyMessage !== undefined) {
78
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), keyMessage));
79
+ return;
80
+ }
72
81
  }
73
82
  const indexSource = node.findExpressionAfterToken("INDEX");
74
83
  if (indexSource) {
@@ -164,6 +173,36 @@ class ReadTable {
164
173
  }
165
174
  }
166
175
  }
176
+ // before 7.40 a WITH [TABLE] KEY operand is not an expression position, a built-in function from 7.02 on
177
+ // is read as a functional method call there, "method TO_UPPER is unknown" on a system, while
178
+ // functional methods and the older built-in functions like lines( ) are accepted
179
+ checkKeyOperands(node, input) {
180
+ var _a, _b;
181
+ if (input.scope.getOpenABAP() || (0, version_1.releaseAtLeast)(input.scope.getRelease(), version_1.Release.v740sp02)) {
182
+ return undefined;
183
+ }
184
+ for (const operand of node.findDirectExpressionsMulti([Expressions.Source, Expressions.SimpleSource4])) {
185
+ const chain = operand.getChildren();
186
+ if (chain.length !== 1 || !(chain[0] instanceof nodes_1.ExpressionNode) || !(chain[0].get() instanceof Expressions.MethodCallChain)) {
187
+ continue;
188
+ }
189
+ const calls = chain[0].getChildren();
190
+ if (calls.length !== 1 || !(calls[0] instanceof nodes_1.ExpressionNode) || !(calls[0].get() instanceof Expressions.MethodCall)) {
191
+ continue;
192
+ }
193
+ const name = (_a = calls[0].findDirectExpression(Expressions.MethodName)) === null || _a === void 0 ? void 0 : _a.concatTokens();
194
+ if (name === undefined || ((_b = _builtin_1.BuiltIn.methods[name.toUpperCase()]) === null || _b === void 0 ? void 0 : _b.release) === undefined) {
195
+ continue;
196
+ }
197
+ // a method of the same name hides the built-in function
198
+ const enclosing = input.scope.findClassDefinition(input.scope.getEnclosingClassName());
199
+ if (enclosing !== undefined && new _object_oriented_1.ObjectOriented(input.scope).searchMethodName(enclosing, name).method !== undefined) {
200
+ continue;
201
+ }
202
+ return `Built-in function "${name}" cannot be a READ TABLE key operand before 7.40`;
203
+ }
204
+ return undefined;
205
+ }
167
206
  }
168
207
  exports.ReadTable = ReadTable;
169
208
  //# sourceMappingURL=read_table.js.map
@@ -0,0 +1,105 @@
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.Cleanup = void 0;
37
+ const Statements = __importStar(require("../../2_statements/statements"));
38
+ const Structures = __importStar(require("../../3_structures/structures"));
39
+ const nodes_1 = require("../../nodes");
40
+ const _syntax_input_1 = require("../_syntax_input");
41
+ const LOOPS = [
42
+ Structures.Loop,
43
+ Structures.LoopAtScreen,
44
+ Structures.LoopExtract,
45
+ Structures.Do,
46
+ Structures.While,
47
+ Structures.Select,
48
+ Structures.With,
49
+ Structures.Provide,
50
+ ];
51
+ // a CLEANUP block cannot contain statements that statically leave it: RETURN, and EXIT, CONTINUE or CHECK
52
+ // that do not belong to a loop inside the block, these end a loop outside the TRY or the processing block
53
+ class Cleanup {
54
+ static runSyntax(node, input) {
55
+ if (input.scope.getOpenABAP()) {
56
+ return;
57
+ }
58
+ const body = node.findDirectStructure(Structures.Body);
59
+ if (body !== undefined) {
60
+ this.walk(body, false, input);
61
+ }
62
+ }
63
+ static walk(node, inLoop, input) {
64
+ for (const child of node.getChildren()) {
65
+ if (child instanceof nodes_1.StructureNode) {
66
+ const stru = child.get();
67
+ // a nested CLEANUP block is checked on its own, macro definitions and test injections do not run here
68
+ if (stru instanceof Structures.Cleanup
69
+ || stru instanceof Structures.Define
70
+ || stru instanceof Structures.TestInjection) {
71
+ continue;
72
+ }
73
+ this.walk(child, inLoop || LOOPS.some(l => stru instanceof l), input);
74
+ }
75
+ else if (child instanceof nodes_1.StatementNode) {
76
+ const name = this.leavingStatement(child, inLoop);
77
+ if (name !== undefined) {
78
+ const message = `${name} cannot leave a CLEANUP block`;
79
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, child.getFirstToken(), message));
80
+ }
81
+ }
82
+ }
83
+ }
84
+ static leavingStatement(node, inLoop) {
85
+ const s = node.get();
86
+ if (s instanceof Statements.Return) {
87
+ return "RETURN";
88
+ }
89
+ else if (inLoop === true) {
90
+ return undefined;
91
+ }
92
+ else if (s instanceof Statements.Exit && node.findDirectTokenByText("FROM") === undefined) {
93
+ return "EXIT";
94
+ }
95
+ else if (s instanceof Statements.Continue) {
96
+ return "CONTINUE";
97
+ }
98
+ else if (s instanceof Statements.Check) {
99
+ return "CHECK";
100
+ }
101
+ return undefined;
102
+ }
103
+ }
104
+ exports.Cleanup = Cleanup;
105
+ //# sourceMappingURL=cleanup.js.map
@@ -50,6 +50,7 @@ const type_mesh_1 = require("./structures/type_mesh");
50
50
  const types_1 = require("./structures/types");
51
51
  const statics_1 = require("./structures/statics");
52
52
  const constants_1 = require("./structures/constants");
53
+ const cleanup_1 = require("./structures/cleanup");
53
54
  const class_definition_1 = require("../types/class_definition");
54
55
  const interface_definition_1 = require("../types/interface_definition");
55
56
  const delete_memory_1 = require("./statements/delete_memory");
@@ -191,6 +192,7 @@ const _syntax_input_1 = require("./_syntax_input");
191
192
  const assert_error_1 = require("./assert_error");
192
193
  const field_group_1 = require("./statements/field_group");
193
194
  const stuff_1 = require("../../stuff");
195
+ const _loop_table_change_1 = require("./_loop_table_change");
194
196
  // -----------------------------------
195
197
  const map = {};
196
198
  function addToMap(handler) {
@@ -352,6 +354,7 @@ class SyntaxLogic {
352
354
  };
353
355
  this.issues = [];
354
356
  this.deferred = [];
357
+ this.loopTables = new _loop_table_change_1.LoopTableChange();
355
358
  this.reg.getDDICReferences().clear(this.object);
356
359
  this.reg.getMSAGReferences().clear(this.object);
357
360
  if (this.object instanceof objects_1.Program && this.object.isInclude()) {
@@ -417,6 +420,9 @@ class SyntaxLogic {
417
420
  this.issues.push(issue);
418
421
  }
419
422
  traverse(node) {
423
+ const loop = node instanceof nodes_1.StructureNode
424
+ && node.get() instanceof Structures.Loop
425
+ && this.loopTables.push(node, this.scope);
420
426
  for (const child of node.getChildren()) {
421
427
  const isStructure = child instanceof nodes_1.StructureNode;
422
428
  const isStatement = child instanceof nodes_1.StatementNode;
@@ -449,6 +455,9 @@ class SyntaxLogic {
449
455
  this.traverse(child);
450
456
  }
451
457
  }
458
+ if (loop === true) {
459
+ this.loopTables.pop();
460
+ }
452
461
  }
453
462
  /**
454
463
  * if this returns true, then the traversal should continue with next child
@@ -505,6 +514,9 @@ class SyntaxLogic {
505
514
  // todo: skipped for now
506
515
  return true;
507
516
  }
517
+ else if (stru instanceof Structures.Cleanup) {
518
+ cleanup_1.Cleanup.runSyntax(node, input);
519
+ }
508
520
  return false;
509
521
  }
510
522
  updateScopeStatement(node) {
@@ -534,6 +546,7 @@ class SyntaxLogic {
534
546
  this.scope.addIdentifier(new data_2.Data().runSyntax(node, input));
535
547
  return;
536
548
  }
549
+ this.loopTables.check(node, input);
537
550
  const name = s.constructor.name;
538
551
  if (map[name]) {
539
552
  map[name].runSyntax(node, input);
package/build/src/ddic.js CHANGED
@@ -256,7 +256,7 @@ class DDIC {
256
256
  lookupDomain(name, dataElement, description) {
257
257
  const found = this.reg.getObject("DOMA", name);
258
258
  if (found) {
259
- return { type: found.parseType(this.reg, dataElement, description), object: found };
259
+ return { type: found.parseDomainType(this.reg, dataElement, description), object: found };
260
260
  }
261
261
  else if (this.reg.inErrorNamespace(name)) {
262
262
  return { type: new Types.UnknownType(name + ", lookupDomain"), object: undefined };
@@ -81,7 +81,10 @@ class Domain extends _abstract_object_1.AbstractObject {
81
81
  this.parsedXML = undefined;
82
82
  super.setDirty();
83
83
  }
84
- parseType(reg, dataElement, description) {
84
+ parseType(reg) {
85
+ return this.parseDomainType(reg);
86
+ }
87
+ parseDomainType(reg, dataElement, description) {
85
88
  // dont cache the DOMA parsed type, they are cached on DTEL level
86
89
  // also note that the type carries the name of the DTEL
87
90
  if (this.parsedXML === undefined) {
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.74";
78
+ return "2.120.76";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -0,0 +1,123 @@
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.AbapdocHtmlTag = exports.AbapdocHtmlTagConf = void 0;
37
+ const Statements = __importStar(require("../abap/2_statements/statements"));
38
+ const issue_1 = require("../issue");
39
+ const _abap_rule_1 = require("./_abap_rule");
40
+ const _basic_rule_config_1 = require("./_basic_rule_config");
41
+ const _irule_1 = require("./_irule");
42
+ const _statement_1 = require("../abap/2_statements/statements/_statement");
43
+ const position_1 = require("../position");
44
+ class AbapdocHtmlTagConf extends _basic_rule_config_1.BasicRuleConfig {
45
+ }
46
+ exports.AbapdocHtmlTagConf = AbapdocHtmlTagConf;
47
+ const ALLOWED = new Set(["p", "em", "strong", "ul", "ol", "li", "br", "h1", "h2", "h3"]);
48
+ class AbapdocHtmlTag extends _abap_rule_1.ABAPRule {
49
+ constructor() {
50
+ super(...arguments);
51
+ this.conf = new AbapdocHtmlTagConf();
52
+ }
53
+ getMetadata() {
54
+ return {
55
+ key: "abapdoc_html_tag",
56
+ title: "Unsupported HTML tag in ABAP Doc",
57
+ shortDescription: `Reports tag-like tokens in ABAP Doc which are not ABAP Doc HTML tags.`,
58
+ extendedInformation: `ABAP Doc is parsed as HTML, a field symbol or a placeholder written as <name> is an
59
+ unsupported and unclosed tag, the system warns and the rendered documentation drops the word.
60
+
61
+ Supported tags are p, em, strong, ul, ol, li, br, h1, h2 and h3, also as closing tags and with attributes.
62
+
63
+ Write &lt;name&gt; to show the angle brackets. A "<" which is not followed by a letter, like "a < b", is not reported.
64
+
65
+ Only checks ABAP Doc inside class definitions and interfaces.`,
66
+ tags: [_irule_1.RuleTag.SingleFile],
67
+ badExample: `INTERFACE zif_foo PUBLIC.
68
+ "! Returns the <name> of the selected row
69
+ METHODS name RETURNING VALUE(result) TYPE string.
70
+ ENDINTERFACE.`,
71
+ goodExample: `INTERFACE zif_foo PUBLIC.
72
+ "! Returns the &lt;name&gt; of the selected row
73
+ METHODS name RETURNING VALUE(result) TYPE string.
74
+ ENDINTERFACE.`,
75
+ };
76
+ }
77
+ getConfig() {
78
+ return this.conf;
79
+ }
80
+ setConfig(conf) {
81
+ this.conf = conf;
82
+ }
83
+ runParsed(file) {
84
+ const issues = [];
85
+ let definition = false;
86
+ for (const statement of file.getStatements()) {
87
+ const type = statement.get();
88
+ if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
89
+ definition = true;
90
+ continue;
91
+ }
92
+ else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
93
+ definition = false;
94
+ continue;
95
+ }
96
+ else if (definition === false || !(type instanceof _statement_1.Comment)) {
97
+ continue;
98
+ }
99
+ const token = statement.getFirstToken();
100
+ const str = token.getStr();
101
+ if (str.startsWith(`"!`) === false) {
102
+ continue;
103
+ }
104
+ const regex = /<\/?([a-zA-Z][\w-]*)(\s[^<>]*)?\/?>/g;
105
+ let match;
106
+ while ((match = regex.exec(str)) !== null) {
107
+ const name = match[1];
108
+ if (ALLOWED.has(name.toLowerCase())) {
109
+ continue;
110
+ }
111
+ const row = token.getStart().getRow();
112
+ const col = token.getStart().getCol() + match.index;
113
+ const start = new position_1.Position(row, col);
114
+ const end = new position_1.Position(row, col + match[0].length);
115
+ const message = `HTML tag <${name}> is not supported in ABAP Doc, write &lt;${name}&gt;`;
116
+ issues.push(issue_1.Issue.atRange(file, start, end, message, this.getMetadata().key, this.conf.severity));
117
+ }
118
+ }
119
+ return issues;
120
+ }
121
+ }
122
+ exports.AbapdocHtmlTag = AbapdocHtmlTag;
123
+ //# sourceMappingURL=abapdoc_html_tag.js.map