@abaplint/core 2.120.45 → 2.120.46

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.
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.45";
78
+ return "2.120.46";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -17,7 +17,7 @@ class AllowedObjectNaming {
17
17
  key: "allowed_object_naming",
18
18
  title: "Allowed object naming",
19
19
  shortDescription: `Enforces basic name length and namespace restrictions, see note SAP 104010`,
20
- tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile],
20
+ tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Syntax],
21
21
  };
22
22
  }
23
23
  initialize(_reg) {
@@ -409,6 +409,10 @@ Make sure to test the downported code, it might not always be completely correct
409
409
  if (found) {
410
410
  return found;
411
411
  }
412
+ found = this.outlineTableExpressionKeyBuiltin(low, high, lowFile, highSyntax);
413
+ if (found) {
414
+ return found;
415
+ }
412
416
  found = this.assignWithTable(low, high, lowFile);
413
417
  if (found) {
414
418
  return found;
@@ -1106,6 +1110,69 @@ ${indentation}`);
1106
1110
  }
1107
1111
  return condition;
1108
1112
  }
1113
+ /** A built-in function is only recognized as one in an operand position that admits an
1114
+ * expression, and "WITH KEY comp = ..." does not become such a position until v740. The
1115
+ * table expression rewrites carry the key operand over verbatim, so
1116
+ * "tab[ comp = to_upper( x ) ]" downports to a READ TABLE that a 702 or 731 compiler can
1117
+ * only read as a functional method call - "method TO_UPPER is unknown", reported as a
1118
+ * SYNTAX_ERROR of the whole class pool. Hoist the call into a variable first, an
1119
+ * assignment IS an expression position at 702.
1120
+ *
1121
+ * Built-ins that predate 702 (lines, strlen, numofchar, ...) carry no release in
1122
+ * BuiltIn.methods; they are accepted in the operand as they are and stay untouched. So do
1123
+ * functional method calls, which are exactly the reading that makes the built-in fail, and
1124
+ * the INDEX operand of "tab[ 1 ]", which is not a key operand. */
1125
+ outlineTableExpressionKeyBuiltin(low, high, lowFile, highSyntax) {
1126
+ if (!(low.get() instanceof _statement_1.Unknown)) {
1127
+ return undefined;
1128
+ }
1129
+ for (const tableExpression of high.findAllExpressionsRecursive(Expressions.TableExpression)) {
1130
+ let afterComponent = false;
1131
+ for (const child of tableExpression.getChildren()) {
1132
+ if (child.get() instanceof Expressions.ComponentChainSimple) {
1133
+ afterComponent = true;
1134
+ continue;
1135
+ }
1136
+ else if (afterComponent === false
1137
+ || !(child.get() instanceof Expressions.Source)
1138
+ || !(child instanceof nodes_1.ExpressionNode)) {
1139
+ continue;
1140
+ }
1141
+ const type = this.builtinReturnType(child, lowFile, highSyntax);
1142
+ if (type === undefined) {
1143
+ continue;
1144
+ }
1145
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
1146
+ const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
1147
+ const code = `DATA ${uniqueName} TYPE ${type}.\n` +
1148
+ indentation + `${uniqueName} = ${child.concatTokens()}.\n` +
1149
+ indentation;
1150
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);
1151
+ const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, child.getFirstToken().getStart(), child.getLastToken().getEnd(), uniqueName);
1152
+ const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
1153
+ return issue_1.Issue.atToken(lowFile, child.getFirstToken(), "Outline built-in function in table expression key", this.getMetadata().key, this.conf.severity, fix);
1154
+ }
1155
+ }
1156
+ return undefined;
1157
+ }
1158
+ /** the ABAP type returned by the built-in function this Source starts with, or undefined
1159
+ * if it does not start with one, or with one that predates 702 */
1160
+ builtinReturnType(source, lowFile, highSyntax) {
1161
+ var _a, _b, _c;
1162
+ const spag = highSyntax.spaghetti.lookupPosition(source.getFirstToken().getStart(), lowFile.getFilename());
1163
+ for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {
1164
+ if (r.referenceType !== _reference_1.ReferenceType.BuiltinMethodReference
1165
+ || r.position.getStart().equals(source.getFirstToken().getStart()) === false) {
1166
+ continue;
1167
+ }
1168
+ const name = r.position.getName().toUpperCase();
1169
+ if (((_a = _builtin_1.BuiltIn.methods[name]) === null || _a === void 0 ? void 0 : _a.release) === undefined) {
1170
+ return undefined;
1171
+ }
1172
+ return (_c = (_b = _builtin_1.BuiltIn.searchBuiltin(name)) === null || _b === void 0 ? void 0 : _b.getParameters().getReturning()) === null || _c === void 0 ? void 0 : _c.getType().toABAP();
1173
+ }
1174
+ return undefined;
1175
+ }
1109
1176
  outlineCatchSimple(node, lowFile) {
1110
1177
  // outlines "CATCH cx_bcs INTO DATA(lx_bcs_excep).", note that this does not need to look at types
1111
1178
  var _a, _b;
@@ -2716,9 +2783,13 @@ ${indentation} output = ${uniqueName}.\n`;
2716
2783
  continue;
2717
2784
  }
2718
2785
  const uniqueName = this.uniqueName(i.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
2719
- const type = this.findType(i, lowFile, highSyntax);
2720
2786
  const indent = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
2721
- const abap = `DATA ${uniqueName} TYPE ${type}.\n` +
2787
+ // the CONV type might just be a component of the row type, so prefer the row type
2788
+ const rowOf = this.findRowTypeOf(high, i);
2789
+ const declaration = rowOf === undefined
2790
+ ? `DATA ${uniqueName} TYPE ${this.findType(i, lowFile, highSyntax)}.`
2791
+ : `DATA ${uniqueName} LIKE LINE OF ${rowOf}.`;
2792
+ const abap = declaration + "\n" +
2722
2793
  indent + `${uniqueName} = ${body}.\n` +
2723
2794
  indent;
2724
2795
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);
@@ -2728,6 +2799,19 @@ ${indentation} output = ${uniqueName}.\n`;
2728
2799
  }
2729
2800
  return undefined;
2730
2801
  }
2802
+ /** if the source expression is the complete source of an INSERT or APPEND statement, then the
2803
+ * outlined variable must be typed via the row type of the table, returns the table name */
2804
+ findRowTypeOf(high, source) {
2805
+ var _a;
2806
+ if (!(high.get() instanceof Statements.InsertInternal)
2807
+ && !(high.get() instanceof Statements.Append)) {
2808
+ return undefined;
2809
+ }
2810
+ else if (high.getChildren()[1] !== source) {
2811
+ return undefined;
2812
+ }
2813
+ return (_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.concatTokens();
2814
+ }
2731
2815
  // "CAST" to "?="
2732
2816
  outlineCast(low, high, lowFile, highSyntax) {
2733
2817
  var _a;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.120.45",
3
+ "version": "2.120.46",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",