@abaplint/core 2.86.3 → 2.86.6

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 (78) hide show
  1. package/README.md +6 -6
  2. package/build/src/abap/flow/flow_graph.js +7 -7
  3. package/build/src/lsp/help.js +7 -7
  4. package/build/src/registry.js +1 -1
  5. package/build/src/rules/7bit_ascii.js +2 -2
  6. package/build/src/rules/abapdoc.js +1 -1
  7. package/build/src/rules/align_parameters.js +33 -33
  8. package/build/src/rules/ambiguous_statement.js +5 -5
  9. package/build/src/rules/avoid_use.js +8 -8
  10. package/build/src/rules/begin_end_names.js +4 -4
  11. package/build/src/rules/begin_single_include.js +12 -12
  12. package/build/src/rules/call_transaction_authority_check.js +3 -3
  13. package/build/src/rules/chain_mainly_declarations.js +4 -4
  14. package/build/src/rules/check_abstract.js +2 -2
  15. package/build/src/rules/check_comments.js +4 -4
  16. package/build/src/rules/check_include.js +3 -3
  17. package/build/src/rules/check_no_handler_pragma.js +8 -8
  18. package/build/src/rules/check_subrc.js +8 -8
  19. package/build/src/rules/commented_code.js +1 -1
  20. package/build/src/rules/constructor_visibility_public.js +4 -4
  21. package/build/src/rules/contains_tab.js +2 -2
  22. package/build/src/rules/dangerous_statement.js +1 -1
  23. package/build/src/rules/downport.js +93 -76
  24. package/build/src/rules/exit_or_check.js +3 -3
  25. package/build/src/rules/exporting.js +1 -1
  26. package/build/src/rules/forbidden_identifier.js +1 -1
  27. package/build/src/rules/forbidden_void_type.js +2 -2
  28. package/build/src/rules/functional_writing.js +17 -17
  29. package/build/src/rules/global_class.js +10 -10
  30. package/build/src/rules/identical_conditions.js +2 -2
  31. package/build/src/rules/identical_contents.js +14 -14
  32. package/build/src/rules/identical_descriptions.js +4 -4
  33. package/build/src/rules/if_in_if.js +7 -7
  34. package/build/src/rules/implement_methods.js +3 -3
  35. package/build/src/rules/in_statement_indentation.js +11 -11
  36. package/build/src/rules/intf_referencing_clas.js +3 -3
  37. package/build/src/rules/keyword_case.js +5 -0
  38. package/build/src/rules/line_break_style.js +2 -2
  39. package/build/src/rules/line_length.js +1 -1
  40. package/build/src/rules/line_only_punc.js +1 -1
  41. package/build/src/rules/local_variable_names.js +2 -2
  42. package/build/src/rules/many_parentheses.js +10 -10
  43. package/build/src/rules/max_one_method_parameter_per_line.js +7 -7
  44. package/build/src/rules/max_one_statement.js +3 -3
  45. package/build/src/rules/method_overwrites_builtin.js +2 -2
  46. package/build/src/rules/nesting.js +1 -1
  47. package/build/src/rules/no_chained_assignment.js +1 -1
  48. package/build/src/rules/no_public_attributes.js +1 -1
  49. package/build/src/rules/no_yoda_conditions.js +4 -4
  50. package/build/src/rules/nrob_consistency.js +2 -2
  51. package/build/src/rules/obsolete_statement.js +40 -40
  52. package/build/src/rules/omit_parameter_name.js +3 -3
  53. package/build/src/rules/omit_receiving.js +13 -13
  54. package/build/src/rules/parser_702_chaining.js +2 -2
  55. package/build/src/rules/parser_error.js +2 -2
  56. package/build/src/rules/parser_missing_space.js +1 -1
  57. package/build/src/rules/prefer_inline.js +16 -16
  58. package/build/src/rules/prefer_is_not.js +7 -7
  59. package/build/src/rules/prefer_raise_exception_new.js +3 -3
  60. package/build/src/rules/prefer_returning_to_exporting.js +1 -1
  61. package/build/src/rules/prefer_xsdbool.js +2 -2
  62. package/build/src/rules/remove_descriptions.js +4 -4
  63. package/build/src/rules/rfc_error_handling.js +9 -9
  64. package/build/src/rules/select_add_order_by.js +5 -5
  65. package/build/src/rules/select_performance.js +2 -2
  66. package/build/src/rules/sicf_consistency.js +4 -4
  67. package/build/src/rules/space_before_dot.js +2 -2
  68. package/build/src/rules/start_at_tab.js +1 -1
  69. package/build/src/rules/sy_modification.js +2 -2
  70. package/build/src/rules/tabl_enhancement_category.js +2 -2
  71. package/build/src/rules/unused_methods.js +9 -9
  72. package/build/src/rules/unused_types.js +2 -21
  73. package/build/src/rules/unused_variables.js +8 -8
  74. package/build/src/rules/use_bool_expression.js +8 -8
  75. package/build/src/rules/use_line_exists.js +6 -6
  76. package/build/src/rules/use_new.js +4 -4
  77. package/build/src/rules/when_others_last.js +6 -6
  78. package/package.json +66 -66
@@ -35,33 +35,33 @@ class Downport {
35
35
  key: "downport",
36
36
  title: "Downport statement",
37
37
  shortDescription: `Experimental downport functionality`,
38
- extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with
39
- a higher level language version. If successful, various rules are applied to downport the statement.
40
- Target downport version is always v702, thus rule is only enabled if target version is v702.
41
-
42
- Current rules:
43
- * NEW transformed to CREATE OBJECT, opposite of https://rules.abaplint.org/use_new/
44
- * DATA() definitions are outlined, opposite of https://rules.abaplint.org/prefer_inline/
45
- * FIELD-SYMBOL() definitions are outlined
46
- * CONV is outlined
47
- * COND is outlined
48
- * REDUCE is outlined
49
- * SWITCH is outlined
50
- * APPEND expression is outlined
51
- * EMPTY KEY is changed to DEFAULT KEY, opposite of DEFAULT KEY in https://rules.abaplint.org/avoid_use/
52
- * CAST changed to ?=
53
- * LOOP AT method_call( ) is outlined
54
- * VALUE # with structure fields
55
- * VALUE # with internal table lines
56
- * Table Expressions are outlined
57
- * SELECT INTO @DATA definitions are outlined
58
- * Some occurrences of string template formatting option ALPHA changed to function module call
59
- * SELECT/INSERT/MODIFY/DELETE/UPDATE "," in field list removed, "@" in source/targets removed
60
- * PARTIALLY IMPLEMENTED removed, it can be quick fixed via rule implement_methods
61
- * RAISE EXCEPTION ... MESSAGE
62
- * Moving with +=, -=, /=, *=, &&= is expanded
63
- * line_exists and line_index is downported to READ TABLE
64
-
38
+ extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with
39
+ a higher level language version. If successful, various rules are applied to downport the statement.
40
+ Target downport version is always v702, thus rule is only enabled if target version is v702.
41
+
42
+ Current rules:
43
+ * NEW transformed to CREATE OBJECT, opposite of https://rules.abaplint.org/use_new/
44
+ * DATA() definitions are outlined, opposite of https://rules.abaplint.org/prefer_inline/
45
+ * FIELD-SYMBOL() definitions are outlined
46
+ * CONV is outlined
47
+ * COND is outlined
48
+ * REDUCE is outlined
49
+ * SWITCH is outlined
50
+ * APPEND expression is outlined
51
+ * EMPTY KEY is changed to DEFAULT KEY, opposite of DEFAULT KEY in https://rules.abaplint.org/avoid_use/
52
+ * CAST changed to ?=
53
+ * LOOP AT method_call( ) is outlined
54
+ * VALUE # with structure fields
55
+ * VALUE # with internal table lines
56
+ * Table Expressions are outlined
57
+ * SELECT INTO @DATA definitions are outlined
58
+ * Some occurrences of string template formatting option ALPHA changed to function module call
59
+ * SELECT/INSERT/MODIFY/DELETE/UPDATE "," in field list removed, "@" in source/targets removed
60
+ * PARTIALLY IMPLEMENTED removed, it can be quick fixed via rule implement_methods
61
+ * RAISE EXCEPTION ... MESSAGE
62
+ * Moving with +=, -=, /=, *=, &&= is expanded
63
+ * line_exists and line_index is downported to READ TABLE
64
+
65
65
  Only one transformation is applied to a statement at a time, so multiple steps might be required to do the full downport.`,
66
66
  tags: [_irule_1.RuleTag.Experimental, _irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],
67
67
  };
@@ -267,6 +267,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
267
267
  if (found) {
268
268
  return found;
269
269
  }
270
+ found = this.replaceMethodConditional(high, lowFile, highSyntax);
271
+ if (found) {
272
+ return found;
273
+ }
270
274
  found = this.replaceTableExpression(high, lowFile, highSyntax);
271
275
  if (found) {
272
276
  return found;
@@ -390,10 +394,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
390
394
  const fieldName = f.concatTokens();
391
395
  fieldDefinition += indentation + " " + fieldName + " TYPE " + tableName + "-" + fieldName + ",\n";
392
396
  }
393
- fieldDefinition = `DATA: BEGIN OF ${name},
397
+ fieldDefinition = `DATA: BEGIN OF ${name},
394
398
  ${fieldDefinition}${indentation} END OF ${name}.`;
395
399
  }
396
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `${fieldDefinition}
400
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `${fieldDefinition}
397
401
  ${indentation}`);
398
402
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inlineData.getFirstToken().getStart(), inlineData.getLastToken().getEnd(), name);
399
403
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
@@ -434,12 +438,12 @@ ${indentation}`);
434
438
  }
435
439
  const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
436
440
  const name = ((_c = inlineData.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || "error";
437
- let fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `TYPES: BEGIN OF ${uniqueName},
438
- ${fieldDefinitions}${indentation} END OF ${uniqueName}.
439
- ${indentation}DATA ${name} TYPE STANDARD TABLE OF ${uniqueName} WITH DEFAULT KEY.
441
+ let fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `TYPES: BEGIN OF ${uniqueName},
442
+ ${fieldDefinitions}${indentation} END OF ${uniqueName}.
443
+ ${indentation}DATA ${name} TYPE STANDARD TABLE OF ${uniqueName} WITH DEFAULT KEY.
440
444
  ${indentation}`);
441
445
  if (fieldDefinitions === "") {
442
- fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `DATA ${name} TYPE STANDARD TABLE OF ${tableName} WITH DEFAULT KEY.
446
+ fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `DATA ${name} TYPE STANDARD TABLE OF ${tableName} WITH DEFAULT KEY.
443
447
  ${indentation}`);
444
448
  }
445
449
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inlineData.getFirstToken().getStart(), inlineData.getLastToken().getEnd(), name);
@@ -460,7 +464,7 @@ ${indentation}`);
460
464
  const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
461
465
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
462
466
  const firstToken = high.getFirstToken();
463
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${target === null || target === void 0 ? void 0 : target.concatTokens()}.
467
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${target === null || target === void 0 ? void 0 : target.concatTokens()}.
464
468
  ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
465
469
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, source.getFirstToken().getStart(), source.getLastToken().getEnd(), uniqueName);
466
470
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
@@ -497,11 +501,11 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
497
501
  const uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
498
502
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
499
503
  const firstToken = node.getFirstToken();
500
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
501
- ${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.
502
- ${indentation}IF sy-subrc <> 0.
503
- ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
504
- ${indentation}ENDIF.
504
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
505
+ ${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.
506
+ ${indentation}IF sy-subrc <> 0.
507
+ ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
508
+ ${indentation}ENDIF.
505
509
  ${indentation}`);
506
510
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, startToken.getStart(), tableExpression.getLastToken().getEnd(), uniqueName);
507
511
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
@@ -542,7 +546,7 @@ ${indentation}`);
542
546
  const className = classNames[0].concatTokens();
543
547
  const targetName = (_b = target.findFirstExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.concatTokens();
544
548
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
545
- const code = ` DATA ${targetName} TYPE REF TO ${className}.
549
+ const code = ` DATA ${targetName} TYPE REF TO ${className}.
546
550
  ${indentation}CATCH ${className} INTO ${targetName}.`;
547
551
  const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getStart(), node.getEnd(), code);
548
552
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
@@ -653,11 +657,11 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
653
657
  const uniqueName1 = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
654
658
  const uniqueName2 = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
655
659
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
656
- const abap = `DATA ${uniqueName1} LIKE if_t100_message=>t100key.
657
- ${indentation}${uniqueName1}-msgid = ${id}.
658
- ${indentation}${uniqueName1}-msgno = ${number}.
659
- ${indentation}DATA ${uniqueName2} TYPE REF TO ${className}.
660
- ${indentation}CREATE OBJECT ${uniqueName2} EXPORTING textid = ${uniqueName1}.
660
+ const abap = `DATA ${uniqueName1} LIKE if_t100_message=>t100key.
661
+ ${indentation}${uniqueName1}-msgid = ${id}.
662
+ ${indentation}${uniqueName1}-msgno = ${number}.
663
+ ${indentation}DATA ${uniqueName2} TYPE REF TO ${className}.
664
+ ${indentation}CREATE OBJECT ${uniqueName2} EXPORTING textid = ${uniqueName1}.
661
665
  ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
662
666
  const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getStart(), node.getEnd(), abap);
663
667
  return issue_1.Issue.atToken(lowFile, startToken, "Downport RAISE MESSAGE", this.getMetadata().key, this.conf.severity, fix);
@@ -738,11 +742,11 @@ ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
738
742
  const tName = target.concatTokens().split("[")[0];
739
743
  const condition = this.tableCondition(tableExpression);
740
744
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
741
- const code = `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${tName}.
742
- ${indentation}READ TABLE ${tName} ${condition}ASSIGNING ${uniqueName}.
743
- ${indentation}IF sy-subrc <> 0.
744
- ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
745
- ${indentation}ENDIF.
745
+ const code = `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${tName}.
746
+ ${indentation}READ TABLE ${tName} ${condition}ASSIGNING ${uniqueName}.
747
+ ${indentation}IF sy-subrc <> 0.
748
+ ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
749
+ ${indentation}ENDIF.
746
750
  ${indentation}${uniqueName}`;
747
751
  const start = target.getFirstToken().getStart();
748
752
  const end = (_a = tableExpression.findDirectTokenByText("]")) === null || _a === void 0 ? void 0 : _a.getEnd();
@@ -830,10 +834,10 @@ ${indentation}${uniqueName}`;
830
834
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
831
835
  const source = (_b = templateSource === null || templateSource === void 0 ? void 0 : templateSource.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens();
832
836
  const topTarget = (_c = node.findDirectExpression(Expressions.Target)) === null || _c === void 0 ? void 0 : _c.concatTokens();
833
- const code = `CALL FUNCTION '${functionName}'
834
- ${indentation} EXPORTING
835
- ${indentation} input = ${source}
836
- ${indentation} IMPORTING
837
+ const code = `CALL FUNCTION '${functionName}'
838
+ ${indentation} EXPORTING
839
+ ${indentation} input = ${source}
840
+ ${indentation} IMPORTING
837
841
  ${indentation} output = ${topTarget}.`;
838
842
  const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getFirstToken().getStart(), node.getLastToken().getEnd(), code);
839
843
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Downport ALPHA", this.getMetadata().key, this.conf.severity, fix);
@@ -894,40 +898,37 @@ ${indentation} output = ${topTarget}.`;
894
898
  return undefined;
895
899
  }
896
900
  outlineFor(forLoop, indentation, lowFile, highSyntax) {
897
- var _a, _b, _c, _d, _e, _f, _g;
901
+ var _a, _b, _c, _d, _e;
898
902
  let body = "";
899
903
  let end = "";
900
904
  const loopSource = (_a = forLoop.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens();
901
905
  const loopTargetField = (_b = forLoop.findFirstExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.concatTokens();
902
- if (forLoop.findDirectTokenByText("UNTIL")) {
903
- const name = (_c = forLoop.findFirstExpression(Expressions.Field)) === null || _c === void 0 ? void 0 : _c.concatTokens();
904
- body += indentation + "DATA " + name + " TYPE i.\n";
905
- const cond = forLoop.findFirstExpression(Expressions.Cond);
906
- body += indentation + `WHILE NOT ${cond === null || cond === void 0 ? void 0 : cond.concatTokens()}.\n`;
907
- const field = (_e = (_d = forLoop.findDirectExpression(Expressions.InlineFieldDefinition)) === null || _d === void 0 ? void 0 : _d.findFirstExpression(Expressions.Field)) === null || _e === void 0 ? void 0 : _e.concatTokens();
908
- end += ` ${field} = ${field} + 1.\n`;
909
- end += indentation + "ENDWHILE";
906
+ let cond = ((_c = forLoop.findDirectExpression(Expressions.ComponentCond)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || "";
907
+ if (cond !== "") {
908
+ cond = " WHERE " + cond;
910
909
  }
911
- else if (forLoop.findDirectTokenByText("WHILE")) {
910
+ if (forLoop.findDirectTokenByText("UNTIL")
911
+ || forLoop.findDirectTokenByText("WHILE")) {
912
912
  const fieldDef = forLoop.findDirectExpression(Expressions.InlineFieldDefinition);
913
- const field = (_f = fieldDef === null || fieldDef === void 0 ? void 0 : fieldDef.findFirstExpression(Expressions.Field)) === null || _f === void 0 ? void 0 : _f.concatTokens();
913
+ const field = (_d = fieldDef === null || fieldDef === void 0 ? void 0 : fieldDef.findFirstExpression(Expressions.Field)) === null || _d === void 0 ? void 0 : _d.concatTokens();
914
914
  body += indentation + "DATA " + field + " TYPE i.\n";
915
915
  const second = fieldDef === null || fieldDef === void 0 ? void 0 : fieldDef.getChildren()[2];
916
916
  if ((second === null || second === void 0 ? void 0 : second.get()) instanceof Expressions.Source) {
917
917
  body += indentation + field + " = " + second.concatTokens() + ".\n";
918
918
  }
919
+ const not = forLoop.findDirectTokenByText("UNTIL") ? " NOT" : "";
919
920
  const cond = forLoop.findFirstExpression(Expressions.Cond);
920
- body += indentation + `WHILE ${cond === null || cond === void 0 ? void 0 : cond.concatTokens()}.\n`;
921
+ body += indentation + `WHILE${not} ${cond === null || cond === void 0 ? void 0 : cond.concatTokens()}.\n`;
921
922
  end += ` ${field} = ${field} + 1.\n`;
922
923
  end += indentation + "ENDWHILE";
923
924
  }
924
925
  else if (loopTargetField) {
925
- body += indentation + `LOOP AT ${loopSource} INTO DATA(${loopTargetField}).\n`;
926
+ body += indentation + `LOOP AT ${loopSource} INTO DATA(${loopTargetField})${cond}.\n`;
926
927
  end = "ENDLOOP";
927
928
  }
928
929
  else if (loopTargetField === undefined) {
929
- const loopTargetFieldSymbol = (_g = forLoop.findFirstExpression(Expressions.TargetFieldSymbol)) === null || _g === void 0 ? void 0 : _g.concatTokens();
930
- body += indentation + `LOOP AT ${loopSource} ASSIGNING FIELD-SYMBOL(${loopTargetFieldSymbol}).\n`;
930
+ const loopTargetFieldSymbol = (_e = forLoop.findFirstExpression(Expressions.TargetFieldSymbol)) === null || _e === void 0 ? void 0 : _e.concatTokens();
931
+ body += indentation + `LOOP AT ${loopSource} ASSIGNING FIELD-SYMBOL(${loopTargetFieldSymbol})${cond}.\n`;
931
932
  end = "ENDLOOP";
932
933
  }
933
934
  const l = forLoop.findDirectExpression(Expressions.Let);
@@ -1030,12 +1031,12 @@ ${indentation} output = ${topTarget}.`;
1030
1031
  name = init.getFirstToken().getStr();
1031
1032
  body += indentation + `DATA(${name}) = ${(_a = reduceBody.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens()}.\n`;
1032
1033
  }
1033
- const forLoop = reduceBody.findDirectExpression(Expressions.For);
1034
- if (forLoop === undefined) {
1035
- continue;
1034
+ let end = "";
1035
+ for (const forLoop of (reduceBody === null || reduceBody === void 0 ? void 0 : reduceBody.findDirectExpressions(Expressions.For)) || []) {
1036
+ const outlineFor = this.outlineFor(forLoop, indentation, lowFile, highSyntax);
1037
+ body += outlineFor.body;
1038
+ end = outlineFor.end + `.\n` + end;
1036
1039
  }
1037
- const outlineFor = this.outlineFor(forLoop, indentation, lowFile, highSyntax);
1038
- body += outlineFor.body;
1039
1040
  const next = reduceBody.findDirectExpression(Expressions.ReduceNext);
1040
1041
  if (next === undefined) {
1041
1042
  continue;
@@ -1055,7 +1056,7 @@ ${indentation} output = ${topTarget}.`;
1055
1056
  body += concat;
1056
1057
  }
1057
1058
  }
1058
- body += indentation + outlineFor.end + `.\n`;
1059
+ body += indentation + end;
1059
1060
  body += indentation + `${uniqueName} = ${name}.\n`;
1060
1061
  const abap = `DATA ${uniqueName} TYPE ${type}.\n` +
1061
1062
  body +
@@ -1355,6 +1356,10 @@ ${indentation} output = ${topTarget}.`;
1355
1356
  if (i.getFirstToken().getStr().toUpperCase() !== "CONV") {
1356
1357
  continue;
1357
1358
  }
1359
+ const end = i.findDirectTokenByText(")");
1360
+ if (end === undefined) {
1361
+ continue;
1362
+ }
1358
1363
  const body = (_a = i.findDirectExpression(Expressions.ConvBody)) === null || _a === void 0 ? void 0 : _a.concatTokens();
1359
1364
  if (body === undefined) {
1360
1365
  continue;
@@ -1366,7 +1371,7 @@ ${indentation} output = ${topTarget}.`;
1366
1371
  indent + `${uniqueName} = ${body}.\n` +
1367
1372
  indent;
1368
1373
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), abap);
1369
- const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), uniqueName);
1374
+ const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), end.getEnd(), uniqueName);
1370
1375
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
1371
1376
  return issue_1.Issue.atToken(lowFile, i.getFirstToken(), "Downport CONV", this.getMetadata().key, this.conf.severity, fix);
1372
1377
  }
@@ -1427,6 +1432,18 @@ ${indentation} output = ${topTarget}.`;
1427
1432
  }
1428
1433
  return undefined;
1429
1434
  }
1435
+ replaceMethodConditional(node, lowFile, _highSyntax) {
1436
+ for (const c of node.findAllExpressionsRecursive(Expressions.Compare)) {
1437
+ const chain = c.findDirectExpression(Expressions.MethodCallChain);
1438
+ if (chain === undefined) {
1439
+ continue;
1440
+ }
1441
+ const end = chain.getLastToken().getEnd();
1442
+ const fix = edit_helper_1.EditHelper.insertAt(lowFile, end, " IS NOT INITIAL");
1443
+ return issue_1.Issue.atToken(lowFile, chain.getFirstToken(), "Downport method conditional", this.getMetadata().key, this.conf.severity, fix);
1444
+ }
1445
+ return undefined;
1446
+ }
1430
1447
  replaceContains(node, lowFile, highSyntax) {
1431
1448
  const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
1432
1449
  // only downport if its an single method call condition
@@ -24,10 +24,10 @@ class ExitOrCheck extends _abap_rule_1.ABAPRule {
24
24
  return {
25
25
  key: "exit_or_check",
26
26
  title: "Find EXIT or CHECK outside loops",
27
- shortDescription: `Detects usages of EXIT or CHECK statements outside of loops.
27
+ shortDescription: `Detects usages of EXIT or CHECK statements outside of loops.
28
28
  Use RETURN to leave procesing blocks instead.`,
29
- extendedInformation: `https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abenleave_processing_blocks.htm
30
- https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abapcheck_processing_blocks.htm
29
+ extendedInformation: `https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abenleave_processing_blocks.htm
30
+ https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abapcheck_processing_blocks.htm
31
31
  https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#check-vs-return`,
32
32
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
33
33
  };
@@ -22,7 +22,7 @@ class Exporting extends _abap_rule_1.ABAPRule {
22
22
  shortDescription: `Detects EXPORTING statements which can be omitted.`,
23
23
  badExample: `call_method( EXPORTING foo = bar ).`,
24
24
  goodExample: `call_method( foo = bar ).`,
25
- extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#omit-the-optional-keyword-exporting
25
+ extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#omit-the-optional-keyword-exporting
26
26
  https://docs.abapopenchecks.org/checks/30/`,
27
27
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
28
28
  };
@@ -26,7 +26,7 @@ class ForbiddenIdentifier extends _abap_rule_1.ABAPRule {
26
26
  key: "forbidden_identifier",
27
27
  title: "Forbidden Identifier",
28
28
  shortDescription: `Forbid use of specified identifiers, list of regex.`,
29
- extendedInformation: `Used in the transpiler to find javascript keywords in ABAP identifiers,
29
+ extendedInformation: `Used in the transpiler to find javascript keywords in ABAP identifiers,
30
30
  https://github.com/abaplint/transpiler/blob/bda94b8b56e2b7f2f87be2168f12361aa530220e/packages/transpiler/src/validation.ts#L44`,
31
31
  tags: [_irule_1.RuleTag.SingleFile],
32
32
  };
@@ -28,8 +28,8 @@ class ForbiddenVoidType {
28
28
  key: "forbidden_void_type",
29
29
  title: "Forbidden Void Types",
30
30
  shortDescription: `Avoid usage of specified void types.`,
31
- extendedInformation: `Inspiration:
32
- BOOLEAN, BOOLE_D, CHAR01, CHAR1, CHAR10, CHAR12, CHAR128, CHAR2, CHAR20, CHAR4, CHAR70,
31
+ extendedInformation: `Inspiration:
32
+ BOOLEAN, BOOLE_D, CHAR01, CHAR1, CHAR10, CHAR12, CHAR128, CHAR2, CHAR20, CHAR4, CHAR70,
33
33
  DATS, TIMS, DATUM, FLAG, INT4, NUMC3, NUMC4, SAP_BOOL, TEXT25, TEXT80, X255, XFELD`,
34
34
  };
35
35
  }
@@ -28,26 +28,26 @@ class FunctionalWriting extends _abap_rule_1.ABAPRule {
28
28
  key: "functional_writing",
29
29
  title: "Use functional writing",
30
30
  shortDescription: `Detects usage of call method when functional style calls can be used.`,
31
- extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-functional-to-procedural-calls
31
+ extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-functional-to-procedural-calls
32
32
  https://docs.abapopenchecks.org/checks/07/`,
33
33
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
34
- badExample: `CALL METHOD zcl_class=>method( ).
35
- CALL METHOD cl_abap_typedescr=>describe_by_name
36
- EXPORTING
37
- p_name = 'NAME'
38
- RECEIVING
39
- p_descr_ref = lr_typedescr
40
- EXCEPTIONS
41
- type_not_found = 1
34
+ badExample: `CALL METHOD zcl_class=>method( ).
35
+ CALL METHOD cl_abap_typedescr=>describe_by_name
36
+ EXPORTING
37
+ p_name = 'NAME'
38
+ RECEIVING
39
+ p_descr_ref = lr_typedescr
40
+ EXCEPTIONS
41
+ type_not_found = 1
42
42
  OTHERS = 2.`,
43
- goodExample: `zcl_class=>method( ).
44
- cl_abap_typedescr=>describe_by_name(
45
- EXPORTING
46
- p_name = 'NAME'
47
- RECEIVING
48
- p_descr_ref = lr_typedescr
49
- EXCEPTIONS
50
- type_not_found = 1
43
+ goodExample: `zcl_class=>method( ).
44
+ cl_abap_typedescr=>describe_by_name(
45
+ EXPORTING
46
+ p_name = 'NAME'
47
+ RECEIVING
48
+ p_descr_ref = lr_typedescr
49
+ EXCEPTIONS
50
+ type_not_found = 1
51
51
  OTHERS = 2 ).`,
52
52
  };
53
53
  }
@@ -18,16 +18,16 @@ class GlobalClass extends _abap_rule_1.ABAPRule {
18
18
  return {
19
19
  key: "global_class",
20
20
  title: "Global class checks",
21
- shortDescription: `Checks related to global classes.
22
-
23
- * global classes must be in own files
24
-
25
- * file names must match class name
26
-
27
- * file names must match interface name
28
-
29
- * global classes must be global definitions
30
-
21
+ shortDescription: `Checks related to global classes.
22
+
23
+ * global classes must be in own files
24
+
25
+ * file names must match class name
26
+
27
+ * file names must match interface name
28
+
29
+ * global classes must be global definitions
30
+
31
31
  * global interfaces must be global definitions`,
32
32
  tags: [_irule_1.RuleTag.Syntax],
33
33
  };
@@ -33,8 +33,8 @@ class IdenticalConditions extends _abap_rule_1.ABAPRule {
33
33
  return {
34
34
  key: "identical_conditions",
35
35
  title: "Identical conditions",
36
- shortDescription: `Find identical conditions in IF + CASE + WHILE etc
37
-
36
+ shortDescription: `Find identical conditions in IF + CASE + WHILE etc
37
+
38
38
  Prerequsites: code is pretty printed with identical cAsE`,
39
39
  tags: [_irule_1.RuleTag.SingleFile],
40
40
  };
@@ -20,23 +20,23 @@ class IdenticalContents extends _abap_rule_1.ABAPRule {
20
20
  key: "identical_contents",
21
21
  title: "Identical contents",
22
22
  shortDescription: `Find identical contents in blocks inside IFs, both in the beginning and in the end.`,
23
- extendedInformation: `
24
- Prerequsites: code is pretty printed with identical cAsE
25
-
23
+ extendedInformation: `
24
+ Prerequsites: code is pretty printed with identical cAsE
25
+
26
26
  Chained statments are ignored`,
27
27
  tags: [_irule_1.RuleTag.SingleFile],
28
- badExample: `IF foo = bar.
29
- WRITE 'bar'.
30
- WRITE 'world'.
31
- ELSE.
32
- WRITE 'foo'.
33
- WRITE 'world'.
28
+ badExample: `IF foo = bar.
29
+ WRITE 'bar'.
30
+ WRITE 'world'.
31
+ ELSE.
32
+ WRITE 'foo'.
33
+ WRITE 'world'.
34
34
  ENDIF.`,
35
- goodExample: `IF foo = bar.
36
- WRITE 'bar'.
37
- ELSE.
38
- WRITE 'foo'.
39
- ENDIF.
35
+ goodExample: `IF foo = bar.
36
+ WRITE 'bar'.
37
+ ELSE.
38
+ WRITE 'foo'.
39
+ ENDIF.
40
40
  WRITE 'world'.`,
41
41
  };
42
42
  }
@@ -16,10 +16,10 @@ class IdenticalDescriptions {
16
16
  key: "identical_descriptions",
17
17
  title: "Identical descriptions",
18
18
  shortDescription: `Searches for objects with the same type and same description`,
19
- extendedInformation: `Case insensitive
20
-
21
- Only checks the master language descriptions
22
-
19
+ extendedInformation: `Case insensitive
20
+
21
+ Only checks the master language descriptions
22
+
23
23
  Works for: INTF, CLAS, DOMA, DTEL, FUNC in same FUGR`,
24
24
  tags: [],
25
25
  };
@@ -19,15 +19,15 @@ class IfInIf extends _abap_rule_1.ABAPRule {
19
19
  key: "if_in_if",
20
20
  title: "IF in IF",
21
21
  shortDescription: `Detects nested ifs which can be refactored to a single condition using AND.`,
22
- extendedInformation: `https://docs.abapopenchecks.org/checks/01/
22
+ extendedInformation: `https://docs.abapopenchecks.org/checks/01/
23
23
  https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#keep-the-nesting-depth-low`,
24
- badExample: `IF condition1.
25
- IF condition2.
26
- ...
27
- ENDIF.
24
+ badExample: `IF condition1.
25
+ IF condition2.
26
+ ...
27
+ ENDIF.
28
28
  ENDIF.`,
29
- goodExample: `IF ( condition1 ) AND ( condition2 ).
30
- ...
29
+ goodExample: `IF ( condition1 ) AND ( condition2 ).
30
+ ...
31
31
  ENDIF.`,
32
32
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
33
33
  };
@@ -102,9 +102,9 @@ class ImplementMethods extends _abap_rule_1.ABAPRule {
102
102
  for (const i of ((_a = file.getStructure()) === null || _a === void 0 ? void 0 : _a.findAllStatements(Statements.ClassImplementation)) || []) {
103
103
  const name = (_b = i.findFirstExpression(Expressions.ClassName)) === null || _b === void 0 ? void 0 : _b.getFirstToken().getStr().toUpperCase();
104
104
  if (name === impl.identifier.getName().toUpperCase()) {
105
- return edit_helper_1.EditHelper.insertAt(file, i.getLastToken().getEnd(), `
106
- METHOD ${methodName.toLowerCase()}.
107
- RETURN. " todo, implement method
105
+ return edit_helper_1.EditHelper.insertAt(file, i.getLastToken().getEnd(), `
106
+ METHOD ${methodName.toLowerCase()}.
107
+ RETURN. " todo, implement method
108
108
  ENDMETHOD.`);
109
109
  }
110
110
  }
@@ -31,19 +31,19 @@ class InStatementIndentation extends _abap_rule_1.ABAPRule {
31
31
  key: "in_statement_indentation",
32
32
  title: "In-statement indentation",
33
33
  shortDescription: "Checks alignment within statements which span multiple lines.",
34
- extendedInformation: `Lines following the first line should be indented once (2 spaces).
35
-
36
- For block declaration statements, lines after the first should be indented an additional time (default: +2 spaces)
34
+ extendedInformation: `Lines following the first line should be indented once (2 spaces).
35
+
36
+ For block declaration statements, lines after the first should be indented an additional time (default: +2 spaces)
37
37
  to distinguish them better from code within the block.`,
38
- badExample: `IF 1 = 1
39
- AND 2 = 2.
40
- WRITE 'hello' &&
41
- 'world'.
38
+ badExample: `IF 1 = 1
39
+ AND 2 = 2.
40
+ WRITE 'hello' &&
41
+ 'world'.
42
42
  ENDIF.`,
43
- goodExample: `IF 1 = 1
44
- AND 2 = 2.
45
- WRITE 'hello' &&
46
- 'world'.
43
+ goodExample: `IF 1 = 1
44
+ AND 2 = 2.
45
+ WRITE 'hello' &&
46
+ 'world'.
47
47
  ENDIF.`,
48
48
  tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
49
49
  };
@@ -26,9 +26,9 @@ class IntfReferencingClas {
26
26
  key: "intf_referencing_clas",
27
27
  title: "INTF referencing CLAS",
28
28
  shortDescription: `Interface contains references to class`,
29
- extendedInformation: `Only global interfaces are checked.
30
- Only first level references are checked.
31
- Exception class references are ignored.
29
+ extendedInformation: `Only global interfaces are checked.
30
+ Only first level references are checked.
31
+ Exception class references are ignored.
32
32
  Void references are ignored.`,
33
33
  };
34
34
  }
@@ -141,12 +141,16 @@ class KeywordCase extends _abap_rule_1.ABAPRule {
141
141
  }
142
142
  }
143
143
  const skip = new Skip(this.getConfig());
144
+ let prev = undefined;
144
145
  for (const statement of file.getStatements()) {
145
146
  if (skip.skipStatement(statement) === true) {
146
147
  continue;
147
148
  }
148
149
  let result = this.traverse(statement, statement.get());
149
150
  if (result.length > 0) {
151
+ if (prev && result[0].token.getStart().equals(prev.getStart())) {
152
+ continue;
153
+ }
150
154
  if (statement.getColon() !== undefined) {
151
155
  // if its a chained statement, go token by token
152
156
  result = [result[0]];
@@ -156,6 +160,7 @@ class KeywordCase extends _abap_rule_1.ABAPRule {
156
160
  if (issues.length > MAX_ISSUES) {
157
161
  break;
158
162
  }
163
+ prev = result[0].token;
159
164
  }
160
165
  }
161
166
  return issues;
@@ -15,8 +15,8 @@ class LineBreakStyle {
15
15
  return {
16
16
  key: "line_break_style",
17
17
  title: "Makes sure line breaks are consistent in the ABAP code",
18
- shortDescription: `Enforces LF as newlines in ABAP files
19
-
18
+ shortDescription: `Enforces LF as newlines in ABAP files
19
+
20
20
  abapGit does not work with CRLF`,
21
21
  tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.SingleFile],
22
22
  };
@@ -23,7 +23,7 @@ class LineLength extends _abap_rule_1.ABAPRule {
23
23
  key: "line_length",
24
24
  title: "Line length",
25
25
  shortDescription: `Detects lines exceeding the provided maximum length.`,
26
- extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#stick-to-a-reasonable-line-length
26
+ extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#stick-to-a-reasonable-line-length
27
27
  https://docs.abapopenchecks.org/checks/04/`,
28
28
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
29
29
  };
@@ -27,7 +27,7 @@ class LineOnlyPunc extends _abap_rule_1.ABAPRule {
27
27
  key: "line_only_punc",
28
28
  title: "Line containing only punctuation",
29
29
  shortDescription: `Detects lines containing only punctuation.`,
30
- extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#close-brackets-at-line-end
30
+ extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#close-brackets-at-line-end
31
31
  https://docs.abapopenchecks.org/checks/16/`,
32
32
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
33
33
  badExample: "zcl_class=>method(\n).",