@abaplint/transpiler-cli 2.13.59 → 2.13.61

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/bundle.js CHANGED
@@ -4229,10 +4229,10 @@ exports.ClassName = ClassName;
4229
4229
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4230
4230
  exports.Color = void 0;
4231
4231
  const combi_1 = __webpack_require__(/*! ../combi */ "./node_modules/@abaplint/core/build/src/abap/2_statements/combi.js");
4232
- const source_1 = __webpack_require__(/*! ./source */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/source.js");
4232
+ const simple_source3_1 = __webpack_require__(/*! ./simple_source3 */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/simple_source3.js");
4233
4233
  class Color extends combi_1.Expression {
4234
4234
  getRunnable() {
4235
- const eq = (0, combi_1.seq)("=", source_1.Source);
4235
+ const eq = (0, combi_1.seq)("=", simple_source3_1.SimpleSource3);
4236
4236
  const integers = (0, combi_1.altPrio)("1", "2", "3", "4", "5", "6", "7");
4237
4237
  const texts = (0, combi_1.altPrio)("COL_BACKGROUND", "COL_HEADING", "COL_NORMAL", "COL_TOTAL", "COL_KEY", "COL_POSITIVE", "COL_NEGATIVE", "COL_GROUP");
4238
4238
  const value = (0, combi_1.alt)(eq, (0, combi_1.altPrio)("ON", "OFF", "COLOR OFF", (0, combi_1.altPrio)(integers, texts)));
@@ -9527,7 +9527,7 @@ const sql_field_1 = __webpack_require__(/*! ./sql_field */ "./node_modules/@abap
9527
9527
  const sql_grouping_sets_1 = __webpack_require__(/*! ./sql_grouping_sets */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/sql_grouping_sets.js");
9528
9528
  class SQLGroupBy extends combi_1.Expression {
9529
9529
  getRunnable() {
9530
- const fieldName = (0, combi_1.alt)(sql_field_name_1.SQLFieldName, dynamic_1.Dynamic);
9530
+ const fieldName = (0, combi_1.seq)((0, combi_1.stopBefore)("ORDER", "BY"), (0, combi_1.alt)(sql_field_name_1.SQLFieldName, dynamic_1.Dynamic));
9531
9531
  const expr = (0, combi_1.ver)(version_1.Release.v740sp02, sql_field_1.SQLField, { also: combi_1.AlsoIn.OpenABAP });
9532
9532
  const newGroup = (0, combi_1.ver)(version_1.Release.v740sp02, (0, combi_1.seq)("GROUP BY", expr, (0, combi_1.altPrio)((0, combi_1.plus)((0, combi_1.seq)(",", expr)), (0, combi_1.optPrio)((0, combi_1.plus)(fieldName)))), { also: combi_1.AlsoIn.OpenABAP });
9533
9533
  const old = (0, combi_1.seq)((0, combi_1.plus)((0, combi_1.seq)(fieldName, ",")), fieldName);
@@ -13129,7 +13129,7 @@ class ClassDefinition {
13129
13129
  const risk = (0, combi_1.seq)("RISK LEVEL", level);
13130
13130
  const time = (0, combi_1.altPrio)("LONG", "MEDIUM", "SHORT");
13131
13131
  const duration = (0, combi_1.seq)("DURATION", time);
13132
- const blah = (0, combi_1.per)(expressions_1.ClassGlobal, expressions_1.ClassFinal, "ABSTRACT", (0, combi_1.seq)("INHERITING FROM", expressions_1.SuperClassName), create, "FOR TESTING", risk, "SHARED MEMORY ENABLED", duration, (0, combi_1.ver)(version_1.Release.v754, (0, combi_1.seq)("FOR BEHAVIOR OF", expressions_1.BehaviorDefinitionName), { also: combi_1.AlsoIn.OpenABAP }), expressions_1.ClassFriends);
13132
+ const blah = (0, combi_1.per)(expressions_1.ClassGlobal, expressions_1.ClassFinal, "ABSTRACT", (0, combi_1.seq)("INHERITING FROM", expressions_1.SuperClassName), create, "FOR TESTING", risk, "SHARED MEMORY ENABLED", duration, (0, combi_1.ver)(version_1.Release.v754, (0, combi_1.seq)("FOR BEHAVIOR OF", expressions_1.BehaviorDefinitionName), { also: combi_1.AlsoIn.OpenABAP }), (0, combi_1.ver)(version_1.Release.v758, (0, combi_1.seq)("FOR EVENTS OF", expressions_1.BehaviorDefinitionName)), expressions_1.ClassFriends);
13133
13133
  const def = (0, combi_1.seq)("DEFINITION", (0, combi_1.optPrio)(blah));
13134
13134
  return (0, combi_1.seq)("CLASS", expressions_1.ClassName, def);
13135
13135
  }
@@ -17098,6 +17098,7 @@ exports.MethodDef = void 0;
17098
17098
  const version_1 = __webpack_require__(/*! ../../../version */ "./node_modules/@abaplint/core/build/src/version.js");
17099
17099
  const combi_1 = __webpack_require__(/*! ../combi */ "./node_modules/@abaplint/core/build/src/abap/2_statements/combi.js");
17100
17100
  const expressions_1 = __webpack_require__(/*! ../expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js");
17101
+ const tokens_1 = __webpack_require__(/*! ../../1_lexer/tokens */ "./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/index.js");
17101
17102
  class MethodDef {
17102
17103
  getMatcher() {
17103
17104
  const def = (0, combi_1.ver)(version_1.Release.v740sp08, (0, combi_1.seq)("DEFAULT", (0, combi_1.altPrio)("FAIL", "IGNORE")), { also: combi_1.AlsoIn.OpenABAP });
@@ -17111,6 +17112,9 @@ class MethodDef {
17111
17112
  const modify = (0, combi_1.alt)((0, combi_1.seq)("FOR ACTION", expressions_1.TypeName, (0, combi_1.optPrio)(result)), (0, combi_1.seq)("FOR CREATE", (0, combi_1.alt)(expressions_1.TypeName, expressions_1.EntityAssociation)), (0, combi_1.seq)("FOR DELETE", expressions_1.TypeName), (0, combi_1.seq)("FOR UPDATE", expressions_1.TypeName));
17112
17113
  const forRead = (0, combi_1.seq)("FOR READ", (0, combi_1.alt)(expressions_1.TypeName, expressions_1.EntityAssociation), (0, combi_1.optPrio)(full), result, (0, combi_1.optPrio)(link));
17113
17114
  const forfunction = (0, combi_1.seq)("FOR FUNCTION", expressions_1.TypeName, result);
17115
+ const entityEventReference = (0, combi_1.seq)("REFERENCE", (0, combi_1.tok)(tokens_1.ParenLeft), expressions_1.MethodParamName, (0, combi_1.tok)(tokens_1.ParenRightW));
17116
+ const entityEventParameter = (0, combi_1.seq)((0, combi_1.altPrio)(entityEventReference, expressions_1.MethodParamName), "FOR", expressions_1.TypeName);
17117
+ const entityEvent = (0, combi_1.seq)((0, combi_1.optPrio)("FINAL"), "FOR ENTITY EVENT", (0, combi_1.optPrio)("IMPORTING"), (0, combi_1.plus)(entityEventParameter));
17114
17118
  const behavior = (0, combi_1.altPrio)("DDL OBJECT OPTIONS CDS SESSION CLIENT REQUIRED", // todo, this is only from version something
17115
17119
  (0, combi_1.seq)("TABLE FUNCTION", expressions_1.NamespaceSimpleName), // todo, this is only from version something
17116
17120
  (0, combi_1.seq)("VALIDATE ON SAVE IMPORTING", expressions_1.MethodParamName, "FOR", expressions_1.TypeName), (0, combi_1.seq)("MODIFY", (0, combi_1.opt)("IMPORTING"), (0, combi_1.plus)((0, combi_1.seq)(expressions_1.MethodParamName, modify))), (0, combi_1.seq)("PRECHECK IMPORTING", expressions_1.MethodParamName, modify), (0, combi_1.seq)("DETERMINATION", expressions_1.TypeName, "IMPORTING", expressions_1.MethodParamName, "FOR", expressions_1.TypeName), (0, combi_1.seq)("VALIDATION", expressions_1.TypeName, "IMPORTING", expressions_1.MethodParamName, "FOR", expressions_1.TypeName), (0, combi_1.seq)("NUMBERING IMPORTING", expressions_1.MethodParamName, modify), (0, combi_1.seq)("READ IMPORTING", expressions_1.MethodParamName, (0, combi_1.altPrio)(forRead, forfunction)), (0, combi_1.seq)("FEATURES IMPORTING", expressions_1.MethodParamName, "REQUEST", expressions_1.NamespaceSimpleName, "FOR", expressions_1.NamespaceSimpleName, result), (0, combi_1.seq)("BEHAVIOR IMPORTING", expressions_1.MethodParamName, "FOR CREATE", expressions_1.TypeName, expressions_1.MethodParamName, "FOR UPDATE", expressions_1.TypeName, expressions_1.MethodParamName, "FOR DELETE", expressions_1.TypeName), (0, combi_1.seq)("BEHAVIOR IMPORTING", expressions_1.MethodParamName, "FOR READ", expressions_1.TypeName, result), (0, combi_1.seq)("BEHAVIOR IMPORTING", expressions_1.MethodParamName, "FOR UPDATE", expressions_1.TypeName), (0, combi_1.seq)((0, combi_1.alt)("BEHAVIOR", "LOCK"), "IMPORTING", expressions_1.MethodParamName, "FOR LOCK", expressions_1.TypeName), (0, combi_1.seq)("DETERMINE", (0, combi_1.alt)("ON MODIFY", "ON SAVE"), "IMPORTING", expressions_1.MethodParamName, "FOR", expressions_1.TypeName), (0, combi_1.seq)("GLOBAL AUTHORIZATION IMPORTING REQUEST", expressions_1.MethodParamName, "FOR", expressions_1.TypeName, result), (0, combi_1.seq)("GLOBAL FEATURES IMPORTING REQUEST", expressions_1.MethodParamName, "FOR", expressions_1.TypeName, result), (0, combi_1.seq)((0, combi_1.seq)((0, combi_1.opt)("INSTANCE"), "AUTHORIZATION IMPORTING"), expressions_1.MethodParamName, "REQUEST", expressions_1.MethodParamName, "FOR", expressions_1.TypeName, result), (0, combi_1.seq)("INSTANCE FEATURES IMPORTING", expressions_1.MethodParamName, "REQUEST", expressions_1.MethodParamName, "FOR", expressions_1.TypeName, result));
@@ -17118,7 +17122,9 @@ class MethodDef {
17118
17122
  // AMDP OPTIONS clause blocked in KeyUser
17119
17123
  const amdp = (0, combi_1.verNotLang)(version_1.LanguageVersion.KeyUser, (0, combi_1.seq)("AMDP OPTIONS", (0, combi_1.optPrio)("READ-ONLY"), "CDS SESSION CLIENT", (0, combi_1.alt)("CURRENT", "DEPENDENT"), (0, combi_1.optPrio)(expressions_1.MethodDefImporting), (0, combi_1.optPrio)(expressions_1.MethodDefExporting), (0, combi_1.optPrio)(expressions_1.MethodDefRaising)));
17120
17124
  // FOR DDL OBJECT / FOR TABLE FUNCTION / FOR SCALAR FUNCTION blocked in KeyUser
17121
- const ret = (0, combi_1.seq)((0, combi_1.altPrio)("CLASS-METHODS", "METHODS"), expressions_1.MethodName, (0, combi_1.alt)((0, combi_1.seq)((0, combi_1.optPrio)(expressions_1.Abstract), (0, combi_1.optPrio)(def), expressions_1.EventHandler), parameters, testing, (0, combi_1.verNotLang)(version_1.LanguageVersion.KeyUser, (0, combi_1.seq)("FOR", behavior)), amdp, "NOT AT END OF MODE", (0, combi_1.optPrio)(expressions_1.Redefinition)));
17125
+ const regular = (0, combi_1.seq)((0, combi_1.altPrio)("CLASS-METHODS", "METHODS"), expressions_1.MethodName, (0, combi_1.alt)((0, combi_1.seq)((0, combi_1.optPrio)(expressions_1.Abstract), (0, combi_1.optPrio)(def), expressions_1.EventHandler), parameters, testing, (0, combi_1.verNotLang)(version_1.LanguageVersion.KeyUser, (0, combi_1.seq)("FOR", behavior)), amdp, "NOT AT END OF MODE", (0, combi_1.optPrio)(expressions_1.Redefinition)));
17126
+ // RAP event handlers are instance methods; CLASS-METHODS is not allowed.
17127
+ const ret = (0, combi_1.alt)((0, combi_1.seq)("METHODS", expressions_1.MethodName, (0, combi_1.verNotLang)(version_1.LanguageVersion.KeyUser, entityEvent)), regular);
17122
17128
  return ret;
17123
17129
  }
17124
17130
  }
@@ -27118,6 +27124,31 @@ class ObjectOriented {
27118
27124
  }
27119
27125
  return ret;
27120
27126
  }
27127
+ // does the supplied class have friendship with "friendName"?
27128
+ // note that interfaces of the friend, and subclasses of the friend also have friendship
27129
+ hasFriendship(cd, friendName) {
27130
+ var _a;
27131
+ const friends = cd.getFriends().map(f => f.toUpperCase());
27132
+ const isFriend = (name) => friends.includes(name.toUpperCase()) || this.scope.isLocalFriend(cd.getName(), name);
27133
+ if (isFriend(friendName)) {
27134
+ return true;
27135
+ }
27136
+ const friendDefinition = this.scope.findClassDefinition(friendName);
27137
+ if (friendDefinition === undefined) {
27138
+ return false;
27139
+ }
27140
+ if (this.findInterfaces(friendDefinition).some(i => friends.includes(i.name.toUpperCase()))) {
27141
+ return true;
27142
+ }
27143
+ let sup = friendDefinition.getSuperClass();
27144
+ while (sup !== undefined) {
27145
+ if (isFriend(sup)) {
27146
+ return true;
27147
+ }
27148
+ sup = (_a = this.scope.findClassDefinition(sup)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
27149
+ }
27150
+ return false;
27151
+ }
27121
27152
  searchEvent(def, name) {
27122
27153
  if (def === undefined || name === undefined) {
27123
27154
  return undefined;
@@ -27126,6 +27157,11 @@ class ObjectOriented {
27126
27157
  if (found) {
27127
27158
  return found;
27128
27159
  }
27160
+ if (name.includes("~")) {
27161
+ // event of an implemented interface, ie. "if_name~event_name"
27162
+ const [interfaceName, eventName] = name.split("~");
27163
+ return this.searchEvent(this.scope.findInterfaceDefinition(interfaceName), eventName);
27164
+ }
27129
27165
  for (const a of def.getAliases() || []) {
27130
27166
  if (a.getName().toUpperCase() === name.toUpperCase()) {
27131
27167
  const comp = a.getComponent();
@@ -28021,6 +28057,12 @@ class TypeUtils {
28021
28057
  if (source2 instanceof basic_1.HexType && this.isCalculated(node2) && source1 instanceof basic_1.IntegerType) {
28022
28058
  return false;
28023
28059
  }
28060
+ if (source1 instanceof basic_1.DateType && this.isCalculated(node2) && source2 instanceof basic_1.IntegerType) {
28061
+ return false;
28062
+ }
28063
+ if (source2 instanceof basic_1.DateType && this.isCalculated(node1) && source1 instanceof basic_1.IntegerType) {
28064
+ return false;
28065
+ }
28024
28066
  return true;
28025
28067
  }
28026
28068
  structureContainsString(structure) {
@@ -28111,7 +28153,10 @@ class TypeUtils {
28111
28153
  || source instanceof basic_1.DataType
28112
28154
  || source instanceof basic_1.UnknownType;
28113
28155
  }
28114
- if (source instanceof basic_1.CharacterType) {
28156
+ if (source instanceof cgeneric_type_1.CGenericType && target instanceof basic_1.StringType) {
28157
+ return false;
28158
+ }
28159
+ else if (source instanceof basic_1.CharacterType) {
28115
28160
  if (target instanceof basic_1.CharacterType) {
28116
28161
  if (((_b = source.getAbstractTypeData()) === null || _b === void 0 ? void 0 : _b.derivedFromConstant) === true) {
28117
28162
  return source.getLength() <= target.getLength();
@@ -28154,6 +28199,11 @@ class TypeUtils {
28154
28199
  return false;
28155
28200
  }
28156
28201
  }
28202
+ else if (source instanceof basic_1.DateType || source instanceof basic_1.TimeType) {
28203
+ if (target instanceof basic_1.CharacterType || target instanceof basic_1.StringType) {
28204
+ return false;
28205
+ }
28206
+ }
28157
28207
  else if (source instanceof basic_1.StringType) {
28158
28208
  if (target instanceof basic_1.StructureType && this.structureContainsString(target)) {
28159
28209
  return false;
@@ -28180,6 +28230,11 @@ class TypeUtils {
28180
28230
  }
28181
28231
  return false;
28182
28232
  }
28233
+ else if (target instanceof basic_1.TableType
28234
+ || target instanceof basic_1.DataReference
28235
+ || target instanceof basic_1.ObjectReferenceType) {
28236
+ return false;
28237
+ }
28183
28238
  return true;
28184
28239
  }
28185
28240
  else if (source instanceof basic_1.StructureType) {
@@ -28204,7 +28259,8 @@ class TypeUtils {
28204
28259
  }
28205
28260
  else if (target instanceof basic_1.VoidType
28206
28261
  || target instanceof basic_1.AnyType
28207
- || target instanceof basic_1.DataType) {
28262
+ || target instanceof basic_1.DataType
28263
+ || target instanceof basic_1.UnknownType) {
28208
28264
  return true;
28209
28265
  }
28210
28266
  return false;
@@ -28215,7 +28271,9 @@ class TypeUtils {
28215
28271
  }
28216
28272
  }
28217
28273
  else if (source instanceof basic_1.IntegerType) {
28218
- if (target instanceof basic_1.StringType || target instanceof basic_1.DateType) {
28274
+ if (target instanceof basic_1.StringType
28275
+ || target instanceof basic_1.DateType
28276
+ || target instanceof basic_1.CharacterType) {
28219
28277
  return false;
28220
28278
  }
28221
28279
  else if (target instanceof basic_1.Integer8Type || target instanceof basic_1.PackedType) {
@@ -28293,6 +28351,29 @@ class TypeUtils {
28293
28351
  }
28294
28352
  return this.isAssignable(source, target);
28295
28353
  }
28354
+ // Typing with the classic STRUCTURE addition, ie. "FORM foo USING bar STRUCTURE zkey",
28355
+ // is not a compatibility check: ABAP only checks the fragment view up to the end of the
28356
+ // formal structure, so the actual parameter is allowed to be longer. For TABLES parameters
28357
+ // the table key is not part of the check at all.
28358
+ isAssignableStructureTyping(source, target, node) {
28359
+ if (source instanceof basic_1.StructureType && target instanceof basic_1.StructureType) {
28360
+ const sourceComponents = source.getComponents();
28361
+ const targetComponents = target.getComponents();
28362
+ if (sourceComponents.length < targetComponents.length) {
28363
+ return false;
28364
+ }
28365
+ for (let i = 0; i < targetComponents.length; i++) {
28366
+ if (this.isAssignableStrict(sourceComponents[i].type, targetComponents[i].type) === false) {
28367
+ return false;
28368
+ }
28369
+ }
28370
+ return true;
28371
+ }
28372
+ else if (source instanceof basic_1.TableType && target instanceof basic_1.TableType) {
28373
+ return this.isAssignableStructureTyping(source.getRowType(), target.getRowType());
28374
+ }
28375
+ return this.isAssignableStrict(source, target, node);
28376
+ }
28296
28377
  isAssignable(source, target) {
28297
28378
  if (source === undefined || target === undefined) {
28298
28379
  return true;
@@ -28301,6 +28382,9 @@ class TypeUtils {
28301
28382
  console.dir(source);
28302
28383
  console.dir(target);
28303
28384
  */
28385
+ if (source instanceof basic_1.UTCLongType || target instanceof basic_1.UTCLongType) {
28386
+ return this.isUTCLongAssignable(source, target);
28387
+ }
28304
28388
  if (target instanceof basic_1.TableType) {
28305
28389
  if (target.isWithHeader()) {
28306
28390
  return this.isAssignable(source, target.getRowType());
@@ -28452,6 +28536,33 @@ class TypeUtils {
28452
28536
  }
28453
28537
  return true;
28454
28538
  }
28539
+ // utclong can only be converted to and from character like types
28540
+ isUTCLongAssignable(source, target) {
28541
+ if (this.isGenericOrVoid(source) || this.isGenericOrVoid(target)) {
28542
+ return true;
28543
+ }
28544
+ else if (source instanceof basic_1.UTCLongType && target instanceof basic_1.UTCLongType) {
28545
+ return true;
28546
+ }
28547
+ else if (source instanceof basic_1.UTCLongType) {
28548
+ return this.isTextLike(target);
28549
+ }
28550
+ return this.isTextLike(source);
28551
+ }
28552
+ isGenericOrVoid(type) {
28553
+ return type instanceof basic_1.VoidType
28554
+ || type instanceof basic_1.AnyType
28555
+ || type instanceof basic_1.DataType
28556
+ || type instanceof basic_1.UnknownType;
28557
+ }
28558
+ isTextLike(type) {
28559
+ return type instanceof basic_1.CharacterType
28560
+ || type instanceof basic_1.StringType
28561
+ || type instanceof basic_1.CLikeType
28562
+ || type instanceof basic_1.CSequenceType
28563
+ || type instanceof cgeneric_type_1.CGenericType
28564
+ || type instanceof basic_1.SimpleType;
28565
+ }
28455
28566
  }
28456
28567
  exports.TypeUtils = TypeUtils;
28457
28568
  //# sourceMappingURL=_type_utils.js.map
@@ -28534,6 +28645,7 @@ const types_1 = __webpack_require__(/*! ../types */ "./node_modules/@abaplint/co
28534
28645
  const expressions_1 = __webpack_require__(/*! ../2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js");
28535
28646
  const _builtin_1 = __webpack_require__(/*! ./_builtin */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js");
28536
28647
  const position_1 = __webpack_require__(/*! ../../position */ "./node_modules/@abaplint/core/build/src/position.js");
28648
+ const _syntax_input_1 = __webpack_require__(/*! ./_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
28537
28649
  class BasicTypes {
28538
28650
  constructor(input) {
28539
28651
  this.input = input;
@@ -29016,7 +29128,7 @@ class BasicTypes {
29016
29128
  return Types.VoidType.get((_f = node.findFirstExpression(Expressions.TypeStructure)) === null || _f === void 0 ? void 0 : _f.concatTokens());
29017
29129
  }
29018
29130
  else if (text.startsWith("LIKE LINE OF ")) {
29019
- const name = (_g = node.findFirstExpression(Expressions.FieldChain)) === null || _g === void 0 ? void 0 : _g.concatTokens();
29131
+ let name = (_g = node.findFirstExpression(Expressions.FieldChain)) === null || _g === void 0 ? void 0 : _g.concatTokens();
29020
29132
  let e = node.findFirstExpression(Expressions.Type);
29021
29133
  if (e === undefined) {
29022
29134
  e = node.findFirstExpression(Expressions.FormParamType);
@@ -29024,19 +29136,32 @@ class BasicTypes {
29024
29136
  if (e === undefined) {
29025
29137
  e = node.findFirstExpression(Expressions.FieldChain);
29026
29138
  }
29139
+ if (e === undefined) {
29140
+ // old style, eg "LIKE LINE OF tab OCCURS 0 WITH HEADER LINE", it is parsed as TypeName
29141
+ e = typeName;
29142
+ name = typeName === null || typeName === void 0 ? void 0 : typeName.concatTokens();
29143
+ }
29027
29144
  const type = this.resolveLikeName(e, false);
29145
+ let row = undefined;
29028
29146
  if (type === undefined) {
29029
29147
  return new Types.UnknownType("Type error, could not resolve \"" + name + "\", parseType");
29030
29148
  }
29031
29149
  else if (type instanceof Types.TableType) {
29032
- return type.getRowType();
29150
+ row = type.getRowType();
29033
29151
  }
29034
29152
  else if (type instanceof Types.VoidType) {
29035
- return type;
29153
+ row = type;
29036
29154
  }
29037
29155
  else {
29038
29156
  return new Types.UnknownType("Type error, not a table type " + name);
29039
29157
  }
29158
+ if (this.isOccurs(node)) {
29159
+ return new Types.TableType(row, {
29160
+ withHeader: text.includes(" WITH HEADER LINE"),
29161
+ keyType: Types.TableKeyType.default
29162
+ }, qualifiedName);
29163
+ }
29164
+ return row;
29040
29165
  }
29041
29166
  else if (text.startsWith("LIKE REF TO ")) {
29042
29167
  const name = (_h = node.findFirstExpression(Expressions.FieldChain)) === null || _h === void 0 ? void 0 : _h.concatTokens();
@@ -29474,6 +29599,13 @@ class BasicTypes {
29474
29599
  }
29475
29600
  const chain = val.findFirstExpression(Expressions.SimpleFieldChain);
29476
29601
  if (chain) {
29602
+ // todo, hardcoded for now, should be a generic check that the chain is a constant
29603
+ const concat = chain.concatTokens().toUpperCase();
29604
+ if (concat === "SY-DATUM" || concat === "SY-UZEIT") {
29605
+ const message = "VALUE, " + concat.toLowerCase() + " is not a constant";
29606
+ this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, chain.getFirstToken(), message));
29607
+ return undefined;
29608
+ }
29477
29609
  return this.resolveConstantValue(chain);
29478
29610
  }
29479
29611
  throw new Error("findValue, unexpected");
@@ -29539,6 +29671,51 @@ exports.BasicTypes = BasicTypes;
29539
29671
 
29540
29672
  /***/ },
29541
29673
 
29674
+ /***/ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_fields.js"
29675
+ /*!***************************************************************************************************!*\
29676
+ !*** ./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_fields.js ***!
29677
+ \***************************************************************************************************/
29678
+ (__unused_webpack_module, exports, __webpack_require__) {
29679
+
29680
+ "use strict";
29681
+
29682
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
29683
+ exports.checkDatabaseFields = checkDatabaseFields;
29684
+ const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
29685
+ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
29686
+ function checkDatabaseFields(fields, dbSources, input, token) {
29687
+ if (dbSources.length > 1) {
29688
+ return;
29689
+ }
29690
+ const first = dbSources[0];
29691
+ if (first === undefined) {
29692
+ // then its voided
29693
+ return;
29694
+ }
29695
+ const type = first.parseType(input.scope.getRegistry());
29696
+ if (type instanceof basic_1.VoidType || type instanceof basic_1.UnknownType) {
29697
+ return;
29698
+ }
29699
+ if (!(type instanceof basic_1.StructureType)) {
29700
+ const message = "checkFields, expected structure, " + type.constructor.name;
29701
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
29702
+ return;
29703
+ }
29704
+ for (const field of fields) {
29705
+ if (field === "*") {
29706
+ continue;
29707
+ }
29708
+ if (/^[A-Z_]\w*$/i.test(field) && type.getComponentByName(field) === undefined) {
29709
+ const message = `checkFields, field ${field} not found`;
29710
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
29711
+ return;
29712
+ }
29713
+ }
29714
+ }
29715
+ //# sourceMappingURL=_check_database_fields.js.map
29716
+
29717
+ /***/ },
29718
+
29542
29719
  /***/ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js"
29543
29720
  /*!*************************************************************************************************!*\
29544
29721
  !*** ./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js ***!
@@ -30018,6 +30195,7 @@ const source_1 = __webpack_require__(/*! ./source */ "./node_modules/@abaplint/c
30018
30195
  const method_call_chain_1 = __webpack_require__(/*! ./method_call_chain */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/method_call_chain.js");
30019
30196
  const source_field_symbol_1 = __webpack_require__(/*! ./source_field_symbol */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source_field_symbol.js");
30020
30197
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
30198
+ const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
30021
30199
  const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_type_utils.js");
30022
30200
  class Compare {
30023
30201
  static runSyntax(node, input) {
@@ -30035,7 +30213,15 @@ class Compare {
30035
30213
  if (node.findDirectExpression(Expressions.CompareOperator)
30036
30214
  && new _type_utils_1.TypeUtils(input.scope).isCompareable(sourceTypes[0], sourceTypes[1], sources[0], sources[1]) === false
30037
30215
  && sourceTypes.length === 2) {
30038
- const message = "Incompatible types for comparison";
30216
+ let message = "Incompatible types for comparison";
30217
+ if ((sourceTypes[0] instanceof basic_1.DateType
30218
+ && sourceTypes[1] instanceof basic_1.IntegerType
30219
+ && sources[1].findFirstExpression(Expressions.ArithOperator))
30220
+ || (sourceTypes[1] instanceof basic_1.DateType
30221
+ && sourceTypes[0] instanceof basic_1.IntegerType
30222
+ && sources[0].findFirstExpression(Expressions.ArithOperator))) {
30223
+ message = "Date cannot be compared with arithmetic result of type Integer";
30224
+ }
30039
30225
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
30040
30226
  }
30041
30227
  }
@@ -31790,18 +31976,27 @@ class FormParam {
31790
31976
  else {
31791
31977
  type = new basic_1.UnknownType("todo, FORM STRUCTURES typing");
31792
31978
  }
31793
- return new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, type, ["form_parameter" /* IdentifierMeta.FormParameter */]);
31979
+ return new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, type, ["form_parameter" /* IdentifierMeta.FormParameter */, "form_parameter_structure" /* IdentifierMeta.FormParameterStructure */]);
31794
31980
  }
31795
31981
  if (node.getChildren().length === 1 && nameToken) {
31796
31982
  // untyped FORM parameter
31797
31983
  return new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, basic_1.AnyType.get(), ["form_parameter" /* IdentifierMeta.FormParameter */]);
31798
31984
  }
31799
31985
  let bfound = new basic_types_1.BasicTypes(input).parseType(node);
31800
- const isTypeC = ((_c = node.findFirstExpression(expressions_1.TypeName)) === null || _c === void 0 ? void 0 : _c.concatTokens().toUpperCase()) === "C";
31986
+ const typeName = (_c = node.findFirstExpression(expressions_1.TypeName)) === null || _c === void 0 ? void 0 : _c.concatTokens().toUpperCase();
31801
31987
  const hasExplicitLength = node.findFirstExpression(expressions_1.Length) !== undefined
31802
31988
  || node.findFirstExpression(expressions_1.ConstantFieldLength) !== undefined;
31803
- if (isTypeC && hasExplicitLength === false && bfound instanceof basic_1.CharacterType) {
31804
- bfound = basic_1.CGenericType.get();
31989
+ // the length cannot be specified for FORM parameters, so these types are generic
31990
+ if (hasExplicitLength === false) {
31991
+ if (typeName === "C" && bfound instanceof basic_1.CharacterType) {
31992
+ bfound = basic_1.CGenericType.get();
31993
+ }
31994
+ else if (typeName === "X" && bfound instanceof basic_1.HexType) {
31995
+ bfound = basic_1.XGenericType.get();
31996
+ }
31997
+ else if (typeName === "P" && bfound instanceof basic_1.PackedType) {
31998
+ bfound = basic_1.PGenericType.get();
31999
+ }
31805
32000
  }
31806
32001
  if (nameToken && bfound) {
31807
32002
  return new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, bfound, ["form_parameter" /* IdentifierMeta.FormParameter */]);
@@ -32693,6 +32888,8 @@ const _reference_1 = __webpack_require__(/*! ../_reference */ "./node_modules/@a
32693
32888
  const component_name_1 = __webpack_require__(/*! ./component_name */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/component_name.js");
32694
32889
  const attribute_name_1 = __webpack_require__(/*! ./attribute_name */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/attribute_name.js");
32695
32890
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
32891
+ const visibility_1 = __webpack_require__(/*! ../../4_file_information/visibility */ "./node_modules/@abaplint/core/build/src/abap/4_file_information/visibility.js");
32892
+ const class_definition_1 = __webpack_require__(/*! ../../types/class_definition */ "./node_modules/@abaplint/core/build/src/abap/types/class_definition.js");
32696
32893
  class MethodCallChain {
32697
32894
  static runSyntax(node, input, targetType) {
32698
32895
  var _a, _b;
@@ -32741,6 +32938,12 @@ class MethodCallChain {
32741
32938
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, methodToken, message));
32742
32939
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
32743
32940
  }
32941
+ const notVisible = method ? this.checkVisibility(method, def, foundDef, input) : undefined;
32942
+ if (notVisible !== undefined) {
32943
+ const message = `Method "${methodName}" is ${notVisible} and cannot be accessed`;
32944
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, methodToken, message));
32945
+ return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
32946
+ }
32744
32947
  const voidedName = context instanceof basic_1.VoidType ? context.getVoided() : undefined;
32745
32948
  const extra = helper.methodReferenceExtras(foundDef, className || voidedName);
32746
32949
  input.scope.addReference(methodToken, method, _reference_1.ReferenceType.MethodReference, input.filename, extra);
@@ -32783,6 +32986,47 @@ class MethodCallChain {
32783
32986
  return context;
32784
32987
  }
32785
32988
  //////////////////////////////////////
32989
+ // returns the visibility as text if the method cannot be accessed from the current scope
32990
+ static checkVisibility(method, def, foundDef, input) {
32991
+ var _a, _b, _c;
32992
+ const visibility = method.getVisibility();
32993
+ if (visibility === visibility_1.Visibility.Public || foundDef === undefined) {
32994
+ return undefined;
32995
+ }
32996
+ else if (!(foundDef instanceof class_definition_1.ClassDefinition)) {
32997
+ // interface members are always public
32998
+ return undefined;
32999
+ }
33000
+ const name = foundDef.getName().toUpperCase();
33001
+ const enclosing = (_a = input.scope.getEnclosingClassName()) === null || _a === void 0 ? void 0 : _a.toUpperCase();
33002
+ if (enclosing === undefined || enclosing === name) {
33003
+ return undefined;
33004
+ }
33005
+ // friendship with the class used at the call site also gives access to inherited members
33006
+ const helper = new _object_oriented_1.ObjectOriented(input.scope);
33007
+ const visited = [];
33008
+ let current = def instanceof class_definition_1.ClassDefinition ? def : foundDef;
33009
+ while (current !== undefined && visited.includes(current.getName().toUpperCase()) === false) {
33010
+ visited.push(current.getName().toUpperCase());
33011
+ if (helper.hasFriendship(current, enclosing)) {
33012
+ return undefined;
33013
+ }
33014
+ const sup = current.getSuperClass();
33015
+ current = sup === undefined ? undefined : input.scope.findClassDefinition(sup);
33016
+ }
33017
+ if (visibility === visibility_1.Visibility.Protected) {
33018
+ // subclasses can access protected members
33019
+ let sup = (_b = input.scope.findClassDefinition(enclosing)) === null || _b === void 0 ? void 0 : _b.getSuperClass();
33020
+ while (sup !== undefined) {
33021
+ if (sup.toUpperCase() === name) {
33022
+ return undefined;
33023
+ }
33024
+ sup = (_c = input.scope.findClassDefinition(sup)) === null || _c === void 0 ? void 0 : _c.getSuperClass();
33025
+ }
33026
+ return "protected";
33027
+ }
33028
+ return "private";
33029
+ }
32786
33030
  static findTop(first, input, targetType) {
32787
33031
  var _a;
32788
33032
  if (first.get() instanceof Expressions.ClassName) {
@@ -34179,6 +34423,7 @@ const dynamic_1 = __webpack_require__(/*! ./dynamic */ "./node_modules/@abaplint
34179
34423
  const _reference_1 = __webpack_require__(/*! ../_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
34180
34424
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
34181
34425
  const version_1 = __webpack_require__(/*! ../../../version */ "./node_modules/@abaplint/core/build/src/version.js");
34426
+ const _check_database_fields_1 = __webpack_require__(/*! ./_check_database_fields */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
34182
34427
  const isSimple = /^\w+$/;
34183
34428
  class Select {
34184
34429
  static runSyntax(node, input, skipImplicitInto = false, selectLoop = false) {
@@ -34203,8 +34448,8 @@ class Select {
34203
34448
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
34204
34449
  return;
34205
34450
  }
34206
- this.checkFields(fields, dbSources, input, node);
34207
- const intoExpression = this.handleInto(node, input, fields, dbSources);
34451
+ (0, _check_database_fields_1.checkDatabaseFields)(fields.map(field => field.code), dbSources, input, node.getFirstToken());
34452
+ const intoExpression = this.handleInto(node, input, fields, dbSources, from);
34208
34453
  const fae = node.findDirectExpression(Expressions.SQLForAllEntries);
34209
34454
  if (fae) {
34210
34455
  input.scope.push(_scope_type_1.ScopeType.OpenSQL, "SELECT", token.getStart(), input.filename);
@@ -34365,12 +34610,12 @@ class Select {
34365
34610
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
34366
34611
  }
34367
34612
  }
34368
- static handleInto(node, input, fields, dbSources) {
34613
+ static handleInto(node, input, fields, dbSources, from) {
34369
34614
  const intoTable = node.findDirectExpression(Expressions.SQLIntoTable);
34370
34615
  if (intoTable) {
34371
34616
  const inline = intoTable.findFirstExpression(Expressions.InlineData);
34372
34617
  if (inline) {
34373
- inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope));
34618
+ inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope, from));
34374
34619
  }
34375
34620
  return intoTable;
34376
34621
  }
@@ -34430,35 +34675,6 @@ class Select {
34430
34675
  }
34431
34676
  return undefined;
34432
34677
  }
34433
- static checkFields(fields, dbSources, input, node) {
34434
- if (dbSources.length > 1) {
34435
- return;
34436
- }
34437
- const first = dbSources[0];
34438
- if (first === undefined) {
34439
- // then its voided
34440
- return;
34441
- }
34442
- const type = first.parseType(input.scope.getRegistry());
34443
- if (type instanceof basic_1.VoidType || type instanceof basic_1.UnknownType) {
34444
- return;
34445
- }
34446
- if (!(type instanceof basic_1.StructureType)) {
34447
- const message = "checkFields, expected structure, " + type.constructor.name;
34448
- input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
34449
- return;
34450
- }
34451
- for (const field of fields) {
34452
- if (field.code === "*") {
34453
- continue;
34454
- }
34455
- if (isSimple.test(field.code) && type.getComponentByName(field.code) === undefined) {
34456
- const message = `checkFields, field ${field.code} not found`;
34457
- input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
34458
- return;
34459
- }
34460
- }
34461
- }
34462
34678
  static countResultType(scope) {
34463
34679
  if ((0, version_1.releaseAtLeast)(scope.getRelease(), version_1.Release.v750)
34464
34680
  || scope.getOpenABAP()
@@ -34547,11 +34763,36 @@ class Select {
34547
34763
  return basic_1.VoidType.get("SELECT_todo13");
34548
34764
  }
34549
34765
  }
34550
- static buildTableType(fields, dbSources, scope) {
34551
- if (dbSources.length !== 1) {
34766
+ static buildTableType(fields, dbSources, scope, from) {
34767
+ var _a;
34768
+ const tableOptions = { withHeader: false, keyType: basic_1.TableKeyType.empty };
34769
+ if (dbSources.length > 1) {
34770
+ const sourceInfos = this.buildDatabaseSourceInfos(from, dbSources);
34771
+ if (fields.length === 1 && fields[0].code === "*") {
34772
+ const components = [];
34773
+ for (const info of sourceInfos) {
34774
+ const type = (_a = info.source) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
34775
+ if (!(type instanceof basic_1.StructureType)) {
34776
+ return basic_1.VoidType.get("SELECT_todo3");
34777
+ }
34778
+ components.push({ name: info.alias || info.name, type });
34779
+ }
34780
+ return new basic_1.TableType(new basic_1.StructureType(components), tableOptions, undefined);
34781
+ }
34782
+ const components = [];
34783
+ for (const field of fields) {
34784
+ const type = this.findFieldType(field.code, sourceInfos, scope);
34785
+ if (type === undefined) {
34786
+ return basic_1.VoidType.get("SELECT_todo3");
34787
+ }
34788
+ const name = field.as || field.code.split("~").pop();
34789
+ components.push({ name, type });
34790
+ }
34791
+ return new basic_1.TableType(new basic_1.StructureType(components), tableOptions, undefined);
34792
+ }
34793
+ else if (dbSources.length !== 1) {
34552
34794
  return basic_1.VoidType.get("SELECT_todo3");
34553
34795
  }
34554
- const tableOptions = { withHeader: false, keyType: basic_1.TableKeyType.empty };
34555
34796
  if (dbSources[0] === undefined) {
34556
34797
  // then its a voided table
34557
34798
  return new basic_1.TableType(basic_1.VoidType.get("SELECT_todo4"), tableOptions, undefined);
@@ -34577,6 +34818,39 @@ class Select {
34577
34818
  }
34578
34819
  return basic_1.VoidType.get("SELECT_todo7");
34579
34820
  }
34821
+ static buildDatabaseSourceInfos(from, dbSources) {
34822
+ const fromSources = from.findAllExpressions(Expressions.SQLFromSource);
34823
+ return dbSources.map((source, index) => {
34824
+ var _a, _b;
34825
+ const fromSource = fromSources[index];
34826
+ const name = ((_a = fromSource === null || fromSource === void 0 ? void 0 : fromSource.findFirstExpression(Expressions.DatabaseTable)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr().replace(/^\*/, "").toUpperCase()) || "";
34827
+ const alias = ((_b = fromSource === null || fromSource === void 0 ? void 0 : fromSource.findDirectExpression(Expressions.SQLAsName)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase()) || "";
34828
+ return { source, name, alias };
34829
+ });
34830
+ }
34831
+ static findFieldType(code, sourceInfos, scope) {
34832
+ var _a;
34833
+ const separator = code.indexOf("~");
34834
+ const qualifier = separator >= 0 ? code.substring(0, separator) : undefined;
34835
+ const fieldName = separator >= 0 ? code.substring(separator + 1) : code;
34836
+ const candidates = qualifier === undefined
34837
+ ? sourceInfos
34838
+ : sourceInfos.filter(info => info.alias === qualifier || info.name === qualifier);
34839
+ for (const candidate of candidates) {
34840
+ let type = (_a = candidate.source) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
34841
+ for (const component of fieldName.split("-")) {
34842
+ if (!(type instanceof basic_1.StructureType)) {
34843
+ type = undefined;
34844
+ break;
34845
+ }
34846
+ type = type.getComponentByName(component);
34847
+ }
34848
+ if (type) {
34849
+ return type;
34850
+ }
34851
+ }
34852
+ return undefined;
34853
+ }
34580
34854
  static findFields(node, input) {
34581
34855
  var _a, _b;
34582
34856
  let expr = undefined;
@@ -34590,7 +34864,7 @@ class Select {
34590
34864
  let code = field.concatTokens().toUpperCase();
34591
34865
  const as = ((_b = field.findDirectExpression(Expressions.SQLAsName)) === null || _b === void 0 ? void 0 : _b.concatTokens()) || "";
34592
34866
  if (as !== "") {
34593
- code = code.replace(" AS " + as, "");
34867
+ code = code.replace(" AS " + as.toUpperCase(), "");
34594
34868
  }
34595
34869
  ret.push({ code, as, expression: field });
34596
34870
  }
@@ -35421,6 +35695,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@ab
35421
35695
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
35422
35696
  const sql_set_op_group_1 = __webpack_require__(/*! ./sql_set_op_group */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/sql_set_op_group.js");
35423
35697
  const sql_source_1 = __webpack_require__(/*! ./sql_source */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/sql_source.js");
35698
+ const RANGE_COMPONENTS = ["SIGN", "OPTION", "LOW", "HIGH"];
35424
35699
  class SQLIn {
35425
35700
  static runSyntax(node, input) {
35426
35701
  const setop = node.findDirectExpression(Expressions.SQLSetOpGroup);
@@ -35440,6 +35715,12 @@ class SQLIn {
35440
35715
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
35441
35716
  return;
35442
35717
  }
35718
+ if (intype instanceof basic_1.TableType && this.isRangeRow(intype.getRowType()) === false) {
35719
+ const name = insource.concatTokens().replace(/^@/, "").replace(/\[\]$/, "");
35720
+ const message = `row structure of ${name} is not correct`;
35721
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
35722
+ return;
35723
+ }
35443
35724
  }
35444
35725
  return;
35445
35726
  }
@@ -35450,6 +35731,16 @@ class SQLIn {
35450
35731
  sql_source_1.SQLSource.runSyntax(s, input);
35451
35732
  }
35452
35733
  }
35734
+ // "IN itab" expects a ranges table, ie. the row must have SIGN, OPTION, LOW and HIGH
35735
+ static isRangeRow(rowType) {
35736
+ if (rowType instanceof basic_1.VoidType || rowType instanceof basic_1.UnknownType || rowType instanceof basic_1.AnyType) {
35737
+ return true;
35738
+ }
35739
+ else if (!(rowType instanceof basic_1.StructureType)) {
35740
+ return false;
35741
+ }
35742
+ return RANGE_COMPONENTS.every(c => rowType.getComponentByName(c) !== undefined);
35743
+ }
35453
35744
  }
35454
35745
  exports.SQLIn = SQLIn;
35455
35746
  //# sourceMappingURL=sql_in.js.map
@@ -36346,6 +36637,7 @@ var __importStar = (this && this.__importStar) || (function () {
36346
36637
  })();
36347
36638
  Object.defineProperty(exports, "__esModule", ({ value: true }));
36348
36639
  exports.ValueBody = void 0;
36640
+ const nodes_1 = __webpack_require__(/*! ../../nodes */ "./node_modules/@abaplint/core/build/src/abap/nodes/index.js");
36349
36641
  const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
36350
36642
  const for_1 = __webpack_require__(/*! ./for */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/for.js");
36351
36643
  const source_1 = __webpack_require__(/*! ./source */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js");
@@ -36355,7 +36647,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@ab
36355
36647
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
36356
36648
  class ValueBody {
36357
36649
  static runSyntax(node, input, targetType) {
36358
- var _a, _b;
36650
+ var _a, _b, _c;
36359
36651
  if (node === undefined) {
36360
36652
  return targetType;
36361
36653
  }
@@ -36372,26 +36664,45 @@ class ValueBody {
36372
36664
  }
36373
36665
  }
36374
36666
  const fields = new Set();
36375
- for (const s of node.findDirectExpressions(Expressions.FieldAssignment)) {
36376
- field_assignment_1.FieldAssignment.runSyntax(s, input, targetType);
36377
- if (node.findDirectExpression(Expressions.ValueBodyLine) === undefined) {
36378
- // todo: refine, still needs to be checked when there are table lines
36379
- const fieldname = (_a = s.findDirectExpression(Expressions.FieldSub)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
36667
+ const hasTableLines = node.findDirectExpression(Expressions.ValueBodyLine) !== undefined;
36668
+ for (const child of node.getChildren()) {
36669
+ if (!(child instanceof nodes_1.ExpressionNode)) {
36670
+ continue;
36671
+ }
36672
+ else if (child.get() instanceof Expressions.FieldAssignment) {
36673
+ const fieldname = (_a = child.findDirectExpression(Expressions.FieldSub)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
36674
+ if (fieldname && hasTableLines === false && fields.has(fieldname)) {
36675
+ const message = "Duplicate field assignment";
36676
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, child.getFirstToken(), message));
36677
+ return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
36678
+ }
36380
36679
  if (fieldname) {
36381
- if (fields.has(fieldname)) {
36680
+ fields.add(fieldname);
36681
+ }
36682
+ }
36683
+ else if (child.get() instanceof Expressions.ValueBodyLine) {
36684
+ const rowFields = new Set(fields);
36685
+ for (const assignment of child.findDirectExpressions(Expressions.FieldAssignment)) {
36686
+ const fieldname = (_b = assignment.findDirectExpression(Expressions.FieldSub)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();
36687
+ if (fieldname && rowFields.has(fieldname)) {
36382
36688
  const message = "Duplicate field assignment";
36383
- input.issues.push((0, _syntax_input_1.syntaxIssue)(input, s.getFirstToken(), message));
36689
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, assignment.getFirstToken(), message));
36384
36690
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
36385
36691
  }
36386
- fields.add(fieldname);
36692
+ if (fieldname) {
36693
+ rowFields.add(fieldname);
36694
+ }
36387
36695
  }
36388
36696
  }
36389
36697
  }
36698
+ for (const s of node.findDirectExpressions(Expressions.FieldAssignment)) {
36699
+ field_assignment_1.FieldAssignment.runSyntax(s, input, targetType);
36700
+ }
36390
36701
  let type = undefined; // todo, this is only correct if there is a single source in the body
36391
36702
  for (const s of node.findDirectExpressions(Expressions.Source)) {
36392
36703
  type = source_1.Source.runSyntax(s, input, type);
36393
36704
  }
36394
- for (const s of ((_b = node.findDirectExpression(Expressions.ValueBase)) === null || _b === void 0 ? void 0 : _b.findDirectExpressions(Expressions.Source)) || []) {
36705
+ for (const s of ((_c = node.findDirectExpression(Expressions.ValueBase)) === null || _c === void 0 ? void 0 : _c.findDirectExpressions(Expressions.Source)) || []) {
36395
36706
  type = source_1.Source.runSyntax(s, input, type);
36396
36707
  }
36397
36708
  for (const foo of node.findDirectExpressions(Expressions.ValueBodyLine)) {
@@ -38067,7 +38378,12 @@ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modu
38067
38378
  const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_type_utils.js");
38068
38379
  class Catch {
38069
38380
  runSyntax(node, input) {
38070
- var _a;
38381
+ var _a, _b, _c;
38382
+ const target = node.findDirectExpression(Expressions.Target);
38383
+ const inlineTarget = (_b = (_a = target === null || target === void 0 ? void 0 : target.findDirectExpression(Expressions.InlineData)) === null || _a === void 0 ? void 0 : _a.findFirstExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.getFirstToken();
38384
+ if (inlineTarget && inlineTarget.getStr().length > 30) {
38385
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, inlineTarget, "Inline exception name longer than 30 characters"));
38386
+ }
38071
38387
  const names = new Set();
38072
38388
  for (const c of node.findDirectExpressions(Expressions.ClassName)) {
38073
38389
  const token = c.getFirstToken();
@@ -38091,9 +38407,8 @@ class Catch {
38091
38407
  }
38092
38408
  names.add(className);
38093
38409
  }
38094
- const target = node.findDirectExpression(Expressions.Target);
38095
38410
  if (target === null || target === void 0 ? void 0 : target.findDirectExpression(Expressions.InlineData)) {
38096
- const token = (_a = target.findFirstExpression(Expressions.TargetField)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
38411
+ const token = (_c = target.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.getFirstToken();
38097
38412
  if (token) {
38098
38413
  const classNames = Array.from(names);
38099
38414
  const unknownClass = classNames.find(name => input.scope.findClassDefinition(name) === undefined);
@@ -39504,7 +39819,7 @@ class CreateObject {
39504
39819
  this.validateParameters(cdef, node, input);
39505
39820
  }
39506
39821
  static checkInstantiationAllowed(cdef, input) {
39507
- var _a, _b, _c;
39822
+ var _a, _b;
39508
39823
  const createVis = cdef.getCreateVisibility();
39509
39824
  if (createVis === visibility_1.Visibility.Public) {
39510
39825
  return undefined;
@@ -39517,34 +39832,17 @@ class CreateObject {
39517
39832
  if (enclosingClass.toUpperCase() === cdef.getName().toUpperCase()) {
39518
39833
  return undefined;
39519
39834
  }
39520
- if (cdef.getFriends().some(f => f.toUpperCase() === enclosingClass.toUpperCase()) ||
39521
- input.scope.isLocalFriend(cdef.getName(), enclosingClass)) {
39835
+ if (new _object_oriented_1.ObjectOriented(input.scope).hasFriendship(cdef, enclosingClass)) {
39522
39836
  return undefined;
39523
39837
  }
39524
- const enclosingDefinition = input.scope.findClassDefinition(enclosingClass);
39525
- if (enclosingDefinition !== undefined) {
39526
- const implementedInterfaces = new _object_oriented_1.ObjectOriented(input.scope).findInterfaces(enclosingDefinition);
39527
- if (cdef.getFriends().some(friend => implementedInterfaces.some(implemented => implemented.name.toUpperCase() === friend.toUpperCase()))) {
39528
- return undefined;
39529
- }
39530
- }
39531
- // subclasses of friends also have friendship
39532
- let enclosingSup = enclosingDefinition === null || enclosingDefinition === void 0 ? void 0 : enclosingDefinition.getSuperClass();
39533
- while (enclosingSup !== undefined) {
39534
- if (cdef.getFriends().some(f => f.toUpperCase() === enclosingSup.toUpperCase()) ||
39535
- input.scope.isLocalFriend(cdef.getName(), enclosingSup)) {
39536
- return undefined;
39537
- }
39538
- enclosingSup = (_a = input.scope.findClassDefinition(enclosingSup)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
39539
- }
39540
39838
  if (createVis === visibility_1.Visibility.Protected) {
39541
39839
  // subclasses are also allowed
39542
- let sup = (_b = input.scope.findClassDefinition(enclosingClass)) === null || _b === void 0 ? void 0 : _b.getSuperClass();
39840
+ let sup = (_a = input.scope.findClassDefinition(enclosingClass)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
39543
39841
  while (sup !== undefined) {
39544
39842
  if (sup.toUpperCase() === cdef.getName().toUpperCase()) {
39545
39843
  return undefined;
39546
39844
  }
39547
- sup = (_c = input.scope.findClassDefinition(sup)) === null || _c === void 0 ? void 0 : _c.getSuperClass();
39845
+ sup = (_b = input.scope.findClassDefinition(sup)) === null || _b === void 0 ? void 0 : _b.getSuperClass();
39548
39846
  }
39549
39847
  }
39550
39848
  return cdef.getName() + " cannot be instantiated, class is defined as " +
@@ -39807,6 +40105,8 @@ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expr
39807
40105
  const source_1 = __webpack_require__(/*! ../expressions/source */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js");
39808
40106
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/dynamic.js");
39809
40107
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/database_table.js");
40108
+ const _check_database_fields_1 = __webpack_require__(/*! ../expressions/_check_database_fields */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
40109
+ const sql_in_1 = __webpack_require__(/*! ../expressions/sql_in */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/sql_in.js");
39810
40110
  class DeleteDatabase {
39811
40111
  runSyntax(node, input) {
39812
40112
  for (const s of node.findAllExpressions(Expressions.Source)) {
@@ -39818,9 +40118,22 @@ class DeleteDatabase {
39818
40118
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
39819
40119
  dynamic_1.Dynamic.runSyntax(d, input);
39820
40120
  }
40121
+ for (const compare of node.findAllExpressions(Expressions.SQLCompare)) {
40122
+ const sqlin = compare.findDirectExpression(Expressions.SQLIn);
40123
+ if (sqlin !== undefined) {
40124
+ sql_in_1.SQLIn.runSyntax(sqlin, input);
40125
+ }
40126
+ }
39821
40127
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
39822
40128
  if (dbtab !== undefined) {
39823
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
40129
+ const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
40130
+ const fields = node.findAllExpressions(Expressions.SQLCompare)
40131
+ .map(compare => { var _a; return (_a = compare.findDirectExpression(Expressions.SQLFieldName)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase(); })
40132
+ .filter(field => field !== undefined);
40133
+ for (const orderBy of node.findAllExpressions(Expressions.SQLOrderBy)) {
40134
+ fields.push(...orderBy.findAllExpressions(Expressions.SQLFieldName).map(field => field.concatTokens().toUpperCase()));
40135
+ }
40136
+ (0, _check_database_fields_1.checkDatabaseFields)(fields, [dbSource], input, node.getFirstToken());
39824
40137
  }
39825
40138
  }
39826
40139
  }
@@ -40815,13 +41128,17 @@ const expressions_1 = __webpack_require__(/*! ../../2_statements/expressions */
40815
41128
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
40816
41129
  class Form {
40817
41130
  runSyntax(node, input) {
40818
- var _a;
40819
- const name = (_a = node.findDirectExpression(expressions_1.FormName)) === null || _a === void 0 ? void 0 : _a.concatTokens();
40820
- if (name === undefined) {
41131
+ const nameExpression = node.findDirectExpression(expressions_1.FormName);
41132
+ const name = nameExpression === null || nameExpression === void 0 ? void 0 : nameExpression.concatTokens();
41133
+ if (nameExpression === undefined || name === undefined) {
40821
41134
  const message = "Form, could not find name";
40822
41135
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
40823
41136
  return;
40824
41137
  }
41138
+ if (name.length > 30) {
41139
+ const message = "FORM name longer than 30 characters";
41140
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, nameExpression.getFirstToken(), message));
41141
+ }
40825
41142
  input.scope.push(_scope_type_1.ScopeType.Form, name, node.getFirstToken().getStart(), input.filename);
40826
41143
  const form = new form_definition_1.FormDefinition(node, input);
40827
41144
  input.scope.addList(form.getUsingParameters());
@@ -40881,7 +41198,7 @@ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expr
40881
41198
  const source_1 = __webpack_require__(/*! ../expressions/source */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js");
40882
41199
  class Format {
40883
41200
  runSyntax(node, input) {
40884
- for (const s of node.findAllExpressions(Expressions.Source)) {
41201
+ for (const s of node.findAllExpressionsMulti([Expressions.Source, Expressions.SimpleSource3])) {
40885
41202
  source_1.Source.runSyntax(s, input);
40886
41203
  }
40887
41204
  }
@@ -43706,6 +44023,16 @@ class Parameter {
43706
44023
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
43707
44024
  return;
43708
44025
  }
44026
+ const radioGroup = node.findFirstExpression(Expressions.RadioGroupName);
44027
+ if (radioGroup && radioGroup.concatTokens().length > 4) {
44028
+ const message = "Radio button group name too long, " + radioGroup.concatTokens();
44029
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, radioGroup.getFirstToken(), message));
44030
+ }
44031
+ if (this.hasUserCommand(node) && this.hasLength(node)) {
44032
+ const message = "USER-COMMAND and LENGTH not possible together";
44033
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
44034
+ return;
44035
+ }
43709
44036
  const bfound = new basic_types_1.BasicTypes(input).parseType(node);
43710
44037
  if (bfound) {
43711
44038
  input.scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, bfound));
@@ -43717,6 +44044,30 @@ class Parameter {
43717
44044
  const magicToken = new tokens_1.Identifier(nameToken.getStart(), magicName);
43718
44045
  input.scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(magicToken, input.filename, basic_1.VoidType.get("PARAMETER-MAGIC")));
43719
44046
  }
44047
+ // "USER-COMMAND" is lexed as three tokens
44048
+ hasUserCommand(node) {
44049
+ const tokens = node.getTokens();
44050
+ for (let i = 0; i < tokens.length - 2; i++) {
44051
+ if (tokens[i].getStr().toUpperCase() === "USER"
44052
+ && tokens[i + 1].getStr() === "-"
44053
+ && tokens[i + 2].getStr().toUpperCase() === "COMMAND") {
44054
+ return true;
44055
+ }
44056
+ }
44057
+ return false;
44058
+ }
44059
+ // "VISIBLE LENGTH" is not the same as "LENGTH"
44060
+ hasLength(node) {
44061
+ var _a;
44062
+ const tokens = node.getTokens();
44063
+ for (let i = 0; i < tokens.length; i++) {
44064
+ if (tokens[i].getStr().toUpperCase() === "LENGTH"
44065
+ && ((_a = tokens[i - 1]) === null || _a === void 0 ? void 0 : _a.getStr().toUpperCase()) !== "VISIBLE") {
44066
+ return true;
44067
+ }
44068
+ }
44069
+ return false;
44070
+ }
43720
44071
  }
43721
44072
  exports.Parameter = Parameter;
43722
44073
  //# sourceMappingURL=parameter.js.map
@@ -43774,6 +44125,7 @@ const target_1 = __webpack_require__(/*! ../expressions/target */ "./node_module
43774
44125
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
43775
44126
  const assert_error_1 = __webpack_require__(/*! ../assert_error */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/assert_error.js");
43776
44127
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/dynamic.js");
44128
+ const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_type_utils.js");
43777
44129
  class Perform {
43778
44130
  runSyntax(node, input) {
43779
44131
  if (!(node.get() instanceof Statements.Perform)) {
@@ -43781,19 +44133,22 @@ class Perform {
43781
44133
  }
43782
44134
  ////////////////////////////
43783
44135
  // check parameters are defined
44136
+ const changing = [];
43784
44137
  for (const c of node.findDirectExpressions(Expressions.PerformChanging)) {
43785
44138
  for (const s of c.findDirectExpressions(Expressions.Target)) {
43786
- target_1.Target.runSyntax(s, input);
44139
+ changing.push({ node: s, type: target_1.Target.runSyntax(s, input) });
43787
44140
  }
43788
44141
  }
44142
+ const tables = [];
43789
44143
  for (const t of node.findDirectExpressions(Expressions.PerformTables)) {
43790
44144
  for (const s of t.findDirectExpressions(Expressions.Source)) {
43791
- source_1.Source.runSyntax(s, input);
44145
+ tables.push({ node: s, type: source_1.Source.runSyntax(s, input) });
43792
44146
  }
43793
44147
  }
44148
+ const using = [];
43794
44149
  for (const u of node.findDirectExpressions(Expressions.PerformUsing)) {
43795
44150
  for (const s of u.findDirectExpressions(Expressions.SimpleSource3)) {
43796
- source_1.Source.runSyntax(s, input);
44151
+ using.push({ node: s, type: source_1.Source.runSyntax(s, input) });
43797
44152
  }
43798
44153
  }
43799
44154
  ////////////////////////////
@@ -43818,7 +44173,40 @@ class Perform {
43818
44173
  return;
43819
44174
  }
43820
44175
  input.scope.addReference(expr.getFirstToken(), found, _reference_1.ReferenceType.FormReference, input.filename);
43821
- // todo, also check parameters match
44176
+ ////////////////////////////
44177
+ // check parameters match
44178
+ // USING and CHANGING are interchangeable, the actual parameters form a single positional list
44179
+ if (this.checkParameters(node, tables, found.getTablesParameters(), "TABLES", input) === false) {
44180
+ return;
44181
+ }
44182
+ const formal = found.getUsingParameters().concat(found.getChangingParameters());
44183
+ this.checkParameters(node, using.concat(changing), formal, "USING/CHANGING", input);
44184
+ }
44185
+ // returns false if an issue was reported
44186
+ checkParameters(node, actual, formal, kind, input) {
44187
+ if (actual.length !== formal.length) {
44188
+ const message = `PERFORM, expected ${formal.length} ${kind} parameters, found ${actual.length}`;
44189
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
44190
+ return false;
44191
+ }
44192
+ const typeUtils = new _type_utils_1.TypeUtils(input.scope);
44193
+ for (let i = 0; i < actual.length; i++) {
44194
+ const { node: source, type } = actual[i];
44195
+ if (type === undefined) {
44196
+ continue;
44197
+ }
44198
+ const parameter = formal[i];
44199
+ const structureTyping = parameter.getMeta().includes("form_parameter_structure" /* IdentifierMeta.FormParameterStructure */);
44200
+ const assignable = structureTyping
44201
+ ? typeUtils.isAssignableStructureTyping(type, parameter.getType(), source)
44202
+ : typeUtils.isAssignableStrict(type, parameter.getType(), source);
44203
+ if (assignable === false) {
44204
+ const message = `PERFORM parameter type not compatible, ${parameter.getName()}`;
44205
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, source.getFirstToken(), message));
44206
+ return false;
44207
+ }
44208
+ }
44209
+ return true;
43822
44210
  }
43823
44211
  }
43824
44212
  exports.Perform = Perform;
@@ -46765,11 +47153,19 @@ const _typed_identifier_1 = __webpack_require__(/*! ../../types/_typed_identifie
46765
47153
  const identifier_1 = __webpack_require__(/*! ../../1_lexer/tokens/identifier */ "./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/identifier.js");
46766
47154
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/database_table.js");
46767
47155
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/dynamic.js");
47156
+ const _check_database_fields_1 = __webpack_require__(/*! ../expressions/_check_database_fields */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
46768
47157
  class UpdateDatabase {
46769
47158
  runSyntax(node, input) {
46770
47159
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
46771
47160
  if (dbtab !== undefined) {
46772
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
47161
+ const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
47162
+ const fields = node.findAllExpressions(Expressions.SQLFieldAndValue)
47163
+ .flatMap(fieldAndValue => fieldAndValue.findDirectExpressions(Expressions.SQLFieldName))
47164
+ .map(field => field.concatTokens().toUpperCase());
47165
+ fields.push(...node.findAllExpressions(Expressions.SQLCompare)
47166
+ .map(compare => { var _a; return (_a = compare.findDirectExpression(Expressions.SQLFieldName)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase(); })
47167
+ .filter(field => field !== undefined));
47168
+ (0, _check_database_fields_1.checkDatabaseFields)(fields, [dbSource], input, node.getFirstToken());
46773
47169
  }
46774
47170
  const tableName = node.findDirectExpression(Expressions.DatabaseTable);
46775
47171
  const tokenName = tableName === null || tableName === void 0 ? void 0 : tableName.getFirstToken();
@@ -48043,6 +48439,7 @@ const include_type_1 = __webpack_require__(/*! ../statements/include_type */ "./
48043
48439
  const type_1 = __webpack_require__(/*! ../statements/type */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/statements/type.js");
48044
48440
  const Basic = __importStar(__webpack_require__(/*! ../../types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js"));
48045
48441
  const _scope_type_1 = __webpack_require__(/*! ../_scope_type */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_scope_type.js");
48442
+ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
48046
48443
  class Types {
48047
48444
  runSyntax(node, input, qualifiedNamePrefix) {
48048
48445
  const name = node.findFirstExpression(Expressions.NamespaceSimpleName).getFirstToken();
@@ -48057,6 +48454,9 @@ class Types {
48057
48454
  if (ctyp instanceof Statements.Type) {
48058
48455
  const found = new type_1.Type().runSyntax(c, input, qualifiedNamePrefix + name.getStr() + "-");
48059
48456
  if (found) {
48457
+ if (found.getName().length > 30) {
48458
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, found.getToken(), "Structure field name longer than 30 characters"));
48459
+ }
48060
48460
  components.push({ name: found.getName(), type: found.getType() });
48061
48461
  }
48062
48462
  }
@@ -48073,6 +48473,9 @@ class Types {
48073
48473
  else if (c instanceof nodes_1.StructureNode && ctyp instanceof Structures.Types) {
48074
48474
  const found = new Types().runSyntax(c, input, qualifiedNamePrefix + name.getStr() + "-");
48075
48475
  if (found) {
48476
+ if (found.getName().length > 30) {
48477
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, found.getToken(), "Structure field name longer than 30 characters"));
48478
+ }
48076
48479
  components.push({ name: found.getName(), type: found.getType() });
48077
48480
  }
48078
48481
  }
@@ -51784,6 +52187,7 @@ const constants_1 = __webpack_require__(/*! ../5_syntax/structures/constants */
51784
52187
  const type_definitions_1 = __webpack_require__(/*! ./type_definitions */ "./node_modules/@abaplint/core/build/src/abap/types/type_definitions.js");
51785
52188
  const types_1 = __webpack_require__(/*! ../5_syntax/structures/types */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/structures/types.js");
51786
52189
  const type_1 = __webpack_require__(/*! ../5_syntax/statements/type */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/statements/type.js");
52190
+ const _syntax_input_1 = __webpack_require__(/*! ../5_syntax/_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
51787
52191
  const _reference_1 = __webpack_require__(/*! ../5_syntax/_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
51788
52192
  const alias_1 = __webpack_require__(/*! ./alias */ "./node_modules/@abaplint/core/build/src/abap/types/alias.js");
51789
52193
  class Attributes {
@@ -52005,6 +52409,13 @@ class Attributes {
52005
52409
  if (foundAttribute) {
52006
52410
  input.scope.addNamedIdentifier(aliasName.getStr(), foundAttribute);
52007
52411
  }
52412
+ const component = compName.split("~")[1];
52413
+ if (foundType === undefined
52414
+ && foundAttribute === undefined
52415
+ && this.existsInInterface(idef, component, input, []) === false) {
52416
+ const message = "Component " + component + " not found in interface " + idef.getName();
52417
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, compToken, message));
52418
+ }
52008
52419
  }
52009
52420
  else if (this.declaredInterfaces.includes(name.toUpperCase()) || input.scope.getDDIC().inErrorNamespace(name) === false) {
52010
52421
  input.scope.addReference(compToken, undefined, _reference_1.ReferenceType.ObjectOrientedVoidReference, input.filename);
@@ -52014,6 +52425,33 @@ class Attributes {
52014
52425
  }
52015
52426
  }
52016
52427
  }
52428
+ /** does the component exist in the interface, or in one of its aliases or included interfaces? */
52429
+ existsInInterface(idef, component, input, visited) {
52430
+ const upperName = idef.getName().toUpperCase();
52431
+ if (visited.includes(upperName)) {
52432
+ return false;
52433
+ }
52434
+ visited.push(upperName);
52435
+ const upper = component.toUpperCase();
52436
+ if (idef.getTypeDefinitions().getByName(component) !== undefined
52437
+ || idef.getAttributes().findByName(component) !== undefined
52438
+ || idef.getMethodDefinitions().getByName(component) !== undefined
52439
+ || idef.getEvents().some(e => e.getName().toUpperCase() === upper)
52440
+ || idef.getAliases().some(a => a.getName().toUpperCase() === upper)) {
52441
+ return true;
52442
+ }
52443
+ for (const i of idef.getImplementing()) {
52444
+ const sub = input.scope.findInterfaceDefinition(i.name);
52445
+ if (sub === undefined) {
52446
+ // voided or not found, assume the component exists
52447
+ return true;
52448
+ }
52449
+ else if (this.existsInInterface(sub, component, input, visited)) {
52450
+ return true;
52451
+ }
52452
+ }
52453
+ return false;
52454
+ }
52017
52455
  parseAttribute(node, visibility, input) {
52018
52456
  let found = undefined;
52019
52457
  const s = node.get();
@@ -52173,7 +52611,7 @@ class ClassDefinition extends _identifier_1.Identifier {
52173
52611
  this.checkEventNameConflicts(input);
52174
52612
  this.checkClassNameLength(input);
52175
52613
  this.checkMethodNameLength(input);
52176
- this.checkClassConstructorStatic(input);
52614
+ this.checkClassConstructor(input);
52177
52615
  }
52178
52616
  getFriends() {
52179
52617
  return this.friends;
@@ -52243,11 +52681,17 @@ class ClassDefinition extends _identifier_1.Identifier {
52243
52681
  }
52244
52682
  }
52245
52683
  }
52246
- checkClassConstructorStatic(input) {
52684
+ checkClassConstructor(input) {
52247
52685
  for (const m of this.methodDefs.getAll()) {
52248
- if (m.getName().toUpperCase() === "CLASS_CONSTRUCTOR" && m.isStatic() === false) {
52686
+ if (m.getName().toUpperCase() !== "CLASS_CONSTRUCTOR") {
52687
+ continue;
52688
+ }
52689
+ if (m.isStatic() === false) {
52249
52690
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, m.getToken(), "CLASS_CONSTRUCTOR must be static"));
52250
52691
  }
52692
+ else if (m.getVisibility() !== visibility_1.Visibility.Public) {
52693
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, m.getToken(), "CLASS_CONSTRUCTOR must be declared in the public section"));
52694
+ }
52251
52695
  }
52252
52696
  }
52253
52697
  checkInterfaceVisibility(input, node) {
@@ -52639,7 +53083,8 @@ class FormDefinition extends _identifier_1.Identifier {
52639
53083
  else if (!(type instanceof basic_1.UnknownType) && !(type instanceof basic_1.VoidType)) {
52640
53084
  type = new basic_1.UnknownType("FORM TABLES type must be table type");
52641
53085
  }
52642
- ret.push(new _typed_identifier_1.TypedIdentifier(p.getToken(), input.filename, type, ["form_parameter" /* IdentifierMeta.FormParameter */]));
53086
+ // keep the meta from FormParam, so STRUCTURE typing can be recognized later
53087
+ ret.push(new _typed_identifier_1.TypedIdentifier(p.getToken(), input.filename, type, p.getMeta()));
52643
53088
  }
52644
53089
  }
52645
53090
  return ret;
@@ -53412,6 +53857,7 @@ const _object_oriented_1 = __webpack_require__(/*! ../5_syntax/_object_oriented
53412
53857
  const _reference_1 = __webpack_require__(/*! ../5_syntax/_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
53413
53858
  const identifier_1 = __webpack_require__(/*! ../1_lexer/tokens/identifier */ "./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/identifier.js");
53414
53859
  const _scope_type_1 = __webpack_require__(/*! ../5_syntax/_scope_type */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_scope_type.js");
53860
+ const _syntax_input_1 = __webpack_require__(/*! ../5_syntax/_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
53415
53861
  // todo:
53416
53862
  // this.exceptions = [];
53417
53863
  // also consider RAISING vs EXCEPTIONS
@@ -53434,6 +53880,7 @@ class MethodParameters {
53434
53880
  input.scope.push(_scope_type_1.ScopeType.MethodDefinition, "method definition", node.getStart(), input.filename);
53435
53881
  try {
53436
53882
  this.parse(node, input, parentName, abstractMethod);
53883
+ this.checkNameLengths(input);
53437
53884
  this.checkDuplicateNames();
53438
53885
  }
53439
53886
  finally {
@@ -53585,6 +54032,13 @@ class MethodParameters {
53585
54032
  names.add(name);
53586
54033
  }
53587
54034
  }
54035
+ checkNameLengths(input) {
54036
+ for (const parameter of this.getAll()) {
54037
+ if (parameter.getName().length > 30) {
54038
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, parameter.getToken(), "Method parameter name longer than 30 characters"));
54039
+ }
54040
+ }
54041
+ }
53588
54042
  workaroundRAP(node, input, parentName) {
53589
54043
  const resultName = node.findExpressionAfterToken("RESULT");
53590
54044
  const concat = node.concatTokens().toUpperCase();
@@ -62875,6 +63329,7 @@ const _abstract_object_1 = __webpack_require__(/*! ./_abstract_object */ "./node
62875
63329
  const ddic_1 = __webpack_require__(/*! ../ddic */ "./node_modules/@abaplint/core/build/src/ddic.js");
62876
63330
  const Types = __importStar(__webpack_require__(/*! ../abap/types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js"));
62877
63331
  const xml_utils_1 = __webpack_require__(/*! ../xml_utils */ "./node_modules/@abaplint/core/build/src/xml_utils.js");
63332
+ const domain_1 = __webpack_require__(/*! ./domain */ "./node_modules/@abaplint/core/build/src/objects/domain.js");
62878
63333
  class DataElement extends _abstract_object_1.AbstractObject {
62879
63334
  constructor() {
62880
63335
  super(...arguments);
@@ -62905,6 +63360,22 @@ class DataElement extends _abstract_object_1.AbstractObject {
62905
63360
  this.parse();
62906
63361
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.domname;
62907
63362
  }
63363
+ /** parseType() cannot distinguish DEC, CURR, and QUAN because they all become PackedType.
63364
+ * Return the original DDIC datatype instead, resolving domain-backed data elements when possible. */
63365
+ getDataType(reg) {
63366
+ var _a, _b;
63367
+ this.parse();
63368
+ if ((_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.datatype) {
63369
+ return this.parsedXML.datatype;
63370
+ }
63371
+ if (reg && ((_b = this.parsedXML) === null || _b === void 0 ? void 0 : _b.refkind) === "D" && this.parsedXML.domname) {
63372
+ const domain = reg.getObject("DOMA", this.parsedXML.domname);
63373
+ if (domain instanceof domain_1.Domain) {
63374
+ return domain.getDataType();
63375
+ }
63376
+ }
63377
+ return undefined;
63378
+ }
62908
63379
  getTexts() {
62909
63380
  var _a;
62910
63381
  this.parse();
@@ -63188,6 +63659,11 @@ class Domain extends _abstract_object_1.AbstractObject {
63188
63659
  var _a;
63189
63660
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.conversionExit;
63190
63661
  }
63662
+ getDataType() {
63663
+ var _a;
63664
+ this.parse();
63665
+ return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.datatype;
63666
+ }
63191
63667
  getAllowedNaming() {
63192
63668
  return {
63193
63669
  maxLength: 30,
@@ -70119,7 +70595,7 @@ class Registry {
70119
70595
  }
70120
70596
  static abaplintVersion() {
70121
70597
  // magic, see build script "version.js"
70122
- return "2.120.23";
70598
+ return "2.120.37";
70123
70599
  }
70124
70600
  getDDICReferences() {
70125
70601
  return this.ddicReferences;
@@ -72783,6 +73259,379 @@ exports.CDSAssociationName = CDSAssociationName;
72783
73259
 
72784
73260
  /***/ },
72785
73261
 
73262
+ /***/ "./node_modules/@abaplint/core/build/src/rules/cds_check_syntax.js"
73263
+ /*!*************************************************************************!*\
73264
+ !*** ./node_modules/@abaplint/core/build/src/rules/cds_check_syntax.js ***!
73265
+ \*************************************************************************/
73266
+ (__unused_webpack_module, exports, __webpack_require__) {
73267
+
73268
+ "use strict";
73269
+
73270
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
73271
+ exports.CDSCheckSyntax = exports.CDSCheckSyntaxConf = void 0;
73272
+ const nodes_1 = __webpack_require__(/*! ../abap/nodes */ "./node_modules/@abaplint/core/build/src/abap/nodes/index.js");
73273
+ const basic_1 = __webpack_require__(/*! ../abap/types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
73274
+ const expressions_1 = __webpack_require__(/*! ../cds/expressions */ "./node_modules/@abaplint/core/build/src/cds/expressions/index.js");
73275
+ const ddic_1 = __webpack_require__(/*! ../ddic */ "./node_modules/@abaplint/core/build/src/ddic.js");
73276
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
73277
+ const objects_1 = __webpack_require__(/*! ../objects */ "./node_modules/@abaplint/core/build/src/objects/index.js");
73278
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
73279
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
73280
+ class CDSCheckSyntaxConf extends _basic_rule_config_1.BasicRuleConfig {
73281
+ }
73282
+ exports.CDSCheckSyntaxConf = CDSCheckSyntaxConf;
73283
+ const KNOWN_QUAN_DATA_ELEMENTS = ["MENGE_D"];
73284
+ const KNOWN_CURR_DATA_ELEMENTS = ["BWERT", "DZWERT"];
73285
+ // Reserved names, cannot be used as element names, see DDIC table TRESE
73286
+ const RESERVED_ELEMENT_NAMES = ["BEGIN", "NUMBER", "POSITION"];
73287
+ const MAX_LABEL_LENGTH = 40;
73288
+ // Annotations which are not supported in CDS view entities
73289
+ const VIEW_ENTITY_FORBIDDEN_ANNOTATIONS = ["Semantics.unitOfMeasure"];
73290
+ class CDSCheckSyntax {
73291
+ constructor() {
73292
+ this.conf = new CDSCheckSyntaxConf();
73293
+ }
73294
+ getMetadata() {
73295
+ return {
73296
+ key: "cds_check_syntax",
73297
+ title: "CDS Check Syntax",
73298
+ shortDescription: "Checks CDS source, field, type, and semantic annotation references",
73299
+ extendedInformation: `Performs semantic checks which require other DDIC objects to be available.
73300
+
73301
+ Missing objects are only reported when their names match the configured errorNamespace.`,
73302
+ tags: [_irule_1.RuleTag.Syntax],
73303
+ };
73304
+ }
73305
+ getConfig() {
73306
+ return this.conf;
73307
+ }
73308
+ setConfig(conf) {
73309
+ this.conf = conf;
73310
+ }
73311
+ initialize(reg) {
73312
+ this.reg = reg;
73313
+ return this;
73314
+ }
73315
+ run(object) {
73316
+ if (!(object instanceof objects_1.DataDefinition)) {
73317
+ return [];
73318
+ }
73319
+ const tree = object.getTree();
73320
+ const file = object.findSourceFile();
73321
+ if (tree === undefined || file === undefined) {
73322
+ return [];
73323
+ }
73324
+ const issues = [];
73325
+ const ddic = new ddic_1.DDIC(this.reg);
73326
+ const sources = this.findSources(tree, ddic, issues, file);
73327
+ this.checkRelations(tree, ddic, issues, file);
73328
+ this.checkTypes(tree, ddic, issues, file);
73329
+ this.checkRootProjection(tree, ddic, issues, file);
73330
+ this.checkFieldAnnotations(tree, ddic, issues, file);
73331
+ this.checkLabels(tree, issues, file);
73332
+ this.checkViewEntityAnnotations(tree, issues, file);
73333
+ this.checkReservedNames(tree, issues, file);
73334
+ this.checkFields(tree, sources, object, issues, file);
73335
+ return issues;
73336
+ }
73337
+ findSources(tree, ddic, issues, file) {
73338
+ var _a;
73339
+ const sources = [];
73340
+ for (const node of tree.findAllExpressionsRecursive(expressions_1.CDSSource)) {
73341
+ const prefixed = node.findDirectExpression(expressions_1.CDSPrefixedName);
73342
+ const entityNode = prefixed === null || prefixed === void 0 ? void 0 : prefixed.findDirectExpression(expressions_1.CDSName);
73343
+ if (entityNode === undefined) {
73344
+ continue;
73345
+ }
73346
+ const entity = this.name(entityNode);
73347
+ const asName = (_a = node.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
73348
+ const bareAlias = node.findDirectExpression(expressions_1.CDSName);
73349
+ const alias = asName === undefined ? bareAlias : asName;
73350
+ const lookup = ddic.lookupTableOrView(entity);
73351
+ if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(entity)) {
73352
+ issues.push(issue_1.Issue.atToken(file, entityNode.getFirstToken(), `CDS source "${entity}" not found`, this.getMetadata().key, this.conf.severity));
73353
+ }
73354
+ if (lookup.type instanceof basic_1.StructureType || lookup.type instanceof basic_1.UnknownType || lookup.type instanceof basic_1.VoidType) {
73355
+ const names = [entity.toUpperCase()];
73356
+ if (alias) {
73357
+ names.push(this.name(alias).toUpperCase());
73358
+ }
73359
+ sources.push({ entity, names, type: lookup.type });
73360
+ }
73361
+ }
73362
+ return sources;
73363
+ }
73364
+ checkRelations(tree, ddic, issues, file) {
73365
+ for (const relation of tree.findAllExpressionsRecursive(expressions_1.CDSRelation)) {
73366
+ const directTokens = relation.getDirectTokens();
73367
+ if (directTokens.length === 0) {
73368
+ continue;
73369
+ }
73370
+ const entity = directTokens.map(t => t.getStr()).join("");
73371
+ const lookup = ddic.lookupTableOrView(entity);
73372
+ if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(entity)) {
73373
+ issues.push(issue_1.Issue.atToken(file, directTokens[0], `CDS source "${entity}" not found`, this.getMetadata().key, this.conf.severity));
73374
+ }
73375
+ }
73376
+ }
73377
+ checkTypes(tree, ddic, issues, file) {
73378
+ for (const typeNode of tree.findAllExpressionsRecursive(expressions_1.CDSType)) {
73379
+ const typeName = typeNode.findDirectExpressions(expressions_1.CDSName).map(n => this.name(n)).join(".");
73380
+ if (typeName === "" || typeName.toUpperCase().startsWith("ABAP.")) {
73381
+ continue;
73382
+ }
73383
+ const lookup = ddic.lookup(typeName);
73384
+ if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(typeName)) {
73385
+ issues.push(issue_1.Issue.atToken(file, typeNode.getFirstToken(), `CDS type "${typeName}" not found`, this.getMetadata().key, this.conf.severity));
73386
+ }
73387
+ }
73388
+ }
73389
+ checkRootProjection(tree, ddic, issues, file) {
73390
+ var _a;
73391
+ const projection = tree.findFirstExpression(expressions_1.CDSDefineProjection);
73392
+ const rootToken = projection === null || projection === void 0 ? void 0 : projection.findDirectTokenByText("ROOT");
73393
+ if (projection === undefined || rootToken === undefined) {
73394
+ return;
73395
+ }
73396
+ const names = projection.findDirectExpressions(expressions_1.CDSName);
73397
+ const projectedEntityNode = names[1];
73398
+ if (projectedEntityNode === undefined) {
73399
+ return;
73400
+ }
73401
+ const projectedEntityName = this.name(projectedEntityNode);
73402
+ const projectedEntity = ddic.lookupTableOrView(projectedEntityName).object;
73403
+ if (projectedEntity instanceof objects_1.DataDefinition
73404
+ && ((_a = projectedEntity.getTree()) === null || _a === void 0 ? void 0 : _a.findDirectTokenByText("ROOT")) === undefined) {
73405
+ const message = `ROOT keyword not valid since ${projectedEntityName} is not a root property`;
73406
+ issues.push(issue_1.Issue.atToken(file, rootToken, message, this.getMetadata().key, this.conf.severity));
73407
+ }
73408
+ }
73409
+ checkFieldAnnotations(tree, ddic, issues, file) {
73410
+ const definition = tree.findFirstExpression(expressions_1.CDSDefineAbstract);
73411
+ if (definition === undefined) {
73412
+ return;
73413
+ }
73414
+ let definitionNameSeen = false;
73415
+ let fieldName;
73416
+ let annotations = [];
73417
+ const fields = [];
73418
+ for (const child of definition.getChildren()) {
73419
+ if (child instanceof nodes_1.TokenNode) {
73420
+ if (child.get().getStr() === ";") {
73421
+ fieldName = undefined;
73422
+ annotations = [];
73423
+ }
73424
+ continue;
73425
+ }
73426
+ else if (child.get() instanceof expressions_1.CDSAnnotation) {
73427
+ annotations.push(child);
73428
+ }
73429
+ else if (child.get() instanceof expressions_1.CDSName) {
73430
+ if (definitionNameSeen === false) {
73431
+ definitionNameSeen = true;
73432
+ annotations = [];
73433
+ }
73434
+ else {
73435
+ fieldName = child;
73436
+ }
73437
+ }
73438
+ else if (child.get() instanceof expressions_1.CDSType && fieldName !== undefined) {
73439
+ const semanticType = this.determineSemanticType(child, ddic);
73440
+ const normalizedAnnotations = annotations.map(a => a.concatTokens().replace(/\s/g, ""));
73441
+ fields.push({ name: this.name(fieldName), node: fieldName, annotations: normalizedAnnotations, semanticType });
73442
+ fieldName = undefined;
73443
+ annotations = [];
73444
+ }
73445
+ }
73446
+ const reportedCompanionFields = new Set();
73447
+ for (const field of fields) {
73448
+ if (field.semanticType === undefined) {
73449
+ continue;
73450
+ }
73451
+ const quantity = field.semanticType === "QUAN";
73452
+ const referenceAnnotation = quantity ? "@Semantics.quantity.unitOfMeasure" : "@Semantics.amount.currencyCode";
73453
+ const companionAnnotation = quantity ? "@Semantics.unitOfMeasure: true" : "@Semantics.currencyCode: true";
73454
+ const reference = this.findSemanticReference(field.annotations, field.semanticType);
73455
+ if (reference === undefined) {
73456
+ const kind = quantity ? "quantity" : "amount";
73457
+ const message = `CDS ${kind} field "${field.name}" requires ${referenceAnnotation}`;
73458
+ issues.push(issue_1.Issue.atToken(file, field.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
73459
+ continue;
73460
+ }
73461
+ const companion = fields.find(f => f.name.toUpperCase() === reference.toUpperCase());
73462
+ if (companion === undefined) {
73463
+ const kind = quantity ? "unit" : "currency";
73464
+ const message = `CDS field "${field.name}" references missing ${kind} field "${reference}"`;
73465
+ issues.push(issue_1.Issue.atToken(file, field.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
73466
+ continue;
73467
+ }
73468
+ const companionKey = field.semanticType + ":" + companion.name.toUpperCase();
73469
+ if (reportedCompanionFields.has(companionKey) === false
73470
+ && this.hasCompanionAnnotation(companion.annotations, field.semanticType) === false) {
73471
+ const message = `CDS field "${companion.name}" requires ${companionAnnotation}`;
73472
+ issues.push(issue_1.Issue.atToken(file, companion.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
73473
+ reportedCompanionFields.add(companionKey);
73474
+ }
73475
+ }
73476
+ }
73477
+ determineSemanticType(typeNode, ddic) {
73478
+ var _a;
73479
+ const typeName = typeNode.findDirectExpressions(expressions_1.CDSName).map(n => this.name(n)).join(".");
73480
+ const upper = typeName.toUpperCase();
73481
+ if (upper === "ABAP.QUAN" || KNOWN_QUAN_DATA_ELEMENTS.includes(upper)) {
73482
+ return "QUAN";
73483
+ }
73484
+ else if (upper === "ABAP.CURR" || KNOWN_CURR_DATA_ELEMENTS.includes(upper)) {
73485
+ return "CURR";
73486
+ }
73487
+ const object = ddic.lookup(typeName).object;
73488
+ if (object instanceof objects_1.DataElement) {
73489
+ const dataType = (_a = object.getDataType(this.reg)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
73490
+ if (dataType === "QUAN" || dataType === "CURR") {
73491
+ return dataType;
73492
+ }
73493
+ }
73494
+ return undefined;
73495
+ }
73496
+ findSemanticReference(annotations, type) {
73497
+ const expression = type === "QUAN"
73498
+ ? /(?:SEMANTICS\.QUANTITY|SEMANTICS:\{QUANTITY:\{)\.?UNITOFMEASURE:'([^']+)'/i
73499
+ : /(?:SEMANTICS\.AMOUNT|SEMANTICS:\{AMOUNT:\{)\.?CURRENCYCODE:'([^']+)'/i;
73500
+ for (const annotation of annotations) {
73501
+ const match = annotation.match(expression);
73502
+ if (match) {
73503
+ return match[1];
73504
+ }
73505
+ }
73506
+ return undefined;
73507
+ }
73508
+ hasCompanionAnnotation(annotations, type) {
73509
+ if (type === "QUAN") {
73510
+ return annotations.some(a => a.toUpperCase().includes("@SEMANTICS.UNITOFMEASURE:TRUE")
73511
+ || a.toUpperCase().includes("@SEMANTICS:{UNITOFMEASURE:TRUE"));
73512
+ }
73513
+ else {
73514
+ return annotations.some(a => a.toUpperCase().includes("@SEMANTICS.CURRENCYCODE:TRUE")
73515
+ || a.toUpperCase().includes("@SEMANTICS:{CURRENCYCODE:TRUE"));
73516
+ }
73517
+ }
73518
+ checkLabels(tree, issues, file) {
73519
+ for (const annotation of tree.findAllExpressionsRecursive(expressions_1.CDSAnnotation)) {
73520
+ const concatenated = annotation.concatTokens();
73521
+ if (/@\s*<?\s*EndUserText/i.test(concatenated) === false) {
73522
+ continue;
73523
+ }
73524
+ const expression = /label\s*:\s*'((?:[^']|'')*)'/gi;
73525
+ let match = expression.exec(concatenated);
73526
+ while (match !== null) {
73527
+ const label = match[1].replace(/''/g, "'");
73528
+ if (label.length > MAX_LABEL_LENGTH) {
73529
+ const message = `CDS label is ${label.length} characters, maximum is ${MAX_LABEL_LENGTH}`;
73530
+ issues.push(issue_1.Issue.atToken(file, annotation.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
73531
+ }
73532
+ match = expression.exec(concatenated);
73533
+ }
73534
+ }
73535
+ }
73536
+ checkViewEntityAnnotations(tree, issues, file) {
73537
+ const view = tree.findFirstExpression(expressions_1.CDSDefineView);
73538
+ if (view === undefined || view.findDirectTokenByText("ENTITY") === undefined) {
73539
+ return;
73540
+ }
73541
+ for (const annotation of tree.findAllExpressionsRecursive(expressions_1.CDSAnnotation)) {
73542
+ const normalized = annotation.concatTokens().replace(/\s/g, "").toUpperCase().replace(/^@</, "@");
73543
+ for (const forbidden of VIEW_ENTITY_FORBIDDEN_ANNOTATIONS) {
73544
+ const upper = forbidden.toUpperCase();
73545
+ if (normalized.startsWith("@" + upper) === false
73546
+ && normalized.startsWith("@" + upper.replace(".", ":{")) === false) {
73547
+ continue;
73548
+ }
73549
+ const message = `Annotation ${forbidden} is not allowed in view entities`;
73550
+ issues.push(issue_1.Issue.atToken(file, annotation.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
73551
+ }
73552
+ }
73553
+ }
73554
+ checkReservedNames(tree, issues, file) {
73555
+ var _a, _b;
73556
+ for (const element of tree.findAllExpressionsRecursive(expressions_1.CDSElement)) {
73557
+ if (element.findDirectTokenByText("INCLUDE") !== undefined) {
73558
+ continue;
73559
+ }
73560
+ let nameNode = (_a = element.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
73561
+ if (nameNode === undefined) {
73562
+ const names = ((_b = element.findDirectExpression(expressions_1.CDSPrefixedName)) === null || _b === void 0 ? void 0 : _b.findDirectExpressions(expressions_1.CDSName)) || [];
73563
+ nameNode = names[names.length - 1];
73564
+ }
73565
+ if (nameNode === undefined) {
73566
+ continue;
73567
+ }
73568
+ const name = this.name(nameNode);
73569
+ if (RESERVED_ELEMENT_NAMES.includes(name.toUpperCase())) {
73570
+ issues.push(issue_1.Issue.atToken(file, nameNode.getFirstToken(), `CDS element name "${name}" is reserved`, this.getMetadata().key, this.conf.severity));
73571
+ }
73572
+ }
73573
+ }
73574
+ checkFields(tree, sources, object, issues, file) {
73575
+ var _a;
73576
+ const associationNames = new Set();
73577
+ for (const association of ((_a = object.getParsedData()) === null || _a === void 0 ? void 0 : _a.associations) || []) {
73578
+ associationNames.add(association.name.toUpperCase());
73579
+ if (association.as) {
73580
+ associationNames.add(association.as.toUpperCase());
73581
+ }
73582
+ }
73583
+ for (const element of tree.findAllExpressionsRecursive(expressions_1.CDSElement)) {
73584
+ const prefixed = element.findDirectExpression(expressions_1.CDSPrefixedName);
73585
+ if (prefixed === undefined) {
73586
+ continue;
73587
+ }
73588
+ const names = prefixed.findDirectExpressions(expressions_1.CDSName);
73589
+ if (names.length === 0) {
73590
+ continue;
73591
+ }
73592
+ const first = this.name(names[0]);
73593
+ if (first === "*" || first.startsWith("$") || first.startsWith("#") || associationNames.has(first.toUpperCase())) {
73594
+ continue;
73595
+ }
73596
+ if (names.length > 1) {
73597
+ const matchingSources = sources.filter(s => s.names.includes(first.toUpperCase()));
73598
+ if (matchingSources.length !== 1) {
73599
+ continue;
73600
+ }
73601
+ const source = matchingSources[0];
73602
+ const sourceType = source.type;
73603
+ if (!(sourceType instanceof basic_1.StructureType)) {
73604
+ continue;
73605
+ }
73606
+ const field = this.name(names[1]);
73607
+ if (field !== "*" && sourceType.getComponentByName(field) === undefined) {
73608
+ issues.push(issue_1.Issue.atToken(file, names[1].getFirstToken(), `CDS field "${field}" not found in "${source.entity}"`, this.getMetadata().key, this.conf.severity));
73609
+ }
73610
+ continue;
73611
+ }
73612
+ // Do not guess across joins or when a dependency is absent.
73613
+ if (sources.length !== 1) {
73614
+ continue;
73615
+ }
73616
+ const source = sources[0];
73617
+ const sourceType = source.type;
73618
+ if (!(sourceType instanceof basic_1.StructureType)) {
73619
+ continue;
73620
+ }
73621
+ if (sourceType.getComponentByName(first) === undefined) {
73622
+ issues.push(issue_1.Issue.atToken(file, names[0].getFirstToken(), `CDS field "${first}" not found in "${source.entity}"`, this.getMetadata().key, this.conf.severity));
73623
+ }
73624
+ }
73625
+ }
73626
+ name(node) {
73627
+ return node.concatTokens().replace(/ /g, "");
73628
+ }
73629
+ }
73630
+ exports.CDSCheckSyntax = CDSCheckSyntax;
73631
+ //# sourceMappingURL=cds_check_syntax.js.map
73632
+
73633
+ /***/ },
73634
+
72786
73635
  /***/ "./node_modules/@abaplint/core/build/src/rules/cds_comment_style.js"
72787
73636
  /*!**************************************************************************!*\
72788
73637
  !*** ./node_modules/@abaplint/core/build/src/rules/cds_comment_style.js ***!
@@ -72950,7 +73799,8 @@ class CDSFieldOrder {
72950
73799
  }
72951
73800
  getAssociationNames(tree) {
72952
73801
  const names = new Set();
72953
- for (const assoc of tree.findAllExpressions(expressions_1.CDSAssociation)) {
73802
+ const found = [...tree.findAllExpressions(expressions_1.CDSAssociation), ...tree.findAllExpressions(expressions_1.CDSComposition)];
73803
+ for (const assoc of found) {
72954
73804
  const relation = assoc.findDirectExpression(expressions_1.CDSRelation);
72955
73805
  if (relation === undefined) {
72956
73806
  continue;
@@ -73068,7 +73918,6 @@ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/c
73068
73918
  const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
73069
73919
  const objects_1 = __webpack_require__(/*! ../objects */ "./node_modules/@abaplint/core/build/src/objects/index.js");
73070
73920
  const expressions_1 = __webpack_require__(/*! ../cds/expressions */ "./node_modules/@abaplint/core/build/src/cds/expressions/index.js");
73071
- const cds_name_1 = __webpack_require__(/*! ../cds/expressions/cds_name */ "./node_modules/@abaplint/core/build/src/cds/expressions/cds_name.js");
73072
73921
  class CDSNamingConf extends _basic_rule_config_1.BasicRuleConfig {
73073
73922
  constructor() {
73074
73923
  super(...arguments);
@@ -73140,7 +73989,7 @@ https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/ee6ff9b281d8448f96b4fe6c89f2bdc8
73140
73989
  if (file === undefined) {
73141
73990
  return [];
73142
73991
  }
73143
- const name = this.getCDSName(tree);
73992
+ const name = o.getDefinitionName();
73144
73993
  if (name === undefined) {
73145
73994
  return [];
73146
73995
  }
@@ -73157,13 +74006,6 @@ https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/ee6ff9b281d8448f96b4fe6c89f2bdc8
73157
74006
  }
73158
74007
  return [];
73159
74008
  }
73160
- getCDSName(tree) {
73161
- const nameNodes = tree.findDirectExpressions(cds_name_1.CDSName);
73162
- if (nameNodes.length > 0) {
73163
- return nameNodes[0].getFirstToken().getStr();
73164
- }
73165
- return undefined;
73166
- }
73167
74009
  getAllowedPrefixes(tree) {
73168
74010
  const root = tree.get();
73169
74011
  if (root instanceof expressions_1.CDSExtendView) {
@@ -75185,6 +76027,7 @@ class CloudTypes {
75185
76027
  || obj instanceof Objects.BehaviorDefinition
75186
76028
  || obj instanceof Objects.BusinessCatalog
75187
76029
  || obj instanceof Objects.BusinessCatalogAppAssignment
76030
+ || obj instanceof Objects.BusinessConfigurationMaintenanceObject
75188
76031
  || obj instanceof Objects.CDSMetadataExtension
75189
76032
  || obj instanceof Objects.Class
75190
76033
  || obj instanceof Objects.CDSType
@@ -75201,11 +76044,13 @@ class CloudTypes {
75201
76044
  || obj instanceof Objects.EventBinding
75202
76045
  || obj instanceof Objects.EventConsumer
75203
76046
  || obj instanceof Objects.FunctionGroup
76047
+ || obj instanceof Objects.GatewayODataGroupAndAssignment
75204
76048
  || obj instanceof Objects.HttpService
75205
76049
  || obj instanceof Objects.IAMApp
75206
76050
  || obj instanceof Objects.InboundService
75207
76051
  || obj instanceof Objects.Interface
75208
76052
  || obj instanceof Objects.LockObject
76053
+ || obj instanceof Objects.MaintenanceAndTransportObject
75209
76054
  || obj instanceof Objects.MessageClass
75210
76055
  || obj instanceof Objects.NumberRange
75211
76056
  || obj instanceof Objects.OutboundService
@@ -83877,6 +84722,7 @@ __exportStar(__webpack_require__(/*! ./begin_single_include */ "./node_modules/@
83877
84722
  __exportStar(__webpack_require__(/*! ./call_transaction_authority_check */ "./node_modules/@abaplint/core/build/src/rules/call_transaction_authority_check.js"), exports);
83878
84723
  __exportStar(__webpack_require__(/*! ./catch_and_raise */ "./node_modules/@abaplint/core/build/src/rules/catch_and_raise.js"), exports);
83879
84724
  __exportStar(__webpack_require__(/*! ./cds_association_name */ "./node_modules/@abaplint/core/build/src/rules/cds_association_name.js"), exports);
84725
+ __exportStar(__webpack_require__(/*! ./cds_check_syntax */ "./node_modules/@abaplint/core/build/src/rules/cds_check_syntax.js"), exports);
83880
84726
  __exportStar(__webpack_require__(/*! ./cds_comment_style */ "./node_modules/@abaplint/core/build/src/rules/cds_comment_style.js"), exports);
83881
84727
  __exportStar(__webpack_require__(/*! ./cds_field_order */ "./node_modules/@abaplint/core/build/src/rules/cds_field_order.js"), exports);
83882
84728
  __exportStar(__webpack_require__(/*! ./cds_legacy_view */ "./node_modules/@abaplint/core/build/src/rules/cds_legacy_view.js"), exports);
@@ -83970,6 +84816,7 @@ __exportStar(__webpack_require__(/*! ./newline_between_methods */ "./node_module
83970
84816
  __exportStar(__webpack_require__(/*! ./no_aliases */ "./node_modules/@abaplint/core/build/src/rules/no_aliases.js"), exports);
83971
84817
  __exportStar(__webpack_require__(/*! ./no_chained_assignment */ "./node_modules/@abaplint/core/build/src/rules/no_chained_assignment.js"), exports);
83972
84818
  __exportStar(__webpack_require__(/*! ./no_comments_between_methods */ "./node_modules/@abaplint/core/build/src/rules/no_comments_between_methods.js"), exports);
84819
+ __exportStar(__webpack_require__(/*! ./no_dynamic_stuff */ "./node_modules/@abaplint/core/build/src/rules/no_dynamic_stuff.js"), exports);
83973
84820
  __exportStar(__webpack_require__(/*! ./no_external_form_calls */ "./node_modules/@abaplint/core/build/src/rules/no_external_form_calls.js"), exports);
83974
84821
  __exportStar(__webpack_require__(/*! ./no_inline_in_optional_branches */ "./node_modules/@abaplint/core/build/src/rules/no_inline_in_optional_branches.js"), exports);
83975
84822
  __exportStar(__webpack_require__(/*! ./no_macros */ "./node_modules/@abaplint/core/build/src/rules/no_macros.js"), exports);
@@ -84049,6 +84896,7 @@ __exportStar(__webpack_require__(/*! ./when_others_last */ "./node_modules/@abap
84049
84896
  __exportStar(__webpack_require__(/*! ./whitespace_end */ "./node_modules/@abaplint/core/build/src/rules/whitespace_end.js"), exports);
84050
84897
  __exportStar(__webpack_require__(/*! ./xml_consistency */ "./node_modules/@abaplint/core/build/src/rules/xml_consistency.js"), exports);
84051
84898
  __exportStar(__webpack_require__(/*! ./no_exclamation_escape */ "./node_modules/@abaplint/core/build/src/rules/no_exclamation_escape.js"), exports);
84899
+ __exportStar(__webpack_require__(/*! ./xml_bom */ "./node_modules/@abaplint/core/build/src/rules/xml_bom.js"), exports);
84052
84900
  __exportStar(__webpack_require__(/*! ./no_exclamation_escape */ "./node_modules/@abaplint/core/build/src/rules/no_exclamation_escape.js"), exports);
84053
84901
  //# sourceMappingURL=index.js.map
84054
84902
 
@@ -88082,6 +88930,250 @@ exports.NoCommentsBetweenMethods = NoCommentsBetweenMethods;
88082
88930
 
88083
88931
  /***/ },
88084
88932
 
88933
+ /***/ "./node_modules/@abaplint/core/build/src/rules/no_dynamic_stuff.js"
88934
+ /*!*************************************************************************!*\
88935
+ !*** ./node_modules/@abaplint/core/build/src/rules/no_dynamic_stuff.js ***!
88936
+ \*************************************************************************/
88937
+ (__unused_webpack_module, exports, __webpack_require__) {
88938
+
88939
+ "use strict";
88940
+
88941
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
88942
+ if (k2 === undefined) k2 = k;
88943
+ var desc = Object.getOwnPropertyDescriptor(m, k);
88944
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
88945
+ desc = { enumerable: true, get: function() { return m[k]; } };
88946
+ }
88947
+ Object.defineProperty(o, k2, desc);
88948
+ }) : (function(o, m, k, k2) {
88949
+ if (k2 === undefined) k2 = k;
88950
+ o[k2] = m[k];
88951
+ }));
88952
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
88953
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
88954
+ }) : function(o, v) {
88955
+ o["default"] = v;
88956
+ });
88957
+ var __importStar = (this && this.__importStar) || (function () {
88958
+ var ownKeys = function(o) {
88959
+ ownKeys = Object.getOwnPropertyNames || function (o) {
88960
+ var ar = [];
88961
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
88962
+ return ar;
88963
+ };
88964
+ return ownKeys(o);
88965
+ };
88966
+ return function (mod) {
88967
+ if (mod && mod.__esModule) return mod;
88968
+ var result = {};
88969
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
88970
+ __setModuleDefault(result, mod);
88971
+ return result;
88972
+ };
88973
+ })();
88974
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
88975
+ exports.NoDynamicStuff = exports.NoDynamicStuffConf = void 0;
88976
+ const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
88977
+ const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
88978
+ const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@abaplint/core/build/src/rules/_abap_rule.js");
88979
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
88980
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
88981
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
88982
+ class NoDynamicStuffConf extends _basic_rule_config_1.BasicRuleConfig {
88983
+ constructor() {
88984
+ super(...arguments);
88985
+ /** Detects dynamic method calls, ie. CALL METHOD (name), SET HANDLER and CALL BADI */
88986
+ this.callMethod = true;
88987
+ /** Detects dynamic CALL FUNCTION, ie. the function module name is not a literal */
88988
+ this.callFunction = true;
88989
+ /** Detects CALL DATABASE PROCEDURE, the procedure name is always dynamic */
88990
+ this.callDatabaseProcedure = true;
88991
+ /** Detects dynamic CALL TRANSFORMATION */
88992
+ this.callTransformation = true;
88993
+ /** Detects dynamic CALL TRANSACTION, ie. the transaction code is not a literal */
88994
+ this.callTransaction = true;
88995
+ /** Detects dynamic PERFORM */
88996
+ this.perform = true;
88997
+ /** Detects dynamic SUBMIT */
88998
+ this.submit = true;
88999
+ /** Detects dynamic CREATE OBJECT */
89000
+ this.createObject = true;
89001
+ /** Detects dynamic CREATE DATA */
89002
+ this.createData = true;
89003
+ /** Detects dynamic GET BADI */
89004
+ this.getBadi = true;
89005
+ /** Detects dynamic ASSIGN, including ASSIGN COMPONENT */
89006
+ this.assign = true;
89007
+ /** Detects dynamic internal table access, ie. dynamic WHERE, keys, SORT BY and TRANSPORTING */
89008
+ this.internalTable = true;
89009
+ /** Detects dynamic EXPORT and IMPORT */
89010
+ this.exportImport = true;
89011
+ }
89012
+ }
89013
+ exports.NoDynamicStuffConf = NoDynamicStuffConf;
89014
+ class NoDynamicStuff extends _abap_rule_1.ABAPRule {
89015
+ constructor() {
89016
+ super(...arguments);
89017
+ this.conf = new NoDynamicStuffConf();
89018
+ }
89019
+ getMetadata() {
89020
+ return {
89021
+ key: "no_dynamic_stuff",
89022
+ title: "No dynamic stuff",
89023
+ shortDescription: `Detects dynamic calls and other dynamic language constructs`,
89024
+ extendedInformation: `Dynamic constructs cannot be checked statically, they are not found by
89025
+ where-used lists and refactorings, and they can introduce injection vulnerabilities.
89026
+
89027
+ Dynamic tokens are also reported when containing a literal, eg. CALL METHOD go_calendar->('RESET_DAY_INFO'),
89028
+ the syntax check does not resolve these either, so they behave like any other dynamic token.
89029
+
89030
+ Dynamic SQL is reported by rule dangerous_statement.`,
89031
+ tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Security],
89032
+ badExample: `CALL METHOD (lv_class)=>(lv_method).
89033
+ CALL METHOD go_calendar->('RESET_DAY_INFO').
89034
+ CALL FUNCTION lv_function_module.
89035
+ CREATE OBJECT ref TYPE (lv_class).
89036
+ ASSIGN (lv_name) TO <fs>.
89037
+ SORT tab BY (lv_field).`,
89038
+ goodExample: `cl_class=>method( ).
89039
+ go_calendar->reset_day_info( ).
89040
+ CALL FUNCTION 'ZFOO'.
89041
+ CREATE OBJECT ref TYPE cl_class.
89042
+ ASSIGN foo TO <fs>.
89043
+ SORT tab BY field.`,
89044
+ };
89045
+ }
89046
+ getConfig() {
89047
+ return this.conf;
89048
+ }
89049
+ setConfig(conf) {
89050
+ this.conf = conf;
89051
+ }
89052
+ runParsed(file) {
89053
+ const issues = [];
89054
+ for (const statementNode of file.getStatements()) {
89055
+ const found = this.check(statementNode);
89056
+ if (found !== undefined) {
89057
+ issues.push(issue_1.Issue.atStatement(file, statementNode, "Dynamic " + found, this.getMetadata().key, this.conf.severity));
89058
+ }
89059
+ }
89060
+ return issues;
89061
+ }
89062
+ check(node) {
89063
+ const statement = node.get();
89064
+ // note that MethodSource is also used by SET HANDLER and CALL BADI
89065
+ if (this.conf.callMethod === true && this.dynamicMethodSource(node) === true) {
89066
+ return "method call";
89067
+ }
89068
+ if (statement instanceof Statements.CallFunction) {
89069
+ if (this.conf.callFunction === true
89070
+ && this.notLiteral(node.findDirectExpression(Expressions.FunctionName))) {
89071
+ return "CALL FUNCTION";
89072
+ }
89073
+ }
89074
+ else if (statement instanceof Statements.CallDatabase) {
89075
+ if (this.conf.callDatabaseProcedure === true) {
89076
+ return "CALL DATABASE PROCEDURE";
89077
+ }
89078
+ }
89079
+ else if (statement instanceof Statements.CallTransformation) {
89080
+ if (this.conf.callTransformation === true && this.hasDynamic(node)) {
89081
+ return "CALL TRANSFORMATION";
89082
+ }
89083
+ }
89084
+ else if (statement instanceof Statements.CallTransaction) {
89085
+ // the transaction code is a Source, ie. there is no parenthesized dynamic variant
89086
+ if (this.conf.callTransaction === true
89087
+ && this.notLiteral(node.findDirectExpression(Expressions.Source))) {
89088
+ return "CALL TRANSACTION";
89089
+ }
89090
+ }
89091
+ else if (statement instanceof Statements.Perform) {
89092
+ if (this.conf.perform === true && this.hasDynamic(node)) {
89093
+ return "PERFORM";
89094
+ }
89095
+ }
89096
+ else if (statement instanceof Statements.Submit) {
89097
+ if (this.conf.submit === true && this.hasDynamic(node)) {
89098
+ return "SUBMIT";
89099
+ }
89100
+ }
89101
+ else if (statement instanceof Statements.CreateObject) {
89102
+ if (this.conf.createObject === true && this.hasDynamic(node)) {
89103
+ return "CREATE OBJECT";
89104
+ }
89105
+ }
89106
+ else if (statement instanceof Statements.CreateData) {
89107
+ if (this.conf.createData === true && this.hasDynamic(node)) {
89108
+ return "CREATE DATA";
89109
+ }
89110
+ }
89111
+ else if (statement instanceof Statements.GetBadi) {
89112
+ if (this.conf.getBadi === true && this.hasDynamic(node)) {
89113
+ return "GET BADI";
89114
+ }
89115
+ }
89116
+ else if (statement instanceof Statements.Assign
89117
+ || statement instanceof Statements.AssignLocalCopy) {
89118
+ if (this.conf.assign === true
89119
+ && (this.hasDynamic(node) || this.dynamicAssignComponent(node))) {
89120
+ return "ASSIGN";
89121
+ }
89122
+ }
89123
+ else if (statement instanceof Statements.Export) {
89124
+ if (this.conf.exportImport === true && this.hasDynamic(node)) {
89125
+ return "EXPORT";
89126
+ }
89127
+ }
89128
+ else if (statement instanceof Statements.Import) {
89129
+ if (this.conf.exportImport === true && this.hasDynamic(node)) {
89130
+ return "IMPORT";
89131
+ }
89132
+ }
89133
+ else if (statement instanceof Statements.At
89134
+ || statement instanceof Statements.DeleteInternal
89135
+ || statement instanceof Statements.InsertInternal
89136
+ || statement instanceof Statements.Loop
89137
+ || statement instanceof Statements.ModifyInternal
89138
+ || statement instanceof Statements.ReadTable
89139
+ || statement instanceof Statements.Sort
89140
+ || statement instanceof Statements.SortDataset) {
89141
+ if (this.conf.internalTable === true && this.hasDynamic(node)) {
89142
+ return "internal table access";
89143
+ }
89144
+ }
89145
+ return undefined;
89146
+ }
89147
+ dynamicMethodSource(node) {
89148
+ for (const source of node.findAllExpressions(Expressions.MethodSource)) {
89149
+ // Dynamic is always a direct child of MethodSource, dynamics further down
89150
+ // are parameters of the method call and not part of the method name
89151
+ if (source.findDirectExpression(Expressions.Dynamic) !== undefined) {
89152
+ return true;
89153
+ }
89154
+ }
89155
+ return false;
89156
+ }
89157
+ dynamicAssignComponent(node) {
89158
+ var _a;
89159
+ const component = (_a = node.findDirectExpression(Expressions.AssignSource)) === null || _a === void 0 ? void 0 : _a.findExpressionAfterToken("COMPONENT");
89160
+ return component !== undefined && this.isLiteral(component) === false;
89161
+ }
89162
+ hasDynamic(node) {
89163
+ return node.findFirstExpression(Expressions.Dynamic) !== undefined;
89164
+ }
89165
+ notLiteral(node) {
89166
+ return node !== undefined && this.isLiteral(node) === false;
89167
+ }
89168
+ isLiteral(node) {
89169
+ return node.findDirectExpression(Expressions.Constant) !== undefined;
89170
+ }
89171
+ }
89172
+ exports.NoDynamicStuff = NoDynamicStuff;
89173
+ //# sourceMappingURL=no_dynamic_stuff.js.map
89174
+
89175
+ /***/ },
89176
+
88085
89177
  /***/ "./node_modules/@abaplint/core/build/src/rules/no_exclamation_escape.js"
88086
89178
  /*!******************************************************************************!*\
88087
89179
  !*** ./node_modules/@abaplint/core/build/src/rules/no_exclamation_escape.js ***!
@@ -99275,6 +100367,64 @@ exports.WhitespaceEnd = WhitespaceEnd;
99275
100367
 
99276
100368
  /***/ },
99277
100369
 
100370
+ /***/ "./node_modules/@abaplint/core/build/src/rules/xml_bom.js"
100371
+ /*!****************************************************************!*\
100372
+ !*** ./node_modules/@abaplint/core/build/src/rules/xml_bom.js ***!
100373
+ \****************************************************************/
100374
+ (__unused_webpack_module, exports, __webpack_require__) {
100375
+
100376
+ "use strict";
100377
+
100378
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
100379
+ exports.XMLBOM = exports.XMLBOMConf = void 0;
100380
+ const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
100381
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
100382
+ const position_1 = __webpack_require__(/*! ../position */ "./node_modules/@abaplint/core/build/src/position.js");
100383
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
100384
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
100385
+ class XMLBOMConf extends _basic_rule_config_1.BasicRuleConfig {
100386
+ }
100387
+ exports.XMLBOMConf = XMLBOMConf;
100388
+ class XMLBOM {
100389
+ constructor() {
100390
+ this.conf = new XMLBOMConf();
100391
+ }
100392
+ getMetadata() {
100393
+ return {
100394
+ key: "xml_bom",
100395
+ title: "XML UTF-8 byte order mark",
100396
+ shortDescription: "Checks that XML files start with a UTF-8 byte order mark",
100397
+ extendedInformation: "Checks that each XML file has a UTF-8 byte order mark (BOM) at its beginning.",
100398
+ tags: [_irule_1.RuleTag.Syntax, _irule_1.RuleTag.Quickfix],
100399
+ };
100400
+ }
100401
+ getConfig() {
100402
+ return this.conf;
100403
+ }
100404
+ setConfig(conf) {
100405
+ this.conf = conf;
100406
+ }
100407
+ initialize(_reg) {
100408
+ return this;
100409
+ }
100410
+ run(obj) {
100411
+ const file = obj.getXMLFile();
100412
+ if (file === undefined || file.getRaw().startsWith("\uFEFF")) {
100413
+ return [];
100414
+ }
100415
+ return [this.createIssue(file)];
100416
+ }
100417
+ createIssue(file) {
100418
+ const start = new position_1.Position(1, 1);
100419
+ const fix = edit_helper_1.EditHelper.insertAt(file, start, "\uFEFF");
100420
+ return issue_1.Issue.atRange(file, start, start, "XML file must start with a UTF-8 byte order mark", this.getMetadata().key, this.conf.severity, fix);
100421
+ }
100422
+ }
100423
+ exports.XMLBOM = XMLBOM;
100424
+ //# sourceMappingURL=xml_bom.js.map
100425
+
100426
+ /***/ },
100427
+
99278
100428
  /***/ "./node_modules/@abaplint/core/build/src/rules/xml_consistency.js"
99279
100429
  /*!************************************************************************!*\
99280
100430
  !*** ./node_modules/@abaplint/core/build/src/rules/xml_consistency.js ***!
@@ -100007,6 +101157,10 @@ exports.DECLARATION_STUFF = [
100007
101157
  Statements.DataBegin,
100008
101158
  Statements.Constant,
100009
101159
  Statements.ConstantBegin,
101160
+ Statements.Static,
101161
+ Statements.StaticBegin,
101162
+ Statements.FieldSymbol,
101163
+ Statements.Ranges,
100010
101164
  Statements.Tables,
100011
101165
  Statements.Include, // this is not super correct, but anyhow
100012
101166
  Statements.Parameter,
@@ -105776,8 +106930,13 @@ class SQLCondTranspiler {
105776
106930
  sqlSource(source, traversal, filename, table) {
105777
106931
  let ret = "";
105778
106932
  const simple = source.findDirectExpression(abaplint.Expressions.SimpleSource3);
106933
+ const hostExpression = source.findDirectExpression(abaplint.Expressions.Source);
105779
106934
  const alias = source.findDirectExpression(abaplint.Expressions.SQLAliasField);
105780
- if (simple && simple.findDirectExpression(abaplint.Expressions.Constant) === undefined) {
106935
+ if (source.getFirstToken().getStr() === "@" && hostExpression) {
106936
+ const code = new source_1.SourceTranspiler(true).transpile(hostExpression, traversal).getCode();
106937
+ ret += "'\" + " + code + " + \"'";
106938
+ }
106939
+ else if (simple && simple.findDirectExpression(abaplint.Expressions.Constant) === undefined) {
105781
106940
  ret += "'\" + " + new simple_source3_1.SimpleSource3Transpiler(true).transpile(simple, traversal).getCode() + " + \"'";
105782
106941
  }
105783
106942
  else if (alias) {
@@ -109873,7 +111032,35 @@ class AuthorityCheckTranspiler {
109873
111032
  transpile(node, traversal) {
109874
111033
  const lookup = traversal.lookupClassOrInterface("KERNEL_AUTHORITY_CHECK", node.getFirstToken());
109875
111034
  const options = [];
109876
- // todo
111035
+ const object = node.findExpressionAfterToken("OBJECT");
111036
+ if (object) {
111037
+ options.push("object: " + traversal.traverse(object).getCode());
111038
+ }
111039
+ const user = node.findExpressionAfterToken("USER");
111040
+ if (user) {
111041
+ options.push("user: " + traversal.traverse(user).getCode());
111042
+ }
111043
+ const fields = [];
111044
+ const children = node.getChildren();
111045
+ for (let i = 0; i < children.length; i++) {
111046
+ if (children[i].concatTokens().toUpperCase() !== "ID") {
111047
+ continue;
111048
+ }
111049
+ const id = children[i + 1];
111050
+ const addition = children[i + 2]?.concatTokens().toUpperCase();
111051
+ if (id === undefined) {
111052
+ continue;
111053
+ }
111054
+ const field = ["id: " + traversal.traverse(id).getCode()];
111055
+ if (addition === "FIELD" && children[i + 3] !== undefined) {
111056
+ field.push("field: " + traversal.traverse(children[i + 3]).getCode());
111057
+ }
111058
+ else if (addition === "DUMMY") {
111059
+ field.push("dummy: true");
111060
+ }
111061
+ fields.push("{" + field.join(", ") + "}");
111062
+ }
111063
+ options.push("fields: [" + fields.join(", ") + "]");
109877
111064
  const call = `await ${lookup}.call({${options.join(",")}});`;
109878
111065
  return new chunk_1.Chunk().append(`if (${lookup} === undefined) throw new Error("AuthorityCheck, kernel class missing");\n${call}`, node, traversal);
109879
111066
  }
@@ -113787,6 +114974,7 @@ __exportStar(__webpack_require__(/*! ./generate_subroutine */ "./node_modules/@a
113787
114974
  __exportStar(__webpack_require__(/*! ./set_screen */ "./node_modules/@abaplint/transpiler/build/src/statements/set_screen.js"), exports);
113788
114975
  __exportStar(__webpack_require__(/*! ./set_titlebar */ "./node_modules/@abaplint/transpiler/build/src/statements/set_titlebar.js"), exports);
113789
114976
  __exportStar(__webpack_require__(/*! ./shift */ "./node_modules/@abaplint/transpiler/build/src/statements/shift.js"), exports);
114977
+ __exportStar(__webpack_require__(/*! ./skip */ "./node_modules/@abaplint/transpiler/build/src/statements/skip.js"), exports);
113790
114978
  __exportStar(__webpack_require__(/*! ./sort_dataset */ "./node_modules/@abaplint/transpiler/build/src/statements/sort_dataset.js"), exports);
113791
114979
  __exportStar(__webpack_require__(/*! ./sort */ "./node_modules/@abaplint/transpiler/build/src/statements/sort.js"), exports);
113792
114980
  __exportStar(__webpack_require__(/*! ./split */ "./node_modules/@abaplint/transpiler/build/src/statements/split.js"), exports);
@@ -116548,7 +117736,10 @@ class SelectTranspiler {
116548
117736
  else if (node.findFirstExpression(abaplint.Expressions.SQLIntoStructure)) {
116549
117737
  target = traversal.traverse(node.findFirstExpression(abaplint.Expressions.SQLIntoStructure)).getCode();
116550
117738
  }
116551
- let select = "SELECT ";
117739
+ const tokens = node.getTokens();
117740
+ const isDistinct = tokens[0]?.getStr().toUpperCase() === "SELECT"
117741
+ && tokens[1]?.getStr().toUpperCase() === "DISTINCT";
117742
+ let select = isDistinct ? "SELECT DISTINCT " : "SELECT ";
116552
117743
  const fieldList = node.findFirstExpression(abaplint.Expressions.SQLFieldList)
116553
117744
  || node.findFirstExpression(abaplint.Expressions.SQLFieldListLoop);
116554
117745
  if (fieldList === undefined) {
@@ -117207,6 +118398,68 @@ exports.ShiftTranspiler = ShiftTranspiler;
117207
118398
 
117208
118399
  /***/ },
117209
118400
 
118401
+ /***/ "./node_modules/@abaplint/transpiler/build/src/statements/skip.js"
118402
+ /*!************************************************************************!*\
118403
+ !*** ./node_modules/@abaplint/transpiler/build/src/statements/skip.js ***!
118404
+ \************************************************************************/
118405
+ (__unused_webpack_module, exports, __webpack_require__) {
118406
+
118407
+ "use strict";
118408
+
118409
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
118410
+ if (k2 === undefined) k2 = k;
118411
+ var desc = Object.getOwnPropertyDescriptor(m, k);
118412
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
118413
+ desc = { enumerable: true, get: function() { return m[k]; } };
118414
+ }
118415
+ Object.defineProperty(o, k2, desc);
118416
+ }) : (function(o, m, k, k2) {
118417
+ if (k2 === undefined) k2 = k;
118418
+ o[k2] = m[k];
118419
+ }));
118420
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
118421
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
118422
+ }) : function(o, v) {
118423
+ o["default"] = v;
118424
+ });
118425
+ var __importStar = (this && this.__importStar) || (function () {
118426
+ var ownKeys = function(o) {
118427
+ ownKeys = Object.getOwnPropertyNames || function (o) {
118428
+ var ar = [];
118429
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
118430
+ return ar;
118431
+ };
118432
+ return ownKeys(o);
118433
+ };
118434
+ return function (mod) {
118435
+ if (mod && mod.__esModule) return mod;
118436
+ var result = {};
118437
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
118438
+ __setModuleDefault(result, mod);
118439
+ return result;
118440
+ };
118441
+ })();
118442
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
118443
+ exports.SkipTranspiler = void 0;
118444
+ const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_modules/@abaplint/core/build/src/index.js"));
118445
+ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
118446
+ class SkipTranspiler {
118447
+ transpile(node, traversal) {
118448
+ const source = node.findDirectExpression(abaplint.Expressions.Source);
118449
+ if (source === undefined) {
118450
+ return new chunk_1.Chunk().append("abap.statements.skip();", node, traversal);
118451
+ }
118452
+ const option = node.concatTokens().toUpperCase().includes("TO LINE") ? "toLine" : "lines";
118453
+ return new chunk_1.Chunk().append("abap.statements.skip({" + option + ": ", node, traversal)
118454
+ .appendChunk(traversal.traverse(source))
118455
+ .append("});", node.getLastToken(), traversal);
118456
+ }
118457
+ }
118458
+ exports.SkipTranspiler = SkipTranspiler;
118459
+ //# sourceMappingURL=skip.js.map
118460
+
118461
+ /***/ },
118462
+
117210
118463
  /***/ "./node_modules/@abaplint/transpiler/build/src/statements/sort.js"
117211
118464
  /*!************************************************************************!*\
117212
118465
  !*** ./node_modules/@abaplint/transpiler/build/src/statements/sort.js ***!
@@ -119460,6 +120713,7 @@ const traversal_1 = __webpack_require__(/*! ../traversal */ "./node_modules/@aba
119460
120713
  const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
119461
120714
  const transpile_types_1 = __webpack_require__(/*! ../transpile_types */ "./node_modules/@abaplint/transpiler/build/src/transpile_types.js");
119462
120715
  const unique_identifier_1 = __webpack_require__(/*! ../unique_identifier */ "./node_modules/@abaplint/transpiler/build/src/unique_identifier.js");
120716
+ const inline_1 = __webpack_require__(/*! ../inline */ "./node_modules/@abaplint/transpiler/build/src/inline.js");
119463
120717
  class FunctionModuleTranspiler {
119464
120718
  transpile(node, traversal) {
119465
120719
  const chunk = new chunk_1.Chunk();
@@ -119472,6 +120726,7 @@ class FunctionModuleTranspiler {
119472
120726
  }
119473
120727
  chunk.append(`async function ${traversal_1.Traversal.escapeNamespace(name)}(INPUT) {\n`, c, traversal);
119474
120728
  chunk.appendString(this.findSignature(traversal, name, c));
120729
+ chunk.appendString(inline_1.InlineDeclarations.buildDeclarations(node, traversal));
119475
120730
  }
119476
120731
  else if (c.get() instanceof abaplint.Statements.EndFunction) {
119477
120732
  chunk.append("}\n", c, traversal);