diff --git a/docs/_checks/02.md b/docs/_checks/02.md index cada9fb1..e9a4b955 100644 --- a/docs/_checks/02.md +++ b/docs/_checks/02.md @@ -15,8 +15,19 @@ Note: this check is also part of SAP standard in "Extended Program Check" -> "Pr ### CHECK See [https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abapcheck_processing_blocks.htm](https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abapcheck_processing_blocks.htm) + +> #### **Rule** ([see](https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abenexit_procedure_guidl.htm#@@ITOC@@ABENEXIT_PROCEDURE_GUIDL_2)) +> Only use RETURN to exit procedures +> +> ##### **Exception** +> An exception to the rule to only use RETURN to exit procedures are CHECK statements that are located at the beginning of a procedure and that check the prerequisites for the execution of the procedure there. Using the CHECK statement in such a way does not impair the legibility and is thus allowed. However, this exception does not apply to other positions within a procedure and outside loops. + [https://github.com/SAP/styleguides/blob/master/clean-abap/CleanABAP.md#check-vs-return](https://github.com/SAP/styleguides/blob/master/clean-abap/CleanABAP.md#check-vs-return) + + + + Note: this check is also part of SAP standard in "Extended Program Check" -> "Programming Guidelines". ### Configuration diff --git a/src/checks/zcl_aoc_check_02.clas.abap b/src/checks/zcl_aoc_check_02.clas.abap index ecb004d7..47f58447 100644 --- a/src/checks/zcl_aoc_check_02.clas.abap +++ b/src/checks/zcl_aoc_check_02.clas.abap @@ -19,6 +19,13 @@ CLASS zcl_aoc_check_02 DEFINITION PROTECTED SECTION. DATA mv_check TYPE flag. DATA mv_exit TYPE flag. + + METHODS _is_check_allow + IMPORTING + !io_scan TYPE REF TO zcl_aoc_scan + !iv_statement_index TYPE i + RETURNING + VALUE(rv_result) TYPE abap_bool . PRIVATE SECTION. ENDCLASS. @@ -65,6 +72,12 @@ CLASS zcl_aoc_check_02 IMPLEMENTATION. EXIT. " current loop ENDLOOP. IF sy-subrc <> 0. + IF lv_error = '002' AND _is_check_allow( + io_scan = io_scan + iv_statement_index = lv_index + ) IS NOT INITIAL. + CONTINUE. + ENDIF. lv_line = io_scan->statement_row( lv_index ). lv_include = io_scan->get_include( -level ). @@ -142,4 +155,103 @@ CLASS zcl_aoc_check_02 IMPLEMENTATION. ASSERT sy-subrc = 0. ENDMETHOD. -ENDCLASS. + + + METHOD _is_check_allow. +************************************************************************ +* Copyright (c) 2023 by Alexandr Zhuravlev +* MIT License +* https://github.com/alezhu/abapOpenChecks/ + +*Rule +* +*Only use RETURN to exit procedures + +*Exception !!!!!! +* +*An exception to the rule to only use RETURN to exit procedures are +*CHECK statements that are located at the beginning of a procedure and +*that check the prerequisites for the execution of the procedure there. +* +*Using the CHECK statement in such a way does not impair the legibility +*and is thus allowed. +************************************************************************ + + DATA(lp_s_check) = REF #( io_scan->statements[ iv_statement_index ] ). + DATA(lv_struct_index) = lp_s_check->struc. + "Search Routine parent + WHILE lv_struct_index > 0. + DATA(lp_s_struct) = REF #( io_scan->structures[ lv_struct_index ] ). + IF lp_s_struct->type = scan_struc_type-routine. + EXIT. + ENDIF. + lv_struct_index = lp_s_struct->back. + ENDWHILE. + IF lp_s_struct IS NOT BOUND. + RETURN. + ENDIF. + + "Check all statements from routine start to current CHECK + "and skip available statements + DATA(lv_from) = SWITCH i( lp_s_struct->type + WHEN scan_struc_type-routine THEN lp_s_struct->stmnt_from + 1 " +1 skips METHOD/FORM/FUNCTION etc + ELSE lp_s_struct->stmnt_from ). + LOOP AT io_scan->statements REFERENCE INTO DATA(lp_s_statement) + FROM lv_from + TO iv_statement_index - 1. " -1 skips current CHECK + + CASE lp_s_statement->type. + WHEN scan_stmnt_type-include + OR scan_stmnt_type-include_miss + OR scan_stmnt_type-type_pools + OR scan_stmnt_type-type_pools_miss + OR scan_stmnt_type-comment + OR scan_stmnt_type-comment_in_stmnt + OR scan_stmnt_type-pragma + OR scan_stmnt_type-abap_doc + OR scan_stmnt_type-macro_definition + OR scan_stmnt_type-empty. + "Skip allow + CONTINUE. + WHEN scan_stmnt_type-standard + OR scan_stmnt_type-unknown. + DATA(lv_keyword) = io_scan->statement_keyword( sy-tabix ). + CASE lv_keyword. + WHEN 'TYPES' + OR 'DATA' + OR 'STATICS' + OR 'TABLES' + OR 'CONSTANTS' + OR 'FIELD-SYMBOLS'. + WHEN 'CLEAR' + OR 'FREE' + OR 'REFRESH'. + WHEN 'ASSERT' + OR 'CHECK' + OR 'LEAVE' + OR 'RAISE' + OR 'RETURN' + OR 'EXIT'. + WHEN 'BREAK-POINT' + OR 'LOG-POINT'. + WHEN 'DESCRIBE' + OR 'GET' + OR 'INCLUDE' + OR 'ASSIGN'. + WHEN 'IF' + OR 'ENDIF'. + WHEN 'DEFINE' + OR 'END-OF-DEFINITION'. + WHEN OTHERS. + "CHECK not allow after others + RETURN. + ENDCASE. + WHEN OTHERS. + "CHECK not allow after such statement type + RETURN. + ENDCASE. + ENDLOOP. + + rv_result = abap_true. + ENDMETHOD. +ENDCLASS. \ No newline at end of file diff --git a/src/checks/zcl_aoc_check_02.clas.testclasses.abap b/src/checks/zcl_aoc_check_02.clas.testclasses.abap index 53bb01ce..fb0ab0e3 100644 --- a/src/checks/zcl_aoc_check_02.clas.testclasses.abap +++ b/src/checks/zcl_aoc_check_02.clas.testclasses.abap @@ -26,6 +26,7 @@ CLASS ltcl_test DEFINITION FOR TESTING test002_02 FOR TESTING, test002_03 FOR TESTING, test002_04 FOR TESTING. + METHODS test002_05 FOR TESTING. ENDCLASS. "lcl_Test @@ -104,13 +105,13 @@ CLASS ltcl_test IMPLEMENTATION. METHOD test002_01. * =========== + _code 'cl_class=>method( ).'. _code 'CHECK 1 = 2.'. ms_result = zcl_aoc_unit_test=>check( mt_code ). cl_abap_unit_assert=>assert_equals( exp = '002' act = ms_result-code ). - ENDMETHOD. "test1 METHOD test002_02. @@ -142,7 +143,7 @@ CLASS ltcl_test IMPLEMENTATION. METHOD test002_04. * =========== - _code 'WHILE 1 = 2'. + _code 'WHILE 1 = 2.'. _code ' CHECK 1 = 2. '. _code 'ENDWHILE. '. @@ -152,4 +153,55 @@ CLASS ltcl_test IMPLEMENTATION. ENDMETHOD. "test001_04 -ENDCLASS. "lcl_Test + METHOD test002_05. +* =========== + + _code 'CLASS LCL_FOO DEFINITION.'. + _code ' PUBLIC SECTION.'. + _code ' METHODS test.'. + _code 'ENDCLASS.'. + _code 'CLASS LCL_FOO IMPLEMENTATION.'. + _code 'METHOD test.'. + _code ' TYPE-POOLS SCAN.'. + _code ' TYPES:'. + _code ' BEGIN OF ts_struct,'. + _code ' date TYPE d,'. + _code ' END OF ts_struct.'. + _code ' CONSTANTS cv_value type string value `test`.'. + _code ' STATICS lv_index type i.'. + _code ' DATA ls_struct TYPE ts_struct'. + _code ' DATA lt_table LIKE STANDARD TABLE OF LS_STRUCT'. + _code ' FIELD-SYMBOLS TYPE any.'. + _code ' TABLES t100.'. + _code ' DEFINE macro.'. + _code ' READ TABLE lt_table INTO &1 INDEX &2.'. + _code ' END-OF-DEFINITION.'. + _code '*******************************'. + _code '" Test comment'. + _code ' CLEAR lv_index.'. + _code ' FREE lt_table.'. + _code ' REFRESH lt_table.'. + _code ' ASSERT 1 = 2.'. + _code ' BREAK-POINT.'. + _code ' BREAK-POINT ID Z.'. + _code ' LOG-POINT ID Z.'. + _code ' DESCRIBE FIELD lv_index LENGTH DATA(lv_length) IN BYTE MODE.'. + _code ' GET TIME.'. + _code ' INCLUDE zdummy IF FOUND.'. + _code ' ASSIGN ls_struct TO .'. + _code ' IF IS NOT ASSIGNED.'. + _code ' RAISE EXCEPTION TYPE CX_STATIC_CHECK.'. + _code ' LEAVE PROGRAM.'. + _code ' RETURN.'. + _code ' ENDIF.'. + _code ''. + _code ' CHECK IS ASSIGNED.'. + _code ''. + _code 'ENDMETHOD.'. + _code 'ENDCLASS.'. + + ms_result = zcl_aoc_unit_test=>check( mt_code ). + cl_abap_unit_assert=>assert_initial( ms_result ). + ENDMETHOD. "test002_05 + +ENDCLASS. "lcl_Test \ No newline at end of file