@abaplint/core 2.120.70 → 2.120.72

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 (47) hide show
  1. package/build/abaplint.d.ts +10 -0
  2. package/build/src/abap/1_lexer/lexer.js +1 -1
  3. package/build/src/abap/1_lexer/lexer_stream.js +8 -0
  4. package/build/src/abap/2_statements/expressions/string_template_formatting.js +1 -1
  5. package/build/src/abap/3_structures/structures/_combi.js +61 -112
  6. package/build/src/abap/5_syntax/basic_types.js +4 -4
  7. package/build/src/abap/5_syntax/expressions/_check_database_work_area.js +127 -0
  8. package/build/src/abap/5_syntax/expressions/attribute_name.js +1 -1
  9. package/build/src/abap/5_syntax/expressions/compare.js +48 -0
  10. package/build/src/abap/5_syntax/expressions/conv_body.js +2 -2
  11. package/build/src/abap/5_syntax/expressions/field_chain.js +1 -1
  12. package/build/src/abap/5_syntax/expressions/form_param.js +1 -1
  13. package/build/src/abap/5_syntax/expressions/method_parameters.js +2 -2
  14. package/build/src/abap/5_syntax/expressions/select.js +1 -2
  15. package/build/src/abap/5_syntax/expressions/source.js +19 -3
  16. package/build/src/abap/5_syntax/statements/assign.js +15 -1
  17. package/build/src/abap/5_syntax/statements/insert_database.js +6 -3
  18. package/build/src/abap/5_syntax/statements/loop.js +1 -1
  19. package/build/src/abap/5_syntax/statements/modify_database.js +8 -4
  20. package/build/src/abap/5_syntax/statements/update_database.js +7 -3
  21. package/build/src/abap/5_syntax/statements/when_type.js +1 -1
  22. package/build/src/abap/types/class_attributes.js +1 -1
  23. package/build/src/cds/cds_lexer.js +1 -1
  24. package/build/src/lsp/help.js +2 -2
  25. package/build/src/objects/data_element.js +1 -1
  26. package/build/src/objects/table.js +1 -0
  27. package/build/src/registry.js +1 -1
  28. package/build/src/rules/align_pseudo_comments.js +1 -1
  29. package/build/src/rules/align_type_expressions.js +1 -1
  30. package/build/src/rules/cds_check_syntax.js +1 -1
  31. package/build/src/rules/change_if_to_case.js +1 -1
  32. package/build/src/rules/check_ddic.js +1 -1
  33. package/build/src/rules/class_attribute_names.js +1 -3
  34. package/build/src/rules/downport.js +122 -24
  35. package/build/src/rules/empty_structure.js +26 -0
  36. package/build/src/rules/functional_writing.js +1 -1
  37. package/build/src/rules/keyword_case.js +1 -1
  38. package/build/src/rules/local_class_naming.js +1 -1
  39. package/build/src/rules/many_parentheses.js +1 -1
  40. package/build/src/rules/obsolete_statement.js +3 -7
  41. package/build/src/rules/parser_missing_space.js +1 -2
  42. package/build/src/rules/prefer_raise_exception_new.js +2 -8
  43. package/build/src/rules/redundant_conversion.js +59 -2
  44. package/build/src/rules/xml_consistency.js +25 -1
  45. package/build/src/utils/form_length_stats.js +1 -1
  46. package/build/src/utils/method_length_stats.js +1 -1
  47. package/package.json +1 -1
@@ -61,6 +61,7 @@ const _typed_identifier_1 = require("../../types/_typed_identifier");
61
61
  const _type_utils_1 = require("../_type_utils");
62
62
  const _syntax_input_1 = require("../_syntax_input");
63
63
  const assert_error_1 = require("../assert_error");
64
+ const version_1 = require("../../../version");
64
65
  /*
65
66
  * Type interference, valid scenarios:
66
67
  * typed = VALUE #( ... ). right hand side must follow left hand type
@@ -73,7 +74,7 @@ const assert_error_1 = require("../assert_error");
73
74
  // TODO: refactor all these method parameters to objects, this is getting messy
74
75
  class Source {
75
76
  static runSyntax(node, input, targetType, writeReference = false, allowGenericDeference = false, readReference = true) {
76
- var _a;
77
+ var _a, _b, _c, _d;
77
78
  if (node === undefined) {
78
79
  return undefined;
79
80
  }
@@ -151,7 +152,7 @@ class Source {
151
152
  case "CONV":
152
153
  {
153
154
  const foundType = this.determineType(node, input, targetType);
154
- const bodyType = conv_body_1.ConvBody.runSyntax(node.findDirectExpression(Expressions.ConvBody), input);
155
+ const bodyType = conv_body_1.ConvBody.runSyntax(node.findDirectExpression(Expressions.ConvBody), input, foundType);
155
156
  const inferred = (_a = node.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _a === void 0 ? void 0 : _a.concatTokens();
156
157
  if (new _type_utils_1.TypeUtils(input.scope).isConvable(foundType, bodyType) === false) {
157
158
  const message = `CONV: Types not compatible, ${foundType === null || foundType === void 0 ? void 0 : foundType.constructor.name}, ${bodyType === null || bodyType === void 0 ? void 0 : bodyType.constructor.name}`;
@@ -168,7 +169,13 @@ class Source {
168
169
  this.traverseRemainingChildren(children, input);
169
170
  return bodyType;
170
171
  }
171
- this.addIfInferred(node, input, foundType);
172
+ const bodySource = (_b = node.findDirectExpression(Expressions.ConvBody)) === null || _b === void 0 ? void 0 : _b.findDirectExpression(Expressions.Source);
173
+ const nestedType = (_c = bodySource === null || bodySource === void 0 ? void 0 : bodySource.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _c === void 0 ? void 0 : _c.concatTokens();
174
+ // CONV # passes its target type into a nested inferred constructor, so
175
+ // showing both inferred types would produce duplicate inlay hints.
176
+ if (!(inferred === "#" && nestedType === "#")) {
177
+ this.addIfInferred(node, input, foundType);
178
+ }
172
179
  this.traverseRemainingChildren(children, input);
173
180
  return foundType;
174
181
  }
@@ -225,6 +232,15 @@ class Source {
225
232
  case "CORRESPONDING":
226
233
  {
227
234
  const foundType = this.determineType(node, input, targetType);
235
+ if ((foundType === null || foundType === void 0 ? void 0 : foundType.isGeneric()) === true
236
+ && ((_d = node.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _d === void 0 ? void 0 : _d.concatTokens()) === "#"
237
+ && !(0, version_1.releaseAtLeast)(input.scope.getRelease(), version_1.Release.v756)
238
+ && input.scope.getLanguageVersion() !== version_1.LanguageVersion.Cloud
239
+ && !input.scope.getOpenABAP()) {
240
+ const message = "CORRESPONDING #, the type of the target is generic";
241
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
242
+ return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
243
+ }
228
244
  corresponding_body_1.CorrespondingBody.runSyntax(node.findDirectExpression(Expressions.CorrespondingBody), input, foundType);
229
245
  this.addIfInferred(node, input, foundType);
230
246
  return foundType;
@@ -41,6 +41,7 @@ const basic_1 = require("../../types/basic");
41
41
  const dynamic_1 = require("../expressions/dynamic");
42
42
  const _type_utils_1 = require("../_type_utils");
43
43
  const _syntax_input_1 = require("../_syntax_input");
44
+ const version_1 = require("../../../version");
44
45
  class Assign {
45
46
  runSyntax(node, input) {
46
47
  var _a;
@@ -48,7 +49,7 @@ class Assign {
48
49
  const isComponent = ((_a = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getFirstChild()) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase()) === "COMPONENT";
49
50
  const sources = (assignSource === null || assignSource === void 0 ? void 0 : assignSource.findDirectExpressionsMulti([Expressions.Source, Expressions.SimpleSource3])) || [];
50
51
  const theSource = sources[sources.length - 1];
51
- let sourceType = undefined;
52
+ let sourceType;
52
53
  const firstAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[0];
53
54
  const secondAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[1];
54
55
  const thirdAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[2];
@@ -64,6 +65,19 @@ class Assign {
64
65
  }
65
66
  else {
66
67
  sourceType = source_1.Source.runSyntax(theSource, input, undefined, false, isComponent === false);
68
+ if ((secondAssign === null || secondAssign === void 0 ? void 0 : secondAssign.concatTokens()) === "->"
69
+ && (thirdAssign === null || thirdAssign === void 0 ? void 0 : thirdAssign.get()) instanceof Expressions.Dynamic
70
+ && (sourceType === null || sourceType === void 0 ? void 0 : sourceType.isGeneric()) === true
71
+ && !(sourceType instanceof basic_1.DataReference)
72
+ && !(sourceType instanceof basic_1.ObjectReferenceType)
73
+ && !(sourceType instanceof basic_1.GenericObjectReferenceType)
74
+ && !(0, version_1.releaseAtLeast)(input.scope.getRelease(), version_1.Release.v756)
75
+ && input.scope.getLanguageVersion() !== version_1.LanguageVersion.Cloud
76
+ && !input.scope.getOpenABAP()) {
77
+ const message = `"${theSource.concatTokens()}" is not a reference variable`;
78
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
79
+ return;
80
+ }
67
81
  }
68
82
  if ((assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren().length) === 5
69
83
  && isComponent) {
@@ -38,20 +38,23 @@ const Expressions = __importStar(require("../../2_statements/expressions"));
38
38
  const source_1 = require("../expressions/source");
39
39
  const dynamic_1 = require("../expressions/dynamic");
40
40
  const database_table_1 = require("../expressions/database_table");
41
+ const _check_database_work_area_1 = require("../expressions/_check_database_work_area");
41
42
  class InsertDatabase {
42
43
  runSyntax(node, input) {
44
+ const sourceTypes = new Map();
43
45
  for (const s of node.findAllExpressions(Expressions.Source)) {
44
- source_1.Source.runSyntax(s, input);
46
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
45
47
  }
46
48
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
47
- source_1.Source.runSyntax(s, input);
49
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
48
50
  }
49
51
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
50
52
  dynamic_1.Dynamic.runSyntax(d, input);
51
53
  }
52
54
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
53
55
  if (dbtab !== undefined) {
54
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
56
+ const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
57
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
55
58
  }
56
59
  }
57
60
  }
@@ -130,7 +130,7 @@ class Loop {
130
130
  && topType instanceof basic_1.TableType) {
131
131
  // https://github.com/abap2xlsx/abap2xlsx/issues/1341
132
132
  const keyName = node.findExpressionAfterToken("KEY");
133
- let key = undefined;
133
+ let key;
134
134
  const name = (keyName === null || keyName === void 0 ? void 0 : keyName.get()) instanceof Expressions.SimpleName ? keyName.getFirstToken().getStr().toUpperCase() : undefined;
135
135
  // it might be dynamic, in that case we cannot check anything; and
136
136
  // primary_key is the predefined name of the primary key every table has
@@ -39,11 +39,13 @@ const dynamic_1 = require("../expressions/dynamic");
39
39
  const database_table_1 = require("../expressions/database_table");
40
40
  const source_1 = require("../expressions/source");
41
41
  const _reference_1 = require("../_reference");
42
+ const _check_database_work_area_1 = require("../expressions/_check_database_work_area");
42
43
  class ModifyDatabase {
43
44
  runSyntax(node, input) {
44
45
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
45
46
  dynamic_1.Dynamic.runSyntax(d, input);
46
47
  }
48
+ let dbSource = undefined;
47
49
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
48
50
  if (dbtab !== undefined) {
49
51
  if (node.getChildren().length === 5) {
@@ -52,19 +54,21 @@ class ModifyDatabase {
52
54
  input.scope.addReference(dbtab.getFirstToken(), found, _reference_1.ReferenceType.DataWriteReference, input.filename);
53
55
  }
54
56
  else {
55
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
57
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
56
58
  }
57
59
  }
58
60
  else {
59
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
61
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
60
62
  }
61
63
  }
64
+ const sourceTypes = new Map();
62
65
  for (const s of node.findAllExpressions(Expressions.Source)) {
63
- source_1.Source.runSyntax(s, input);
66
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
64
67
  }
65
68
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
66
- source_1.Source.runSyntax(s, input);
69
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
67
70
  }
71
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
68
72
  }
69
73
  }
70
74
  exports.ModifyDatabase = ModifyDatabase;
@@ -43,11 +43,13 @@ const identifier_1 = require("../../1_lexer/tokens/identifier");
43
43
  const database_table_1 = require("../expressions/database_table");
44
44
  const dynamic_1 = require("../expressions/dynamic");
45
45
  const _check_database_fields_1 = require("../expressions/_check_database_fields");
46
+ const _check_database_work_area_1 = require("../expressions/_check_database_work_area");
46
47
  class UpdateDatabase {
47
48
  runSyntax(node, input) {
49
+ let dbSource = undefined;
48
50
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
49
51
  if (dbtab !== undefined) {
50
- const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
52
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
51
53
  const fields = node.findAllExpressions(Expressions.SQLFieldAndValue)
52
54
  .flatMap(fieldAndValue => fieldAndValue.findDirectExpressions(Expressions.SQLFieldName))
53
55
  .map(field => field.concatTokens().toUpperCase());
@@ -70,15 +72,17 @@ class UpdateDatabase {
70
72
  }
71
73
  }
72
74
  }
75
+ const sourceTypes = new Map();
73
76
  for (const s of node.findAllExpressions(Expressions.Source)) {
74
- source_1.Source.runSyntax(s, input);
77
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
75
78
  }
76
79
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
77
- source_1.Source.runSyntax(s, input);
80
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
78
81
  }
79
82
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
80
83
  dynamic_1.Dynamic.runSyntax(d, input);
81
84
  }
85
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
82
86
  if (input.scope.getType() === _scope_type_1.ScopeType.OpenSQL) {
83
87
  input.scope.pop(node.getLastToken().getEnd());
84
88
  }
@@ -47,7 +47,7 @@ class WhenType {
47
47
  if (nameToken === undefined) {
48
48
  return undefined;
49
49
  }
50
- let type = undefined;
50
+ let type;
51
51
  const className = nameToken.getStr().toUpperCase();
52
52
  const found = input.scope.existsObject(className);
53
53
  if (found === null || found === void 0 ? void 0 : found.id) {
@@ -318,7 +318,7 @@ class Attributes {
318
318
  return false;
319
319
  }
320
320
  parseAttribute(node, visibility, input) {
321
- let found = undefined;
321
+ let found;
322
322
  const s = node.get();
323
323
  if (s instanceof Statements.Data) {
324
324
  found = new data_1.Data().runSyntax(node, input);
@@ -188,7 +188,7 @@ class CDSLexer {
188
188
  break;
189
189
  case "@":
190
190
  // @ starts a new annotation; flush current token and start building with @
191
- build = result.add(build, row, col, mode);
191
+ result.add(build, row, col, mode);
192
192
  build = "@";
193
193
  break;
194
194
  default:
@@ -50,7 +50,7 @@ class Help {
50
50
  return content;
51
51
  }
52
52
  static dumpABAP(file, reg, textDocument, position) {
53
- let content = "";
53
+ let content;
54
54
  content = `
55
55
  <a href="#_tokens" rel="no-refresh">Tokens</a> |
56
56
  <a href="#_statements" rel="no-refresh">Statements</a> |
@@ -83,7 +83,7 @@ class Help {
83
83
  return `<h3 id="_info">Info Dump</h3><pre>` + text + "</pre>";
84
84
  }
85
85
  static cursorInformation(reg, textDocument, position, file) {
86
- let ret = "";
86
+ let ret;
87
87
  const found = _lsp_utils_1.LSPUtils.findCursor(reg, { textDocument, position });
88
88
  if (found !== undefined) {
89
89
  ret = "Statement: " + this.linkToStatement(found.snode.get()) + "<br>\n" +
@@ -121,7 +121,7 @@ class DataElement extends _abstract_object_1.AbstractObject {
121
121
  }
122
122
  parseType(reg) {
123
123
  const references = [];
124
- let lookup = undefined;
124
+ let lookup;
125
125
  this.parse();
126
126
  if (this.parsedXML === undefined) {
127
127
  lookup = { type: new Types.UnknownType("Data Element " + this.getName() + ", parser error") };
@@ -392,6 +392,7 @@ class Table extends _abstract_object_1.AbstractObject {
392
392
  PRECFIELD: field.PRECFIELD,
393
393
  LENG: field.LENG,
394
394
  INTLEN: field.INTLEN,
395
+ INTTYPE: field.INTTYPE,
395
396
  DATATYPE: field.DATATYPE,
396
397
  DECIMALS: field.DECIMALS,
397
398
  KEYFLAG: field.KEYFLAG,
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.70";
78
+ return "2.120.72";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -54,7 +54,7 @@ class AlignPseudoComments extends _abap_rule_1.ABAPRule {
54
54
  }
55
55
  const col = firstCommentToken.getStart().getCol();
56
56
  if (previousEnd.getCol() < expectedColumn && col !== expectedColumn) {
57
- let fix = undefined;
57
+ let fix;
58
58
  if (col < expectedColumn) {
59
59
  fix = edit_helper_1.EditHelper.insertAt(file, firstCommentToken.getStart(), " ".repeat(expectedColumn - col));
60
60
  }
@@ -138,7 +138,7 @@ ENDINTERFACE.`,
138
138
  if (f.after.getCol() === column) {
139
139
  continue;
140
140
  }
141
- let fix = undefined;
141
+ let fix;
142
142
  if (f.after.getCol() < column) {
143
143
  fix = edit_helper_1.EditHelper.insertAt(file, f.after, " ".repeat(column - f.after.getCol()));
144
144
  }
@@ -15,7 +15,7 @@ exports.CDSCheckSyntaxConf = CDSCheckSyntaxConf;
15
15
  const KNOWN_QUAN_DATA_ELEMENTS = ["MENGE_D"];
16
16
  const KNOWN_CURR_DATA_ELEMENTS = ["BWERT", "DZWERT"];
17
17
  // Reserved names, cannot be used as element names, see DDIC table TRESE
18
- const RESERVED_ELEMENT_NAMES = ["BEGIN", "NUMBER", "POSITION"];
18
+ const RESERVED_ELEMENT_NAMES = ["BEGIN", "NUMBER", "POSITION", "ZONE", "HANDLER", "SECTION"];
19
19
  const MAX_LABEL_LENGTH = 40;
20
20
  // Annotations which are not supported in CDS view entities
21
21
  const VIEW_ENTITY_FORBIDDEN_ANNOTATIONS = ["Semantics.unitOfMeasure", "Semantics.currencyCode"];
@@ -142,7 +142,7 @@ ENDCASE.`,
142
142
  if (tuples.length === 1) {
143
143
  return false;
144
144
  }
145
- let chain = "";
145
+ let chain;
146
146
  if (tuples[0].left === tuples[1].left) {
147
147
  chain = tuples[0].left;
148
148
  }
@@ -68,7 +68,7 @@ class CheckDDIC {
68
68
  this.conf = conf;
69
69
  }
70
70
  run(obj) {
71
- let found = undefined;
71
+ let found;
72
72
  if (obj instanceof Objects.DataElement
73
73
  || obj instanceof Objects.Domain
74
74
  || obj instanceof Objects.Table
@@ -59,7 +59,6 @@ ENDCLASS.`,
59
59
  this.conf = conf;
60
60
  }
61
61
  runParsed(file, obj) {
62
- let issues = [];
63
62
  if (this.conf.patternKind === undefined) {
64
63
  this.conf.patternKind = "required";
65
64
  }
@@ -80,8 +79,7 @@ ENDCLASS.`,
80
79
  attributes = attributes.concat(intfDef.attributes);
81
80
  }
82
81
  }
83
- issues = this.checkAttributes(attributes);
84
- return issues;
82
+ return this.checkAttributes(attributes);
85
83
  }
86
84
  checkAttributes(attr) {
87
85
  if (attr === undefined) {