@abaplint/cli 2.120.70 → 2.120.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/build/cli.js +584 -209
  2. package/package.json +2 -2
package/build/cli.js CHANGED
@@ -353,7 +353,7 @@ class Lexer {
353
353
  else if (this.m === ModeTemplate
354
354
  && this.buffer.length() > 1
355
355
  && (current === CH_PIPE || current === CH_LBRACE)
356
- && (stream.prevChar() !== CH_BACKSLASH || (stream.prevPrevChar() === CH_BACKSLASH && stream.prevChar() === CH_BACKSLASH))) {
356
+ && stream.countPrevious(CH_BACKSLASH) % 2 === 0) {
357
357
  // end of template
358
358
  if (current === CH_LBRACE || AFTER_LITERAL.has(ahead)) {
359
359
  this.add();
@@ -507,6 +507,14 @@ class LexerStream {
507
507
  }
508
508
  return this.raw.charCodeAt(o);
509
509
  }
510
+ /** number of consecutive occurrences of the character directly before the current one */
511
+ countPrevious(code) {
512
+ let count = 0;
513
+ for (let o = this.offset - 1; o >= 0 && this.raw.charCodeAt(o) === code; o--) {
514
+ count++;
515
+ }
516
+ return count;
517
+ }
510
518
  currentChar() {
511
519
  if (this.offset < 0) {
512
520
  return NL; // simulate newline at start of file to handle star(*) comments
@@ -10389,7 +10397,7 @@ class StringTemplateFormatting extends combi_1.Expression {
10389
10397
  const alpha = (0, combi_1.ver)(version_1.Release.v740sp02, (0, combi_1.seq)("ALPHA =", alphaOptions), { also: combi_1.AlsoIn.OpenABAP });
10390
10398
  const xsd = (0, combi_1.ver)(version_1.Release.v740sp02, (0, combi_1.seq)("XSD =", zeroXSDOptions));
10391
10399
  const country = (0, combi_1.seq)("COUNTRY =", _1.Source);
10392
- const formatting = (0, combi_1.altPrio)((0, combi_1.seq)("TIME =", dateTimeOptions), (0, combi_1.seq)("DATE =", dateTimeOptions), (0, combi_1.seq)("CASE =", caseOptions), (0, combi_1.seq)("EXPONENT", _1.Source), (0, combi_1.seq)("ZERO =", zeroXSDOptions), xsd, (0, combi_1.seq)("STYLE =", styleOptions), (0, combi_1.seq)("CURRENCY =", _1.Source), (0, combi_1.per)(sign, number, decimals, width, pad, alpha, align, country), (0, combi_1.per)(timezone, timestamp));
10400
+ const formatting = (0, combi_1.altPrio)((0, combi_1.seq)("TIME =", dateTimeOptions), (0, combi_1.seq)("DATE =", dateTimeOptions), (0, combi_1.seq)("CASE =", caseOptions), (0, combi_1.seq)("ZERO =", zeroXSDOptions), xsd, (0, combi_1.seq)("STYLE =", styleOptions), (0, combi_1.seq)("CURRENCY =", _1.Source), (0, combi_1.per)(sign, number, decimals, width, pad, alpha, align, country, (0, combi_1.seq)("EXPONENT =", _1.Source)), (0, combi_1.per)(timezone, timestamp));
10393
10401
  return formatting;
10394
10402
  }
10395
10403
  }
@@ -20506,6 +20514,21 @@ exports.sta = sta;
20506
20514
  exports.sub = sub;
20507
20515
  const nodes_1 = __webpack_require__(/*! ../../nodes */ "../core/build/src/abap/nodes/index.js");
20508
20516
  const _statement_1 = __webpack_require__(/*! ../../2_statements/statements/_statement */ "../core/build/src/abap/2_statements/statements/_statement.js");
20517
+ function toMatch(statements, m) {
20518
+ return {
20519
+ matched: statements.slice(0, m.next),
20520
+ unmatched: statements.slice(m.next),
20521
+ error: m.error,
20522
+ errorDescription: m.errorDescription,
20523
+ errorMatched: m.errorMatched,
20524
+ };
20525
+ }
20526
+ function success(next) {
20527
+ return { next, error: false, errorDescription: "", errorMatched: 0 };
20528
+ }
20529
+ function failure(next, errorDescription, errorMatched) {
20530
+ return { next, error: true, errorDescription, errorMatched };
20531
+ }
20509
20532
  class Sequence {
20510
20533
  constructor(list) {
20511
20534
  if (list.length < 2) {
@@ -20524,36 +20547,18 @@ class Sequence {
20524
20547
  return this.list[0].first();
20525
20548
  }
20526
20549
  run(statements, parent) {
20527
- let inn = statements;
20528
- let out = [];
20550
+ return toMatch(statements, this.runAt(statements, 0, parent));
20551
+ }
20552
+ runAt(statements, index, parent) {
20553
+ let next = index;
20529
20554
  for (const i of this.list) {
20530
- const match = i.run(inn, parent);
20555
+ const match = i.runAt(statements, next, parent);
20531
20556
  if (match.error) {
20532
- return {
20533
- matched: [],
20534
- unmatched: statements,
20535
- error: true,
20536
- errorDescription: match.errorDescription,
20537
- errorMatched: out.length,
20538
- };
20557
+ return failure(index, match.errorDescription, next - index);
20539
20558
  }
20540
- if (match.matched.length < 100) {
20541
- out.push(...match.matched);
20542
- }
20543
- else {
20544
- // avoid using the spread operator, it might trigger "Maximum call stack size exceeded"
20545
- // when the number of matched elements is very large
20546
- out = out.concat(match.matched);
20547
- }
20548
- inn = match.unmatched;
20559
+ next = match.next;
20549
20560
  }
20550
- return {
20551
- matched: out,
20552
- unmatched: inn,
20553
- error: false,
20554
- errorDescription: "",
20555
- errorMatched: 0,
20556
- };
20561
+ return success(next);
20557
20562
  }
20558
20563
  }
20559
20564
  // Note that the Alternative does not nessesarily return the first in the alternative
@@ -20592,21 +20597,18 @@ class Alternative {
20592
20597
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
20593
20598
  }
20594
20599
  run(statements, parent) {
20600
+ return toMatch(statements, this.runAt(statements, 0, parent));
20601
+ }
20602
+ runAt(statements, index, parent) {
20595
20603
  this.setupMap();
20596
20604
  let count = 0;
20597
20605
  let countError = "";
20598
- if (statements.length === 0) {
20599
- return {
20600
- matched: [],
20601
- unmatched: statements,
20602
- error: true,
20603
- errorDescription: countError,
20604
- errorMatched: count,
20605
- };
20606
+ if (index >= statements.length) {
20607
+ return failure(index, countError, count);
20606
20608
  }
20607
- const token = statements[0].getFirstToken().getStr().toUpperCase();
20609
+ const token = statements[index].getFirstToken().getStr().toUpperCase();
20608
20610
  for (const i of this.map[token] || []) {
20609
- const match = i.run(statements, parent);
20611
+ const match = i.runAt(statements, index, parent);
20610
20612
  if (match.error === false) {
20611
20613
  return match;
20612
20614
  }
@@ -20616,7 +20618,7 @@ class Alternative {
20616
20618
  }
20617
20619
  }
20618
20620
  for (const i of this.map[""] || []) {
20619
- const match = i.run(statements, parent);
20621
+ const match = i.runAt(statements, index, parent);
20620
20622
  if (match.error === false) {
20621
20623
  return match;
20622
20624
  }
@@ -20626,22 +20628,10 @@ class Alternative {
20626
20628
  }
20627
20629
  }
20628
20630
  if (count === 0) {
20629
- return {
20630
- matched: [],
20631
- unmatched: statements,
20632
- error: true,
20633
- errorDescription: "Unexpected code structure",
20634
- errorMatched: count,
20635
- };
20631
+ return failure(index, "Unexpected code structure", count);
20636
20632
  }
20637
20633
  else {
20638
- return {
20639
- matched: [],
20640
- unmatched: statements,
20641
- error: true,
20642
- errorDescription: countError,
20643
- errorMatched: count,
20644
- };
20634
+ return failure(index, countError, count);
20645
20635
  }
20646
20636
  }
20647
20637
  }
@@ -20656,7 +20646,10 @@ class Optional {
20656
20646
  return this.obj.getUsing();
20657
20647
  }
20658
20648
  run(statements, parent) {
20659
- const ret = this.obj.run(statements, parent);
20649
+ return toMatch(statements, this.runAt(statements, 0, parent));
20650
+ }
20651
+ runAt(statements, index, parent) {
20652
+ const ret = this.obj.runAt(statements, index, parent);
20660
20653
  ret.error = false;
20661
20654
  return ret;
20662
20655
  }
@@ -20675,48 +20668,24 @@ class Star {
20675
20668
  return this.obj.getUsing();
20676
20669
  }
20677
20670
  run(statements, parent) {
20678
- let inn = statements;
20679
- let out = [];
20671
+ return toMatch(statements, this.runAt(statements, 0, parent));
20672
+ }
20673
+ runAt(statements, index, parent) {
20674
+ let next = index;
20680
20675
  while (true) {
20681
- if (inn.length === 0) {
20682
- return {
20683
- matched: out,
20684
- unmatched: inn,
20685
- error: false,
20686
- errorDescription: "",
20687
- errorMatched: 0,
20688
- };
20676
+ if (next >= statements.length) {
20677
+ return success(next);
20689
20678
  }
20690
- const match = this.obj.run(inn, parent);
20679
+ const match = this.obj.runAt(statements, next, parent);
20691
20680
  if (match.error === true) {
20692
20681
  if (match.errorMatched > 0) {
20693
- return {
20694
- matched: out,
20695
- unmatched: inn,
20696
- error: true,
20697
- errorDescription: match.errorDescription,
20698
- errorMatched: match.errorMatched,
20699
- };
20682
+ return failure(next, match.errorDescription, match.errorMatched);
20700
20683
  }
20701
20684
  else {
20702
- return {
20703
- matched: out,
20704
- unmatched: inn,
20705
- error: false,
20706
- errorDescription: "",
20707
- errorMatched: 0,
20708
- };
20685
+ return success(next);
20709
20686
  }
20710
20687
  }
20711
- if (match.matched.length < 100) {
20712
- out.push(...match.matched);
20713
- }
20714
- else {
20715
- // avoid using the spread operator, it might trigger "Maximum call stack size exceeded"
20716
- // when the number of matched elements is very large
20717
- out = out.concat(match.matched);
20718
- }
20719
- inn = match.unmatched;
20688
+ next = match.next;
20720
20689
  }
20721
20690
  }
20722
20691
  first() {
@@ -20745,10 +20714,13 @@ class SubStructure {
20745
20714
  }
20746
20715
  }
20747
20716
  run(statements, parent) {
20717
+ return toMatch(statements, this.runAt(statements, 0, parent));
20718
+ }
20719
+ runAt(statements, index, parent) {
20748
20720
  const nparent = new nodes_1.StructureNode(this.s);
20749
20721
  this.setupMatcher();
20750
- const ret = this.matcher.run(statements, nparent);
20751
- if (ret.matched.length === 0) {
20722
+ const ret = this.matcher.runAt(statements, index, nparent);
20723
+ if (ret.next === index) {
20752
20724
  ret.error = true;
20753
20725
  }
20754
20726
  else {
@@ -20778,33 +20750,18 @@ class SubStatement {
20778
20750
  return this.obj.name;
20779
20751
  }
20780
20752
  run(statements, parent) {
20781
- if (statements.length === 0) {
20782
- return {
20783
- matched: [],
20784
- unmatched: [],
20785
- error: true,
20786
- errorDescription: "Expected " + this.className().toUpperCase(),
20787
- errorMatched: 0,
20788
- };
20753
+ return toMatch(statements, this.runAt(statements, 0, parent));
20754
+ }
20755
+ runAt(statements, index, parent) {
20756
+ if (index >= statements.length) {
20757
+ return failure(statements.length, "Expected " + this.className().toUpperCase(), 0);
20789
20758
  }
20790
- else if (statements[0].get() instanceof this.obj) {
20791
- parent.addChild(statements[0]);
20792
- return {
20793
- matched: [statements[0]],
20794
- unmatched: statements.splice(1),
20795
- error: false,
20796
- errorDescription: "",
20797
- errorMatched: 0,
20798
- };
20759
+ else if (statements[index].get() instanceof this.obj) {
20760
+ parent.addChild(statements[index]);
20761
+ return success(index + 1);
20799
20762
  }
20800
20763
  else {
20801
- return {
20802
- matched: [],
20803
- unmatched: statements,
20804
- error: true,
20805
- errorDescription: "Expected " + this.className().toUpperCase(),
20806
- errorMatched: 0,
20807
- };
20764
+ return failure(index, "Expected " + this.className().toUpperCase(), 0);
20808
20765
  }
20809
20766
  }
20810
20767
  }
@@ -28550,7 +28507,7 @@ class BasicTypes {
28550
28507
  if (children.length === 0) {
28551
28508
  return new Types.UnknownType("Type error, could not resolve \"" + fullName + "\", resolveLikeName1");
28552
28509
  }
28553
- let type = undefined;
28510
+ let type;
28554
28511
  if (children[1] && (children[1].getFirstToken().getStr() === "=>" || children[1].getFirstToken().getStr() === "->")) {
28555
28512
  type = field_chain_1.FieldChain.runSyntax(chain, this.input, _reference_1.ReferenceType.TypeReference);
28556
28513
  }
@@ -28813,7 +28770,7 @@ class BasicTypes {
28813
28770
  primaryKey: primaryKey,
28814
28771
  secondary: secondaryKeys,
28815
28772
  };
28816
- let found = undefined;
28773
+ let found;
28817
28774
  if (text.startsWith("TYPE TABLE OF REF TO ")
28818
28775
  || text.startsWith("TYPE STANDARD TABLE OF REF TO ")
28819
28776
  || text.startsWith("TYPE SORTED TABLE OF REF TO ")
@@ -28951,7 +28908,7 @@ class BasicTypes {
28951
28908
  name = typeName === null || typeName === void 0 ? void 0 : typeName.concatTokens();
28952
28909
  }
28953
28910
  const type = this.resolveLikeName(e, false);
28954
- let row = undefined;
28911
+ let row;
28955
28912
  if (type === undefined) {
28956
28913
  return new Types.UnknownType("Type error, could not resolve \"" + name + "\", parseType");
28957
28914
  }
@@ -29146,7 +29103,7 @@ class BasicTypes {
29146
29103
  rest = split[1];
29147
29104
  }
29148
29105
  const subs = rest.split("-");
29149
- let foundType = undefined;
29106
+ let foundType;
29150
29107
  if (className && chainText.includes("=>")) {
29151
29108
  const split = chainText.split("=>");
29152
29109
  const className = split[0];
@@ -29569,6 +29526,143 @@ function checkDatabaseFields(fields, dbSources, input, token) {
29569
29526
 
29570
29527
  /***/ },
29571
29528
 
29529
+ /***/ "../core/build/src/abap/5_syntax/expressions/_check_database_work_area.js"
29530
+ /*!********************************************************************************!*\
29531
+ !*** ../core/build/src/abap/5_syntax/expressions/_check_database_work_area.js ***!
29532
+ \********************************************************************************/
29533
+ (__unused_webpack_module, exports, __webpack_require__) {
29534
+
29535
+ "use strict";
29536
+
29537
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
29538
+ if (k2 === undefined) k2 = k;
29539
+ var desc = Object.getOwnPropertyDescriptor(m, k);
29540
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
29541
+ desc = { enumerable: true, get: function() { return m[k]; } };
29542
+ }
29543
+ Object.defineProperty(o, k2, desc);
29544
+ }) : (function(o, m, k, k2) {
29545
+ if (k2 === undefined) k2 = k;
29546
+ o[k2] = m[k];
29547
+ }));
29548
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29549
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29550
+ }) : function(o, v) {
29551
+ o["default"] = v;
29552
+ });
29553
+ var __importStar = (this && this.__importStar) || (function () {
29554
+ var ownKeys = function(o) {
29555
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29556
+ var ar = [];
29557
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29558
+ return ar;
29559
+ };
29560
+ return ownKeys(o);
29561
+ };
29562
+ return function (mod) {
29563
+ if (mod && mod.__esModule) return mod;
29564
+ var result = {};
29565
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
29566
+ __setModuleDefault(result, mod);
29567
+ return result;
29568
+ };
29569
+ })();
29570
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
29571
+ exports.checkDatabaseWorkArea = checkDatabaseWorkArea;
29572
+ const nodes_1 = __webpack_require__(/*! ../../nodes */ "../core/build/src/abap/nodes/index.js");
29573
+ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expressions */ "../core/build/src/abap/2_statements/expressions/index.js"));
29574
+ const Basic = __importStar(__webpack_require__(/*! ../../types/basic */ "../core/build/src/abap/types/basic/index.js"));
29575
+ const objects_1 = __webpack_require__(/*! ../../../objects */ "../core/build/src/objects/index.js");
29576
+ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
29577
+ // byte length of a flat type in a unicode system, as a lower and an upper bound:
29578
+ // IntegerType also stands for INT1 and INT2, and padding is left out of the lower bound
29579
+ function bounds(type) {
29580
+ if (type instanceof Basic.CharacterType || type instanceof Basic.NumericType) {
29581
+ return { min: type.getLength() * 2, max: type.getLength() * 2, align: 2 };
29582
+ }
29583
+ else if (type instanceof Basic.DateType) {
29584
+ return { min: 16, max: 16, align: 2 };
29585
+ }
29586
+ else if (type instanceof Basic.TimeType) {
29587
+ return { min: 12, max: 12, align: 2 };
29588
+ }
29589
+ else if (type instanceof Basic.IntegerType) {
29590
+ return { min: 1, max: 4, align: 4 };
29591
+ }
29592
+ else if (type instanceof Basic.Integer8Type || type instanceof Basic.FloatType
29593
+ || type instanceof Basic.DecFloat16Type || type instanceof Basic.UTCLongType) {
29594
+ return { min: 8, max: 8, align: 8 };
29595
+ }
29596
+ else if (type instanceof Basic.DecFloat34Type) {
29597
+ return { min: 16, max: 16, align: 16 };
29598
+ }
29599
+ else if (type instanceof Basic.PackedType || type instanceof Basic.HexType) {
29600
+ return { min: type.getLength(), max: type.getLength(), align: 1 };
29601
+ }
29602
+ else if (type instanceof Basic.StructureType) {
29603
+ let min = 0;
29604
+ let max = 0;
29605
+ let align = 1;
29606
+ for (const component of type.getComponents()) {
29607
+ const sub = bounds(component.type);
29608
+ if (sub === undefined) {
29609
+ return undefined;
29610
+ }
29611
+ align = Math.max(align, sub.align);
29612
+ max = Math.ceil(max / sub.align) * sub.align + sub.max;
29613
+ min = min + sub.min;
29614
+ }
29615
+ max = Math.ceil(max / align) * align;
29616
+ return { min, max, align };
29617
+ }
29618
+ // deep, generic, void or unknown
29619
+ return undefined;
29620
+ }
29621
+ // INSERT/MODIFY/UPDATE dbtab FROM wa: the work area must be at least as long as the table line,
29622
+ // client field included, else the statement is a syntax error on the system
29623
+ function checkDatabaseWorkArea(node, dbSource, sourceTypes, input) {
29624
+ var _a;
29625
+ if (!(dbSource instanceof objects_1.Table)) {
29626
+ return;
29627
+ }
29628
+ const children = node.getChildren();
29629
+ let workArea = undefined;
29630
+ for (let i = 0; i < children.length - 1; i++) {
29631
+ const child = children[i];
29632
+ if (child instanceof nodes_1.TokenNode && child.concatTokens().toUpperCase() === "FROM") {
29633
+ const next = children[i + 1];
29634
+ if (next instanceof nodes_1.ExpressionNode && next.get() instanceof Expressions.SQLSource) {
29635
+ workArea = next;
29636
+ }
29637
+ break;
29638
+ }
29639
+ }
29640
+ if (workArea === undefined) {
29641
+ return;
29642
+ }
29643
+ const source = (_a = workArea.findFirstExpression(Expressions.SimpleSource3)) !== null && _a !== void 0 ? _a : workArea.findFirstExpression(Expressions.Source);
29644
+ if (source === undefined) {
29645
+ return;
29646
+ }
29647
+ const waType = sourceTypes.get(source);
29648
+ if (!(waType instanceof Basic.StructureType)) {
29649
+ return;
29650
+ }
29651
+ const tableType = dbSource.parseType(input.scope.getRegistry());
29652
+ const waBounds = bounds(waType);
29653
+ const tableBounds = bounds(tableType);
29654
+ if (waBounds === undefined || tableBounds === undefined) {
29655
+ return;
29656
+ }
29657
+ if (waBounds.max < tableBounds.min) {
29658
+ const message = "The work area \"" + source.concatTokens() + "\" is not long enough for table " + dbSource.getName();
29659
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, source.getFirstToken(), message));
29660
+ }
29661
+ }
29662
+ //# sourceMappingURL=_check_database_work_area.js.map
29663
+
29664
+ /***/ },
29665
+
29572
29666
  /***/ "../core/build/src/abap/5_syntax/expressions/_check_offset_length.js"
29573
29667
  /*!***************************************************************************!*\
29574
29668
  !*** ../core/build/src/abap/5_syntax/expressions/_check_offset_length.js ***!
@@ -29890,7 +29984,7 @@ class AttributeName {
29890
29984
  return context;
29891
29985
  }
29892
29986
  const helper = new _object_oriented_1.ObjectOriented(input.scope);
29893
- let ret = undefined;
29987
+ let ret;
29894
29988
  if (context instanceof object_reference_type_1.ObjectReferenceType) {
29895
29989
  const def = input.scope.findObjectDefinition(context.getIdentifierName());
29896
29990
  if (def === undefined) {
@@ -30121,12 +30215,15 @@ var __importStar = (this && this.__importStar) || (function () {
30121
30215
  Object.defineProperty(exports, "__esModule", ({ value: true }));
30122
30216
  exports.Compare = void 0;
30123
30217
  const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expressions */ "../core/build/src/abap/2_statements/expressions/index.js"));
30218
+ const nodes_1 = __webpack_require__(/*! ../../nodes */ "../core/build/src/abap/nodes/index.js");
30124
30219
  const source_1 = __webpack_require__(/*! ./source */ "../core/build/src/abap/5_syntax/expressions/source.js");
30125
30220
  const method_call_chain_1 = __webpack_require__(/*! ./method_call_chain */ "../core/build/src/abap/5_syntax/expressions/method_call_chain.js");
30126
30221
  const source_field_symbol_1 = __webpack_require__(/*! ./source_field_symbol */ "../core/build/src/abap/5_syntax/expressions/source_field_symbol.js");
30127
30222
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
30128
30223
  const basic_1 = __webpack_require__(/*! ../../types/basic */ "../core/build/src/abap/types/basic/index.js");
30129
30224
  const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "../core/build/src/abap/5_syntax/_type_utils.js");
30225
+ const _builtin_1 = __webpack_require__(/*! ../_builtin */ "../core/build/src/abap/5_syntax/_builtin.js");
30226
+ const _object_oriented_1 = __webpack_require__(/*! ../_object_oriented */ "../core/build/src/abap/5_syntax/_object_oriented.js");
30130
30227
  class Compare {
30131
30228
  static runSyntax(node, input) {
30132
30229
  var _a;
@@ -30141,6 +30238,11 @@ class Compare {
30141
30238
  for (const t of node.findDirectExpressions(Expressions.MethodCallChain)) {
30142
30239
  method_call_chain_1.MethodCallChain.runSyntax(t, input);
30143
30240
  }
30241
+ const initialMessage = this.checkInitialOperand(node, input);
30242
+ if (initialMessage !== undefined) {
30243
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), initialMessage));
30244
+ return;
30245
+ }
30144
30246
  const typeUtils = new _type_utils_1.TypeUtils(input.scope);
30145
30247
  const compareOperator = (_a = node.findDirectExpression(Expressions.CompareOperator)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
30146
30248
  if (compareOperator === "CS"
@@ -30164,6 +30266,46 @@ class Compare {
30164
30266
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
30165
30267
  }
30166
30268
  }
30269
+ // a built-in function with a character-like result cannot be the operand of IS [NOT] INITIAL,
30270
+ // "Unexpected operator IS" on a system, while one with a numeric result, lines( ), can
30271
+ static checkInitialOperand(node, input) {
30272
+ var _a, _b, _c, _d;
30273
+ if (input.scope.getOpenABAP()) {
30274
+ return undefined;
30275
+ }
30276
+ const tokens = node.getChildren().filter(c => c instanceof nodes_1.TokenNode).map(c => c.getFirstToken().getStr().toUpperCase());
30277
+ if (tokens.includes("IS") === false || tokens[tokens.length - 1] !== "INITIAL") {
30278
+ return undefined;
30279
+ }
30280
+ const chain = (_a = node.findDirectExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.getChildren();
30281
+ // xsdbool( ) and boolc( ) are their own form in the Source grammar, a condition in parentheses
30282
+ const first = (_b = chain === null || chain === void 0 ? void 0 : chain[0]) === null || _b === void 0 ? void 0 : _b.getFirstToken().getStr().toUpperCase();
30283
+ if ((chain === null || chain === void 0 ? void 0 : chain.length) === 4 && chain[0] instanceof nodes_1.TokenNode && (first === "XSDBOOL" || first === "BOOLC")) {
30284
+ return `Built-in function "${chain[0].getFirstToken().getStr()}" cannot be the operand of IS INITIAL`;
30285
+ }
30286
+ if ((chain === null || chain === void 0 ? void 0 : chain.length) !== 1 || !(chain[0] instanceof nodes_1.ExpressionNode) || !(chain[0].get() instanceof Expressions.MethodCallChain)) {
30287
+ return undefined;
30288
+ }
30289
+ const calls = chain[0].getChildren();
30290
+ if (calls.length !== 1 || !(calls[0] instanceof nodes_1.ExpressionNode) || !(calls[0].get() instanceof Expressions.MethodCall)) {
30291
+ return undefined;
30292
+ }
30293
+ const name = (_c = calls[0].findDirectExpression(Expressions.MethodName)) === null || _c === void 0 ? void 0 : _c.concatTokens();
30294
+ const builtin = _builtin_1.BuiltIn.searchBuiltin(name);
30295
+ if (name === undefined || builtin === undefined) {
30296
+ return undefined;
30297
+ }
30298
+ // a method of the same name hides the built-in function
30299
+ const enclosing = input.scope.findClassDefinition(input.scope.getEnclosingClassName());
30300
+ if (enclosing !== undefined && new _object_oriented_1.ObjectOriented(input.scope).searchMethodName(enclosing, name).method !== undefined) {
30301
+ return undefined;
30302
+ }
30303
+ const returning = (_d = builtin.getParameters().getReturning()) === null || _d === void 0 ? void 0 : _d.getType();
30304
+ if (returning instanceof basic_1.StringType || returning instanceof basic_1.CharacterType) {
30305
+ return `Built-in function "${name}" cannot be the operand of IS INITIAL`;
30306
+ }
30307
+ return undefined;
30308
+ }
30167
30309
  }
30168
30310
  exports.Compare = Compare;
30169
30311
  //# sourceMappingURL=compare.js.map
@@ -30867,7 +31009,7 @@ const let_1 = __webpack_require__(/*! ./let */ "../core/build/src/abap/5_syntax/
30867
31009
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
30868
31010
  const basic_1 = __webpack_require__(/*! ../../types/basic */ "../core/build/src/abap/types/basic/index.js");
30869
31011
  class ConvBody {
30870
- static runSyntax(node, input) {
31012
+ static runSyntax(node, input, targetType) {
30871
31013
  let scoped = false;
30872
31014
  const l = node.findDirectExpression(Expressions.Let);
30873
31015
  if (l) {
@@ -30879,7 +31021,7 @@ class ConvBody {
30879
31021
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
30880
31022
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
30881
31023
  }
30882
- const sourceType = source_1.Source.runSyntax(s, input);
31024
+ const sourceType = source_1.Source.runSyntax(s, input, targetType);
30883
31025
  if (scoped === true) {
30884
31026
  input.scope.pop(node.getLastToken().getEnd());
30885
31027
  }
@@ -31412,7 +31554,7 @@ class FieldChain {
31412
31554
  return found.getType();
31413
31555
  }
31414
31556
  }
31415
- let context = undefined;
31557
+ let context;
31416
31558
  const children = node.getChildren();
31417
31559
  context = this.findTop(children[0], input, refType);
31418
31560
  let prev = children[0].concatTokens();
@@ -31905,7 +32047,7 @@ class FormParam {
31905
32047
  if (node.findDirectTokenByText("STRUCTURE") && nameToken) {
31906
32048
  // STRUCTURES typing
31907
32049
  const typeName = (_a = node.findDirectExpression(expressions_1.SimpleFieldChain)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr();
31908
- let type = undefined;
32050
+ let type;
31909
32051
  if (typeName) {
31910
32052
  type = (_b = input.scope.findType(typeName)) === null || _b === void 0 ? void 0 : _b.getType();
31911
32053
  if (type === undefined) {
@@ -33478,7 +33620,7 @@ class MethodParameters {
33478
33620
  }
33479
33621
  checkImporting(node, input, method) {
33480
33622
  for (const item of this.parameterListT(node, input)) {
33481
- let parameterType = undefined;
33623
+ let parameterType;
33482
33624
  if (method instanceof basic_1.VoidType) {
33483
33625
  parameterType = method;
33484
33626
  }
@@ -33515,7 +33657,7 @@ class MethodParameters {
33515
33657
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
33516
33658
  return;
33517
33659
  }
33518
- let parameterType = undefined;
33660
+ let parameterType;
33519
33661
  if (method instanceof basic_1.VoidType) {
33520
33662
  parameterType = method;
33521
33663
  }
@@ -34832,9 +34974,8 @@ class Select {
34832
34974
  }
34833
34975
  static findFields(node, input) {
34834
34976
  var _a, _b;
34835
- let expr = undefined;
34977
+ const expr = node.findFirstExpression(Expressions.SQLFieldList);
34836
34978
  const ret = [];
34837
- expr = node.findFirstExpression(Expressions.SQLFieldList);
34838
34979
  if (((_a = expr === null || expr === void 0 ? void 0 : expr.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.Dynamic) {
34839
34980
  dynamic_1.Dynamic.runSyntax(expr.getFirstChild(), input);
34840
34981
  }
@@ -34928,6 +35069,7 @@ const _typed_identifier_1 = __webpack_require__(/*! ../../types/_typed_identifie
34928
35069
  const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "../core/build/src/abap/5_syntax/_type_utils.js");
34929
35070
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
34930
35071
  const assert_error_1 = __webpack_require__(/*! ../assert_error */ "../core/build/src/abap/5_syntax/assert_error.js");
35072
+ const version_1 = __webpack_require__(/*! ../../../version */ "../core/build/src/version.js");
34931
35073
  /*
34932
35074
  * Type interference, valid scenarios:
34933
35075
  * typed = VALUE #( ... ). right hand side must follow left hand type
@@ -34940,7 +35082,7 @@ const assert_error_1 = __webpack_require__(/*! ../assert_error */ "../core/build
34940
35082
  // TODO: refactor all these method parameters to objects, this is getting messy
34941
35083
  class Source {
34942
35084
  static runSyntax(node, input, targetType, writeReference = false, allowGenericDeference = false, readReference = true) {
34943
- var _a;
35085
+ var _a, _b, _c, _d;
34944
35086
  if (node === undefined) {
34945
35087
  return undefined;
34946
35088
  }
@@ -35018,7 +35160,7 @@ class Source {
35018
35160
  case "CONV":
35019
35161
  {
35020
35162
  const foundType = this.determineType(node, input, targetType);
35021
- const bodyType = conv_body_1.ConvBody.runSyntax(node.findDirectExpression(Expressions.ConvBody), input);
35163
+ const bodyType = conv_body_1.ConvBody.runSyntax(node.findDirectExpression(Expressions.ConvBody), input, foundType);
35022
35164
  const inferred = (_a = node.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _a === void 0 ? void 0 : _a.concatTokens();
35023
35165
  if (new _type_utils_1.TypeUtils(input.scope).isConvable(foundType, bodyType) === false) {
35024
35166
  const message = `CONV: Types not compatible, ${foundType === null || foundType === void 0 ? void 0 : foundType.constructor.name}, ${bodyType === null || bodyType === void 0 ? void 0 : bodyType.constructor.name}`;
@@ -35035,7 +35177,13 @@ class Source {
35035
35177
  this.traverseRemainingChildren(children, input);
35036
35178
  return bodyType;
35037
35179
  }
35038
- this.addIfInferred(node, input, foundType);
35180
+ const bodySource = (_b = node.findDirectExpression(Expressions.ConvBody)) === null || _b === void 0 ? void 0 : _b.findDirectExpression(Expressions.Source);
35181
+ const nestedType = (_c = bodySource === null || bodySource === void 0 ? void 0 : bodySource.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _c === void 0 ? void 0 : _c.concatTokens();
35182
+ // CONV # passes its target type into a nested inferred constructor, so
35183
+ // showing both inferred types would produce duplicate inlay hints.
35184
+ if (!(inferred === "#" && nestedType === "#")) {
35185
+ this.addIfInferred(node, input, foundType);
35186
+ }
35039
35187
  this.traverseRemainingChildren(children, input);
35040
35188
  return foundType;
35041
35189
  }
@@ -35092,6 +35240,15 @@ class Source {
35092
35240
  case "CORRESPONDING":
35093
35241
  {
35094
35242
  const foundType = this.determineType(node, input, targetType);
35243
+ if ((foundType === null || foundType === void 0 ? void 0 : foundType.isGeneric()) === true
35244
+ && ((_d = node.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _d === void 0 ? void 0 : _d.concatTokens()) === "#"
35245
+ && !(0, version_1.releaseAtLeast)(input.scope.getRelease(), version_1.Release.v756)
35246
+ && input.scope.getLanguageVersion() !== version_1.LanguageVersion.Cloud
35247
+ && !input.scope.getOpenABAP()) {
35248
+ const message = "CORRESPONDING #, the type of the target is generic";
35249
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
35250
+ return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
35251
+ }
35095
35252
  corresponding_body_1.CorrespondingBody.runSyntax(node.findDirectExpression(Expressions.CorrespondingBody), input, foundType);
35096
35253
  this.addIfInferred(node, input, foundType);
35097
35254
  return foundType;
@@ -37737,6 +37894,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "../core/build/src/
37737
37894
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "../core/build/src/abap/5_syntax/expressions/dynamic.js");
37738
37895
  const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "../core/build/src/abap/5_syntax/_type_utils.js");
37739
37896
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
37897
+ const version_1 = __webpack_require__(/*! ../../../version */ "../core/build/src/version.js");
37740
37898
  class Assign {
37741
37899
  runSyntax(node, input) {
37742
37900
  var _a;
@@ -37744,7 +37902,7 @@ class Assign {
37744
37902
  const isComponent = ((_a = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getFirstChild()) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase()) === "COMPONENT";
37745
37903
  const sources = (assignSource === null || assignSource === void 0 ? void 0 : assignSource.findDirectExpressionsMulti([Expressions.Source, Expressions.SimpleSource3])) || [];
37746
37904
  const theSource = sources[sources.length - 1];
37747
- let sourceType = undefined;
37905
+ let sourceType;
37748
37906
  const firstAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[0];
37749
37907
  const secondAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[1];
37750
37908
  const thirdAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[2];
@@ -37760,6 +37918,19 @@ class Assign {
37760
37918
  }
37761
37919
  else {
37762
37920
  sourceType = source_1.Source.runSyntax(theSource, input, undefined, false, isComponent === false);
37921
+ if ((secondAssign === null || secondAssign === void 0 ? void 0 : secondAssign.concatTokens()) === "->"
37922
+ && (thirdAssign === null || thirdAssign === void 0 ? void 0 : thirdAssign.get()) instanceof Expressions.Dynamic
37923
+ && (sourceType === null || sourceType === void 0 ? void 0 : sourceType.isGeneric()) === true
37924
+ && !(sourceType instanceof basic_1.DataReference)
37925
+ && !(sourceType instanceof basic_1.ObjectReferenceType)
37926
+ && !(sourceType instanceof basic_1.GenericObjectReferenceType)
37927
+ && !(0, version_1.releaseAtLeast)(input.scope.getRelease(), version_1.Release.v756)
37928
+ && input.scope.getLanguageVersion() !== version_1.LanguageVersion.Cloud
37929
+ && !input.scope.getOpenABAP()) {
37930
+ const message = `"${theSource.concatTokens()}" is not a reference variable`;
37931
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
37932
+ return;
37933
+ }
37763
37934
  }
37764
37935
  if ((assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren().length) === 5
37765
37936
  && isComponent) {
@@ -42486,20 +42657,23 @@ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expr
42486
42657
  const source_1 = __webpack_require__(/*! ../expressions/source */ "../core/build/src/abap/5_syntax/expressions/source.js");
42487
42658
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "../core/build/src/abap/5_syntax/expressions/dynamic.js");
42488
42659
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "../core/build/src/abap/5_syntax/expressions/database_table.js");
42660
+ const _check_database_work_area_1 = __webpack_require__(/*! ../expressions/_check_database_work_area */ "../core/build/src/abap/5_syntax/expressions/_check_database_work_area.js");
42489
42661
  class InsertDatabase {
42490
42662
  runSyntax(node, input) {
42663
+ const sourceTypes = new Map();
42491
42664
  for (const s of node.findAllExpressions(Expressions.Source)) {
42492
- source_1.Source.runSyntax(s, input);
42665
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
42493
42666
  }
42494
42667
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
42495
- source_1.Source.runSyntax(s, input);
42668
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
42496
42669
  }
42497
42670
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
42498
42671
  dynamic_1.Dynamic.runSyntax(d, input);
42499
42672
  }
42500
42673
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
42501
42674
  if (dbtab !== undefined) {
42502
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
42675
+ const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
42676
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
42503
42677
  }
42504
42678
  }
42505
42679
  }
@@ -43085,7 +43259,7 @@ class Loop {
43085
43259
  && topType instanceof basic_1.TableType) {
43086
43260
  // https://github.com/abap2xlsx/abap2xlsx/issues/1341
43087
43261
  const keyName = node.findExpressionAfterToken("KEY");
43088
- let key = undefined;
43262
+ let key;
43089
43263
  const name = (keyName === null || keyName === void 0 ? void 0 : keyName.get()) instanceof Expressions.SimpleName ? keyName.getFirstToken().getStr().toUpperCase() : undefined;
43090
43264
  // it might be dynamic, in that case we cannot check anything; and
43091
43265
  // primary_key is the predefined name of the primary key every table has
@@ -43442,11 +43616,13 @@ const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "../core/bui
43442
43616
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "../core/build/src/abap/5_syntax/expressions/database_table.js");
43443
43617
  const source_1 = __webpack_require__(/*! ../expressions/source */ "../core/build/src/abap/5_syntax/expressions/source.js");
43444
43618
  const _reference_1 = __webpack_require__(/*! ../_reference */ "../core/build/src/abap/5_syntax/_reference.js");
43619
+ const _check_database_work_area_1 = __webpack_require__(/*! ../expressions/_check_database_work_area */ "../core/build/src/abap/5_syntax/expressions/_check_database_work_area.js");
43445
43620
  class ModifyDatabase {
43446
43621
  runSyntax(node, input) {
43447
43622
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
43448
43623
  dynamic_1.Dynamic.runSyntax(d, input);
43449
43624
  }
43625
+ let dbSource = undefined;
43450
43626
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
43451
43627
  if (dbtab !== undefined) {
43452
43628
  if (node.getChildren().length === 5) {
@@ -43455,19 +43631,21 @@ class ModifyDatabase {
43455
43631
  input.scope.addReference(dbtab.getFirstToken(), found, _reference_1.ReferenceType.DataWriteReference, input.filename);
43456
43632
  }
43457
43633
  else {
43458
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
43634
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
43459
43635
  }
43460
43636
  }
43461
43637
  else {
43462
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
43638
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
43463
43639
  }
43464
43640
  }
43641
+ const sourceTypes = new Map();
43465
43642
  for (const s of node.findAllExpressions(Expressions.Source)) {
43466
- source_1.Source.runSyntax(s, input);
43643
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
43467
43644
  }
43468
43645
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
43469
- source_1.Source.runSyntax(s, input);
43646
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
43470
43647
  }
43648
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
43471
43649
  }
43472
43650
  }
43473
43651
  exports.ModifyDatabase = ModifyDatabase;
@@ -47367,11 +47545,13 @@ const identifier_1 = __webpack_require__(/*! ../../1_lexer/tokens/identifier */
47367
47545
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "../core/build/src/abap/5_syntax/expressions/database_table.js");
47368
47546
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "../core/build/src/abap/5_syntax/expressions/dynamic.js");
47369
47547
  const _check_database_fields_1 = __webpack_require__(/*! ../expressions/_check_database_fields */ "../core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
47548
+ const _check_database_work_area_1 = __webpack_require__(/*! ../expressions/_check_database_work_area */ "../core/build/src/abap/5_syntax/expressions/_check_database_work_area.js");
47370
47549
  class UpdateDatabase {
47371
47550
  runSyntax(node, input) {
47551
+ let dbSource = undefined;
47372
47552
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
47373
47553
  if (dbtab !== undefined) {
47374
- const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
47554
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
47375
47555
  const fields = node.findAllExpressions(Expressions.SQLFieldAndValue)
47376
47556
  .flatMap(fieldAndValue => fieldAndValue.findDirectExpressions(Expressions.SQLFieldName))
47377
47557
  .map(field => field.concatTokens().toUpperCase());
@@ -47394,15 +47574,17 @@ class UpdateDatabase {
47394
47574
  }
47395
47575
  }
47396
47576
  }
47577
+ const sourceTypes = new Map();
47397
47578
  for (const s of node.findAllExpressions(Expressions.Source)) {
47398
- source_1.Source.runSyntax(s, input);
47579
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
47399
47580
  }
47400
47581
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
47401
- source_1.Source.runSyntax(s, input);
47582
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
47402
47583
  }
47403
47584
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
47404
47585
  dynamic_1.Dynamic.runSyntax(d, input);
47405
47586
  }
47587
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
47406
47588
  if (input.scope.getType() === _scope_type_1.ScopeType.OpenSQL) {
47407
47589
  input.scope.pop(node.getLastToken().getEnd());
47408
47590
  }
@@ -47591,7 +47773,7 @@ class WhenType {
47591
47773
  if (nameToken === undefined) {
47592
47774
  return undefined;
47593
47775
  }
47594
- let type = undefined;
47776
+ let type;
47595
47777
  const className = nameToken.getStr().toUpperCase();
47596
47778
  const found = input.scope.existsObject(className);
47597
47779
  if (found === null || found === void 0 ? void 0 : found.id) {
@@ -52715,7 +52897,7 @@ class Attributes {
52715
52897
  return false;
52716
52898
  }
52717
52899
  parseAttribute(node, visibility, input) {
52718
- let found = undefined;
52900
+ let found;
52719
52901
  const s = node.get();
52720
52902
  if (s instanceof Statements.Data) {
52721
52903
  found = new data_1.Data().runSyntax(node, input);
@@ -54891,7 +55073,7 @@ class CDSLexer {
54891
55073
  break;
54892
55074
  case "@":
54893
55075
  // @ starts a new annotation; flush current token and start building with @
54894
- build = result.add(build, row, col, mode);
55076
+ result.add(build, row, col, mode);
54895
55077
  build = "@";
54896
55078
  break;
54897
55079
  default:
@@ -59765,7 +59947,7 @@ class Help {
59765
59947
  return content;
59766
59948
  }
59767
59949
  static dumpABAP(file, reg, textDocument, position) {
59768
- let content = "";
59950
+ let content;
59769
59951
  content = `
59770
59952
  <a href="#_tokens" rel="no-refresh">Tokens</a> |
59771
59953
  <a href="#_statements" rel="no-refresh">Statements</a> |
@@ -59798,7 +59980,7 @@ class Help {
59798
59980
  return `<h3 id="_info">Info Dump</h3><pre>` + text + "</pre>";
59799
59981
  }
59800
59982
  static cursorInformation(reg, textDocument, position, file) {
59801
- let ret = "";
59983
+ let ret;
59802
59984
  const found = _lsp_utils_1.LSPUtils.findCursor(reg, { textDocument, position });
59803
59985
  if (found !== undefined) {
59804
59986
  ret = "Statement: " + this.linkToStatement(found.snode.get()) + "<br>\n" +
@@ -63556,7 +63738,7 @@ class DataElement extends _abstract_object_1.AbstractObject {
63556
63738
  }
63557
63739
  parseType(reg) {
63558
63740
  const references = [];
63559
- let lookup = undefined;
63741
+ let lookup;
63560
63742
  this.parse();
63561
63743
  if (this.parsedXML === undefined) {
63562
63744
  lookup = { type: new Types.UnknownType("Data Element " + this.getName() + ", parser error") };
@@ -69007,6 +69189,7 @@ class Table extends _abstract_object_1.AbstractObject {
69007
69189
  PRECFIELD: field.PRECFIELD,
69008
69190
  LENG: field.LENG,
69009
69191
  INTLEN: field.INTLEN,
69192
+ INTTYPE: field.INTTYPE,
69010
69193
  DATATYPE: field.DATATYPE,
69011
69194
  DECIMALS: field.DECIMALS,
69012
69195
  KEYFLAG: field.KEYFLAG,
@@ -70525,7 +70708,7 @@ class Registry {
70525
70708
  }
70526
70709
  static abaplintVersion() {
70527
70710
  // magic, see build script "version.js"
70528
- return "2.120.70";
70711
+ return "2.120.72";
70529
70712
  }
70530
70713
  getDDICReferences() {
70531
70714
  return this.ddicReferences;
@@ -71873,7 +72056,7 @@ class AlignPseudoComments extends _abap_rule_1.ABAPRule {
71873
72056
  }
71874
72057
  const col = firstCommentToken.getStart().getCol();
71875
72058
  if (previousEnd.getCol() < expectedColumn && col !== expectedColumn) {
71876
- let fix = undefined;
72059
+ let fix;
71877
72060
  if (col < expectedColumn) {
71878
72061
  fix = edit_helper_1.EditHelper.insertAt(file, firstCommentToken.getStart(), " ".repeat(expectedColumn - col));
71879
72062
  }
@@ -72040,7 +72223,7 @@ ENDINTERFACE.`,
72040
72223
  if (f.after.getCol() === column) {
72041
72224
  continue;
72042
72225
  }
72043
- let fix = undefined;
72226
+ let fix;
72044
72227
  if (f.after.getCol() < column) {
72045
72228
  fix = edit_helper_1.EditHelper.insertAt(file, f.after, " ".repeat(column - f.after.getCol()));
72046
72229
  }
@@ -73214,7 +73397,7 @@ exports.CDSCheckSyntaxConf = CDSCheckSyntaxConf;
73214
73397
  const KNOWN_QUAN_DATA_ELEMENTS = ["MENGE_D"];
73215
73398
  const KNOWN_CURR_DATA_ELEMENTS = ["BWERT", "DZWERT"];
73216
73399
  // Reserved names, cannot be used as element names, see DDIC table TRESE
73217
- const RESERVED_ELEMENT_NAMES = ["BEGIN", "NUMBER", "POSITION"];
73400
+ const RESERVED_ELEMENT_NAMES = ["BEGIN", "NUMBER", "POSITION", "ZONE", "HANDLER", "SECTION"];
73218
73401
  const MAX_LABEL_LENGTH = 40;
73219
73402
  // Annotations which are not supported in CDS view entities
73220
73403
  const VIEW_ENTITY_FORBIDDEN_ANNOTATIONS = ["Semantics.unitOfMeasure", "Semantics.currencyCode"];
@@ -74431,7 +74614,7 @@ ENDCASE.`,
74431
74614
  if (tuples.length === 1) {
74432
74615
  return false;
74433
74616
  }
74434
- let chain = "";
74617
+ let chain;
74435
74618
  if (tuples[0].left === tuples[1].left) {
74436
74619
  chain = tuples[0].left;
74437
74620
  }
@@ -74720,7 +74903,7 @@ class CheckDDIC {
74720
74903
  this.conf = conf;
74721
74904
  }
74722
74905
  run(obj) {
74723
- let found = undefined;
74906
+ let found;
74724
74907
  if (obj instanceof Objects.DataElement
74725
74908
  || obj instanceof Objects.Domain
74726
74909
  || obj instanceof Objects.Table
@@ -75444,7 +75627,6 @@ ENDCLASS.`,
75444
75627
  this.conf = conf;
75445
75628
  }
75446
75629
  runParsed(file, obj) {
75447
- let issues = [];
75448
75630
  if (this.conf.patternKind === undefined) {
75449
75631
  this.conf.patternKind = "required";
75450
75632
  }
@@ -75465,8 +75647,7 @@ ENDCLASS.`,
75465
75647
  attributes = attributes.concat(intfDef.attributes);
75466
75648
  }
75467
75649
  }
75468
- issues = this.checkAttributes(attributes);
75469
- return issues;
75650
+ return this.checkAttributes(attributes);
75470
75651
  }
75471
75652
  checkAttributes(attr) {
75472
75653
  if (attr === undefined) {
@@ -78136,7 +78317,7 @@ Make sure to test the downported code, it might not always be completely correct
78136
78317
  if (found) {
78137
78318
  return found;
78138
78319
  }
78139
- found = this.outlineGetReferenceSimple(high, lowFile);
78320
+ found = this.outlineGetReferenceSimple(high, lowFile, highSyntax);
78140
78321
  if (found) {
78141
78322
  return found;
78142
78323
  }
@@ -78811,7 +78992,17 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
78811
78992
  const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getStart(), node.getEnd(), code);
78812
78993
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
78813
78994
  }
78814
- outlineGetReferenceSimple(node, lowFile) {
78995
+ /** the type of a reference to the source: LIKE REF TO it, or REF TO data when its type is generic,
78996
+ * as LIKE REF TO a generically typed field symbol or parameter does not activate */
78997
+ refTypeOf(sourceName, node, lowFile, highSyntax) {
78998
+ var _a;
78999
+ const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
79000
+ if (((_a = spag === null || spag === void 0 ? void 0 : spag.findVariable(sourceName)) === null || _a === void 0 ? void 0 : _a.getType().isGeneric()) === true) {
79001
+ return "TYPE REF TO data";
79002
+ }
79003
+ return "LIKE REF TO " + sourceName;
79004
+ }
79005
+ outlineGetReferenceSimple(node, lowFile, highSyntax) {
78815
79006
  var _a, _b, _c;
78816
79007
  if (!(node.get() instanceof Statements.GetReference)) {
78817
79008
  return undefined;
@@ -78828,7 +79019,8 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
78828
79019
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
78829
79020
  const firstToken = target.getFirstToken();
78830
79021
  const lastToken = target.getLastToken();
78831
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getStart(), `DATA ${targetName} LIKE REF TO ${source.concatTokens()}.\n${indentation}`);
79022
+ const refType = this.refTypeOf(source.concatTokens(), node, lowFile, highSyntax);
79023
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getStart(), `DATA ${targetName} ${refType}.\n${indentation}`);
78832
79024
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), lastToken.getEnd(), targetName);
78833
79025
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
78834
79026
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
@@ -78845,7 +79037,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
78845
79037
  if (!(((_a = target === null || target === void 0 ? void 0 : target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.InlineData)) {
78846
79038
  return undefined;
78847
79039
  }
78848
- let type = "";
79040
+ let type;
78849
79041
  const source = node.findFirstExpression(Expressions.Source);
78850
79042
  if (source === undefined) {
78851
79043
  return undefined;
@@ -78935,8 +79127,8 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
78935
79127
  if (!(node.get() instanceof Statements.Raise)) {
78936
79128
  return undefined;
78937
79129
  }
78938
- let id = undefined;
78939
- let number = undefined;
79130
+ let id;
79131
+ let number;
78940
79132
  let startToken = node.findDirectTokenByText("ID");
78941
79133
  if (startToken) {
78942
79134
  const sources = node.findDirectExpressions(Expressions.Source);
@@ -79094,7 +79286,7 @@ ${indentation}${uniqueName2}->if_t100_message~t100key = ${uniqueName1}.\n`;
79094
79286
  || sourceRef.getChildren().length !== 1) {
79095
79287
  return undefined;
79096
79288
  }
79097
- let code = "";
79289
+ let code;
79098
79290
  if (sourceRef.findFirstExpression(Expressions.TableExpression)) {
79099
79291
  const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79100
79292
  code = `ASSIGN ${sourceRef.concatTokens()} TO FIELD-SYMBOL(<${uniqueName}>).
@@ -79286,7 +79478,7 @@ LOOP AT ${groupTargetName}tab ${groupTarget}.`;
79286
79478
  || !(tableExpression instanceof nodes_1.ExpressionNode)) {
79287
79479
  return undefined;
79288
79480
  }
79289
- let condition = "";
79481
+ let condition;
79290
79482
  if (tableExpression.getChildren().length === 3) {
79291
79483
  const index = tableExpression.findDirectExpression(Expressions.Source);
79292
79484
  if (index === undefined) {
@@ -79470,7 +79662,7 @@ ${indentation}${uniqueName}`;
79470
79662
  return undefined;
79471
79663
  }
79472
79664
  const op = secondChild.getFirstToken();
79473
- let operator = "";
79665
+ let operator;
79474
79666
  switch (op.getStr()) {
79475
79667
  case "+":
79476
79668
  operator = " + ";
@@ -79512,7 +79704,7 @@ ${indentation}${uniqueName}`;
79512
79704
  || (formatting === null || formatting === void 0 ? void 0 : formatting.startsWith("ALPHA = ")) === false) {
79513
79705
  continue;
79514
79706
  }
79515
- let functionName = "";
79707
+ let functionName;
79516
79708
  switch (formatting) {
79517
79709
  case "ALPHA = IN":
79518
79710
  functionName = "CONVERSION_EXIT_ALPHA_INPUT";
@@ -79808,13 +80000,12 @@ ${indentation} output = ${uniqueName}.\n`;
79808
80000
  const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
79809
80001
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
79810
80002
  let body = "";
79811
- let name = "";
79812
80003
  const switchBody = i.findDirectExpression(Expressions.SwitchBody);
79813
80004
  if (switchBody === undefined) {
79814
80005
  continue;
79815
80006
  }
79816
80007
  for (const l of ((_c = switchBody === null || switchBody === void 0 ? void 0 : switchBody.findDirectExpression(Expressions.Let)) === null || _c === void 0 ? void 0 : _c.findDirectExpressions(Expressions.InlineFieldDefinition)) || []) {
79817
- name = l.getFirstToken().getStr();
80008
+ const name = l.getFirstToken().getStr();
79818
80009
  body += indentation + `DATA(${name}) = ${(_d = switchBody.findFirstExpression(Expressions.Source)) === null || _d === void 0 ? void 0 : _d.concatTokens()}.\n`;
79819
80010
  }
79820
80011
  body += `DATA ${uniqueName} ${type}.\n`;
@@ -79872,7 +80063,6 @@ ${indentation} output = ${uniqueName}.\n`;
79872
80063
  const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
79873
80064
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
79874
80065
  let body = "";
79875
- let name = "";
79876
80066
  const reduceBody = i.findDirectExpression(Expressions.ReduceBody);
79877
80067
  if (reduceBody === undefined) {
79878
80068
  continue;
@@ -79883,7 +80073,7 @@ ${indentation} output = ${uniqueName}.\n`;
79883
80073
  }
79884
80074
  let firstName = "";
79885
80075
  for (const init of reduceBody.findDirectExpressions(Expressions.InlineFieldDefinition)) {
79886
- name = init.getFirstToken().getStr();
80076
+ const name = init.getFirstToken().getStr();
79887
80077
  if (firstName === "") {
79888
80078
  firstName = name;
79889
80079
  }
@@ -80115,7 +80305,7 @@ ${indentation} output = ${uniqueName}.\n`;
80115
80305
  after += c.concatTokens();
80116
80306
  }
80117
80307
  }
80118
- let condition = "";
80308
+ let condition;
80119
80309
  if ((tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.getChildren().length) === 3) {
80120
80310
  condition = "INDEX " + ((_d = tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.findDirectExpression(Expressions.Source)) === null || _d === void 0 ? void 0 : _d.concatTokens());
80121
80311
  }
@@ -80266,7 +80456,7 @@ ${indentation} output = ${uniqueName}.\n`;
80266
80456
  continue;
80267
80457
  }
80268
80458
  const name = nameToken.getStr();
80269
- let type = "";
80459
+ let type;
80270
80460
  if (high.concatTokens().toUpperCase().startsWith("APPEND INITIAL LINE TO ")) {
80271
80461
  type = "LIKE LINE OF " + ((_b = high.findFirstExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());
80272
80462
  }
@@ -80632,7 +80822,7 @@ ${indentation} output = ${uniqueName}.\n`;
80632
80822
  }
80633
80823
  return undefined;
80634
80824
  }
80635
- getReference(node, lowFile, _highSyntax) {
80825
+ getReference(node, lowFile, highSyntax) {
80636
80826
  var _a, _b, _c;
80637
80827
  if (!(node.get() instanceof Statements.GetReference)) {
80638
80828
  return undefined;
@@ -80646,7 +80836,7 @@ ${indentation} output = ${uniqueName}.\n`;
80646
80836
  if (targetName === undefined || sourceName === undefined) {
80647
80837
  return undefined;
80648
80838
  }
80649
- const code = `DATA ${targetName} LIKE REF TO ${sourceName}.\n`;
80839
+ const code = `DATA ${targetName} ${this.refTypeOf(sourceName, node, lowFile, highSyntax)}.\n`;
80650
80840
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);
80651
80841
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inline.getFirstToken().getStart(), inline.getLastToken().getEnd(), targetName);
80652
80842
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
@@ -80723,18 +80913,30 @@ ${indentation} output = ${uniqueName}.\n`;
80723
80913
  const uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
80724
80914
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
80725
80915
  const sy = func === "LINE_EXISTS" ? "sy-subrc" : "sy-tabix";
80726
- const code = `DATA ${uniqueName} LIKE sy-subrc.\n` +
80727
- indentation + `READ TABLE ${tableName} ${condition}TRANSPORTING NO FIELDS.\n` +
80728
- indentation + uniqueName + ` = ${sy}.\n` +
80729
- indentation;
80730
80916
  let insertAt = node.getFirstToken().getStart();
80731
80917
  if (node.get() instanceof statements_1.ElseIf) {
80732
- // assumption: no side effects in IF conditions
80918
+ // assumption: no side effects in IF conditions, except the READ itself, see below
80733
80919
  insertAt = this.findStartOfIf(node, highFile);
80734
80920
  if (insertAt === undefined) {
80735
80921
  continue;
80736
80922
  }
80737
80923
  }
80924
+ // the READ sets sy-subrc and sy-tabix, which the built-in function does not,
80925
+ // keep the values for the code that reads them after the inserted READ
80926
+ const keep = [];
80927
+ const reads = this.readSyFields(insertAt, highFile);
80928
+ for (const field of ["sy-subrc", "sy-tabix"]) {
80929
+ if (reads.has(field)) {
80930
+ keep.push({ field, name: this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax) });
80931
+ }
80932
+ }
80933
+ const code = `DATA ${uniqueName} LIKE sy-subrc.\n` +
80934
+ keep.map(k => indentation + `DATA ${k.name} LIKE ${k.field}.\n`).join("") +
80935
+ keep.map(k => indentation + `${k.name} = ${k.field}.\n`).join("") +
80936
+ indentation + `READ TABLE ${tableName} ${condition}TRANSPORTING NO FIELDS.\n` +
80937
+ indentation + uniqueName + ` = ${sy}.\n` +
80938
+ keep.map(k => indentation + `${k.field} = ${k.name}.\n`).join("") +
80939
+ indentation;
80738
80940
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, insertAt, code);
80739
80941
  const start = expression.getFirstToken().getStart();
80740
80942
  const end = expression.getLastToken().getEnd();
@@ -80745,6 +80947,46 @@ ${indentation} output = ${uniqueName}.\n`;
80745
80947
  }
80746
80948
  return undefined;
80747
80949
  }
80950
+ /** sy-subrc and sy-tabix, when read from the position on, in the procedure around it or the file outside of one;
80951
+ * inside a loop from the start of the outermost loop, as the next pass reads what this one left */
80952
+ readSyFields(position, highFile) {
80953
+ const structure = highFile.getStructure();
80954
+ const contains = (s) => !position.isBefore(s.getFirstToken().getStart())
80955
+ && !position.isAfter(s.getLastToken().getStart());
80956
+ let scope = undefined;
80957
+ for (const s of [Structures.Method, Structures.Form, Structures.FunctionModule]) {
80958
+ for (const p of (structure === null || structure === void 0 ? void 0 : structure.findAllStructuresRecursive(s)) || []) {
80959
+ if (contains(p)) {
80960
+ scope = p;
80961
+ }
80962
+ }
80963
+ }
80964
+ scope = scope || structure;
80965
+ let from = position;
80966
+ for (const s of [Structures.Loop, Structures.Do, Structures.While, Structures.Select]) {
80967
+ for (const l of (scope === null || scope === void 0 ? void 0 : scope.findAllStructuresRecursive(s)) || []) {
80968
+ if (contains(l) && l.getFirstToken().getStart().isBefore(from)) {
80969
+ from = l.getFirstToken().getStart();
80970
+ }
80971
+ }
80972
+ }
80973
+ const ret = new Set();
80974
+ for (const s of (scope === null || scope === void 0 ? void 0 : scope.findAllStatementNodes()) || []) {
80975
+ if (s.getLastToken().getStart().isBefore(from)) {
80976
+ continue;
80977
+ }
80978
+ const tokens = s.getTokens();
80979
+ for (let i = 0; i < tokens.length - 2; i++) {
80980
+ if (tokens[i].getStr().toUpperCase() === "SY" && tokens[i + 1].getStr() === "-") {
80981
+ const field = "sy-" + tokens[i + 2].getStr().toLowerCase();
80982
+ if (field === "sy-subrc" || field === "sy-tabix") {
80983
+ ret.add(field);
80984
+ }
80985
+ }
80986
+ }
80987
+ }
80988
+ return ret;
80989
+ }
80748
80990
  findStartOfIf(node, highFile) {
80749
80991
  const structure = highFile.getStructure();
80750
80992
  for (const c of (structure === null || structure === void 0 ? void 0 : structure.findAllStructuresRecursive(Structures.If)) || []) {
@@ -80757,6 +80999,7 @@ ${indentation} output = ${uniqueName}.\n`;
80757
80999
  return undefined;
80758
81000
  }
80759
81001
  newToCreateObject(low, high, lowFile, highSyntax) {
81002
+ var _a;
80760
81003
  if (!(low.get() instanceof _statement_1.Unknown)) {
80761
81004
  return undefined;
80762
81005
  }
@@ -80772,7 +81015,7 @@ ${indentation} output = ${uniqueName}.\n`;
80772
81015
  && found
80773
81016
  && source.concatTokens() === found.concatTokens()
80774
81017
  && target.findDirectExpression(Expressions.InlineData) === undefined) {
80775
- const abap = this.newParameters(found, target.concatTokens(), highSyntax, lowFile);
81018
+ const abap = (_a = this.newDataReference(high, target, found, lowFile, highSyntax)) !== null && _a !== void 0 ? _a : this.newParameters(found, target.concatTokens(), highSyntax, lowFile);
80776
81019
  if (abap !== undefined) {
80777
81020
  fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), abap);
80778
81021
  }
@@ -80811,6 +81054,42 @@ ${indentation} output = ${uniqueName}.\n`;
80811
81054
  return undefined;
80812
81055
  }
80813
81056
  }
81057
+ /** NEW into a data reference creates data, CREATE OBJECT cannot: "target = NEW #|type( [value] )"
81058
+ * with a variable typed REF TO a data type becomes CREATE DATA plus the assignment of the value */
81059
+ newDataReference(high, target, found, lowFile, highSyntax) {
81060
+ var _a, _b, _c;
81061
+ if (target.getChildren().length !== 1 || !(((_a = target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.TargetField)) {
81062
+ return undefined;
81063
+ }
81064
+ const children = found.getChildren();
81065
+ const value = found.findDirectExpression(Expressions.Source);
81066
+ // NEW, the type, "(", optionally one value, ")"
81067
+ if (children.length !== 4 + (value ? 1 : 0)) {
81068
+ return undefined;
81069
+ }
81070
+ const name = target.concatTokens();
81071
+ const spag = highSyntax.spaghetti.lookupPosition(high.getFirstToken().getStart(), lowFile.getFilename());
81072
+ const type = (_b = spag === null || spag === void 0 ? void 0 : spag.findVariable(name)) === null || _b === void 0 ? void 0 : _b.getType();
81073
+ if (!(type instanceof basic_1.DataReference)) {
81074
+ return undefined;
81075
+ }
81076
+ const typeName = (_c = found.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _c === void 0 ? void 0 : _c.concatTokens();
81077
+ const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
81078
+ let abap = `CREATE DATA ${name}` + (typeName === "#" ? "" : ` TYPE ${typeName}`) + ".";
81079
+ if (value === undefined) {
81080
+ return abap;
81081
+ }
81082
+ else if (type.getType().isGeneric() === false) {
81083
+ return abap + `\n${indentation}${name}->* = ${value.concatTokens()}.`;
81084
+ }
81085
+ // a generic reference cannot be dereferenced as a target below v756
81086
+ const fs = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
81087
+ abap = `FIELD-SYMBOLS ${fs} TYPE any.\n` +
81088
+ indentation + abap + "\n" +
81089
+ indentation + `ASSIGN ${name}->* TO ${fs}.\n` +
81090
+ indentation + `${fs} = ${value.concatTokens()}.`;
81091
+ return abap;
81092
+ }
80814
81093
  newParameters(found, name, highSyntax, lowFile) {
80815
81094
  var _a, _b, _c;
80816
81095
  const typeToken = (_a = found.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
@@ -81602,6 +81881,8 @@ class EmptyStructureConf extends _basic_rule_config_1.BasicRuleConfig {
81602
81881
  this.try = true;
81603
81882
  /** Checks for empty WHEN blocks */
81604
81883
  this.when = true;
81884
+ /** Checks for empty CATCH blocks, unless the CATCH has pragma ##NO_HANDLER or pseudo comment "#EC NO_HANDLER */
81885
+ this.catch = false;
81605
81886
  // todo, other category containing ELSE
81606
81887
  }
81607
81888
  }
@@ -81714,6 +81995,21 @@ result = xsdbool( sy-subrc = 0 ).`,
81714
81995
  }
81715
81996
  }
81716
81997
  }
81998
+ if (this.getConfig().catch === true) {
81999
+ for (const c of stru.findAllStructuresRecursive(Structures.Catch)) {
82000
+ // a comment in the block does not count, the extended check (SLIN) reports it too
82001
+ if (c.findDirectStructure(Structures.Body) !== undefined) {
82002
+ continue;
82003
+ }
82004
+ const catchStatement = c.getFirstStatement();
82005
+ if (catchStatement === undefined || this.isNoHandler(catchStatement, statements)) {
82006
+ continue;
82007
+ }
82008
+ const token = c.getFirstToken();
82009
+ const issue = issue_1.Issue.atToken(file, token, this.getDescription(c.get().constructor.name), this.getMetadata().key, this.conf.severity);
82010
+ issues.push(issue);
82011
+ }
82012
+ }
81717
82013
  if (this.getConfig().when === true) {
81718
82014
  const tries = stru.findAllStructuresRecursive(Structures.When);
81719
82015
  for (const t of tries) {
@@ -81727,6 +82023,15 @@ result = xsdbool( sy-subrc = 0 ).`,
81727
82023
  }
81728
82024
  return issues;
81729
82025
  }
82026
+ isNoHandler(catchStatement, statements) {
82027
+ if (catchStatement.getPragmas().some(p => p.getStr().toUpperCase() === "##NO_HANDLER")) {
82028
+ return true;
82029
+ }
82030
+ const next = statements[statements.indexOf(catchStatement) + 1];
82031
+ return (next === null || next === void 0 ? void 0 : next.get()) instanceof _statement_1.Comment
82032
+ && next.getStart().getRow() === catchStatement.getEnd().getRow()
82033
+ && next.concatTokens().toUpperCase().replace(/\s/g, "").includes("\"#ECNO_HANDLER");
82034
+ }
81730
82035
  }
81731
82036
  exports.EmptyStructure = EmptyStructure;
81732
82037
  //# sourceMappingURL=empty_structure.js.map
@@ -83163,7 +83468,7 @@ cl_abap_typedescr=>describe_by_name(
83163
83468
  const methodSource = statNode.findDirectExpression(Expressions.MethodSource);
83164
83469
  let methodSourceStr = methodSource === null || methodSource === void 0 ? void 0 : methodSource.concatTokens();
83165
83470
  const methodBody = statNode.findDirectExpression(Expressions.MethodCallBody);
83166
- let methodBodyStr = "";
83471
+ let methodBodyStr;
83167
83472
  if (methodBody) {
83168
83473
  const methodCallParam = methodBody.findDirectExpression(Expressions.MethodCallParam);
83169
83474
  if (methodCallParam && methodCallParam.getFirstToken().getStr() === "(") {
@@ -86057,7 +86362,7 @@ class KeywordCase extends _abap_rule_1.ABAPRule {
86057
86362
  const firstToken = tokens[0].token;
86058
86363
  const lastToken = tokens[tokens.length - 1].token;
86059
86364
  const firstTokenValue = firstToken.getStr();
86060
- let description = "";
86365
+ let description;
86061
86366
  if (first.keyword === true) {
86062
86367
  description = `Keyword should be ${this.conf.style} case: "${firstTokenValue}"`;
86063
86368
  }
@@ -86582,7 +86887,7 @@ ENDCLASS.`,
86582
86887
  continue;
86583
86888
  }
86584
86889
  const className = classDef.name;
86585
- let expected = "";
86890
+ let expected;
86586
86891
  if (classDef.isForTesting) {
86587
86892
  expected = this.conf.test;
86588
86893
  }
@@ -87248,7 +87553,7 @@ ENDIF.
87248
87553
  issues.push(...this.analyzeCondition(file, cond));
87249
87554
  }
87250
87555
  for (const sub of structure.findAllExpressionsMulti([Expressions.CondSub, Expressions.ComponentCondSub])) {
87251
- let cond = [];
87556
+ let cond;
87252
87557
  if (sub.get() instanceof Expressions.CondSub) {
87253
87558
  cond = sub.findDirectExpressions(Expressions.Cond);
87254
87559
  }
@@ -91286,13 +91591,9 @@ ENDIF.`,
91286
91591
  }
91287
91592
  else if (statement instanceof Statements.ClassDefinitionLoad ||
91288
91593
  statement instanceof Statements.InterfaceLoad) {
91289
- let token = undefined;
91290
- if (statement instanceof Statements.ClassDefinitionLoad) {
91291
- token = statementNode.getChildren()[3].getFirstToken();
91292
- }
91293
- else {
91294
- token = statementNode.getChildren()[2].getFirstToken();
91295
- }
91594
+ const token = statement instanceof Statements.ClassDefinitionLoad
91595
+ ? statementNode.getChildren()[3].getFirstToken()
91596
+ : statementNode.getChildren()[2].getFirstToken();
91296
91597
  let startPosition = token.getStart();
91297
91598
  startPosition = new position_1.Position(startPosition.getRow(), startPosition.getCol() - 1);
91298
91599
  return edit_helper_1.EditHelper.deleteRange(file, startPosition, token.getEnd());
@@ -92089,7 +92390,6 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
92089
92390
  exports.ParserMissingSpace = exports.ParserMissingSpaceConf = void 0;
92090
92391
  const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/expressions */ "../core/build/src/abap/2_statements/expressions/index.js"));
92091
92392
  const issue_1 = __webpack_require__(/*! ../issue */ "../core/build/src/issue.js");
92092
- const position_1 = __webpack_require__(/*! ../position */ "../core/build/src/position.js");
92093
92393
  const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "../core/build/src/rules/_abap_rule.js");
92094
92394
  const nodes_1 = __webpack_require__(/*! ../abap/nodes */ "../core/build/src/abap/nodes/index.js");
92095
92395
  const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "../core/build/src/rules/_basic_rule_config.js");
@@ -92122,7 +92422,7 @@ This rule makes sure the spaces are consistently required across the language.`,
92122
92422
  }
92123
92423
  runParsed(file) {
92124
92424
  const issues = [];
92125
- let start = new position_1.Position(0, 0);
92425
+ let start;
92126
92426
  for (const statement of file.getStatements()) {
92127
92427
  const missing = this.missingSpace(statement);
92128
92428
  if (missing) {
@@ -93683,14 +93983,8 @@ From 752 and up`,
93683
93983
  }
93684
93984
  getFix(file, statement, withExporting) {
93685
93985
  const children = statement.getChildren();
93686
- let contentFix = undefined;
93687
- if (withExporting) {
93688
- const fixText = "( " + children[5].concatTokens() + " ).";
93689
- contentFix = edit_helper_1.EditHelper.replaceRange(file, children[3].getLastToken().getEnd(), statement.getEnd(), fixText);
93690
- }
93691
- else {
93692
- contentFix = edit_helper_1.EditHelper.replaceRange(file, children[3].getLastToken().getEnd(), statement.getEnd(), "( ).");
93693
- }
93986
+ const fixText = withExporting ? "( " + children[5].concatTokens() + " )." : "( ).";
93987
+ const contentFix = edit_helper_1.EditHelper.replaceRange(file, children[3].getLastToken().getEnd(), statement.getEnd(), fixText);
93694
93988
  const replaceType = edit_helper_1.EditHelper.replaceToken(file, children[2].getFirstToken(), "NEW");
93695
93989
  return edit_helper_1.EditHelper.merge(contentFix, replaceType);
93696
93990
  }
@@ -94924,7 +95218,8 @@ class RedundantConversion {
94924
95218
  key: "redundant_conversion",
94925
95219
  title: "Redundant Conversion",
94926
95220
  shortDescription: `Find redundant CONV expressions`,
94927
- extendedInformation: `Reports CONV expressions whose operand already has the conversion's target type.`,
95221
+ extendedInformation: `Reports CONV expressions whose operand already has the conversion's target type,
95222
+ including the result of a built-in function with a fixed result type, like to_upper( ) or strlen( ).`,
94928
95223
  tags: [_irule_1.RuleTag.Quickfix],
94929
95224
  badExample: `DATA text TYPE string.
94930
95225
  text = CONV string( text ).`,
@@ -94961,7 +95256,8 @@ text = text.`,
94961
95256
  if (structure === undefined) {
94962
95257
  continue;
94963
95258
  }
94964
- for (const source of structure.findAllExpressions(Expressions.Source)) {
95259
+ // recursive, a CONV can be the argument of a built-in function, which is itself a Source
95260
+ for (const source of structure.findAllExpressionsRecursive(Expressions.Source)) {
94965
95261
  if (source.getFirstToken().getStr().toUpperCase() !== "CONV") {
94966
95262
  continue;
94967
95263
  }
@@ -95020,6 +95316,15 @@ text = text.`,
95020
95316
  }
95021
95317
  sourceType(source, scope) {
95022
95318
  let context;
95319
+ // boolc( <condition> ) is not a MethodCallChain, xsdbool( ) has the same shape but is not reported
95320
+ const first = source.getFirstToken();
95321
+ if (first.getStr().toUpperCase() === "BOOLC"
95322
+ && source.findDirectExpression(Expressions.Cond) !== undefined
95323
+ && source.getChildren().length === 4
95324
+ && scope.getData().references.some(reference => reference.referenceType === _reference_1.ReferenceType.BuiltinMethodReference
95325
+ && reference.position.getStart().equals(first.getStart()))) {
95326
+ return basic_1.StringType.get();
95327
+ }
95023
95328
  for (const child of source.getChildren()) {
95024
95329
  if (!(child instanceof nodes_1.ExpressionNode)) {
95025
95330
  continue;
@@ -95030,6 +95335,15 @@ text = text.`,
95030
95335
  return undefined;
95031
95336
  }
95032
95337
  }
95338
+ else if (child.get() instanceof Expressions.MethodCallChain) {
95339
+ if (source.getChildren().length !== 1) {
95340
+ return undefined;
95341
+ }
95342
+ context = this.builtinResultType(child, scope);
95343
+ if (context === undefined) {
95344
+ return undefined;
95345
+ }
95346
+ }
95033
95347
  else if (child.get() instanceof Expressions.Constant) {
95034
95348
  context = this.infer(context, constant_1.Constant.runSyntax(child));
95035
95349
  }
@@ -95050,6 +95364,32 @@ text = text.`,
95050
95364
  }
95051
95365
  return context;
95052
95366
  }
95367
+ /** The result type of a call to a built-in function whose result type does not depend on its arguments,
95368
+ * undefined for anything else, e.g. abs( ) or xsdbool( ), or a method of the same name */
95369
+ builtinResultType(chain, scope) {
95370
+ var _a;
95371
+ const children = chain.getChildren();
95372
+ if (children.length !== 1 || !(children[0].get() instanceof Expressions.MethodCall)) {
95373
+ return undefined;
95374
+ }
95375
+ const name = (_a = children[0].findDirectExpression(Expressions.MethodName)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
95376
+ if (name === undefined) {
95377
+ return undefined;
95378
+ }
95379
+ const isBuiltin = scope.getData().references.some(reference => reference.referenceType === _reference_1.ReferenceType.BuiltinMethodReference
95380
+ && reference.position.getStart().equals(name.getStart()));
95381
+ if (isBuiltin === false) {
95382
+ return undefined;
95383
+ }
95384
+ const upper = name.getStr().toUpperCase();
95385
+ if (RedundantConversion.stringResult.has(upper)) {
95386
+ return basic_1.StringType.get();
95387
+ }
95388
+ else if (RedundantConversion.integerResult.has(upper)) {
95389
+ return basic_1.IntegerType.get();
95390
+ }
95391
+ return undefined;
95392
+ }
95053
95393
  fieldChainType(fieldChain, scope) {
95054
95394
  var _a;
95055
95395
  const operand = (_a = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.DataReadReference
@@ -95114,6 +95454,17 @@ text = text.`,
95114
95454
  }
95115
95455
  }
95116
95456
  exports.RedundantConversion = RedundantConversion;
95457
+ // built-in functions that always return a string, whatever their arguments
95458
+ RedundantConversion.stringResult = new Set([
95459
+ "BOOLC", "CONCAT_LINES_OF", "CONDENSE", "ESCAPE", "FROM_MIXED", "INSERT", "REPEAT", "REPLACE",
95460
+ "REVERSE", "SEGMENT", "SHIFT_LEFT", "SHIFT_RIGHT", "SUBSTRING", "SUBSTRING_AFTER", "SUBSTRING_BEFORE",
95461
+ "SUBSTRING_FROM", "SUBSTRING_TO", "TO_LOWER", "TO_MIXED", "TO_UPPER", "TRANSLATE"
95462
+ ]);
95463
+ // built-in functions that always return an i
95464
+ RedundantConversion.integerResult = new Set([
95465
+ "CHARLEN", "COUNT", "COUNT_ANY_NOT_OF", "COUNT_ANY_OF", "DBMAXLEN", "DISTANCE", "FIND", "FIND_ANY_NOT_OF",
95466
+ "FIND_ANY_OF", "FIND_END", "LINES", "NUMOFCHAR", "STRLEN", "XSTRLEN"
95467
+ ]);
95117
95468
  //# sourceMappingURL=redundant_conversion.js.map
95118
95469
 
95119
95470
  /***/ },
@@ -102060,6 +102411,7 @@ class XMLConsistency {
102060
102411
  * Naming for CLAS and INTF objects
102061
102412
  * QUAN fields in TABL objects have reference table and field values
102062
102413
  * Transparent TABL objects have delivery class and size category set
102414
+ * TABL fields with a built-in type carry the INTTYPE abapGit serializes for it, for the confirmed pairs
102063
102415
  * Lock parameter names in ENQU objects are max 16 characters
102064
102416
  * Texts and translations do not exceed maximum allowed length.`,
102065
102417
  tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax],
@@ -102319,15 +102671,29 @@ class XMLConsistency {
102319
102671
  }
102320
102672
  runTable(obj, file) {
102321
102673
  var _a, _b, _c, _d;
102322
- var _e;
102674
+ var _e, _f;
102323
102675
  const issues = [];
102324
102676
  for (const field of (_e = obj.getFields()) !== null && _e !== void 0 ? _e : []) {
102325
102677
  if (field.DATATYPE === "QUAN" && (!((_a = field.REFTABLE) === null || _a === void 0 ? void 0 : _a.trim()) || !((_b = field.REFFIELD) === null || _b === void 0 ? void 0 : _b.trim()))) {
102326
102678
  const message = `QUAN field ${field.FIELDNAME} must have REFTABLE and REFFIELD set`;
102327
102679
  issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
102328
102680
  }
102681
+ const expected = field.DATATYPE ? XMLConsistency.intTypes[field.DATATYPE] : undefined;
102682
+ if (expected !== undefined && field.INTTYPE !== undefined && field.INTTYPE !== expected) {
102683
+ const message = `Field ${field.FIELDNAME}: INTTYPE "${field.INTTYPE}" does not match DATATYPE ${field.DATATYPE}, ` +
102684
+ `abapGit serializes "${expected}"`;
102685
+ issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
102686
+ }
102329
102687
  }
102330
102688
  if (obj.getTableCategory() === Objects.TableCategory.Transparent) {
102689
+ // Confirmed reserved database field names, see issue #4331, DAY and HOUR reported by activation.
102690
+ // TRESE also contains names such as TEXT and LENGTH which are allowed here.
102691
+ const reservedFieldNames = ["ZONE", "HANDLER", "SECTION", "PARAMETER", "DAY", "HOUR"];
102692
+ for (const field of (_f = obj.getFields()) !== null && _f !== void 0 ? _f : []) {
102693
+ if (reservedFieldNames.includes(field.FIELDNAME.toUpperCase())) {
102694
+ issues.push(issue_1.Issue.atRow(file, 1, `Table field name "${field.FIELDNAME}" is reserved`, this.getMetadata().key, this.conf.severity));
102695
+ }
102696
+ }
102331
102697
  if (!((_c = obj.getDeliveryClass()) === null || _c === void 0 ? void 0 : _c.trim())) {
102332
102698
  const message = `Transparent table must have delivery class(CONTFLAG in DD02V) set`;
102333
102699
  issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.transparentTableSeverity));
@@ -102341,6 +102707,15 @@ class XMLConsistency {
102341
102707
  }
102342
102708
  }
102343
102709
  exports.XMLConsistency = XMLConsistency;
102710
+ // INTTYPE that abapGit serializes for a built-in DATATYPE, confirmed by exported tables;
102711
+ // a different value activates, but shows as a diff on every pull
102712
+ XMLConsistency.intTypes = {
102713
+ "CHAR": "C", "CLNT": "C", "CUKY": "C", "LANG": "C",
102714
+ "DATS": "D", "TIMS": "T",
102715
+ "INT4": "X", "RAW": "X",
102716
+ "DEC": "P", "CURR": "P",
102717
+ "STRG": "g", "SSTR": "g", "RSTR": "y",
102718
+ };
102344
102719
  //# sourceMappingURL=xml_consistency.js.map
102345
102720
 
102346
102721
  /***/ },
@@ -102963,7 +103338,7 @@ class FormLengthStats {
102963
103338
  return res;
102964
103339
  }
102965
103340
  static findName(stat) {
102966
- let name = "";
103341
+ let name;
102967
103342
  const nameExpr = stat.findFirstExpression(expressions_1.FormName);
102968
103343
  if (nameExpr) {
102969
103344
  name = nameExpr.getFirstToken().getStr();
@@ -103374,7 +103749,7 @@ class MethodLengthStats {
103374
103749
  return res;
103375
103750
  }
103376
103751
  static findName(stat) {
103377
- let name = "";
103752
+ let name;
103378
103753
  const nameExpr = stat.findFirstExpression(expressions_1.MethodName);
103379
103754
  if (nameExpr) {
103380
103755
  name = nameExpr.getFirstToken().getStr();
@@ -104976,7 +105351,7 @@ function loadConfig(filename) {
104976
105351
  // c) specified and found
104977
105352
  // d) specified and not found => use default
104978
105353
  // e) supplied but a directory => use default
104979
- let f = "";
105354
+ let f;
104980
105355
  if (filename === undefined) {
104981
105356
  f = process.cwd() + path.sep + "abaplint.json";
104982
105357
  if (fs.existsSync(f) === false) {
@@ -105119,7 +105494,7 @@ async function run(arg) {
105119
105494
  else {
105120
105495
  process.stderr.write("abaplint " + core_1.Registry.abaplintVersion() + "\n");
105121
105496
  let loaded = [];
105122
- let deps = [];
105497
+ let deps;
105123
105498
  const { config, base } = loadConfig(arg.configFilename);
105124
105499
  outputSyntaxConfig(config);
105125
105500
  try {