Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Legend

2021-08-XX v.1.16.0
------------------
* Magic Number: Table Index (#468)
* Use native *_wa variables (#474)
* Refactoring (#436,#452,#458)
* Cannot run unit tests on 752 (#461)
Expand Down
113 changes: 61 additions & 52 deletions src/checks/y_check_magic_number.clas.abap
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,16 @@ CLASS y_check_magic_number DEFINITION PUBLIC INHERITING FROM y_check_base CREATE
METHODS inspect_tokens REDEFINITION.

PRIVATE SECTION.
CONSTANTS second_token TYPE i VALUE 2 ##NO_TEXT.
METHODS is_magic_number RETURNING VALUE(result) TYPE abap_bool.
METHODS is_index RETURNING VALUE(result) TYPE abap_bool.
METHODS is_lines RETURNING VALUE(result) TYPE abap_bool.
METHODS is_sy_subrc_in_case RETURNING VALUE(result) TYPE abap_bool.

DATA magic_number TYPE string.
DATA has_case_with_subrc TYPE abap_bool.

METHODS is_exception IMPORTING token TYPE string
RETURNING VALUE(result) TYPE abap_bool.

METHODS is_keyword_valid RETURNING VALUE(result) TYPE abap_bool.

METHODS is_magic_number IMPORTING token_string TYPE string
RETURNING VALUE(result) TYPE abap_bool.
ENDCLASS.



CLASS Y_CHECK_MAGIC_NUMBER IMPLEMENTATION.
CLASS y_check_magic_number IMPLEMENTATION.


METHOD constructor.
Expand All @@ -38,62 +31,78 @@ CLASS Y_CHECK_MAGIC_NUMBER IMPLEMENTATION.
ENDMETHOD.


METHOD is_exception.
IF token = 'ENDCASE' AND has_case_with_subrc = abap_true.
has_case_with_subrc = abap_false.
ENDIF.
METHOD inspect_tokens.
DATA(keyword) = keyword( ).

IF token = 'SY-SUBRC' OR has_case_with_subrc = abap_true.
result = abap_true.
ELSEIF token = 'CASE' AND get_token_rel( second_token ) = 'SY-SUBRC'.
has_case_with_subrc = abap_true.
IF keyword <> if_kaizen_keywords_c=>gc_do
AND keyword <> if_kaizen_keywords_c=>gc_if
AND keyword <> if_kaizen_keywords_c=>gc_elseif
AND keyword <> if_kaizen_keywords_c=>gc_when
AND keyword <> if_kaizen_keywords_c=>gc_check.
RETURN.
ENDIF.
ENDMETHOD.

IF keyword = if_kaizen_keywords_c=>gc_when
AND is_sy_subrc_in_case( ) = abap_true.
RETURN.
ELSEIF next1( 'SY-SUBRC' ) IS NOT INITIAL
OR next1( 'SY-TABIX' ) IS NOT INITIAL.
RETURN.
ENDIF.

METHOD inspect_tokens.
statement_wa = statement.

LOOP AT ref_scan->tokens ASSIGNING FIELD-SYMBOL(<token>)
LOOP AT ref_scan->tokens INTO token_wa
FROM statement-from TO statement-to.

IF is_exception( <token>-str ) = abap_true.
EXIT.
IF is_magic_number( ) = abap_false
OR is_lines( ) = abap_true
OR is_index( ) = abap_true.
CONTINUE.
ENDIF.

IF is_magic_number( <token>-str ).
DATA(check_configuration) = detect_check_configuration( statement_wa ).
DATA(check_configuration) = detect_check_configuration( statement ).

raise_error( statement_level = statement_wa-level
statement_index = index
statement_from = statement_wa-from
check_configuration = check_configuration
parameter_01 = |{ magic_number }| ).
ENDIF.
raise_error( statement_level = statement-level
statement_index = index
statement_from = statement-from
check_configuration = check_configuration
parameter_01 = |{ token_wa-str }| ).
ENDLOOP.
ENDMETHOD.


METHOD is_keyword_valid.
DATA(keyword) = keyword( ).
result = xsdbool( keyword = 'DO' OR
keyword = 'IF' OR
keyword = 'ELSEIF' OR
keyword = 'WHEN' OR
keyword = 'CHECK' ).
METHOD is_magic_number.
DATA(string) = token_wa-str.
REPLACE ALL OCCURRENCES OF |'| IN string WITH ||.
result = xsdbool( string IS NOT INITIAL
AND string CO '0123456789'
AND string <> '0'
AND string <> '1' ).
ENDMETHOD.


METHOD is_magic_number.
IF is_keyword_valid( ) = abap_false.
RETURN.
ENDIF.
METHOD is_index.
DATA(current) = line_index( ref_scan->tokens[ table_line = token_wa ] ).
DATA(last) = VALUE #( ref_scan->tokens[ current - 1 ] OPTIONAL ).
DATA(next) = VALUE #( ref_scan->tokens[ current + 1 ] OPTIONAL ).

FIND REGEX `^(?!'?[01]'?$)'?\d+'?$` IN token_string.
IF sy-subrc = 0.
magic_number = token_string.
result = abap_true.
ENDIF.
result = xsdbool( last-str CA '[('
OR next-str CA '])' ).
ENDMETHOD.


METHOD is_lines.
result = xsdbool( next1( 'LINES(' ) ).
ENDMETHOD.


METHOD is_sy_subrc_in_case.
DATA(when_statement) = statement_wa.
DATA(when_structure) = ref_scan->structures[ when_statement-struc ].

DATA(case_structure) = ref_scan->structures[ when_structure-back ].
DATA(case_statement) = ref_scan->statements[ case_structure-stmnt_from ].
DATA(case_target) = ref_scan->tokens[ case_statement-to ].

result = xsdbool( case_target-str = 'SY-SUBRC' ).
ENDMETHOD.


Expand Down
153 changes: 153 additions & 0 deletions src/checks/y_check_magic_number.clas.testclasses.abap
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ CLASS ltc_if IMPLEMENTATION.

ENDCLASS.


CLASS ltc_do DEFINITION INHERITING FROM y_unit_test_base FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PROTECTED SECTION.
METHODS get_cut REDEFINITION.
Expand Down Expand Up @@ -97,6 +98,7 @@ CLASS ltc_do IMPLEMENTATION.

ENDCLASS.


CLASS ltc_check DEFINITION INHERITING FROM y_unit_test_base FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PROTECTED SECTION.
METHODS get_cut REDEFINITION.
Expand Down Expand Up @@ -183,3 +185,154 @@ CLASS ltc_numeric_string IMPLEMENTATION.
ENDMETHOD.

ENDCLASS.


CLASS ltc_case DEFINITION INHERITING FROM y_unit_test_base FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PROTECTED SECTION.
METHODS get_cut REDEFINITION.
METHODS get_code_with_issue REDEFINITION.
METHODS get_code_without_issue REDEFINITION.
METHODS get_code_with_exemption REDEFINITION.
ENDCLASS.

CLASS ltc_case IMPLEMENTATION.

METHOD get_cut.
result ?= NEW y_check_magic_number( ).
ENDMETHOD.

METHOD get_code_with_issue.
result = VALUE #(
( ' REPORT ut_test.' )
( ' START-OF-SELECTION.' )
( | DATA(position) = 10. | )
( | CASE position. | )
( | WHEN 8. | )
( | WRITE 'ok'. | )
( | ENDCASE. | )
).
ENDMETHOD.

METHOD get_code_without_issue.
result = VALUE #(
( ' REPORT ut_test.' )
( ' START-OF-SELECTION.' )
( | CONSTANTS first TYPE i VALUE 1. | )
( | DATA(position) = 10. | )
( | CASE position. | )
( | WHEN first. | )
( | WRITE 'ok'. | )
( | ENDCASE. | )
).
ENDMETHOD.

METHOD get_code_with_exemption.
result = VALUE #(
( ' REPORT ut_test.' )
( ' START-OF-SELECTION.' )
( | DATA(position) = 10. | )
( | CASE position. | )
( | WHEN 8. "#EC CI_MAGIC | )
( | WRITE 'ok'. | )
( | ENDCASE. | )
).
ENDMETHOD.

ENDCLASS.


CLASS ltc_sy_subrc DEFINITION INHERITING FROM ltc_if FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PROTECTED SECTION.
METHODS get_code_without_issue REDEFINITION.
ENDCLASS.

CLASS ltc_sy_subrc IMPLEMENTATION.

METHOD get_code_without_issue.
result = VALUE #(
( ' REPORT ut_test.' )
( ' START-OF-SELECTION.' )
( ' CHECK sy-subrc = 4. ' )

( ' IF sy-subrc = 0. ' )
( ' ENDIF. ' )

( | CASE sy-subrc. | )
( | WHEN 0. | )
( | WRITE 'ok'. | )
( | WHEN 4. | )
( | WRITE 'not found'. | )
( | WHEN 8. | )
( | WRITE 'other error'. | )
( | ENDCASE. | )
).
ENDMETHOD.

ENDCLASS.


CLASS ltc_index DEFINITION INHERITING FROM ltc_if FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PROTECTED SECTION.
METHODS get_code_without_issue REDEFINITION.
ENDCLASS.

CLASS ltc_index IMPLEMENTATION.

METHOD get_code_without_issue.
result = VALUE #(
( ' REPORT ut_test.' )
( ' START-OF-SELECTION.' )
( ' DATA tokens TYPE stokesx_tab. ' )

( ' IF tokens[ 3 + 5 ] IS INITIAL. ' )
( ' ENDIF. ' )

( ' DATA(first) = tokens[ 4 ]. ' )
( ' IF tokens[ line_index( tokens[ table_line = first ] ) + 1 ] IS INITIAL. ' )
( ' ENDIF. ' )

( ' IF sy-tabix = 10. ' )
( ' ENDIF. ' )
).
ENDMETHOD.

ENDCLASS.


CLASS ltc_lines DEFINITION INHERITING FROM ltc_if FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PROTECTED SECTION.
METHODS get_code_without_issue REDEFINITION.
ENDCLASS.

CLASS ltc_lines IMPLEMENTATION.

METHOD get_code_without_issue.
result = VALUE #(
( ' REPORT ut_test.' )
( ' START-OF-SELECTION.' )
( ' DATA tokens TYPE stokesx_tab. ' )
( ' IF lines( tokens ) = 10. ' )
( ' ENDIF. ' )
).
ENDMETHOD.

ENDCLASS.


CLASS ltc_empty_string DEFINITION INHERITING FROM ltc_if FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PROTECTED SECTION.
METHODS get_code_without_issue REDEFINITION.
ENDCLASS.

CLASS ltc_empty_string IMPLEMENTATION.

METHOD get_code_without_issue.
result = VALUE #(
( ' REPORT ut_test.' )
( ' START-OF-SELECTION.' )
( | IF '' = ''. | )
( ' ENDIF. ' )
).
ENDMETHOD.

ENDCLASS.