@abaplint/core 2.79.22 → 2.79.23

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 (74) hide show
  1. package/README.md +6 -6
  2. package/build/abaplint.d.ts +5 -0
  3. package/build/src/abap/2_statements/expressions/index.js +1 -0
  4. package/build/src/abap/2_statements/expressions/reduce_body.js +2 -2
  5. package/build/src/abap/2_statements/expressions/reduce_next.js +13 -0
  6. package/build/src/abap/5_syntax/expressions/reduce_body.js +4 -0
  7. package/build/src/abap/5_syntax/expressions/reduce_next.js +17 -0
  8. package/build/src/lsp/help.js +7 -7
  9. package/build/src/registry.js +1 -1
  10. package/build/src/rules/abapdoc.js +1 -1
  11. package/build/src/rules/ambiguous_statement.js +5 -5
  12. package/build/src/rules/avoid_use.js +6 -6
  13. package/build/src/rules/begin_end_names.js +4 -4
  14. package/build/src/rules/begin_single_include.js +12 -12
  15. package/build/src/rules/chain_mainly_declarations.js +4 -4
  16. package/build/src/rules/check_abstract.js +2 -2
  17. package/build/src/rules/check_comments.js +3 -3
  18. package/build/src/rules/check_include.js +3 -3
  19. package/build/src/rules/check_no_handler_pragma.js +8 -8
  20. package/build/src/rules/check_subrc.js +8 -8
  21. package/build/src/rules/commented_code.js +1 -1
  22. package/build/src/rules/constructor_visibility_public.js +4 -4
  23. package/build/src/rules/contains_tab.js +2 -2
  24. package/build/src/rules/downport.js +131 -36
  25. package/build/src/rules/exit_or_check.js +3 -3
  26. package/build/src/rules/exporting.js +1 -1
  27. package/build/src/rules/forbidden_identifier.js +1 -1
  28. package/build/src/rules/forbidden_void_type.js +2 -2
  29. package/build/src/rules/functional_writing.js +17 -17
  30. package/build/src/rules/global_class.js +4 -4
  31. package/build/src/rules/identical_conditions.js +2 -2
  32. package/build/src/rules/identical_contents.js +15 -15
  33. package/build/src/rules/identical_descriptions.js +4 -4
  34. package/build/src/rules/if_in_if.js +7 -7
  35. package/build/src/rules/implement_methods.js +3 -3
  36. package/build/src/rules/in_statement_indentation.js +11 -11
  37. package/build/src/rules/intf_referencing_clas.js +3 -3
  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/nesting.js +1 -1
  46. package/build/src/rules/no_public_attributes.js +1 -1
  47. package/build/src/rules/no_yoda_conditions.js +4 -4
  48. package/build/src/rules/obsolete_statement.js +36 -36
  49. package/build/src/rules/omit_parameter_name.js +3 -3
  50. package/build/src/rules/omit_receiving.js +13 -13
  51. package/build/src/rules/parser_702_chaining.js +2 -2
  52. package/build/src/rules/parser_error.js +2 -2
  53. package/build/src/rules/parser_missing_space.js +1 -1
  54. package/build/src/rules/prefer_inline.js +16 -16
  55. package/build/src/rules/prefer_is_not.js +7 -7
  56. package/build/src/rules/prefer_raise_exception_new.js +3 -3
  57. package/build/src/rules/prefer_returning_to_exporting.js +1 -1
  58. package/build/src/rules/prefer_xsdbool.js +2 -2
  59. package/build/src/rules/remove_descriptions.js +4 -4
  60. package/build/src/rules/rfc_error_handling.js +9 -9
  61. package/build/src/rules/select_add_order_by.js +5 -5
  62. package/build/src/rules/select_performance.js +2 -2
  63. package/build/src/rules/sicf_consistency.js +4 -4
  64. package/build/src/rules/space_before_dot.js +2 -2
  65. package/build/src/rules/start_at_tab.js +1 -1
  66. package/build/src/rules/sy_modification.js +2 -2
  67. package/build/src/rules/tabl_enhancement_category.js +2 -2
  68. package/build/src/rules/unused_methods.js +9 -9
  69. package/build/src/rules/unused_variables.js +6 -6
  70. package/build/src/rules/use_bool_expression.js +8 -8
  71. package/build/src/rules/use_line_exists.js +6 -6
  72. package/build/src/rules/use_new.js +2 -2
  73. package/build/src/rules/when_others_last.js +6 -6
  74. package/package.json +76 -76
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # @abaplint/core
2
-
3
- [abaplint](https://abaplint.org/) core library
4
-
5
- Exposes functionallity like the parser and rules, which can be used in other projects.
6
-
1
+ # @abaplint/core
2
+
3
+ [abaplint](https://abaplint.org/) core library
4
+
5
+ Exposes functionallity like the parser and rules, which can be used in other projects.
6
+
7
7
  For more information see https://github.com/abaplint/abaplint
@@ -1764,6 +1764,7 @@ declare namespace Expressions {
1764
1764
  ReceiveParameters,
1765
1765
  Redefinition,
1766
1766
  ReduceBody,
1767
+ ReduceNext,
1767
1768
  ReportName,
1768
1769
  SelectLoop_2 as SelectLoop,
1769
1770
  Select_3 as Select,
@@ -4086,6 +4087,10 @@ declare class ReduceBody extends Expression {
4086
4087
  getRunnable(): IStatementRunnable;
4087
4088
  }
4088
4089
 
4090
+ declare class ReduceNext extends Expression {
4091
+ getRunnable(): IStatementRunnable;
4092
+ }
4093
+
4089
4094
  export declare enum ReferenceType {
4090
4095
  /** for classes and interface references */
4091
4096
  ObjectOrientedReference = "ObjectOrientedReference",
@@ -137,6 +137,7 @@ __exportStar(require("./read_table_target"), exports);
137
137
  __exportStar(require("./receive_parameters"), exports);
138
138
  __exportStar(require("./redefinition"), exports);
139
139
  __exportStar(require("./reduce_body"), exports);
140
+ __exportStar(require("./reduce_next"), exports);
140
141
  __exportStar(require("./report_name"), exports);
141
142
  __exportStar(require("./select_loop"), exports);
142
143
  __exportStar(require("./select"), exports);
@@ -3,11 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ReduceBody = void 0;
4
4
  const combi_1 = require("../combi");
5
5
  const _1 = require(".");
6
+ const reduce_next_1 = require("./reduce_next");
6
7
  class ReduceBody extends combi_1.Expression {
7
8
  getRunnable() {
8
- const fields = (0, combi_1.seq)(_1.Field, "=", _1.Source);
9
9
  const init = (0, combi_1.seq)("INIT", (0, combi_1.plus)(_1.InlineFieldDefinition));
10
- return (0, combi_1.seq)((0, combi_1.opt)(_1.Let), init, _1.For, "NEXT", (0, combi_1.plus)(fields));
10
+ return (0, combi_1.seq)((0, combi_1.opt)(_1.Let), init, _1.For, reduce_next_1.ReduceNext);
11
11
  }
12
12
  }
13
13
  exports.ReduceBody = ReduceBody;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReduceNext = void 0;
4
+ const combi_1 = require("../combi");
5
+ const _1 = require(".");
6
+ class ReduceNext extends combi_1.Expression {
7
+ getRunnable() {
8
+ const fields = (0, combi_1.seq)(_1.Field, "=", _1.Source);
9
+ return (0, combi_1.seq)("NEXT", (0, combi_1.plus)(fields));
10
+ }
11
+ }
12
+ exports.ReduceNext = ReduceNext;
13
+ //# sourceMappingURL=reduce_next.js.map
@@ -7,6 +7,7 @@ const source_1 = require("./source");
7
7
  const inline_field_definition_1 = require("./inline_field_definition");
8
8
  const unknown_type_1 = require("../../types/basic/unknown_type");
9
9
  const _scope_type_1 = require("../_scope_type");
10
+ const reduce_next_1 = require("./reduce_next");
10
11
  class ReduceBody {
11
12
  runSyntax(node, scope, filename) {
12
13
  if (node === undefined) {
@@ -22,6 +23,9 @@ class ReduceBody {
22
23
  for (const s of node.findDirectExpressions(Expressions.Source)) {
23
24
  new source_1.Source().runSyntax(s, scope, filename);
24
25
  }
26
+ for (const s of node.findDirectExpressions(Expressions.ReduceNext)) {
27
+ new reduce_next_1.ReduceNext().runSyntax(s, scope, filename);
28
+ }
25
29
  if (scope.getType() === _scope_type_1.ScopeType.For) {
26
30
  scope.pop(node.getLastToken().getEnd());
27
31
  }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReduceNext = void 0;
4
+ const Expressions = require("../../2_statements/expressions");
5
+ const source_1 = require("./source");
6
+ class ReduceNext {
7
+ runSyntax(node, scope, filename) {
8
+ if (node === undefined) {
9
+ return;
10
+ }
11
+ for (const s of node.findDirectExpressions(Expressions.Source)) {
12
+ new source_1.Source().runSyntax(s, scope, filename);
13
+ }
14
+ }
15
+ }
16
+ exports.ReduceNext = ReduceNext;
17
+ //# sourceMappingURL=reduce_next.js.map
@@ -9,13 +9,13 @@ const dump_scope_1 = require("./dump_scope");
9
9
  class Help {
10
10
  static find(reg, textDocument, position) {
11
11
  let content = "";
12
- content = `
13
- <a href="#_tokens" rel="no-refresh">Tokens</a> |
14
- <a href="#_statements" rel="no-refresh">Statements</a> |
15
- <a href="#_structure" rel="no-refresh">Structure</a> |
16
- <a href="#_files" rel="no-refresh">Files</a> |
17
- <a href="#_info" rel="no-refresh">Info Dump</a>
18
- <hr>
12
+ content = `
13
+ <a href="#_tokens" rel="no-refresh">Tokens</a> |
14
+ <a href="#_statements" rel="no-refresh">Statements</a> |
15
+ <a href="#_structure" rel="no-refresh">Structure</a> |
16
+ <a href="#_files" rel="no-refresh">Files</a> |
17
+ <a href="#_info" rel="no-refresh">Info Dump</a>
18
+ <hr>
19
19
  ` +
20
20
  "<tt>" + textDocument.uri + " (" +
21
21
  (position.line + 1) + ", " +
@@ -68,7 +68,7 @@ class Registry {
68
68
  }
69
69
  static abaplintVersion() {
70
70
  // magic, see build script "version.sh"
71
- return "2.79.22";
71
+ return "2.79.23";
72
72
  }
73
73
  getDDICReferences() {
74
74
  return this.references;
@@ -23,7 +23,7 @@ class Abapdoc extends _abap_rule_1.ABAPRule {
23
23
  return {
24
24
  key: "abapdoc",
25
25
  title: "Check abapdoc",
26
- shortDescription: `Various checks regarding abapdoc.
26
+ shortDescription: `Various checks regarding abapdoc.
27
27
  Base rule checks for existence of abapdoc for public class methods and all interface methods.`,
28
28
  tags: [_irule_1.RuleTag.SingleFile],
29
29
  };
@@ -20,14 +20,14 @@ class AmbiguousStatement extends _abap_rule_1.ABAPRule {
20
20
  return {
21
21
  key: "ambiguous_statement",
22
22
  title: "Check for ambigious statements",
23
- shortDescription: `Checks for ambiguity between deleting or modifying from internal and database table
24
- Add "TABLE" keyword or "@" for escaping SQL variables
25
-
23
+ shortDescription: `Checks for ambiguity between deleting or modifying from internal and database table
24
+ Add "TABLE" keyword or "@" for escaping SQL variables
25
+
26
26
  Only works if the target version is 740sp05 or above`,
27
27
  tags: [_irule_1.RuleTag.SingleFile],
28
- badExample: `DELETE foo FROM bar.
28
+ badExample: `DELETE foo FROM bar.
29
29
  MODIFY foo FROM bar.`,
30
- goodExample: `DELETE foo FROM @bar.
30
+ goodExample: `DELETE foo FROM @bar.
31
31
  MODIFY TABLE foo FROM bar.`,
32
32
  };
33
33
  }
@@ -35,12 +35,12 @@ class AvoidUse extends _abap_rule_1.ABAPRule {
35
35
  key: "avoid_use",
36
36
  title: "Avoid use of certain statements",
37
37
  shortDescription: `Detects usage of certain statements.`,
38
- extendedInformation: `DEFAULT KEY: https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#avoid-default-key
39
-
40
- Macros: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abenmacros_guidl.htm
41
-
42
- STATICS: use CLASS-DATA instead
43
-
38
+ extendedInformation: `DEFAULT KEY: https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#avoid-default-key
39
+
40
+ Macros: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abenmacros_guidl.htm
41
+
42
+ STATICS: use CLASS-DATA instead
43
+
44
44
  DESCRIBE TABLE LINES: use lines() instead (quickfix exists)`,
45
45
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
46
46
  };
@@ -23,11 +23,11 @@ class BeginEndNames extends _abap_rule_1.ABAPRule {
23
23
  title: "Check BEGIN END names",
24
24
  shortDescription: `Check BEGIN OF and END OF names match, plus there must be statements between BEGIN and END`,
25
25
  tags: [_irule_1.RuleTag.Syntax, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
26
- badExample: `DATA: BEGIN OF stru,
27
- field TYPE i,
26
+ badExample: `DATA: BEGIN OF stru,
27
+ field TYPE i,
28
28
  END OF structure_not_the_same.`,
29
- goodExample: `DATA: BEGIN OF stru,
30
- field TYPE i,
29
+ goodExample: `DATA: BEGIN OF stru,
30
+ field TYPE i,
31
31
  END OF stru.`,
32
32
  };
33
33
  }
@@ -21,19 +21,19 @@ class BeginSingleInclude extends _abap_rule_1.ABAPRule {
21
21
  title: "BEGIN contains single INCLUDE",
22
22
  shortDescription: `Finds TYPE BEGIN with just one INCLUDE TYPE, and DATA with single INCLUDE STRUCTURE`,
23
23
  tags: [_irule_1.RuleTag.SingleFile],
24
- badExample: `TYPES: BEGIN OF dummy1.
25
- INCLUDE TYPE dselc.
26
- TYPES: END OF dummy1.
27
-
28
- DATA BEGIN OF foo.
29
- INCLUDE STRUCTURE syst.
30
- DATA END OF foo.
31
-
32
- STATICS BEGIN OF bar.
33
- INCLUDE STRUCTURE syst.
24
+ badExample: `TYPES: BEGIN OF dummy1.
25
+ INCLUDE TYPE dselc.
26
+ TYPES: END OF dummy1.
27
+
28
+ DATA BEGIN OF foo.
29
+ INCLUDE STRUCTURE syst.
30
+ DATA END OF foo.
31
+
32
+ STATICS BEGIN OF bar.
33
+ INCLUDE STRUCTURE syst.
34
34
  STATICS END OF bar.`,
35
- goodExample: `DATA BEGIN OF foo.
36
- INCLUDE STRUCTURE dselc.
35
+ goodExample: `DATA BEGIN OF foo.
36
+ INCLUDE STRUCTURE dselc.
37
37
  DATA END OF foo.`,
38
38
  };
39
39
  }
@@ -45,10 +45,10 @@ class ChainMainlyDeclarations extends _abap_rule_1.ABAPRule {
45
45
  key: "chain_mainly_declarations",
46
46
  title: "Chain mainly declarations",
47
47
  shortDescription: `Chain mainly declarations, allows chaining for the configured statements, reports errors for other statements.`,
48
- extendedInformation: `
49
- https://docs.abapopenchecks.org/checks/23/
50
-
51
- https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abenchained_statements_guidl.htm
48
+ extendedInformation: `
49
+ https://docs.abapopenchecks.org/checks/23/
50
+
51
+ https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abenchained_statements_guidl.htm
52
52
  `,
53
53
  tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
54
54
  badExample: `CALL METHOD: bar.`,
@@ -23,8 +23,8 @@ class CheckAbstract extends _abap_rule_1.ABAPRule {
23
23
  return {
24
24
  key: "check_abstract",
25
25
  title: "Check abstract methods and classes",
26
- shortDescription: `Checks abstract methods and classes:
27
- - class defined as abstract and final,
26
+ shortDescription: `Checks abstract methods and classes:
27
+ - class defined as abstract and final,
28
28
  - non-abstract class contains abstract methods`,
29
29
  extendedInformation: `If a class defines only constants, use an interface instead`,
30
30
  tags: [_irule_1.RuleTag.SingleFile],
@@ -27,9 +27,9 @@ class CheckComments extends _abap_rule_1.ABAPRule {
27
27
  return {
28
28
  key: "check_comments",
29
29
  title: "Check Comments",
30
- shortDescription: `
31
- Various checks for comment usage.
32
-
30
+ shortDescription: `
31
+ Various checks for comment usage.
32
+
33
33
  * End of line comments. Comments starting with "#EC" or "##" are ignored`,
34
34
  extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#put-comments-before-the-statement-they-relate-to`,
35
35
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
@@ -17,9 +17,9 @@ class CheckInclude {
17
17
  key: "check_include",
18
18
  title: "Check INCLUDEs",
19
19
  shortDescription: `Checks INCLUDE statements`,
20
- extendedInformation: `
21
- * Reports unused includes
22
- * Errors if the includes are not found
20
+ extendedInformation: `
21
+ * Reports unused includes
22
+ * Errors if the includes are not found
23
23
  * Error if including a main program`,
24
24
  tags: [_irule_1.RuleTag.Syntax],
25
25
  };
@@ -21,15 +21,15 @@ class CheckNoHandlerPragma extends _abap_rule_1.ABAPRule {
21
21
  title: "Check if NO_HANDLER can be removed",
22
22
  shortDescription: `Checks NO_HANDLER pragmas that can be removed`,
23
23
  tags: [_irule_1.RuleTag.SingleFile],
24
- badExample: `TRY.
25
- ...
26
- CATCH zcx_abapgit_exception ##NO_HANDLER.
27
- RETURN. " it has a handler
24
+ badExample: `TRY.
25
+ ...
26
+ CATCH zcx_abapgit_exception ##NO_HANDLER.
27
+ RETURN. " it has a handler
28
28
  ENDTRY.`,
29
- goodExample: `TRY.
30
- ...
31
- CATCH zcx_abapgit_exception.
32
- RETURN.
29
+ goodExample: `TRY.
30
+ ...
31
+ CATCH zcx_abapgit_exception.
32
+ RETURN.
33
33
  ENDTRY.`,
34
34
  };
35
35
  }
@@ -34,14 +34,14 @@ class CheckSubrc extends _abap_rule_1.ABAPRule {
34
34
  key: "check_subrc",
35
35
  title: "Check sy-subrc",
36
36
  shortDescription: `Check sy-subrc`,
37
- extendedInformation: `Pseudo comment "#EC CI_SUBRC can be added to suppress findings
38
-
39
- If sy-dbcnt is checked after database statements, it is considered okay.
40
-
41
- "SELECT SINGLE @abap_true FROM " is considered as an existence check
42
-
43
- If IS ASSIGNED is checked after assigning, it is considered okay.
44
-
37
+ extendedInformation: `Pseudo comment "#EC CI_SUBRC can be added to suppress findings
38
+
39
+ If sy-dbcnt is checked after database statements, it is considered okay.
40
+
41
+ "SELECT SINGLE @abap_true FROM " is considered as an existence check
42
+
43
+ If IS ASSIGNED is checked after assigning, it is considered okay.
44
+
45
45
  FIND statement with MATCH COUNT is considered okay if subrc is not checked`,
46
46
  tags: [_irule_1.RuleTag.SingleFile],
47
47
  pseudoComment: "EC CI_SUBRC",
@@ -30,7 +30,7 @@ class CommentedCode extends _abap_rule_1.ABAPRule {
30
30
  key: "commented_code",
31
31
  title: "Find commented code",
32
32
  shortDescription: `Detects usage of commented out code.`,
33
- extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#delete-code-instead-of-commenting-it
33
+ extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#delete-code-instead-of-commenting-it
34
34
  https://docs.abapopenchecks.org/checks/14/`,
35
35
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
36
36
  };
@@ -18,10 +18,10 @@ class ConstructorVisibilityPublic {
18
18
  key: "constructor_visibility_public",
19
19
  title: "Check constructor visibility is public",
20
20
  shortDescription: `Constructor must be placed in the public section, even if the class is not CREATE PUBLIC.`,
21
- extendedInformation: `
22
- This only applies to global classes.
23
-
24
- https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#if-your-global-class-is-create-private-leave-the-constructor-public
21
+ extendedInformation: `
22
+ This only applies to global classes.
23
+
24
+ https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#if-your-global-class-is-create-private-leave-the-constructor-public
25
25
  https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abeninstance_constructor_guidl.htm`,
26
26
  tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
27
27
  };
@@ -25,8 +25,8 @@ class ContainsTab extends _abap_rule_1.ABAPRule {
25
25
  key: "contains_tab",
26
26
  title: "Code contains tab",
27
27
  shortDescription: `Checks for usage of tabs (enable to enforce spaces)`,
28
- extendedInformation: `
29
- https://docs.abapopenchecks.org/checks/09/
28
+ extendedInformation: `
29
+ https://docs.abapopenchecks.org/checks/09/
30
30
  https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#indent-and-snap-to-tab`,
31
31
  tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
32
32
  };
@@ -19,6 +19,7 @@ const _typed_identifier_1 = require("../abap/types/_typed_identifier");
19
19
  const basic_1 = require("../abap/types/basic");
20
20
  const config_1 = require("../config");
21
21
  const tokens_1 = require("../abap/1_lexer/tokens");
22
+ // todo: refactor each sub-rule to new classes
22
23
  class DownportConf extends _basic_rule_config_1.BasicRuleConfig {
23
24
  }
24
25
  exports.DownportConf = DownportConf;
@@ -31,26 +32,27 @@ class Downport {
31
32
  key: "downport",
32
33
  title: "Downport statement",
33
34
  shortDescription: `Experimental downport functionality`,
34
- extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with
35
- a higher level language version. If successful, various rules are applied to downport the statement.
36
- Target downport version is always v702, thus rule is only enabled if target version is v702.
37
-
38
- Current rules:
39
- * NEW transformed to CREATE OBJECT, opposite of https://rules.abaplint.org/use_new/
40
- * DATA() definitions are outlined, opposite of https://rules.abaplint.org/prefer_inline/
41
- * FIELD-SYMBOL() definitions are outlined
42
- * CONV is outlined
43
- * COND is outlined
44
- * EMPTY KEY is changed to DEFAULT KEY, opposite of DEFAULT KEY in https://rules.abaplint.org/avoid_use/
45
- * CAST changed to ?=
46
- * LOOP AT method_call( ) is outlined
47
- * VALUE # with structure fields
48
- * VALUE # with internal table lines
49
- * Table Expressions[ index ] are outlined
50
- * SELECT INTO @DATA definitions are outlined
51
- * Some occurrences of string template formatting option ALPHA changed to function module call
52
- * SELECT/INSERT/MODIFY/DELETE/UPDATE "," in field list removed, "@" in source/targets removed
53
-
35
+ extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with
36
+ a higher level language version. If successful, various rules are applied to downport the statement.
37
+ Target downport version is always v702, thus rule is only enabled if target version is v702.
38
+
39
+ Current rules:
40
+ * NEW transformed to CREATE OBJECT, opposite of https://rules.abaplint.org/use_new/
41
+ * DATA() definitions are outlined, opposite of https://rules.abaplint.org/prefer_inline/
42
+ * FIELD-SYMBOL() definitions are outlined
43
+ * CONV is outlined
44
+ * COND is outlined
45
+ * REDUCE is outlined
46
+ * EMPTY KEY is changed to DEFAULT KEY, opposite of DEFAULT KEY in https://rules.abaplint.org/avoid_use/
47
+ * CAST changed to ?=
48
+ * LOOP AT method_call( ) is outlined
49
+ * VALUE # with structure fields
50
+ * VALUE # with internal table lines
51
+ * Table Expressions[ index ] are outlined
52
+ * SELECT INTO @DATA definitions are outlined
53
+ * Some occurrences of string template formatting option ALPHA changed to function module call
54
+ * SELECT/INSERT/MODIFY/DELETE/UPDATE "," in field list removed, "@" in source/targets removed
55
+
54
56
  Only one transformation is applied to a statement at a time, so multiple steps might be required to do the full downport.`,
55
57
  tags: [_irule_1.RuleTag.Experimental, _irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],
56
58
  };
@@ -169,6 +171,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
169
171
  if (found) {
170
172
  return found;
171
173
  }
174
+ found = this.outlineReduce(high, lowFile, highSyntax);
175
+ if (found) {
176
+ return found;
177
+ }
172
178
  found = this.outlineCast(high, lowFile, highSyntax);
173
179
  if (found) {
174
180
  return found;
@@ -300,10 +306,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
300
306
  const fieldName = f.concatTokens();
301
307
  fieldDefinition += indentation + " " + fieldName + " TYPE " + tableName + "-" + fieldName + ",\n";
302
308
  }
303
- fieldDefinition = `DATA: BEGIN OF ${name},
309
+ fieldDefinition = `DATA: BEGIN OF ${name},
304
310
  ${fieldDefinition}${indentation} END OF ${name}.`;
305
311
  }
306
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `${fieldDefinition}
312
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `${fieldDefinition}
307
313
  ${indentation}`);
308
314
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inlineData.getFirstToken().getStart(), inlineData.getLastToken().getEnd(), name);
309
315
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
@@ -339,9 +345,9 @@ ${indentation}`);
339
345
  }
340
346
  const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
341
347
  const name = ((_c = inlineData.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || "error";
342
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `TYPES: BEGIN OF ${uniqueName},
343
- ${fieldDefinitions}${indentation} END OF ${uniqueName}.
344
- ${indentation}DATA ${name} TYPE STANDARD TABLE OF ${uniqueName} WITH DEFAULT KEY.
348
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `TYPES: BEGIN OF ${uniqueName},
349
+ ${fieldDefinitions}${indentation} END OF ${uniqueName}.
350
+ ${indentation}DATA ${name} TYPE STANDARD TABLE OF ${uniqueName} WITH DEFAULT KEY.
345
351
  ${indentation}`);
346
352
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inlineData.getFirstToken().getStart(), inlineData.getLastToken().getEnd(), name);
347
353
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
@@ -375,11 +381,11 @@ ${indentation}`);
375
381
  const uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
376
382
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
377
383
  const firstToken = node.getFirstToken();
378
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
379
- ${indentation}READ TABLE ${pre} INDEX ${(_a = tableExpression.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens()} INTO ${uniqueName}.
380
- ${indentation}IF sy-subrc <> 0.
381
- ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
382
- ${indentation}ENDIF.
384
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
385
+ ${indentation}READ TABLE ${pre} INDEX ${(_a = tableExpression.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens()} INTO ${uniqueName}.
386
+ ${indentation}IF sy-subrc <> 0.
387
+ ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
388
+ ${indentation}ENDIF.
383
389
  ${indentation}`);
384
390
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, startToken.getStart(), tableExpression.getLastToken().getEnd(), uniqueName);
385
391
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
@@ -478,10 +484,10 @@ ${indentation}`);
478
484
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
479
485
  const source = (_b = templateSource === null || templateSource === void 0 ? void 0 : templateSource.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens();
480
486
  const topTarget = (_c = node.findDirectExpression(Expressions.Target)) === null || _c === void 0 ? void 0 : _c.concatTokens();
481
- const code = `CALL FUNCTION '${functionName}'
482
- ${indentation} EXPORTING
483
- ${indentation} input = ${source}
484
- ${indentation} IMPORTING
487
+ const code = `CALL FUNCTION '${functionName}'
488
+ ${indentation} EXPORTING
489
+ ${indentation} input = ${source}
490
+ ${indentation} IMPORTING
485
491
  ${indentation} output = ${topTarget}.`;
486
492
  const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getFirstToken().getStart(), node.getLastToken().getEnd(), code);
487
493
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Downport ALPHA", this.getMetadata().key, this.conf.severity, fix);
@@ -541,6 +547,66 @@ ${indentation} output = ${topTarget}.`;
541
547
  }
542
548
  return undefined;
543
549
  }
550
+ outlineReduce(node, lowFile, highSyntax) {
551
+ var _a, _b, _c;
552
+ for (const i of node.findAllExpressionsRecursive(Expressions.Source)) {
553
+ const firstToken = i.getFirstToken();
554
+ if (firstToken.getStr().toUpperCase() !== "REDUCE") {
555
+ continue;
556
+ }
557
+ const type = this.findType(i, lowFile, highSyntax);
558
+ if (type === undefined) {
559
+ continue;
560
+ }
561
+ const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
562
+ const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
563
+ let body = "";
564
+ let name = "";
565
+ const reduceBody = i.findDirectExpression(Expressions.ReduceBody);
566
+ if (reduceBody === undefined) {
567
+ continue;
568
+ }
569
+ for (const init of reduceBody.findDirectExpressions(Expressions.InlineFieldDefinition)) {
570
+ name = init.getFirstToken().getStr();
571
+ body += indentation + `DATA(${name}) = ${(_a = reduceBody.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens()}.\n`;
572
+ }
573
+ const loop = reduceBody.findFirstExpression(Expressions.InlineLoopDefinition);
574
+ if (loop === undefined) {
575
+ continue;
576
+ }
577
+ const loopSource = (_b = loop.findFirstExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens();
578
+ const loopTarget = (_c = loop.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens();
579
+ body += indentation + `LOOP AT ${loopSource} INTO DATA(${loopTarget}).\n`;
580
+ const next = reduceBody.findDirectExpression(Expressions.ReduceNext);
581
+ if (next === undefined) {
582
+ continue;
583
+ }
584
+ for (const n of next.getChildren()) {
585
+ if (n.concatTokens().toUpperCase() === "NEXT") {
586
+ continue;
587
+ }
588
+ else if (n.concatTokens() === "=") {
589
+ body += " = ";
590
+ }
591
+ else if (n.get() instanceof Expressions.Field) {
592
+ body += indentation + " " + n.concatTokens();
593
+ }
594
+ else if (n.get() instanceof Expressions.Source) {
595
+ body += n.concatTokens() + ".\n";
596
+ }
597
+ }
598
+ body += indentation + `ENDLOOP.\n`;
599
+ body += indentation + `${uniqueName} = ${name}.\n`;
600
+ const abap = `DATA ${uniqueName} TYPE ${type}.\n` +
601
+ body +
602
+ indentation;
603
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), abap);
604
+ const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), i.getLastToken().getEnd(), uniqueName);
605
+ const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
606
+ return issue_1.Issue.atToken(lowFile, firstToken, "Downport REDUCE", this.getMetadata().key, this.conf.severity, fix);
607
+ }
608
+ return undefined;
609
+ }
544
610
  outlineValue(node, lowFile, highSyntax) {
545
611
  var _a;
546
612
  for (const i of node.findAllExpressionsRecursive(Expressions.Source)) {
@@ -570,10 +636,13 @@ ${indentation} output = ${topTarget}.`;
570
636
  }
571
637
  body += indentation + structureName + "-" + b.concatTokens() + ".\n";
572
638
  }
573
- if (b.get() instanceof Expressions.Source) {
639
+ else if (b.get() instanceof Expressions.Source) {
574
640
  structureName = b.concatTokens();
575
641
  }
576
- if (b.concatTokens() === ")") {
642
+ else if (b instanceof nodes_1.ExpressionNode && b.get() instanceof Expressions.Let) {
643
+ body += this.outlineLet(b, indentation, highSyntax, lowFile);
644
+ }
645
+ else if (b.concatTokens() === ")") {
577
646
  body += indentation + `APPEND ${structureName} TO ${uniqueName}.\n`;
578
647
  }
579
648
  }
@@ -587,6 +656,32 @@ ${indentation} output = ${topTarget}.`;
587
656
  }
588
657
  return undefined;
589
658
  }
659
+ outlineLet(node, indentation, highSyntax, lowFile) {
660
+ var _a;
661
+ let ret = "";
662
+ for (const f of node.findDirectExpressions(Expressions.InlineFieldDefinition)) {
663
+ const c = f.getFirstChild();
664
+ if (c === undefined) {
665
+ continue;
666
+ }
667
+ const name = c.concatTokens().toLowerCase();
668
+ const spag = highSyntax.spaghetti.lookupPosition(c.getFirstToken().getStart(), lowFile.getFilename());
669
+ if (spag === undefined) {
670
+ continue;
671
+ }
672
+ const found = spag.findVariable(name);
673
+ if (found === undefined) {
674
+ continue;
675
+ }
676
+ const type = found.getType().getQualifiedName() ? (_a = found.getType().getQualifiedName()) === null || _a === void 0 ? void 0 : _a.toLowerCase() : found.getType().toABAP();
677
+ ret += indentation + "DATA " + name + ` TYPE ${type}.\n`;
678
+ const source = node.findFirstExpression(Expressions.Source);
679
+ if (source) {
680
+ ret += indentation + name + ` = ${source.concatTokens()}.\n`;
681
+ }
682
+ }
683
+ return ret;
684
+ }
590
685
  findType(i, lowFile, highSyntax) {
591
686
  var _a;
592
687
  const expr = i.findDirectExpression(Expressions.TypeNameOrInfer);
@@ -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
  };