From a34c09ed224065a9f3f2df9db45c0e2b4e6c6b19 Mon Sep 17 00:00:00 2001 From: Josia Kempf Date: Tue, 29 Aug 2023 11:32:02 +0000 Subject: [PATCH 1/9] Migrate check MODER_LANGUAGE --- src/checks/#cc4a#modern_language.clas.abap | 1101 +++++++++++++++++ ...#cc4a#modern_language.clas.locals_def.abap | 6 + ...#cc4a#modern_language.clas.locals_imp.abap | 6 + ...cc4a#modern_language.clas.testclasses.abap | 447 +++++++ src/checks/#cc4a#modern_language.clas.xml | 133 ++ src/checks/(cc4a)modern.chko.json | 10 + .../#cc4a#test_modern_language.clas.abap | 381 ++++++ ...#test_modern_language.clas.locals_imp.abap | 141 +++ .../#cc4a#test_modern_language.clas.xml | 16 + 9 files changed, 2241 insertions(+) create mode 100644 src/checks/#cc4a#modern_language.clas.abap create mode 100644 src/checks/#cc4a#modern_language.clas.locals_def.abap create mode 100644 src/checks/#cc4a#modern_language.clas.locals_imp.abap create mode 100644 src/checks/#cc4a#modern_language.clas.testclasses.abap create mode 100644 src/checks/#cc4a#modern_language.clas.xml create mode 100644 src/checks/(cc4a)modern.chko.json create mode 100644 src/test_objects/#cc4a#test_modern_language.clas.abap create mode 100644 src/test_objects/#cc4a#test_modern_language.clas.locals_imp.abap create mode 100644 src/test_objects/#cc4a#test_modern_language.clas.xml diff --git a/src/checks/#cc4a#modern_language.clas.abap b/src/checks/#cc4a#modern_language.clas.abap new file mode 100644 index 0000000..b9f1a3f --- /dev/null +++ b/src/checks/#cc4a#modern_language.clas.abap @@ -0,0 +1,1101 @@ +CLASS /cc4a/modern_language DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + INTERFACES if_ci_atc_check . + CONSTANTS c_code_move TYPE if_ci_atc_check=>ty_finding_code VALUE 'MOVE'. + CONSTANTS c_code_translate TYPE if_ci_atc_check=>ty_finding_code VALUE 'TRANSLATE'. + CONSTANTS c_code_line_exists TYPE if_ci_atc_check=>ty_finding_code VALUE 'LINE_EXIST'. + CONSTANTS c_code_prefer_new TYPE if_ci_atc_check=>ty_finding_code VALUE 'PREFER_NEW'. + CONSTANTS c_code_call_method TYPE if_ci_atc_check=>ty_finding_code VALUE 'CALL_METH'. + CONSTANTS c_code_method_exporting TYPE if_ci_atc_check=>ty_finding_code VALUE 'METH_EXP'. + CONSTANTS c_code_exporting_receiving TYPE if_ci_atc_check=>ty_finding_code VALUE 'EXP_REC'. + CONSTANTS c_code_text_assembly TYPE if_ci_atc_check=>ty_finding_code VALUE 'TEXT_ASM'. + CONSTANTS c_code_qf_synerr TYPE if_ci_atc_check=>ty_finding_code VALUE 'QF_SYNERR'. + CONSTANTS c_code_qf_tsterr TYPE if_ci_atc_check=>ty_finding_code VALUE 'QF_TSTERR'. + CONSTANTS c_qf_move TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_MOVE'. + CONSTANTS c_qf_translate TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_TRANSL'. + CONSTANTS c_qf_line_exists TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_LINEEX'. + CONSTANTS c_qf_prefer_new TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_PREFNEW'. + CONSTANTS c_qf_call_method TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_CALLM'. + CONSTANTS c_qf_method_exporting TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_MEXP'. + CONSTANTS c_qf_exporting_receiving TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_EXP_REC'. + CONSTANTS c_qf_text_assembly TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_TEXTASM'. + CONSTANTS c_ps_deprecated_key TYPE string VALUE 'DEPRECATED_KEY'. + CONSTANTS c_ps_line_exists TYPE string VALUE 'PREF_LINE_EX'. + CONSTANTS c_ps_prefer_new TYPE string VALUE 'PREF_NEW'. + CONSTANTS c_ps_call_method TYPE string VALUE 'CALL_METH_USAGE'. + CONSTANTS c_ps_method_exporting TYPE string VALUE 'OPTL_EXP'. + CONSTANTS c_ps_exporting_receiving TYPE string VALUE 'RECEIVING_USAGE'. + CONSTANTS c_ps_text_assembly TYPE string VALUE 'TEXT_ASSEMBLY'. + CONSTANTS c_max_line_length TYPE i VALUE 255. + PROTECTED SECTION. + PRIVATE SECTION. + DATA code_provider TYPE REF TO if_ci_atc_source_code_provider. + DATA analyzer TYPE REF TO /cc4a/if_abap_analyzer. + DATA assistant_factory TYPE REF TO cl_ci_atc_assistant_factory. + + METHODS analyze_procedure + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_move + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + EXPORTING changed_line TYPE string + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_translate + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_read + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_loop + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_create_object + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_call_method + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_exporting_receiving + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_text_assembly + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS check_quickfixes + IMPORTING quickfixes TYPE REF TO cl_ci_atc_quickfixes + procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + CHANGING findings TYPE if_ci_atc_check=>ty_findings. + METHODS add_finding + IMPORTING quickfixes TYPE REF TO cl_ci_atc_quickfixes OPTIONAL + procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + code TYPE cl_ci_atc_quickfixes=>ty_quickfix_code + pseudo_comment TYPE string + CHANGING findings TYPE if_ci_atc_check=>ty_findings. + METHODS is_used + IMPORTING + procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + from_index TYPE i + full_name TYPE string + RETURNING + VALUE(result) TYPE abap_bool. + + METHODS check_remove_exporting + IMPORTING + statement TYPE if_ci_atc_source_code_provider=>ty_statement + token_idx TYPE i + RETURNING + VALUE(result) TYPE abap_bool. + METHODS get_value + IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token + RETURNING VALUE(result) TYPE string + RAISING lcx_error. + METHODS append_token + IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token + CHANGING result TYPE string. + METHODS append_tokens + IMPORTING tokens TYPE if_ci_atc_source_code_provider=>ty_tokens + VALUE(from_idx) TYPE i OPTIONAL + VALUE(to_idx) TYPE i OPTIONAL + CHANGING result TYPE string. + METHODS get_receiving_infos + IMPORTING + tokens TYPE if_ci_atc_source_code_provider=>ty_tokens + EXPORTING + receiving_idx TYPE i + end_idx TYPE i + result_line TYPE string. +ENDCLASS. + + + +CLASS /cc4a/modern_language IMPLEMENTATION. + + + METHOD check_quickfixes. + DATA(program_name) = cl_ci_atc_data_provider=>main_program_from_comp_unit( procedure-id-main_unit ). + TRY. + DATA(qfix_tester) = NEW cl_ci_quickfix_testing( ). + qfix_tester->set( p_atc_quickfixes = quickfixes ). + IF qfix_tester->check_quickfixes( p_program = program_name ) = abap_false. + INSERT VALUE #( code = c_code_qf_synerr + location = code_provider->get_statement_location( procedure-statements[ statement_index ] ) + checksum = code_provider->get_statement_checksum( procedure-statements[ statement_index ] ) + has_pseudo_comment = abap_false ) INTO TABLE findings. + ENDIF. + CATCH cx_ci_quickfix_testing_error. + INSERT VALUE #( code = c_code_qf_tsterr + location = code_provider->get_statement_location( procedure-statements[ statement_index ] ) + checksum = code_provider->get_statement_checksum( procedure-statements[ statement_index ] ) + has_pseudo_comment = abap_false ) INTO TABLE findings. + ENDTRY. + ENDMETHOD. + + + METHOD if_ci_atc_check~get_meta_data. + meta_data = /cc4a/check_meta_data=>create( + VALUE #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs + description = 'Modern Language'(des) + remote_enablement = /cc4a/check_meta_data=>remote_enablement-unconditional + finding_codes = VALUE #( ( code = c_code_move text = 'MOVE is obsolete'(001) pseudo_comment = c_ps_deprecated_key ) + ( code = c_code_translate text = 'TRANSLATE TO UPPER/LOWERCASE is obsolete'(002) pseudo_comment = c_ps_deprecated_key ) + ( code = c_code_line_exists text = 'Prefer LINE_EXISTS/LINE_INDEX'(003) pseudo_comment = c_ps_line_exists ) + ( code = c_code_prefer_new text = 'Prefer NEW instead of CREATE OBJECT'(004) pseudo_comment = c_ps_prefer_new ) + ( code = c_code_call_method text = 'Prefer functional call instead of CALL METHOD'(005) pseudo_comment = c_ps_call_method ) + ( code = c_code_method_exporting text = 'Omit EXPORTING in functional Method Call if possible'(006) pseudo_comment = c_ps_method_exporting ) + ( code = c_code_exporting_receiving text = 'Do not use RECEIVING in functional Method Call if possible'(007) pseudo_comment = c_ps_exporting_receiving ) + ( code = c_code_text_assembly text = 'Use string templates instead of &&'(008) pseudo_comment = c_ps_text_assembly ) + ( code = c_code_qf_synerr text = 'Quickfix Syntax Error'(q01) ) + ( code = c_code_qf_tsterr text = 'Quickfix Testing Error'(q02) ) ) + quickfix_codes = VALUE #( ( code = c_qf_move short_text = 'Replace MOVE statement'(qf1) ) + ( code = c_qf_translate short_text = 'Replace TRANSLATE statement'(qf2) ) + ( code = c_qf_line_exists short_text = 'Use LINE_EXISTS/LINE_INDEX'(qf3) ) + ( code = c_qf_prefer_new short_text = 'Use NEW instead of CREATE OBJECT'(qf4) ) + ( code = c_qf_call_method short_text = 'Use functional call instead of CALL METHOD'(qf5) ) + ( code = c_qf_method_exporting short_text = 'Omit EXPORTING'(qf6) ) + ( code = c_qf_exporting_receiving short_text = 'Do not use EXPORTING/RECEIVING'(qf7) ) + ( code = c_qf_text_assembly short_text = 'Replace && by string templates'(qf8) ) + ) ) ). + ENDMETHOD. + + + METHOD if_ci_atc_check~run. + code_provider = data_provider->get_code_provider( ). + analyzer = /cc4a/abap_analyzer=>create( ). + DATA(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). + LOOP AT procedures->* ASSIGNING FIELD-SYMBOL(). + INSERT LINES OF analyze_procedure( ) INTO TABLE findings. + ENDLOOP. + ENDMETHOD. + + + METHOD if_ci_atc_check~set_assistant_factory. + assistant_factory = factory. + ENDMETHOD. + + + METHOD if_ci_atc_check~set_attributes ##NEEDED. + ENDMETHOD. + + + METHOD if_ci_atc_check~verify_prerequisites ##NEEDED. + ENDMETHOD. + + + METHOD add_finding. + DATA finding LIKE LINE OF findings. + DATA(statement) = procedure-statements[ statement_index ]. + IF quickfixes IS INITIAL. + finding = VALUE #( code = code + location = code_provider->get_statement_location( statement ) + checksum = code_provider->get_statement_checksum( statement ) + has_pseudo_comment = xsdbool( line_exists( statement-pseudo_comments[ table_line = pseudo_comment ] ) ) + ). + + ELSE. + finding = VALUE #( code = code + location = code_provider->get_statement_location( statement ) + checksum = code_provider->get_statement_checksum( statement ) + has_pseudo_comment = xsdbool( line_exists( statement-pseudo_comments[ table_line = pseudo_comment ] ) ) + details = assistant_factory->create_finding_details( )->attach_quickfixes( quickfixes ) ). + IF code <> c_code_translate. + check_quickfixes( + EXPORTING + quickfixes = quickfixes + procedure = procedure + statement_index = statement_index + CHANGING findings = findings ). + ENDIF. + ENDIF. + INSERT finding INTO TABLE findings. + ENDMETHOD. + + + METHOD analyze_move. + DATA source TYPE string. + DATA dest TYPE string. + DATA between TYPE string. + CLEAR changed_line. + DATA(statement) = procedure-statements[ statement_index ]. + + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'PERCENTAGE' ) <> 0. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_move + pseudo_comment = c_ps_deprecated_key + CHANGING findings = findings ). + RETURN. + ENDIF. + DATA(from_token) = 2. + IF statement-tokens[ 2 ]-lexeme = 'EXACT' AND statement-tokens[ 2 ]-references IS INITIAL. + DATA(exact) = abap_true. + from_token = 3. + ENDIF. + LOOP AT statement-tokens FROM from_token ASSIGNING FIELD-SYMBOL(). + + IF -references IS INITIAL. + CASE -lexeme. + WHEN 'TO'. + IF exact = abap_true. + between = `= EXACT #(`. + ELSE. + between = `=`. + ENDIF. + CONTINUE. + WHEN '?TO'. + between = `?=`. + CONTINUE. + ENDCASE. + ENDIF. + IF between IS INITIAL. + source = |{ source } { -lexeme }|. + ELSE. + dest = |{ dest } { -lexeme }|. + ENDIF. + ENDLOOP. + DATA(line) = |{ dest } { between } { source }|. + IF exact = abap_true. + line = |{ line } )|. + ENDIF. + line = |{ line }.|. + IF changed_line IS SUPPLIED. + changed_line = line. + RETURN. + ENDIF. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( c_qf_move ). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = statement_index ) ) ) + code = VALUE #( ( line ) ) ). + + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_move + pseudo_comment = c_ps_deprecated_key + quickfixes = quickfixes + CHANGING findings = findings ). + ENDMETHOD. + + + METHOD analyze_translate. + DATA line TYPE string. + DATA(statement) = procedure-statements[ statement_index ]. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'USING MASK' ) <> 0. + RETURN. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TO UPPER CASE' ) = 3. + line = |{ statement-tokens[ 2 ]-lexeme } = to_upper( { statement-tokens[ 2 ]-lexeme } ).| ##NO_TEXT. + ELSEIF analyzer->find_clause_index( tokens = statement-tokens clause = 'TO LOWER CASE' ) = 3. + line = |{ statement-tokens[ 2 ]-lexeme } = to_lower( { statement-tokens[ 2 ]-lexeme } ).| ##NO_TEXT. + ELSE. + RETURN. + ENDIF. + + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( c_qf_translate ). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = statement_index ) ) ) + code = VALUE #( ( line ) ) ). + + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_translate + pseudo_comment = c_ps_deprecated_key + quickfixes = quickfixes + CHANGING findings = findings ). + + ENDMETHOD. + + + METHOD analyze_read. + DATA code_line_index TYPE string. + DATA code_line_exists TYPE string. + DATA code_lines TYPE if_ci_atc_quickfix=>ty_code. + DATA key TYPE string. + DATA token_idx TYPE i. + DATA(statement) = procedure-statements[ statement_index ]. + + + IF lines( statement-tokens ) <= 2 OR statement-tokens[ 2 ]-lexeme <> 'TABLE' OR statement-tokens[ 2 ]-references IS NOT INITIAL + OR lines( procedure-statements ) = statement_index + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING NO FIELDS' ) = 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 + OR statement-tokens[ 3 ]-lexeme CP '*('. + RETURN. + ENDIF. + DATA(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WITH KEY' ). + IF key_idx = 0. + RETURN. + ELSE. + DATA(start_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'COMPONENTS' + start_index = key_idx + 1 ). + IF start_idx = 0. "with key... + start_idx = key_idx + 2. + ELSE. "with key name components ... + start_idx -= 2. + ENDIF. + DATA(keylen) = 0. + DATA(to_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' start_index = start_idx ) - 1. + IF to_idx <= 0. + to_idx = lines( statement-tokens ). + ENDIF. + append_tokens( EXPORTING tokens = statement-tokens from_idx = start_idx to_idx = to_idx + CHANGING result = key ). + keylen = to_idx - start_idx + 1. + + ENDIF. + IF keylen = 1. +* finding without quickfix since obsolete version read table with key val. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_line_exists + pseudo_comment = c_ps_line_exists + CHANGING findings = findings ). + RETURN. + ENDIF. + DATA(table) = statement-tokens[ 3 ]-lexeme. + IF table CP '*[]'. + DATA(len) = strlen( table ) - 2. + table = table(len). + ENDIF. + DATA(idx) = statement_index + 1. + ASSIGN procedure-statements[ idx ] TO FIELD-SYMBOL(). + IF -keyword = 'IF' AND lines( -tokens ) = 4 + AND -tokens[ 2 ]-lexeme = 'SY-SUBRC' + + AND -tokens[ 4 ]-lexeme = '0'. + CASE -tokens[ 3 ]-lexeme. + WHEN '=' OR 'EQ' . + DATA(if_sysubrc) = 1. + WHEN '<>' OR 'NE'. + if_sysubrc = 2. + ENDCASE. + idx += 1. + ENDIF. + DATA(end_idx) = idx. + IF if_sysubrc <> 0. + to_idx = lines( procedure-statements ). + ELSE. + to_idx = idx. + ENDIF. + LOOP AT procedure-statements FROM idx TO to_idx ASSIGNING FIELD-SYMBOL(). + DATA(tabix) = sy-tabix. + IF -keyword = 'ENDIF'. + end_idx = sy-tabix. + EXIT. + ENDIF. + DATA(sytabix_idx) = line_index( -tokens[ lexeme = 'SY-TABIX' ] ). + + IF sytabix_idx <> 0. + IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-lexeme = '&&'. + RETURN. + ENDIF. + IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-references IS INITIAL + AND -tokens[ sytabix_idx - 1 ]-lexeme = 'LIKE' + AND -keyword = 'DATA'. + RETURN. + ENDIF. + CASE -keyword. + WHEN 'MOVE'. + analyze_move( EXPORTING procedure = procedure statement_index = tabix IMPORTING changed_line = code_line_index ). + REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. + APPEND code_line_index TO code_lines. + WHEN 'MESSAGE'. + RETURN. + WHEN OTHERS. + IF if_sysubrc <> 2. + code_line_index = analyzer->flatten_tokens( tokens = -tokens ). + REPLACE FIRST OCCURRENCE OF 'SY-TABIX IS INITIAL' IN code_line_index WITH |line_index( { table }[ { key } ] ) = 0| ##NO_TEXT. + REPLACE FIRST OCCURRENCE OF 'SY-TABIX IS NOT INITIAL' IN code_line_index WITH |line_index( { table }[ { key } ] ) <> 0| ##NO_TEXT. + REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. + code_line_index = |{ code_line_index }.|. + APPEND code_line_index TO code_lines. + ENDIF. + ENDCASE. + ELSEIF if_sysubrc <> 0 AND tabix > statement_index + 1. + IF -keyword = 'CALL' OR -keyword = '+CALL_METHOD'. + RETURN. + ENDIF. + CASE if_sysubrc. + WHEN 1. + token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). + IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_TRUE'. + RETURN. + ENDIF. + WHEN 2. + token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). + IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_FALSE' + OR procedure-statements[ tabix + 1 ]-keyword <> 'ENDIF'. + RETURN. + ENDIF. + ENDCASE. + append_tokens( EXPORTING tokens = -tokens to_idx = token_idx - 1 CHANGING result = code_line_exists ). + IF if_sysubrc = 1. + code_line_exists = |{ code_line_exists } = xsdbool( line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. + ELSE. + code_line_exists = |{ code_line_exists } = xsdbool( NOT line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. + ENDIF. + APPEND code_line_exists TO code_lines. + ENDIF. + IF if_sysubrc = 0. + EXIT. + ENDIF. + ENDLOOP. + + IF code_line_index IS NOT INITIAL OR code_line_exists IS NOT INITIAL. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( c_qf_line_exists ). + + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = end_idx ) ) ) + code = code_lines ). + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_line_exists + pseudo_comment = c_ps_line_exists + quickfixes = quickfixes + CHANGING findings = findings ). + ENDIF. + + ENDMETHOD. + + + METHOD analyze_loop. + DATA code_line_index TYPE string. + DATA code_line_exists TYPE string. + DATA code_lines TYPE if_ci_atc_quickfix=>ty_code. + DATA key TYPE string. + + DATA(statement) = procedure-statements[ statement_index ]. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'OR' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'NOT' ) <> 0. + RETURN. + ENDIF. + DATA(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WHERE' ). + IF key_idx = 0 OR statement-tokens[ key_idx + 1 ]-lexeme CP '(*'. + RETURN. + ENDIF. + DATA(table) = statement-tokens[ 3 ]-lexeme. + IF table CP '*('. + RETURN. + ENDIF. + DATA(result_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ). + IF result_idx <> 0. + ASSIGN statement-tokens[ result_idx + 1 ] TO FIELD-SYMBOL(). + IF is_used( procedure = procedure from_index = statement_index + 1 full_name = -references[ lines( -references ) ]-full_name ). + RETURN. + ENDIF. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = '(' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = ')' ) <> 0. + RETURN. + ENDIF. + DATA(token_idx) = key_idx + 1. + DO. + ASSIGN statement-tokens[ token_idx ] TO . + append_token( EXPORTING token = CHANGING result = key ). + token_idx += 1. + ASSIGN statement-tokens[ token_idx ] TO . + CASE -lexeme. + WHEN '=' OR 'EQ'. + key = |{ key } = |. + WHEN OTHERS. + RETURN. + ENDCASE. + DATA(and_idx) = analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'AND' ). + IF and_idx = 0. + append_tokens( EXPORTING tokens = statement-tokens from_idx = token_idx + 1 CHANGING result = key ). + EXIT. + ELSE. + append_tokens( EXPORTING tokens = statement-tokens from_idx = token_idx + 1 to_idx = and_idx - 1 CHANGING result = key ). + token_idx = and_idx + 1. + ENDIF. + ENDDO. + + LOOP AT procedure-statements FROM statement_index + 1 ASSIGNING FIELD-SYMBOL(). + CASE -keyword. + WHEN 'ENDLOOP'. + DATA(end_idx) = sy-tabix. + EXIT. + WHEN 'EXIT'. + DATA(contains_exit) = abap_true. + WHEN OTHERS. + IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + LOOP AT -tokens ASSIGNING . + IF -lexeme = 'SY-TABIX'. + code_line_index = |{ code_line_index } line_index( { table }[ { key } ] )| ##NO_TEXT. + ELSEIF code_line_index IS INITIAL. + code_line_index = -lexeme. + ELSE. + code_line_index = |{ code_line_index } { -lexeme }|. + ENDIF. + ENDLOOP. + code_line_index = |{ code_line_index }.|. + APPEND code_line_index TO code_lines. + ELSE. + DATA(idx) = analyzer->find_clause_index( tokens = -tokens clause = '=' ). + IF idx = 0 OR -tokens[ idx + 1 ]-lexeme <> 'ABAP_TRUE'. + RETURN. + ENDIF. + LOOP AT -tokens TO idx - 1 ASSIGNING . + IF code_line_exists IS INITIAL. + code_line_exists = -lexeme. + ELSE. + code_line_exists = |{ code_line_exists } { -lexeme }|. + ENDIF. + ENDLOOP. + code_line_exists = |{ code_line_exists } = xsdbool( line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. + APPEND code_line_exists TO code_lines. + ENDIF. + ENDCASE. + ENDLOOP. + IF contains_exit = abap_false. + RETURN. + ENDIF. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( c_qf_line_exists ). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = end_idx ) ) ) + code = code_lines ). + + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_line_exists + pseudo_comment = c_ps_deprecated_key + quickfixes = quickfixes + CHANGING findings = findings ). + + ENDMETHOD. + + + METHOD analyze_create_object. + DATA code_line TYPE string. + DATA(statement) = procedure-statements[ statement_index ]. + + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TYPE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'AREA HANDLE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 "old exceptions cannot be handled with NEW + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'FOR TESTING' ) <> 0. + RETURN. + ENDIF. + + DATA(object_name) = statement-tokens[ 3 ]-lexeme. + DATA(full_name) = statement-tokens[ 3 ]-references[ lines( statement-tokens[ 3 ]-references ) ]-full_name. +* self reference is working with create object but not with new + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() FROM 4 WHERE lexeme CP |{ object_name }*| AND references IS NOT INITIAL. + LOOP AT -references TRANSPORTING NO FIELDS WHERE full_name CP |{ full_name }*|. + RETURN. + ENDLOOP. + ENDLOOP. +* find data statement + DATA(data_idx) = statement_index - 1. + WHILE data_idx > 0. + IF procedure-statements[ data_idx ]-keyword = 'DATA' + AND procedure-statements[ data_idx ]-tokens[ 2 ]-lexeme = object_name. + ASSIGN procedure-statements[ data_idx ] TO FIELD-SYMBOL(). + DATA(type_idx) = analyzer->find_clause_index( tokens = -tokens clause = 'TYPE REF TO' ). + IF type_idx = 0. + RETURN. + ENDIF. + IF data_idx = statement_index - 1. + DATA(type_name) = -tokens[ type_idx + 3 ]-lexeme. + code_line = |DATA({ object_name }) = NEW { type_name }( |. + DATA(from_idx) = data_idx. + ELSE. + code_line = |{ object_name } = NEW #( |. + from_idx = statement_index. + ENDIF. + ENDIF. + data_idx -= 1. + ENDWHILE. + IF code_line IS INITIAL. + RETURN. + ENDIF. + DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). + +* IF exporting_idx <> 0. +* append_tokens( EXPORTING tokens = statement-tokens from_idx = exporting_idx + 1 CHANGING result = code_line ). +* ENDIF. + +* code_line = |{ code_line } ).|. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( c_qf_prefer_new ). + IF from_idx < statement_index. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = from_idx to = statement_index - 1 ) ) ) + code = VALUE #( ( `` ) ) ). + ENDIF. + IF exporting_idx = 0. + DATA(to_idx) = 3. + ELSE. + to_idx = exporting_idx. + ENDIF. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = 1 to = to_idx ) ) ) + code = VALUE #( ( code_line ) ) ). + quickfix->insert_after( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) + code = VALUE #( ( `)` ) ) ). + + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_prefer_new + pseudo_comment = c_ps_prefer_new + quickfixes = quickfixes + CHANGING findings = findings ). + ENDMETHOD. + + + METHOD analyze_call_method. + DATA code_line TYPE string. + DATA(statement) = procedure-statements[ statement_index ]. + IF statement-tokens[ 3 ]-references IS INITIAL AND statement-tokens[ 3 ]-lexeme = 'OF'. "ole + RETURN. + ENDIF. + DATA(method_name) = statement-tokens[ 3 ]-lexeme. + IF method_name(1) = '(' OR method_name CP '*->(*' OR method_name CP '*=>(*' OR method_name CP '(*)' + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'PARAMETER-TABLE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTION-TABLE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0. +* dynamic call / exceptions + RETURN. + ENDIF. + + IF method_name NP '*('. + DATA(method_line) = |{ method_name }(|. + ELSE. + method_line = method_name. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) = 0 + AND analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) = 0 . + DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). + get_receiving_infos( EXPORTING tokens = statement-tokens + IMPORTING receiving_idx = DATA(receiving_idx) + end_idx = DATA(to_idx) + result_line = DATA(result_line) ). + ENDIF. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( c_qf_call_method ). + IF lines( statement-tokens ) = 3 + OR lines( statement-tokens ) = 4. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) ) ) + code = VALUE #( ( |{ method_line } ).| ) ) ). + ELSE. + IF exporting_idx <> 0. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = exporting_idx to = exporting_idx ) ) ) + code = VALUE #( ( `` ) ) ). + ENDIF. + IF result_line IS NOT INITIAL. + IF to_idx = lines( statement-tokens ). + code_line = ')'. + ELSE. + code_line = ''. + ENDIF. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = receiving_idx to = to_idx ) ) ) + code = VALUE #( ( code_line ) ) ). + method_line = |{ result_line } = { method_line }|. + ENDIF. + + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = 1 to = 3 ) ) ) + code = VALUE #( ( method_line ) ) ). + + IF to_idx <> lines( statement-tokens ) AND method_name NP '*('. + quickfix->insert_after( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) + code = VALUE #( ( `)` ) ) ). + ENDIF. + ENDIF. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_call_method + pseudo_comment = c_ps_call_method + quickfixes = quickfixes + CHANGING findings = findings ). + ENDMETHOD. + + + METHOD analyze_exporting_receiving. + DATA exporting_idxs TYPE SORTED TABLE OF i WITH UNIQUE KEY table_line. + DATA(statement) = procedure-statements[ statement_index ]. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. + RETURN. + ENDIF. + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE references IS INITIAL AND lexeme = 'EXPORTING'. + DATA(token_idx) = sy-tabix. + IF check_remove_exporting( statement = statement token_idx = token_idx ) = abap_true. + INSERT token_idx INTO TABLE exporting_idxs. + ENDIF. + ENDLOOP. + + get_receiving_infos( EXPORTING tokens = statement-tokens + IMPORTING receiving_idx = DATA(receiving_idx) + end_idx = DATA(end_idx) + result_line = DATA(result_line) ). + + IF result_line IS INITIAL AND exporting_idxs IS INITIAL. + RETURN. + ENDIF. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + IF result_line IS NOT INITIAL. + DATA(finding_code) = c_code_exporting_receiving. + DATA(ps) = c_ps_exporting_receiving. + DATA(quickfix) = quickfixes->create_quickfix( c_qf_exporting_receiving ). + result_line = |{ result_line } = { statement-tokens[ 1 ]-lexeme }|. + quickfix->replace( context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = 1 to = 1 ) ) ) + code = VALUE #( ( result_line ) ) ). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = receiving_idx to = end_idx ) ) ) + code = VALUE #( ( `` ) ) ). + ELSE. + finding_code = c_code_method_exporting. + ps = c_ps_method_exporting. + quickfix = quickfixes->create_quickfix( c_qf_method_exporting ). + ENDIF. + LOOP AT exporting_idxs INTO DATA(exporting_idx). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = exporting_idx to = exporting_idx + 1 ) ) ) + code = VALUE #( ( statement-tokens[ exporting_idx + 1 ]-lexeme ) ) ). + ENDLOOP. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = finding_code + pseudo_comment = ps + quickfixes = quickfixes + CHANGING findings = findings ). + ENDMETHOD. + + + METHOD analyze_text_assembly. + + DATA(statement) = procedure-statements[ statement_index ]. + +* if statement-keyword = 'CONCATENATE' +* and analyzer->find_clause_index( tokens = statement-tokens clause = 'IN BYTE MODE' ) = 0 +* AND analyzer->find_clause_index( tokens = statement-tokens clause = 'LINES OF' ) = 0. +* data(into_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ). +* data(result_line) = statement-tokens[ into_idx + 1 ]-lexeme. +* loop at statement-tokens ASSIGNING FIELD-SYMBOL() from into_idx + 2. +* if -references is initial. +* case -lexeme. +* when 'IN'. +* exit. +* when 'SEPARATED'. +* data(sep_by) = statement-tokens[ sy-tabix + 2 ]-lexeme. +* exit. +* when 'RESPECTING'. +* exit. +* endcase. +* endif. +* result_line = |{ result_line } { -lexeme }|. +* endloop. +* result_line = |{ result_line } = |. +* endif. + DATA start_idx TYPE i. + DATA end_idx TYPE i. + DATA last_idx TYPE i. + DATA code_line TYPE string. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( c_qf_text_assembly ). + TRY. + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE lexeme = '&&'. + DATA(tabix) = sy-tabix. + IF tabix - 1 <> last_idx. + IF code_line IS NOT INITIAL. +* store old code_line + code_line = |{ code_line }\||. + IF strlen( code_line ) >= c_max_line_length - 1. + DATA(no_quickfixes) = abap_true. + EXIT. + ELSE. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = start_idx to = end_idx ) ) ) + code = VALUE #( ( code_line ) ) ). + ENDIF. + ENDIF. +* new && connection + code_line = '|'. + start_idx = tabix - 1. + DATA(value) = get_value( statement-tokens[ tabix - 1 ] ). + code_line = |{ code_line }{ value }|. + ENDIF. + value = get_value( statement-tokens[ tabix + 1 ] ). + code_line = |{ code_line }{ value }|. + end_idx = tabix + 1. + last_idx = tabix + 1. + ENDLOOP. + IF no_quickfixes = abap_false AND code_line IS NOT INITIAL. + code_line = |{ code_line }\||. + IF strlen( code_line ) >= c_max_line_length - 1. + no_quickfixes = abap_true. + ELSE. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = start_idx to = end_idx ) ) ) + code = VALUE #( ( code_line ) ) ). + ENDIF. + ENDIF. + CATCH lcx_error. + no_quickfixes = abap_true. + ENDTRY. + IF no_quickfixes = abap_true. + CLEAR quickfixes. + ENDIF. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_text_assembly + pseudo_comment = c_ps_text_assembly + quickfixes = quickfixes + CHANGING findings = findings ). + + ENDMETHOD. + + + METHOD analyze_procedure. + "DATA(program_name) = cl_ci_atc_data_provider=>main_program_from_comp_unit( procedure-id-main_unit ). + + LOOP AT procedure-statements ASSIGNING FIELD-SYMBOL(). + DATA(idx) = sy-tabix. + CASE -keyword. + WHEN 'MOVE'. + INSERT LINES OF analyze_move( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'TRANSLATE'. + INSERT LINES OF analyze_translate( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'READ'. + INSERT LINES OF analyze_read( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'LOOP'. + INSERT LINES OF analyze_loop( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'CREATE'. + IF -tokens[ 2 ]-lexeme = 'OBJECT' AND -tokens[ 2 ]-references IS INITIAL. + INSERT LINES OF analyze_create_object( procedure = procedure statement_index = idx ) INTO TABLE findings. + ENDIF. + WHEN 'CALL'. + IF -tokens[ 2 ]-lexeme = 'METHOD' AND -tokens[ 2 ]-references IS INITIAL. + INSERT LINES OF analyze_call_method( procedure = procedure statement_index = idx ) INTO TABLE findings. + ENDIF. +* WHEN 'CONCATENATE'. +* INSERT LINES OF analyze_text_assembly( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'METHODS' OR 'CLASS-METHODS'. + CONTINUE. + ENDCASE. +* functional method call may occur in many statements + IF -keyword <> 'CALL' AND -keyword <> 'CREATE' + AND analyzer->find_clause_index( tokens = -tokens clause = 'EXPORTING' ) <> 0. + INSERT LINES OF analyze_exporting_receiving( procedure = procedure statement_index = idx ) INTO TABLE findings. + ENDIF. +* text assembly + IF analyzer->find_clause_index( tokens = -tokens clause = '&&' ) <> 0 + AND -keyword <> 'CONCATENATE' + AND -keyword <> 'SPLIT' + AND analyzer->is_db_statement( statement = ) IS INITIAL. + INSERT LINES OF analyze_text_assembly( procedure = procedure statement_index = idx ) INTO TABLE findings. + ENDIF. + ENDLOOP. + ENDMETHOD. + + + METHOD is_used. + result = abap_false. + LOOP AT procedure-statements FROM from_index ASSIGNING FIELD-SYMBOL(). + LOOP AT -tokens ASSIGNING FIELD-SYMBOL() + WHERE references IS NOT INITIAL. + result = xsdbool( line_exists( -references[ full_name = full_name ] ) ). + IF result = abap_true. + RETURN. + ENDIF. + ENDLOOP. + ENDLOOP. + ENDMETHOD. + + + METHOD check_remove_exporting. + result = abap_false. + ASSIGN statement-tokens[ token_idx - 1 ] TO FIELD-SYMBOL(). + IF NOT -lexeme CP '*('. + RETURN. + ENDIF. + LOOP AT -references ASSIGNING FIELD-SYMBOL() + WHERE kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-method + AND usage_grade <> if_ci_atc_source_code_provider=>usage_grades-definition. + DATA(is_method_call) = abap_true. + EXIT. + ENDLOOP. + IF is_method_call = abap_false. + RETURN. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. + RETURN. + ENDIF. + result = abap_true. + ENDMETHOD. + + + METHOD get_value. + IF token-lexeme CP '*(' + OR token-lexeme CP '*[' + OR token-lexeme(1) = ']' + OR token-lexeme(1) = ')'. + RAISE EXCEPTION TYPE lcx_error. + ENDIF. + IF token-references IS INITIAL. + CASE token-lexeme. + WHEN ')' OR '|'. + RAISE EXCEPTION TYPE lcx_error. + WHEN OTHERS. + IF token-lexeme CP '`*`' OR token-lexeme CP `'*'`. + DATA(len) = strlen( token-lexeme ) - 2. + result = token-lexeme+1(len). + IF result CA '|'. + RAISE EXCEPTION TYPE lcx_error. + ENDIF. + result = replace( val = result sub = '\' with = '\\' occ = 0 ). + result = replace( val = result sub = '{' with = '\{' occ = 0 ). + result = replace( val = result sub = '}' with = '\}' occ = 0 ). + ELSE. + RAISE EXCEPTION TYPE lcx_error. + ENDIF. + ENDCASE. + ELSE. + result = |\{ { token-lexeme } \}|. + ENDIF. + ENDMETHOD. + + + METHOD append_token. + IF result IS INITIAL. + result = token-lexeme. + ELSE. + result = |{ result } { token-lexeme }|. + ENDIF. + ENDMETHOD. + + + METHOD append_tokens. + DATA itab LIKE tokens. + IF from_idx IS SUPPLIED OR to_idx IS SUPPLIED. + IF from_idx = 0. + from_idx = 1. + ENDIF. + IF to_idx = 0. + to_idx = lines( tokens ). + ENDIF. + LOOP AT tokens FROM from_idx TO to_idx ASSIGNING FIELD-SYMBOL(). + APPEND TO itab. + ENDLOOP. + DATA(flattened) = analyzer->flatten_tokens( tokens = itab ). + ELSE. + flattened = analyzer->flatten_tokens( tokens = tokens ). + ENDIF. + IF result IS INITIAL. + result = flattened. + ELSE. + result = |{ result } { flattened }|. + ENDIF. + ENDMETHOD. + + + METHOD get_receiving_infos. + CLEAR end_idx. + CLEAR result_line. + receiving_idx = analyzer->find_clause_index( tokens = tokens clause = 'RECEIVING ' ). + IF receiving_idx = 0. + RETURN. + ENDIF. + DATA(copy_idx) = analyzer->find_clause_index( tokens = tokens start_index = receiving_idx + 1 clause = '=' ). + IF copy_idx <> 0. + end_idx = lines( tokens ). + LOOP AT tokens FROM copy_idx + 1 ASSIGNING FIELD-SYMBOL() + WHERE references IS INITIAL. + CASE -lexeme. + WHEN ')' OR 'EXPORTING'. + end_idx = sy-tabix - 1. + EXIT. + ENDCASE. + ENDLOOP. + append_tokens( EXPORTING tokens = tokens from_idx = copy_idx + 1 to_idx = end_idx CHANGING result = result_line ). + ENDIF. + + ENDMETHOD. +ENDCLASS. diff --git a/src/checks/#cc4a#modern_language.clas.locals_def.abap b/src/checks/#cc4a#modern_language.clas.locals_def.abap new file mode 100644 index 0000000..1a14d7c --- /dev/null +++ b/src/checks/#cc4a#modern_language.clas.locals_def.abap @@ -0,0 +1,6 @@ +*"* use this source file for any type of declarations (class +*"* definitions, interfaces or type declarations) you need for +*"* components in the private section +class lcx_error definition final + inheriting from cx_static_check. +endclass. diff --git a/src/checks/#cc4a#modern_language.clas.locals_imp.abap b/src/checks/#cc4a#modern_language.clas.locals_imp.abap new file mode 100644 index 0000000..cafb524 --- /dev/null +++ b/src/checks/#cc4a#modern_language.clas.locals_imp.abap @@ -0,0 +1,6 @@ +*"* use this source file for the definition and implementation of +*"* local helper classes, interface definitions and type +*"* declarations + +class lcx_error IMPLEMENTATION. +endclass. diff --git a/src/checks/#cc4a#modern_language.clas.testclasses.abap b/src/checks/#cc4a#modern_language.clas.testclasses.abap new file mode 100644 index 0000000..bf682e1 --- /dev/null +++ b/src/checks/#cc4a#modern_language.clas.testclasses.abap @@ -0,0 +1,447 @@ +CLASS test DEFINITION FINAL FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. + + PRIVATE SECTION. + CONSTANTS test_class TYPE c LENGTH 30 VALUE '/CC4A/TEST_MODERN_LANGUAGE'. + METHODS test FOR TESTING RAISING cx_static_check. +ENDCLASS. + +CLASS test IMPLEMENTATION. + + METHOD test. + DATA(test_move) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_MOVE' ) ). + DATA(test_translate) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_TRANSLATE' ) ). + DATA(test_read) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_READ' ) ). + DATA(test_loop) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_LOOP' ) ). + DATA(test_create_object) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_CREATE_OBJECT' ) ). + DATA(test_call_method) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_CALL_METHOD' ) ). + DATA(test_exporting_receiving) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_EXPORTING_RECEIVING' ) ). + DATA(test_text_assembly) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_TEXT_ASSEMBLY' ) ). + cl_ci_atc_unit_driver=>create_test_case( + check = NEW /cc4a/modern_language( ) + object = VALUE #( type = 'CLAS' name = test_class ) + )->execute_and_assert( VALUE #( + ( code = /cc4a/modern_language=>c_code_move + location = VALUE #( object = test_move position = VALUE #( line = 9 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_move + span = VALUE #( object = test_move from = 9 to = 9 ) + code_lines = VALUE #( ( `NUM = EXACT #( 1 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_move + location = VALUE #( object = test_move position = VALUE #( line = 13 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_move + span = VALUE #( object = test_move from = 13 to = 13 ) + code_lines = VALUE #( ( `N = 5.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_move + location = VALUE #( object = test_move position = VALUE #( line = 15 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_move + span = VALUE #( object = test_move from = 15 to = 15 ) + code_lines = VALUE #( ( `N = EXACT #( 5 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_move + location = VALUE #( object = test_move position = VALUE #( line = 20 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_move + span = VALUE #( object = test_move from = 20 to = 20 ) + code_lines = VALUE #( ( `B ?= A.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_move + location = VALUE #( object = test_move position = VALUE #( line = 22 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_move + span = VALUE #( object = test_move from = 22 to = 22 ) + code_lines = VALUE #( ( `B = A.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_move + location = VALUE #( object = test_move position = VALUE #( line = 24 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_move + + span = VALUE #( object = test_move from = 24 to = 24 ) + code_lines = VALUE #( ( `B = A.` ) ) ) ) ) + + +* TRANSLATE + ( code = /cc4a/modern_language=>c_code_translate + location = VALUE #( object = test_translate position = VALUE #( line = 3 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_translate + span = VALUE #( object = test_translate from = 3 to = 3 ) + code_lines = VALUE #( ( `STR1 = to_upper( STR1 ).` ) ) ) ) ) + ( code = /cc4a/modern_language=>c_code_translate + location = VALUE #( object = test_translate position = VALUE #( line = 4 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_translate + span = VALUE #( object = test_translate from = 4 to = 4 ) + code_lines = VALUE #( ( `STR1 = to_lower( STR1 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_translate + location = VALUE #( object = test_translate position = VALUE #( line = 5 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_translate + span = VALUE #( object = test_translate from = 5 to = 5 ) + code_lines = VALUE #( ( `STR1 = to_lower( STR1 ).` ) ) ) ) ) + + +* READ + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 4 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 4 to = 5 ) + code_lines = VALUE #( ( `DATA(IDX) = LINE_INDEX( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 7 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 7 to = 11 ) + code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ).` ) + ( `DATA(EXISTS) = XSDBOOL( LINE_EXISTS( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ) ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 19 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 19 to = 20 ) + code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 21 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 21 to = 25 ) + code_lines = VALUE #( ( `EXISTS = XSDBOOL( LINE_EXISTS( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ) ).` ) + ( `IDX = LINE_INDEX( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 34 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 34 to = 35 ) + code_lines = VALUE #( ( `IDX = line_index( ITAB[ PGMID = 'R3TR' ] ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_move + location = VALUE #( object = test_read position = VALUE #( line = 35 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_move + span = VALUE #( object = test_read from = 35 to = 35 ) + code_lines = VALUE #( ( `idx = sy-tabix.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 41 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 41 to = 44 ) + code_lines = VALUE #( ( `DATA(BLUE) = xsdbool( NOT line_exists( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLUE' ] ) ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 52 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 52 to = 54 ) + code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) = 0 .` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 57 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 57 to = 59 ) + code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) = 0 .` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 62 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 62 to = 64 ) + code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 67 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_read from = 67 to = 69 ) + code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) + + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_loop position = VALUE #( line = 4 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_loop from = 4 to = 7 ) + code_lines = VALUE #( ( `DATA(IDX) = LINE_INDEX( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_loop position = VALUE #( line = 9 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_loop from = 9 to = 13 ) + code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ).` ) + ( `DATA(EXISTS) = XSDBOOL( LINE_EXISTS( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ) ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_loop position = VALUE #( line = 21 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_loop from = 21 to = 24 ) + code_lines = VALUE #( ( `EXISTS = xsdbool( line_exists( ITAB[ OBJ_NAME = 'BLA' ] ) ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_loop position = VALUE #( line = 38 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_line_exists + span = VALUE #( object = test_loop from = 38 to = 41 ) + code_lines = VALUE #( ( `EXISTS = xsdbool( line_exists( ITAB[ OBJ_NAME = 'BLA' ] ) ).` ) ) ) ) ) + + + ( code = /cc4a/modern_language=>c_code_prefer_new + location = VALUE #( object = test_create_object position = VALUE #( line = 3 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + span = VALUE #( object = test_create_object from = 2 to = 3 ) + code_lines = VALUE #( ( `DATA(object1) = NEW /cc4a/test_modern_language( ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_prefer_new + location = VALUE #( object = test_create_object position = VALUE #( line = 5 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + span = VALUE #( object = test_create_object from = 5 to = 5 ) + code_lines = VALUE #( ( `object1 = NEW #( ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_prefer_new + location = VALUE #( object = test_create_object position = VALUE #( line = 9 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + span = VALUE #( object = test_create_object from = 7 to = 12 ) + code_lines = VALUE #( ( `DATA(CLASS_REF) = NEW LCL_TEST( PARAM1 = 5 PARAM2 = 4 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_prefer_new + location = VALUE #( object = test_create_object position = VALUE #( line = 16 column = 8 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + span = VALUE #( object = test_create_object from = 16 to = 18 ) + code_lines = VALUE #( ( `CLASS_REF1 = NEW #( PARAM1 = 15 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_prefer_new + location = VALUE #( object = test_create_object position = VALUE #( line = 32 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + span = VALUE #( object = test_create_object from = 31 to = 35 ) + code_lines = VALUE #( ( `DATA(CLASS_REF3) = NEW LCL_TEST3( param1 = 'blabla' param2 = |{ sy-datum } { sy-uzeit }| ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_prefer_new + location = VALUE #( object = test_create_object position = VALUE #( line = 37 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + span = VALUE #( object = test_create_object from = 37 to = 40 ) + code_lines = VALUE #( ( `CLASS_REF3 = NEW #( param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_prefer_new + location = VALUE #( object = test_create_object position = VALUE #( line = 42 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + span = VALUE #( object = test_create_object from = 42 to = 45 ) + code_lines = VALUE #( ( `CLASS_REF3 = NEW #( param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_call_method + location = VALUE #( object = test_call_method position = VALUE #( line = 6 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_call_method + span = VALUE #( object = test_call_method from = 6 to = 6 ) + code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_call_method + location = VALUE #( object = test_call_method position = VALUE #( line = 8 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_call_method + span = VALUE #( object = test_call_method from = 8 to = 8 ) + code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_call_method + location = VALUE #( object = test_call_method position = VALUE #( line = 10 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_call_method + span = VALUE #( object = test_call_method from = 10 to = 14 ) + code_lines = VALUE #( ( `DATA(RESULT) = CLASS_REF->TEST1( PARAM1 = 15 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_call_method + location = VALUE #( object = test_call_method position = VALUE #( line = 16 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_call_method + span = VALUE #( object = test_call_method from = 16 to = 22 ) + code_lines = VALUE #( ( `CLASS_REF->TEST2(` ) + ( `EXPORTING PARAM1 = 'Blabla'` ) + ( `IMPORTING PARAM2 = DATA(STRING_RESULT)` ) + ( `CHANGING PARAM3 = TEST_STRING ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_call_method + location = VALUE #( object = test_call_method position = VALUE #( line = 33 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_call_method + span = VALUE #( object = test_call_method from = 33 to = 39 ) + code_lines = VALUE #( ( `CLASS_REF->TEST4(` ) + ( `EXPORTING` ) + ( `param1 = 1` ) + ( `param2 = 2` ) + ( `param3 = 3` ) + ( `IMPORTING` ) + ( `param4 = result` ) + ( `).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_call_method + location = VALUE #( object = test_call_method position = VALUE #( line = 41 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_call_method + span = VALUE #( object = test_call_method from = 41 to = 41 ) + code_lines = VALUE #( ( `class_ref->test1( param1 = 3 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_call_method + location = VALUE #( object = test_call_method position = VALUE #( line = 51 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_call_method + span = VALUE #( object = test_call_method from = 51 to = 51 ) + code_lines = VALUE #( ( ` class_ref->test7(` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_call_method + location = VALUE #( object = test_call_method position = VALUE #( line = 59 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_call_method + span = VALUE #( object = test_call_method from = 59 to = 59 ) + code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) + + + ( code = /cc4a/modern_language=>c_code_method_exporting + location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 6 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_method_exporting + span = VALUE #( object = test_call_method from = 6 to = 8 ) + code_lines = VALUE #( ( `DATA(RESULT) = CLASS_REF->TEST1(` ) + ( `PARAM1 = 15 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_method_exporting + location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 18 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_method_exporting + span = VALUE #( object = test_call_method from = 18 to = 18 ) + code_lines = VALUE #( ( `result = class_ref->test3( param1 = 15 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_method_exporting + location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 20 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_method_exporting + span = VALUE #( object = test_exporting_receiving from = 20 to = 20 ) + code_lines = VALUE #( ( `result = class_ref->test1( param1 = class_ref->test3( param1 = 3 ) ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_exporting_receiving + location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 23 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_exporting_receiving + span = VALUE #( object = test_exporting_receiving from = 23 to = 26 ) + code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST1( PARAM1 = 15 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_exporting_receiving + location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 29 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_exporting_receiving + span = VALUE #( object = test_exporting_receiving from = 29 to = 29 ) + code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST3( PARAM1 = 15 ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_exporting_receiving + location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 33 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_exporting_receiving + span = VALUE #( object = test_exporting_receiving from = 33 to = 33 ) + code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST1( PARAM1 = CLASS_REF->TEST3( PARAM1 = 3 ) ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 4 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + span = VALUE #( object = test_text_assembly from = 4 to = 4 ) + code_lines = VALUE #( ( `text1 = |ab{ TEXT1 }{ ABAP_TRUE }|.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 5 column = 4 ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 7 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + span = VALUE #( object = test_text_assembly from = 7 to = 7 ) + code_lines = VALUE #( ( ` WRITE class_ref->test5( param1 = |ab| param2 = |cd| ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 9 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + span = VALUE #( object = test_text_assembly from = 9 to = 9 ) + code_lines = VALUE #( ( `WRITE class_ref->test5( param1 = |ab| param2 = 'xxx' ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 11 column = 4 ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 13 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + span = VALUE #( object = test_text_assembly from = 13 to = 13 ) + code_lines = VALUE #( ( `text1 = |{ TEXT1 } \}| ##no_text.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 15 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + span = VALUE #( object = test_text_assembly from = 15 to = 18 ) + code_lines = VALUE #( ( `text1 = |[\{"TYPE":"U","TARGET":\{"URL":\{"URL":"www.sap.com/en"\}\}\},\{\}]|.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 21 column = 4 ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 22 column = 4 ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 23 column = 4 ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 25 column = 4 ) ) + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + span = VALUE #( object = test_text_assembly from = 25 to = 25 ) + code_lines = VALUE #( ( `text1 = |\\{ TEXT1 }-|.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 27 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + span = VALUE #( object = test_text_assembly from = 27 to = 27 ) + code_lines = VALUE #( ( `WRITE |ab|.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_text_assembly + location = VALUE #( object = test_read position = VALUE #( line = 75 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + span = VALUE #( object = test_read from = 75 to = 75 ) + code_lines = VALUE #( ( `WRITE |Difference in contructor code/line{ SY-TABIX }|.` ) ) ) ) ) + + + ) ). + + ENDMETHOD. + + +ENDCLASS. diff --git a/src/checks/#cc4a#modern_language.clas.xml b/src/checks/#cc4a#modern_language.clas.xml new file mode 100644 index 0000000..7f368ce --- /dev/null +++ b/src/checks/#cc4a#modern_language.clas.xml @@ -0,0 +1,133 @@ + + + + + + /CC4A/MODERN_LANGUAGE + E + check for modern language + 1 + X + X + X + X + + + + I + 001 + MOVE is obsolete + 26 + + + I + 002 + TRANSLATE TO UPPER/LOWERCASE is obsolete + 80 + + + I + 003 + Prefer LINE_EXISTS/LINE_INDEX + 50 + + + I + 004 + Prefer NEW instead of CREATE OBJECT + 70 + + + I + 005 + Prefer functional call instead of CALL METHOD + 90 + + + I + 006 + Omit EXPORTING in functional Method Call if possible + 104 + + + I + 007 + Do not use RECEIVING in functional Method Call if possible + 116 + + + I + 008 + Use string templates instead of && + 68 + + + I + DES + Modern Language + 25 + + + I + Q01 + Quickfix Syntax Error + 42 + + + I + Q02 + Quickfix Testing Error + 44 + + + I + QF1 + Replace MOVE statement + 44 + + + I + QF2 + Replace TRANSLATE statement + 54 + + + I + QF3 + Use LINE_EXISTS/LINE_INDEX + 52 + + + I + QF4 + Use NEW instead of CREATE OBJECT + 64 + + + I + QF5 + Use functional call instead of CALL METHOD + 84 + + + I + QF6 + Omit EXPORTING + 24 + + + I + QF7 + Do not use EXPORTING/RECEIVING + 60 + + + I + QF8 + Replace && by string templates + 60 + + + + + diff --git a/src/checks/(cc4a)modern.chko.json b/src/checks/(cc4a)modern.chko.json new file mode 100644 index 0000000..a32bb2e --- /dev/null +++ b/src/checks/(cc4a)modern.chko.json @@ -0,0 +1,10 @@ +{ + "formatVersion": "1", + "header": { + "description": "Modern Language", + "originalLanguage": "en" + }, + "category": "/CC4A/CODE_PAL", + "implementingClass": "/CC4A/MODERN_LANGUAGE", + "checkType": "remoteEnabled" +} \ No newline at end of file diff --git a/src/test_objects/#cc4a#test_modern_language.clas.abap b/src/test_objects/#cc4a#test_modern_language.clas.abap new file mode 100644 index 0000000..c0aea80 --- /dev/null +++ b/src/test_objects/#cc4a#test_modern_language.clas.abap @@ -0,0 +1,381 @@ +CLASS /cc4a/test_modern_language DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + METHODS test_move. + METHODS test_translate. + METHODS test_read. + METHODS test_loop. + METHODS test_create_object. + METHODS test_call_method. + METHODS test_exporting_receiving. + METHODS test_text_assembly. + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS /cc4a/test_modern_language IMPLEMENTATION. + + + METHOD test_move. + TYPES: + BEGIN OF ENUM number, + n0, n1, n2, + END OF ENUM number. + + DATA num TYPE number ##NEEDED. + + MOVE EXACT 1 TO num. + + DATA n TYPE i ##NEEDED ##FLD_TYPE_NAME. + + MOVE 5 TO n. + + MOVE EXACT 5 TO n. + + DATA a TYPE REF TO i ##NEEDED. + DATA b TYPE REF TO i ##NEEDED. + + MOVE a ?TO b. + + MOVE a TO b ##DUPLICATE_OK. + + MOVE a TO b. "#EC DEPRECATED_KEY + ENDMETHOD. + + + METHOD test_translate. + DATA(str1) = `This is Really Mixed` ##NEEDED ##NO_TEXT. + TRANSLATE str1 TO UPPER CASE. + TRANSLATE str1 TO LOWER CASE. + TRANSLATE str1 TO LOWER CASE. "#EC DEPRECATED_KEY + ENDMETHOD. + + + METHOD test_read. + DATA itab TYPE STANDARD TABLE OF /cc4a/db_test1 WITH NON-UNIQUE SORTED KEY name COMPONENTS obj_name. + + READ TABLE itab TRANSPORTING NO FIELDS WITH KEY pgmid = 'R3TR' object = 'CLAS' . + DATA(idx) = sy-tabix ##NEEDED. + + READ TABLE itab WITH KEY pgmid = 'R3TR' object = 'CLAS' TRANSPORTING NO FIELDS . + IF sy-subrc = 0. + idx = sy-tabix. + DATA(exists) = abap_true. + ENDIF. + "DATA(idx) = line_index( itab[ pgmid = 'R3TR' object = 'CLAS' ] ). + READ TABLE itab WITH KEY pgmid = 'R3TR' object = 'CLAS' BINARY SEARCH TRANSPORTING NO FIELDS . "no finding because of binary search + IF sy-subrc = 0. + idx = sy-tabix. + exists = abap_true. + ENDIF. + + READ TABLE itab WITH KEY name COMPONENTS obj_name = 'BLABLA' TRANSPORTING NO FIELDS. + idx = sy-tabix. + READ TABLE itab TRANSPORTING NO FIELDS WITH KEY name COMPONENTS obj_name = 'BLABLA'. + IF sy-subrc EQ 0. + exists = abap_true. + idx = sy-tabix. + ENDIF. + "idx = line_index( itab[ KEY name COMPONENTS obj_name = 'BLABLA' ] ). + READ TABLE itab TRANSPORTING NO FIELDS WITH KEY name COMPONENTS obj_name = 'BLABLA'. + IF sy-subrc EQ 0. + exists = abap_true. + idx = sy-tabix. + WRITE 'hallo' ##NO_TEXT. + ENDIF. + + READ TABLE itab WITH KEY pgmid = 'R3TR' TRANSPORTING NO FIELDS. + MOVE sy-tabix TO idx. + + READ TABLE itab WITH KEY pgmid = 'R3TR' TRANSPORTING NO FIELDS. + IF sy-subrc <> 0 OR exists = abap_true ##NEEDED. + ENDIF. + + READ TABLE itab TRANSPORTING NO FIELDS WITH KEY name COMPONENTS obj_name = 'BLUE'. + IF sy-subrc <> 0. + DATA(blue) = abap_false ##NEEDED. + ENDIF. + + READ TABLE itab TRANSPORTING NO FIELDS WITH KEY name COMPONENTS obj_name = 'BLUE'. + IF sy-subrc <> 0. + blue = abap_false. + idx = sy-tabix. + ENDIF. + + READ TABLE itab TRANSPORTING NO FIELDS + WITH KEY pgmid = 'R3TR'. + IF sy-tabix = 0 ##NEEDED. + ENDIF. + + READ TABLE itab TRANSPORTING NO FIELDS + WITH KEY pgmid = 'R3TR'. + IF sy-tabix IS INITIAL ##NEEDED. + ENDIF. + + READ TABLE itab TRANSPORTING NO FIELDS + WITH KEY pgmid = 'R3TR'. + IF sy-tabix IS NOT INITIAL ##NEEDED. + ENDIF. + + READ TABLE itab TRANSPORTING NO FIELDS + WITH KEY pgmid = 'R3TR'. "#EC PREF_LINE_EX + IF sy-tabix IS NOT INITIAL ##NEEDED. + ENDIF. + + DATA itab_string TYPE TABLE OF string. + READ TABLE itab_string TRANSPORTING NO FIELDS + WITH KEY table_line = 'blabla' ##NO_TEXT. + WRITE 'Difference in contructor code/line' && sy-tabix ##NO_TEXT. + READ TABLE itab_string TRANSPORTING NO FIELDS + WITH KEY table_line = 'blub' ##NO_TEXT. + MESSAGE i011(sci) INTO DATA(lv_dummy) WITH sy-tabix ##NEEDED. + + DATA(test) = NEW lcl_test4( ). + READ TABLE itab WITH KEY pgmid = 'BLUB' TRANSPORTING NO FIELDS. + IF sy-subrc <> 0. + test->test( param = abap_false ). + ENDIF. + ENDMETHOD. + + + METHOD test_loop. + DATA itab TYPE STANDARD TABLE OF /cc4a/db_test1. + + LOOP AT itab TRANSPORTING NO FIELDS WHERE pgmid = 'R3TR' AND object = 'CLAS' . + DATA(idx) = sy-tabix ##NEEDED. + EXIT. + ENDLOOP. + + LOOP AT itab TRANSPORTING NO FIELDS WHERE pgmid = 'R3TR' AND object = 'CLAS' . + idx = sy-tabix. + DATA(exists) = abap_true ##NEEDED. + EXIT. + ENDLOOP. + + LOOP AT itab INTO DATA(l_entry) WHERE obj_name = 'BLA' ##INTO_OK. "no finding because l_entry is used + exists = abap_true. + EXIT. + ENDLOOP. + WRITE l_entry-pgmid. + + LOOP AT itab INTO l_entry WHERE obj_name = 'BLA' ##INTO_OK. + exists = abap_true. + EXIT. + ENDLOOP. + + + LOOP AT itab TRANSPORTING NO FIELDS WHERE obj_name = 'BLABLA' AND pgmid IS NOT INITIAL. + exists = abap_true. + EXIT. + ENDLOOP. + + CONSTANTS c_where TYPE string VALUE 'blabla' ##NO_TEXT. + LOOP AT itab TRANSPORTING NO FIELDS WHERE (c_where). + exists = abap_true. + EXIT. + ENDLOOP. + + LOOP AT itab TRANSPORTING NO FIELDS WHERE obj_name = 'BLA'. "#EC PREF_LINE_EX + exists = abap_true. + EXIT. + ENDLOOP. + + ENDMETHOD. + + + METHOD test_create_object. + DATA object1 TYPE REF TO /cc4a/test_modern_language. + CREATE OBJECT object1 ##DUPLICATE_OK. + + CREATE OBJECT object1. + + DATA class_ref TYPE REF TO lcl_test. + + CREATE OBJECT class_ref + EXPORTING + param1 = 5 + param2 = 4. + + DATA class_ref1 TYPE REF TO lcl_test1. + TRY. + CREATE OBJECT class_ref1 + EXPORTING + param1 = 15 ##NUMBER_OK. + CATCH lcx_error ##NO_HANDLER. + ENDTRY. + + DATA class_ref2 TYPE REF TO lcl_test2. + CREATE OBJECT class_ref2 + EXPORTING + param1 = 13 ##NUMBER_OK + EXCEPTIONS + error = 1 ##SUBRC_OK. + IF sy-subrc <> 0 ##NEEDED. + ENDIF. + + DATA class_ref3 TYPE REF TO lcl_test3. + CREATE OBJECT class_ref3 + EXPORTING + param1 = 'blabla' ##NO_TEXT + param2 = |{ sy-datum } { sy-uzeit }|. + + CREATE OBJECT class_ref3 + EXPORTING + param1 = |{ sy-datum } { sy-uzeit }| + param2 = 'bla' ##DUPLICATE_OK. + + CREATE OBJECT class_ref3 + EXPORTING + param1 = |{ sy-datum } { sy-uzeit }| + param2 = 'bla'. "#EC PREF_NEW + + + DATA selfish TYPE REF TO lcl_test_selfish. + CREATE OBJECT selfish + EXPORTING + val = selfish->my_val. + ENDMETHOD. + + + METHOD test_call_method. + DATA test_string TYPE string. + + DATA(class_ref) = NEW lcl_test( param1 = 5 param2 = 3 ). + + CALL METHOD test_create_object( ). + + CALL METHOD test_create_object. + + CALL METHOD class_ref->test1 + EXPORTING + param1 = 15 ##NUMBER_OK + RECEIVING + result = DATA(result) ##NEEDED. + + CALL METHOD class_ref->test2 + EXPORTING + param1 = 'Blabla' ##NO_TEXT + IMPORTING + param2 = DATA(string_result) ##NEEDED + CHANGING + param3 = test_string. + + CALL METHOD class_ref->test3 "no finding because of exceptions + EXPORTING + param1 = 15 ##NUMBER_OK + RECEIVING + result = result + EXCEPTIONS + error1 = 1 + error2 = 2 ##SUBRC_OK. + + CALL METHOD class_ref->test4 + EXPORTING + param1 = 1 + param2 = 2 + param3 = 3 + IMPORTING + param4 = result. + + CALL METHOD class_ref->test1( param1 = 3 ). + + CALL METHOD (test_string). + + DATA ptab TYPE abap_parmbind_tab. + DATA xtab TYPE abap_excpbind_tab. + CALL METHOD ('class')=>('method') + PARAMETER-TABLE ptab + EXCEPTION-TABLE xtab. + + CALL METHOD class_ref->test7( + EXPORTING + param1 = 5 + IMPORTING + param2 = DATA(testnumber1) + RECEIVING + result = DATA(testnumber2) ) ##NEEDED. + + CALL METHOD test_create_object. "#EC CALL_METH_USAGE + + ENDMETHOD. + + + METHOD test_exporting_receiving. + DATA test_string TYPE string. + + DATA(class_ref) = NEW lcl_test( param1 = 5 param2 = 3 ). + + DATA(result) = class_ref->test1( + EXPORTING + param1 = 15 ) ##NEEDED ##NUMBER_OK. + + class_ref->test2( + EXPORTING + param1 = 'Blabla' ##NO_TEXT + IMPORTING + param2 = DATA(string_result) ##NEEDED + CHANGING + param3 = test_string ) ##NEEDED. + + result = class_ref->test3( EXPORTING param1 = 15 ) ##NUMBER_OK. + + result = class_ref->test1( EXPORTING param1 = class_ref->test3( EXPORTING param1 = 3 ) ). + +* with receiving + class_ref->test1( + EXPORTING + param1 = 15 ##NUMBER_OK + RECEIVING result = result ). + + + class_ref->test3( EXPORTING param1 = 15 RECEIVING result = result ) ##NUMBER_OK. + + class_ref->test3( EXPORTING param1 = 15 RECEIVING result = result EXCEPTIONS error1 = 1 error2 = 2 ) ##SUBRC_OK ##NUMBER_OK. + + class_ref->test1( EXPORTING param1 = class_ref->test3( EXPORTING param1 = 3 ) RECEIVING result = result ). + + class_ref->test7( "#EC OPTL_EXP + EXPORTING + param1 = 5 + IMPORTING + param2 = DATA(testnumber1) ##NEEDED + RECEIVING + result = DATA(testnumber2) ) ##NEEDED. "#EC RECEIVING_USAGE + + ENDMETHOD. + + + METHOD test_text_assembly. + DATA class_ref TYPE REF TO lcl_test ##NEEDED. + DATA text1 TYPE string. + text1 = 'ab' && text1 && abap_true. + text1 = class_ref->test5( param1 = 'a' param2 = 'b' ) && 'end'. + + WRITE class_ref->test5( param1 = 'a' && 'b' param2 = 'c' && 'd' ). + + WRITE class_ref->test5( param1 = 'a' && 'b' param2 = 'xxx' ). + + WRITE class_ref->test6( 'a' && 'b' ) && 'end'. + + text1 = text1 && ' }' ##no_text. + + text1 = '[' && + '{"TYPE":"U","TARGET":{"URL":{"URL":"www.sap.com/en"}}}' && + ',{}' && + ']'. + + DATA itab TYPE STANDARD TABLE OF /cc4a/db_test1. + WRITE itab[ 1 ]-object && 'a'. + WRITE 'a' && itab[ 1 ]-obj_name. + text1 = text1 && COND #( WHEN itab IS INITIAL THEN 'a' ELSE 'b' ). + + text1 = `\` && text1 && `-`. + + WRITE 'a' && 'b'. "#EC TEXT_ASSEMBLY + ENDMETHOD. +ENDCLASS. diff --git a/src/test_objects/#cc4a#test_modern_language.clas.locals_imp.abap b/src/test_objects/#cc4a#test_modern_language.clas.locals_imp.abap new file mode 100644 index 0000000..5a4af1b --- /dev/null +++ b/src/test_objects/#cc4a#test_modern_language.clas.locals_imp.abap @@ -0,0 +1,141 @@ +*"* use this source file for the definition and implementation of +*"* local helper classes, interface definitions and type +*"* declarations + +CLASS lcx_error DEFINITION FINAL + INHERITING FROM cx_static_check. +ENDCLASS. + +CLASS lcx_error IMPLEMENTATION. +ENDCLASS. + +CLASS lcl_test DEFINITION FINAL. + PUBLIC SECTION. + METHODS constructor + IMPORTING param1 TYPE i + param2 TYPE i ##NEEDED. + METHODS test1 + IMPORTING param1 TYPE i + RETURNING VALUE(result) TYPE i. + METHODS test2 + IMPORTING param1 TYPE string + EXPORTING param2 TYPE string + CHANGING param3 TYPE string. + METHODS test3 + IMPORTING param1 TYPE i + RETURNING VALUE(result) TYPE i + EXCEPTIONS error1 error2 ##NEEDED. + METHODS test4 + IMPORTING param1 TYPE i + param2 TYPE i + param3 TYPE i + EXPORTING param4 TYPE i. + METHODS test5 + IMPORTING param1 TYPE string + param2 TYPE string + RETURNING VALUE(result) TYPE string. + METHODS test6 + IMPORTING param TYPE string + RETURNING VALUE(result) TYPE string. + METHODS test7 + IMPORTING param1 TYPE i + EXPORTING param2 TYPE i + RETURNING VALUE(result) TYPE i. +ENDCLASS. + +CLASS lcl_test IMPLEMENTATION. + METHOD test1. + result = param1. + ENDMETHOD. + METHOD test2. + param2 = |{ param1 }{ param3 }|. + CLEAR param3. + ENDMETHOD. + METHOD test3. + IF param1 > 10. + RAISE error1. + ENDIF. + result = param1 + 5. + IF result < 0. + RAISE error2. + ENDIF. + ENDMETHOD. + METHOD test4. + param4 = param1 + param2 + param3. + ENDMETHOD. + METHOD test5. + result = |{ param1 } { param2 }|. + ENDMETHOD. + METHOD test6. + result = |{ param } end|. + ENDMETHOD. + METHOD test7. + result = param1 + 3. + param2 = param1 + 5. + ENDMETHOD. + METHOD constructor ##NEEDED. + ENDMETHOD. +ENDCLASS. + +CLASS lcl_test1 DEFINITION FINAL. + PUBLIC SECTION. + METHODS constructor + IMPORTING param1 TYPE i + RAISING lcx_error. +ENDCLASS. +CLASS lcl_test1 IMPLEMENTATION. + METHOD constructor. + IF param1 <= 0. + RAISE EXCEPTION TYPE lcx_error. + ENDIF. + ENDMETHOD. +ENDCLASS. + + +CLASS lcl_test2 DEFINITION FINAL. + PUBLIC SECTION. + METHODS constructor + IMPORTING param1 TYPE i + EXCEPTIONS error. +ENDCLASS. +CLASS lcl_test2 IMPLEMENTATION. + METHOD constructor. + IF param1 <= 0. + RAISE error. + ENDIF. + ENDMETHOD. +ENDCLASS. + +CLASS lcl_test3 DEFINITION FINAL. + PUBLIC SECTION. + METHODS constructor + IMPORTING param1 TYPE string + param2 TYPE string ##NEEDED. +ENDCLASS. +CLASS lcl_test3 IMPLEMENTATION. + METHOD constructor ##NEEDED. + ENDMETHOD. +ENDCLASS. + +CLASS lcl_test_selfish DEFINITION FINAL. + PUBLIC SECTION. + METHODS constructor + IMPORTING val TYPE i ##NEEDED. + DATA my_val TYPE i. +ENDCLASS. + +CLASS lcl_test_selfish IMPLEMENTATION. + METHOD constructor ##NEEDED. + ENDMETHOD. +ENDCLASS. + +CLASS lcl_test4 DEFINITION FINAL. + PUBLIC SECTION. + METHODS test + IMPORTING param TYPE abap_bool ##NEEDED. +ENDCLASS. + +CLASS lcl_test4 IMPLEMENTATION. + METHOD test ##NEEDED. + ENDMETHOD. +ENDCLASS. diff --git a/src/test_objects/#cc4a#test_modern_language.clas.xml b/src/test_objects/#cc4a#test_modern_language.clas.xml new file mode 100644 index 0000000..15a9ce7 --- /dev/null +++ b/src/test_objects/#cc4a#test_modern_language.clas.xml @@ -0,0 +1,16 @@ + + + + + + /CC4A/TEST_MODERN_LANGUAGE + E + test + 1 + X + X + X + + + + From df6d1576cab6b203525d6c01208465cb05818364 Mon Sep 17 00:00:00 2001 From: Josia Kempf Date: Mon, 25 Sep 2023 15:02:00 +0200 Subject: [PATCH 2/9] Update #cc4a#modern_language.clas.abap --- src/checks/#cc4a#modern_language.clas.abap | 94 +++++++++++++++++----- 1 file changed, 75 insertions(+), 19 deletions(-) diff --git a/src/checks/#cc4a#modern_language.clas.abap b/src/checks/#cc4a#modern_language.clas.abap index b9f1a3f..bd001a9 100644 --- a/src/checks/#cc4a#modern_language.clas.abap +++ b/src/checks/#cc4a#modern_language.clas.abap @@ -350,6 +350,7 @@ CLASS /cc4a/modern_language IMPLEMENTATION. IF key_idx = 0. RETURN. ELSE. + DATA(start_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'COMPONENTS' start_index = key_idx + 1 ). IF start_idx = 0. "with key... @@ -362,8 +363,14 @@ CLASS /cc4a/modern_language IMPLEMENTATION. IF to_idx <= 0. to_idx = lines( statement-tokens ). ENDIF. - append_tokens( EXPORTING tokens = statement-tokens from_idx = start_idx to_idx = to_idx - CHANGING result = key ). + IF statement-tokens[ key_idx + 2 ]-lexeme = '='. + key = 'TABLE_LINE'. + append_tokens( EXPORTING tokens = statement-tokens from_idx = key_idx + 2 to_idx = to_idx + CHANGING result = key ). + ELSE. + append_tokens( EXPORTING tokens = statement-tokens from_idx = start_idx to_idx = to_idx + CHANGING result = key ). + ENDIF. keylen = to_idx - start_idx + 1. ENDIF. @@ -378,6 +385,10 @@ CLASS /cc4a/modern_language IMPLEMENTATION. CHANGING findings = findings ). RETURN. ENDIF. + DATA(quickfixable) = abap_true. +* if statement-tokens[ key_idx + 2 ]-lexeme = '='. +* quickfixable = abap_false. +* endif. DATA(table) = statement-tokens[ 3 ]-lexeme. IF table CP '*[]'. DATA(len) = strlen( table ) - 2. @@ -413,20 +424,27 @@ CLASS /cc4a/modern_language IMPLEMENTATION. IF sytabix_idx <> 0. IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-lexeme = '&&'. - RETURN. + quickfixable = abap_false. + EXIT. ENDIF. IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-references IS INITIAL AND -tokens[ sytabix_idx - 1 ]-lexeme = 'LIKE' AND -keyword = 'DATA'. - RETURN. + quickfixable = abap_false. + EXIT. ENDIF. CASE -keyword. WHEN 'MOVE'. analyze_move( EXPORTING procedure = procedure statement_index = tabix IMPORTING changed_line = code_line_index ). REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. APPEND code_line_index TO code_lines. - WHEN 'MESSAGE'. - RETURN. + WHEN 'MESSAGE' OR 'PERFORM' OR '+CALL_MACRO'. + quickfixable = abap_false. + EXIT. + WHEN 'SET'. + IF -tokens[ 2 ]-references IS INITIAL AND -tokens[ 2 ]-lexeme = 'BIT'. + quickfixable = abap_false. + ENDIF. WHEN OTHERS. IF if_sysubrc <> 2. code_line_index = analyzer->flatten_tokens( tokens = -tokens ). @@ -439,19 +457,22 @@ CLASS /cc4a/modern_language IMPLEMENTATION. ENDCASE. ELSEIF if_sysubrc <> 0 AND tabix > statement_index + 1. IF -keyword = 'CALL' OR -keyword = '+CALL_METHOD'. - RETURN. + quickfixable = abap_false. + EXIT. ENDIF. CASE if_sysubrc. WHEN 1. token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_TRUE'. - RETURN. + quickfixable = abap_false. + EXIT. ENDIF. WHEN 2. token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_FALSE' OR procedure-statements[ tabix + 1 ]-keyword <> 'ENDIF'. - RETURN. + quickfixable = abap_false. + EXIT. ENDIF. ENDCASE. append_tokens( EXPORTING tokens = -tokens to_idx = token_idx - 1 CHANGING result = code_line_exists ). @@ -467,7 +488,7 @@ CLASS /cc4a/modern_language IMPLEMENTATION. ENDIF. ENDLOOP. - IF code_line_index IS NOT INITIAL OR code_line_exists IS NOT INITIAL. + IF quickfixable = abap_true AND ( code_line_index IS NOT INITIAL OR code_line_exists IS NOT INITIAL ). DATA(quickfixes) = assistant_factory->create_quickfixes( ). DATA(quickfix) = quickfixes->create_quickfix( c_qf_line_exists ). @@ -483,6 +504,14 @@ CLASS /cc4a/modern_language IMPLEMENTATION. pseudo_comment = c_ps_line_exists quickfixes = quickfixes CHANGING findings = findings ). + ELSE. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_line_exists + pseudo_comment = c_ps_line_exists + CHANGING findings = findings ). ENDIF. ENDMETHOD. @@ -541,14 +570,31 @@ CLASS /cc4a/modern_language IMPLEMENTATION. token_idx = and_idx + 1. ENDIF. ENDDO. - + DATA(quickfixable) = abap_true. LOOP AT procedure-statements FROM statement_index + 1 ASSIGNING FIELD-SYMBOL(). + DATA(tabix) = sy-tabix. CASE -keyword. WHEN 'ENDLOOP'. DATA(end_idx) = sy-tabix. EXIT. WHEN 'EXIT'. DATA(contains_exit) = abap_true. + WHEN 'MOVE'. + IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + analyze_move( EXPORTING procedure = procedure statement_index = tabix IMPORTING changed_line = code_line_index ). + REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. + APPEND code_line_index TO code_lines. + ENDIF. + WHEN 'MESSAGE' OR 'PERFORM' OR '+CALL_MACRO'. + IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + quickfixable = abap_false. + EXIT. + ENDIF. + WHEN 'SET'. + IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ) + AND -tokens[ 2 ]-references IS INITIAL AND -tokens[ 2 ]-lexeme = 'BIT'. + quickfixable = abap_false. + ENDIF. WHEN OTHERS. IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). LOOP AT -tokens ASSIGNING . @@ -594,7 +640,7 @@ CLASS /cc4a/modern_language IMPLEMENTATION. procedure = procedure statement_index = statement_index code = c_code_line_exists - pseudo_comment = c_ps_deprecated_key + pseudo_comment = c_ps_line_exists quickfixes = quickfixes CHANGING findings = findings ). @@ -604,6 +650,7 @@ CLASS /cc4a/modern_language IMPLEMENTATION. METHOD analyze_create_object. DATA code_line TYPE string. DATA(statement) = procedure-statements[ statement_index ]. + data(replace_data) = abap_true. IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TYPE' ) <> 0 OR analyzer->find_clause_index( tokens = statement-tokens clause = 'AREA HANDLE' ) <> 0 @@ -617,7 +664,8 @@ CLASS /cc4a/modern_language IMPLEMENTATION. * self reference is working with create object but not with new LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() FROM 4 WHERE lexeme CP |{ object_name }*| AND references IS NOT INITIAL. LOOP AT -references TRANSPORTING NO FIELDS WHERE full_name CP |{ full_name }*|. - RETURN. + replace_data = abap_false. + exit. ENDLOOP. ENDLOOP. * find data statement @@ -630,7 +678,7 @@ CLASS /cc4a/modern_language IMPLEMENTATION. IF type_idx = 0. RETURN. ENDIF. - IF data_idx = statement_index - 1. + IF replace_data = abap_true AND data_idx = statement_index - 1. DATA(type_name) = -tokens[ type_idx + 3 ]-lexeme. code_line = |DATA({ object_name }) = NEW { type_name }( |. DATA(from_idx) = data_idx. @@ -642,6 +690,13 @@ CLASS /cc4a/modern_language IMPLEMENTATION. data_idx -= 1. ENDWHILE. IF code_line IS INITIAL. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = c_code_prefer_new + pseudo_comment = c_ps_prefer_new + CHANGING findings = findings ). RETURN. ENDIF. DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). @@ -871,6 +926,7 @@ CLASS /cc4a/modern_language IMPLEMENTATION. DATA code_line TYPE string. DATA(quickfixes) = assistant_factory->create_quickfixes( ). DATA(quickfix) = quickfixes->create_quickfix( c_qf_text_assembly ). + DATA(quickfixable) = abap_true. TRY. LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE lexeme = '&&'. DATA(tabix) = sy-tabix. @@ -879,7 +935,7 @@ CLASS /cc4a/modern_language IMPLEMENTATION. * store old code_line code_line = |{ code_line }\||. IF strlen( code_line ) >= c_max_line_length - 1. - DATA(no_quickfixes) = abap_true. + quickfixable = abap_false. EXIT. ELSE. quickfix->replace( @@ -901,10 +957,10 @@ CLASS /cc4a/modern_language IMPLEMENTATION. end_idx = tabix + 1. last_idx = tabix + 1. ENDLOOP. - IF no_quickfixes = abap_false AND code_line IS NOT INITIAL. + IF quickfixable = abap_true AND code_line IS NOT INITIAL. code_line = |{ code_line }\||. IF strlen( code_line ) >= c_max_line_length - 1. - no_quickfixes = abap_true. + quickfixable = abap_false. ELSE. quickfix->replace( context = assistant_factory->create_quickfix_context( @@ -915,9 +971,9 @@ CLASS /cc4a/modern_language IMPLEMENTATION. ENDIF. ENDIF. CATCH lcx_error. - no_quickfixes = abap_true. + quickfixable = abap_false. ENDTRY. - IF no_quickfixes = abap_true. + IF quickfixable = abap_false. CLEAR quickfixes. ENDIF. add_finding( From 20d4ea3e3d0e1c00e41bca2b123f9b4d0fad8c8e Mon Sep 17 00:00:00 2001 From: Josia Kempf Date: Mon, 25 Sep 2023 15:02:53 +0200 Subject: [PATCH 3/9] Update #cc4a#modern_language.clas.testclasses.abap --- ...cc4a#modern_language.clas.testclasses.abap | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/checks/#cc4a#modern_language.clas.testclasses.abap b/src/checks/#cc4a#modern_language.clas.testclasses.abap index bf682e1..84cfd2a 100644 --- a/src/checks/#cc4a#modern_language.clas.testclasses.abap +++ b/src/checks/#cc4a#modern_language.clas.testclasses.abap @@ -121,6 +121,10 @@ CLASS test IMPLEMENTATION. code_lines = VALUE #( ( `EXISTS = XSDBOOL( LINE_EXISTS( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ) ).` ) ( `IDX = LINE_INDEX( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ).` ) ) ) ) ) + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 27 column = 4 ) ) + has_pseudo_comment = abap_true ) + ( code = /cc4a/modern_language=>c_code_line_exists location = VALUE #( object = test_read position = VALUE #( line = 34 column = 4 ) ) quickfixes = VALUE #( ( @@ -135,6 +139,10 @@ CLASS test IMPLEMENTATION. span = VALUE #( object = test_read from = 35 to = 35 ) code_lines = VALUE #( ( `idx = sy-tabix.` ) ) ) ) ) + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 37 column = 4 ) ) + has_pseudo_comment = abap_true ) + ( code = /cc4a/modern_language=>c_code_line_exists location = VALUE #( object = test_read position = VALUE #( line = 41 column = 4 ) ) quickfixes = VALUE #( ( @@ -142,6 +150,10 @@ CLASS test IMPLEMENTATION. span = VALUE #( object = test_read from = 41 to = 44 ) code_lines = VALUE #( ( `DATA(BLUE) = xsdbool( NOT line_exists( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLUE' ] ) ).` ) ) ) ) ) + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 46 column = 4 ) ) + has_pseudo_comment = abap_true ) + ( code = /cc4a/modern_language=>c_code_line_exists location = VALUE #( object = test_read position = VALUE #( line = 52 column = 4 ) ) quickfixes = VALUE #( ( @@ -163,6 +175,8 @@ CLASS test IMPLEMENTATION. span = VALUE #( object = test_read from = 62 to = 64 ) code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) + + ( code = /cc4a/modern_language=>c_code_line_exists location = VALUE #( object = test_read position = VALUE #( line = 67 column = 4 ) ) has_pseudo_comment = abap_true @@ -171,6 +185,18 @@ CLASS test IMPLEMENTATION. span = VALUE #( object = test_read from = 67 to = 69 ) code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 73 column = 4 ) ) + has_pseudo_comment = abap_true ) + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 76 column = 4 ) ) + has_pseudo_comment = abap_true ) + + + ( code = /cc4a/modern_language=>c_code_line_exists + location = VALUE #( object = test_read position = VALUE #( line = 81 column = 4 ) ) + has_pseudo_comment = abap_true ) ( code = /cc4a/modern_language=>c_code_line_exists location = VALUE #( object = test_loop position = VALUE #( line = 4 column = 4 ) ) From 788bc079c8e87eba46a1c05793a57b3ed6864b7e Mon Sep 17 00:00:00 2001 From: Josia Kempf Date: Tue, 9 Jan 2024 09:12:10 +0000 Subject: [PATCH 4/9] Migrate check MODER_LANGUAGE II --- src/checks/#cc4a#modern_language.clas.abap | 1158 +---------------- src/checks/#cc4a#modern_language.clas.xml | 131 +- .../#cc4a#test_modern_language.clas.abap | 56 +- 3 files changed, 37 insertions(+), 1308 deletions(-) diff --git a/src/checks/#cc4a#modern_language.clas.abap b/src/checks/#cc4a#modern_language.clas.abap index bd001a9..f8bb911 100644 --- a/src/checks/#cc4a#modern_language.clas.abap +++ b/src/checks/#cc4a#modern_language.clas.abap @@ -1,1157 +1,13 @@ -CLASS /cc4a/modern_language DEFINITION - PUBLIC - FINAL - CREATE PUBLIC . +class /CC4A/MODERN_LANGUAGE definition + public + create private . - PUBLIC SECTION. - - INTERFACES if_ci_atc_check . - CONSTANTS c_code_move TYPE if_ci_atc_check=>ty_finding_code VALUE 'MOVE'. - CONSTANTS c_code_translate TYPE if_ci_atc_check=>ty_finding_code VALUE 'TRANSLATE'. - CONSTANTS c_code_line_exists TYPE if_ci_atc_check=>ty_finding_code VALUE 'LINE_EXIST'. - CONSTANTS c_code_prefer_new TYPE if_ci_atc_check=>ty_finding_code VALUE 'PREFER_NEW'. - CONSTANTS c_code_call_method TYPE if_ci_atc_check=>ty_finding_code VALUE 'CALL_METH'. - CONSTANTS c_code_method_exporting TYPE if_ci_atc_check=>ty_finding_code VALUE 'METH_EXP'. - CONSTANTS c_code_exporting_receiving TYPE if_ci_atc_check=>ty_finding_code VALUE 'EXP_REC'. - CONSTANTS c_code_text_assembly TYPE if_ci_atc_check=>ty_finding_code VALUE 'TEXT_ASM'. - CONSTANTS c_code_qf_synerr TYPE if_ci_atc_check=>ty_finding_code VALUE 'QF_SYNERR'. - CONSTANTS c_code_qf_tsterr TYPE if_ci_atc_check=>ty_finding_code VALUE 'QF_TSTERR'. - CONSTANTS c_qf_move TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_MOVE'. - CONSTANTS c_qf_translate TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_TRANSL'. - CONSTANTS c_qf_line_exists TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_LINEEX'. - CONSTANTS c_qf_prefer_new TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_PREFNEW'. - CONSTANTS c_qf_call_method TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_CALLM'. - CONSTANTS c_qf_method_exporting TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_MEXP'. - CONSTANTS c_qf_exporting_receiving TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_EXP_REC'. - CONSTANTS c_qf_text_assembly TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_TEXTASM'. - CONSTANTS c_ps_deprecated_key TYPE string VALUE 'DEPRECATED_KEY'. - CONSTANTS c_ps_line_exists TYPE string VALUE 'PREF_LINE_EX'. - CONSTANTS c_ps_prefer_new TYPE string VALUE 'PREF_NEW'. - CONSTANTS c_ps_call_method TYPE string VALUE 'CALL_METH_USAGE'. - CONSTANTS c_ps_method_exporting TYPE string VALUE 'OPTL_EXP'. - CONSTANTS c_ps_exporting_receiving TYPE string VALUE 'RECEIVING_USAGE'. - CONSTANTS c_ps_text_assembly TYPE string VALUE 'TEXT_ASSEMBLY'. - CONSTANTS c_max_line_length TYPE i VALUE 255. - PROTECTED SECTION. - PRIVATE SECTION. - DATA code_provider TYPE REF TO if_ci_atc_source_code_provider. - DATA analyzer TYPE REF TO /cc4a/if_abap_analyzer. - DATA assistant_factory TYPE REF TO cl_ci_atc_assistant_factory. - - METHODS analyze_procedure - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_move - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - EXPORTING changed_line TYPE string - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_translate - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_read - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_loop - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_create_object - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_call_method - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_exporting_receiving - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_text_assembly - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS check_quickfixes - IMPORTING quickfixes TYPE REF TO cl_ci_atc_quickfixes - procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - CHANGING findings TYPE if_ci_atc_check=>ty_findings. - METHODS add_finding - IMPORTING quickfixes TYPE REF TO cl_ci_atc_quickfixes OPTIONAL - procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - code TYPE cl_ci_atc_quickfixes=>ty_quickfix_code - pseudo_comment TYPE string - CHANGING findings TYPE if_ci_atc_check=>ty_findings. - METHODS is_used - IMPORTING - procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - from_index TYPE i - full_name TYPE string - RETURNING - VALUE(result) TYPE abap_bool. - - METHODS check_remove_exporting - IMPORTING - statement TYPE if_ci_atc_source_code_provider=>ty_statement - token_idx TYPE i - RETURNING - VALUE(result) TYPE abap_bool. - METHODS get_value - IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token - RETURNING VALUE(result) TYPE string - RAISING lcx_error. - METHODS append_token - IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token - CHANGING result TYPE string. - METHODS append_tokens - IMPORTING tokens TYPE if_ci_atc_source_code_provider=>ty_tokens - VALUE(from_idx) TYPE i OPTIONAL - VALUE(to_idx) TYPE i OPTIONAL - CHANGING result TYPE string. - METHODS get_receiving_infos - IMPORTING - tokens TYPE if_ci_atc_source_code_provider=>ty_tokens - EXPORTING - receiving_idx TYPE i - end_idx TYPE i - result_line TYPE string. +public section. +protected section. +private section. ENDCLASS. -CLASS /cc4a/modern_language IMPLEMENTATION. - - - METHOD check_quickfixes. - DATA(program_name) = cl_ci_atc_data_provider=>main_program_from_comp_unit( procedure-id-main_unit ). - TRY. - DATA(qfix_tester) = NEW cl_ci_quickfix_testing( ). - qfix_tester->set( p_atc_quickfixes = quickfixes ). - IF qfix_tester->check_quickfixes( p_program = program_name ) = abap_false. - INSERT VALUE #( code = c_code_qf_synerr - location = code_provider->get_statement_location( procedure-statements[ statement_index ] ) - checksum = code_provider->get_statement_checksum( procedure-statements[ statement_index ] ) - has_pseudo_comment = abap_false ) INTO TABLE findings. - ENDIF. - CATCH cx_ci_quickfix_testing_error. - INSERT VALUE #( code = c_code_qf_tsterr - location = code_provider->get_statement_location( procedure-statements[ statement_index ] ) - checksum = code_provider->get_statement_checksum( procedure-statements[ statement_index ] ) - has_pseudo_comment = abap_false ) INTO TABLE findings. - ENDTRY. - ENDMETHOD. - - - METHOD if_ci_atc_check~get_meta_data. - meta_data = /cc4a/check_meta_data=>create( - VALUE #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs - description = 'Modern Language'(des) - remote_enablement = /cc4a/check_meta_data=>remote_enablement-unconditional - finding_codes = VALUE #( ( code = c_code_move text = 'MOVE is obsolete'(001) pseudo_comment = c_ps_deprecated_key ) - ( code = c_code_translate text = 'TRANSLATE TO UPPER/LOWERCASE is obsolete'(002) pseudo_comment = c_ps_deprecated_key ) - ( code = c_code_line_exists text = 'Prefer LINE_EXISTS/LINE_INDEX'(003) pseudo_comment = c_ps_line_exists ) - ( code = c_code_prefer_new text = 'Prefer NEW instead of CREATE OBJECT'(004) pseudo_comment = c_ps_prefer_new ) - ( code = c_code_call_method text = 'Prefer functional call instead of CALL METHOD'(005) pseudo_comment = c_ps_call_method ) - ( code = c_code_method_exporting text = 'Omit EXPORTING in functional Method Call if possible'(006) pseudo_comment = c_ps_method_exporting ) - ( code = c_code_exporting_receiving text = 'Do not use RECEIVING in functional Method Call if possible'(007) pseudo_comment = c_ps_exporting_receiving ) - ( code = c_code_text_assembly text = 'Use string templates instead of &&'(008) pseudo_comment = c_ps_text_assembly ) - ( code = c_code_qf_synerr text = 'Quickfix Syntax Error'(q01) ) - ( code = c_code_qf_tsterr text = 'Quickfix Testing Error'(q02) ) ) - quickfix_codes = VALUE #( ( code = c_qf_move short_text = 'Replace MOVE statement'(qf1) ) - ( code = c_qf_translate short_text = 'Replace TRANSLATE statement'(qf2) ) - ( code = c_qf_line_exists short_text = 'Use LINE_EXISTS/LINE_INDEX'(qf3) ) - ( code = c_qf_prefer_new short_text = 'Use NEW instead of CREATE OBJECT'(qf4) ) - ( code = c_qf_call_method short_text = 'Use functional call instead of CALL METHOD'(qf5) ) - ( code = c_qf_method_exporting short_text = 'Omit EXPORTING'(qf6) ) - ( code = c_qf_exporting_receiving short_text = 'Do not use EXPORTING/RECEIVING'(qf7) ) - ( code = c_qf_text_assembly short_text = 'Replace && by string templates'(qf8) ) - ) ) ). - ENDMETHOD. - - - METHOD if_ci_atc_check~run. - code_provider = data_provider->get_code_provider( ). - analyzer = /cc4a/abap_analyzer=>create( ). - DATA(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). - LOOP AT procedures->* ASSIGNING FIELD-SYMBOL(). - INSERT LINES OF analyze_procedure( ) INTO TABLE findings. - ENDLOOP. - ENDMETHOD. - - - METHOD if_ci_atc_check~set_assistant_factory. - assistant_factory = factory. - ENDMETHOD. - - - METHOD if_ci_atc_check~set_attributes ##NEEDED. - ENDMETHOD. - - - METHOD if_ci_atc_check~verify_prerequisites ##NEEDED. - ENDMETHOD. - - - METHOD add_finding. - DATA finding LIKE LINE OF findings. - DATA(statement) = procedure-statements[ statement_index ]. - IF quickfixes IS INITIAL. - finding = VALUE #( code = code - location = code_provider->get_statement_location( statement ) - checksum = code_provider->get_statement_checksum( statement ) - has_pseudo_comment = xsdbool( line_exists( statement-pseudo_comments[ table_line = pseudo_comment ] ) ) - ). - - ELSE. - finding = VALUE #( code = code - location = code_provider->get_statement_location( statement ) - checksum = code_provider->get_statement_checksum( statement ) - has_pseudo_comment = xsdbool( line_exists( statement-pseudo_comments[ table_line = pseudo_comment ] ) ) - details = assistant_factory->create_finding_details( )->attach_quickfixes( quickfixes ) ). - IF code <> c_code_translate. - check_quickfixes( - EXPORTING - quickfixes = quickfixes - procedure = procedure - statement_index = statement_index - CHANGING findings = findings ). - ENDIF. - ENDIF. - INSERT finding INTO TABLE findings. - ENDMETHOD. - - - METHOD analyze_move. - DATA source TYPE string. - DATA dest TYPE string. - DATA between TYPE string. - CLEAR changed_line. - DATA(statement) = procedure-statements[ statement_index ]. - - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'PERCENTAGE' ) <> 0. - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_move - pseudo_comment = c_ps_deprecated_key - CHANGING findings = findings ). - RETURN. - ENDIF. - DATA(from_token) = 2. - IF statement-tokens[ 2 ]-lexeme = 'EXACT' AND statement-tokens[ 2 ]-references IS INITIAL. - DATA(exact) = abap_true. - from_token = 3. - ENDIF. - LOOP AT statement-tokens FROM from_token ASSIGNING FIELD-SYMBOL(). - - IF -references IS INITIAL. - CASE -lexeme. - WHEN 'TO'. - IF exact = abap_true. - between = `= EXACT #(`. - ELSE. - between = `=`. - ENDIF. - CONTINUE. - WHEN '?TO'. - between = `?=`. - CONTINUE. - ENDCASE. - ENDIF. - IF between IS INITIAL. - source = |{ source } { -lexeme }|. - ELSE. - dest = |{ dest } { -lexeme }|. - ENDIF. - ENDLOOP. - DATA(line) = |{ dest } { between } { source }|. - IF exact = abap_true. - line = |{ line } )|. - ENDIF. - line = |{ line }.|. - IF changed_line IS SUPPLIED. - changed_line = line. - RETURN. - ENDIF. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( c_qf_move ). - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = statement_index ) ) ) - code = VALUE #( ( line ) ) ). - - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_move - pseudo_comment = c_ps_deprecated_key - quickfixes = quickfixes - CHANGING findings = findings ). - ENDMETHOD. - - - METHOD analyze_translate. - DATA line TYPE string. - DATA(statement) = procedure-statements[ statement_index ]. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'USING MASK' ) <> 0. - RETURN. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TO UPPER CASE' ) = 3. - line = |{ statement-tokens[ 2 ]-lexeme } = to_upper( { statement-tokens[ 2 ]-lexeme } ).| ##NO_TEXT. - ELSEIF analyzer->find_clause_index( tokens = statement-tokens clause = 'TO LOWER CASE' ) = 3. - line = |{ statement-tokens[ 2 ]-lexeme } = to_lower( { statement-tokens[ 2 ]-lexeme } ).| ##NO_TEXT. - ELSE. - RETURN. - ENDIF. - - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( c_qf_translate ). - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = statement_index ) ) ) - code = VALUE #( ( line ) ) ). - - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_translate - pseudo_comment = c_ps_deprecated_key - quickfixes = quickfixes - CHANGING findings = findings ). - - ENDMETHOD. - - - METHOD analyze_read. - DATA code_line_index TYPE string. - DATA code_line_exists TYPE string. - DATA code_lines TYPE if_ci_atc_quickfix=>ty_code. - DATA key TYPE string. - DATA token_idx TYPE i. - DATA(statement) = procedure-statements[ statement_index ]. - - - IF lines( statement-tokens ) <= 2 OR statement-tokens[ 2 ]-lexeme <> 'TABLE' OR statement-tokens[ 2 ]-references IS NOT INITIAL - OR lines( procedure-statements ) = statement_index - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING NO FIELDS' ) = 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 - OR statement-tokens[ 3 ]-lexeme CP '*('. - RETURN. - ENDIF. - DATA(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WITH KEY' ). - IF key_idx = 0. - RETURN. - ELSE. - - DATA(start_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'COMPONENTS' - start_index = key_idx + 1 ). - IF start_idx = 0. "with key... - start_idx = key_idx + 2. - ELSE. "with key name components ... - start_idx -= 2. - ENDIF. - DATA(keylen) = 0. - DATA(to_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' start_index = start_idx ) - 1. - IF to_idx <= 0. - to_idx = lines( statement-tokens ). - ENDIF. - IF statement-tokens[ key_idx + 2 ]-lexeme = '='. - key = 'TABLE_LINE'. - append_tokens( EXPORTING tokens = statement-tokens from_idx = key_idx + 2 to_idx = to_idx - CHANGING result = key ). - ELSE. - append_tokens( EXPORTING tokens = statement-tokens from_idx = start_idx to_idx = to_idx - CHANGING result = key ). - ENDIF. - keylen = to_idx - start_idx + 1. - - ENDIF. - IF keylen = 1. -* finding without quickfix since obsolete version read table with key val. - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_line_exists - pseudo_comment = c_ps_line_exists - CHANGING findings = findings ). - RETURN. - ENDIF. - DATA(quickfixable) = abap_true. -* if statement-tokens[ key_idx + 2 ]-lexeme = '='. -* quickfixable = abap_false. -* endif. - DATA(table) = statement-tokens[ 3 ]-lexeme. - IF table CP '*[]'. - DATA(len) = strlen( table ) - 2. - table = table(len). - ENDIF. - DATA(idx) = statement_index + 1. - ASSIGN procedure-statements[ idx ] TO FIELD-SYMBOL(). - IF -keyword = 'IF' AND lines( -tokens ) = 4 - AND -tokens[ 2 ]-lexeme = 'SY-SUBRC' - - AND -tokens[ 4 ]-lexeme = '0'. - CASE -tokens[ 3 ]-lexeme. - WHEN '=' OR 'EQ' . - DATA(if_sysubrc) = 1. - WHEN '<>' OR 'NE'. - if_sysubrc = 2. - ENDCASE. - idx += 1. - ENDIF. - DATA(end_idx) = idx. - IF if_sysubrc <> 0. - to_idx = lines( procedure-statements ). - ELSE. - to_idx = idx. - ENDIF. - LOOP AT procedure-statements FROM idx TO to_idx ASSIGNING FIELD-SYMBOL(). - DATA(tabix) = sy-tabix. - IF -keyword = 'ENDIF'. - end_idx = sy-tabix. - EXIT. - ENDIF. - DATA(sytabix_idx) = line_index( -tokens[ lexeme = 'SY-TABIX' ] ). - - IF sytabix_idx <> 0. - IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-lexeme = '&&'. - quickfixable = abap_false. - EXIT. - ENDIF. - IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-references IS INITIAL - AND -tokens[ sytabix_idx - 1 ]-lexeme = 'LIKE' - AND -keyword = 'DATA'. - quickfixable = abap_false. - EXIT. - ENDIF. - CASE -keyword. - WHEN 'MOVE'. - analyze_move( EXPORTING procedure = procedure statement_index = tabix IMPORTING changed_line = code_line_index ). - REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. - APPEND code_line_index TO code_lines. - WHEN 'MESSAGE' OR 'PERFORM' OR '+CALL_MACRO'. - quickfixable = abap_false. - EXIT. - WHEN 'SET'. - IF -tokens[ 2 ]-references IS INITIAL AND -tokens[ 2 ]-lexeme = 'BIT'. - quickfixable = abap_false. - ENDIF. - WHEN OTHERS. - IF if_sysubrc <> 2. - code_line_index = analyzer->flatten_tokens( tokens = -tokens ). - REPLACE FIRST OCCURRENCE OF 'SY-TABIX IS INITIAL' IN code_line_index WITH |line_index( { table }[ { key } ] ) = 0| ##NO_TEXT. - REPLACE FIRST OCCURRENCE OF 'SY-TABIX IS NOT INITIAL' IN code_line_index WITH |line_index( { table }[ { key } ] ) <> 0| ##NO_TEXT. - REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. - code_line_index = |{ code_line_index }.|. - APPEND code_line_index TO code_lines. - ENDIF. - ENDCASE. - ELSEIF if_sysubrc <> 0 AND tabix > statement_index + 1. - IF -keyword = 'CALL' OR -keyword = '+CALL_METHOD'. - quickfixable = abap_false. - EXIT. - ENDIF. - CASE if_sysubrc. - WHEN 1. - token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). - IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_TRUE'. - quickfixable = abap_false. - EXIT. - ENDIF. - WHEN 2. - token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). - IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_FALSE' - OR procedure-statements[ tabix + 1 ]-keyword <> 'ENDIF'. - quickfixable = abap_false. - EXIT. - ENDIF. - ENDCASE. - append_tokens( EXPORTING tokens = -tokens to_idx = token_idx - 1 CHANGING result = code_line_exists ). - IF if_sysubrc = 1. - code_line_exists = |{ code_line_exists } = xsdbool( line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. - ELSE. - code_line_exists = |{ code_line_exists } = xsdbool( NOT line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. - ENDIF. - APPEND code_line_exists TO code_lines. - ENDIF. - IF if_sysubrc = 0. - EXIT. - ENDIF. - ENDLOOP. - - IF quickfixable = abap_true AND ( code_line_index IS NOT INITIAL OR code_line_exists IS NOT INITIAL ). - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( c_qf_line_exists ). - - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = end_idx ) ) ) - code = code_lines ). - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_line_exists - pseudo_comment = c_ps_line_exists - quickfixes = quickfixes - CHANGING findings = findings ). - ELSE. - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_line_exists - pseudo_comment = c_ps_line_exists - CHANGING findings = findings ). - ENDIF. - - ENDMETHOD. - - - METHOD analyze_loop. - DATA code_line_index TYPE string. - DATA code_line_exists TYPE string. - DATA code_lines TYPE if_ci_atc_quickfix=>ty_code. - DATA key TYPE string. - - DATA(statement) = procedure-statements[ statement_index ]. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'OR' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'NOT' ) <> 0. - RETURN. - ENDIF. - DATA(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WHERE' ). - IF key_idx = 0 OR statement-tokens[ key_idx + 1 ]-lexeme CP '(*'. - RETURN. - ENDIF. - DATA(table) = statement-tokens[ 3 ]-lexeme. - IF table CP '*('. - RETURN. - ENDIF. - DATA(result_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ). - IF result_idx <> 0. - ASSIGN statement-tokens[ result_idx + 1 ] TO FIELD-SYMBOL(). - IF is_used( procedure = procedure from_index = statement_index + 1 full_name = -references[ lines( -references ) ]-full_name ). - RETURN. - ENDIF. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = '(' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = ')' ) <> 0. - RETURN. - ENDIF. - DATA(token_idx) = key_idx + 1. - DO. - ASSIGN statement-tokens[ token_idx ] TO . - append_token( EXPORTING token = CHANGING result = key ). - token_idx += 1. - ASSIGN statement-tokens[ token_idx ] TO . - CASE -lexeme. - WHEN '=' OR 'EQ'. - key = |{ key } = |. - WHEN OTHERS. - RETURN. - ENDCASE. - DATA(and_idx) = analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'AND' ). - IF and_idx = 0. - append_tokens( EXPORTING tokens = statement-tokens from_idx = token_idx + 1 CHANGING result = key ). - EXIT. - ELSE. - append_tokens( EXPORTING tokens = statement-tokens from_idx = token_idx + 1 to_idx = and_idx - 1 CHANGING result = key ). - token_idx = and_idx + 1. - ENDIF. - ENDDO. - DATA(quickfixable) = abap_true. - LOOP AT procedure-statements FROM statement_index + 1 ASSIGNING FIELD-SYMBOL(). - DATA(tabix) = sy-tabix. - CASE -keyword. - WHEN 'ENDLOOP'. - DATA(end_idx) = sy-tabix. - EXIT. - WHEN 'EXIT'. - DATA(contains_exit) = abap_true. - WHEN 'MOVE'. - IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). - analyze_move( EXPORTING procedure = procedure statement_index = tabix IMPORTING changed_line = code_line_index ). - REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. - APPEND code_line_index TO code_lines. - ENDIF. - WHEN 'MESSAGE' OR 'PERFORM' OR '+CALL_MACRO'. - IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). - quickfixable = abap_false. - EXIT. - ENDIF. - WHEN 'SET'. - IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ) - AND -tokens[ 2 ]-references IS INITIAL AND -tokens[ 2 ]-lexeme = 'BIT'. - quickfixable = abap_false. - ENDIF. - WHEN OTHERS. - IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). - LOOP AT -tokens ASSIGNING . - IF -lexeme = 'SY-TABIX'. - code_line_index = |{ code_line_index } line_index( { table }[ { key } ] )| ##NO_TEXT. - ELSEIF code_line_index IS INITIAL. - code_line_index = -lexeme. - ELSE. - code_line_index = |{ code_line_index } { -lexeme }|. - ENDIF. - ENDLOOP. - code_line_index = |{ code_line_index }.|. - APPEND code_line_index TO code_lines. - ELSE. - DATA(idx) = analyzer->find_clause_index( tokens = -tokens clause = '=' ). - IF idx = 0 OR -tokens[ idx + 1 ]-lexeme <> 'ABAP_TRUE'. - RETURN. - ENDIF. - LOOP AT -tokens TO idx - 1 ASSIGNING . - IF code_line_exists IS INITIAL. - code_line_exists = -lexeme. - ELSE. - code_line_exists = |{ code_line_exists } { -lexeme }|. - ENDIF. - ENDLOOP. - code_line_exists = |{ code_line_exists } = xsdbool( line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. - APPEND code_line_exists TO code_lines. - ENDIF. - ENDCASE. - ENDLOOP. - IF contains_exit = abap_false. - RETURN. - ENDIF. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( c_qf_line_exists ). - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = end_idx ) ) ) - code = code_lines ). - - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_line_exists - pseudo_comment = c_ps_line_exists - quickfixes = quickfixes - CHANGING findings = findings ). - - ENDMETHOD. - - - METHOD analyze_create_object. - DATA code_line TYPE string. - DATA(statement) = procedure-statements[ statement_index ]. - data(replace_data) = abap_true. - - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TYPE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'AREA HANDLE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 "old exceptions cannot be handled with NEW - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'FOR TESTING' ) <> 0. - RETURN. - ENDIF. - - DATA(object_name) = statement-tokens[ 3 ]-lexeme. - DATA(full_name) = statement-tokens[ 3 ]-references[ lines( statement-tokens[ 3 ]-references ) ]-full_name. -* self reference is working with create object but not with new - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() FROM 4 WHERE lexeme CP |{ object_name }*| AND references IS NOT INITIAL. - LOOP AT -references TRANSPORTING NO FIELDS WHERE full_name CP |{ full_name }*|. - replace_data = abap_false. - exit. - ENDLOOP. - ENDLOOP. -* find data statement - DATA(data_idx) = statement_index - 1. - WHILE data_idx > 0. - IF procedure-statements[ data_idx ]-keyword = 'DATA' - AND procedure-statements[ data_idx ]-tokens[ 2 ]-lexeme = object_name. - ASSIGN procedure-statements[ data_idx ] TO FIELD-SYMBOL(). - DATA(type_idx) = analyzer->find_clause_index( tokens = -tokens clause = 'TYPE REF TO' ). - IF type_idx = 0. - RETURN. - ENDIF. - IF replace_data = abap_true AND data_idx = statement_index - 1. - DATA(type_name) = -tokens[ type_idx + 3 ]-lexeme. - code_line = |DATA({ object_name }) = NEW { type_name }( |. - DATA(from_idx) = data_idx. - ELSE. - code_line = |{ object_name } = NEW #( |. - from_idx = statement_index. - ENDIF. - ENDIF. - data_idx -= 1. - ENDWHILE. - IF code_line IS INITIAL. - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_prefer_new - pseudo_comment = c_ps_prefer_new - CHANGING findings = findings ). - RETURN. - ENDIF. - DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). - -* IF exporting_idx <> 0. -* append_tokens( EXPORTING tokens = statement-tokens from_idx = exporting_idx + 1 CHANGING result = code_line ). -* ENDIF. - -* code_line = |{ code_line } ).|. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( c_qf_prefer_new ). - IF from_idx < statement_index. - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = from_idx to = statement_index - 1 ) ) ) - code = VALUE #( ( `` ) ) ). - ENDIF. - IF exporting_idx = 0. - DATA(to_idx) = 3. - ELSE. - to_idx = exporting_idx. - ENDIF. - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = 1 to = to_idx ) ) ) - code = VALUE #( ( code_line ) ) ). - quickfix->insert_after( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) - code = VALUE #( ( `)` ) ) ). - - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_prefer_new - pseudo_comment = c_ps_prefer_new - quickfixes = quickfixes - CHANGING findings = findings ). - ENDMETHOD. - - - METHOD analyze_call_method. - DATA code_line TYPE string. - DATA(statement) = procedure-statements[ statement_index ]. - IF statement-tokens[ 3 ]-references IS INITIAL AND statement-tokens[ 3 ]-lexeme = 'OF'. "ole - RETURN. - ENDIF. - DATA(method_name) = statement-tokens[ 3 ]-lexeme. - IF method_name(1) = '(' OR method_name CP '*->(*' OR method_name CP '*=>(*' OR method_name CP '(*)' - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'PARAMETER-TABLE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTION-TABLE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0. -* dynamic call / exceptions - RETURN. - ENDIF. - - IF method_name NP '*('. - DATA(method_line) = |{ method_name }(|. - ELSE. - method_line = method_name. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) = 0 - AND analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) = 0 . - DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). - get_receiving_infos( EXPORTING tokens = statement-tokens - IMPORTING receiving_idx = DATA(receiving_idx) - end_idx = DATA(to_idx) - result_line = DATA(result_line) ). - ENDIF. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( c_qf_call_method ). - IF lines( statement-tokens ) = 3 - OR lines( statement-tokens ) = 4. - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) ) ) - code = VALUE #( ( |{ method_line } ).| ) ) ). - ELSE. - IF exporting_idx <> 0. - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = exporting_idx to = exporting_idx ) ) ) - code = VALUE #( ( `` ) ) ). - ENDIF. - IF result_line IS NOT INITIAL. - IF to_idx = lines( statement-tokens ). - code_line = ')'. - ELSE. - code_line = ''. - ENDIF. - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = receiving_idx to = to_idx ) ) ) - code = VALUE #( ( code_line ) ) ). - method_line = |{ result_line } = { method_line }|. - ENDIF. - - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = 1 to = 3 ) ) ) - code = VALUE #( ( method_line ) ) ). - - IF to_idx <> lines( statement-tokens ) AND method_name NP '*('. - quickfix->insert_after( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) - code = VALUE #( ( `)` ) ) ). - ENDIF. - ENDIF. - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_call_method - pseudo_comment = c_ps_call_method - quickfixes = quickfixes - CHANGING findings = findings ). - ENDMETHOD. - - - METHOD analyze_exporting_receiving. - DATA exporting_idxs TYPE SORTED TABLE OF i WITH UNIQUE KEY table_line. - DATA(statement) = procedure-statements[ statement_index ]. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. - RETURN. - ENDIF. - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE references IS INITIAL AND lexeme = 'EXPORTING'. - DATA(token_idx) = sy-tabix. - IF check_remove_exporting( statement = statement token_idx = token_idx ) = abap_true. - INSERT token_idx INTO TABLE exporting_idxs. - ENDIF. - ENDLOOP. - - get_receiving_infos( EXPORTING tokens = statement-tokens - IMPORTING receiving_idx = DATA(receiving_idx) - end_idx = DATA(end_idx) - result_line = DATA(result_line) ). - - IF result_line IS INITIAL AND exporting_idxs IS INITIAL. - RETURN. - ENDIF. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - IF result_line IS NOT INITIAL. - DATA(finding_code) = c_code_exporting_receiving. - DATA(ps) = c_ps_exporting_receiving. - DATA(quickfix) = quickfixes->create_quickfix( c_qf_exporting_receiving ). - result_line = |{ result_line } = { statement-tokens[ 1 ]-lexeme }|. - quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = 1 to = 1 ) ) ) - code = VALUE #( ( result_line ) ) ). - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = receiving_idx to = end_idx ) ) ) - code = VALUE #( ( `` ) ) ). - ELSE. - finding_code = c_code_method_exporting. - ps = c_ps_method_exporting. - quickfix = quickfixes->create_quickfix( c_qf_method_exporting ). - ENDIF. - LOOP AT exporting_idxs INTO DATA(exporting_idx). - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = exporting_idx to = exporting_idx + 1 ) ) ) - code = VALUE #( ( statement-tokens[ exporting_idx + 1 ]-lexeme ) ) ). - ENDLOOP. - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = finding_code - pseudo_comment = ps - quickfixes = quickfixes - CHANGING findings = findings ). - ENDMETHOD. - - - METHOD analyze_text_assembly. - - DATA(statement) = procedure-statements[ statement_index ]. - -* if statement-keyword = 'CONCATENATE' -* and analyzer->find_clause_index( tokens = statement-tokens clause = 'IN BYTE MODE' ) = 0 -* AND analyzer->find_clause_index( tokens = statement-tokens clause = 'LINES OF' ) = 0. -* data(into_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ). -* data(result_line) = statement-tokens[ into_idx + 1 ]-lexeme. -* loop at statement-tokens ASSIGNING FIELD-SYMBOL() from into_idx + 2. -* if -references is initial. -* case -lexeme. -* when 'IN'. -* exit. -* when 'SEPARATED'. -* data(sep_by) = statement-tokens[ sy-tabix + 2 ]-lexeme. -* exit. -* when 'RESPECTING'. -* exit. -* endcase. -* endif. -* result_line = |{ result_line } { -lexeme }|. -* endloop. -* result_line = |{ result_line } = |. -* endif. - DATA start_idx TYPE i. - DATA end_idx TYPE i. - DATA last_idx TYPE i. - DATA code_line TYPE string. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( c_qf_text_assembly ). - DATA(quickfixable) = abap_true. - TRY. - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE lexeme = '&&'. - DATA(tabix) = sy-tabix. - IF tabix - 1 <> last_idx. - IF code_line IS NOT INITIAL. -* store old code_line - code_line = |{ code_line }\||. - IF strlen( code_line ) >= c_max_line_length - 1. - quickfixable = abap_false. - EXIT. - ELSE. - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = start_idx to = end_idx ) ) ) - code = VALUE #( ( code_line ) ) ). - ENDIF. - ENDIF. -* new && connection - code_line = '|'. - start_idx = tabix - 1. - DATA(value) = get_value( statement-tokens[ tabix - 1 ] ). - code_line = |{ code_line }{ value }|. - ENDIF. - value = get_value( statement-tokens[ tabix + 1 ] ). - code_line = |{ code_line }{ value }|. - end_idx = tabix + 1. - last_idx = tabix + 1. - ENDLOOP. - IF quickfixable = abap_true AND code_line IS NOT INITIAL. - code_line = |{ code_line }\||. - IF strlen( code_line ) >= c_max_line_length - 1. - quickfixable = abap_false. - ELSE. - quickfix->replace( - context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = start_idx to = end_idx ) ) ) - code = VALUE #( ( code_line ) ) ). - ENDIF. - ENDIF. - CATCH lcx_error. - quickfixable = abap_false. - ENDTRY. - IF quickfixable = abap_false. - CLEAR quickfixes. - ENDIF. - add_finding( - EXPORTING - procedure = procedure - statement_index = statement_index - code = c_code_text_assembly - pseudo_comment = c_ps_text_assembly - quickfixes = quickfixes - CHANGING findings = findings ). - - ENDMETHOD. - - - METHOD analyze_procedure. - "DATA(program_name) = cl_ci_atc_data_provider=>main_program_from_comp_unit( procedure-id-main_unit ). - - LOOP AT procedure-statements ASSIGNING FIELD-SYMBOL(). - DATA(idx) = sy-tabix. - CASE -keyword. - WHEN 'MOVE'. - INSERT LINES OF analyze_move( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'TRANSLATE'. - INSERT LINES OF analyze_translate( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'READ'. - INSERT LINES OF analyze_read( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'LOOP'. - INSERT LINES OF analyze_loop( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'CREATE'. - IF -tokens[ 2 ]-lexeme = 'OBJECT' AND -tokens[ 2 ]-references IS INITIAL. - INSERT LINES OF analyze_create_object( procedure = procedure statement_index = idx ) INTO TABLE findings. - ENDIF. - WHEN 'CALL'. - IF -tokens[ 2 ]-lexeme = 'METHOD' AND -tokens[ 2 ]-references IS INITIAL. - INSERT LINES OF analyze_call_method( procedure = procedure statement_index = idx ) INTO TABLE findings. - ENDIF. -* WHEN 'CONCATENATE'. -* INSERT LINES OF analyze_text_assembly( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'METHODS' OR 'CLASS-METHODS'. - CONTINUE. - ENDCASE. -* functional method call may occur in many statements - IF -keyword <> 'CALL' AND -keyword <> 'CREATE' - AND analyzer->find_clause_index( tokens = -tokens clause = 'EXPORTING' ) <> 0. - INSERT LINES OF analyze_exporting_receiving( procedure = procedure statement_index = idx ) INTO TABLE findings. - ENDIF. -* text assembly - IF analyzer->find_clause_index( tokens = -tokens clause = '&&' ) <> 0 - AND -keyword <> 'CONCATENATE' - AND -keyword <> 'SPLIT' - AND analyzer->is_db_statement( statement = ) IS INITIAL. - INSERT LINES OF analyze_text_assembly( procedure = procedure statement_index = idx ) INTO TABLE findings. - ENDIF. - ENDLOOP. - ENDMETHOD. - - - METHOD is_used. - result = abap_false. - LOOP AT procedure-statements FROM from_index ASSIGNING FIELD-SYMBOL(). - LOOP AT -tokens ASSIGNING FIELD-SYMBOL() - WHERE references IS NOT INITIAL. - result = xsdbool( line_exists( -references[ full_name = full_name ] ) ). - IF result = abap_true. - RETURN. - ENDIF. - ENDLOOP. - ENDLOOP. - ENDMETHOD. - - - METHOD check_remove_exporting. - result = abap_false. - ASSIGN statement-tokens[ token_idx - 1 ] TO FIELD-SYMBOL(). - IF NOT -lexeme CP '*('. - RETURN. - ENDIF. - LOOP AT -references ASSIGNING FIELD-SYMBOL() - WHERE kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-method - AND usage_grade <> if_ci_atc_source_code_provider=>usage_grades-definition. - DATA(is_method_call) = abap_true. - EXIT. - ENDLOOP. - IF is_method_call = abap_false. - RETURN. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. - RETURN. - ENDIF. - result = abap_true. - ENDMETHOD. - - - METHOD get_value. - IF token-lexeme CP '*(' - OR token-lexeme CP '*[' - OR token-lexeme(1) = ']' - OR token-lexeme(1) = ')'. - RAISE EXCEPTION TYPE lcx_error. - ENDIF. - IF token-references IS INITIAL. - CASE token-lexeme. - WHEN ')' OR '|'. - RAISE EXCEPTION TYPE lcx_error. - WHEN OTHERS. - IF token-lexeme CP '`*`' OR token-lexeme CP `'*'`. - DATA(len) = strlen( token-lexeme ) - 2. - result = token-lexeme+1(len). - IF result CA '|'. - RAISE EXCEPTION TYPE lcx_error. - ENDIF. - result = replace( val = result sub = '\' with = '\\' occ = 0 ). - result = replace( val = result sub = '{' with = '\{' occ = 0 ). - result = replace( val = result sub = '}' with = '\}' occ = 0 ). - ELSE. - RAISE EXCEPTION TYPE lcx_error. - ENDIF. - ENDCASE. - ELSE. - result = |\{ { token-lexeme } \}|. - ENDIF. - ENDMETHOD. - - - METHOD append_token. - IF result IS INITIAL. - result = token-lexeme. - ELSE. - result = |{ result } { token-lexeme }|. - ENDIF. - ENDMETHOD. - - - METHOD append_tokens. - DATA itab LIKE tokens. - IF from_idx IS SUPPLIED OR to_idx IS SUPPLIED. - IF from_idx = 0. - from_idx = 1. - ENDIF. - IF to_idx = 0. - to_idx = lines( tokens ). - ENDIF. - LOOP AT tokens FROM from_idx TO to_idx ASSIGNING FIELD-SYMBOL(). - APPEND TO itab. - ENDLOOP. - DATA(flattened) = analyzer->flatten_tokens( tokens = itab ). - ELSE. - flattened = analyzer->flatten_tokens( tokens = tokens ). - ENDIF. - IF result IS INITIAL. - result = flattened. - ELSE. - result = |{ result } { flattened }|. - ENDIF. - ENDMETHOD. - - - METHOD get_receiving_infos. - CLEAR end_idx. - CLEAR result_line. - receiving_idx = analyzer->find_clause_index( tokens = tokens clause = 'RECEIVING ' ). - IF receiving_idx = 0. - RETURN. - ENDIF. - DATA(copy_idx) = analyzer->find_clause_index( tokens = tokens start_index = receiving_idx + 1 clause = '=' ). - IF copy_idx <> 0. - end_idx = lines( tokens ). - LOOP AT tokens FROM copy_idx + 1 ASSIGNING FIELD-SYMBOL() - WHERE references IS INITIAL. - CASE -lexeme. - WHEN ')' OR 'EXPORTING'. - end_idx = sy-tabix - 1. - EXIT. - ENDCASE. - ENDLOOP. - append_tokens( EXPORTING tokens = tokens from_idx = copy_idx + 1 to_idx = end_idx CHANGING result = result_line ). - ENDIF. - - ENDMETHOD. +CLASS /CC4A/MODERN_LANGUAGE IMPLEMENTATION. ENDCLASS. diff --git a/src/checks/#cc4a#modern_language.clas.xml b/src/checks/#cc4a#modern_language.clas.xml index 7f368ce..4a1b746 100644 --- a/src/checks/#cc4a#modern_language.clas.xml +++ b/src/checks/#cc4a#modern_language.clas.xml @@ -1,133 +1,4 @@  - - - - /CC4A/MODERN_LANGUAGE - E - check for modern language - 1 - X - X - X - X - - - - I - 001 - MOVE is obsolete - 26 - - - I - 002 - TRANSLATE TO UPPER/LOWERCASE is obsolete - 80 - - - I - 003 - Prefer LINE_EXISTS/LINE_INDEX - 50 - - - I - 004 - Prefer NEW instead of CREATE OBJECT - 70 - - - I - 005 - Prefer functional call instead of CALL METHOD - 90 - - - I - 006 - Omit EXPORTING in functional Method Call if possible - 104 - - - I - 007 - Do not use RECEIVING in functional Method Call if possible - 116 - - - I - 008 - Use string templates instead of && - 68 - - - I - DES - Modern Language - 25 - - - I - Q01 - Quickfix Syntax Error - 42 - - - I - Q02 - Quickfix Testing Error - 44 - - - I - QF1 - Replace MOVE statement - 44 - - - I - QF2 - Replace TRANSLATE statement - 54 - - - I - QF3 - Use LINE_EXISTS/LINE_INDEX - 52 - - - I - QF4 - Use NEW instead of CREATE OBJECT - 64 - - - I - QF5 - Use functional call instead of CALL METHOD - 84 - - - I - QF6 - Omit EXPORTING - 24 - - - I - QF7 - Do not use EXPORTING/RECEIVING - 60 - - - I - QF8 - Replace && by string templates - 60 - - - - + diff --git a/src/test_objects/#cc4a#test_modern_language.clas.abap b/src/test_objects/#cc4a#test_modern_language.clas.abap index c0aea80..9c675a0 100644 --- a/src/test_objects/#cc4a#test_modern_language.clas.abap +++ b/src/test_objects/#cc4a#test_modern_language.clas.abap @@ -29,22 +29,22 @@ CLASS /cc4a/test_modern_language IMPLEMENTATION. DATA num TYPE number ##NEEDED. - MOVE EXACT 1 TO num. - - DATA n TYPE i ##NEEDED ##FLD_TYPE_NAME. - - MOVE 5 TO n. - - MOVE EXACT 5 TO n. - - DATA a TYPE REF TO i ##NEEDED. - DATA b TYPE REF TO i ##NEEDED. - - MOVE a ?TO b. - - MOVE a TO b ##DUPLICATE_OK. - - MOVE a TO b. "#EC DEPRECATED_KEY +* MOVE EXACT 1 TO num. +* +* DATA n TYPE i ##NEEDED ##FLD_TYPE_NAME. +* +* MOVE 5 TO n. +* +* MOVE EXACT 5 TO n. +* +* DATA a TYPE REF TO i ##NEEDED. +* DATA b TYPE REF TO i ##NEEDED. +* +* MOVE a ?TO b. +* +* MOVE a TO b ##DUPLICATE_OK. +* +* MOVE a TO b. "#EC DEPRECATED_KEY ENDMETHOD. @@ -86,11 +86,11 @@ CLASS /cc4a/test_modern_language IMPLEMENTATION. IF sy-subrc EQ 0. exists = abap_true. idx = sy-tabix. - WRITE 'hallo' ##NO_TEXT. + data(bla) = 'hallo' ##NO_TEXT. ENDIF. READ TABLE itab WITH KEY pgmid = 'R3TR' TRANSPORTING NO FIELDS. - MOVE sy-tabix TO idx. + idx = sy-tabix. READ TABLE itab WITH KEY pgmid = 'R3TR' TRANSPORTING NO FIELDS. IF sy-subrc <> 0 OR exists = abap_true ##NEEDED. @@ -130,10 +130,10 @@ CLASS /cc4a/test_modern_language IMPLEMENTATION. DATA itab_string TYPE TABLE OF string. READ TABLE itab_string TRANSPORTING NO FIELDS WITH KEY table_line = 'blabla' ##NO_TEXT. - WRITE 'Difference in contructor code/line' && sy-tabix ##NO_TEXT. + bla = 'Difference in contructor code/line' && sy-tabix ##NO_TEXT. READ TABLE itab_string TRANSPORTING NO FIELDS WITH KEY table_line = 'blub' ##NO_TEXT. - MESSAGE i011(sci) INTO DATA(lv_dummy) WITH sy-tabix ##NEEDED. +* MESSAGE i011(sci) INTO DATA(lv_dummy) WITH sy-tabix ##NEEDED. DATA(test) = NEW lcl_test4( ). READ TABLE itab WITH KEY pgmid = 'BLUB' TRANSPORTING NO FIELDS. @@ -161,7 +161,7 @@ CLASS /cc4a/test_modern_language IMPLEMENTATION. exists = abap_true. EXIT. ENDLOOP. - WRITE l_entry-pgmid. +* WRITE l_entry-pgmid. LOOP AT itab INTO l_entry WHERE obj_name = 'BLA' ##INTO_OK. exists = abap_true. @@ -356,11 +356,11 @@ CLASS /cc4a/test_modern_language IMPLEMENTATION. text1 = 'ab' && text1 && abap_true. text1 = class_ref->test5( param1 = 'a' param2 = 'b' ) && 'end'. - WRITE class_ref->test5( param1 = 'a' && 'b' param2 = 'c' && 'd' ). + data(bla) = class_ref->test5( param1 = 'a' && 'b' param2 = 'c' && 'd' ). - WRITE class_ref->test5( param1 = 'a' && 'b' param2 = 'xxx' ). + bla = class_ref->test5( param1 = 'a' && 'b' param2 = 'xxx' ). - WRITE class_ref->test6( 'a' && 'b' ) && 'end'. + bla = class_ref->test6( 'a' && 'b' ) && 'end'. text1 = text1 && ' }' ##no_text. @@ -370,12 +370,14 @@ CLASS /cc4a/test_modern_language IMPLEMENTATION. ']'. DATA itab TYPE STANDARD TABLE OF /cc4a/db_test1. - WRITE itab[ 1 ]-object && 'a'. - WRITE 'a' && itab[ 1 ]-obj_name. + bla = itab[ 1 ]-object && 'a'. + bla = 'a' && itab[ 1 ]-obj_name. text1 = text1 && COND #( WHEN itab IS INITIAL THEN 'a' ELSE 'b' ). text1 = `\` && text1 && `-`. - WRITE 'a' && 'b'. "#EC TEXT_ASSEMBLY + bla = 'a' && 'b'. "#EC TEXT_ASSEMBLY + + text1 = 'abc' && new lcl_test( param1 = 4 param2 = 5 )->test5( param1 = 'bla' param2 = 'blub' ). ENDMETHOD. ENDCLASS. From 3b4d21c849557c26a1675109cf0a6ac7611b3586 Mon Sep 17 00:00:00 2001 From: Josia Kempf Date: Mon, 15 Jan 2024 09:49:27 +0100 Subject: [PATCH 5/9] Update #cc4a#modern_language.clas.xml --- src/checks/#cc4a#modern_language.clas.xml | 119 +++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/src/checks/#cc4a#modern_language.clas.xml b/src/checks/#cc4a#modern_language.clas.xml index 4a1b746..6c178e9 100644 --- a/src/checks/#cc4a#modern_language.clas.xml +++ b/src/checks/#cc4a#modern_language.clas.xml @@ -1,4 +1,121 @@  - + + + + /CC4A/MODERN_LANGUAGE + E + check for modern language + 1 + X + X + X + X + + + + I + 001 + MOVE is obsolete + 26 + + + I + 002 + TRANSLATE TO UPPER/LOWERCASE is obsolete + 80 + + + I + 003 + Prefer LINE_EXISTS/LINE_INDEX + 50 + + + I + 004 + Prefer NEW instead of CREATE OBJECT + 70 + + + I + 005 + Prefer functional call instead of CALL METHOD + 90 + + + I + 006 + Omit EXPORTING in functional Method Call if possible + 104 + + + I + 007 + Do not use RECEIVING in functional Method Call if possible + 116 + + + I + 008 + Use string templates instead of && + 68 + + + I + DES + Modern Language + 25 + + + I + QF1 + Replace MOVE statement + 44 + + + I + QF2 + Replace TRANSLATE statement + 54 + + + I + QF3 + Use LINE_EXISTS/LINE_INDEX + 52 + + + I + QF4 + Use NEW instead of CREATE OBJECT + 64 + + + I + QF5 + Use functional call instead of CALL METHOD + 84 + + + I + QF6 + Omit EXPORTING + 24 + + + I + QF7 + Do not use EXPORTING/RECEIVING + 60 + + + I + QF8 + Replace && by string templates + 60 + + + + From 9b99b04c68a7e44ae1b634aa84295bb334649b9f Mon Sep 17 00:00:00 2001 From: Josia Kempf Date: Fri, 19 Jan 2024 08:36:07 +0000 Subject: [PATCH 6/9] Migrate check MODER_LANGUAGE III --- src/checks/#cc4a#modern_language.clas.abap | 1089 ++++++++++++++++- ...cc4a#modern_language.clas.testclasses.abap | 299 ++--- src/core/#cc4a#abap_analyzer.clas.abap | 577 +++++---- .../#cc4a#abap_analyzer.clas.locals_imp.abap | 718 +++++------ .../#cc4a#abap_analyzer.clas.testclasses.abap | 479 ++++---- .../#cc4a#cx_line_break_impossible.clas.abap | 23 + .../#cc4a#cx_line_break_impossible.clas.xml | 17 + src/core/#cc4a#if_abap_analyzer.intf.abap | 187 ++- 8 files changed, 2289 insertions(+), 1100 deletions(-) create mode 100644 src/core/#cc4a#cx_line_break_impossible.clas.abap create mode 100644 src/core/#cc4a#cx_line_break_impossible.clas.xml diff --git a/src/checks/#cc4a#modern_language.clas.abap b/src/checks/#cc4a#modern_language.clas.abap index f8bb911..fa6f810 100644 --- a/src/checks/#cc4a#modern_language.clas.abap +++ b/src/checks/#cc4a#modern_language.clas.abap @@ -1,13 +1,1088 @@ -class /CC4A/MODERN_LANGUAGE definition - public - create private . +CLASS /cc4a/modern_language DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . -public section. -protected section. -private section. + PUBLIC SECTION. + + INTERFACES if_ci_atc_check . + + PROTECTED SECTION. + PRIVATE SECTION. + CONSTANTS: + BEGIN OF message_codes, + move TYPE if_ci_atc_check=>ty_finding_code VALUE 'MOVE', + translate TYPE if_ci_atc_check=>ty_finding_code VALUE 'TRANSLATE', + line_exists TYPE if_ci_atc_check=>ty_finding_code VALUE 'LINE_EXIST', + prefer_new TYPE if_ci_atc_check=>ty_finding_code VALUE 'PREFER_NEW', + call_method TYPE if_ci_atc_check=>ty_finding_code VALUE 'CALL_METH', + method_exporting TYPE if_ci_atc_check=>ty_finding_code VALUE 'METH_EXP', + exporting_receiving TYPE if_ci_atc_check=>ty_finding_code VALUE 'EXP_REC', + text_assembly TYPE if_ci_atc_check=>ty_finding_code VALUE 'TEXT_ASM', + END OF message_codes. + CONSTANTS: + BEGIN OF quickfix_codes, + move TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_MOVE', + translate TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_TRANSL', + line_exists TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_LINEEX', + prefer_new TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_PREFNEW', + call_method TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_CALLM', + method_exporting TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_MEXP', + exporting_receiving TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_EXP_REC', + text_assembly TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_TEXTASM', + END OF quickfix_codes. + CONSTANTS: + BEGIN OF pseudo_comments, + deprecated_key TYPE string VALUE 'DEPRECATED_KEY', + line_exists TYPE string VALUE 'PREF_LINE_EX', + prefer_new TYPE string VALUE 'PREF_NEW', + call_method TYPE string VALUE 'CALL_METH_USAGE', + method_exporting TYPE string VALUE 'OPTL_EXP', + exporting_receiving TYPE string VALUE 'RECEIVING_USAGE', + text_assembly TYPE string VALUE 'TEXT_ASSEMBLY', + END OF pseudo_comments. + + TYPES: BEGIN OF t_receiving_infos, + receiving_idx TYPE i, + end_idx TYPE i, + result_line TYPE string, + END OF t_receiving_infos. + DATA code_provider TYPE REF TO if_ci_atc_source_code_provider. + DATA analyzer TYPE REF TO /cc4a/if_abap_analyzer. + DATA assistant_factory TYPE REF TO cl_ci_atc_assistant_factory. + + METHODS analyze_procedure + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_move + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_translate + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_read + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_loop + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_create_object + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_call_method + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_exporting_receiving + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS analyze_text_assembly + IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. + METHODS add_finding + IMPORTING quickfixes TYPE REF TO cl_ci_atc_quickfixes OPTIONAL + procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + statement_index TYPE i + code TYPE cl_ci_atc_quickfixes=>ty_quickfix_code + pseudo_comment TYPE string + CHANGING findings TYPE if_ci_atc_check=>ty_findings. + METHODS is_used + IMPORTING + procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + from_index TYPE i + full_name TYPE string + RETURNING + VALUE(result) TYPE abap_bool. + + METHODS check_remove_exporting + IMPORTING + statement TYPE if_ci_atc_source_code_provider=>ty_statement + token_idx TYPE i + RETURNING + VALUE(result) TYPE abap_bool. + METHODS get_value + IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token + RETURNING VALUE(result) TYPE string + RAISING lcx_error. + METHODS append_token + IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token + CHANGING result TYPE string. + METHODS append_tokens + IMPORTING tokens TYPE if_ci_atc_source_code_provider=>ty_tokens + VALUE(from_idx) TYPE i OPTIONAL + VALUE(to_idx) TYPE i OPTIONAL + CHANGING result TYPE string. + METHODS get_receiving_infos + IMPORTING + tokens TYPE if_ci_atc_source_code_provider=>ty_tokens + RETURNING VALUE(result) TYPE t_receiving_infos. + METHODS get_move_changed_line + IMPORTING statement TYPE if_ci_atc_source_code_provider=>ty_statement + RETURNING VALUE(result) TYPE string. ENDCLASS. -CLASS /CC4A/MODERN_LANGUAGE IMPLEMENTATION. +CLASS /cc4a/modern_language IMPLEMENTATION. + + + + + + METHOD if_ci_atc_check~get_meta_data. + meta_data = /cc4a/check_meta_data=>create( + VALUE #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs + description = 'Modern Language'(des) + remote_enablement = /cc4a/check_meta_data=>remote_enablement-unconditional + finding_codes = VALUE #( ( code = message_codes-move text = 'MOVE is obsolete'(001) pseudo_comment = pseudo_comments-deprecated_key ) + ( code = message_codes-translate text = 'TRANSLATE TO UPPER/LOWERCASE is obsolete'(002) pseudo_comment = pseudo_comments-deprecated_key ) + ( code = message_codes-line_exists text = 'Prefer LINE_EXISTS/LINE_INDEX'(003) pseudo_comment = pseudo_comments-line_exists ) + ( code = message_codes-prefer_new text = 'Prefer NEW instead of CREATE OBJECT'(004) pseudo_comment = pseudo_comments-prefer_new ) + ( code = message_codes-call_method text = 'Prefer functional call instead of CALL METHOD'(005) pseudo_comment = pseudo_comments-call_method ) + ( code = message_codes-method_exporting text = 'Omit EXPORTING in functional Method Call if possible'(006) pseudo_comment = pseudo_comments-method_exporting ) + ( code = message_codes-exporting_receiving text = 'Do not use RECEIVING in functional Method Call if possible'(007) pseudo_comment = pseudo_comments-exporting_receiving ) + ( code = message_codes-text_assembly text = 'Use string templates instead of &&'(008) pseudo_comment = pseudo_comments-text_assembly ) ) + quickfix_codes = VALUE #( ( code = quickfix_codes-move short_text = 'Replace MOVE statement'(qf1) ) + ( code = quickfix_codes-translate short_text = 'Replace TRANSLATE statement'(qf2) ) + ( code = quickfix_codes-line_exists short_text = 'Use LINE_EXISTS/LINE_INDEX'(qf3) ) + ( code = quickfix_codes-prefer_new short_text = 'Use NEW instead of CREATE OBJECT'(qf4) ) + ( code = quickfix_codes-call_method short_text = 'Use functional call instead of CALL METHOD'(qf5) ) + ( code = quickfix_codes-method_exporting short_text = 'Omit EXPORTING'(qf6) ) + ( code = quickfix_codes-exporting_receiving short_text = 'Do not use EXPORTING/RECEIVING'(qf7) ) + ( code = quickfix_codes-text_assembly short_text = 'Replace && by string templates'(qf8) ) + ) ) ). + ENDMETHOD. + + + METHOD if_ci_atc_check~run. + code_provider = data_provider->get_code_provider( ). + analyzer = /cc4a/abap_analyzer=>create( ). + DATA(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). + LOOP AT procedures->* ASSIGNING FIELD-SYMBOL(). + INSERT LINES OF analyze_procedure( ) INTO TABLE findings. + ENDLOOP. + ENDMETHOD. + + + METHOD if_ci_atc_check~set_assistant_factory. + assistant_factory = factory. + ENDMETHOD. + + + METHOD if_ci_atc_check~set_attributes ##NEEDED. + ENDMETHOD. + + + METHOD if_ci_atc_check~verify_prerequisites ##NEEDED. + ENDMETHOD. + + + METHOD add_finding. + DATA finding LIKE LINE OF findings. + DATA(statement) = procedure-statements[ statement_index ]. + IF quickfixes IS INITIAL. + finding = VALUE #( code = code + location = code_provider->get_statement_location( statement ) + checksum = code_provider->get_statement_checksum( statement ) + has_pseudo_comment = xsdbool( line_exists( statement-pseudo_comments[ table_line = pseudo_comment ] ) ) + ). + + ELSE. + finding = VALUE #( code = code + location = code_provider->get_statement_location( statement ) + checksum = code_provider->get_statement_checksum( statement ) + has_pseudo_comment = xsdbool( line_exists( statement-pseudo_comments[ table_line = pseudo_comment ] ) ) + details = assistant_factory->create_finding_details( )->attach_quickfixes( quickfixes ) ). + ENDIF. + INSERT finding INTO TABLE findings. + ENDMETHOD. + + METHOD get_move_changed_line. + DATA source TYPE string. + DATA dest TYPE string. + DATA between TYPE string. + + DATA(from_token) = 2. + IF statement-tokens[ 2 ]-lexeme = 'EXACT' AND statement-tokens[ 2 ]-references IS INITIAL. + DATA(exact) = abap_true. + from_token = 3. + ENDIF. + LOOP AT statement-tokens FROM from_token ASSIGNING FIELD-SYMBOL(). + + IF -references IS INITIAL. + CASE -lexeme. + WHEN 'TO'. + IF exact = abap_true. + between = `= EXACT #(`. + ELSE. + between = `=`. + ENDIF. + CONTINUE. + WHEN '?TO'. + between = `?=`. + CONTINUE. + ENDCASE. + ENDIF. + IF between IS INITIAL. + source = |{ source } { -lexeme }|. + ELSE. + dest = |{ dest } { -lexeme }|. + ENDIF. + ENDLOOP. + result = |{ dest } { between } { source }|. + IF exact = abap_true. + result = |{ result } )|. + ENDIF. + result = |{ result }.|. + ENDMETHOD. + + METHOD analyze_move. + DATA(statement) = procedure-statements[ statement_index ]. + + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'PERCENTAGE' ) <> 0. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-move + pseudo_comment = pseudo_comments-deprecated_key + CHANGING findings = findings ). + ELSE. + DATA(line) = get_move_changed_line( statement ). + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-move ). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = statement_index ) ) ) + code = VALUE #( ( line ) ) ). + + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-move + pseudo_comment = pseudo_comments-deprecated_key + quickfixes = quickfixes + CHANGING findings = findings ). + ENDIF. + ENDMETHOD. + + + METHOD analyze_translate. + DATA(statement) = procedure-statements[ statement_index ]. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'USING MASK' ) <> 0. + RETURN. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TO UPPER CASE' ) = 3 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'TO LOWER CASE' ) = 3. + + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-translate + pseudo_comment = pseudo_comments-deprecated_key + CHANGING findings = findings ). + ENDIF. + ENDMETHOD. + + + METHOD analyze_read. + DATA code_line_index TYPE string. + DATA code_line_exists TYPE string. + DATA code_lines TYPE if_ci_atc_quickfix=>ty_code. + DATA key TYPE string. + DATA token_idx TYPE i. + DATA(statement) = procedure-statements[ statement_index ]. + + + IF lines( statement-tokens ) <= 2 OR statement-tokens[ 2 ]-lexeme <> 'TABLE' OR statement-tokens[ 2 ]-references IS NOT INITIAL + OR lines( procedure-statements ) = statement_index + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING NO FIELDS' ) = 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 + OR statement-tokens[ 3 ]-lexeme CP '*('. + RETURN. + ENDIF. + DATA(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WITH KEY' ). + IF key_idx = 0. + RETURN. + ELSE. + + DATA(start_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'COMPONENTS' + start_index = key_idx + 1 ). + IF start_idx = 0. "with key... + start_idx = key_idx + 2. + ELSE. "with key name components ... + start_idx -= 2. + ENDIF. + DATA(keylen) = 0. + DATA(to_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' start_index = start_idx ) - 1. + IF to_idx <= 0. + to_idx = lines( statement-tokens ). + ENDIF. + IF statement-tokens[ key_idx + 2 ]-lexeme = '='. + key = 'TABLE_LINE'. + append_tokens( EXPORTING tokens = statement-tokens from_idx = key_idx + 2 to_idx = to_idx + CHANGING result = key ). + ELSE. + append_tokens( EXPORTING tokens = statement-tokens from_idx = start_idx to_idx = to_idx + CHANGING result = key ). + ENDIF. + keylen = to_idx - start_idx + 1. + + ENDIF. + IF keylen = 1. +* finding without quickfix since obsolete version read table with key val. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-line_exists + pseudo_comment = pseudo_comments-line_exists + CHANGING findings = findings ). + RETURN. + ENDIF. + DATA(quickfixable) = abap_true. + DATA(table) = statement-tokens[ 3 ]-lexeme. + IF table CP '*[]'. + DATA(len) = strlen( table ) - 2. + table = table(len). + ENDIF. + DATA(idx) = statement_index + 1. + ASSIGN procedure-statements[ idx ] TO FIELD-SYMBOL(). + IF -keyword = 'IF' AND lines( -tokens ) = 4 + AND -tokens[ 2 ]-lexeme = 'SY-SUBRC' + + AND -tokens[ 4 ]-lexeme = '0'. + CASE -tokens[ 3 ]-lexeme. + WHEN '=' OR 'EQ' . + DATA(if_sysubrc) = 1. + WHEN '<>' OR 'NE'. + if_sysubrc = 2. + ENDCASE. + idx += 1. + ENDIF. + DATA(end_idx) = idx. + IF if_sysubrc <> 0. + to_idx = lines( procedure-statements ). + ELSE. + to_idx = idx. + ENDIF. + LOOP AT procedure-statements FROM idx TO to_idx ASSIGNING FIELD-SYMBOL(). + DATA(tabix) = sy-tabix. + IF -keyword = 'ENDIF'. + end_idx = sy-tabix. + EXIT. + ENDIF. + DATA(sytabix_idx) = line_index( -tokens[ lexeme = 'SY-TABIX' ] ). + + IF sytabix_idx <> 0. + IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-lexeme = '&&'. + quickfixable = abap_false. + EXIT. + ENDIF. + IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-references IS INITIAL + AND -tokens[ sytabix_idx - 1 ]-lexeme = 'LIKE' + AND -keyword = 'DATA'. + quickfixable = abap_false. + EXIT. + ENDIF. + CASE -keyword. + WHEN 'MOVE'. + code_line_index = get_move_changed_line( ). + REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. + APPEND code_line_index TO code_lines. + WHEN 'MESSAGE' OR 'PERFORM' OR '+CALL_MACRO'. + quickfixable = abap_false. + EXIT. + WHEN 'SET'. + IF -tokens[ 2 ]-references IS INITIAL AND -tokens[ 2 ]-lexeme = 'BIT'. + quickfixable = abap_false. + ENDIF. + WHEN OTHERS. + IF if_sysubrc <> 2. + code_line_index = analyzer->flatten_tokens( tokens = -tokens ). + REPLACE FIRST OCCURRENCE OF 'SY-TABIX IS INITIAL' IN code_line_index WITH |line_index( { table }[ { key } ] ) = 0| ##NO_TEXT. + REPLACE FIRST OCCURRENCE OF 'SY-TABIX IS NOT INITIAL' IN code_line_index WITH |line_index( { table }[ { key } ] ) <> 0| ##NO_TEXT. + REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. + code_line_index = |{ code_line_index }.|. + APPEND code_line_index TO code_lines. + ENDIF. + ENDCASE. + ELSEIF if_sysubrc <> 0 AND tabix > statement_index + 1. + IF -keyword = 'CALL' OR -keyword = '+CALL_METHOD'. + quickfixable = abap_false. + EXIT. + ENDIF. + CASE if_sysubrc. + WHEN 1. + token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). + IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_TRUE'. + quickfixable = abap_false. + EXIT. + ENDIF. + WHEN 2. + token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). + IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_FALSE' + OR procedure-statements[ tabix + 1 ]-keyword <> 'ENDIF'. + quickfixable = abap_false. + EXIT. + ENDIF. + ENDCASE. + append_tokens( EXPORTING tokens = -tokens to_idx = token_idx - 1 CHANGING result = code_line_exists ). + IF if_sysubrc = 1. + code_line_exists = |{ code_line_exists } = xsdbool( line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. + ELSE. + code_line_exists = |{ code_line_exists } = xsdbool( NOT line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. + ENDIF. + APPEND code_line_exists TO code_lines. + ENDIF. + IF if_sysubrc = 0. + EXIT. + ENDIF. + ENDLOOP. + + IF quickfixable = abap_true AND ( code_line_index IS NOT INITIAL OR code_line_exists IS NOT INITIAL ). + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-line_exists ). + + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = end_idx ) ) ) + code = code_lines ). + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-line_exists + pseudo_comment = pseudo_comments-line_exists + quickfixes = quickfixes + CHANGING findings = findings ). + ELSE. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-line_exists + pseudo_comment = pseudo_comments-line_exists + CHANGING findings = findings ). + ENDIF. + + ENDMETHOD. + + + METHOD analyze_loop. + DATA code_line_index TYPE string. + DATA code_line_exists TYPE string. + DATA code_lines TYPE if_ci_atc_quickfix=>ty_code. + DATA key TYPE string. + + DATA(statement) = procedure-statements[ statement_index ]. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'OR' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'NOT' ) <> 0. + RETURN. + ENDIF. + DATA(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WHERE' ). + IF key_idx = 0 OR statement-tokens[ key_idx + 1 ]-lexeme CP '(*'. + RETURN. + ENDIF. + DATA(table) = statement-tokens[ 3 ]-lexeme. + IF table CP '*('. + RETURN. + ENDIF. + DATA(result_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ). + IF result_idx <> 0. + ASSIGN statement-tokens[ result_idx + 1 ] TO FIELD-SYMBOL(). + IF is_used( procedure = procedure from_index = statement_index + 1 full_name = -references[ lines( -references ) ]-full_name ). + RETURN. + ENDIF. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = '(' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = ')' ) <> 0. + RETURN. + ENDIF. + DATA(token_idx) = key_idx + 1. + DO. + ASSIGN statement-tokens[ token_idx ] TO . + append_token( EXPORTING token = CHANGING result = key ). + token_idx += 1. + ASSIGN statement-tokens[ token_idx ] TO . + CASE -lexeme. + WHEN '=' OR 'EQ'. + key = |{ key } = |. + WHEN OTHERS. + RETURN. + ENDCASE. + DATA(and_idx) = analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'AND' ). + IF and_idx = 0. + append_tokens( EXPORTING tokens = statement-tokens from_idx = token_idx + 1 CHANGING result = key ). + EXIT. + ELSE. + append_tokens( EXPORTING tokens = statement-tokens from_idx = token_idx + 1 to_idx = and_idx - 1 CHANGING result = key ). + token_idx = and_idx + 1. + ENDIF. + ENDDO. + DATA(quickfixable) = abap_true. + LOOP AT procedure-statements FROM statement_index + 1 ASSIGNING FIELD-SYMBOL(). + CASE -keyword. + WHEN 'ENDLOOP'. + DATA(end_idx) = sy-tabix. + EXIT. + WHEN 'EXIT'. + DATA(contains_exit) = abap_true. + WHEN 'MOVE'. + IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + code_line_index = get_move_changed_line( ). + REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. + APPEND code_line_index TO code_lines. + ENDIF. + WHEN 'MESSAGE' OR 'PERFORM' OR '+CALL_MACRO'. + IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + quickfixable = abap_false. + EXIT. + ENDIF. + WHEN 'SET'. + IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ) + AND -tokens[ 2 ]-references IS INITIAL AND -tokens[ 2 ]-lexeme = 'BIT'. + quickfixable = abap_false. + ENDIF. + WHEN OTHERS. + IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + LOOP AT -tokens ASSIGNING . + IF -lexeme = 'SY-TABIX'. + code_line_index = |{ code_line_index } line_index( { table }[ { key } ] )| ##NO_TEXT. + ELSEIF code_line_index IS INITIAL. + code_line_index = -lexeme. + ELSE. + code_line_index = |{ code_line_index } { -lexeme }|. + ENDIF. + ENDLOOP. + code_line_index = |{ code_line_index }.|. + APPEND code_line_index TO code_lines. + ELSE. + DATA(idx) = analyzer->find_clause_index( tokens = -tokens clause = '=' ). + IF idx = 0 OR -tokens[ idx + 1 ]-lexeme <> 'ABAP_TRUE'. + RETURN. + ENDIF. + LOOP AT -tokens TO idx - 1 ASSIGNING . + IF code_line_exists IS INITIAL. + code_line_exists = -lexeme. + ELSE. + code_line_exists = |{ code_line_exists } { -lexeme }|. + ENDIF. + ENDLOOP. + code_line_exists = |{ code_line_exists } = xsdbool( line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. + APPEND code_line_exists TO code_lines. + ENDIF. + ENDCASE. + ENDLOOP. + IF contains_exit = abap_true. + DATA quickfixes TYPE REF TO cl_ci_atc_quickfixes. + IF quickfixable = abap_true. + quickfixes = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-line_exists ). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = end_idx ) ) ) + code = code_lines ). + ENDIF. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-line_exists + pseudo_comment = pseudo_comments-line_exists + quickfixes = quickfixes + CHANGING findings = findings ). + ENDIF. + ENDMETHOD. + + + METHOD analyze_create_object. + DATA code_line TYPE string. + DATA(statement) = procedure-statements[ statement_index ]. + DATA(replace_data) = abap_true. + + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TYPE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'AREA HANDLE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 "old exceptions cannot be handled with NEW + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'FOR TESTING' ) <> 0. + RETURN. + ENDIF. + + DATA(object_name) = statement-tokens[ 3 ]-lexeme. + DATA(full_name) = statement-tokens[ 3 ]-references[ lines( statement-tokens[ 3 ]-references ) ]-full_name. +* self reference is working with create object but not with new + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() FROM 4 WHERE lexeme CP |{ object_name }*| AND references IS NOT INITIAL. + LOOP AT -references TRANSPORTING NO FIELDS WHERE full_name CP |{ full_name }*|. + replace_data = abap_false. + EXIT. + ENDLOOP. + ENDLOOP. +* find data statement + DATA(data_idx) = statement_index - 1. + WHILE data_idx > 0. + IF procedure-statements[ data_idx ]-keyword = 'DATA' + AND procedure-statements[ data_idx ]-tokens[ 2 ]-lexeme = object_name. + ASSIGN procedure-statements[ data_idx ] TO FIELD-SYMBOL(). + DATA(type_idx) = analyzer->find_clause_index( tokens = -tokens clause = 'TYPE REF TO' ). + IF type_idx = 0. + RETURN. + ENDIF. + IF replace_data = abap_true AND data_idx = statement_index - 1. + DATA(type_name) = -tokens[ type_idx + 3 ]-lexeme. + code_line = |DATA({ object_name }) = NEW { type_name }( |. + DATA(from_idx) = data_idx. + ELSE. + code_line = |{ object_name } = NEW #( |. + from_idx = statement_index. + ENDIF. + ENDIF. + data_idx -= 1. + ENDWHILE. + IF code_line IS INITIAL. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-prefer_new + pseudo_comment = pseudo_comments-prefer_new + CHANGING findings = findings ). + RETURN. + ENDIF. + DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). + + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-prefer_new ). + IF from_idx < statement_index. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id statements = VALUE #( from = from_idx to = statement_index - 1 ) ) ) + code = VALUE #( ( `` ) ) ). + ENDIF. + IF exporting_idx = 0. + DATA(to_idx) = 3. + ELSE. + to_idx = exporting_idx. + ENDIF. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = 1 to = to_idx ) ) ) + code = VALUE #( ( code_line ) ) ). + quickfix->insert_after( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) + code = VALUE #( ( `)` ) ) ). + + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-prefer_new + pseudo_comment = pseudo_comments-prefer_new + quickfixes = quickfixes + CHANGING findings = findings ). + ENDMETHOD. + + + METHOD analyze_call_method. + DATA code_line TYPE string. + DATA(statement) = procedure-statements[ statement_index ]. + IF statement-tokens[ 3 ]-references IS INITIAL AND statement-tokens[ 3 ]-lexeme = 'OF'. "ole + RETURN. + ENDIF. + DATA(method_name) = statement-tokens[ 3 ]-lexeme. + IF method_name(1) = '(' OR method_name CP '*->(*' OR method_name CP '*=>(*' OR method_name CP '(*)' + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'PARAMETER-TABLE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTION-TABLE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0. +* dynamic call / exceptions + RETURN. + ENDIF. + + IF method_name NP '*('. + DATA(method_line) = |{ method_name }(|. + ELSE. + method_line = method_name. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) = 0 + AND analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) = 0 . + DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). + DATA(receiving_infos) = get_receiving_infos( tokens = statement-tokens ). + ENDIF. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-call_method ). + IF lines( statement-tokens ) = 3 + OR lines( statement-tokens ) = 4. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) ) ) + code = VALUE #( ( |{ method_line } ).| ) ) ). + ELSE. + IF exporting_idx <> 0. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = exporting_idx to = exporting_idx ) ) ) + code = VALUE #( ( `` ) ) ). + ENDIF. + IF receiving_infos-result_line IS NOT INITIAL. + IF receiving_infos-end_idx = lines( statement-tokens ). + code_line = ')'. + ELSE. + code_line = ''. + ENDIF. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = receiving_infos-receiving_idx to = receiving_infos-end_idx ) ) ) + code = VALUE #( ( code_line ) ) ). + method_line = |{ receiving_infos-result_line } = { method_line }|. + ENDIF. + + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = 1 to = 3 ) ) ) + code = VALUE #( ( method_line ) ) ). + + IF receiving_infos-end_idx <> lines( statement-tokens ) AND method_name NP '*('. + quickfix->insert_after( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) + code = VALUE #( ( `)` ) ) ). + ENDIF. + ENDIF. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-call_method + pseudo_comment = pseudo_comments-call_method + quickfixes = quickfixes + CHANGING findings = findings ). + ENDMETHOD. + + + METHOD analyze_exporting_receiving. + DATA exporting_idxs TYPE SORTED TABLE OF i WITH UNIQUE KEY table_line. + DATA(statement) = procedure-statements[ statement_index ]. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. + RETURN. + ENDIF. + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE references IS INITIAL AND lexeme = 'EXPORTING'. + DATA(token_idx) = sy-tabix. + IF check_remove_exporting( statement = statement token_idx = token_idx ) = abap_true. + INSERT token_idx INTO TABLE exporting_idxs. + ENDIF. + ENDLOOP. + + DATA(receiving_infos) = get_receiving_infos( tokens = statement-tokens ). + + IF receiving_infos-result_line IS INITIAL AND exporting_idxs IS INITIAL. + RETURN. + ENDIF. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA pseudo_comment TYPE string. + IF receiving_infos-result_line IS NOT INITIAL. + DATA(finding_code) = message_codes-exporting_receiving. + pseudo_comment = pseudo_comments-exporting_receiving. + DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-exporting_receiving ). + receiving_infos-result_line = |{ receiving_infos-result_line } = { statement-tokens[ 1 ]-lexeme }|. + quickfix->replace( context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = 1 to = 1 ) ) ) + code = VALUE #( ( receiving_infos-result_line ) ) ). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = receiving_infos-receiving_idx to = receiving_infos-end_idx ) ) ) + code = VALUE #( ( `` ) ) ). + ELSE. + finding_code = message_codes-method_exporting. + pseudo_comment = pseudo_comments-method_exporting. + quickfix = quickfixes->create_quickfix( quickfix_codes-method_exporting ). + ENDIF. + LOOP AT exporting_idxs INTO DATA(exporting_idx). + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = exporting_idx to = exporting_idx + 1 ) ) ) + code = VALUE #( ( statement-tokens[ exporting_idx + 1 ]-lexeme ) ) ). + ENDLOOP. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = finding_code + pseudo_comment = pseudo_comment + quickfixes = quickfixes + CHANGING findings = findings ). + ENDMETHOD. + + + METHOD analyze_text_assembly. + + DATA(statement) = procedure-statements[ statement_index ]. + + DATA start_idx TYPE i. + DATA end_idx TYPE i. + DATA last_idx TYPE i. + DATA code_line TYPE string. + DATA(quickfixes) = assistant_factory->create_quickfixes( ). + DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-text_assembly ). + DATA(quickfixable) = abap_true. + TRY. + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE lexeme = '&&'. + DATA(tabix) = sy-tabix. + IF tabix - 1 <> last_idx. + IF code_line IS NOT INITIAL. +* store old code_line + code_line = |{ code_line }\||. + IF strlen( code_line ) >= analyzer->max_line_length - 1. + quickfixable = abap_false. + EXIT. + ELSE. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = start_idx to = end_idx ) ) ) + code = VALUE #( ( code_line ) ) ). + ENDIF. + ENDIF. +* new && connection + code_line = '|'. + start_idx = tabix - 1. + DATA(value) = get_value( statement-tokens[ tabix - 1 ] ). + code_line = |{ code_line }{ value }|. + ENDIF. + value = get_value( statement-tokens[ tabix + 1 ] ). + code_line = |{ code_line }{ value }|. + end_idx = tabix + 1. + last_idx = tabix + 1. + ENDLOOP. + IF quickfixable = abap_true AND code_line IS NOT INITIAL. + code_line = |{ code_line }\||. + IF strlen( code_line ) >= analyzer->max_line_length - 1. + quickfixable = abap_false. + ELSE. + quickfix->replace( + context = assistant_factory->create_quickfix_context( + VALUE #( procedure_id = procedure-id + statements = VALUE #( from = statement_index to = statement_index ) + tokens = VALUE #( from = start_idx to = end_idx ) ) ) + code = VALUE #( ( code_line ) ) ). + ENDIF. + ENDIF. + CATCH lcx_error. + quickfixable = abap_false. + ENDTRY. + IF quickfixable = abap_false. + CLEAR quickfixes. + ENDIF. + add_finding( + EXPORTING + procedure = procedure + statement_index = statement_index + code = message_codes-text_assembly + pseudo_comment = pseudo_comments-text_assembly + quickfixes = quickfixes + CHANGING findings = findings ). + + ENDMETHOD. + + + METHOD analyze_procedure. + + LOOP AT procedure-statements ASSIGNING FIELD-SYMBOL(). + DATA(idx) = sy-tabix. + CASE -keyword. + WHEN 'MOVE'. + INSERT LINES OF analyze_move( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'TRANSLATE'. + INSERT LINES OF analyze_translate( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'READ'. + INSERT LINES OF analyze_read( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'LOOP'. + INSERT LINES OF analyze_loop( procedure = procedure statement_index = idx ) INTO TABLE findings. + WHEN 'CREATE'. + IF -tokens[ 2 ]-lexeme = 'OBJECT' AND -tokens[ 2 ]-references IS INITIAL. + INSERT LINES OF analyze_create_object( procedure = procedure statement_index = idx ) INTO TABLE findings. + ENDIF. + WHEN 'CALL'. + IF -tokens[ 2 ]-lexeme = 'METHOD' AND -tokens[ 2 ]-references IS INITIAL. + INSERT LINES OF analyze_call_method( procedure = procedure statement_index = idx ) INTO TABLE findings. + ENDIF. + WHEN 'METHODS' OR 'CLASS-METHODS'. + CONTINUE. + ENDCASE. +* functional method call may occur in many statements + IF -keyword <> 'CALL' AND -keyword <> 'CREATE' + AND analyzer->find_clause_index( tokens = -tokens clause = 'EXPORTING' ) <> 0. + INSERT LINES OF analyze_exporting_receiving( procedure = procedure statement_index = idx ) INTO TABLE findings. + ENDIF. +* text assembly + IF analyzer->find_clause_index( tokens = -tokens clause = '&&' ) <> 0 + AND -keyword <> 'CONCATENATE' + AND -keyword <> 'SPLIT' + AND analyzer->is_db_statement( statement = ) IS INITIAL. + INSERT LINES OF analyze_text_assembly( procedure = procedure statement_index = idx ) INTO TABLE findings. + ENDIF. + ENDLOOP. + ENDMETHOD. + + + METHOD is_used. + result = abap_false. + LOOP AT procedure-statements FROM from_index ASSIGNING FIELD-SYMBOL(). + LOOP AT -tokens ASSIGNING FIELD-SYMBOL() + WHERE references IS NOT INITIAL. + result = xsdbool( line_exists( -references[ full_name = full_name ] ) ). + IF result = abap_true. + RETURN. + ENDIF. + ENDLOOP. + ENDLOOP. + ENDMETHOD. + + + METHOD check_remove_exporting. + result = abap_false. + ASSIGN statement-tokens[ token_idx - 1 ] TO FIELD-SYMBOL(). + IF NOT -lexeme CP '*('. + RETURN. + ENDIF. + LOOP AT -references ASSIGNING FIELD-SYMBOL() + WHERE kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-method + AND usage_grade <> if_ci_atc_source_code_provider=>usage_grades-definition. + DATA(is_method_call) = abap_true. + EXIT. + ENDLOOP. + IF is_method_call = abap_false. + RETURN. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. + RETURN. + ENDIF. + result = abap_true. + ENDMETHOD. + + + METHOD get_value. + IF token-lexeme CP '*(' + OR token-lexeme CP '*[' + OR token-lexeme(1) = ']' + OR token-lexeme(1) = ')'. + RAISE EXCEPTION TYPE lcx_error. + ENDIF. + + IF token-references IS INITIAL. + CASE token-lexeme. + WHEN ')' OR '|'. + RAISE EXCEPTION TYPE lcx_error. + WHEN OTHERS. + IF token-lexeme CP '`*`' OR token-lexeme CP `'*'`. + DATA(len) = strlen( token-lexeme ) - 2. + result = token-lexeme+1(len). + IF result CA '|'. + RAISE EXCEPTION TYPE lcx_error. + ENDIF. + result = replace( val = result sub = '\' with = '\\' occ = 0 ). + result = replace( val = result sub = '{' with = '\{' occ = 0 ). + result = replace( val = result sub = '}' with = '\}' occ = 0 ). + ELSE. + RAISE EXCEPTION TYPE lcx_error. + ENDIF. + ENDCASE. + ELSE. + IF token-lexeme = 'NEW'. + RAISE EXCEPTION TYPE lcx_error. + ENDIF. + result = |\{ { token-lexeme } \}|. + ENDIF. + ENDMETHOD. + + + METHOD append_token. + IF result IS INITIAL. + result = token-lexeme. + ELSE. + result = |{ result } { token-lexeme }|. + ENDIF. + ENDMETHOD. + + + METHOD append_tokens. + DATA itab LIKE tokens. + IF from_idx IS SUPPLIED OR to_idx IS SUPPLIED. + IF from_idx = 0. + from_idx = 1. + ENDIF. + IF to_idx = 0. + to_idx = lines( tokens ). + ENDIF. + LOOP AT tokens FROM from_idx TO to_idx ASSIGNING FIELD-SYMBOL(). + APPEND TO itab. + ENDLOOP. + DATA(flattened) = analyzer->flatten_tokens( tokens = itab ). + ELSE. + flattened = analyzer->flatten_tokens( tokens = tokens ). + ENDIF. + IF result IS INITIAL. + result = flattened. + ELSE. + result = |{ result } { flattened }|. + ENDIF. + ENDMETHOD. + + + METHOD get_receiving_infos. + CLEAR result-end_idx. + CLEAR result-result_line. + result-receiving_idx = analyzer->find_clause_index( tokens = tokens clause = 'RECEIVING ' ). + IF result-receiving_idx = 0. + RETURN. + ENDIF. + DATA(copy_idx) = analyzer->find_clause_index( tokens = tokens start_index = result-receiving_idx + 1 clause = '=' ). + IF copy_idx <> 0. + result-end_idx = lines( tokens ). + LOOP AT tokens FROM copy_idx + 1 ASSIGNING FIELD-SYMBOL() + WHERE references IS INITIAL. + CASE -lexeme. + WHEN ')' OR 'EXPORTING'. + result-end_idx = sy-tabix - 1. + EXIT. + ENDCASE. + ENDLOOP. + append_tokens( EXPORTING tokens = tokens from_idx = copy_idx + 1 to_idx = result-end_idx CHANGING result = result-result_line ). + ENDIF. + + ENDMETHOD. ENDCLASS. diff --git a/src/checks/#cc4a#modern_language.clas.testclasses.abap b/src/checks/#cc4a#modern_language.clas.testclasses.abap index 84cfd2a..3a656d4 100644 --- a/src/checks/#cc4a#modern_language.clas.testclasses.abap +++ b/src/checks/#cc4a#modern_language.clas.testclasses.abap @@ -1,3 +1,5 @@ + + CLASS test DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. @@ -6,11 +8,11 @@ CLASS test DEFINITION FINAL FOR TESTING CONSTANTS test_class TYPE c LENGTH 30 VALUE '/CC4A/TEST_MODERN_LANGUAGE'. METHODS test FOR TESTING RAISING cx_static_check. ENDCLASS. +CLASS /cc4a/modern_language DEFINITION LOCAL FRIENDS test. CLASS test IMPLEMENTATION. METHOD test. - DATA(test_move) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_MOVE' ) ). DATA(test_translate) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_TRANSLATE' ) ). DATA(test_read) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_READ' ) ). DATA(test_loop) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_LOOP' ) ). @@ -22,298 +24,248 @@ CLASS test IMPLEMENTATION. check = NEW /cc4a/modern_language( ) object = VALUE #( type = 'CLAS' name = test_class ) )->execute_and_assert( VALUE #( - ( code = /cc4a/modern_language=>c_code_move - location = VALUE #( object = test_move position = VALUE #( line = 9 column = 4 ) ) - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_move - span = VALUE #( object = test_move from = 9 to = 9 ) - code_lines = VALUE #( ( `NUM = EXACT #( 1 ).` ) ) ) ) ) - - ( code = /cc4a/modern_language=>c_code_move - location = VALUE #( object = test_move position = VALUE #( line = 13 column = 4 ) ) - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_move - span = VALUE #( object = test_move from = 13 to = 13 ) - code_lines = VALUE #( ( `N = 5.` ) ) ) ) ) - - ( code = /cc4a/modern_language=>c_code_move - location = VALUE #( object = test_move position = VALUE #( line = 15 column = 4 ) ) - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_move - span = VALUE #( object = test_move from = 15 to = 15 ) - code_lines = VALUE #( ( `N = EXACT #( 5 ).` ) ) ) ) ) - - ( code = /cc4a/modern_language=>c_code_move - location = VALUE #( object = test_move position = VALUE #( line = 20 column = 4 ) ) - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_move - span = VALUE #( object = test_move from = 20 to = 20 ) - code_lines = VALUE #( ( `B ?= A.` ) ) ) ) ) - - ( code = /cc4a/modern_language=>c_code_move - location = VALUE #( object = test_move position = VALUE #( line = 22 column = 4 ) ) - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_move - span = VALUE #( object = test_move from = 22 to = 22 ) - code_lines = VALUE #( ( `B = A.` ) ) ) ) ) - - ( code = /cc4a/modern_language=>c_code_move - location = VALUE #( object = test_move position = VALUE #( line = 24 column = 4 ) ) - has_pseudo_comment = abap_true - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_move - - span = VALUE #( object = test_move from = 24 to = 24 ) - code_lines = VALUE #( ( `B = A.` ) ) ) ) ) - * TRANSLATE - ( code = /cc4a/modern_language=>c_code_translate - location = VALUE #( object = test_translate position = VALUE #( line = 3 column = 4 ) ) - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_translate - span = VALUE #( object = test_translate from = 3 to = 3 ) - code_lines = VALUE #( ( `STR1 = to_upper( STR1 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_translate - location = VALUE #( object = test_translate position = VALUE #( line = 4 column = 4 ) ) - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_translate - span = VALUE #( object = test_translate from = 4 to = 4 ) - code_lines = VALUE #( ( `STR1 = to_lower( STR1 ).` ) ) ) ) ) - - ( code = /cc4a/modern_language=>c_code_translate + ( code = /cc4a/modern_language=>message_codes-translate + location = VALUE #( object = test_translate position = VALUE #( line = 3 column = 4 ) ) ) + ( code = /cc4a/modern_language=>message_codes-translate + location = VALUE #( object = test_translate position = VALUE #( line = 4 column = 4 ) ) ) + ( code = /cc4a/modern_language=>message_codes-translate location = VALUE #( object = test_translate position = VALUE #( line = 5 column = 4 ) ) - has_pseudo_comment = abap_true - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_translate - span = VALUE #( object = test_translate from = 5 to = 5 ) - code_lines = VALUE #( ( `STR1 = to_lower( STR1 ).` ) ) ) ) ) - + has_pseudo_comment = abap_true ) * READ - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 4 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 4 to = 5 ) code_lines = VALUE #( ( `DATA(IDX) = LINE_INDEX( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 7 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 7 to = 11 ) code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ).` ) ( `DATA(EXISTS) = XSDBOOL( LINE_EXISTS( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ) ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 19 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 19 to = 20 ) code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 21 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 21 to = 25 ) code_lines = VALUE #( ( `EXISTS = XSDBOOL( LINE_EXISTS( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ) ).` ) ( `IDX = LINE_INDEX( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 27 column = 4 ) ) has_pseudo_comment = abap_true ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 34 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 34 to = 35 ) code_lines = VALUE #( ( `IDX = line_index( ITAB[ PGMID = 'R3TR' ] ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_move - location = VALUE #( object = test_read position = VALUE #( line = 35 column = 4 ) ) - quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_move - span = VALUE #( object = test_read from = 35 to = 35 ) - code_lines = VALUE #( ( `idx = sy-tabix.` ) ) ) ) ) +* ( code = /cc4a/modern_language=>message_codes-move +* location = VALUE #( object = test_read position = VALUE #( line = 35 column = 4 ) ) +* quickfixes = VALUE #( ( +* quickfix_code = /cc4a/modern_language=>quickfix_codes-move +* span = VALUE #( object = test_read from = 35 to = 35 ) +* code_lines = VALUE #( ( `idx = sy-tabix.` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 37 column = 4 ) ) has_pseudo_comment = abap_true ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 41 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 41 to = 44 ) code_lines = VALUE #( ( `DATA(BLUE) = xsdbool( NOT line_exists( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLUE' ] ) ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 46 column = 4 ) ) has_pseudo_comment = abap_true ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 52 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 52 to = 54 ) code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) = 0 .` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 57 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 57 to = 59 ) code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) = 0 .` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 62 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 62 to = 64 ) code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 67 column = 4 ) ) has_pseudo_comment = abap_true quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_read from = 67 to = 69 ) code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 73 column = 4 ) ) has_pseudo_comment = abap_true ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 76 column = 4 ) ) has_pseudo_comment = abap_true ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_read position = VALUE #( line = 81 column = 4 ) ) has_pseudo_comment = abap_true ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_loop position = VALUE #( line = 4 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_loop from = 4 to = 7 ) code_lines = VALUE #( ( `DATA(IDX) = LINE_INDEX( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_loop position = VALUE #( line = 9 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_loop from = 9 to = 13 ) code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ).` ) ( `DATA(EXISTS) = XSDBOOL( LINE_EXISTS( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ) ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_loop position = VALUE #( line = 21 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_loop from = 21 to = 24 ) code_lines = VALUE #( ( `EXISTS = xsdbool( line_exists( ITAB[ OBJ_NAME = 'BLA' ] ) ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_line_exists + ( code = /cc4a/modern_language=>message_codes-line_exists location = VALUE #( object = test_loop position = VALUE #( line = 38 column = 4 ) ) has_pseudo_comment = abap_true quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_line_exists + quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists span = VALUE #( object = test_loop from = 38 to = 41 ) code_lines = VALUE #( ( `EXISTS = xsdbool( line_exists( ITAB[ OBJ_NAME = 'BLA' ] ) ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_prefer_new + ( code = /cc4a/modern_language=>message_codes-prefer_new location = VALUE #( object = test_create_object position = VALUE #( line = 3 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new span = VALUE #( object = test_create_object from = 2 to = 3 ) code_lines = VALUE #( ( `DATA(object1) = NEW /cc4a/test_modern_language( ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_prefer_new + ( code = /cc4a/modern_language=>message_codes-prefer_new location = VALUE #( object = test_create_object position = VALUE #( line = 5 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new span = VALUE #( object = test_create_object from = 5 to = 5 ) code_lines = VALUE #( ( `object1 = NEW #( ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_prefer_new + ( code = /cc4a/modern_language=>message_codes-prefer_new location = VALUE #( object = test_create_object position = VALUE #( line = 9 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new span = VALUE #( object = test_create_object from = 7 to = 12 ) code_lines = VALUE #( ( `DATA(CLASS_REF) = NEW LCL_TEST( PARAM1 = 5 PARAM2 = 4 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_prefer_new + ( code = /cc4a/modern_language=>message_codes-prefer_new location = VALUE #( object = test_create_object position = VALUE #( line = 16 column = 8 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new span = VALUE #( object = test_create_object from = 16 to = 18 ) code_lines = VALUE #( ( `CLASS_REF1 = NEW #( PARAM1 = 15 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_prefer_new + ( code = /cc4a/modern_language=>message_codes-prefer_new location = VALUE #( object = test_create_object position = VALUE #( line = 32 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new span = VALUE #( object = test_create_object from = 31 to = 35 ) code_lines = VALUE #( ( `DATA(CLASS_REF3) = NEW LCL_TEST3( param1 = 'blabla' param2 = |{ sy-datum } { sy-uzeit }| ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_prefer_new + ( code = /cc4a/modern_language=>message_codes-prefer_new location = VALUE #( object = test_create_object position = VALUE #( line = 37 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new span = VALUE #( object = test_create_object from = 37 to = 40 ) code_lines = VALUE #( ( `CLASS_REF3 = NEW #( param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_prefer_new + ( code = /cc4a/modern_language=>message_codes-prefer_new location = VALUE #( object = test_create_object position = VALUE #( line = 42 column = 4 ) ) has_pseudo_comment = abap_true quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_prefer_new + quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new span = VALUE #( object = test_create_object from = 42 to = 45 ) code_lines = VALUE #( ( `CLASS_REF3 = NEW #( param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_call_method + ( code = /cc4a/modern_language=>message_codes-prefer_new + location = VALUE #( object = test_create_object position = VALUE #( line = 49 column = 4 ) ) + has_pseudo_comment = abap_true + quickfixes = VALUE #( ( + quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new + span = VALUE #( object = test_create_object from = 49 to = 51 ) + code_lines = VALUE #( ( `SELFISH = NEW #( val = selfish->my_val ).` ) ) ) ) ) + + ( code = /cc4a/modern_language=>message_codes-call_method location = VALUE #( object = test_call_method position = VALUE #( line = 6 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_call_method + quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method span = VALUE #( object = test_call_method from = 6 to = 6 ) code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_call_method + ( code = /cc4a/modern_language=>message_codes-call_method location = VALUE #( object = test_call_method position = VALUE #( line = 8 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_call_method + quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method span = VALUE #( object = test_call_method from = 8 to = 8 ) code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_call_method + ( code = /cc4a/modern_language=>message_codes-call_method location = VALUE #( object = test_call_method position = VALUE #( line = 10 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_call_method + quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method span = VALUE #( object = test_call_method from = 10 to = 14 ) code_lines = VALUE #( ( `DATA(RESULT) = CLASS_REF->TEST1( PARAM1 = 15 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_call_method + ( code = /cc4a/modern_language=>message_codes-call_method location = VALUE #( object = test_call_method position = VALUE #( line = 16 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_call_method + quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method span = VALUE #( object = test_call_method from = 16 to = 22 ) code_lines = VALUE #( ( `CLASS_REF->TEST2(` ) ( `EXPORTING PARAM1 = 'Blabla'` ) ( `IMPORTING PARAM2 = DATA(STRING_RESULT)` ) ( `CHANGING PARAM3 = TEST_STRING ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_call_method + ( code = /cc4a/modern_language=>message_codes-call_method location = VALUE #( object = test_call_method position = VALUE #( line = 33 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_call_method + quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method span = VALUE #( object = test_call_method from = 33 to = 39 ) code_lines = VALUE #( ( `CLASS_REF->TEST4(` ) ( `EXPORTING` ) @@ -324,145 +276,148 @@ CLASS test IMPLEMENTATION. ( `param4 = result` ) ( `).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_call_method + ( code = /cc4a/modern_language=>message_codes-call_method location = VALUE #( object = test_call_method position = VALUE #( line = 41 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_call_method + quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method span = VALUE #( object = test_call_method from = 41 to = 41 ) code_lines = VALUE #( ( `class_ref->test1( param1 = 3 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_call_method + ( code = /cc4a/modern_language=>message_codes-call_method location = VALUE #( object = test_call_method position = VALUE #( line = 51 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_call_method + quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method span = VALUE #( object = test_call_method from = 51 to = 51 ) code_lines = VALUE #( ( ` class_ref->test7(` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_call_method + ( code = /cc4a/modern_language=>message_codes-call_method location = VALUE #( object = test_call_method position = VALUE #( line = 59 column = 4 ) ) has_pseudo_comment = abap_true quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_call_method + quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method span = VALUE #( object = test_call_method from = 59 to = 59 ) code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_method_exporting + ( code = /cc4a/modern_language=>message_codes-method_exporting location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 6 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_method_exporting + quickfix_code = /cc4a/modern_language=>quickfix_codes-method_exporting span = VALUE #( object = test_call_method from = 6 to = 8 ) code_lines = VALUE #( ( `DATA(RESULT) = CLASS_REF->TEST1(` ) ( `PARAM1 = 15 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_method_exporting + ( code = /cc4a/modern_language=>message_codes-method_exporting location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 18 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_method_exporting + quickfix_code = /cc4a/modern_language=>quickfix_codes-method_exporting span = VALUE #( object = test_call_method from = 18 to = 18 ) code_lines = VALUE #( ( `result = class_ref->test3( param1 = 15 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_method_exporting + ( code = /cc4a/modern_language=>message_codes-method_exporting location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 20 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_method_exporting + quickfix_code = /cc4a/modern_language=>quickfix_codes-method_exporting span = VALUE #( object = test_exporting_receiving from = 20 to = 20 ) code_lines = VALUE #( ( `result = class_ref->test1( param1 = class_ref->test3( param1 = 3 ) ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_exporting_receiving + ( code = /cc4a/modern_language=>message_codes-exporting_receiving location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 23 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_exporting_receiving + quickfix_code = /cc4a/modern_language=>quickfix_codes-exporting_receiving span = VALUE #( object = test_exporting_receiving from = 23 to = 26 ) code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST1( PARAM1 = 15 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_exporting_receiving + ( code = /cc4a/modern_language=>message_codes-exporting_receiving location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 29 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_exporting_receiving + quickfix_code = /cc4a/modern_language=>quickfix_codes-exporting_receiving span = VALUE #( object = test_exporting_receiving from = 29 to = 29 ) code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST3( PARAM1 = 15 ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_exporting_receiving + ( code = /cc4a/modern_language=>message_codes-exporting_receiving location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 33 column = 4 ) ) has_pseudo_comment = abap_true quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_exporting_receiving + quickfix_code = /cc4a/modern_language=>quickfix_codes-exporting_receiving span = VALUE #( object = test_exporting_receiving from = 33 to = 33 ) code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST1( PARAM1 = CLASS_REF->TEST3( PARAM1 = 3 ) ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 4 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly span = VALUE #( object = test_text_assembly from = 4 to = 4 ) code_lines = VALUE #( ( `text1 = |ab{ TEXT1 }{ ABAP_TRUE }|.` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 5 column = 4 ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 7 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly span = VALUE #( object = test_text_assembly from = 7 to = 7 ) - code_lines = VALUE #( ( ` WRITE class_ref->test5( param1 = |ab| param2 = |cd| ).` ) ) ) ) ) + code_lines = VALUE #( ( ` DATA(bla) = class_ref->test5( param1 = |ab| param2 = |cd| ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 9 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly span = VALUE #( object = test_text_assembly from = 9 to = 9 ) - code_lines = VALUE #( ( `WRITE class_ref->test5( param1 = |ab| param2 = 'xxx' ).` ) ) ) ) ) + code_lines = VALUE #( ( `bla = class_ref->test5( param1 = |ab| param2 = 'xxx' ).` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 11 column = 4 ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 13 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly span = VALUE #( object = test_text_assembly from = 13 to = 13 ) code_lines = VALUE #( ( `text1 = |{ TEXT1 } \}| ##no_text.` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 15 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly span = VALUE #( object = test_text_assembly from = 15 to = 18 ) code_lines = VALUE #( ( `text1 = |[\{"TYPE":"U","TARGET":\{"URL":\{"URL":"www.sap.com/en"\}\}\},\{\}]|.` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 21 column = 4 ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 22 column = 4 ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 23 column = 4 ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 25 column = 4 ) ) quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly span = VALUE #( object = test_text_assembly from = 25 to = 25 ) code_lines = VALUE #( ( `text1 = |\\{ TEXT1 }-|.` ) ) ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_text_assembly position = VALUE #( line = 27 column = 4 ) ) has_pseudo_comment = abap_true quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly span = VALUE #( object = test_text_assembly from = 27 to = 27 ) - code_lines = VALUE #( ( `WRITE |ab|.` ) ) ) ) ) + code_lines = VALUE #( ( `bla = |ab|.` ) ) ) ) ) + + ( code = /cc4a/modern_language=>message_codes-text_assembly + location = VALUE #( object = test_text_assembly position = VALUE #( line = 29 column = 4 ) ) ) - ( code = /cc4a/modern_language=>c_code_text_assembly + ( code = /cc4a/modern_language=>message_codes-text_assembly location = VALUE #( object = test_read position = VALUE #( line = 75 column = 4 ) ) has_pseudo_comment = abap_true quickfixes = VALUE #( ( - quickfix_code = /cc4a/modern_language=>c_qf_text_assembly + quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly span = VALUE #( object = test_read from = 75 to = 75 ) - code_lines = VALUE #( ( `WRITE |Difference in contructor code/line{ SY-TABIX }|.` ) ) ) ) ) + code_lines = VALUE #( ( `bla = |Difference in contructor code/line{ SY-TABIX }|.` ) ) ) ) ) ) ). diff --git a/src/core/#cc4a#abap_analyzer.clas.abap b/src/core/#cc4a#abap_analyzer.clas.abap index 281bbb0..addd4f3 100644 --- a/src/core/#cc4a#abap_analyzer.clas.abap +++ b/src/core/#cc4a#abap_analyzer.clas.abap @@ -1,239 +1,239 @@ -class /cc4a/abap_analyzer definition - public - final - create private. - - public section. - interfaces /cc4a/if_abap_analyzer. - - class-methods create returning value(instance) type ref to /cc4a/if_abap_analyzer. - class-methods class_constructor. - aliases find_clause_index for /cc4a/if_abap_analyzer~find_clause_index. - aliases is_token_keyword for /cc4a/if_abap_analyzer~is_token_keyword. - aliases is_db_statement for /cc4a/if_abap_analyzer~is_db_statement. - aliases is_bracket for /cc4a/if_abap_analyzer~is_bracket. - protected section. - private section. - - types: - begin of ty_negation, - operator type string, - negated type string, - end of ty_negation. - class-data negations type table of ty_negation. - - methods _flatten_tokens - changing tokens type if_ci_atc_source_code_provider=>ty_tokens - returning value(flat) type string. - methods _flatten_template - changing tokens type if_ci_atc_source_code_provider=>ty_tokens - returning value(flat) type string. +CLASS /cc4a/abap_analyzer DEFINITION + PUBLIC + FINAL + CREATE PRIVATE. + + PUBLIC SECTION. + INTERFACES /cc4a/if_abap_analyzer. + + CLASS-METHODS create RETURNING VALUE(instance) TYPE REF TO /cc4a/if_abap_analyzer. + CLASS-METHODS class_constructor. + ALIASES find_clause_index FOR /cc4a/if_abap_analyzer~find_clause_index. + ALIASES is_token_keyword FOR /cc4a/if_abap_analyzer~is_token_keyword. + ALIASES is_db_statement FOR /cc4a/if_abap_analyzer~is_db_statement. + ALIASES is_bracket FOR /cc4a/if_abap_analyzer~is_bracket. + ALIASES max_line_length FOR /cc4a/if_abap_analyzer~max_line_length. + + PROTECTED SECTION. + PRIVATE SECTION. + + TYPES: + BEGIN OF ty_negation, + operator TYPE string, + negated TYPE string, + END OF ty_negation. + CLASS-DATA negations TYPE TABLE OF ty_negation. + + CLASS-METHODS _flatten_tokens + CHANGING tokens TYPE if_ci_atc_source_code_provider=>ty_tokens + RETURNING VALUE(flat) TYPE string. + + CLASS-METHODS _flatten_template + CHANGING tokens TYPE if_ci_atc_source_code_provider=>ty_tokens + RETURNING VALUE(flat) TYPE string. + + CLASS-METHODS _break_into_lines + IMPORTING VALUE(code) TYPE string + break_at TYPE i + RETURNING VALUE(code_lines) TYPE string_table + RAISING /cc4a/cx_line_break_impossible. + ENDCLASS. -CLASS /CC4A/ABAP_ANALYZER IMPLEMENTATION. +CLASS /cc4a/abap_analyzer IMPLEMENTATION. - method /cc4a/if_abap_analyzer~break_into_lines. - constants allowed_line_length type i value 255. - data(remaining_chunk) = strlen( code ). - while remaining_chunk > 0. - data(already_chopped_chars) = lines( code_lines ) * allowed_line_length. - data(chars_to_chop) = cond #( - when remaining_chunk > allowed_line_length - then allowed_line_length - else remaining_chunk ). - insert code+already_chopped_chars(chars_to_chop) into table code_lines. - remaining_chunk -= chars_to_chop. - endwhile. - endmethod. + METHOD /cc4a/if_abap_analyzer~break_into_lines. + code_lines = _break_into_lines( code = code break_at = max_line_length ). + ENDMETHOD. - method /cc4a/if_abap_analyzer~calculate_bracket_end. - if is_bracket( statement-tokens[ bracket_position ] ) ne /cc4a/if_abap_analyzer=>bracket_type-opening and - is_bracket( statement-tokens[ bracket_position ] ) ne /cc4a/if_abap_analyzer=>bracket_type-closing. - raise exception new /cc4a/cx_token_is_no_bracket( ). - endif. + METHOD /cc4a/if_abap_analyzer~calculate_bracket_end. + IF is_bracket( statement-tokens[ bracket_position ] ) NE /cc4a/if_abap_analyzer=>bracket_type-opening AND + is_bracket( statement-tokens[ bracket_position ] ) NE /cc4a/if_abap_analyzer=>bracket_type-closing. + RAISE EXCEPTION NEW /cc4a/cx_token_is_no_bracket( ). + ENDIF. - data(bracket_counter) = 1. - loop at statement-tokens assigning field-symbol() from bracket_position + 1. - data(idx) = sy-tabix. - case is_bracket( ). - when /cc4a/if_abap_analyzer=>bracket_type-opening. + DATA(bracket_counter) = 1. + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() FROM bracket_position + 1. + DATA(idx) = sy-tabix. + CASE is_bracket( ). + WHEN /cc4a/if_abap_analyzer=>bracket_type-opening. bracket_counter += 1. - when /cc4a/if_abap_analyzer=>bracket_type-closing. - if bracket_counter eq 1. + WHEN /cc4a/if_abap_analyzer=>bracket_type-closing. + IF bracket_counter EQ 1. end_of_bracket = idx. - exit. - endif. + EXIT. + ENDIF. bracket_counter -= 1. - when /cc4a/if_abap_analyzer=>bracket_type-clopening. - if bracket_counter eq 1. + WHEN /cc4a/if_abap_analyzer=>bracket_type-clopening. + IF bracket_counter EQ 1. end_of_bracket = idx. - exit. - endif. - endcase. - endloop. - if end_of_bracket is initial. + EXIT. + ENDIF. + ENDCASE. + ENDLOOP. + IF end_of_bracket IS INITIAL. end_of_bracket = -1. - endif. - endmethod. + ENDIF. + ENDMETHOD. - method /cc4a/if_abap_analyzer~find_clause_index. + METHOD /cc4a/if_abap_analyzer~find_clause_index. token_index = 0. - split condense( clause ) at space into table data(clauses). - if clauses is initial or clauses[ 1 ] is initial. - raise exception type /cc4a/cx_clause_is_initial. - endif. - loop at tokens transporting no fields from start_index - where references is initial - and lexeme = clauses[ 1 ]. + SPLIT condense( clause ) AT space INTO TABLE DATA(clauses). + IF clauses IS INITIAL OR clauses[ 1 ] IS INITIAL. + RAISE EXCEPTION TYPE /cc4a/cx_clause_is_initial. + ENDIF. + LOOP AT tokens TRANSPORTING NO FIELDS FROM start_index + WHERE references IS INITIAL + AND lexeme = clauses[ 1 ]. token_index = sy-tabix. - data(clause_index) = 2. - while clause_index <= lines( clauses ) - and token_index + clause_index - 1 <= lines( tokens ). - assign tokens[ token_index + clause_index - 1 ] to field-symbol(). - if -lexeme = clauses[ clause_index ] - and -references is initial. + DATA(clause_index) = 2. + WHILE clause_index <= lines( clauses ) + AND token_index + clause_index - 1 <= lines( tokens ). + ASSIGN tokens[ token_index + clause_index - 1 ] TO FIELD-SYMBOL(). + IF -lexeme = clauses[ clause_index ] + AND -references IS INITIAL. clause_index += 1. - else. + ELSE. token_index = 0. - exit. - endif. - endwhile. - if token_index <> 0. - return. - endif. - endloop. - endmethod. + EXIT. + ENDIF. + ENDWHILE. + IF token_index <> 0. + RETURN. + ENDIF. + ENDLOOP. + ENDMETHOD. - method /cc4a/if_abap_analyzer~find_key_words. + METHOD /cc4a/if_abap_analyzer~find_key_words. position = -1. - loop at statement-tokens transporting no fields where lexeme eq key_words[ 1 ] and references is initial. - data(token_index) = sy-tabix. - if lines( key_words ) eq 1. + LOOP AT statement-tokens TRANSPORTING NO FIELDS WHERE lexeme EQ key_words[ 1 ] AND references IS INITIAL. + DATA(token_index) = sy-tabix. + IF lines( key_words ) EQ 1. position = token_index. - return. - else. - loop at key_words assigning field-symbol() from 2. - data(next_token) = value #( statement-tokens[ token_index + sy-tabix - 1 ] optional ). - if next_token-references is not initial or next_token-lexeme ne . - exit. - elseif sy-tabix eq lines( key_words ). + RETURN. + ELSE. + LOOP AT key_words ASSIGNING FIELD-SYMBOL() FROM 2. + DATA(next_token) = VALUE #( statement-tokens[ token_index + sy-tabix - 1 ] OPTIONAL ). + IF next_token-references IS NOT INITIAL OR next_token-lexeme NE . + EXIT. + ELSEIF sy-tabix EQ lines( key_words ). position = token_index. - endif. - endloop. - endif. - endloop. - endmethod. + ENDIF. + ENDLOOP. + ENDIF. + ENDLOOP. + ENDMETHOD. - method /cc4a/if_abap_analyzer~flatten_tokens. - data(tokens_to_process) = tokens. - flat_statement = _flatten_tokens( changing tokens = tokens_to_process ). - endmethod. + METHOD /cc4a/if_abap_analyzer~flatten_tokens. + DATA(tokens_to_process) = tokens. + flat_statement = _flatten_tokens( CHANGING tokens = tokens_to_process ). + ENDMETHOD. - method /cc4a/if_abap_analyzer~is_bracket. - data(first_char) = token-lexeme(1). - data(offset_for_last_char) = strlen( token-lexeme ) - 1. - data(last_char) = cond #( when offset_for_last_char > 0 then token-lexeme+offset_for_last_char(1) else first_char ). - bracket_type = switch #( + METHOD /cc4a/if_abap_analyzer~is_bracket. + DATA(first_char) = token-lexeme(1). + DATA(offset_for_last_char) = strlen( token-lexeme ) - 1. + DATA(last_char) = COND #( WHEN offset_for_last_char > 0 THEN token-lexeme+offset_for_last_char(1) ELSE first_char ). + bracket_type = SWITCH #( last_char - when ')' then /cc4a/if_abap_analyzer=>bracket_type-closing - when '(' then switch #( + WHEN ')' THEN /cc4a/if_abap_analyzer=>bracket_type-closing + WHEN '(' THEN SWITCH #( first_char - when ')' then /cc4a/if_abap_analyzer=>bracket_type-clopening - else /cc4a/if_abap_analyzer=>bracket_type-opening ) - else /cc4a/if_abap_analyzer=>bracket_type-no_bracket ). - endmethod. + WHEN ')' THEN /cc4a/if_abap_analyzer=>bracket_type-clopening + ELSE /cc4a/if_abap_analyzer=>bracket_type-opening ) + ELSE /cc4a/if_abap_analyzer=>bracket_type-no_bracket ). + ENDMETHOD. - method /cc4a/if_abap_analyzer~is_logical_connective. + METHOD /cc4a/if_abap_analyzer~is_logical_connective. is_logical_connective = xsdbool( - token-references is initial and ( token-lexeme = 'AND' or token-lexeme = 'OR' or token-lexeme = 'EQUIV' ) ). - endmethod. + token-references IS INITIAL AND ( token-lexeme = 'AND' OR token-lexeme = 'OR' OR token-lexeme = 'EQUIV' ) ). + ENDMETHOD. - method /cc4a/if_abap_analyzer~is_token_keyword. + METHOD /cc4a/if_abap_analyzer~is_token_keyword. result = abap_true. - if token-references is not initial or token-lexeme <> keyword. + IF token-references IS NOT INITIAL OR token-lexeme <> keyword. result = abap_false. - endif. - endmethod. + ENDIF. + ENDMETHOD. - method /cc4a/if_abap_analyzer~negate_comparison_operator. - if not /cc4a/if_abap_analyzer~token_is_comparison_operator( value #( lexeme = comparison_operator ) ). - raise exception new /cc4a/cx_token_is_no_operator( ). - endif. + METHOD /cc4a/if_abap_analyzer~negate_comparison_operator. + IF NOT /cc4a/if_abap_analyzer~token_is_comparison_operator( VALUE #( lexeme = comparison_operator ) ). + RAISE EXCEPTION NEW /cc4a/cx_token_is_no_operator( ). + ENDIF. negated_comparison_operator = negations[ operator = comparison_operator ]-negated. - endmethod. + ENDMETHOD. - method /cc4a/if_abap_analyzer~parse_method_definition. - if statement-keyword <> 'METHODS' and statement-keyword <> 'CLASS-METHODS'. - return. - endif. - data(current_kind) = /cc4a/if_abap_analyzer=>parameter_kind-importing. + METHOD /cc4a/if_abap_analyzer~parse_method_definition. + IF statement-keyword <> 'METHODS' AND statement-keyword <> 'CLASS-METHODS'. + RETURN. + ENDIF. + DATA(current_kind) = /cc4a/if_abap_analyzer=>parameter_kind-importing. method_definition-name = statement-tokens[ 2 ]-lexeme. - if lines( statement-tokens ) >= 3 and statement-tokens[ 3 ]-lexeme = 'REDEFINITION'. + IF lines( statement-tokens ) >= 3 AND statement-tokens[ 3 ]-lexeme = 'REDEFINITION'. method_definition-is_redefinition = abap_true. - return. - endif. - loop at statement-tokens assigning field-symbol(). - data(token_idx) = sy-tabix. - if -references is initial. - case -lexeme. - when 'IMPORTING'. + RETURN. + ENDIF. + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL(). + DATA(token_idx) = sy-tabix. + IF -references IS INITIAL. + CASE -lexeme. + WHEN 'IMPORTING'. current_kind = /cc4a/if_abap_analyzer=>parameter_kind-importing. - when 'EXPORTING'. + WHEN 'EXPORTING'. current_kind = /cc4a/if_abap_analyzer=>parameter_kind-exporting. - when 'CHANGING'. + WHEN 'CHANGING'. current_kind = /cc4a/if_abap_analyzer=>parameter_kind-changing. - when 'RETURNING'. + WHEN 'RETURNING'. current_kind = /cc4a/if_abap_analyzer=>parameter_kind-returning. - when 'TYPE'. - assign statement-tokens[ token_idx - 1 ] to field-symbol(). - data(parameter_token_length) = strlen( -lexeme ). - if parameter_token_length > 10 and -lexeme(10) = 'REFERENCE('. - data(reference_offset) = parameter_token_length - 11. - insert value #( + WHEN 'TYPE'. + ASSIGN statement-tokens[ token_idx - 1 ] TO FIELD-SYMBOL(). + DATA(parameter_token_length) = strlen( -lexeme ). + IF parameter_token_length > 10 AND -lexeme(10) = 'REFERENCE('. + DATA(reference_offset) = parameter_token_length - 11. + INSERT VALUE #( name = -lexeme+10(reference_offset) - kind = current_kind ) into table method_definition-parameters. - elseif parameter_token_length > 6 and -lexeme(6) = 'VALUE('. - data(value_offset) = parameter_token_length - 7. - insert value #( + kind = current_kind ) INTO TABLE method_definition-parameters. + ELSEIF parameter_token_length > 6 AND -lexeme(6) = 'VALUE('. + DATA(value_offset) = parameter_token_length - 7. + INSERT VALUE #( name = -lexeme+6(value_offset) - kind = current_kind ) into table method_definition-parameters. - else. - insert value #( + kind = current_kind ) INTO TABLE method_definition-parameters. + ELSE. + INSERT VALUE #( name = -lexeme - kind = current_kind ) into table method_definition-parameters. - endif. - endcase. - endif. - endloop. - endmethod. + kind = current_kind ) INTO TABLE method_definition-parameters. + ENDIF. + ENDCASE. + ENDIF. + ENDLOOP. + ENDMETHOD. - method /cc4a/if_abap_analyzer~token_is_comparison_operator. - case token-lexeme. - when 'IS' or 'IN' or '>' or 'GT' or '<' or 'LT' or '>=' or 'GE' or '<=' or 'LE' or '=' or 'EQ' or '<>' or 'NE'. + METHOD /cc4a/if_abap_analyzer~token_is_comparison_operator. + CASE token-lexeme. + WHEN 'IS' OR 'IN' OR '>' OR 'GT' OR '<' OR 'LT' OR '>=' OR 'GE' OR '<=' OR 'LE' OR '=' OR 'EQ' OR '<>' OR 'NE'. is_operator = abap_true. - when others. + WHEN OTHERS. is_operator = abap_false. - endcase. - endmethod. + ENDCASE. + ENDMETHOD. - method class_constructor. - negations = value #( ( operator = '>' negated = '<=' ) + METHOD class_constructor. + negations = VALUE #( ( operator = '>' negated = '<=' ) ( operator = 'GT' negated = 'LE' ) ( operator = '<' negated = '>=' ) ( operator = 'LT' negated = 'GE' ) @@ -245,98 +245,177 @@ CLASS /CC4A/ABAP_ANALYZER IMPLEMENTATION. ( operator = 'LE' negated = 'GT' ) ( operator = '>=' negated = '<' ) ( operator = 'GE' negated = 'LT' ) ). - endmethod. + ENDMETHOD. - method create. - instance = new /cc4a/abap_analyzer( ). - endmethod. + METHOD create. + instance = NEW /cc4a/abap_analyzer( ). + ENDMETHOD. - method is_db_statement. - case statement-keyword. - when 'SELECT' or 'WITH' or 'DELETE' or 'UPDATE' or 'INSERT' or 'MODIFY' or 'READ' or 'LOOP' - or 'IMPORT' or 'EXPORT' or 'FETCH' or 'OPEN' or 'EXEC'. - if ( find_clause_index( tokens = statement-tokens clause = 'CONNECTION' ) <> 0 - and ( statement-keyword = 'DELETE' - or statement-keyword = 'UPDATE' - or statement-keyword = 'INSERT' - or statement-keyword = 'MODIFY' ) ). + METHOD is_db_statement. + CASE statement-keyword. + WHEN 'SELECT' OR 'WITH' OR 'DELETE' OR 'UPDATE' OR 'INSERT' OR 'MODIFY' OR 'READ' OR 'LOOP' + OR 'IMPORT' OR 'EXPORT' OR 'FETCH' OR 'OPEN' OR 'EXEC'. + IF ( find_clause_index( tokens = statement-tokens clause = 'CONNECTION' ) <> 0 + AND ( statement-keyword = 'DELETE' + OR statement-keyword = 'UPDATE' + OR statement-keyword = 'INSERT' + OR statement-keyword = 'MODIFY' ) ). result-is_db = abap_true. - if get_dbtab_name = abap_false. - return. - endif. - endif. - when others. - return. - endcase. - data(token_idx) = 2. - while lines( statement-tokens ) > token_idx and statement-tokens[ token_idx ]-lexeme cp '%_*(' - and statement-tokens[ token_idx ]-references is initial. + IF get_dbtab_name = abap_false. + RETURN. + ENDIF. + ENDIF. + WHEN OTHERS. + RETURN. + ENDCASE. + DATA(token_idx) = 2. + WHILE lines( statement-tokens ) > token_idx AND statement-tokens[ token_idx ]-lexeme CP '%_*(' + AND statement-tokens[ token_idx ]-references IS INITIAL. token_idx += 3. - endwhile. - data(analyzer) = new db_statement_analyzer( + ENDWHILE. + DATA(analyzer) = NEW db_statement_analyzer( statement = statement start_idx = token_idx analyzer = me include_subqueries = include_subqueries ). result = analyzer->analyze( ). - endmethod. - - method _flatten_tokens. - if not line_exists( tokens[ lexeme = '|' ] ). - flat = reduce #( init str = `` for tok in tokens next str = |{ str }{ tok-lexeme } | ). - else. - assign tokens[ 1 ] to field-symbol(). - while lines( tokens ) > 0. - if -lexeme = '|'. - delete tokens index 1. - flat &&= |\|{ _flatten_template( changing tokens = tokens ) }\||. - else. + ENDMETHOD. + + + METHOD _flatten_tokens. + IF NOT line_exists( tokens[ lexeme = '|' ] ). + flat = REDUCE #( INIT str = `` FOR tok IN tokens NEXT str = |{ str }{ tok-lexeme } | ). + ELSE. + ASSIGN tokens[ 1 ] TO FIELD-SYMBOL(). + WHILE lines( tokens ) > 0. + IF -lexeme = '|'. + DELETE tokens INDEX 1. + DATA(template) = _flatten_template( CHANGING tokens = tokens ). + flat &&= |\|{ template }\| |. + ELSE. flat &&= |{ -lexeme } |. - endif. - delete tokens index 1. - assign tokens[ 1 ] to . - endwhile. - endif. - endmethod. - - method _flatten_template. - data(inside_braces) = abap_true. - assign tokens[ 1 ] to field-symbol(). - while lines( tokens ) > 0. - case -lexeme. - when `|`. - delete tokens index 1. - if inside_braces = abap_true. - flat &&= |\|{ _flatten_template( changing tokens = tokens ) }\| |. - else. - return. - endif. - - when `{`. + DELETE tokens INDEX 1. + ENDIF. + ASSIGN tokens[ 1 ] TO . + ENDWHILE. + ENDIF. + DATA(len) = strlen( flat ) - 1. + IF flat+len(1) = ` `. + flat = flat(len). + ENDIF. + ENDMETHOD. + + METHOD _flatten_template. + DATA(inside_braces) = abap_false. + ASSIGN tokens[ 1 ] TO FIELD-SYMBOL(). + WHILE lines( tokens ) > 0. + CASE -lexeme. + WHEN `|`. + DELETE tokens INDEX 1. + IF inside_braces = abap_true. + flat &&= |\|{ _flatten_template( CHANGING tokens = tokens ) }\| |. + ELSE. + RETURN. + ENDIF. + + WHEN `{`. inside_braces = abap_true. flat &&= `{ `. - delete tokens index 1. + DELETE tokens INDEX 1. - when `}`. + WHEN `}`. inside_braces = abap_false. flat &&= ` }`. - delete tokens index 1. + DELETE tokens INDEX 1. - when others. - if -lexeme cp '`*`'. - data(token_inner_length) = strlen( -lexeme ) - 2. + WHEN OTHERS. + IF -lexeme CP '`*`'. + DATA(token_inner_length) = strlen( -lexeme ) - 2. flat &&= -lexeme+1(token_inner_length). - else. + ELSE. flat &&= |{ -lexeme } |. - endif. - delete tokens index 1. - - endcase. - assign tokens[ 1 ] to . - endwhile. - endmethod. - + ENDIF. + DELETE tokens INDEX 1. + + ENDCASE. + ASSIGN tokens[ 1 ] TO . + ENDWHILE. + ENDMETHOD. + + + + METHOD _break_into_lines. + DATA i TYPE i. + DATA in_sqmarks TYPE abap_bool. + DATA in_quotes TYPE abap_bool. + DATA in_template TYPE abap_bool. + DATA in_braces TYPE abap_bool. + DATA last_space TYPE i. + IF strlen( code ) <= break_at. + code_lines = VALUE #( ( code ) ). + RETURN. + ENDIF. + + WHILE i < strlen( code ). + CASE code+i(1). + WHEN '`'. + IF in_quotes = abap_false AND in_template = abap_false. + in_sqmarks = COND #( WHEN in_sqmarks = abap_false THEN abap_true ELSE abap_false ). + ENDIF. + WHEN `'`. + IF in_sqmarks = abap_false AND in_template = abap_false. + in_quotes = COND #( WHEN in_quotes = abap_false THEN abap_true ELSE abap_false ). + ENDIF. + WHEN '|'. + IF in_sqmarks = abap_false AND in_quotes = abap_false. + in_template = COND #( WHEN in_template = abap_false THEN abap_true ELSE abap_false ). + ENDIF. + WHEN `\`. + i += 1. + WHEN '{'. + IF in_template = abap_true AND in_sqmarks = abap_false AND in_quotes = abap_false. + in_braces = abap_true. + ENDIF. + WHEN '}'. + IF in_template = abap_true AND in_sqmarks = abap_false AND in_quotes = abap_false. + in_braces = abap_false. + ENDIF. + WHEN ` `. + IF in_sqmarks = abap_false AND in_quotes = abap_false AND + ( in_template = abap_false OR in_braces = abap_true ). + last_space = i. + ENDIF. + ENDCASE. + i += 1. + IF i > break_at. + IF last_space = 0. + RAISE EXCEPTION TYPE /cc4a/cx_line_break_impossible. + ELSE. + APPEND code(last_space) TO code_lines. + last_space += 1. + IF last_space >= strlen( code ). + RETURN. + ENDIF. + code = code+last_space. + IF strlen( code ) <= break_at. + APPEND code TO code_lines. + RETURN. + ENDIF. + i = 0. + last_space = 0. + in_sqmarks = abap_false. + in_quotes = abap_false. + in_template = abap_false. + ENDIF. + ENDIF. + ENDWHILE. + IF i > break_at. + RAISE EXCEPTION TYPE /cc4a/cx_line_break_impossible. + ELSE. + APPEND code TO code_lines. + ENDIF. + ENDMETHOD. ENDCLASS. diff --git a/src/core/#cc4a#abap_analyzer.clas.locals_imp.abap b/src/core/#cc4a#abap_analyzer.clas.locals_imp.abap index 73214e2..b6f11b3 100644 --- a/src/core/#cc4a#abap_analyzer.clas.locals_imp.abap +++ b/src/core/#cc4a#abap_analyzer.clas.locals_imp.abap @@ -1,515 +1,515 @@ *"* use this source file for the definition and implementation of *"* local helper classes, interface definitions and type *"* declarations -class db_statement_analyzer definition deferred. -class /cc4a/abap_analyzer definition local friends db_statement_analyzer. -class db_statement_analyzer definition final. - public section. +CLASS db_statement_analyzer DEFINITION DEFERRED. +CLASS /cc4a/abap_analyzer DEFINITION LOCAL FRIENDS db_statement_analyzer. +CLASS db_statement_analyzer DEFINITION FINAL. + PUBLIC SECTION. - methods constructor - importing - statement type if_ci_atc_source_code_provider=>ty_statement - start_idx type i - analyzer type ref to /cc4a/abap_analyzer - include_subqueries type abap_bool. - methods analyze - returning value(result) type /cc4a/if_abap_analyzer=>ty_db_statement. + METHODS constructor + IMPORTING + statement TYPE if_ci_atc_source_code_provider=>ty_statement + start_idx TYPE i + analyzer TYPE REF TO /cc4a/abap_analyzer + include_subqueries TYPE abap_bool. + METHODS analyze + RETURNING VALUE(result) TYPE /cc4a/if_abap_analyzer=>ty_db_statement. - private section. - methods get_result - returning value(result) type /cc4a/if_abap_analyzer=>ty_db_statement. - methods analyze_select. - methods analyze_with. - methods analyze_delete. - methods analyze_insert. - methods analyze_update. - methods analyze_modify. - methods analyze_open_cursor. - methods analyze_read_loop. - methods analyze_import. - methods analyze_export. - class-methods check_dbtab - importing token_db type if_ci_atc_source_code_provider=>ty_token - returning value(result) type /cc4a/if_abap_analyzer=>ty_db_statement. - constants tag_common_part type if_ci_atc_source_code_provider=>ty_compiler_reference_tag - value if_ci_atc_source_code_provider=>compiler_reference_kinds-common_part ##TYPE. - constants tag_data type if_ci_atc_source_code_provider=>ty_compiler_reference_tag - value if_ci_atc_source_code_provider=>compiler_reference_kinds-data ##TYPE. - constants tag_type type if_ci_atc_source_code_provider=>ty_compiler_reference_tag - value if_ci_atc_source_code_provider=>compiler_reference_kinds-type ##TYPE. - data statement type if_ci_atc_source_code_provider=>ty_statement. - data start_idx type i. - data analyzer type ref to /cc4a/abap_analyzer. - data token_idx type i. - data check_if_dbtab type abap_bool. - data is_db type abap_bool. - data dbtab_name type string. - data include_subqueries type abap_bool. -endclass. -class db_statement_analyzer implementation. + PRIVATE SECTION. + METHODS get_result + RETURNING VALUE(result) TYPE /cc4a/if_abap_analyzer=>ty_db_statement. + METHODS analyze_select. + METHODS analyze_with. + METHODS analyze_delete. + METHODS analyze_insert. + METHODS analyze_update. + METHODS analyze_modify. + METHODS analyze_open_cursor. + METHODS analyze_read_loop. + METHODS analyze_import. + METHODS analyze_export. + CLASS-METHODS check_dbtab + IMPORTING token_db TYPE if_ci_atc_source_code_provider=>ty_token + RETURNING VALUE(result) TYPE /cc4a/if_abap_analyzer=>ty_db_statement. + CONSTANTS tag_common_part TYPE if_ci_atc_source_code_provider=>ty_compiler_reference_tag + VALUE if_ci_atc_source_code_provider=>compiler_reference_kinds-common_part ##TYPE. + CONSTANTS tag_data TYPE if_ci_atc_source_code_provider=>ty_compiler_reference_tag + VALUE if_ci_atc_source_code_provider=>compiler_reference_kinds-data ##TYPE. + CONSTANTS tag_type TYPE if_ci_atc_source_code_provider=>ty_compiler_reference_tag + VALUE if_ci_atc_source_code_provider=>compiler_reference_kinds-type ##TYPE. + DATA statement TYPE if_ci_atc_source_code_provider=>ty_statement. + DATA start_idx TYPE i. + DATA analyzer TYPE REF TO /cc4a/abap_analyzer. + DATA token_idx TYPE i. + DATA check_if_dbtab TYPE abap_bool. + DATA is_db TYPE abap_bool. + DATA dbtab_name TYPE string. + DATA include_subqueries TYPE abap_bool. +ENDCLASS. +CLASS db_statement_analyzer IMPLEMENTATION. - method constructor. + METHOD constructor. me->statement = statement. me->start_idx = start_idx. me->analyzer = analyzer. token_idx = start_idx. check_if_dbtab = abap_true. me->include_subqueries = include_subqueries. - endmethod. + ENDMETHOD. - method analyze. - case statement-keyword. - when 'SELECT'. + METHOD analyze. + CASE statement-keyword. + WHEN 'SELECT'. analyze_select( ). - when 'WITH'. + WHEN 'WITH'. analyze_with( ). - when 'DELETE'. + WHEN 'DELETE'. analyze_delete( ). - when 'INSERT'. + WHEN 'INSERT'. analyze_insert( ). - when 'MODIFY'. + WHEN 'MODIFY'. analyze_modify( ). - when 'UPDATE'. + WHEN 'UPDATE'. analyze_update( ). - when 'OPEN'. + WHEN 'OPEN'. analyze_open_cursor( ). - when 'READ' or 'LOOP'. + WHEN 'READ' OR 'LOOP'. analyze_read_loop( ). - when 'IMPORT'. + WHEN 'IMPORT'. analyze_import( ). - when 'EXPORT'. + WHEN 'EXPORT'. analyze_export( ). - when 'FETCH'. - if analyzer->find_clause_index( tokens = statement-tokens clause = 'NEXT CURSOR' ) <> 0. + WHEN 'FETCH'. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'NEXT CURSOR' ) <> 0. result-is_db = abap_true. - endif. - return. - when 'EXEC'. + ENDIF. + RETURN. + WHEN 'EXEC'. result-is_db = abap_true. - return. - when others. + RETURN. + WHEN OTHERS. result-is_db = abap_false. - return. - endcase. + RETURN. + ENDCASE. result = get_result( ). - endmethod. + ENDMETHOD. - method get_result. + METHOD get_result. result-is_db = is_db. * special case for obsolete READ and LOOP statements - if dbtab_name is not initial and check_if_dbtab = abap_false. + IF dbtab_name IS NOT INITIAL AND check_if_dbtab = abap_false. result-dbtab = dbtab_name. result-is_db = is_db. - return. - endif. + RETURN. + ENDIF. - if token_idx > 0 and is_db = abap_true. - data(token_db) = statement-tokens[ token_idx ]. - if token_db is not initial. - if check_if_dbtab = abap_true. + IF token_idx > 0 AND is_db = abap_true. + DATA(token_db) = statement-tokens[ token_idx ]. + IF token_db IS NOT INITIAL. + IF check_if_dbtab = abap_true. result = check_dbtab( token_db ). - else. + ELSE. result-dbtab = token_db-lexeme. - endif. - endif. - if result-dbtab is not initial. - if result-dbtab(1) = '*'. + ENDIF. + ENDIF. + IF result-dbtab IS NOT INITIAL. + IF result-dbtab(1) = '*'. result-dbtab = result-dbtab+1. - endif. - if result-dbtab(1) <> '('. - split result-dbtab at '(' into result-dbtab data(dummy) ##NEEDED. - endif. - split result-dbtab at '\' into result-dbtab dummy. - endif. - endif. - if include_subqueries = abap_true and statement-keyword <> 'WITH'. - data(sub_idx) = token_idx. - do. + ENDIF. + IF result-dbtab(1) <> '('. + SPLIT result-dbtab AT '(' INTO result-dbtab DATA(dummy) ##NEEDED. + ENDIF. + SPLIT result-dbtab AT '\' INTO result-dbtab dummy. + ENDIF. + ENDIF. + IF include_subqueries = abap_true AND statement-keyword <> 'WITH'. + DATA(sub_idx) = token_idx. + DO. sub_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'SELECT' start_index = sub_idx ). - if sub_idx < 3. - exit. - else. - data(substatement) = statement. + IF sub_idx < 3. + EXIT. + ELSE. + DATA(substatement) = statement. substatement-keyword = 'SELECT'. - delete substatement-tokens to sub_idx - 1. - data(result_sub) = analyzer->is_db_statement( + DELETE substatement-tokens TO sub_idx - 1. + DATA(result_sub) = analyzer->is_db_statement( statement = substatement include_subqueries = abap_true get_dbtab_name = abap_true ). - if result_sub-is_db = abap_true. + IF result_sub-is_db = abap_true. result-is_db = abap_true. result-dbtab_subquery = result_sub-dbtab. - exit. - endif. + EXIT. + ENDIF. sub_idx += 1. - endif. - enddo. - endif. + ENDIF. + ENDDO. + ENDIF. - endmethod. + ENDMETHOD. - method check_dbtab. + METHOD check_dbtab. result-is_db = abap_false. - if token_db-lexeme(1) = '@' - or ( token_db-references is initial and token_db-lexeme(1) <> '(' ). + IF token_db-lexeme(1) = '@' + OR ( token_db-references IS INITIAL AND token_db-lexeme(1) <> '(' ). result-is_db = abap_false. - elseif token_db-lexeme np '(*)'. - assign token_db-references[ 1 ] to field-symbol(). - case -kind. - when if_ci_atc_source_code_provider=>compiler_reference_kinds-type. - if lines( token_db-references ) > 1. + ELSEIF token_db-lexeme NP '(*)'. + ASSIGN token_db-references[ 1 ] TO FIELD-SYMBOL(). + CASE -kind. + WHEN if_ci_atc_source_code_provider=>compiler_reference_kinds-type. + IF lines( token_db-references ) > 1. result-is_db = abap_false. * no symbol - so try okay - elseif -full_name(3) = '\' && tag_type. + ELSEIF -full_name(3) = |\\{ TAG_TYPE }|. result-is_db = abap_true. - endif. - when if_ci_atc_source_code_provider=>compiler_reference_kinds-data. + ENDIF. + WHEN if_ci_atc_source_code_provider=>compiler_reference_kinds-data. result-is_db = abap_false. - if token_db-references[ 1 ]-full_name(3) = '\' && tag_common_part. - split token_db-references[ 1 ]-full_name+4 at |\\{ tag_data }:| into data(l_name1) data(l_name2). - if l_name1 = l_name2. + IF token_db-references[ 1 ]-full_name(3) = |\\{ TAG_COMMON_PART }|. + SPLIT token_db-references[ 1 ]-full_name+4 AT |\\{ tag_data }:| INTO DATA(l_name1) DATA(l_name2). + IF l_name1 = l_name2. result-is_db = abap_true. - endif. - elseif token_db-references[ 1 ]-full_name np |*\\{ tag_common_part }:*| - and lines( token_db-references ) = 2 - and token_db-references[ 2 ]-kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-type - and token_db-references[ 2 ]-full_name+4 np '*\*'. + ENDIF. + ELSEIF token_db-references[ 1 ]-full_name NP |*\\{ tag_common_part }:*| + AND lines( token_db-references ) = 2 + AND token_db-references[ 2 ]-kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-type + AND token_db-references[ 2 ]-full_name+4 NP '*\*'. result-is_db = abap_true. - endif. - when others. + ENDIF. + WHEN OTHERS. result-is_db = abap_false. - endcase. - endif. - if result-is_db = abap_true. + ENDCASE. + ENDIF. + IF result-is_db = abap_true. result-dbtab = token_db-lexeme. - endif. - endmethod. + ENDIF. + ENDMETHOD. - method analyze_select. + METHOD analyze_select. is_db = abap_false. check_if_dbtab = abap_false. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'FROM' start_index = start_idx ). - if token_idx <= 1. - return. - endif. - assign statement-tokens[ token_idx - 1 ] to field-symbol(). - if sy-subrc = 0 and -lexeme = 'CONNECTION' and -references is initial. + IF token_idx <= 1. + RETURN. + ENDIF. + ASSIGN statement-tokens[ token_idx - 1 ] TO FIELD-SYMBOL(). + IF sy-subrc = 0 AND -lexeme = 'CONNECTION' AND -references IS INITIAL. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'FROM' start_index = token_idx + 1 ). - endif. + ENDIF. token_idx += 1. - while statement-tokens[ token_idx ]-lexeme = '('. + WHILE statement-tokens[ token_idx ]-lexeme = '('. token_idx += 1. - endwhile. - while statement-tokens[ token_idx ]-lexeme cp 'HIERARCHY*(' and statement-tokens[ token_idx ]-references is initial. - if analyzer->is_token_keyword( token = statement-tokens[ token_idx + 1 ] keyword = 'SOURCE' ). + ENDWHILE. + WHILE statement-tokens[ token_idx ]-lexeme CP 'HIERARCHY*(' AND statement-tokens[ token_idx ]-references IS INITIAL. + IF analyzer->is_token_keyword( token = statement-tokens[ token_idx + 1 ] keyword = 'SOURCE' ). token_idx += 2. - else. - exit. - endif. - endwhile. - if statement-tokens[ token_idx ]-lexeme(1) = '@'. + ELSE. + EXIT. + ENDIF. + ENDWHILE. + IF statement-tokens[ token_idx ]-lexeme(1) = '@'. * check for joined tables - do. + DO. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'JOIN' start_index = token_idx ). - if token_idx = 0. - return. - else. - if statement-tokens[ token_idx + 1 ]-lexeme(1) <> '@'. + IF token_idx = 0. + RETURN. + ELSE. + IF statement-tokens[ token_idx + 1 ]-lexeme(1) <> '@'. token_idx += 1. is_db = abap_true. - return. - else. - continue. - endif. - endif. - enddo. - else. + RETURN. + ELSE. + CONTINUE. + ENDIF. + ENDIF. + ENDDO. + ELSE. is_db = abap_true. - endif. - endmethod. + ENDIF. + ENDMETHOD. - method analyze_with. + METHOD analyze_with. check_if_dbtab = abap_false. is_db = abap_false. token_idx = start_idx. - do. + DO. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'SELECT' start_index = token_idx ). - if token_idx = 0. - return. - endif. + IF token_idx = 0. + RETURN. + ENDIF. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'FROM' start_index = token_idx ). - if token_idx = 0. - return. - endif. + IF token_idx = 0. + RETURN. + ENDIF. token_idx += 1. - while statement-tokens[ token_idx ]-lexeme cp 'HIERARCHY*(' - and statement-tokens[ token_idx ]-references is initial. - if analyzer->is_token_keyword( token = statement-tokens[ token_idx + 1 ] keyword = 'SOURCE' ). + WHILE statement-tokens[ token_idx ]-lexeme CP 'HIERARCHY*(' + AND statement-tokens[ token_idx ]-references IS INITIAL. + IF analyzer->is_token_keyword( token = statement-tokens[ token_idx + 1 ] keyword = 'SOURCE' ). token_idx += 2. - else. - exit. - endif. - endwhile. - if statement-tokens[ token_idx ]-lexeme cp 'HIERARCHY*(' and statement-tokens[ token_idx ]-references is initial. - continue. - endif. - if statement-tokens[ token_idx ]-lexeme(1) <> '@' and statement-tokens[ token_idx ]-lexeme(1) <> '+'. + ELSE. + EXIT. + ENDIF. + ENDWHILE. + IF statement-tokens[ token_idx ]-lexeme CP 'HIERARCHY*(' AND statement-tokens[ token_idx ]-references IS INITIAL. + CONTINUE. + ENDIF. + IF statement-tokens[ token_idx ]-lexeme(1) <> '@' AND statement-tokens[ token_idx ]-lexeme(1) <> '+'. is_db = abap_true. - exit. - endif. - enddo. - endmethod. + EXIT. + ENDIF. + ENDDO. + ENDMETHOD. - method analyze_delete. + METHOD analyze_delete. check_if_dbtab = abap_true. - if analyzer->find_clause_index( tokens = statement-tokens clause = 'CONNECTION' ) <> 0. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'CONNECTION' ) <> 0. is_db = abap_true. check_if_dbtab = abap_false. - endif. + ENDIF. token_idx = start_idx. - assign statement-tokens[ token_idx ] to field-symbol(). - if -references is initial and -lexeme(1) <> '('. - case -lexeme. - when 'ADJACENT' or 'REPORT' or 'TEXTPOOL' or 'DYNPRO' or 'DATASET' or 'TABLE'. - return. - when 'FROM'. + ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). + IF -references IS INITIAL AND -lexeme(1) <> '('. + CASE -lexeme. + WHEN 'ADJACENT' OR 'REPORT' OR 'TEXTPOOL' OR 'DYNPRO' OR 'DATASET' OR 'TABLE'. + RETURN. + WHEN 'FROM'. token_idx += 1. - assign statement-tokens[ token_idx ] to field-symbol(). - if -references is initial and -lexeme(1) <> '('. - case -lexeme. - when 'MEMORY' or 'SHARED'. - return. - when 'DATABASE'. + ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). + IF -references IS INITIAL AND -lexeme(1) <> '('. + CASE -lexeme. + WHEN 'MEMORY' OR 'SHARED'. + RETURN. + WHEN 'DATABASE'. is_db = abap_true. token_idx += 1. check_if_dbtab = abap_false. - endcase. - else. + ENDCASE. + ELSE. is_db = abap_true. - endif. - endcase. - elseif lines( statement-tokens ) = token_idx. + ENDIF. + ENDCASE. + ELSEIF lines( statement-tokens ) = token_idx. is_db = abap_true. - elseif statement-tokens[ 3 ]-lexeme = 'INDEX' and statement-tokens[ 3 ]-references is initial. - return. - else. + ELSEIF statement-tokens[ 3 ]-lexeme = 'INDEX' AND statement-tokens[ 3 ]-references IS INITIAL. + RETURN. + ELSE. is_db = abap_true. - endif. - if is_db = abap_true and statement-tokens[ token_idx ]-lexeme(1) = '('. + ENDIF. + IF is_db = abap_true AND statement-tokens[ token_idx ]-lexeme(1) = '('. check_if_dbtab = abap_false. - endif. - endmethod. + ENDIF. + ENDMETHOD. - method analyze_insert. + METHOD analyze_insert. check_if_dbtab = abap_true. - if analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO TABLE' ) <> 0 - or analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 - or analyzer->find_clause_index( tokens = statement-tokens clause = 'REFERENCE INTO' ) <> 0 - or analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL LINE' ) <> 0 - or analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0. - return. - endif. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO TABLE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'REFERENCE INTO' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL LINE' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0. + RETURN. + ENDIF. token_idx = start_idx. - assign statement-tokens[ token_idx ] to field-symbol(). - if lines( statement-tokens ) = token_idx and -references is not initial. + ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). + IF lines( statement-tokens ) = token_idx AND -references IS NOT INITIAL. is_db = abap_true. - endif. - if -references is initial and -lexeme(1) <> '('. - case -lexeme. - when 'REPORT' or 'TEXTPOOL' or 'INITIAL' or 'LINES'. - return. - when 'INTO'. + ENDIF. + IF -references IS INITIAL AND -lexeme(1) <> '('. + CASE -lexeme. + WHEN 'REPORT' OR 'TEXTPOOL' OR 'INITIAL' OR 'LINES'. + RETURN. + WHEN 'INTO'. is_db = abap_true. token_idx += 1. check_if_dbtab = abap_false. - endcase. - else. - if analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ) <> 0 - and analyzer->find_clause_index( tokens = statement-tokens clause = 'VALUES' ) = 0. - return. - endif. + ENDCASE. + ELSE. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ) <> 0 + AND analyzer->find_clause_index( tokens = statement-tokens clause = 'VALUES' ) = 0. + RETURN. + ENDIF. is_db = abap_true. - if statement-tokens[ token_idx ]-lexeme(1) = '('. + IF statement-tokens[ token_idx ]-lexeme(1) = '('. check_if_dbtab = abap_false. - endif. - endif. - endmethod. + ENDIF. + ENDIF. + ENDMETHOD. - method analyze_modify. + METHOD analyze_modify. * modify dbtab (from...) token_idx = start_idx. - assign statement-tokens[ token_idx ] to field-symbol(). - if -references is initial and -lexeme(1) <> '('. - return. - endif. - if analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 - or analyzer->find_clause_index( tokens = statement-tokens clause = 'USING KEY' ) <> 0 - or analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' ) <> 0. - return. - endif. + ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). + IF -references IS INITIAL AND -lexeme(1) <> '('. + RETURN. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'USING KEY' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' ) <> 0. + RETURN. + ENDIF. is_db = abap_true. - if statement-tokens[ token_idx ]-lexeme(1) = '('. + IF statement-tokens[ token_idx ]-lexeme(1) = '('. check_if_dbtab = abap_false. - endif. - if lines( statement-tokens ) = token_idx. - return. - elseif analyzer->find_clause_index( tokens = statement-tokens clause = 'VERSION' + ENDIF. + IF lines( statement-tokens ) = token_idx. + RETURN. + ELSEIF analyzer->find_clause_index( tokens = statement-tokens clause = 'VERSION' start_index = token_idx + 1 ) <> 0. token_idx = lines( statement-tokens ). check_if_dbtab = abap_false. - endif. - endmethod. + ENDIF. + ENDMETHOD. - method analyze_update. + METHOD analyze_update. token_idx = start_idx. - assign statement-tokens[ token_idx ] to field-symbol(). - if -references is not initial or -lexeme(1) = '('. + ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). + IF -references IS NOT INITIAL OR -lexeme(1) = '('. is_db = abap_true. - endif. - if analyzer->find_clause_index( tokens = statement-tokens clause = 'SET' + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'SET' start_index = token_idx + 1 ). check_if_dbtab = abap_false. - elseif -lexeme(1) = '('. + ELSEIF -lexeme(1) = '('. check_if_dbtab = abap_false. - endif. - endmethod. + ENDIF. + ENDMETHOD. - method analyze_open_cursor. - data(found) = 0. - loop at statement-tokens assigning field-symbol() - where references is initial. + METHOD analyze_open_cursor. + DATA(found) = 0. + LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() + WHERE references IS INITIAL. token_idx = sy-tabix. - case -lexeme. - when 'CURSOR'. + CASE -lexeme. + WHEN 'CURSOR'. found = 1. - when 'FOR'. - if found = 1. + WHEN 'FOR'. + IF found = 1. found = 2. - endif. - when 'SELECT'. - if found = 2. + ENDIF. + WHEN 'SELECT'. + IF found = 2. found = 3. - endif. - when 'FROM'. - if found = 3. + ENDIF. + WHEN 'FROM'. + IF found = 3. found = 4. - exit. - endif. - endcase. - endloop. - if found = 4. + EXIT. + ENDIF. + ENDCASE. + ENDLOOP. + IF found = 4. token_idx += 1. - while statement-tokens[ token_idx ]-lexeme = '('. + WHILE statement-tokens[ token_idx ]-lexeme = '('. token_idx += 1. - endwhile. - if statement-tokens[ token_idx ]-lexeme(1) = '@'. - return. - endif. + ENDWHILE. + IF statement-tokens[ token_idx ]-lexeme(1) = '@'. + RETURN. + ENDIF. is_db = abap_true. check_if_dbtab = abap_false. - endif. - endmethod. + ENDIF. + ENDMETHOD. - method analyze_read_loop. + METHOD analyze_read_loop. check_if_dbtab = abap_false. - if lines( statement-tokens ) = 1. - return. - endif. - if analyzer->find_clause_index( tokens = statement-tokens clause = 'VERSION' ) <> 0. + IF lines( statement-tokens ) = 1. + RETURN. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'VERSION' ) <> 0. * name of dbtab is determined in token after VERSION, dynamically: unknown table is_db = abap_true. - clear dbtab_name. + CLEAR dbtab_name. token_idx = 0. - return. - endif. - case statement-keyword. - when 'LOOP'. - if statement-tokens[ 2 ]-lexeme <> 'AT'. - return. - endif. - if lines( statement-tokens ) <> 3 or statement-tokens[ 3 ]-references is initial. - return. - endif. - when 'READ'. - if statement-tokens[ 2 ]-lexeme <> 'TABLE'. - return. - endif. - if analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 - or analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ) <> 0 - or analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0. - return. - endif. + RETURN. + ENDIF. + CASE statement-keyword. + WHEN 'LOOP'. + IF statement-tokens[ 2 ]-lexeme <> 'AT'. + RETURN. + ENDIF. + IF lines( statement-tokens ) <> 3 OR statement-tokens[ 3 ]-references IS INITIAL. + RETURN. + ENDIF. + WHEN 'READ'. + IF statement-tokens[ 2 ]-lexeme <> 'TABLE'. + RETURN. + ENDIF. + IF analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ) <> 0 + OR analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0. + RETURN. + ENDIF. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'SEARCH' ). - if token_idx <> 0 and lines( statement-tokens ) > token_idx. - case statement-tokens[ token_idx + 1 ]-lexeme. - when 'FKEQ' or 'FKGE' or 'GKEQ' or 'GKGE'. - if statement-tokens[ token_idx + 1 ]-references is initial. + IF token_idx <> 0 AND lines( statement-tokens ) > token_idx. + CASE statement-tokens[ token_idx + 1 ]-lexeme. + WHEN 'FKEQ' OR 'FKGE' OR 'GKEQ' OR 'GKGE'. + IF statement-tokens[ token_idx + 1 ]-references IS INITIAL. is_db = abap_true. - endif. - when others. - return. - endcase. - endif. - endcase. + ENDIF. + WHEN OTHERS. + RETURN. + ENDCASE. + ENDIF. + ENDCASE. token_idx = 0. - data(token_db) = statement-tokens[ 3 ]. - data(l_name) = token_db-lexeme. - if l_name(1) = '*'. + DATA(token_db) = statement-tokens[ 3 ]. + DATA(l_name) = token_db-lexeme. + IF l_name(1) = '*'. l_name = l_name+1. - endif. - if strlen( l_name ) > 5. - return. - endif. + ENDIF. + IF strlen( l_name ) > 5. + RETURN. + ENDIF. * must be common part if dbtab loop or read - read table token_db-references index 1 into data(l_reference). - if sy-subrc <> 0. - return. - endif. - data(l_full_name) = |\\{ tag_common_part }:{ token_db-lexeme }\\{ tag_data }:{ token_db-lexeme }|. - if l_reference-full_name <> l_full_name. - return. - endif. + READ TABLE token_db-references INDEX 1 INTO DATA(l_reference). + IF sy-subrc <> 0. + RETURN. + ENDIF. + DATA(l_full_name) = |\\{ tag_common_part }:{ token_db-lexeme }\\{ tag_data }:{ token_db-lexeme }|. + IF l_reference-full_name <> l_full_name. + RETURN. + ENDIF. is_db = abap_true. dbtab_name = l_name. - if dbtab_name(1) = '*'. + IF dbtab_name(1) = '*'. dbtab_name = dbtab_name+1. - endif. - if dbtab_name(1) <> 'T'. + ENDIF. + IF dbtab_name(1) <> 'T'. dbtab_name = |T{ dbtab_name+1 }|. - endif. + ENDIF. check_if_dbtab = abap_false. - endmethod. + ENDMETHOD. - method analyze_import. + METHOD analyze_import. * import... from database dbtab id ... token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'FROM DATABASE' ). - if token_idx = 0. - return. - endif. + IF token_idx = 0. + RETURN. + ENDIF. token_idx += 2. - if analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'ID' ) = 0. - return. - endif. + IF analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'ID' ) = 0. + RETURN. + ENDIF. is_db = abap_true. check_if_dbtab = abap_false. - endmethod. + ENDMETHOD. - method analyze_export. + METHOD analyze_export. * export... to database dbtab id ... token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'TO DATABASE' ). - if token_idx = 0. - return. - endif. + IF token_idx = 0. + RETURN. + ENDIF. token_idx += 2. - if analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'ID' ) = 0. - return. - endif. + IF analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'ID' ) = 0. + RETURN. + ENDIF. is_db = abap_true. check_if_dbtab = abap_false. - endmethod. -endclass. + ENDMETHOD. +ENDCLASS. diff --git a/src/core/#cc4a#abap_analyzer.clas.testclasses.abap b/src/core/#cc4a#abap_analyzer.clas.testclasses.abap index 1941fde..f34ed03 100644 --- a/src/core/#cc4a#abap_analyzer.clas.testclasses.abap +++ b/src/core/#cc4a#abap_analyzer.clas.testclasses.abap @@ -1,236 +1,237 @@ -class key_words definition final for testing - duration short - risk level harmless. - - private section. - methods statement_is_all_keywords for testing raising cx_static_check. - methods identifiers_like_keywords for testing raising cx_static_check. - methods test_find_clause_index for testing. -endclass. - -class key_words implementation. - method statement_is_all_keywords. - data(test_statement) = value if_ci_atc_source_code_provider=>ty_statement( - tokens = value #( for i = 1 then i + 1 until i >= 10 ( lexeme = |{ i }| ) ) ). - data(analyzer) = /cc4a/abap_analyzer=>create( ). +CLASS key_words DEFINITION FINAL FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS statement_is_all_keywords FOR TESTING RAISING cx_static_check. + METHODS identifiers_like_keywords FOR TESTING RAISING cx_static_check. + METHODS test_find_clause_index FOR TESTING. +ENDCLASS. + +CLASS key_words IMPLEMENTATION. + METHOD statement_is_all_keywords. + DATA(test_statement) = VALUE if_ci_atc_source_code_provider=>ty_statement( + tokens = VALUE #( FOR i = 1 THEN i + 1 UNTIL i >= 10 ( lexeme = |{ i }| ) ) ). + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `3` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `3` ) ) statement = test_statement ) exp = 3 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `3` ) ( `4` ) ( `5` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `3` ) ( `4` ) ( `5` ) ) statement = test_statement ) exp = 3 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `1` ) ( `5` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `1` ) ( `5` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `8` ) ( `9` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `8` ) ( `9` ) ) statement = test_statement ) exp = 8 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `6` ) ( `8` ) ( `9` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `6` ) ( `8` ) ( `9` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `5` ) ( `3` ) ( `4` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `5` ) ( `3` ) ( `4` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( act = analyzer->find_key_words( - key_words = value #( ( `1` ) ( `2` ) ( `3` ) ( `4` ) ) + key_words = VALUE #( ( `1` ) ( `2` ) ( `3` ) ( `4` ) ) statement = test_statement ) exp = 1 ). - endmethod. + ENDMETHOD. - method identifiers_like_keywords. - data(test_statement) = value if_ci_atc_source_code_provider=>ty_statement( - tokens = value #( + METHOD identifiers_like_keywords. + DATA(test_statement) = VALUE if_ci_atc_source_code_provider=>ty_statement( + tokens = VALUE #( ( lexeme = `1` ) ( lexeme = `2` ) - ( lexeme = `3` references = value #( ( full_name = `FOO` ) ) ) + ( lexeme = `3` references = VALUE #( ( full_name = `FOO` ) ) ) ( lexeme = `4` ) ) ). - data(analyzer) = /cc4a/abap_analyzer=>create( ). + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `2` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `2` ) ) statement = test_statement ) exp = 2 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `3` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `3` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `2` ) ( `3` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `2` ) ( `3` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `2` ) ( `3` ) ( `4` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `2` ) ( `3` ) ( `4` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = value #( ( `1` ) ( `2` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = VALUE #( ( `1` ) ( `2` ) ) statement = test_statement ) exp = 1 ). - endmethod. + ENDMETHOD. - method test_find_clause_index. - data(test_tokens) = value if_ci_atc_source_code_provider=>ty_tokens( + METHOD test_find_clause_index. + DATA(test_tokens) = VALUE if_ci_atc_source_code_provider=>ty_tokens( ( lexeme = '1' ) ( lexeme = '2' ) ( lexeme = '3' ) ( lexeme = '4' ) ( lexeme = '5' ) ( lexeme = '6' ) ( lexeme = '7' ) ( lexeme = '8' ) ( lexeme = '9' ) ( lexeme = '10' ) ). - data(test_clause) = `5 6 7`. - data(index) = /cc4a/abap_analyzer=>create( )->find_clause_index( tokens = test_tokens clause = test_clause ). + DATA(test_clause) = `5 6 7`. + DATA(index) = /cc4a/abap_analyzer=>create( )->find_clause_index( tokens = test_tokens clause = test_clause ). cl_abap_unit_assert=>assert_equals( act = index exp = 5 ). - test_tokens = value #( ( lexeme = 'A' ) ( lexeme = 'B' ) ( lexeme = '3' ) + test_tokens = VALUE #( ( lexeme = 'A' ) ( lexeme = 'B' ) ( lexeme = '3' ) ( lexeme = 'A' ) ( lexeme = 'B' ) ( lexeme = 'C' ) ( lexeme = 'A' ) ( lexeme = 'B' ) ( lexeme = 'C' ) ( lexeme = 'D' ) ). index = /cc4a/abap_analyzer=>create( )->find_clause_index( tokens = test_tokens clause = `A B C D` ). cl_abap_unit_assert=>assert_equals( act = index exp = 7 ). - try. + TRY. index = /cc4a/abap_analyzer=>create( )->find_clause_index( tokens = test_tokens clause = ` ` ). cl_abap_unit_assert=>fail( ). - catch /cc4a/cx_clause_is_initial. - endtry. - endmethod. -endclass. + CATCH /cc4a/cx_clause_is_initial. + ENDTRY. + ENDMETHOD. +ENDCLASS. -class lcl_atc_check_db_stmt definition final. +CLASS lcl_atc_check_db_stmt DEFINITION FINAL. - public section. - interfaces if_ci_atc_check. + PUBLIC SECTION. + INTERFACES if_ci_atc_check. - private section. - data code_provider type ref to if_ci_atc_source_code_provider. - data assistant_factory type ref to cl_ci_atc_assistant_factory ##needed. + PRIVATE SECTION. + DATA code_provider TYPE REF TO if_ci_atc_source_code_provider. + DATA assistant_factory TYPE REF TO cl_ci_atc_assistant_factory ##needed. - methods analyze_procedure - importing !procedure type if_ci_atc_source_code_provider=>ty_procedure - returning value(findings) type if_ci_atc_check=>ty_findings. -endclass. + METHODS analyze_procedure + IMPORTING !procedure TYPE if_ci_atc_source_code_provider=>ty_procedure + RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. +ENDCLASS. -class lcl_atc_check_db_stmt implementation. - method if_ci_atc_check~get_meta_data. +CLASS lcl_atc_check_db_stmt IMPLEMENTATION. + METHOD if_ci_atc_check~get_meta_data. meta_data = /cc4a/check_meta_data=>create( - value #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs + VALUE #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs remote_enablement = /cc4a/check_meta_data=>remote_enablement-unconditional - finding_codes = value #( ( code = 'SELECT' ) ( code = 'WITH' ) ( code = 'INSERT' ) + finding_codes = VALUE #( ( code = 'SELECT' ) ( code = 'WITH' ) ( code = 'INSERT' ) ( code = 'DELETE' ) ( code = 'UPDATE' ) ( code = 'MODIFY' ) ( code = 'OPEN' ) ( code = 'EXEC' ) ( code = 'LOOP' ) ( code = 'READ' ) ( code = 'IMPORT' ) ( code = 'EXPORT' ) ) ) ). - endmethod. + ENDMETHOD. - method if_ci_atc_check~run. + METHOD if_ci_atc_check~run. code_provider = data_provider->get_code_provider( ). - data(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). - loop at procedures->* assigning field-symbol(). - insert lines of analyze_procedure( ) into table findings. - endloop. - endmethod. + DATA(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). + LOOP AT procedures->* ASSIGNING FIELD-SYMBOL(). + INSERT LINES OF analyze_procedure( ) INTO TABLE findings. + ENDLOOP. + ENDMETHOD. - method if_ci_atc_check~set_assistant_factory. + METHOD if_ci_atc_check~set_assistant_factory. assistant_factory = factory. - endmethod. + ENDMETHOD. - method if_ci_atc_check~verify_prerequisites ##needed. - endmethod. + METHOD if_ci_atc_check~verify_prerequisites ##needed. + ENDMETHOD. - method analyze_procedure. - data(analyzer) = /cc4a/abap_analyzer=>create( ). - loop at procedure-statements assigning field-symbol(). - data(result) = analyzer->is_db_statement( ). - if result-is_db = abap_true. - insert value #( + METHOD analyze_procedure. + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). + LOOP AT procedure-statements ASSIGNING FIELD-SYMBOL(). + DATA(result) = analyzer->is_db_statement( ). + IF result-is_db = abap_true. + INSERT VALUE #( code = -keyword - parameters = value #( param_1 = result-dbtab param_2 = result-dbtab_subquery ) - location = value #( object = code_provider->get_statement_location( )-object + parameters = VALUE #( param_1 = result-dbtab param_2 = result-dbtab_subquery ) + location = VALUE #( object = code_provider->get_statement_location( )-object position = code_provider->get_statement_location( )-position ) - checksum = code_provider->get_statement_checksum( ) ) into table findings. - endif. - endloop. - endmethod. -endclass. - -class db_stmt definition final for testing - duration short - risk level harmless. - - private section. - constants test_class type c length 30 value '/CC4A/TEST_FOR_DB_STATEMENTS'. - - methods execute_test_class for testing raising cx_static_check. -endclass. - -class db_stmt implementation. - method execute_test_class. - data(dyn) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'DYN' ) ). - data(mixed) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'MIXED' ) ). + checksum = code_provider->get_statement_checksum( ) ) INTO TABLE findings. + ENDIF. + ENDLOOP. + ENDMETHOD. +ENDCLASS. + +CLASS db_stmt DEFINITION FINAL FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. + + PRIVATE SECTION. + CONSTANTS test_class TYPE c LENGTH 30 VALUE '/CC4A/TEST_FOR_DB_STATEMENTS'. + + METHODS execute_test_class FOR TESTING RAISING cx_static_check. +ENDCLASS. + +CLASS db_stmt IMPLEMENTATION. + METHOD execute_test_class. + DATA(dyn) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'DYN' ) ). + DATA(mixed) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'MIXED' ) ). cl_ci_atc_unit_driver=>create_asserter( )->check_and_assert( - check = new lcl_atc_check_db_stmt( ) - object = value #( type = 'CLAS' name = test_class ) - expected_findings = value #( - ( code = 'DELETE' location = value #( object = dyn position = value #( line = 6 column = 4 ) ) ) - ( code = 'SELECT' location = value #( object = dyn position = value #( line = 9 column = 6 ) ) ) - ( code = 'SELECT' location = value #( object = dyn position = value #( line = 12 column = 6 ) ) ) - ( code = 'SELECT' location = value #( object = dyn position = value #( line = 14 column = 4 ) ) ) - ( code = 'SELECT' location = value #( object = dyn position = value #( line = 15 column = 4 ) ) ) - ( code = 'SELECT' location = value #( object = dyn position = value #( line = 17 column = 4 ) ) ) - ( code = 'INSERT' location = value #( object = dyn position = value #( line = 18 column = 4 ) ) ) - ( code = 'INSERT' location = value #( object = dyn position = value #( line = 19 column = 4 ) ) ) - ( code = 'UPDATE' location = value #( object = dyn position = value #( line = 20 column = 4 ) ) ) - ( code = 'UPDATE' location = value #( object = dyn position = value #( line = 21 column = 4 ) ) ) - ( code = 'MODIFY' location = value #( object = dyn position = value #( line = 22 column = 4 ) ) ) - ( code = 'DELETE' location = value #( object = dyn position = value #( line = 23 column = 4 ) ) ) - ( code = 'DELETE' location = value #( object = dyn position = value #( line = 24 column = 4 ) ) ) - ( code = 'DELETE' location = value #( object = dyn position = value #( line = 26 column = 4 ) ) ) - ( code = 'SELECT' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 8 column = 4 ) ) ) - ( code = 'SELECT' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 9 column = 4 ) ) ) - ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 13 column = 4 ) ) ) - ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 14 column = 4 ) ) ) - ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 15 column = 4 ) ) ) - ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 17 column = 4 ) ) ) - ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 18 column = 4 ) ) ) - ( code = 'INSERT' parameters = value #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 23 column = 4 ) ) ) - ( code = 'UPDATE' parameters = value #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 29 column = 4 ) ) ) - ( code = 'UPDATE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 30 column = 4 ) ) ) - ( code = 'UPDATE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 31 column = 4 ) ) ) - ( code = 'MODIFY' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) - location = value #( object = mixed position = value #( line = 33 column = 4 ) ) ) - ( code = 'WITH' parameters = value #( param_1 = 'SCI_TEST_SFLIGHT' ) - location = value #( object = mixed position = value #( line = 46 column = 4 ) ) ) ) - asserter_config = value #( + check = NEW lcl_atc_check_db_stmt( ) + object = VALUE #( type = 'CLAS' name = test_class ) + expected_findings = VALUE #( + ( code = 'DELETE' location = VALUE #( object = dyn position = VALUE #( line = 6 column = 4 ) ) ) + ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 9 column = 6 ) ) ) + ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 12 column = 6 ) ) ) + ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 14 column = 4 ) ) ) + ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 15 column = 4 ) ) ) + ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 17 column = 4 ) ) ) + ( code = 'INSERT' location = VALUE #( object = dyn position = VALUE #( line = 18 column = 4 ) ) ) + ( code = 'INSERT' location = VALUE #( object = dyn position = VALUE #( line = 19 column = 4 ) ) ) + ( code = 'UPDATE' location = VALUE #( object = dyn position = VALUE #( line = 20 column = 4 ) ) ) + ( code = 'UPDATE' location = VALUE #( object = dyn position = VALUE #( line = 21 column = 4 ) ) ) + ( code = 'MODIFY' location = VALUE #( object = dyn position = VALUE #( line = 22 column = 4 ) ) ) + ( code = 'DELETE' location = VALUE #( object = dyn position = VALUE #( line = 23 column = 4 ) ) ) + ( code = 'DELETE' location = VALUE #( object = dyn position = VALUE #( line = 24 column = 4 ) ) ) + ( code = 'DELETE' location = VALUE #( object = dyn position = VALUE #( line = 26 column = 4 ) ) ) + ( code = 'SELECT' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 8 column = 4 ) ) ) + ( code = 'SELECT' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 9 column = 4 ) ) ) + ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 13 column = 4 ) ) ) + ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 14 column = 4 ) ) ) + ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 15 column = 4 ) ) ) + ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 17 column = 4 ) ) ) + ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 18 column = 4 ) ) ) + ( code = 'INSERT' parameters = VALUE #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 23 column = 4 ) ) ) + ( code = 'UPDATE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 29 column = 4 ) ) ) + ( code = 'UPDATE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 30 column = 4 ) ) ) + ( code = 'UPDATE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 31 column = 4 ) ) ) + ( code = 'MODIFY' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) + location = VALUE #( object = mixed position = VALUE #( line = 33 column = 4 ) ) ) + ( code = 'WITH' parameters = VALUE #( param_1 = 'SCI_TEST_SFLIGHT' ) + location = VALUE #( object = mixed position = VALUE #( line = 46 column = 4 ) ) ) ) + asserter_config = VALUE #( quickfixes = abap_false ) ). - endmethod. -endclass. - -class shared definition final abstract. - public section. - class-methods tokenize - importing !code type string - returning value(statement) type if_ci_atc_source_code_provider=>ty_statement. -endclass. - -class shared implementation. - method tokenize. - split code at space into table data(tokens). - statement = value #( tokens = value #( for in tokens ( lexeme = to_upper( ) ) ) ). + ENDMETHOD. +ENDCLASS. + +CLASS shared DEFINITION FINAL ABSTRACT. + PUBLIC SECTION. + CLASS-METHODS tokenize + IMPORTING !code TYPE string + RETURNING VALUE(statement) TYPE if_ci_atc_source_code_provider=>ty_statement. +ENDCLASS. + +CLASS shared IMPLEMENTATION. + METHOD tokenize. + SPLIT code AT space INTO TABLE DATA(tokens). + DELETE tokens WHERE table_line = '.'. + statement = VALUE #( tokens = VALUE #( FOR IN tokens ( lexeme = to_upper( ) ) ) ). statement-keyword = statement-tokens[ 1 ]-lexeme. - endmethod. -endclass. + ENDMETHOD. +ENDCLASS. -class bracket_matching definition final for testing - duration short - risk level harmless. +CLASS bracket_matching DEFINITION FINAL FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. - private section. - methods bracket_ends for testing raising cx_static_check. -endclass. + PRIVATE SECTION. + METHODS bracket_ends FOR TESTING RAISING cx_static_check. +ENDCLASS. -class bracket_matching implementation. - method bracket_ends. - data(analyzer) = /cc4a/abap_analyzer=>create( ). +CLASS bracket_matching IMPLEMENTATION. + METHOD bracket_ends. + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( act = analyzer->calculate_bracket_end( @@ -267,103 +268,143 @@ class bracket_matching implementation. statement = shared=>tokenize( `obj->call( )->second_call( )` ) bracket_position = 1 ) exp = 2 ). - endmethod. -endclass. + ENDMETHOD. +ENDCLASS. -class method_definitions definition final for testing - duration short - risk level harmless. +CLASS method_definitions DEFINITION FINAL FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. - private section. - methods method_definitions for testing raising cx_static_check. -endclass. + PRIVATE SECTION. + METHODS method_definitions FOR TESTING RAISING cx_static_check. +ENDCLASS. -class method_definitions implementation. - method method_definitions. - data(analyzer) = /cc4a/abap_analyzer=>create( ). +CLASS method_definitions IMPLEMENTATION. + METHOD method_definitions. + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth redefinition .` ) ) - exp = value /cc4a/if_abap_analyzer=>ty_method_definition( + exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` is_redefinition = abap_true ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth .` ) ) - exp = value /cc4a/if_abap_analyzer=>ty_method_definition( + exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth importing par type i .` ) ) - exp = value /cc4a/if_abap_analyzer=>ty_method_definition( + exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ) ) ). + parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth importing reference(par) type i .` ) ) - exp = value /cc4a/if_abap_analyzer=>ty_method_definition( + exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ) ) ). + parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth exporting par type i .` ) ) - exp = value /cc4a/if_abap_analyzer=>ty_method_definition( + exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-exporting ) ) ) ). + parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-exporting ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth changing par type i .` ) ) - exp = value /cc4a/if_abap_analyzer=>ty_method_definition( + exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ) ) ). + parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth changing par type i .` ) ) - exp = value /cc4a/if_abap_analyzer=>ty_method_definition( + exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ) ) ). + parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth importing imp type i exporting reference(exp) type i changing ch type i returning value(ret) type i.` ) ) - exp = value /cc4a/if_abap_analyzer=>ty_method_definition( + exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = value #( + parameters = VALUE #( ( name = `IMP` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ( name = `EXP` kind = /cc4a/if_abap_analyzer=>parameter_kind-exporting ) ( name = `CH` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ( name = `RET` kind = /cc4a/if_abap_analyzer=>parameter_kind-returning ) ) ) ). - endmethod. -endclass. - -class flatten_tokens definition final for testing - duration short - risk level harmless. - - private section. - methods simple_statement for testing raising cx_static_check. - methods string_template for testing raising cx_static_check. - methods nested_string_template for testing raising cx_static_check. -endclass. - -class flatten_tokens implementation. - method simple_statement. - data(analyzer) = /cc4a/abap_analyzer=>create( ). + ENDMETHOD. +ENDCLASS. + +CLASS flatten_tokens DEFINITION FINAL FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. + + PRIVATE SECTION. + METHODS simple_statement FOR TESTING RAISING cx_static_check. + METHODS string_template FOR TESTING RAISING cx_static_check. + METHODS nested_string_template FOR TESTING RAISING cx_static_check. + METHODS test1 FOR TESTING RAISING cx_static_check. + METHODS test_line_break FOR TESTING RAISING cx_static_check. +ENDCLASS. + +CLASS /cc4a/abap_analyzer DEFINITION LOCAL FRIENDS flatten_tokens. + +CLASS flatten_tokens IMPLEMENTATION. + METHOD test1. + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). + DATA(flat) = analyzer->flatten_tokens( tokens = VALUE #( + ( lexeme = `DATA(text)` ) ( lexeme = `=` ) ( lexeme = `method(` ) + ( lexeme = `|` ) ( lexeme = '`whatsoever`' ) ( lexeme = `|` ) ( lexeme = `)` ) ) ). + cl_abap_unit_assert=>assert_equals( + act = flat + exp = `DATA(text) = method( |whatsoever| )` ). +* 123456789012345678901234567890123456 + DATA(lines) = /cc4a/abap_analyzer=>_break_into_lines( code = flat break_at = 20 ). + DATA(exp_lines) = VALUE string_table( ( `DATA(text) = method(` ) ( `|whatsoever| )` ) ). + cl_abap_unit_assert=>assert_equals( act = lines exp = exp_lines ). + ENDMETHOD. + METHOD test_line_break. + DATA lines TYPE string_table. + TRY. + lines = /cc4a/abap_analyzer=>_break_into_lines( code = `12345678901` break_at = 10 ). + cl_abap_unit_assert=>fail( `Exception expected` ). + CATCH /cc4a/cx_line_break_impossible. +* expected + ENDTRY. + TRY. + lines = /cc4a/abap_analyzer=>_break_into_lines( code = `1234567890 123467890123` break_at = 10 ). + cl_abap_unit_assert=>fail( `Exception expected` ). + CATCH /cc4a/cx_line_break_impossible. +* expected + ENDTRY. + + TRY. + lines = /cc4a/abap_analyzer=>_break_into_lines( code = `|23456789| blabla` break_at = 10 ). + DATA(exp_lines) = VALUE string_table( ( `|23456789|` ) ( `blabla` ) ). + cl_abap_unit_assert=>assert_equals( act = lines exp = exp_lines ). + CATCH /cc4a/cx_line_break_impossible. + cl_abap_unit_assert=>fail( `No Exception expected` ). + ENDTRY. + ENDMETHOD. + METHOD simple_statement. + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( act = analyzer->flatten_tokens( shared=>tokenize( `data my_int type i.` )-tokens ) - exp = `DATA MY_INT TYPE I. ` ). + exp = `DATA MY_INT TYPE I.` ). cl_abap_unit_assert=>assert_equals( act = analyzer->flatten_tokens( shared=>tokenize( `obj->meth( par = val ).` )-tokens ) - exp = `OBJ->METH( PAR = VAL ). ` ). - endmethod. + exp = `OBJ->METH( PAR = VAL ).` ). + ENDMETHOD. - method string_template. - data(analyzer) = /cc4a/abap_analyzer=>create( ). + METHOD string_template. + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( - act = condense( analyzer->flatten_tokens( value #( + act = condense( analyzer->flatten_tokens( VALUE #( ( lexeme = `STR` ) ( lexeme = `=` ) ( lexeme = `|` ) @@ -374,12 +415,12 @@ class flatten_tokens implementation. ( lexeme = '`!`' ) ( lexeme = `|` ) ) ) ) exp = 'STR = |hello, { WORLD }!|' ). - endmethod. + ENDMETHOD. - method nested_string_template. - data(analyzer) = /cc4a/abap_analyzer=>create( ). + METHOD nested_string_template. + DATA(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( - act = condense( analyzer->flatten_tokens( value #( + act = condense( analyzer->flatten_tokens( VALUE #( ( lexeme = `STR` ) ( lexeme = `=` ) ( lexeme = `|` ) @@ -398,5 +439,5 @@ class flatten_tokens implementation. ( lexeme = `|` ) ) ) ) exp = 'STR = |hello, { func( |inner { TEMPLATE }| ) }!|' ). - endmethod. -endclass. + ENDMETHOD. +ENDCLASS. diff --git a/src/core/#cc4a#cx_line_break_impossible.clas.abap b/src/core/#cc4a#cx_line_break_impossible.clas.abap new file mode 100644 index 0000000..21e5cd7 --- /dev/null +++ b/src/core/#cc4a#cx_line_break_impossible.clas.abap @@ -0,0 +1,23 @@ +CLASS /cc4a/cx_line_break_impossible DEFINITION + PUBLIC + INHERITING FROM cx_dynamic_check + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + METHODS constructor. + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS /cc4a/cx_line_break_impossible IMPLEMENTATION. + METHOD constructor ##ADT_SUPPRESS_GENERATION. + + super->constructor( textid = textid previous = previous ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/core/#cc4a#cx_line_break_impossible.clas.xml b/src/core/#cc4a#cx_line_break_impossible.clas.xml new file mode 100644 index 0000000..977af81 --- /dev/null +++ b/src/core/#cc4a#cx_line_break_impossible.clas.xml @@ -0,0 +1,17 @@ + + + + + + /CC4A/CX_LINE_BREAK_IMPOSSIBLE + E + line break impossible + 40 + 1 + X + X + X + + + + diff --git a/src/core/#cc4a#if_abap_analyzer.intf.abap b/src/core/#cc4a#if_abap_analyzer.intf.abap index 4552818..83d1349 100644 --- a/src/core/#cc4a#if_abap_analyzer.intf.abap +++ b/src/core/#cc4a#if_abap_analyzer.intf.abap @@ -2,11 +2,11 @@ "! "! Any logic that processes ABAP code information (e.g. parsing a specific assignment) should be located here "! so it can be accessed by any check that needs it. -interface /cc4a/if_abap_analyzer - public . - - types: - begin of enum ty_bracket_type structure bracket_type, +INTERFACE /cc4a/if_abap_analyzer + PUBLIC . + CONSTANTS max_line_length TYPE i VALUE 255. + TYPES: + BEGIN OF ENUM ty_bracket_type STRUCTURE bracket_type, no_bracket, opening, closing, @@ -14,108 +14,107 @@ interface /cc4a/if_abap_analyzer "! obj->method_1( )->method_2( ) produces a single token `)->method_2(` that is both a closing and an "! opening bracket. clopening, - end of enum ty_bracket_type structure bracket_type. - types: - begin of ty_db_statement, - is_db type abap_bool, - dbtab type string, - dbtab_subquery type string, - end of ty_db_statement. - types: - begin of enum ty_parameter_kind structure parameter_kind, + END OF ENUM ty_bracket_type STRUCTURE bracket_type. + TYPES: + BEGIN OF ty_db_statement, + is_db TYPE abap_bool, + dbtab TYPE string, + dbtab_subquery TYPE string, + END OF ty_db_statement. + TYPES: + BEGIN OF ENUM ty_parameter_kind STRUCTURE parameter_kind, importing, exporting, changing, returning, - end of enum ty_parameter_kind structure parameter_kind. - types: - begin of ty_method_parameter, - name type string, - kind type ty_parameter_kind, - end of ty_method_parameter. - types ty_method_parameters type hashed table of ty_method_parameter with unique key name. - types: - begin of ty_method_definition, - name type string, - is_redefinition type abap_bool, - parameters type ty_method_parameters, - end of ty_method_definition. + END OF ENUM ty_parameter_kind STRUCTURE parameter_kind. + TYPES: + BEGIN OF ty_method_parameter, + name TYPE string, + kind TYPE ty_parameter_kind, + END OF ty_method_parameter. + TYPES ty_method_parameters TYPE HASHED TABLE OF ty_method_parameter WITH UNIQUE KEY name. + TYPES: + BEGIN OF ty_method_definition, + name TYPE string, + is_redefinition TYPE abap_bool, + parameters TYPE ty_method_parameters, + END OF ty_method_definition. - methods find_key_words - importing - key_words type string_table - statement type if_ci_atc_source_code_provider=>ty_statement - returning - value(position) type i . - methods break_into_lines - importing - code type string - returning - value(code_lines) type if_ci_atc_quickfix=>ty_code . - methods flatten_tokens - importing - tokens type if_ci_atc_source_code_provider=>ty_tokens - returning - value(flat_statement) type string . - methods is_bracket - importing - token type if_ci_atc_source_code_provider=>ty_token - returning - value(bracket_type) type ty_bracket_type . - methods calculate_bracket_end - importing - statement type if_ci_atc_source_code_provider=>ty_statement - bracket_position type i - returning - value(end_of_bracket) type i - raising + METHODS find_key_words + IMPORTING + key_words TYPE string_table + statement TYPE if_ci_atc_source_code_provider=>ty_statement + RETURNING + VALUE(position) TYPE i . + METHODS break_into_lines + IMPORTING code TYPE string + RETURNING VALUE(code_lines) TYPE if_ci_atc_quickfix=>ty_code + RAISING /cc4a/cx_line_break_impossible. + METHODS flatten_tokens + IMPORTING + tokens TYPE if_ci_atc_source_code_provider=>ty_tokens + RETURNING + VALUE(flat_statement) TYPE string . + METHODS is_bracket + IMPORTING + token TYPE if_ci_atc_source_code_provider=>ty_token + RETURNING + VALUE(bracket_type) TYPE ty_bracket_type . + METHODS calculate_bracket_end + IMPORTING + statement TYPE if_ci_atc_source_code_provider=>ty_statement + bracket_position TYPE i + RETURNING + VALUE(end_of_bracket) TYPE i + RAISING /cc4a/cx_token_is_no_bracket . "! The method analyze the given token whether this is an comparison operator or not. "! Operators like +, -, * and / does not count as comparison operator. "! The following operators are currently supported: is, in, >, gt, <, lt, >=, ge, <=, le, =, eq, <>, ne - methods token_is_comparison_operator - importing - token type if_ci_atc_source_code_provider=>ty_token - returning - value(is_operator) type abap_bool . - methods negate_comparison_operator - importing - comparison_operator type string - returning - value(negated_comparison_operator) type string - raising + METHODS token_is_comparison_operator + IMPORTING + token TYPE if_ci_atc_source_code_provider=>ty_token + RETURNING + VALUE(is_operator) TYPE abap_bool . + METHODS negate_comparison_operator + IMPORTING + comparison_operator TYPE string + RETURNING + VALUE(negated_comparison_operator) TYPE string + RAISING /cc4a/cx_token_is_no_operator . - methods is_db_statement - importing - statement type if_ci_atc_source_code_provider=>ty_statement - get_dbtab_name type abap_bool default abap_false - include_subqueries type abap_bool default abap_true - returning - value(result) type ty_db_statement. + METHODS is_db_statement + IMPORTING + statement TYPE if_ci_atc_source_code_provider=>ty_statement + get_dbtab_name TYPE abap_bool DEFAULT abap_false + include_subqueries TYPE abap_bool DEFAULT abap_true + RETURNING + VALUE(result) TYPE ty_db_statement. "! The method checks if clause is contained in tokens "! if so it returns the index of the first token of the first occurrence of the clause "! otherwise token_index = 0 - methods find_clause_index - importing - tokens type if_ci_atc_source_code_provider=>ty_tokens - clause type string - start_index type i default 1 - returning - value(token_index) type i - raising + METHODS find_clause_index + IMPORTING + tokens TYPE if_ci_atc_source_code_provider=>ty_tokens + clause TYPE string + start_index TYPE i DEFAULT 1 + RETURNING + VALUE(token_index) TYPE i + RAISING /cc4a/cx_clause_is_initial . - methods is_token_keyword - importing - token type if_ci_atc_source_code_provider=>ty_token - keyword type string - returning - value(result) type abap_bool . - methods is_logical_connective - importing token type if_ci_atc_source_code_provider=>ty_token - returning value(is_logical_connective) type abap_bool. - methods parse_method_definition - importing statement type if_ci_atc_source_code_provider=>ty_statement - returning value(method_definition) type ty_method_definition. -endinterface. + METHODS is_token_keyword + IMPORTING + token TYPE if_ci_atc_source_code_provider=>ty_token + keyword TYPE string + RETURNING + VALUE(result) TYPE abap_bool . + METHODS is_logical_connective + IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token + RETURNING VALUE(is_logical_connective) TYPE abap_bool. + METHODS parse_method_definition + IMPORTING statement TYPE if_ci_atc_source_code_provider=>ty_statement + RETURNING VALUE(method_definition) TYPE ty_method_definition. +ENDINTERFACE. From 40cd3c08e9b35db98c49c8db126e0b85816591ec Mon Sep 17 00:00:00 2001 From: Bjoern Jueliger Date: Wed, 7 Feb 2024 09:16:00 +0000 Subject: [PATCH 7/9] Formatting & minor naming --- src/checks/#cc4a#modern_language.clas.abap | 1634 ++++++++--------- ...#cc4a#modern_language.clas.locals_imp.abap | 2 +- ...cc4a#modern_language.clas.testclasses.abap | 434 +++-- src/core/#cc4a#abap_analyzer.clas.abap | 610 +++--- .../#cc4a#abap_analyzer.clas.locals_imp.abap | 721 ++++---- .../#cc4a#abap_analyzer.clas.testclasses.abap | 478 ++--- .../#cc4a#cx_line_break_impossible.clas.abap | 28 +- 7 files changed, 1951 insertions(+), 1956 deletions(-) diff --git a/src/checks/#cc4a#modern_language.clas.abap b/src/checks/#cc4a#modern_language.clas.abap index fa6f810..866e4ba 100644 --- a/src/checks/#cc4a#modern_language.clas.abap +++ b/src/checks/#cc4a#modern_language.clas.abap @@ -1,147 +1,147 @@ -CLASS /cc4a/modern_language DEFINITION - PUBLIC - FINAL - CREATE PUBLIC . - - PUBLIC SECTION. - - INTERFACES if_ci_atc_check . - - PROTECTED SECTION. - PRIVATE SECTION. - CONSTANTS: - BEGIN OF message_codes, - move TYPE if_ci_atc_check=>ty_finding_code VALUE 'MOVE', - translate TYPE if_ci_atc_check=>ty_finding_code VALUE 'TRANSLATE', - line_exists TYPE if_ci_atc_check=>ty_finding_code VALUE 'LINE_EXIST', - prefer_new TYPE if_ci_atc_check=>ty_finding_code VALUE 'PREFER_NEW', - call_method TYPE if_ci_atc_check=>ty_finding_code VALUE 'CALL_METH', - method_exporting TYPE if_ci_atc_check=>ty_finding_code VALUE 'METH_EXP', - exporting_receiving TYPE if_ci_atc_check=>ty_finding_code VALUE 'EXP_REC', - text_assembly TYPE if_ci_atc_check=>ty_finding_code VALUE 'TEXT_ASM', - END OF message_codes. - CONSTANTS: - BEGIN OF quickfix_codes, - move TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_MOVE', - translate TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_TRANSL', - line_exists TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_LINEEX', - prefer_new TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_PREFNEW', - call_method TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_CALLM', - method_exporting TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_MEXP', - exporting_receiving TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_EXP_REC', - text_assembly TYPE cl_ci_atc_quickfixes=>ty_quickfix_code VALUE 'QF_TEXTASM', - END OF quickfix_codes. - CONSTANTS: - BEGIN OF pseudo_comments, - deprecated_key TYPE string VALUE 'DEPRECATED_KEY', - line_exists TYPE string VALUE 'PREF_LINE_EX', - prefer_new TYPE string VALUE 'PREF_NEW', - call_method TYPE string VALUE 'CALL_METH_USAGE', - method_exporting TYPE string VALUE 'OPTL_EXP', - exporting_receiving TYPE string VALUE 'RECEIVING_USAGE', - text_assembly TYPE string VALUE 'TEXT_ASSEMBLY', - END OF pseudo_comments. - - TYPES: BEGIN OF t_receiving_infos, - receiving_idx TYPE i, - end_idx TYPE i, - result_line TYPE string, - END OF t_receiving_infos. - DATA code_provider TYPE REF TO if_ci_atc_source_code_provider. - DATA analyzer TYPE REF TO /cc4a/if_abap_analyzer. - DATA assistant_factory TYPE REF TO cl_ci_atc_assistant_factory. - - METHODS analyze_procedure - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_move - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_translate - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_read - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_loop - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_create_object - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_call_method - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_exporting_receiving - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS analyze_text_assembly - IMPORTING procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. - METHODS add_finding - IMPORTING quickfixes TYPE REF TO cl_ci_atc_quickfixes OPTIONAL - procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - statement_index TYPE i - code TYPE cl_ci_atc_quickfixes=>ty_quickfix_code - pseudo_comment TYPE string - CHANGING findings TYPE if_ci_atc_check=>ty_findings. - METHODS is_used - IMPORTING - procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - from_index TYPE i - full_name TYPE string - RETURNING - VALUE(result) TYPE abap_bool. - - METHODS check_remove_exporting - IMPORTING - statement TYPE if_ci_atc_source_code_provider=>ty_statement - token_idx TYPE i - RETURNING - VALUE(result) TYPE abap_bool. - METHODS get_value - IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token - RETURNING VALUE(result) TYPE string - RAISING lcx_error. - METHODS append_token - IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token - CHANGING result TYPE string. - METHODS append_tokens - IMPORTING tokens TYPE if_ci_atc_source_code_provider=>ty_tokens - VALUE(from_idx) TYPE i OPTIONAL - VALUE(to_idx) TYPE i OPTIONAL - CHANGING result TYPE string. - METHODS get_receiving_infos - IMPORTING - tokens TYPE if_ci_atc_source_code_provider=>ty_tokens - RETURNING VALUE(result) TYPE t_receiving_infos. - METHODS get_move_changed_line - IMPORTING statement TYPE if_ci_atc_source_code_provider=>ty_statement - RETURNING VALUE(result) TYPE string. -ENDCLASS. - - - -CLASS /cc4a/modern_language IMPLEMENTATION. - - - - - - METHOD if_ci_atc_check~get_meta_data. +class /cc4a/modern_language definition + public + final + create public . + + public section. + + interfaces if_ci_atc_check . + + protected section. + private section. + constants: + begin of message_codes, + move type if_ci_atc_check=>ty_finding_code value 'MOVE', + translate type if_ci_atc_check=>ty_finding_code value 'TRANSLATE', + line_exists type if_ci_atc_check=>ty_finding_code value 'LINE_EXIST', + prefer_new type if_ci_atc_check=>ty_finding_code value 'PREFER_NEW', + call_method type if_ci_atc_check=>ty_finding_code value 'CALL_METH', + method_exporting type if_ci_atc_check=>ty_finding_code value 'METH_EXP', + exporting_receiving type if_ci_atc_check=>ty_finding_code value 'EXP_REC', + text_assembly type if_ci_atc_check=>ty_finding_code value 'TEXT_ASM', + end of message_codes. + constants: + begin of quickfix_codes, + move type cl_ci_atc_quickfixes=>ty_quickfix_code value 'QF_MOVE', + translate type cl_ci_atc_quickfixes=>ty_quickfix_code value 'QF_TRANSL', + line_exists type cl_ci_atc_quickfixes=>ty_quickfix_code value 'QF_LINEEX', + prefer_new type cl_ci_atc_quickfixes=>ty_quickfix_code value 'QF_PREFNEW', + call_method type cl_ci_atc_quickfixes=>ty_quickfix_code value 'QF_CALLM', + method_exporting type cl_ci_atc_quickfixes=>ty_quickfix_code value 'QF_MEXP', + exporting_receiving type cl_ci_atc_quickfixes=>ty_quickfix_code value 'QF_EXP_REC', + text_assembly type cl_ci_atc_quickfixes=>ty_quickfix_code value 'QF_TEXTASM', + end of quickfix_codes. + constants: + begin of pseudo_comments, + deprecated_key type string value 'DEPRECATED_KEY', + line_exists type string value 'PREF_LINE_EX', + prefer_new type string value 'PREF_NEW', + call_method type string value 'CALL_METH_USAGE', + method_exporting type string value 'OPTL_EXP', + exporting_receiving type string value 'RECEIVING_USAGE', + text_assembly type string value 'TEXT_ASSEMBLY', + end of pseudo_comments. + + types: begin of ty_receiving_infos, + receiving_idx type i, + end_idx type i, + result_line type string, + end of ty_receiving_infos. + data code_provider type ref to if_ci_atc_source_code_provider. + data analyzer type ref to /cc4a/if_abap_analyzer. + data assistant_factory type ref to cl_ci_atc_assistant_factory. + + methods analyze_procedure + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + returning value(findings) type if_ci_atc_check=>ty_findings. + methods analyze_move + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + returning value(findings) type if_ci_atc_check=>ty_findings. + methods analyze_translate + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + returning value(findings) type if_ci_atc_check=>ty_findings. + methods analyze_read + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + returning value(findings) type if_ci_atc_check=>ty_findings. + methods analyze_loop + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + returning value(findings) type if_ci_atc_check=>ty_findings. + methods analyze_create_object + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + returning value(findings) type if_ci_atc_check=>ty_findings. + methods analyze_call_method + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + returning value(findings) type if_ci_atc_check=>ty_findings. + methods analyze_exporting_receiving + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + returning value(findings) type if_ci_atc_check=>ty_findings. + methods analyze_text_assembly + importing procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + returning value(findings) type if_ci_atc_check=>ty_findings. + methods add_finding + importing quickfixes type ref to cl_ci_atc_quickfixes optional + procedure type if_ci_atc_source_code_provider=>ty_procedure + statement_index type i + code type cl_ci_atc_quickfixes=>ty_quickfix_code + pseudo_comment type string + changing findings type if_ci_atc_check=>ty_findings. + methods is_used + importing + procedure type if_ci_atc_source_code_provider=>ty_procedure + from_index type i + full_name type string + returning + value(result) type abap_bool. + + methods check_remove_exporting + importing + statement type if_ci_atc_source_code_provider=>ty_statement + token_idx type i + returning + value(result) type abap_bool. + methods get_value + importing token type if_ci_atc_source_code_provider=>ty_token + returning value(result) type string + raising lcx_error. + methods append_token + importing token type if_ci_atc_source_code_provider=>ty_token + changing result type string. + methods append_tokens + importing tokens type if_ci_atc_source_code_provider=>ty_tokens + value(from_idx) type i optional + value(to_idx) type i optional + changing result type string. + methods get_receiving_infos + importing + tokens type if_ci_atc_source_code_provider=>ty_tokens + returning value(result) type ty_receiving_infos. + methods get_move_changed_line + importing statement type if_ci_atc_source_code_provider=>ty_statement + returning value(result) type string. +endclass. + + + +class /cc4a/modern_language implementation. + + + + + + method if_ci_atc_check~get_meta_data. meta_data = /cc4a/check_meta_data=>create( - VALUE #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs + value #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs description = 'Modern Language'(des) remote_enablement = /cc4a/check_meta_data=>remote_enablement-unconditional - finding_codes = VALUE #( ( code = message_codes-move text = 'MOVE is obsolete'(001) pseudo_comment = pseudo_comments-deprecated_key ) + finding_codes = value #( ( code = message_codes-move text = 'MOVE is obsolete'(001) pseudo_comment = pseudo_comments-deprecated_key ) ( code = message_codes-translate text = 'TRANSLATE TO UPPER/LOWERCASE is obsolete'(002) pseudo_comment = pseudo_comments-deprecated_key ) ( code = message_codes-line_exists text = 'Prefer LINE_EXISTS/LINE_INDEX'(003) pseudo_comment = pseudo_comments-line_exists ) ( code = message_codes-prefer_new text = 'Prefer NEW instead of CREATE OBJECT'(004) pseudo_comment = pseudo_comments-prefer_new ) @@ -149,7 +149,7 @@ CLASS /cc4a/modern_language IMPLEMENTATION. ( code = message_codes-method_exporting text = 'Omit EXPORTING in functional Method Call if possible'(006) pseudo_comment = pseudo_comments-method_exporting ) ( code = message_codes-exporting_receiving text = 'Do not use RECEIVING in functional Method Call if possible'(007) pseudo_comment = pseudo_comments-exporting_receiving ) ( code = message_codes-text_assembly text = 'Use string templates instead of &&'(008) pseudo_comment = pseudo_comments-text_assembly ) ) - quickfix_codes = VALUE #( ( code = quickfix_codes-move short_text = 'Replace MOVE statement'(qf1) ) + quickfix_codes = value #( ( code = quickfix_codes-move short_text = 'Replace MOVE statement'(qf1) ) ( code = quickfix_codes-translate short_text = 'Replace TRANSLATE statement'(qf2) ) ( code = quickfix_codes-line_exists short_text = 'Use LINE_EXISTS/LINE_INDEX'(qf3) ) ( code = quickfix_codes-prefer_new short_text = 'Use NEW instead of CREATE OBJECT'(qf4) ) @@ -158,931 +158,931 @@ CLASS /cc4a/modern_language IMPLEMENTATION. ( code = quickfix_codes-exporting_receiving short_text = 'Do not use EXPORTING/RECEIVING'(qf7) ) ( code = quickfix_codes-text_assembly short_text = 'Replace && by string templates'(qf8) ) ) ) ). - ENDMETHOD. + endmethod. - METHOD if_ci_atc_check~run. + method if_ci_atc_check~run. code_provider = data_provider->get_code_provider( ). analyzer = /cc4a/abap_analyzer=>create( ). - DATA(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). - LOOP AT procedures->* ASSIGNING FIELD-SYMBOL(). - INSERT LINES OF analyze_procedure( ) INTO TABLE findings. - ENDLOOP. - ENDMETHOD. + data(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). + loop at procedures->* assigning field-symbol(). + insert lines of analyze_procedure( ) into table findings. + endloop. + endmethod. - METHOD if_ci_atc_check~set_assistant_factory. + method if_ci_atc_check~set_assistant_factory. assistant_factory = factory. - ENDMETHOD. + endmethod. - METHOD if_ci_atc_check~set_attributes ##NEEDED. - ENDMETHOD. + method if_ci_atc_check~set_attributes ##NEEDED. + endmethod. - METHOD if_ci_atc_check~verify_prerequisites ##NEEDED. - ENDMETHOD. + method if_ci_atc_check~verify_prerequisites ##NEEDED. + endmethod. - METHOD add_finding. - DATA finding LIKE LINE OF findings. - DATA(statement) = procedure-statements[ statement_index ]. - IF quickfixes IS INITIAL. - finding = VALUE #( code = code + method add_finding. + data finding like line of findings. + data(statement) = procedure-statements[ statement_index ]. + if quickfixes is initial. + finding = value #( code = code location = code_provider->get_statement_location( statement ) checksum = code_provider->get_statement_checksum( statement ) has_pseudo_comment = xsdbool( line_exists( statement-pseudo_comments[ table_line = pseudo_comment ] ) ) ). - ELSE. - finding = VALUE #( code = code + else. + finding = value #( code = code location = code_provider->get_statement_location( statement ) checksum = code_provider->get_statement_checksum( statement ) has_pseudo_comment = xsdbool( line_exists( statement-pseudo_comments[ table_line = pseudo_comment ] ) ) details = assistant_factory->create_finding_details( )->attach_quickfixes( quickfixes ) ). - ENDIF. - INSERT finding INTO TABLE findings. - ENDMETHOD. - - METHOD get_move_changed_line. - DATA source TYPE string. - DATA dest TYPE string. - DATA between TYPE string. - - DATA(from_token) = 2. - IF statement-tokens[ 2 ]-lexeme = 'EXACT' AND statement-tokens[ 2 ]-references IS INITIAL. - DATA(exact) = abap_true. + endif. + insert finding into table findings. + endmethod. + + method get_move_changed_line. + data source type string. + data dest type string. + data between type string. + + data(from_token) = 2. + if statement-tokens[ 2 ]-lexeme = 'EXACT' and statement-tokens[ 2 ]-references is initial. + data(exact) = abap_true. from_token = 3. - ENDIF. - LOOP AT statement-tokens FROM from_token ASSIGNING FIELD-SYMBOL(). + endif. + loop at statement-tokens from from_token assigning field-symbol(). - IF -references IS INITIAL. - CASE -lexeme. - WHEN 'TO'. - IF exact = abap_true. + if -references is initial. + case -lexeme. + when 'TO'. + if exact = abap_true. between = `= EXACT #(`. - ELSE. + else. between = `=`. - ENDIF. - CONTINUE. - WHEN '?TO'. + endif. + continue. + when '?TO'. between = `?=`. - CONTINUE. - ENDCASE. - ENDIF. - IF between IS INITIAL. + continue. + endcase. + endif. + if between is initial. source = |{ source } { -lexeme }|. - ELSE. + else. dest = |{ dest } { -lexeme }|. - ENDIF. - ENDLOOP. + endif. + endloop. result = |{ dest } { between } { source }|. - IF exact = abap_true. + if exact = abap_true. result = |{ result } )|. - ENDIF. + endif. result = |{ result }.|. - ENDMETHOD. + endmethod. - METHOD analyze_move. - DATA(statement) = procedure-statements[ statement_index ]. + method analyze_move. + data(statement) = procedure-statements[ statement_index ]. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'PERCENTAGE' ) <> 0. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'PERCENTAGE' ) <> 0. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-move pseudo_comment = pseudo_comments-deprecated_key - CHANGING findings = findings ). - ELSE. - DATA(line) = get_move_changed_line( statement ). - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-move ). + changing findings = findings ). + else. + data(line) = get_move_changed_line( statement ). + data(quickfixes) = assistant_factory->create_quickfixes( ). + data(quickfix) = quickfixes->create_quickfix( quickfix_codes-move ). quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = statement_index ) ) ) - code = VALUE #( ( line ) ) ). + value #( procedure_id = procedure-id statements = value #( from = statement_index to = statement_index ) ) ) + code = value #( ( line ) ) ). add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-move pseudo_comment = pseudo_comments-deprecated_key quickfixes = quickfixes - CHANGING findings = findings ). - ENDIF. - ENDMETHOD. + changing findings = findings ). + endif. + endmethod. - METHOD analyze_translate. - DATA(statement) = procedure-statements[ statement_index ]. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'USING MASK' ) <> 0. - RETURN. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TO UPPER CASE' ) = 3 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'TO LOWER CASE' ) = 3. + method analyze_translate. + data(statement) = procedure-statements[ statement_index ]. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'USING MASK' ) <> 0. + return. + endif. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'TO UPPER CASE' ) = 3 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'TO LOWER CASE' ) = 3. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-translate pseudo_comment = pseudo_comments-deprecated_key - CHANGING findings = findings ). - ENDIF. - ENDMETHOD. - - - METHOD analyze_read. - DATA code_line_index TYPE string. - DATA code_line_exists TYPE string. - DATA code_lines TYPE if_ci_atc_quickfix=>ty_code. - DATA key TYPE string. - DATA token_idx TYPE i. - DATA(statement) = procedure-statements[ statement_index ]. - - - IF lines( statement-tokens ) <= 2 OR statement-tokens[ 2 ]-lexeme <> 'TABLE' OR statement-tokens[ 2 ]-references IS NOT INITIAL - OR lines( procedure-statements ) = statement_index - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING NO FIELDS' ) = 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 - OR statement-tokens[ 3 ]-lexeme CP '*('. - RETURN. - ENDIF. - DATA(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WITH KEY' ). - IF key_idx = 0. - RETURN. - ELSE. - - DATA(start_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'COMPONENTS' + changing findings = findings ). + endif. + endmethod. + + + method analyze_read. + data code_line_index type string. + data code_line_exists type string. + data code_lines type if_ci_atc_quickfix=>ty_code. + data key type string. + data token_idx type i. + data(statement) = procedure-statements[ statement_index ]. + + + if lines( statement-tokens ) <= 2 or statement-tokens[ 2 ]-lexeme <> 'TABLE' or statement-tokens[ 2 ]-references is not initial + or lines( procedure-statements ) = statement_index + or analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING NO FIELDS' ) = 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 + or statement-tokens[ 3 ]-lexeme cp '*('. + return. + endif. + data(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WITH KEY' ). + if key_idx = 0. + return. + else. + + data(start_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'COMPONENTS' start_index = key_idx + 1 ). - IF start_idx = 0. "with key... + if start_idx = 0. "with key... start_idx = key_idx + 2. - ELSE. "with key name components ... + else. "with key name components ... start_idx -= 2. - ENDIF. - DATA(keylen) = 0. - DATA(to_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' start_index = start_idx ) - 1. - IF to_idx <= 0. + endif. + data(keylen) = 0. + data(to_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' start_index = start_idx ) - 1. + if to_idx <= 0. to_idx = lines( statement-tokens ). - ENDIF. - IF statement-tokens[ key_idx + 2 ]-lexeme = '='. + endif. + if statement-tokens[ key_idx + 2 ]-lexeme = '='. key = 'TABLE_LINE'. - append_tokens( EXPORTING tokens = statement-tokens from_idx = key_idx + 2 to_idx = to_idx - CHANGING result = key ). - ELSE. - append_tokens( EXPORTING tokens = statement-tokens from_idx = start_idx to_idx = to_idx - CHANGING result = key ). - ENDIF. + append_tokens( exporting tokens = statement-tokens from_idx = key_idx + 2 to_idx = to_idx + changing result = key ). + else. + append_tokens( exporting tokens = statement-tokens from_idx = start_idx to_idx = to_idx + changing result = key ). + endif. keylen = to_idx - start_idx + 1. - ENDIF. - IF keylen = 1. + endif. + if keylen = 1. * finding without quickfix since obsolete version read table with key val. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-line_exists pseudo_comment = pseudo_comments-line_exists - CHANGING findings = findings ). - RETURN. - ENDIF. - DATA(quickfixable) = abap_true. - DATA(table) = statement-tokens[ 3 ]-lexeme. - IF table CP '*[]'. - DATA(len) = strlen( table ) - 2. + changing findings = findings ). + return. + endif. + data(quickfixable) = abap_true. + data(table) = statement-tokens[ 3 ]-lexeme. + if table cp '*[]'. + data(len) = strlen( table ) - 2. table = table(len). - ENDIF. - DATA(idx) = statement_index + 1. - ASSIGN procedure-statements[ idx ] TO FIELD-SYMBOL(). - IF -keyword = 'IF' AND lines( -tokens ) = 4 - AND -tokens[ 2 ]-lexeme = 'SY-SUBRC' - - AND -tokens[ 4 ]-lexeme = '0'. - CASE -tokens[ 3 ]-lexeme. - WHEN '=' OR 'EQ' . - DATA(if_sysubrc) = 1. - WHEN '<>' OR 'NE'. + endif. + data(idx) = statement_index + 1. + assign procedure-statements[ idx ] to field-symbol(). + if -keyword = 'IF' and lines( -tokens ) = 4 + and -tokens[ 2 ]-lexeme = 'SY-SUBRC' + + and -tokens[ 4 ]-lexeme = '0'. + case -tokens[ 3 ]-lexeme. + when '=' or 'EQ' . + data(if_sysubrc) = 1. + when '<>' or 'NE'. if_sysubrc = 2. - ENDCASE. + endcase. idx += 1. - ENDIF. - DATA(end_idx) = idx. - IF if_sysubrc <> 0. + endif. + data(end_idx) = idx. + if if_sysubrc <> 0. to_idx = lines( procedure-statements ). - ELSE. + else. to_idx = idx. - ENDIF. - LOOP AT procedure-statements FROM idx TO to_idx ASSIGNING FIELD-SYMBOL(). - DATA(tabix) = sy-tabix. - IF -keyword = 'ENDIF'. + endif. + loop at procedure-statements from idx to to_idx assigning field-symbol(). + data(tabix) = sy-tabix. + if -keyword = 'ENDIF'. end_idx = sy-tabix. - EXIT. - ENDIF. - DATA(sytabix_idx) = line_index( -tokens[ lexeme = 'SY-TABIX' ] ). + exit. + endif. + data(sytabix_idx) = line_index( -tokens[ lexeme = 'SY-TABIX' ] ). - IF sytabix_idx <> 0. - IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-lexeme = '&&'. + if sytabix_idx <> 0. + if sytabix_idx > 1 and -tokens[ sytabix_idx - 1 ]-lexeme = '&&'. quickfixable = abap_false. - EXIT. - ENDIF. - IF sytabix_idx > 1 AND -tokens[ sytabix_idx - 1 ]-references IS INITIAL - AND -tokens[ sytabix_idx - 1 ]-lexeme = 'LIKE' - AND -keyword = 'DATA'. + exit. + endif. + if sytabix_idx > 1 and -tokens[ sytabix_idx - 1 ]-references is initial + and -tokens[ sytabix_idx - 1 ]-lexeme = 'LIKE' + and -keyword = 'DATA'. quickfixable = abap_false. - EXIT. - ENDIF. - CASE -keyword. - WHEN 'MOVE'. + exit. + endif. + case -keyword. + when 'MOVE'. code_line_index = get_move_changed_line( ). - REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. - APPEND code_line_index TO code_lines. - WHEN 'MESSAGE' OR 'PERFORM' OR '+CALL_MACRO'. + replace first occurrence of 'SY-TABIX' in code_line_index with |line_index( { table }[ { key } ] )| ##NO_TEXT. + append code_line_index to code_lines. + when 'MESSAGE' or 'PERFORM' or '+CALL_MACRO'. quickfixable = abap_false. - EXIT. - WHEN 'SET'. - IF -tokens[ 2 ]-references IS INITIAL AND -tokens[ 2 ]-lexeme = 'BIT'. + exit. + when 'SET'. + if -tokens[ 2 ]-references is initial and -tokens[ 2 ]-lexeme = 'BIT'. quickfixable = abap_false. - ENDIF. - WHEN OTHERS. - IF if_sysubrc <> 2. + endif. + when others. + if if_sysubrc <> 2. code_line_index = analyzer->flatten_tokens( tokens = -tokens ). - REPLACE FIRST OCCURRENCE OF 'SY-TABIX IS INITIAL' IN code_line_index WITH |line_index( { table }[ { key } ] ) = 0| ##NO_TEXT. - REPLACE FIRST OCCURRENCE OF 'SY-TABIX IS NOT INITIAL' IN code_line_index WITH |line_index( { table }[ { key } ] ) <> 0| ##NO_TEXT. - REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. + replace first occurrence of 'SY-TABIX IS INITIAL' in code_line_index with |line_index( { table }[ { key } ] ) = 0| ##NO_TEXT. + replace first occurrence of 'SY-TABIX IS NOT INITIAL' in code_line_index with |line_index( { table }[ { key } ] ) <> 0| ##NO_TEXT. + replace first occurrence of 'SY-TABIX' in code_line_index with |line_index( { table }[ { key } ] )| ##NO_TEXT. code_line_index = |{ code_line_index }.|. - APPEND code_line_index TO code_lines. - ENDIF. - ENDCASE. - ELSEIF if_sysubrc <> 0 AND tabix > statement_index + 1. - IF -keyword = 'CALL' OR -keyword = '+CALL_METHOD'. + append code_line_index to code_lines. + endif. + endcase. + elseif if_sysubrc <> 0 and tabix > statement_index + 1. + if -keyword = 'CALL' or -keyword = '+CALL_METHOD'. quickfixable = abap_false. - EXIT. - ENDIF. - CASE if_sysubrc. - WHEN 1. + exit. + endif. + case if_sysubrc. + when 1. token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). - IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_TRUE'. + if token_idx = 0 or -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_TRUE'. quickfixable = abap_false. - EXIT. - ENDIF. - WHEN 2. + exit. + endif. + when 2. token_idx = analyzer->find_clause_index( tokens = -tokens clause = '=' ). - IF token_idx = 0 OR -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_FALSE' - OR procedure-statements[ tabix + 1 ]-keyword <> 'ENDIF'. + if token_idx = 0 or -tokens[ token_idx + 1 ]-lexeme <> 'ABAP_FALSE' + or procedure-statements[ tabix + 1 ]-keyword <> 'ENDIF'. quickfixable = abap_false. - EXIT. - ENDIF. - ENDCASE. - append_tokens( EXPORTING tokens = -tokens to_idx = token_idx - 1 CHANGING result = code_line_exists ). - IF if_sysubrc = 1. + exit. + endif. + endcase. + append_tokens( exporting tokens = -tokens to_idx = token_idx - 1 changing result = code_line_exists ). + if if_sysubrc = 1. code_line_exists = |{ code_line_exists } = xsdbool( line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. - ELSE. + else. code_line_exists = |{ code_line_exists } = xsdbool( NOT line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. - ENDIF. - APPEND code_line_exists TO code_lines. - ENDIF. - IF if_sysubrc = 0. - EXIT. - ENDIF. - ENDLOOP. - - IF quickfixable = abap_true AND ( code_line_index IS NOT INITIAL OR code_line_exists IS NOT INITIAL ). - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-line_exists ). + endif. + append code_line_exists to code_lines. + endif. + if if_sysubrc = 0. + exit. + endif. + endloop. + + if quickfixable = abap_true and ( code_line_index is not initial or code_line_exists is not initial ). + data(quickfixes) = assistant_factory->create_quickfixes( ). + data(quickfix) = quickfixes->create_quickfix( quickfix_codes-line_exists ). quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = end_idx ) ) ) + value #( procedure_id = procedure-id statements = value #( from = statement_index to = end_idx ) ) ) code = code_lines ). add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-line_exists pseudo_comment = pseudo_comments-line_exists quickfixes = quickfixes - CHANGING findings = findings ). - ELSE. + changing findings = findings ). + else. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-line_exists pseudo_comment = pseudo_comments-line_exists - CHANGING findings = findings ). - ENDIF. - - ENDMETHOD. - - - METHOD analyze_loop. - DATA code_line_index TYPE string. - DATA code_line_exists TYPE string. - DATA code_lines TYPE if_ci_atc_quickfix=>ty_code. - DATA key TYPE string. - - DATA(statement) = procedure-statements[ statement_index ]. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'OR' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'NOT' ) <> 0. - RETURN. - ENDIF. - DATA(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WHERE' ). - IF key_idx = 0 OR statement-tokens[ key_idx + 1 ]-lexeme CP '(*'. - RETURN. - ENDIF. - DATA(table) = statement-tokens[ 3 ]-lexeme. - IF table CP '*('. - RETURN. - ENDIF. - DATA(result_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ). - IF result_idx <> 0. - ASSIGN statement-tokens[ result_idx + 1 ] TO FIELD-SYMBOL(). - IF is_used( procedure = procedure from_index = statement_index + 1 full_name = -references[ lines( -references ) ]-full_name ). - RETURN. - ENDIF. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = '(' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = ')' ) <> 0. - RETURN. - ENDIF. - DATA(token_idx) = key_idx + 1. - DO. - ASSIGN statement-tokens[ token_idx ] TO . - append_token( EXPORTING token = CHANGING result = key ). + changing findings = findings ). + endif. + + endmethod. + + + method analyze_loop. + data code_line_index type string. + data code_line_exists type string. + data code_lines type if_ci_atc_quickfix=>ty_code. + data key type string. + + data(statement) = procedure-statements[ statement_index ]. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'OR' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'NOT' ) <> 0. + return. + endif. + data(key_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'WHERE' ). + if key_idx = 0 or statement-tokens[ key_idx + 1 ]-lexeme cp '(*'. + return. + endif. + data(table) = statement-tokens[ 3 ]-lexeme. + if table cp '*('. + return. + endif. + data(result_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ). + if result_idx <> 0. + assign statement-tokens[ result_idx + 1 ] to field-symbol(). + if is_used( procedure = procedure from_index = statement_index + 1 full_name = -references[ lines( -references ) ]-full_name ). + return. + endif. + endif. + if analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = '(' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens start_index = key_idx + 1 clause = ')' ) <> 0. + return. + endif. + data(token_idx) = key_idx + 1. + do. + assign statement-tokens[ token_idx ] to . + append_token( exporting token = changing result = key ). token_idx += 1. - ASSIGN statement-tokens[ token_idx ] TO . - CASE -lexeme. - WHEN '=' OR 'EQ'. + assign statement-tokens[ token_idx ] to . + case -lexeme. + when '=' or 'EQ'. key = |{ key } = |. - WHEN OTHERS. - RETURN. - ENDCASE. - DATA(and_idx) = analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'AND' ). - IF and_idx = 0. - append_tokens( EXPORTING tokens = statement-tokens from_idx = token_idx + 1 CHANGING result = key ). - EXIT. - ELSE. - append_tokens( EXPORTING tokens = statement-tokens from_idx = token_idx + 1 to_idx = and_idx - 1 CHANGING result = key ). + when others. + return. + endcase. + data(and_idx) = analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'AND' ). + if and_idx = 0. + append_tokens( exporting tokens = statement-tokens from_idx = token_idx + 1 changing result = key ). + exit. + else. + append_tokens( exporting tokens = statement-tokens from_idx = token_idx + 1 to_idx = and_idx - 1 changing result = key ). token_idx = and_idx + 1. - ENDIF. - ENDDO. - DATA(quickfixable) = abap_true. - LOOP AT procedure-statements FROM statement_index + 1 ASSIGNING FIELD-SYMBOL(). - CASE -keyword. - WHEN 'ENDLOOP'. - DATA(end_idx) = sy-tabix. - EXIT. - WHEN 'EXIT'. - DATA(contains_exit) = abap_true. - WHEN 'MOVE'. - IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + endif. + enddo. + data(quickfixable) = abap_true. + loop at procedure-statements from statement_index + 1 assigning field-symbol(). + case -keyword. + when 'ENDLOOP'. + data(end_idx) = sy-tabix. + exit. + when 'EXIT'. + data(contains_exit) = abap_true. + when 'MOVE'. + if line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). code_line_index = get_move_changed_line( ). - REPLACE FIRST OCCURRENCE OF 'SY-TABIX' IN code_line_index WITH |line_index( { table }[ { key } ] )| ##NO_TEXT. - APPEND code_line_index TO code_lines. - ENDIF. - WHEN 'MESSAGE' OR 'PERFORM' OR '+CALL_MACRO'. - IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + replace first occurrence of 'SY-TABIX' in code_line_index with |line_index( { table }[ { key } ] )| ##NO_TEXT. + append code_line_index to code_lines. + endif. + when 'MESSAGE' or 'PERFORM' or '+CALL_MACRO'. + if line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). quickfixable = abap_false. - EXIT. - ENDIF. - WHEN 'SET'. - IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ) - AND -tokens[ 2 ]-references IS INITIAL AND -tokens[ 2 ]-lexeme = 'BIT'. + exit. + endif. + when 'SET'. + if line_exists( -tokens[ lexeme = 'SY-TABIX' ] ) + and -tokens[ 2 ]-references is initial and -tokens[ 2 ]-lexeme = 'BIT'. quickfixable = abap_false. - ENDIF. - WHEN OTHERS. - IF line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). - LOOP AT -tokens ASSIGNING . - IF -lexeme = 'SY-TABIX'. + endif. + when others. + if line_exists( -tokens[ lexeme = 'SY-TABIX' ] ). + loop at -tokens assigning . + if -lexeme = 'SY-TABIX'. code_line_index = |{ code_line_index } line_index( { table }[ { key } ] )| ##NO_TEXT. - ELSEIF code_line_index IS INITIAL. + elseif code_line_index is initial. code_line_index = -lexeme. - ELSE. + else. code_line_index = |{ code_line_index } { -lexeme }|. - ENDIF. - ENDLOOP. + endif. + endloop. code_line_index = |{ code_line_index }.|. - APPEND code_line_index TO code_lines. - ELSE. - DATA(idx) = analyzer->find_clause_index( tokens = -tokens clause = '=' ). - IF idx = 0 OR -tokens[ idx + 1 ]-lexeme <> 'ABAP_TRUE'. - RETURN. - ENDIF. - LOOP AT -tokens TO idx - 1 ASSIGNING . - IF code_line_exists IS INITIAL. + append code_line_index to code_lines. + else. + data(idx) = analyzer->find_clause_index( tokens = -tokens clause = '=' ). + if idx = 0 or -tokens[ idx + 1 ]-lexeme <> 'ABAP_TRUE'. + return. + endif. + loop at -tokens to idx - 1 assigning . + if code_line_exists is initial. code_line_exists = -lexeme. - ELSE. + else. code_line_exists = |{ code_line_exists } { -lexeme }|. - ENDIF. - ENDLOOP. + endif. + endloop. code_line_exists = |{ code_line_exists } = xsdbool( line_exists( { table }[ { key } ] ) ).| ##NO_TEXT. - APPEND code_line_exists TO code_lines. - ENDIF. - ENDCASE. - ENDLOOP. - IF contains_exit = abap_true. - DATA quickfixes TYPE REF TO cl_ci_atc_quickfixes. - IF quickfixable = abap_true. + append code_line_exists to code_lines. + endif. + endcase. + endloop. + if contains_exit = abap_true. + data quickfixes type ref to cl_ci_atc_quickfixes. + if quickfixable = abap_true. quickfixes = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-line_exists ). + data(quickfix) = quickfixes->create_quickfix( quickfix_codes-line_exists ). quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = statement_index to = end_idx ) ) ) + value #( procedure_id = procedure-id statements = value #( from = statement_index to = end_idx ) ) ) code = code_lines ). - ENDIF. + endif. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-line_exists pseudo_comment = pseudo_comments-line_exists quickfixes = quickfixes - CHANGING findings = findings ). - ENDIF. - ENDMETHOD. + changing findings = findings ). + endif. + endmethod. - METHOD analyze_create_object. - DATA code_line TYPE string. - DATA(statement) = procedure-statements[ statement_index ]. - DATA(replace_data) = abap_true. + method analyze_create_object. + data code_line type string. + data(statement) = procedure-statements[ statement_index ]. + data(replace_data) = abap_true. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'TYPE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'AREA HANDLE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 "old exceptions cannot be handled with NEW - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'FOR TESTING' ) <> 0. - RETURN. - ENDIF. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'TYPE' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'AREA HANDLE' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 "old exceptions cannot be handled with NEW + or analyzer->find_clause_index( tokens = statement-tokens clause = 'FOR TESTING' ) <> 0. + return. + endif. - DATA(object_name) = statement-tokens[ 3 ]-lexeme. - DATA(full_name) = statement-tokens[ 3 ]-references[ lines( statement-tokens[ 3 ]-references ) ]-full_name. + data(object_name) = statement-tokens[ 3 ]-lexeme. + data(full_name) = statement-tokens[ 3 ]-references[ lines( statement-tokens[ 3 ]-references ) ]-full_name. * self reference is working with create object but not with new - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() FROM 4 WHERE lexeme CP |{ object_name }*| AND references IS NOT INITIAL. - LOOP AT -references TRANSPORTING NO FIELDS WHERE full_name CP |{ full_name }*|. + loop at statement-tokens assigning field-symbol() from 4 where lexeme cp |{ object_name }*| and references is not initial. + loop at -references transporting no fields where full_name cp |{ full_name }*|. replace_data = abap_false. - EXIT. - ENDLOOP. - ENDLOOP. + exit. + endloop. + endloop. * find data statement - DATA(data_idx) = statement_index - 1. - WHILE data_idx > 0. - IF procedure-statements[ data_idx ]-keyword = 'DATA' - AND procedure-statements[ data_idx ]-tokens[ 2 ]-lexeme = object_name. - ASSIGN procedure-statements[ data_idx ] TO FIELD-SYMBOL(). - DATA(type_idx) = analyzer->find_clause_index( tokens = -tokens clause = 'TYPE REF TO' ). - IF type_idx = 0. - RETURN. - ENDIF. - IF replace_data = abap_true AND data_idx = statement_index - 1. - DATA(type_name) = -tokens[ type_idx + 3 ]-lexeme. + data(data_idx) = statement_index - 1. + while data_idx > 0. + if procedure-statements[ data_idx ]-keyword = 'DATA' + and procedure-statements[ data_idx ]-tokens[ 2 ]-lexeme = object_name. + assign procedure-statements[ data_idx ] to field-symbol(). + data(type_idx) = analyzer->find_clause_index( tokens = -tokens clause = 'TYPE REF TO' ). + if type_idx = 0. + return. + endif. + if replace_data = abap_true and data_idx = statement_index - 1. + data(type_name) = -tokens[ type_idx + 3 ]-lexeme. code_line = |DATA({ object_name }) = NEW { type_name }( |. - DATA(from_idx) = data_idx. - ELSE. + data(from_idx) = data_idx. + else. code_line = |{ object_name } = NEW #( |. from_idx = statement_index. - ENDIF. - ENDIF. + endif. + endif. data_idx -= 1. - ENDWHILE. - IF code_line IS INITIAL. + endwhile. + if code_line is initial. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-prefer_new pseudo_comment = pseudo_comments-prefer_new - CHANGING findings = findings ). - RETURN. - ENDIF. - DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). - - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-prefer_new ). - IF from_idx < statement_index. + changing findings = findings ). + return. + endif. + data(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). + + data(quickfixes) = assistant_factory->create_quickfixes( ). + data(quickfix) = quickfixes->create_quickfix( quickfix_codes-prefer_new ). + if from_idx < statement_index. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id statements = VALUE #( from = from_idx to = statement_index - 1 ) ) ) - code = VALUE #( ( `` ) ) ). - ENDIF. - IF exporting_idx = 0. - DATA(to_idx) = 3. - ELSE. + value #( procedure_id = procedure-id statements = value #( from = from_idx to = statement_index - 1 ) ) ) + code = value #( ( `` ) ) ). + endif. + if exporting_idx = 0. + data(to_idx) = 3. + else. to_idx = exporting_idx. - ENDIF. + endif. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = 1 to = to_idx ) ) ) - code = VALUE #( ( code_line ) ) ). + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = 1 to = to_idx ) ) ) + code = value #( ( code_line ) ) ). quickfix->insert_after( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) - code = VALUE #( ( `)` ) ) ). + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) + code = value #( ( `)` ) ) ). add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-prefer_new pseudo_comment = pseudo_comments-prefer_new quickfixes = quickfixes - CHANGING findings = findings ). - ENDMETHOD. - - - METHOD analyze_call_method. - DATA code_line TYPE string. - DATA(statement) = procedure-statements[ statement_index ]. - IF statement-tokens[ 3 ]-references IS INITIAL AND statement-tokens[ 3 ]-lexeme = 'OF'. "ole - RETURN. - ENDIF. - DATA(method_name) = statement-tokens[ 3 ]-lexeme. - IF method_name(1) = '(' OR method_name CP '*->(*' OR method_name CP '*=>(*' OR method_name CP '(*)' - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'PARAMETER-TABLE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTION-TABLE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0. + changing findings = findings ). + endmethod. + + + method analyze_call_method. + data code_line type string. + data(statement) = procedure-statements[ statement_index ]. + if statement-tokens[ 3 ]-references is initial and statement-tokens[ 3 ]-lexeme = 'OF'. "ole + return. + endif. + data(method_name) = statement-tokens[ 3 ]-lexeme. + if method_name(1) = '(' or method_name cp '*->(*' or method_name cp '*=>(*' or method_name cp '(*)' + or analyzer->find_clause_index( tokens = statement-tokens clause = 'PARAMETER-TABLE' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTION-TABLE' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0. * dynamic call / exceptions - RETURN. - ENDIF. + return. + endif. - IF method_name NP '*('. - DATA(method_line) = |{ method_name }(|. - ELSE. + if method_name np '*('. + data(method_line) = |{ method_name }(|. + else. method_line = method_name. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) = 0 - AND analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) = 0 . - DATA(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). - DATA(receiving_infos) = get_receiving_infos( tokens = statement-tokens ). - ENDIF. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-call_method ). - IF lines( statement-tokens ) = 3 - OR lines( statement-tokens ) = 4. + endif. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) = 0 + and analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) = 0 . + data(exporting_idx) = analyzer->find_clause_index( tokens = statement-tokens clause = 'EXPORTING' ). + data(receiving_infos) = get_receiving_infos( tokens = statement-tokens ). + endif. + data(quickfixes) = assistant_factory->create_quickfixes( ). + data(quickfix) = quickfixes->create_quickfix( quickfix_codes-call_method ). + if lines( statement-tokens ) = 3 + or lines( statement-tokens ) = 4. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) ) ) - code = VALUE #( ( |{ method_line } ).| ) ) ). - ELSE. - IF exporting_idx <> 0. + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) ) ) + code = value #( ( |{ method_line } ).| ) ) ). + else. + if exporting_idx <> 0. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = exporting_idx to = exporting_idx ) ) ) - code = VALUE #( ( `` ) ) ). - ENDIF. - IF receiving_infos-result_line IS NOT INITIAL. - IF receiving_infos-end_idx = lines( statement-tokens ). + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = exporting_idx to = exporting_idx ) ) ) + code = value #( ( `` ) ) ). + endif. + if receiving_infos-result_line is not initial. + if receiving_infos-end_idx = lines( statement-tokens ). code_line = ')'. - ELSE. + else. code_line = ''. - ENDIF. + endif. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = receiving_infos-receiving_idx to = receiving_infos-end_idx ) ) ) - code = VALUE #( ( code_line ) ) ). + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = receiving_infos-receiving_idx to = receiving_infos-end_idx ) ) ) + code = value #( ( code_line ) ) ). method_line = |{ receiving_infos-result_line } = { method_line }|. - ENDIF. + endif. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = 1 to = 3 ) ) ) - code = VALUE #( ( method_line ) ) ). + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = 1 to = 3 ) ) ) + code = value #( ( method_line ) ) ). - IF receiving_infos-end_idx <> lines( statement-tokens ) AND method_name NP '*('. + if receiving_infos-end_idx <> lines( statement-tokens ) and method_name np '*('. quickfix->insert_after( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) - code = VALUE #( ( `)` ) ) ). - ENDIF. - ENDIF. + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = lines( statement-tokens ) to = lines( statement-tokens ) ) ) ) + code = value #( ( `)` ) ) ). + endif. + endif. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-call_method pseudo_comment = pseudo_comments-call_method quickfixes = quickfixes - CHANGING findings = findings ). - ENDMETHOD. - - - METHOD analyze_exporting_receiving. - DATA exporting_idxs TYPE SORTED TABLE OF i WITH UNIQUE KEY table_line. - DATA(statement) = procedure-statements[ statement_index ]. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. - RETURN. - ENDIF. - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE references IS INITIAL AND lexeme = 'EXPORTING'. - DATA(token_idx) = sy-tabix. - IF check_remove_exporting( statement = statement token_idx = token_idx ) = abap_true. - INSERT token_idx INTO TABLE exporting_idxs. - ENDIF. - ENDLOOP. - - DATA(receiving_infos) = get_receiving_infos( tokens = statement-tokens ). - - IF receiving_infos-result_line IS INITIAL AND exporting_idxs IS INITIAL. - RETURN. - ENDIF. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA pseudo_comment TYPE string. - IF receiving_infos-result_line IS NOT INITIAL. - DATA(finding_code) = message_codes-exporting_receiving. + changing findings = findings ). + endmethod. + + + method analyze_exporting_receiving. + data exporting_idxs type sorted table of i with unique key table_line. + data(statement) = procedure-statements[ statement_index ]. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'EXCEPTIONS' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. + return. + endif. + loop at statement-tokens assigning field-symbol() where references is initial and lexeme = 'EXPORTING'. + data(token_idx) = sy-tabix. + if check_remove_exporting( statement = statement token_idx = token_idx ) = abap_true. + insert token_idx into table exporting_idxs. + endif. + endloop. + + data(receiving_infos) = get_receiving_infos( tokens = statement-tokens ). + + if receiving_infos-result_line is initial and exporting_idxs is initial. + return. + endif. + data(quickfixes) = assistant_factory->create_quickfixes( ). + data pseudo_comment type string. + if receiving_infos-result_line is not initial. + data(finding_code) = message_codes-exporting_receiving. pseudo_comment = pseudo_comments-exporting_receiving. - DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-exporting_receiving ). + data(quickfix) = quickfixes->create_quickfix( quickfix_codes-exporting_receiving ). receiving_infos-result_line = |{ receiving_infos-result_line } = { statement-tokens[ 1 ]-lexeme }|. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = 1 to = 1 ) ) ) - code = VALUE #( ( receiving_infos-result_line ) ) ). + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = 1 to = 1 ) ) ) + code = value #( ( receiving_infos-result_line ) ) ). quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = receiving_infos-receiving_idx to = receiving_infos-end_idx ) ) ) - code = VALUE #( ( `` ) ) ). - ELSE. + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = receiving_infos-receiving_idx to = receiving_infos-end_idx ) ) ) + code = value #( ( `` ) ) ). + else. finding_code = message_codes-method_exporting. pseudo_comment = pseudo_comments-method_exporting. quickfix = quickfixes->create_quickfix( quickfix_codes-method_exporting ). - ENDIF. - LOOP AT exporting_idxs INTO DATA(exporting_idx). + endif. + loop at exporting_idxs into data(exporting_idx). quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = exporting_idx to = exporting_idx + 1 ) ) ) - code = VALUE #( ( statement-tokens[ exporting_idx + 1 ]-lexeme ) ) ). - ENDLOOP. + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = exporting_idx to = exporting_idx + 1 ) ) ) + code = value #( ( statement-tokens[ exporting_idx + 1 ]-lexeme ) ) ). + endloop. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = finding_code pseudo_comment = pseudo_comment quickfixes = quickfixes - CHANGING findings = findings ). - ENDMETHOD. - - - METHOD analyze_text_assembly. - - DATA(statement) = procedure-statements[ statement_index ]. - - DATA start_idx TYPE i. - DATA end_idx TYPE i. - DATA last_idx TYPE i. - DATA code_line TYPE string. - DATA(quickfixes) = assistant_factory->create_quickfixes( ). - DATA(quickfix) = quickfixes->create_quickfix( quickfix_codes-text_assembly ). - DATA(quickfixable) = abap_true. - TRY. - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() WHERE lexeme = '&&'. - DATA(tabix) = sy-tabix. - IF tabix - 1 <> last_idx. - IF code_line IS NOT INITIAL. + changing findings = findings ). + endmethod. + + + method analyze_text_assembly. + + data(statement) = procedure-statements[ statement_index ]. + + data start_idx type i. + data end_idx type i. + data last_idx type i. + data code_line type string. + data(quickfixes) = assistant_factory->create_quickfixes( ). + data(quickfix) = quickfixes->create_quickfix( quickfix_codes-text_assembly ). + data(quickfixable) = abap_true. + try. + loop at statement-tokens assigning field-symbol() where lexeme = '&&'. + data(tabix) = sy-tabix. + if tabix - 1 <> last_idx. + if code_line is not initial. * store old code_line code_line = |{ code_line }\||. - IF strlen( code_line ) >= analyzer->max_line_length - 1. + if strlen( code_line ) >= analyzer->max_line_length - 1. quickfixable = abap_false. - EXIT. - ELSE. + exit. + else. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = start_idx to = end_idx ) ) ) - code = VALUE #( ( code_line ) ) ). - ENDIF. - ENDIF. + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = start_idx to = end_idx ) ) ) + code = value #( ( code_line ) ) ). + endif. + endif. * new && connection code_line = '|'. start_idx = tabix - 1. - DATA(value) = get_value( statement-tokens[ tabix - 1 ] ). + data(value) = get_value( statement-tokens[ tabix - 1 ] ). code_line = |{ code_line }{ value }|. - ENDIF. + endif. value = get_value( statement-tokens[ tabix + 1 ] ). code_line = |{ code_line }{ value }|. end_idx = tabix + 1. last_idx = tabix + 1. - ENDLOOP. - IF quickfixable = abap_true AND code_line IS NOT INITIAL. + endloop. + if quickfixable = abap_true and code_line is not initial. code_line = |{ code_line }\||. - IF strlen( code_line ) >= analyzer->max_line_length - 1. + if strlen( code_line ) >= analyzer->max_line_length - 1. quickfixable = abap_false. - ELSE. + else. quickfix->replace( context = assistant_factory->create_quickfix_context( - VALUE #( procedure_id = procedure-id - statements = VALUE #( from = statement_index to = statement_index ) - tokens = VALUE #( from = start_idx to = end_idx ) ) ) - code = VALUE #( ( code_line ) ) ). - ENDIF. - ENDIF. - CATCH lcx_error. + value #( procedure_id = procedure-id + statements = value #( from = statement_index to = statement_index ) + tokens = value #( from = start_idx to = end_idx ) ) ) + code = value #( ( code_line ) ) ). + endif. + endif. + catch lcx_error. quickfixable = abap_false. - ENDTRY. - IF quickfixable = abap_false. - CLEAR quickfixes. - ENDIF. + endtry. + if quickfixable = abap_false. + clear quickfixes. + endif. add_finding( - EXPORTING + exporting procedure = procedure statement_index = statement_index code = message_codes-text_assembly pseudo_comment = pseudo_comments-text_assembly quickfixes = quickfixes - CHANGING findings = findings ). - - ENDMETHOD. - - - METHOD analyze_procedure. - - LOOP AT procedure-statements ASSIGNING FIELD-SYMBOL(). - DATA(idx) = sy-tabix. - CASE -keyword. - WHEN 'MOVE'. - INSERT LINES OF analyze_move( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'TRANSLATE'. - INSERT LINES OF analyze_translate( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'READ'. - INSERT LINES OF analyze_read( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'LOOP'. - INSERT LINES OF analyze_loop( procedure = procedure statement_index = idx ) INTO TABLE findings. - WHEN 'CREATE'. - IF -tokens[ 2 ]-lexeme = 'OBJECT' AND -tokens[ 2 ]-references IS INITIAL. - INSERT LINES OF analyze_create_object( procedure = procedure statement_index = idx ) INTO TABLE findings. - ENDIF. - WHEN 'CALL'. - IF -tokens[ 2 ]-lexeme = 'METHOD' AND -tokens[ 2 ]-references IS INITIAL. - INSERT LINES OF analyze_call_method( procedure = procedure statement_index = idx ) INTO TABLE findings. - ENDIF. - WHEN 'METHODS' OR 'CLASS-METHODS'. - CONTINUE. - ENDCASE. + changing findings = findings ). + + endmethod. + + + method analyze_procedure. + + loop at procedure-statements assigning field-symbol(). + data(idx) = sy-tabix. + case -keyword. + when 'MOVE'. + insert lines of analyze_move( procedure = procedure statement_index = idx ) into table findings. + when 'TRANSLATE'. + insert lines of analyze_translate( procedure = procedure statement_index = idx ) into table findings. + when 'READ'. + insert lines of analyze_read( procedure = procedure statement_index = idx ) into table findings. + when 'LOOP'. + insert lines of analyze_loop( procedure = procedure statement_index = idx ) into table findings. + when 'CREATE'. + if -tokens[ 2 ]-lexeme = 'OBJECT' and -tokens[ 2 ]-references is initial. + insert lines of analyze_create_object( procedure = procedure statement_index = idx ) into table findings. + endif. + when 'CALL'. + if -tokens[ 2 ]-lexeme = 'METHOD' and -tokens[ 2 ]-references is initial. + insert lines of analyze_call_method( procedure = procedure statement_index = idx ) into table findings. + endif. + when 'METHODS' or 'CLASS-METHODS'. + continue. + endcase. * functional method call may occur in many statements - IF -keyword <> 'CALL' AND -keyword <> 'CREATE' - AND analyzer->find_clause_index( tokens = -tokens clause = 'EXPORTING' ) <> 0. - INSERT LINES OF analyze_exporting_receiving( procedure = procedure statement_index = idx ) INTO TABLE findings. - ENDIF. + if -keyword <> 'CALL' and -keyword <> 'CREATE' + and analyzer->find_clause_index( tokens = -tokens clause = 'EXPORTING' ) <> 0. + insert lines of analyze_exporting_receiving( procedure = procedure statement_index = idx ) into table findings. + endif. * text assembly - IF analyzer->find_clause_index( tokens = -tokens clause = '&&' ) <> 0 - AND -keyword <> 'CONCATENATE' - AND -keyword <> 'SPLIT' - AND analyzer->is_db_statement( statement = ) IS INITIAL. - INSERT LINES OF analyze_text_assembly( procedure = procedure statement_index = idx ) INTO TABLE findings. - ENDIF. - ENDLOOP. - ENDMETHOD. + if analyzer->find_clause_index( tokens = -tokens clause = '&&' ) <> 0 + and -keyword <> 'CONCATENATE' + and -keyword <> 'SPLIT' + and analyzer->is_db_statement( statement = ) is initial. + insert lines of analyze_text_assembly( procedure = procedure statement_index = idx ) into table findings. + endif. + endloop. + endmethod. - METHOD is_used. + method is_used. result = abap_false. - LOOP AT procedure-statements FROM from_index ASSIGNING FIELD-SYMBOL(). - LOOP AT -tokens ASSIGNING FIELD-SYMBOL() - WHERE references IS NOT INITIAL. + loop at procedure-statements from from_index assigning field-symbol(). + loop at -tokens assigning field-symbol() + where references is not initial. result = xsdbool( line_exists( -references[ full_name = full_name ] ) ). - IF result = abap_true. - RETURN. - ENDIF. - ENDLOOP. - ENDLOOP. - ENDMETHOD. + if result = abap_true. + return. + endif. + endloop. + endloop. + endmethod. - METHOD check_remove_exporting. + method check_remove_exporting. result = abap_false. - ASSIGN statement-tokens[ token_idx - 1 ] TO FIELD-SYMBOL(). - IF NOT -lexeme CP '*('. - RETURN. - ENDIF. - LOOP AT -references ASSIGNING FIELD-SYMBOL() - WHERE kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-method - AND usage_grade <> if_ci_atc_source_code_provider=>usage_grades-definition. - DATA(is_method_call) = abap_true. - EXIT. - ENDLOOP. - IF is_method_call = abap_false. - RETURN. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. - RETURN. - ENDIF. + assign statement-tokens[ token_idx - 1 ] to field-symbol(). + if not -lexeme cp '*('. + return. + endif. + loop at -references assigning field-symbol() + where kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-method + and usage_grade <> if_ci_atc_source_code_provider=>usage_grades-definition. + data(is_method_call) = abap_true. + exit. + endloop. + if is_method_call = abap_false. + return. + endif. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'IMPORTING' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'CHANGING' ) <> 0. + return. + endif. result = abap_true. - ENDMETHOD. - - - METHOD get_value. - IF token-lexeme CP '*(' - OR token-lexeme CP '*[' - OR token-lexeme(1) = ']' - OR token-lexeme(1) = ')'. - RAISE EXCEPTION TYPE lcx_error. - ENDIF. - - IF token-references IS INITIAL. - CASE token-lexeme. - WHEN ')' OR '|'. - RAISE EXCEPTION TYPE lcx_error. - WHEN OTHERS. - IF token-lexeme CP '`*`' OR token-lexeme CP `'*'`. - DATA(len) = strlen( token-lexeme ) - 2. + endmethod. + + + method get_value. + if token-lexeme cp '*(' + or token-lexeme cp '*[' + or token-lexeme(1) = ']' + or token-lexeme(1) = ')'. + raise exception type lcx_error. + endif. + + if token-references is initial. + case token-lexeme. + when ')' or '|'. + raise exception type lcx_error. + when others. + if token-lexeme cp '`*`' or token-lexeme cp `'*'`. + data(len) = strlen( token-lexeme ) - 2. result = token-lexeme+1(len). - IF result CA '|'. - RAISE EXCEPTION TYPE lcx_error. - ENDIF. + if result ca '|'. + raise exception type lcx_error. + endif. result = replace( val = result sub = '\' with = '\\' occ = 0 ). result = replace( val = result sub = '{' with = '\{' occ = 0 ). result = replace( val = result sub = '}' with = '\}' occ = 0 ). - ELSE. - RAISE EXCEPTION TYPE lcx_error. - ENDIF. - ENDCASE. - ELSE. - IF token-lexeme = 'NEW'. - RAISE EXCEPTION TYPE lcx_error. - ENDIF. + else. + raise exception type lcx_error. + endif. + endcase. + else. + if token-lexeme = 'NEW'. + raise exception type lcx_error. + endif. result = |\{ { token-lexeme } \}|. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD append_token. - IF result IS INITIAL. + method append_token. + if result is initial. result = token-lexeme. - ELSE. + else. result = |{ result } { token-lexeme }|. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD append_tokens. - DATA itab LIKE tokens. - IF from_idx IS SUPPLIED OR to_idx IS SUPPLIED. - IF from_idx = 0. + method append_tokens. + data itab like tokens. + if from_idx is supplied or to_idx is supplied. + if from_idx = 0. from_idx = 1. - ENDIF. - IF to_idx = 0. + endif. + if to_idx = 0. to_idx = lines( tokens ). - ENDIF. - LOOP AT tokens FROM from_idx TO to_idx ASSIGNING FIELD-SYMBOL(). - APPEND TO itab. - ENDLOOP. - DATA(flattened) = analyzer->flatten_tokens( tokens = itab ). - ELSE. + endif. + loop at tokens from from_idx to to_idx assigning field-symbol(). + append to itab. + endloop. + data(flattened) = analyzer->flatten_tokens( tokens = itab ). + else. flattened = analyzer->flatten_tokens( tokens = tokens ). - ENDIF. - IF result IS INITIAL. + endif. + if result is initial. result = flattened. - ELSE. + else. result = |{ result } { flattened }|. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD get_receiving_infos. - CLEAR result-end_idx. - CLEAR result-result_line. + method get_receiving_infos. + clear result-end_idx. + clear result-result_line. result-receiving_idx = analyzer->find_clause_index( tokens = tokens clause = 'RECEIVING ' ). - IF result-receiving_idx = 0. - RETURN. - ENDIF. - DATA(copy_idx) = analyzer->find_clause_index( tokens = tokens start_index = result-receiving_idx + 1 clause = '=' ). - IF copy_idx <> 0. + if result-receiving_idx = 0. + return. + endif. + data(copy_idx) = analyzer->find_clause_index( tokens = tokens start_index = result-receiving_idx + 1 clause = '=' ). + if copy_idx <> 0. result-end_idx = lines( tokens ). - LOOP AT tokens FROM copy_idx + 1 ASSIGNING FIELD-SYMBOL() - WHERE references IS INITIAL. - CASE -lexeme. - WHEN ')' OR 'EXPORTING'. + loop at tokens from copy_idx + 1 assigning field-symbol() + where references is initial. + case -lexeme. + when ')' or 'EXPORTING'. result-end_idx = sy-tabix - 1. - EXIT. - ENDCASE. - ENDLOOP. - append_tokens( EXPORTING tokens = tokens from_idx = copy_idx + 1 to_idx = result-end_idx CHANGING result = result-result_line ). - ENDIF. - - ENDMETHOD. -ENDCLASS. + exit. + endcase. + endloop. + append_tokens( exporting tokens = tokens from_idx = copy_idx + 1 to_idx = result-end_idx changing result = result-result_line ). + endif. + + endmethod. +endclass. diff --git a/src/checks/#cc4a#modern_language.clas.locals_imp.abap b/src/checks/#cc4a#modern_language.clas.locals_imp.abap index cafb524..a281e4e 100644 --- a/src/checks/#cc4a#modern_language.clas.locals_imp.abap +++ b/src/checks/#cc4a#modern_language.clas.locals_imp.abap @@ -2,5 +2,5 @@ *"* local helper classes, interface definitions and type *"* declarations -class lcx_error IMPLEMENTATION. +class lcx_error implementation. endclass. diff --git a/src/checks/#cc4a#modern_language.clas.testclasses.abap b/src/checks/#cc4a#modern_language.clas.testclasses.abap index 3a656d4..0d2050d 100644 --- a/src/checks/#cc4a#modern_language.clas.testclasses.abap +++ b/src/checks/#cc4a#modern_language.clas.testclasses.abap @@ -1,80 +1,78 @@ - - -CLASS test DEFINITION FINAL FOR TESTING - DURATION SHORT - RISK LEVEL HARMLESS. - - PRIVATE SECTION. - CONSTANTS test_class TYPE c LENGTH 30 VALUE '/CC4A/TEST_MODERN_LANGUAGE'. - METHODS test FOR TESTING RAISING cx_static_check. -ENDCLASS. -CLASS /cc4a/modern_language DEFINITION LOCAL FRIENDS test. - -CLASS test IMPLEMENTATION. - - METHOD test. - DATA(test_translate) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_TRANSLATE' ) ). - DATA(test_read) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_READ' ) ). - DATA(test_loop) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_LOOP' ) ). - DATA(test_create_object) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_CREATE_OBJECT' ) ). - DATA(test_call_method) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_CALL_METHOD' ) ). - DATA(test_exporting_receiving) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_EXPORTING_RECEIVING' ) ). - DATA(test_text_assembly) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'TEST_TEXT_ASSEMBLY' ) ). +class test definition final for testing + duration short + risk level harmless. + + private section. + constants test_class type c length 30 value '/CC4A/TEST_MODERN_LANGUAGE'. + methods test for testing raising cx_static_check. +endclass. +class /cc4a/modern_language definition local friends test. + +class test implementation. + + method test. + data(test_translate) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'TEST_TRANSLATE' ) ). + data(test_read) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'TEST_READ' ) ). + data(test_loop) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'TEST_LOOP' ) ). + data(test_create_object) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'TEST_CREATE_OBJECT' ) ). + data(test_call_method) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'TEST_CALL_METHOD' ) ). + data(test_exporting_receiving) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'TEST_EXPORTING_RECEIVING' ) ). + data(test_text_assembly) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'TEST_TEXT_ASSEMBLY' ) ). cl_ci_atc_unit_driver=>create_test_case( - check = NEW /cc4a/modern_language( ) - object = VALUE #( type = 'CLAS' name = test_class ) - )->execute_and_assert( VALUE #( + check = new /cc4a/modern_language( ) + object = value #( type = 'CLAS' name = test_class ) + )->execute_and_assert( value #( * TRANSLATE ( code = /cc4a/modern_language=>message_codes-translate - location = VALUE #( object = test_translate position = VALUE #( line = 3 column = 4 ) ) ) + location = value #( object = test_translate position = value #( line = 3 column = 4 ) ) ) ( code = /cc4a/modern_language=>message_codes-translate - location = VALUE #( object = test_translate position = VALUE #( line = 4 column = 4 ) ) ) + location = value #( object = test_translate position = value #( line = 4 column = 4 ) ) ) ( code = /cc4a/modern_language=>message_codes-translate - location = VALUE #( object = test_translate position = VALUE #( line = 5 column = 4 ) ) + location = value #( object = test_translate position = value #( line = 5 column = 4 ) ) has_pseudo_comment = abap_true ) * READ ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 4 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 4 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 4 to = 5 ) - code_lines = VALUE #( ( `DATA(IDX) = LINE_INDEX( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ).` ) ) ) ) ) + span = value #( object = test_read from = 4 to = 5 ) + code_lines = value #( ( `DATA(IDX) = LINE_INDEX( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 7 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 7 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 7 to = 11 ) - code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ).` ) + span = value #( object = test_read from = 7 to = 11 ) + code_lines = value #( ( `IDX = LINE_INDEX( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ).` ) ( `DATA(EXISTS) = XSDBOOL( LINE_EXISTS( ITAB[ PGMID = 'R3TR' OBJECT = 'CLAS' ] ) ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 19 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 19 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 19 to = 20 ) - code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ).` ) ) ) ) ) + span = value #( object = test_read from = 19 to = 20 ) + code_lines = value #( ( `IDX = LINE_INDEX( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 21 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 21 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 21 to = 25 ) - code_lines = VALUE #( ( `EXISTS = XSDBOOL( LINE_EXISTS( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ) ).` ) + span = value #( object = test_read from = 21 to = 25 ) + code_lines = value #( ( `EXISTS = XSDBOOL( LINE_EXISTS( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ) ).` ) ( `IDX = LINE_INDEX( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLABLA' ] ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 27 column = 4 ) ) + location = value #( object = test_read position = value #( line = 27 column = 4 ) ) has_pseudo_comment = abap_true ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 34 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 34 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 34 to = 35 ) - code_lines = VALUE #( ( `IDX = line_index( ITAB[ PGMID = 'R3TR' ] ).` ) ) ) ) ) + span = value #( object = test_read from = 34 to = 35 ) + code_lines = value #( ( `IDX = line_index( ITAB[ PGMID = 'R3TR' ] ).` ) ) ) ) ) * ( code = /cc4a/modern_language=>message_codes-move * location = VALUE #( object = test_read position = VALUE #( line = 35 column = 4 ) ) @@ -84,190 +82,190 @@ CLASS test IMPLEMENTATION. * code_lines = VALUE #( ( `idx = sy-tabix.` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 37 column = 4 ) ) + location = value #( object = test_read position = value #( line = 37 column = 4 ) ) has_pseudo_comment = abap_true ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 41 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 41 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 41 to = 44 ) - code_lines = VALUE #( ( `DATA(BLUE) = xsdbool( NOT line_exists( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLUE' ] ) ).` ) ) ) ) ) + span = value #( object = test_read from = 41 to = 44 ) + code_lines = value #( ( `DATA(BLUE) = xsdbool( NOT line_exists( ITAB[ KEY NAME COMPONENTS OBJ_NAME = 'BLUE' ] ) ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 46 column = 4 ) ) + location = value #( object = test_read position = value #( line = 46 column = 4 ) ) has_pseudo_comment = abap_true ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 52 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 52 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 52 to = 54 ) - code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) = 0 .` ) ) ) ) ) + span = value #( object = test_read from = 52 to = 54 ) + code_lines = value #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) = 0 .` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 57 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 57 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 57 to = 59 ) - code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) = 0 .` ) ) ) ) ) + span = value #( object = test_read from = 57 to = 59 ) + code_lines = value #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) = 0 .` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 62 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_read position = value #( line = 62 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 62 to = 64 ) - code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) + span = value #( object = test_read from = 62 to = 64 ) + code_lines = value #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 67 column = 4 ) ) + location = value #( object = test_read position = value #( line = 67 column = 4 ) ) has_pseudo_comment = abap_true - quickfixes = VALUE #( ( + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_read from = 67 to = 69 ) - code_lines = VALUE #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) + span = value #( object = test_read from = 67 to = 69 ) + code_lines = value #( ( `IF line_index( ITAB[ PGMID = 'R3TR' ] ) <> 0 .` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 73 column = 4 ) ) + location = value #( object = test_read position = value #( line = 73 column = 4 ) ) has_pseudo_comment = abap_true ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 76 column = 4 ) ) + location = value #( object = test_read position = value #( line = 76 column = 4 ) ) has_pseudo_comment = abap_true ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_read position = VALUE #( line = 81 column = 4 ) ) + location = value #( object = test_read position = value #( line = 81 column = 4 ) ) has_pseudo_comment = abap_true ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_loop position = VALUE #( line = 4 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_loop position = value #( line = 4 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_loop from = 4 to = 7 ) - code_lines = VALUE #( ( `DATA(IDX) = LINE_INDEX( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ).` ) ) ) ) ) + span = value #( object = test_loop from = 4 to = 7 ) + code_lines = value #( ( `DATA(IDX) = LINE_INDEX( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_loop position = VALUE #( line = 9 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_loop position = value #( line = 9 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_loop from = 9 to = 13 ) - code_lines = VALUE #( ( `IDX = LINE_INDEX( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ).` ) + span = value #( object = test_loop from = 9 to = 13 ) + code_lines = value #( ( `IDX = LINE_INDEX( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ).` ) ( `DATA(EXISTS) = XSDBOOL( LINE_EXISTS( ITAB[ pgmid = 'R3TR' object = 'CLAS' ] ) ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_loop position = VALUE #( line = 21 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_loop position = value #( line = 21 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_loop from = 21 to = 24 ) - code_lines = VALUE #( ( `EXISTS = xsdbool( line_exists( ITAB[ OBJ_NAME = 'BLA' ] ) ).` ) ) ) ) ) + span = value #( object = test_loop from = 21 to = 24 ) + code_lines = value #( ( `EXISTS = xsdbool( line_exists( ITAB[ OBJ_NAME = 'BLA' ] ) ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-line_exists - location = VALUE #( object = test_loop position = VALUE #( line = 38 column = 4 ) ) + location = value #( object = test_loop position = value #( line = 38 column = 4 ) ) has_pseudo_comment = abap_true - quickfixes = VALUE #( ( + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-line_exists - span = VALUE #( object = test_loop from = 38 to = 41 ) - code_lines = VALUE #( ( `EXISTS = xsdbool( line_exists( ITAB[ OBJ_NAME = 'BLA' ] ) ).` ) ) ) ) ) + span = value #( object = test_loop from = 38 to = 41 ) + code_lines = value #( ( `EXISTS = xsdbool( line_exists( ITAB[ OBJ_NAME = 'BLA' ] ) ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-prefer_new - location = VALUE #( object = test_create_object position = VALUE #( line = 3 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_create_object position = value #( line = 3 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new - span = VALUE #( object = test_create_object from = 2 to = 3 ) - code_lines = VALUE #( ( `DATA(object1) = NEW /cc4a/test_modern_language( ).` ) ) ) ) ) + span = value #( object = test_create_object from = 2 to = 3 ) + code_lines = value #( ( `DATA(object1) = NEW /cc4a/test_modern_language( ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-prefer_new - location = VALUE #( object = test_create_object position = VALUE #( line = 5 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_create_object position = value #( line = 5 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new - span = VALUE #( object = test_create_object from = 5 to = 5 ) - code_lines = VALUE #( ( `object1 = NEW #( ).` ) ) ) ) ) + span = value #( object = test_create_object from = 5 to = 5 ) + code_lines = value #( ( `object1 = NEW #( ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-prefer_new - location = VALUE #( object = test_create_object position = VALUE #( line = 9 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_create_object position = value #( line = 9 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new - span = VALUE #( object = test_create_object from = 7 to = 12 ) - code_lines = VALUE #( ( `DATA(CLASS_REF) = NEW LCL_TEST( PARAM1 = 5 PARAM2 = 4 ).` ) ) ) ) ) + span = value #( object = test_create_object from = 7 to = 12 ) + code_lines = value #( ( `DATA(CLASS_REF) = NEW LCL_TEST( PARAM1 = 5 PARAM2 = 4 ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-prefer_new - location = VALUE #( object = test_create_object position = VALUE #( line = 16 column = 8 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_create_object position = value #( line = 16 column = 8 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new - span = VALUE #( object = test_create_object from = 16 to = 18 ) - code_lines = VALUE #( ( `CLASS_REF1 = NEW #( PARAM1 = 15 ).` ) ) ) ) ) + span = value #( object = test_create_object from = 16 to = 18 ) + code_lines = value #( ( `CLASS_REF1 = NEW #( PARAM1 = 15 ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-prefer_new - location = VALUE #( object = test_create_object position = VALUE #( line = 32 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_create_object position = value #( line = 32 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new - span = VALUE #( object = test_create_object from = 31 to = 35 ) - code_lines = VALUE #( ( `DATA(CLASS_REF3) = NEW LCL_TEST3( param1 = 'blabla' param2 = |{ sy-datum } { sy-uzeit }| ).` ) ) ) ) ) + span = value #( object = test_create_object from = 31 to = 35 ) + code_lines = value #( ( `DATA(CLASS_REF3) = NEW LCL_TEST3( param1 = 'blabla' param2 = |{ sy-datum } { sy-uzeit }| ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-prefer_new - location = VALUE #( object = test_create_object position = VALUE #( line = 37 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_create_object position = value #( line = 37 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new - span = VALUE #( object = test_create_object from = 37 to = 40 ) - code_lines = VALUE #( ( `CLASS_REF3 = NEW #( param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ).` ) ) ) ) ) + span = value #( object = test_create_object from = 37 to = 40 ) + code_lines = value #( ( `CLASS_REF3 = NEW #( param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-prefer_new - location = VALUE #( object = test_create_object position = VALUE #( line = 42 column = 4 ) ) + location = value #( object = test_create_object position = value #( line = 42 column = 4 ) ) has_pseudo_comment = abap_true - quickfixes = VALUE #( ( + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new - span = VALUE #( object = test_create_object from = 42 to = 45 ) - code_lines = VALUE #( ( `CLASS_REF3 = NEW #( param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ).` ) ) ) ) ) + span = value #( object = test_create_object from = 42 to = 45 ) + code_lines = value #( ( `CLASS_REF3 = NEW #( param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-prefer_new - location = VALUE #( object = test_create_object position = VALUE #( line = 49 column = 4 ) ) + location = value #( object = test_create_object position = value #( line = 49 column = 4 ) ) has_pseudo_comment = abap_true - quickfixes = VALUE #( ( + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-prefer_new - span = VALUE #( object = test_create_object from = 49 to = 51 ) - code_lines = VALUE #( ( `SELFISH = NEW #( val = selfish->my_val ).` ) ) ) ) ) + span = value #( object = test_create_object from = 49 to = 51 ) + code_lines = value #( ( `SELFISH = NEW #( val = selfish->my_val ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-call_method - location = VALUE #( object = test_call_method position = VALUE #( line = 6 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_call_method position = value #( line = 6 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method - span = VALUE #( object = test_call_method from = 6 to = 6 ) - code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) + span = value #( object = test_call_method from = 6 to = 6 ) + code_lines = value #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-call_method - location = VALUE #( object = test_call_method position = VALUE #( line = 8 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_call_method position = value #( line = 8 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method - span = VALUE #( object = test_call_method from = 8 to = 8 ) - code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) + span = value #( object = test_call_method from = 8 to = 8 ) + code_lines = value #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-call_method - location = VALUE #( object = test_call_method position = VALUE #( line = 10 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_call_method position = value #( line = 10 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method - span = VALUE #( object = test_call_method from = 10 to = 14 ) - code_lines = VALUE #( ( `DATA(RESULT) = CLASS_REF->TEST1( PARAM1 = 15 ).` ) ) ) ) ) + span = value #( object = test_call_method from = 10 to = 14 ) + code_lines = value #( ( `DATA(RESULT) = CLASS_REF->TEST1( PARAM1 = 15 ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-call_method - location = VALUE #( object = test_call_method position = VALUE #( line = 16 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_call_method position = value #( line = 16 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method - span = VALUE #( object = test_call_method from = 16 to = 22 ) - code_lines = VALUE #( ( `CLASS_REF->TEST2(` ) + span = value #( object = test_call_method from = 16 to = 22 ) + code_lines = value #( ( `CLASS_REF->TEST2(` ) ( `EXPORTING PARAM1 = 'Blabla'` ) ( `IMPORTING PARAM2 = DATA(STRING_RESULT)` ) ( `CHANGING PARAM3 = TEST_STRING ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-call_method - location = VALUE #( object = test_call_method position = VALUE #( line = 33 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_call_method position = value #( line = 33 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method - span = VALUE #( object = test_call_method from = 33 to = 39 ) - code_lines = VALUE #( ( `CLASS_REF->TEST4(` ) + span = value #( object = test_call_method from = 33 to = 39 ) + code_lines = value #( ( `CLASS_REF->TEST4(` ) ( `EXPORTING` ) ( `param1 = 1` ) ( `param2 = 2` ) @@ -277,152 +275,152 @@ CLASS test IMPLEMENTATION. ( `).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-call_method - location = VALUE #( object = test_call_method position = VALUE #( line = 41 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_call_method position = value #( line = 41 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method - span = VALUE #( object = test_call_method from = 41 to = 41 ) - code_lines = VALUE #( ( `class_ref->test1( param1 = 3 ).` ) ) ) ) ) + span = value #( object = test_call_method from = 41 to = 41 ) + code_lines = value #( ( `class_ref->test1( param1 = 3 ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-call_method - location = VALUE #( object = test_call_method position = VALUE #( line = 51 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_call_method position = value #( line = 51 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method - span = VALUE #( object = test_call_method from = 51 to = 51 ) - code_lines = VALUE #( ( ` class_ref->test7(` ) ) ) ) ) + span = value #( object = test_call_method from = 51 to = 51 ) + code_lines = value #( ( ` class_ref->test7(` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-call_method - location = VALUE #( object = test_call_method position = VALUE #( line = 59 column = 4 ) ) + location = value #( object = test_call_method position = value #( line = 59 column = 4 ) ) has_pseudo_comment = abap_true - quickfixes = VALUE #( ( + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-call_method - span = VALUE #( object = test_call_method from = 59 to = 59 ) - code_lines = VALUE #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) + span = value #( object = test_call_method from = 59 to = 59 ) + code_lines = value #( ( `TEST_CREATE_OBJECT( ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-method_exporting - location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 6 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_exporting_receiving position = value #( line = 6 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-method_exporting - span = VALUE #( object = test_call_method from = 6 to = 8 ) - code_lines = VALUE #( ( `DATA(RESULT) = CLASS_REF->TEST1(` ) + span = value #( object = test_call_method from = 6 to = 8 ) + code_lines = value #( ( `DATA(RESULT) = CLASS_REF->TEST1(` ) ( `PARAM1 = 15 ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-method_exporting - location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 18 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_exporting_receiving position = value #( line = 18 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-method_exporting - span = VALUE #( object = test_call_method from = 18 to = 18 ) - code_lines = VALUE #( ( `result = class_ref->test3( param1 = 15 ).` ) ) ) ) ) + span = value #( object = test_call_method from = 18 to = 18 ) + code_lines = value #( ( `result = class_ref->test3( param1 = 15 ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-method_exporting - location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 20 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_exporting_receiving position = value #( line = 20 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-method_exporting - span = VALUE #( object = test_exporting_receiving from = 20 to = 20 ) - code_lines = VALUE #( ( `result = class_ref->test1( param1 = class_ref->test3( param1 = 3 ) ).` ) ) ) ) ) + span = value #( object = test_exporting_receiving from = 20 to = 20 ) + code_lines = value #( ( `result = class_ref->test1( param1 = class_ref->test3( param1 = 3 ) ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-exporting_receiving - location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 23 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_exporting_receiving position = value #( line = 23 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-exporting_receiving - span = VALUE #( object = test_exporting_receiving from = 23 to = 26 ) - code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST1( PARAM1 = 15 ).` ) ) ) ) ) + span = value #( object = test_exporting_receiving from = 23 to = 26 ) + code_lines = value #( ( `RESULT = CLASS_REF->TEST1( PARAM1 = 15 ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-exporting_receiving - location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 29 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_exporting_receiving position = value #( line = 29 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-exporting_receiving - span = VALUE #( object = test_exporting_receiving from = 29 to = 29 ) - code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST3( PARAM1 = 15 ).` ) ) ) ) ) + span = value #( object = test_exporting_receiving from = 29 to = 29 ) + code_lines = value #( ( `RESULT = CLASS_REF->TEST3( PARAM1 = 15 ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-exporting_receiving - location = VALUE #( object = test_exporting_receiving position = VALUE #( line = 33 column = 4 ) ) + location = value #( object = test_exporting_receiving position = value #( line = 33 column = 4 ) ) has_pseudo_comment = abap_true - quickfixes = VALUE #( ( + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-exporting_receiving - span = VALUE #( object = test_exporting_receiving from = 33 to = 33 ) - code_lines = VALUE #( ( `RESULT = CLASS_REF->TEST1( PARAM1 = CLASS_REF->TEST3( PARAM1 = 3 ) ).` ) ) ) ) ) + span = value #( object = test_exporting_receiving from = 33 to = 33 ) + code_lines = value #( ( `RESULT = CLASS_REF->TEST1( PARAM1 = CLASS_REF->TEST3( PARAM1 = 3 ) ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 4 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_text_assembly position = value #( line = 4 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly - span = VALUE #( object = test_text_assembly from = 4 to = 4 ) - code_lines = VALUE #( ( `text1 = |ab{ TEXT1 }{ ABAP_TRUE }|.` ) ) ) ) ) + span = value #( object = test_text_assembly from = 4 to = 4 ) + code_lines = value #( ( `text1 = |ab{ TEXT1 }{ ABAP_TRUE }|.` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 5 column = 4 ) ) ) + location = value #( object = test_text_assembly position = value #( line = 5 column = 4 ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 7 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_text_assembly position = value #( line = 7 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly - span = VALUE #( object = test_text_assembly from = 7 to = 7 ) - code_lines = VALUE #( ( ` DATA(bla) = class_ref->test5( param1 = |ab| param2 = |cd| ).` ) ) ) ) ) + span = value #( object = test_text_assembly from = 7 to = 7 ) + code_lines = value #( ( ` DATA(bla) = class_ref->test5( param1 = |ab| param2 = |cd| ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 9 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_text_assembly position = value #( line = 9 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly - span = VALUE #( object = test_text_assembly from = 9 to = 9 ) - code_lines = VALUE #( ( `bla = class_ref->test5( param1 = |ab| param2 = 'xxx' ).` ) ) ) ) ) + span = value #( object = test_text_assembly from = 9 to = 9 ) + code_lines = value #( ( `bla = class_ref->test5( param1 = |ab| param2 = 'xxx' ).` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 11 column = 4 ) ) ) + location = value #( object = test_text_assembly position = value #( line = 11 column = 4 ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 13 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_text_assembly position = value #( line = 13 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly - span = VALUE #( object = test_text_assembly from = 13 to = 13 ) - code_lines = VALUE #( ( `text1 = |{ TEXT1 } \}| ##no_text.` ) ) ) ) ) + span = value #( object = test_text_assembly from = 13 to = 13 ) + code_lines = value #( ( `text1 = |{ TEXT1 } \}| ##no_text.` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 15 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_text_assembly position = value #( line = 15 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly - span = VALUE #( object = test_text_assembly from = 15 to = 18 ) - code_lines = VALUE #( ( `text1 = |[\{"TYPE":"U","TARGET":\{"URL":\{"URL":"www.sap.com/en"\}\}\},\{\}]|.` ) ) ) ) ) + span = value #( object = test_text_assembly from = 15 to = 18 ) + code_lines = value #( ( `text1 = |[\{"TYPE":"U","TARGET":\{"URL":\{"URL":"www.sap.com/en"\}\}\},\{\}]|.` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 21 column = 4 ) ) ) + location = value #( object = test_text_assembly position = value #( line = 21 column = 4 ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 22 column = 4 ) ) ) + location = value #( object = test_text_assembly position = value #( line = 22 column = 4 ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 23 column = 4 ) ) ) + location = value #( object = test_text_assembly position = value #( line = 23 column = 4 ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 25 column = 4 ) ) - quickfixes = VALUE #( ( + location = value #( object = test_text_assembly position = value #( line = 25 column = 4 ) ) + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly - span = VALUE #( object = test_text_assembly from = 25 to = 25 ) - code_lines = VALUE #( ( `text1 = |\\{ TEXT1 }-|.` ) ) ) ) ) + span = value #( object = test_text_assembly from = 25 to = 25 ) + code_lines = value #( ( `text1 = |\\{ TEXT1 }-|.` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 27 column = 4 ) ) + location = value #( object = test_text_assembly position = value #( line = 27 column = 4 ) ) has_pseudo_comment = abap_true - quickfixes = VALUE #( ( + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly - span = VALUE #( object = test_text_assembly from = 27 to = 27 ) - code_lines = VALUE #( ( `bla = |ab|.` ) ) ) ) ) + span = value #( object = test_text_assembly from = 27 to = 27 ) + code_lines = value #( ( `bla = |ab|.` ) ) ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_text_assembly position = VALUE #( line = 29 column = 4 ) ) ) + location = value #( object = test_text_assembly position = value #( line = 29 column = 4 ) ) ) ( code = /cc4a/modern_language=>message_codes-text_assembly - location = VALUE #( object = test_read position = VALUE #( line = 75 column = 4 ) ) + location = value #( object = test_read position = value #( line = 75 column = 4 ) ) has_pseudo_comment = abap_true - quickfixes = VALUE #( ( + quickfixes = value #( ( quickfix_code = /cc4a/modern_language=>quickfix_codes-text_assembly - span = VALUE #( object = test_read from = 75 to = 75 ) - code_lines = VALUE #( ( `bla = |Difference in contructor code/line{ SY-TABIX }|.` ) ) ) ) ) + span = value #( object = test_read from = 75 to = 75 ) + code_lines = value #( ( `bla = |Difference in contructor code/line{ SY-TABIX }|.` ) ) ) ) ) ) ). - ENDMETHOD. + endmethod. -ENDCLASS. +endclass. diff --git a/src/core/#cc4a#abap_analyzer.clas.abap b/src/core/#cc4a#abap_analyzer.clas.abap index addd4f3..058d2f9 100644 --- a/src/core/#cc4a#abap_analyzer.clas.abap +++ b/src/core/#cc4a#abap_analyzer.clas.abap @@ -1,239 +1,239 @@ -CLASS /cc4a/abap_analyzer DEFINITION - PUBLIC - FINAL - CREATE PRIVATE. +class /cc4a/abap_analyzer definition + public + final + create private. - PUBLIC SECTION. - INTERFACES /cc4a/if_abap_analyzer. + public section. + interfaces /cc4a/if_abap_analyzer. - CLASS-METHODS create RETURNING VALUE(instance) TYPE REF TO /cc4a/if_abap_analyzer. - CLASS-METHODS class_constructor. - ALIASES find_clause_index FOR /cc4a/if_abap_analyzer~find_clause_index. - ALIASES is_token_keyword FOR /cc4a/if_abap_analyzer~is_token_keyword. - ALIASES is_db_statement FOR /cc4a/if_abap_analyzer~is_db_statement. - ALIASES is_bracket FOR /cc4a/if_abap_analyzer~is_bracket. - ALIASES max_line_length FOR /cc4a/if_abap_analyzer~max_line_length. + class-methods create returning value(instance) type ref to /cc4a/if_abap_analyzer. + class-methods class_constructor. + aliases find_clause_index for /cc4a/if_abap_analyzer~find_clause_index. + aliases is_token_keyword for /cc4a/if_abap_analyzer~is_token_keyword. + aliases is_db_statement for /cc4a/if_abap_analyzer~is_db_statement. + aliases is_bracket for /cc4a/if_abap_analyzer~is_bracket. + aliases max_line_length for /cc4a/if_abap_analyzer~max_line_length. - PROTECTED SECTION. - PRIVATE SECTION. + protected section. + private section. - TYPES: - BEGIN OF ty_negation, - operator TYPE string, - negated TYPE string, - END OF ty_negation. - CLASS-DATA negations TYPE TABLE OF ty_negation. + types: + begin of ty_negation, + operator type string, + negated type string, + end of ty_negation. + class-data negations type table of ty_negation. - CLASS-METHODS _flatten_tokens - CHANGING tokens TYPE if_ci_atc_source_code_provider=>ty_tokens - RETURNING VALUE(flat) TYPE string. + class-methods _flatten_tokens + changing tokens type if_ci_atc_source_code_provider=>ty_tokens + returning value(flat) type string. - CLASS-METHODS _flatten_template - CHANGING tokens TYPE if_ci_atc_source_code_provider=>ty_tokens - RETURNING VALUE(flat) TYPE string. + class-methods _flatten_template + changing tokens type if_ci_atc_source_code_provider=>ty_tokens + returning value(flat) type string. - CLASS-METHODS _break_into_lines - IMPORTING VALUE(code) TYPE string - break_at TYPE i - RETURNING VALUE(code_lines) TYPE string_table - RAISING /cc4a/cx_line_break_impossible. + class-methods _break_into_lines + importing value(code) type string + break_at type i + returning value(code_lines) type string_table + raising /cc4a/cx_line_break_impossible. -ENDCLASS. +endclass. -CLASS /cc4a/abap_analyzer IMPLEMENTATION. +class /cc4a/abap_analyzer implementation. - METHOD /cc4a/if_abap_analyzer~break_into_lines. + method /cc4a/if_abap_analyzer~break_into_lines. code_lines = _break_into_lines( code = code break_at = max_line_length ). - ENDMETHOD. + endmethod. - METHOD /cc4a/if_abap_analyzer~calculate_bracket_end. - IF is_bracket( statement-tokens[ bracket_position ] ) NE /cc4a/if_abap_analyzer=>bracket_type-opening AND - is_bracket( statement-tokens[ bracket_position ] ) NE /cc4a/if_abap_analyzer=>bracket_type-closing. - RAISE EXCEPTION NEW /cc4a/cx_token_is_no_bracket( ). - ENDIF. + method /cc4a/if_abap_analyzer~calculate_bracket_end. + if is_bracket( statement-tokens[ bracket_position ] ) ne /cc4a/if_abap_analyzer=>bracket_type-opening and + is_bracket( statement-tokens[ bracket_position ] ) ne /cc4a/if_abap_analyzer=>bracket_type-closing. + raise exception new /cc4a/cx_token_is_no_bracket( ). + endif. - DATA(bracket_counter) = 1. - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() FROM bracket_position + 1. - DATA(idx) = sy-tabix. - CASE is_bracket( ). - WHEN /cc4a/if_abap_analyzer=>bracket_type-opening. + data(bracket_counter) = 1. + loop at statement-tokens assigning field-symbol() from bracket_position + 1. + data(idx) = sy-tabix. + case is_bracket( ). + when /cc4a/if_abap_analyzer=>bracket_type-opening. bracket_counter += 1. - WHEN /cc4a/if_abap_analyzer=>bracket_type-closing. - IF bracket_counter EQ 1. + when /cc4a/if_abap_analyzer=>bracket_type-closing. + if bracket_counter eq 1. end_of_bracket = idx. - EXIT. - ENDIF. + exit. + endif. bracket_counter -= 1. - WHEN /cc4a/if_abap_analyzer=>bracket_type-clopening. - IF bracket_counter EQ 1. + when /cc4a/if_abap_analyzer=>bracket_type-clopening. + if bracket_counter eq 1. end_of_bracket = idx. - EXIT. - ENDIF. - ENDCASE. - ENDLOOP. - IF end_of_bracket IS INITIAL. + exit. + endif. + endcase. + endloop. + if end_of_bracket is initial. end_of_bracket = -1. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD /cc4a/if_abap_analyzer~find_clause_index. + method /cc4a/if_abap_analyzer~find_clause_index. token_index = 0. - SPLIT condense( clause ) AT space INTO TABLE DATA(clauses). - IF clauses IS INITIAL OR clauses[ 1 ] IS INITIAL. - RAISE EXCEPTION TYPE /cc4a/cx_clause_is_initial. - ENDIF. - LOOP AT tokens TRANSPORTING NO FIELDS FROM start_index - WHERE references IS INITIAL - AND lexeme = clauses[ 1 ]. + split condense( clause ) at space into table data(clauses). + if clauses is initial or clauses[ 1 ] is initial. + raise exception type /cc4a/cx_clause_is_initial. + endif. + loop at tokens transporting no fields from start_index + where references is initial + and lexeme = clauses[ 1 ]. token_index = sy-tabix. - DATA(clause_index) = 2. - WHILE clause_index <= lines( clauses ) - AND token_index + clause_index - 1 <= lines( tokens ). - ASSIGN tokens[ token_index + clause_index - 1 ] TO FIELD-SYMBOL(). - IF -lexeme = clauses[ clause_index ] - AND -references IS INITIAL. + data(clause_index) = 2. + while clause_index <= lines( clauses ) + and token_index + clause_index - 1 <= lines( tokens ). + assign tokens[ token_index + clause_index - 1 ] to field-symbol(). + if -lexeme = clauses[ clause_index ] + and -references is initial. clause_index += 1. - ELSE. + else. token_index = 0. - EXIT. - ENDIF. - ENDWHILE. - IF token_index <> 0. - RETURN. - ENDIF. - ENDLOOP. - ENDMETHOD. + exit. + endif. + endwhile. + if token_index <> 0. + return. + endif. + endloop. + endmethod. - METHOD /cc4a/if_abap_analyzer~find_key_words. + method /cc4a/if_abap_analyzer~find_key_words. position = -1. - LOOP AT statement-tokens TRANSPORTING NO FIELDS WHERE lexeme EQ key_words[ 1 ] AND references IS INITIAL. - DATA(token_index) = sy-tabix. - IF lines( key_words ) EQ 1. + loop at statement-tokens transporting no fields where lexeme eq key_words[ 1 ] and references is initial. + data(token_index) = sy-tabix. + if lines( key_words ) eq 1. position = token_index. - RETURN. - ELSE. - LOOP AT key_words ASSIGNING FIELD-SYMBOL() FROM 2. - DATA(next_token) = VALUE #( statement-tokens[ token_index + sy-tabix - 1 ] OPTIONAL ). - IF next_token-references IS NOT INITIAL OR next_token-lexeme NE . - EXIT. - ELSEIF sy-tabix EQ lines( key_words ). + return. + else. + loop at key_words assigning field-symbol() from 2. + data(next_token) = value #( statement-tokens[ token_index + sy-tabix - 1 ] optional ). + if next_token-references is not initial or next_token-lexeme ne . + exit. + elseif sy-tabix eq lines( key_words ). position = token_index. - ENDIF. - ENDLOOP. - ENDIF. - ENDLOOP. - ENDMETHOD. + endif. + endloop. + endif. + endloop. + endmethod. - METHOD /cc4a/if_abap_analyzer~flatten_tokens. - DATA(tokens_to_process) = tokens. - flat_statement = _flatten_tokens( CHANGING tokens = tokens_to_process ). - ENDMETHOD. + method /cc4a/if_abap_analyzer~flatten_tokens. + data(tokens_to_process) = tokens. + flat_statement = _flatten_tokens( changing tokens = tokens_to_process ). + endmethod. - METHOD /cc4a/if_abap_analyzer~is_bracket. - DATA(first_char) = token-lexeme(1). - DATA(offset_for_last_char) = strlen( token-lexeme ) - 1. - DATA(last_char) = COND #( WHEN offset_for_last_char > 0 THEN token-lexeme+offset_for_last_char(1) ELSE first_char ). - bracket_type = SWITCH #( + method /cc4a/if_abap_analyzer~is_bracket. + data(first_char) = token-lexeme(1). + data(offset_for_last_char) = strlen( token-lexeme ) - 1. + data(last_char) = cond #( when offset_for_last_char > 0 then token-lexeme+offset_for_last_char(1) else first_char ). + bracket_type = switch #( last_char - WHEN ')' THEN /cc4a/if_abap_analyzer=>bracket_type-closing - WHEN '(' THEN SWITCH #( + when ')' then /cc4a/if_abap_analyzer=>bracket_type-closing + when '(' then switch #( first_char - WHEN ')' THEN /cc4a/if_abap_analyzer=>bracket_type-clopening - ELSE /cc4a/if_abap_analyzer=>bracket_type-opening ) - ELSE /cc4a/if_abap_analyzer=>bracket_type-no_bracket ). - ENDMETHOD. + when ')' then /cc4a/if_abap_analyzer=>bracket_type-clopening + else /cc4a/if_abap_analyzer=>bracket_type-opening ) + else /cc4a/if_abap_analyzer=>bracket_type-no_bracket ). + endmethod. - METHOD /cc4a/if_abap_analyzer~is_logical_connective. + method /cc4a/if_abap_analyzer~is_logical_connective. is_logical_connective = xsdbool( - token-references IS INITIAL AND ( token-lexeme = 'AND' OR token-lexeme = 'OR' OR token-lexeme = 'EQUIV' ) ). - ENDMETHOD. + token-references is initial and ( token-lexeme = 'AND' or token-lexeme = 'OR' or token-lexeme = 'EQUIV' ) ). + endmethod. - METHOD /cc4a/if_abap_analyzer~is_token_keyword. + method /cc4a/if_abap_analyzer~is_token_keyword. result = abap_true. - IF token-references IS NOT INITIAL OR token-lexeme <> keyword. + if token-references is not initial or token-lexeme <> keyword. result = abap_false. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD /cc4a/if_abap_analyzer~negate_comparison_operator. - IF NOT /cc4a/if_abap_analyzer~token_is_comparison_operator( VALUE #( lexeme = comparison_operator ) ). - RAISE EXCEPTION NEW /cc4a/cx_token_is_no_operator( ). - ENDIF. + method /cc4a/if_abap_analyzer~negate_comparison_operator. + if not /cc4a/if_abap_analyzer~token_is_comparison_operator( value #( lexeme = comparison_operator ) ). + raise exception new /cc4a/cx_token_is_no_operator( ). + endif. negated_comparison_operator = negations[ operator = comparison_operator ]-negated. - ENDMETHOD. + endmethod. - METHOD /cc4a/if_abap_analyzer~parse_method_definition. - IF statement-keyword <> 'METHODS' AND statement-keyword <> 'CLASS-METHODS'. - RETURN. - ENDIF. - DATA(current_kind) = /cc4a/if_abap_analyzer=>parameter_kind-importing. + method /cc4a/if_abap_analyzer~parse_method_definition. + if statement-keyword <> 'METHODS' and statement-keyword <> 'CLASS-METHODS'. + return. + endif. + data(current_kind) = /cc4a/if_abap_analyzer=>parameter_kind-importing. method_definition-name = statement-tokens[ 2 ]-lexeme. - IF lines( statement-tokens ) >= 3 AND statement-tokens[ 3 ]-lexeme = 'REDEFINITION'. + if lines( statement-tokens ) >= 3 and statement-tokens[ 3 ]-lexeme = 'REDEFINITION'. method_definition-is_redefinition = abap_true. - RETURN. - ENDIF. - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL(). - DATA(token_idx) = sy-tabix. - IF -references IS INITIAL. - CASE -lexeme. - WHEN 'IMPORTING'. + return. + endif. + loop at statement-tokens assigning field-symbol(). + data(token_idx) = sy-tabix. + if -references is initial. + case -lexeme. + when 'IMPORTING'. current_kind = /cc4a/if_abap_analyzer=>parameter_kind-importing. - WHEN 'EXPORTING'. + when 'EXPORTING'. current_kind = /cc4a/if_abap_analyzer=>parameter_kind-exporting. - WHEN 'CHANGING'. + when 'CHANGING'. current_kind = /cc4a/if_abap_analyzer=>parameter_kind-changing. - WHEN 'RETURNING'. + when 'RETURNING'. current_kind = /cc4a/if_abap_analyzer=>parameter_kind-returning. - WHEN 'TYPE'. - ASSIGN statement-tokens[ token_idx - 1 ] TO FIELD-SYMBOL(). - DATA(parameter_token_length) = strlen( -lexeme ). - IF parameter_token_length > 10 AND -lexeme(10) = 'REFERENCE('. - DATA(reference_offset) = parameter_token_length - 11. - INSERT VALUE #( + when 'TYPE'. + assign statement-tokens[ token_idx - 1 ] to field-symbol(). + data(parameter_token_length) = strlen( -lexeme ). + if parameter_token_length > 10 and -lexeme(10) = 'REFERENCE('. + data(reference_offset) = parameter_token_length - 11. + insert value #( name = -lexeme+10(reference_offset) - kind = current_kind ) INTO TABLE method_definition-parameters. - ELSEIF parameter_token_length > 6 AND -lexeme(6) = 'VALUE('. - DATA(value_offset) = parameter_token_length - 7. - INSERT VALUE #( + kind = current_kind ) into table method_definition-parameters. + elseif parameter_token_length > 6 and -lexeme(6) = 'VALUE('. + data(value_offset) = parameter_token_length - 7. + insert value #( name = -lexeme+6(value_offset) - kind = current_kind ) INTO TABLE method_definition-parameters. - ELSE. - INSERT VALUE #( + kind = current_kind ) into table method_definition-parameters. + else. + insert value #( name = -lexeme - kind = current_kind ) INTO TABLE method_definition-parameters. - ENDIF. - ENDCASE. - ENDIF. - ENDLOOP. - ENDMETHOD. + kind = current_kind ) into table method_definition-parameters. + endif. + endcase. + endif. + endloop. + endmethod. - METHOD /cc4a/if_abap_analyzer~token_is_comparison_operator. - CASE token-lexeme. - WHEN 'IS' OR 'IN' OR '>' OR 'GT' OR '<' OR 'LT' OR '>=' OR 'GE' OR '<=' OR 'LE' OR '=' OR 'EQ' OR '<>' OR 'NE'. + method /cc4a/if_abap_analyzer~token_is_comparison_operator. + case token-lexeme. + when 'IS' or 'IN' or '>' or 'GT' or '<' or 'LT' or '>=' or 'GE' or '<=' or 'LE' or '=' or 'EQ' or '<>' or 'NE'. is_operator = abap_true. - WHEN OTHERS. + when others. is_operator = abap_false. - ENDCASE. - ENDMETHOD. + endcase. + endmethod. - METHOD class_constructor. - negations = VALUE #( ( operator = '>' negated = '<=' ) + method class_constructor. + negations = value #( ( operator = '>' negated = '<=' ) ( operator = 'GT' negated = 'LE' ) ( operator = '<' negated = '>=' ) ( operator = 'LT' negated = 'GE' ) @@ -245,177 +245,177 @@ CLASS /cc4a/abap_analyzer IMPLEMENTATION. ( operator = 'LE' negated = 'GT' ) ( operator = '>=' negated = '<' ) ( operator = 'GE' negated = 'LT' ) ). - ENDMETHOD. + endmethod. - METHOD create. - instance = NEW /cc4a/abap_analyzer( ). - ENDMETHOD. + method create. + instance = new /cc4a/abap_analyzer( ). + endmethod. - METHOD is_db_statement. - CASE statement-keyword. - WHEN 'SELECT' OR 'WITH' OR 'DELETE' OR 'UPDATE' OR 'INSERT' OR 'MODIFY' OR 'READ' OR 'LOOP' - OR 'IMPORT' OR 'EXPORT' OR 'FETCH' OR 'OPEN' OR 'EXEC'. - IF ( find_clause_index( tokens = statement-tokens clause = 'CONNECTION' ) <> 0 - AND ( statement-keyword = 'DELETE' - OR statement-keyword = 'UPDATE' - OR statement-keyword = 'INSERT' - OR statement-keyword = 'MODIFY' ) ). + method is_db_statement. + case statement-keyword. + when 'SELECT' or 'WITH' or 'DELETE' or 'UPDATE' or 'INSERT' or 'MODIFY' or 'READ' or 'LOOP' + or 'IMPORT' or 'EXPORT' or 'FETCH' or 'OPEN' or 'EXEC'. + if ( find_clause_index( tokens = statement-tokens clause = 'CONNECTION' ) <> 0 + and ( statement-keyword = 'DELETE' + or statement-keyword = 'UPDATE' + or statement-keyword = 'INSERT' + or statement-keyword = 'MODIFY' ) ). result-is_db = abap_true. - IF get_dbtab_name = abap_false. - RETURN. - ENDIF. - ENDIF. - WHEN OTHERS. - RETURN. - ENDCASE. - DATA(token_idx) = 2. - WHILE lines( statement-tokens ) > token_idx AND statement-tokens[ token_idx ]-lexeme CP '%_*(' - AND statement-tokens[ token_idx ]-references IS INITIAL. + if get_dbtab_name = abap_false. + return. + endif. + endif. + when others. + return. + endcase. + data(token_idx) = 2. + while lines( statement-tokens ) > token_idx and statement-tokens[ token_idx ]-lexeme cp '%_*(' + and statement-tokens[ token_idx ]-references is initial. token_idx += 3. - ENDWHILE. - DATA(analyzer) = NEW db_statement_analyzer( + endwhile. + data(analyzer) = new db_statement_analyzer( statement = statement start_idx = token_idx analyzer = me include_subqueries = include_subqueries ). result = analyzer->analyze( ). - ENDMETHOD. + endmethod. - METHOD _flatten_tokens. - IF NOT line_exists( tokens[ lexeme = '|' ] ). - flat = REDUCE #( INIT str = `` FOR tok IN tokens NEXT str = |{ str }{ tok-lexeme } | ). - ELSE. - ASSIGN tokens[ 1 ] TO FIELD-SYMBOL(). - WHILE lines( tokens ) > 0. - IF -lexeme = '|'. - DELETE tokens INDEX 1. - DATA(template) = _flatten_template( CHANGING tokens = tokens ). + method _flatten_tokens. + if not line_exists( tokens[ lexeme = '|' ] ). + flat = reduce #( init str = `` for tok in tokens next str = |{ str }{ tok-lexeme } | ). + else. + assign tokens[ 1 ] to field-symbol(). + while lines( tokens ) > 0. + if -lexeme = '|'. + delete tokens index 1. + data(template) = _flatten_template( changing tokens = tokens ). flat &&= |\|{ template }\| |. - ELSE. + else. flat &&= |{ -lexeme } |. - DELETE tokens INDEX 1. - ENDIF. - ASSIGN tokens[ 1 ] TO . - ENDWHILE. - ENDIF. - DATA(len) = strlen( flat ) - 1. - IF flat+len(1) = ` `. + delete tokens index 1. + endif. + assign tokens[ 1 ] to . + endwhile. + endif. + data(len) = strlen( flat ) - 1. + if flat+len(1) = ` `. flat = flat(len). - ENDIF. - ENDMETHOD. - - METHOD _flatten_template. - DATA(inside_braces) = abap_false. - ASSIGN tokens[ 1 ] TO FIELD-SYMBOL(). - WHILE lines( tokens ) > 0. - CASE -lexeme. - WHEN `|`. - DELETE tokens INDEX 1. - IF inside_braces = abap_true. - flat &&= |\|{ _flatten_template( CHANGING tokens = tokens ) }\| |. - ELSE. - RETURN. - ENDIF. - - WHEN `{`. + endif. + endmethod. + + method _flatten_template. + data(inside_braces) = abap_false. + assign tokens[ 1 ] to field-symbol(). + while lines( tokens ) > 0. + case -lexeme. + when `|`. + delete tokens index 1. + if inside_braces = abap_true. + flat &&= |\|{ _flatten_template( changing tokens = tokens ) }\| |. + else. + return. + endif. + + when `{`. inside_braces = abap_true. flat &&= `{ `. - DELETE tokens INDEX 1. + delete tokens index 1. - WHEN `}`. + when `}`. inside_braces = abap_false. flat &&= ` }`. - DELETE tokens INDEX 1. + delete tokens index 1. - WHEN OTHERS. - IF -lexeme CP '`*`'. - DATA(token_inner_length) = strlen( -lexeme ) - 2. + when others. + if -lexeme cp '`*`'. + data(token_inner_length) = strlen( -lexeme ) - 2. flat &&= -lexeme+1(token_inner_length). - ELSE. + else. flat &&= |{ -lexeme } |. - ENDIF. - DELETE tokens INDEX 1. - - ENDCASE. - ASSIGN tokens[ 1 ] TO . - ENDWHILE. - ENDMETHOD. - - - - METHOD _break_into_lines. - DATA i TYPE i. - DATA in_sqmarks TYPE abap_bool. - DATA in_quotes TYPE abap_bool. - DATA in_template TYPE abap_bool. - DATA in_braces TYPE abap_bool. - DATA last_space TYPE i. - IF strlen( code ) <= break_at. - code_lines = VALUE #( ( code ) ). - RETURN. - ENDIF. - - WHILE i < strlen( code ). - CASE code+i(1). - WHEN '`'. - IF in_quotes = abap_false AND in_template = abap_false. - in_sqmarks = COND #( WHEN in_sqmarks = abap_false THEN abap_true ELSE abap_false ). - ENDIF. - WHEN `'`. - IF in_sqmarks = abap_false AND in_template = abap_false. - in_quotes = COND #( WHEN in_quotes = abap_false THEN abap_true ELSE abap_false ). - ENDIF. - WHEN '|'. - IF in_sqmarks = abap_false AND in_quotes = abap_false. - in_template = COND #( WHEN in_template = abap_false THEN abap_true ELSE abap_false ). - ENDIF. - WHEN `\`. + endif. + delete tokens index 1. + + endcase. + assign tokens[ 1 ] to . + endwhile. + endmethod. + + + + method _break_into_lines. + data i type i. + data in_sqmarks type abap_bool. + data in_quotes type abap_bool. + data in_template type abap_bool. + data in_braces type abap_bool. + data last_space type i. + if strlen( code ) <= break_at. + code_lines = value #( ( code ) ). + return. + endif. + + while i < strlen( code ). + case code+i(1). + when '`'. + if in_quotes = abap_false and in_template = abap_false. + in_sqmarks = cond #( when in_sqmarks = abap_false then abap_true else abap_false ). + endif. + when `'`. + if in_sqmarks = abap_false and in_template = abap_false. + in_quotes = cond #( when in_quotes = abap_false then abap_true else abap_false ). + endif. + when '|'. + if in_sqmarks = abap_false and in_quotes = abap_false. + in_template = cond #( when in_template = abap_false then abap_true else abap_false ). + endif. + when `\`. i += 1. - WHEN '{'. - IF in_template = abap_true AND in_sqmarks = abap_false AND in_quotes = abap_false. + when '{'. + if in_template = abap_true and in_sqmarks = abap_false and in_quotes = abap_false. in_braces = abap_true. - ENDIF. - WHEN '}'. - IF in_template = abap_true AND in_sqmarks = abap_false AND in_quotes = abap_false. + endif. + when '}'. + if in_template = abap_true and in_sqmarks = abap_false and in_quotes = abap_false. in_braces = abap_false. - ENDIF. - WHEN ` `. - IF in_sqmarks = abap_false AND in_quotes = abap_false AND - ( in_template = abap_false OR in_braces = abap_true ). + endif. + when ` `. + if in_sqmarks = abap_false and in_quotes = abap_false and + ( in_template = abap_false or in_braces = abap_true ). last_space = i. - ENDIF. - ENDCASE. + endif. + endcase. i += 1. - IF i > break_at. - IF last_space = 0. - RAISE EXCEPTION TYPE /cc4a/cx_line_break_impossible. - ELSE. - APPEND code(last_space) TO code_lines. + if i > break_at. + if last_space = 0. + raise exception type /cc4a/cx_line_break_impossible. + else. + append code(last_space) to code_lines. last_space += 1. - IF last_space >= strlen( code ). - RETURN. - ENDIF. + if last_space >= strlen( code ). + return. + endif. code = code+last_space. - IF strlen( code ) <= break_at. - APPEND code TO code_lines. - RETURN. - ENDIF. + if strlen( code ) <= break_at. + append code to code_lines. + return. + endif. i = 0. last_space = 0. in_sqmarks = abap_false. in_quotes = abap_false. in_template = abap_false. - ENDIF. - ENDIF. - ENDWHILE. - IF i > break_at. - RAISE EXCEPTION TYPE /cc4a/cx_line_break_impossible. - ELSE. - APPEND code TO code_lines. - ENDIF. - ENDMETHOD. -ENDCLASS. + endif. + endif. + endwhile. + if i > break_at. + raise exception type /cc4a/cx_line_break_impossible. + else. + append code to code_lines. + endif. + endmethod. +endclass. diff --git a/src/core/#cc4a#abap_analyzer.clas.locals_imp.abap b/src/core/#cc4a#abap_analyzer.clas.locals_imp.abap index b6f11b3..a00d7a8 100644 --- a/src/core/#cc4a#abap_analyzer.clas.locals_imp.abap +++ b/src/core/#cc4a#abap_analyzer.clas.locals_imp.abap @@ -1,515 +1,512 @@ -*"* use this source file for the definition and implementation of -*"* local helper classes, interface definitions and type -*"* declarations -CLASS db_statement_analyzer DEFINITION DEFERRED. -CLASS /cc4a/abap_analyzer DEFINITION LOCAL FRIENDS db_statement_analyzer. -CLASS db_statement_analyzer DEFINITION FINAL. - PUBLIC SECTION. +class db_statement_analyzer definition deferred. +class /cc4a/abap_analyzer definition local friends db_statement_analyzer. +class db_statement_analyzer definition final. + public section. - METHODS constructor - IMPORTING - statement TYPE if_ci_atc_source_code_provider=>ty_statement - start_idx TYPE i - analyzer TYPE REF TO /cc4a/abap_analyzer - include_subqueries TYPE abap_bool. - METHODS analyze - RETURNING VALUE(result) TYPE /cc4a/if_abap_analyzer=>ty_db_statement. + methods constructor + importing + statement type if_ci_atc_source_code_provider=>ty_statement + start_idx type i + analyzer type ref to /cc4a/abap_analyzer + include_subqueries type abap_bool. + methods analyze + returning value(result) type /cc4a/if_abap_analyzer=>ty_db_statement. - PRIVATE SECTION. - METHODS get_result - RETURNING VALUE(result) TYPE /cc4a/if_abap_analyzer=>ty_db_statement. - METHODS analyze_select. - METHODS analyze_with. - METHODS analyze_delete. - METHODS analyze_insert. - METHODS analyze_update. - METHODS analyze_modify. - METHODS analyze_open_cursor. - METHODS analyze_read_loop. - METHODS analyze_import. - METHODS analyze_export. - CLASS-METHODS check_dbtab - IMPORTING token_db TYPE if_ci_atc_source_code_provider=>ty_token - RETURNING VALUE(result) TYPE /cc4a/if_abap_analyzer=>ty_db_statement. - CONSTANTS tag_common_part TYPE if_ci_atc_source_code_provider=>ty_compiler_reference_tag - VALUE if_ci_atc_source_code_provider=>compiler_reference_kinds-common_part ##TYPE. - CONSTANTS tag_data TYPE if_ci_atc_source_code_provider=>ty_compiler_reference_tag - VALUE if_ci_atc_source_code_provider=>compiler_reference_kinds-data ##TYPE. - CONSTANTS tag_type TYPE if_ci_atc_source_code_provider=>ty_compiler_reference_tag - VALUE if_ci_atc_source_code_provider=>compiler_reference_kinds-type ##TYPE. - DATA statement TYPE if_ci_atc_source_code_provider=>ty_statement. - DATA start_idx TYPE i. - DATA analyzer TYPE REF TO /cc4a/abap_analyzer. - DATA token_idx TYPE i. - DATA check_if_dbtab TYPE abap_bool. - DATA is_db TYPE abap_bool. - DATA dbtab_name TYPE string. - DATA include_subqueries TYPE abap_bool. -ENDCLASS. -CLASS db_statement_analyzer IMPLEMENTATION. + private section. + methods get_result + returning value(result) type /cc4a/if_abap_analyzer=>ty_db_statement. + methods analyze_select. + methods analyze_with. + methods analyze_delete. + methods analyze_insert. + methods analyze_update. + methods analyze_modify. + methods analyze_open_cursor. + methods analyze_read_loop. + methods analyze_import. + methods analyze_export. + class-methods check_dbtab + importing token_db type if_ci_atc_source_code_provider=>ty_token + returning value(result) type /cc4a/if_abap_analyzer=>ty_db_statement. + constants tag_common_part type if_ci_atc_source_code_provider=>ty_compiler_reference_tag + value if_ci_atc_source_code_provider=>compiler_reference_kinds-common_part ##TYPE. + constants tag_data type if_ci_atc_source_code_provider=>ty_compiler_reference_tag + value if_ci_atc_source_code_provider=>compiler_reference_kinds-data ##TYPE. + constants tag_type type if_ci_atc_source_code_provider=>ty_compiler_reference_tag + value if_ci_atc_source_code_provider=>compiler_reference_kinds-type ##TYPE. + data statement type if_ci_atc_source_code_provider=>ty_statement. + data start_idx type i. + data analyzer type ref to /cc4a/abap_analyzer. + data token_idx type i. + data check_if_dbtab type abap_bool. + data is_db type abap_bool. + data dbtab_name type string. + data include_subqueries type abap_bool. +endclass. +class db_statement_analyzer implementation. - METHOD constructor. + method constructor. me->statement = statement. me->start_idx = start_idx. me->analyzer = analyzer. token_idx = start_idx. check_if_dbtab = abap_true. me->include_subqueries = include_subqueries. - ENDMETHOD. + endmethod. - METHOD analyze. - CASE statement-keyword. - WHEN 'SELECT'. + method analyze. + case statement-keyword. + when 'SELECT'. analyze_select( ). - WHEN 'WITH'. + when 'WITH'. analyze_with( ). - WHEN 'DELETE'. + when 'DELETE'. analyze_delete( ). - WHEN 'INSERT'. + when 'INSERT'. analyze_insert( ). - WHEN 'MODIFY'. + when 'MODIFY'. analyze_modify( ). - WHEN 'UPDATE'. + when 'UPDATE'. analyze_update( ). - WHEN 'OPEN'. + when 'OPEN'. analyze_open_cursor( ). - WHEN 'READ' OR 'LOOP'. + when 'READ' or 'LOOP'. analyze_read_loop( ). - WHEN 'IMPORT'. + when 'IMPORT'. analyze_import( ). - WHEN 'EXPORT'. + when 'EXPORT'. analyze_export( ). - WHEN 'FETCH'. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'NEXT CURSOR' ) <> 0. + when 'FETCH'. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'NEXT CURSOR' ) <> 0. result-is_db = abap_true. - ENDIF. - RETURN. - WHEN 'EXEC'. + endif. + return. + when 'EXEC'. result-is_db = abap_true. - RETURN. - WHEN OTHERS. + return. + when others. result-is_db = abap_false. - RETURN. - ENDCASE. + return. + endcase. result = get_result( ). - ENDMETHOD. + endmethod. - METHOD get_result. + method get_result. result-is_db = is_db. * special case for obsolete READ and LOOP statements - IF dbtab_name IS NOT INITIAL AND check_if_dbtab = abap_false. + if dbtab_name is not initial and check_if_dbtab = abap_false. result-dbtab = dbtab_name. result-is_db = is_db. - RETURN. - ENDIF. + return. + endif. - IF token_idx > 0 AND is_db = abap_true. - DATA(token_db) = statement-tokens[ token_idx ]. - IF token_db IS NOT INITIAL. - IF check_if_dbtab = abap_true. + if token_idx > 0 and is_db = abap_true. + data(token_db) = statement-tokens[ token_idx ]. + if token_db is not initial. + if check_if_dbtab = abap_true. result = check_dbtab( token_db ). - ELSE. + else. result-dbtab = token_db-lexeme. - ENDIF. - ENDIF. - IF result-dbtab IS NOT INITIAL. - IF result-dbtab(1) = '*'. + endif. + endif. + if result-dbtab is not initial. + if result-dbtab(1) = '*'. result-dbtab = result-dbtab+1. - ENDIF. - IF result-dbtab(1) <> '('. - SPLIT result-dbtab AT '(' INTO result-dbtab DATA(dummy) ##NEEDED. - ENDIF. - SPLIT result-dbtab AT '\' INTO result-dbtab dummy. - ENDIF. - ENDIF. - IF include_subqueries = abap_true AND statement-keyword <> 'WITH'. - DATA(sub_idx) = token_idx. - DO. + endif. + if result-dbtab(1) <> '('. + split result-dbtab at '(' into result-dbtab data(dummy) ##NEEDED. + endif. + split result-dbtab at '\' into result-dbtab dummy. + endif. + endif. + if include_subqueries = abap_true and statement-keyword <> 'WITH'. + data(sub_idx) = token_idx. + do. sub_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'SELECT' start_index = sub_idx ). - IF sub_idx < 3. - EXIT. - ELSE. - DATA(substatement) = statement. + if sub_idx < 3. + exit. + else. + data(substatement) = statement. substatement-keyword = 'SELECT'. - DELETE substatement-tokens TO sub_idx - 1. - DATA(result_sub) = analyzer->is_db_statement( + delete substatement-tokens to sub_idx - 1. + data(result_sub) = analyzer->is_db_statement( statement = substatement include_subqueries = abap_true get_dbtab_name = abap_true ). - IF result_sub-is_db = abap_true. + if result_sub-is_db = abap_true. result-is_db = abap_true. result-dbtab_subquery = result_sub-dbtab. - EXIT. - ENDIF. + exit. + endif. sub_idx += 1. - ENDIF. - ENDDO. - ENDIF. + endif. + enddo. + endif. - ENDMETHOD. + endmethod. - METHOD check_dbtab. + method check_dbtab. result-is_db = abap_false. - IF token_db-lexeme(1) = '@' - OR ( token_db-references IS INITIAL AND token_db-lexeme(1) <> '(' ). + if token_db-lexeme(1) = '@' + or ( token_db-references is initial and token_db-lexeme(1) <> '(' ). result-is_db = abap_false. - ELSEIF token_db-lexeme NP '(*)'. - ASSIGN token_db-references[ 1 ] TO FIELD-SYMBOL(). - CASE -kind. - WHEN if_ci_atc_source_code_provider=>compiler_reference_kinds-type. - IF lines( token_db-references ) > 1. + elseif token_db-lexeme np '(*)'. + assign token_db-references[ 1 ] to field-symbol(). + case -kind. + when if_ci_atc_source_code_provider=>compiler_reference_kinds-type. + if lines( token_db-references ) > 1. result-is_db = abap_false. * no symbol - so try okay - ELSEIF -full_name(3) = |\\{ TAG_TYPE }|. + elseif -full_name(3) = |\\{ tag_type }|. result-is_db = abap_true. - ENDIF. - WHEN if_ci_atc_source_code_provider=>compiler_reference_kinds-data. + endif. + when if_ci_atc_source_code_provider=>compiler_reference_kinds-data. result-is_db = abap_false. - IF token_db-references[ 1 ]-full_name(3) = |\\{ TAG_COMMON_PART }|. - SPLIT token_db-references[ 1 ]-full_name+4 AT |\\{ tag_data }:| INTO DATA(l_name1) DATA(l_name2). - IF l_name1 = l_name2. + if token_db-references[ 1 ]-full_name(3) = |\\{ tag_common_part }|. + split token_db-references[ 1 ]-full_name+4 at |\\{ tag_data }:| into data(l_name1) data(l_name2). + if l_name1 = l_name2. result-is_db = abap_true. - ENDIF. - ELSEIF token_db-references[ 1 ]-full_name NP |*\\{ tag_common_part }:*| - AND lines( token_db-references ) = 2 - AND token_db-references[ 2 ]-kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-type - AND token_db-references[ 2 ]-full_name+4 NP '*\*'. + endif. + elseif token_db-references[ 1 ]-full_name np |*\\{ tag_common_part }:*| + and lines( token_db-references ) = 2 + and token_db-references[ 2 ]-kind = if_ci_atc_source_code_provider=>compiler_reference_kinds-type + and token_db-references[ 2 ]-full_name+4 np '*\*'. result-is_db = abap_true. - ENDIF. - WHEN OTHERS. + endif. + when others. result-is_db = abap_false. - ENDCASE. - ENDIF. - IF result-is_db = abap_true. + endcase. + endif. + if result-is_db = abap_true. result-dbtab = token_db-lexeme. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD analyze_select. + method analyze_select. is_db = abap_false. check_if_dbtab = abap_false. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'FROM' start_index = start_idx ). - IF token_idx <= 1. - RETURN. - ENDIF. - ASSIGN statement-tokens[ token_idx - 1 ] TO FIELD-SYMBOL(). - IF sy-subrc = 0 AND -lexeme = 'CONNECTION' AND -references IS INITIAL. + if token_idx <= 1. + return. + endif. + assign statement-tokens[ token_idx - 1 ] to field-symbol(). + if sy-subrc = 0 and -lexeme = 'CONNECTION' and -references is initial. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'FROM' start_index = token_idx + 1 ). - ENDIF. + endif. token_idx += 1. - WHILE statement-tokens[ token_idx ]-lexeme = '('. + while statement-tokens[ token_idx ]-lexeme = '('. token_idx += 1. - ENDWHILE. - WHILE statement-tokens[ token_idx ]-lexeme CP 'HIERARCHY*(' AND statement-tokens[ token_idx ]-references IS INITIAL. - IF analyzer->is_token_keyword( token = statement-tokens[ token_idx + 1 ] keyword = 'SOURCE' ). + endwhile. + while statement-tokens[ token_idx ]-lexeme cp 'HIERARCHY*(' and statement-tokens[ token_idx ]-references is initial. + if analyzer->is_token_keyword( token = statement-tokens[ token_idx + 1 ] keyword = 'SOURCE' ). token_idx += 2. - ELSE. - EXIT. - ENDIF. - ENDWHILE. - IF statement-tokens[ token_idx ]-lexeme(1) = '@'. + else. + exit. + endif. + endwhile. + if statement-tokens[ token_idx ]-lexeme(1) = '@'. * check for joined tables - DO. + do. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'JOIN' start_index = token_idx ). - IF token_idx = 0. - RETURN. - ELSE. - IF statement-tokens[ token_idx + 1 ]-lexeme(1) <> '@'. + if token_idx = 0. + return. + else. + if statement-tokens[ token_idx + 1 ]-lexeme(1) <> '@'. token_idx += 1. is_db = abap_true. - RETURN. - ELSE. - CONTINUE. - ENDIF. - ENDIF. - ENDDO. - ELSE. + return. + else. + continue. + endif. + endif. + enddo. + else. is_db = abap_true. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD analyze_with. + method analyze_with. check_if_dbtab = abap_false. is_db = abap_false. token_idx = start_idx. - DO. + do. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'SELECT' start_index = token_idx ). - IF token_idx = 0. - RETURN. - ENDIF. + if token_idx = 0. + return. + endif. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'FROM' start_index = token_idx ). - IF token_idx = 0. - RETURN. - ENDIF. + if token_idx = 0. + return. + endif. token_idx += 1. - WHILE statement-tokens[ token_idx ]-lexeme CP 'HIERARCHY*(' - AND statement-tokens[ token_idx ]-references IS INITIAL. - IF analyzer->is_token_keyword( token = statement-tokens[ token_idx + 1 ] keyword = 'SOURCE' ). + while statement-tokens[ token_idx ]-lexeme cp 'HIERARCHY*(' + and statement-tokens[ token_idx ]-references is initial. + if analyzer->is_token_keyword( token = statement-tokens[ token_idx + 1 ] keyword = 'SOURCE' ). token_idx += 2. - ELSE. - EXIT. - ENDIF. - ENDWHILE. - IF statement-tokens[ token_idx ]-lexeme CP 'HIERARCHY*(' AND statement-tokens[ token_idx ]-references IS INITIAL. - CONTINUE. - ENDIF. - IF statement-tokens[ token_idx ]-lexeme(1) <> '@' AND statement-tokens[ token_idx ]-lexeme(1) <> '+'. + else. + exit. + endif. + endwhile. + if statement-tokens[ token_idx ]-lexeme cp 'HIERARCHY*(' and statement-tokens[ token_idx ]-references is initial. + continue. + endif. + if statement-tokens[ token_idx ]-lexeme(1) <> '@' and statement-tokens[ token_idx ]-lexeme(1) <> '+'. is_db = abap_true. - EXIT. - ENDIF. - ENDDO. - ENDMETHOD. + exit. + endif. + enddo. + endmethod. - METHOD analyze_delete. + method analyze_delete. check_if_dbtab = abap_true. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'CONNECTION' ) <> 0. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'CONNECTION' ) <> 0. is_db = abap_true. check_if_dbtab = abap_false. - ENDIF. + endif. token_idx = start_idx. - ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). - IF -references IS INITIAL AND -lexeme(1) <> '('. - CASE -lexeme. - WHEN 'ADJACENT' OR 'REPORT' OR 'TEXTPOOL' OR 'DYNPRO' OR 'DATASET' OR 'TABLE'. - RETURN. - WHEN 'FROM'. + assign statement-tokens[ token_idx ] to field-symbol(). + if -references is initial and -lexeme(1) <> '('. + case -lexeme. + when 'ADJACENT' or 'REPORT' or 'TEXTPOOL' or 'DYNPRO' or 'DATASET' or 'TABLE'. + return. + when 'FROM'. token_idx += 1. - ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). - IF -references IS INITIAL AND -lexeme(1) <> '('. - CASE -lexeme. - WHEN 'MEMORY' OR 'SHARED'. - RETURN. - WHEN 'DATABASE'. + assign statement-tokens[ token_idx ] to field-symbol(). + if -references is initial and -lexeme(1) <> '('. + case -lexeme. + when 'MEMORY' or 'SHARED'. + return. + when 'DATABASE'. is_db = abap_true. token_idx += 1. check_if_dbtab = abap_false. - ENDCASE. - ELSE. + endcase. + else. is_db = abap_true. - ENDIF. - ENDCASE. - ELSEIF lines( statement-tokens ) = token_idx. + endif. + endcase. + elseif lines( statement-tokens ) = token_idx. is_db = abap_true. - ELSEIF statement-tokens[ 3 ]-lexeme = 'INDEX' AND statement-tokens[ 3 ]-references IS INITIAL. - RETURN. - ELSE. + elseif statement-tokens[ 3 ]-lexeme = 'INDEX' and statement-tokens[ 3 ]-references is initial. + return. + else. is_db = abap_true. - ENDIF. - IF is_db = abap_true AND statement-tokens[ token_idx ]-lexeme(1) = '('. + endif. + if is_db = abap_true and statement-tokens[ token_idx ]-lexeme(1) = '('. check_if_dbtab = abap_false. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD analyze_insert. + method analyze_insert. check_if_dbtab = abap_true. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO TABLE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'REFERENCE INTO' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL LINE' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0. - RETURN. - ENDIF. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO TABLE' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'REFERENCE INTO' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'INITIAL LINE' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0. + return. + endif. token_idx = start_idx. - ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). - IF lines( statement-tokens ) = token_idx AND -references IS NOT INITIAL. + assign statement-tokens[ token_idx ] to field-symbol(). + if lines( statement-tokens ) = token_idx and -references is not initial. is_db = abap_true. - ENDIF. - IF -references IS INITIAL AND -lexeme(1) <> '('. - CASE -lexeme. - WHEN 'REPORT' OR 'TEXTPOOL' OR 'INITIAL' OR 'LINES'. - RETURN. - WHEN 'INTO'. + endif. + if -references is initial and -lexeme(1) <> '('. + case -lexeme. + when 'REPORT' or 'TEXTPOOL' or 'INITIAL' or 'LINES'. + return. + when 'INTO'. is_db = abap_true. token_idx += 1. check_if_dbtab = abap_false. - ENDCASE. - ELSE. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ) <> 0 - AND analyzer->find_clause_index( tokens = statement-tokens clause = 'VALUES' ) = 0. - RETURN. - ENDIF. + endcase. + else. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ) <> 0 + and analyzer->find_clause_index( tokens = statement-tokens clause = 'VALUES' ) = 0. + return. + endif. is_db = abap_true. - IF statement-tokens[ token_idx ]-lexeme(1) = '('. + if statement-tokens[ token_idx ]-lexeme(1) = '('. check_if_dbtab = abap_false. - ENDIF. - ENDIF. - ENDMETHOD. + endif. + endif. + endmethod. - METHOD analyze_modify. + method analyze_modify. * modify dbtab (from...) token_idx = start_idx. - ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). - IF -references IS INITIAL AND -lexeme(1) <> '('. - RETURN. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'USING KEY' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' ) <> 0. - RETURN. - ENDIF. + assign statement-tokens[ token_idx ] to field-symbol(). + if -references is initial and -lexeme(1) <> '('. + return. + endif. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'INDEX' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'USING KEY' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'TRANSPORTING' ) <> 0. + return. + endif. is_db = abap_true. - IF statement-tokens[ token_idx ]-lexeme(1) = '('. + if statement-tokens[ token_idx ]-lexeme(1) = '('. check_if_dbtab = abap_false. - ENDIF. - IF lines( statement-tokens ) = token_idx. - RETURN. - ELSEIF analyzer->find_clause_index( tokens = statement-tokens clause = 'VERSION' + endif. + if lines( statement-tokens ) = token_idx. + return. + elseif analyzer->find_clause_index( tokens = statement-tokens clause = 'VERSION' start_index = token_idx + 1 ) <> 0. token_idx = lines( statement-tokens ). check_if_dbtab = abap_false. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD analyze_update. + method analyze_update. token_idx = start_idx. - ASSIGN statement-tokens[ token_idx ] TO FIELD-SYMBOL(). - IF -references IS NOT INITIAL OR -lexeme(1) = '('. + assign statement-tokens[ token_idx ] to field-symbol(). + if -references is not initial or -lexeme(1) = '('. is_db = abap_true. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'SET' + endif. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'SET' start_index = token_idx + 1 ). check_if_dbtab = abap_false. - ELSEIF -lexeme(1) = '('. + elseif -lexeme(1) = '('. check_if_dbtab = abap_false. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD analyze_open_cursor. - DATA(found) = 0. - LOOP AT statement-tokens ASSIGNING FIELD-SYMBOL() - WHERE references IS INITIAL. + method analyze_open_cursor. + data(found) = 0. + loop at statement-tokens assigning field-symbol() + where references is initial. token_idx = sy-tabix. - CASE -lexeme. - WHEN 'CURSOR'. + case -lexeme. + when 'CURSOR'. found = 1. - WHEN 'FOR'. - IF found = 1. + when 'FOR'. + if found = 1. found = 2. - ENDIF. - WHEN 'SELECT'. - IF found = 2. + endif. + when 'SELECT'. + if found = 2. found = 3. - ENDIF. - WHEN 'FROM'. - IF found = 3. + endif. + when 'FROM'. + if found = 3. found = 4. - EXIT. - ENDIF. - ENDCASE. - ENDLOOP. - IF found = 4. + exit. + endif. + endcase. + endloop. + if found = 4. token_idx += 1. - WHILE statement-tokens[ token_idx ]-lexeme = '('. + while statement-tokens[ token_idx ]-lexeme = '('. token_idx += 1. - ENDWHILE. - IF statement-tokens[ token_idx ]-lexeme(1) = '@'. - RETURN. - ENDIF. + endwhile. + if statement-tokens[ token_idx ]-lexeme(1) = '@'. + return. + endif. is_db = abap_true. check_if_dbtab = abap_false. - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD analyze_read_loop. + method analyze_read_loop. check_if_dbtab = abap_false. - IF lines( statement-tokens ) = 1. - RETURN. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'VERSION' ) <> 0. + if lines( statement-tokens ) = 1. + return. + endif. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'VERSION' ) <> 0. * name of dbtab is determined in token after VERSION, dynamically: unknown table is_db = abap_true. - CLEAR dbtab_name. + clear dbtab_name. token_idx = 0. - RETURN. - ENDIF. - CASE statement-keyword. - WHEN 'LOOP'. - IF statement-tokens[ 2 ]-lexeme <> 'AT'. - RETURN. - ENDIF. - IF lines( statement-tokens ) <> 3 OR statement-tokens[ 3 ]-references IS INITIAL. - RETURN. - ENDIF. - WHEN 'READ'. - IF statement-tokens[ 2 ]-lexeme <> 'TABLE'. - RETURN. - ENDIF. - IF analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ) <> 0 - OR analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0. - RETURN. - ENDIF. + return. + endif. + case statement-keyword. + when 'LOOP'. + if statement-tokens[ 2 ]-lexeme <> 'AT'. + return. + endif. + if lines( statement-tokens ) <> 3 or statement-tokens[ 3 ]-references is initial. + return. + endif. + when 'READ'. + if statement-tokens[ 2 ]-lexeme <> 'TABLE'. + return. + endif. + if analyzer->find_clause_index( tokens = statement-tokens clause = 'BINARY SEARCH' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'INTO' ) <> 0 + or analyzer->find_clause_index( tokens = statement-tokens clause = 'ASSIGNING' ) <> 0. + return. + endif. token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'SEARCH' ). - IF token_idx <> 0 AND lines( statement-tokens ) > token_idx. - CASE statement-tokens[ token_idx + 1 ]-lexeme. - WHEN 'FKEQ' OR 'FKGE' OR 'GKEQ' OR 'GKGE'. - IF statement-tokens[ token_idx + 1 ]-references IS INITIAL. + if token_idx <> 0 and lines( statement-tokens ) > token_idx. + case statement-tokens[ token_idx + 1 ]-lexeme. + when 'FKEQ' or 'FKGE' or 'GKEQ' or 'GKGE'. + if statement-tokens[ token_idx + 1 ]-references is initial. is_db = abap_true. - ENDIF. - WHEN OTHERS. - RETURN. - ENDCASE. - ENDIF. - ENDCASE. + endif. + when others. + return. + endcase. + endif. + endcase. token_idx = 0. - DATA(token_db) = statement-tokens[ 3 ]. - DATA(l_name) = token_db-lexeme. - IF l_name(1) = '*'. + data(token_db) = statement-tokens[ 3 ]. + data(l_name) = token_db-lexeme. + if l_name(1) = '*'. l_name = l_name+1. - ENDIF. - IF strlen( l_name ) > 5. - RETURN. - ENDIF. + endif. + if strlen( l_name ) > 5. + return. + endif. * must be common part if dbtab loop or read - READ TABLE token_db-references INDEX 1 INTO DATA(l_reference). - IF sy-subrc <> 0. - RETURN. - ENDIF. - DATA(l_full_name) = |\\{ tag_common_part }:{ token_db-lexeme }\\{ tag_data }:{ token_db-lexeme }|. - IF l_reference-full_name <> l_full_name. - RETURN. - ENDIF. + read table token_db-references index 1 into data(l_reference). + if sy-subrc <> 0. + return. + endif. + data(l_full_name) = |\\{ tag_common_part }:{ token_db-lexeme }\\{ tag_data }:{ token_db-lexeme }|. + if l_reference-full_name <> l_full_name. + return. + endif. is_db = abap_true. dbtab_name = l_name. - IF dbtab_name(1) = '*'. + if dbtab_name(1) = '*'. dbtab_name = dbtab_name+1. - ENDIF. - IF dbtab_name(1) <> 'T'. + endif. + if dbtab_name(1) <> 'T'. dbtab_name = |T{ dbtab_name+1 }|. - ENDIF. + endif. check_if_dbtab = abap_false. - ENDMETHOD. + endmethod. - METHOD analyze_import. + method analyze_import. * import... from database dbtab id ... token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'FROM DATABASE' ). - IF token_idx = 0. - RETURN. - ENDIF. + if token_idx = 0. + return. + endif. token_idx += 2. - IF analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'ID' ) = 0. - RETURN. - ENDIF. + if analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'ID' ) = 0. + return. + endif. is_db = abap_true. check_if_dbtab = abap_false. - ENDMETHOD. + endmethod. - METHOD analyze_export. + method analyze_export. * export... to database dbtab id ... token_idx = analyzer->find_clause_index( tokens = statement-tokens clause = 'TO DATABASE' ). - IF token_idx = 0. - RETURN. - ENDIF. + if token_idx = 0. + return. + endif. token_idx += 2. - IF analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'ID' ) = 0. - RETURN. - ENDIF. + if analyzer->find_clause_index( tokens = statement-tokens start_index = token_idx + 1 clause = 'ID' ) = 0. + return. + endif. is_db = abap_true. check_if_dbtab = abap_false. - ENDMETHOD. -ENDCLASS. + endmethod. +endclass. diff --git a/src/core/#cc4a#abap_analyzer.clas.testclasses.abap b/src/core/#cc4a#abap_analyzer.clas.testclasses.abap index f34ed03..bbaa4ce 100644 --- a/src/core/#cc4a#abap_analyzer.clas.testclasses.abap +++ b/src/core/#cc4a#abap_analyzer.clas.testclasses.abap @@ -1,237 +1,237 @@ -CLASS key_words DEFINITION FINAL FOR TESTING - DURATION SHORT - RISK LEVEL HARMLESS. +class key_words definition final for testing + duration short + risk level harmless. - PRIVATE SECTION. - METHODS statement_is_all_keywords FOR TESTING RAISING cx_static_check. - METHODS identifiers_like_keywords FOR TESTING RAISING cx_static_check. - METHODS test_find_clause_index FOR TESTING. -ENDCLASS. + private section. + methods statement_is_all_keywords for testing raising cx_static_check. + methods identifiers_like_keywords for testing raising cx_static_check. + methods test_find_clause_index for testing. +endclass. -CLASS key_words IMPLEMENTATION. - METHOD statement_is_all_keywords. - DATA(test_statement) = VALUE if_ci_atc_source_code_provider=>ty_statement( - tokens = VALUE #( FOR i = 1 THEN i + 1 UNTIL i >= 10 ( lexeme = |{ i }| ) ) ). - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). +class key_words implementation. + method statement_is_all_keywords. + data(test_statement) = value if_ci_atc_source_code_provider=>ty_statement( + tokens = value #( for i = 1 then i + 1 until i >= 10 ( lexeme = |{ i }| ) ) ). + data(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `3` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `3` ) ) statement = test_statement ) exp = 3 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `3` ) ( `4` ) ( `5` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `3` ) ( `4` ) ( `5` ) ) statement = test_statement ) exp = 3 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `1` ) ( `5` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `1` ) ( `5` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `8` ) ( `9` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `8` ) ( `9` ) ) statement = test_statement ) exp = 8 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `6` ) ( `8` ) ( `9` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `6` ) ( `8` ) ( `9` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `5` ) ( `3` ) ( `4` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `5` ) ( `3` ) ( `4` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( act = analyzer->find_key_words( - key_words = VALUE #( ( `1` ) ( `2` ) ( `3` ) ( `4` ) ) + key_words = value #( ( `1` ) ( `2` ) ( `3` ) ( `4` ) ) statement = test_statement ) exp = 1 ). - ENDMETHOD. + endmethod. - METHOD identifiers_like_keywords. - DATA(test_statement) = VALUE if_ci_atc_source_code_provider=>ty_statement( - tokens = VALUE #( + method identifiers_like_keywords. + data(test_statement) = value if_ci_atc_source_code_provider=>ty_statement( + tokens = value #( ( lexeme = `1` ) ( lexeme = `2` ) - ( lexeme = `3` references = VALUE #( ( full_name = `FOO` ) ) ) + ( lexeme = `3` references = value #( ( full_name = `FOO` ) ) ) ( lexeme = `4` ) ) ). - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). + data(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `2` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `2` ) ) statement = test_statement ) exp = 2 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `3` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `3` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `2` ) ( `3` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `2` ) ( `3` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `2` ) ( `3` ) ( `4` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `2` ) ( `3` ) ( `4` ) ) statement = test_statement ) exp = -1 ). cl_abap_unit_assert=>assert_equals( - act = analyzer->find_key_words( key_words = VALUE #( ( `1` ) ( `2` ) ) statement = test_statement ) + act = analyzer->find_key_words( key_words = value #( ( `1` ) ( `2` ) ) statement = test_statement ) exp = 1 ). - ENDMETHOD. + endmethod. - METHOD test_find_clause_index. - DATA(test_tokens) = VALUE if_ci_atc_source_code_provider=>ty_tokens( + method test_find_clause_index. + data(test_tokens) = value if_ci_atc_source_code_provider=>ty_tokens( ( lexeme = '1' ) ( lexeme = '2' ) ( lexeme = '3' ) ( lexeme = '4' ) ( lexeme = '5' ) ( lexeme = '6' ) ( lexeme = '7' ) ( lexeme = '8' ) ( lexeme = '9' ) ( lexeme = '10' ) ). - DATA(test_clause) = `5 6 7`. - DATA(index) = /cc4a/abap_analyzer=>create( )->find_clause_index( tokens = test_tokens clause = test_clause ). + data(test_clause) = `5 6 7`. + data(index) = /cc4a/abap_analyzer=>create( )->find_clause_index( tokens = test_tokens clause = test_clause ). cl_abap_unit_assert=>assert_equals( act = index exp = 5 ). - test_tokens = VALUE #( ( lexeme = 'A' ) ( lexeme = 'B' ) ( lexeme = '3' ) + test_tokens = value #( ( lexeme = 'A' ) ( lexeme = 'B' ) ( lexeme = '3' ) ( lexeme = 'A' ) ( lexeme = 'B' ) ( lexeme = 'C' ) ( lexeme = 'A' ) ( lexeme = 'B' ) ( lexeme = 'C' ) ( lexeme = 'D' ) ). index = /cc4a/abap_analyzer=>create( )->find_clause_index( tokens = test_tokens clause = `A B C D` ). cl_abap_unit_assert=>assert_equals( act = index exp = 7 ). - TRY. + try. index = /cc4a/abap_analyzer=>create( )->find_clause_index( tokens = test_tokens clause = ` ` ). cl_abap_unit_assert=>fail( ). - CATCH /cc4a/cx_clause_is_initial. - ENDTRY. - ENDMETHOD. -ENDCLASS. + catch /cc4a/cx_clause_is_initial. + endtry. + endmethod. +endclass. -CLASS lcl_atc_check_db_stmt DEFINITION FINAL. +class lcl_atc_check_db_stmt definition final. - PUBLIC SECTION. - INTERFACES if_ci_atc_check. + public section. + interfaces if_ci_atc_check. - PRIVATE SECTION. - DATA code_provider TYPE REF TO if_ci_atc_source_code_provider. - DATA assistant_factory TYPE REF TO cl_ci_atc_assistant_factory ##needed. + private section. + data code_provider type ref to if_ci_atc_source_code_provider. + data assistant_factory type ref to cl_ci_atc_assistant_factory ##needed. - METHODS analyze_procedure - IMPORTING !procedure TYPE if_ci_atc_source_code_provider=>ty_procedure - RETURNING VALUE(findings) TYPE if_ci_atc_check=>ty_findings. -ENDCLASS. + methods analyze_procedure + importing !procedure type if_ci_atc_source_code_provider=>ty_procedure + returning value(findings) type if_ci_atc_check=>ty_findings. +endclass. -CLASS lcl_atc_check_db_stmt IMPLEMENTATION. - METHOD if_ci_atc_check~get_meta_data. +class lcl_atc_check_db_stmt implementation. + method if_ci_atc_check~get_meta_data. meta_data = /cc4a/check_meta_data=>create( - VALUE #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs + value #( checked_types = /cc4a/check_meta_data=>checked_types-abap_programs remote_enablement = /cc4a/check_meta_data=>remote_enablement-unconditional - finding_codes = VALUE #( ( code = 'SELECT' ) ( code = 'WITH' ) ( code = 'INSERT' ) + finding_codes = value #( ( code = 'SELECT' ) ( code = 'WITH' ) ( code = 'INSERT' ) ( code = 'DELETE' ) ( code = 'UPDATE' ) ( code = 'MODIFY' ) ( code = 'OPEN' ) ( code = 'EXEC' ) ( code = 'LOOP' ) ( code = 'READ' ) ( code = 'IMPORT' ) ( code = 'EXPORT' ) ) ) ). - ENDMETHOD. + endmethod. - METHOD if_ci_atc_check~run. + method if_ci_atc_check~run. code_provider = data_provider->get_code_provider( ). - DATA(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). - LOOP AT procedures->* ASSIGNING FIELD-SYMBOL(). - INSERT LINES OF analyze_procedure( ) INTO TABLE findings. - ENDLOOP. - ENDMETHOD. + data(procedures) = code_provider->get_procedures( code_provider->object_to_comp_unit( object ) ). + loop at procedures->* assigning field-symbol(). + insert lines of analyze_procedure( ) into table findings. + endloop. + endmethod. - METHOD if_ci_atc_check~set_assistant_factory. + method if_ci_atc_check~set_assistant_factory. assistant_factory = factory. - ENDMETHOD. + endmethod. - METHOD if_ci_atc_check~verify_prerequisites ##needed. - ENDMETHOD. + method if_ci_atc_check~verify_prerequisites ##needed. + endmethod. - METHOD analyze_procedure. - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). - LOOP AT procedure-statements ASSIGNING FIELD-SYMBOL(). - DATA(result) = analyzer->is_db_statement( ). - IF result-is_db = abap_true. - INSERT VALUE #( + method analyze_procedure. + data(analyzer) = /cc4a/abap_analyzer=>create( ). + loop at procedure-statements assigning field-symbol(). + data(result) = analyzer->is_db_statement( ). + if result-is_db = abap_true. + insert value #( code = -keyword - parameters = VALUE #( param_1 = result-dbtab param_2 = result-dbtab_subquery ) - location = VALUE #( object = code_provider->get_statement_location( )-object + parameters = value #( param_1 = result-dbtab param_2 = result-dbtab_subquery ) + location = value #( object = code_provider->get_statement_location( )-object position = code_provider->get_statement_location( )-position ) - checksum = code_provider->get_statement_checksum( ) ) INTO TABLE findings. - ENDIF. - ENDLOOP. - ENDMETHOD. -ENDCLASS. - -CLASS db_stmt DEFINITION FINAL FOR TESTING - DURATION SHORT - RISK LEVEL HARMLESS. - - PRIVATE SECTION. - CONSTANTS test_class TYPE c LENGTH 30 VALUE '/CC4A/TEST_FOR_DB_STATEMENTS'. - - METHODS execute_test_class FOR TESTING RAISING cx_static_check. -ENDCLASS. - -CLASS db_stmt IMPLEMENTATION. - METHOD execute_test_class. - DATA(dyn) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'DYN' ) ). - DATA(mixed) = cl_ci_atc_unit_driver=>get_method_object( VALUE #( class = test_class method = 'MIXED' ) ). + checksum = code_provider->get_statement_checksum( ) ) into table findings. + endif. + endloop. + endmethod. +endclass. + +class db_stmt definition final for testing + duration short + risk level harmless. + + private section. + constants test_class type c length 30 value '/CC4A/TEST_FOR_DB_STATEMENTS'. + + methods execute_test_class for testing raising cx_static_check. +endclass. + +class db_stmt implementation. + method execute_test_class. + data(dyn) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'DYN' ) ). + data(mixed) = cl_ci_atc_unit_driver=>get_method_object( value #( class = test_class method = 'MIXED' ) ). cl_ci_atc_unit_driver=>create_asserter( )->check_and_assert( - check = NEW lcl_atc_check_db_stmt( ) - object = VALUE #( type = 'CLAS' name = test_class ) - expected_findings = VALUE #( - ( code = 'DELETE' location = VALUE #( object = dyn position = VALUE #( line = 6 column = 4 ) ) ) - ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 9 column = 6 ) ) ) - ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 12 column = 6 ) ) ) - ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 14 column = 4 ) ) ) - ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 15 column = 4 ) ) ) - ( code = 'SELECT' location = VALUE #( object = dyn position = VALUE #( line = 17 column = 4 ) ) ) - ( code = 'INSERT' location = VALUE #( object = dyn position = VALUE #( line = 18 column = 4 ) ) ) - ( code = 'INSERT' location = VALUE #( object = dyn position = VALUE #( line = 19 column = 4 ) ) ) - ( code = 'UPDATE' location = VALUE #( object = dyn position = VALUE #( line = 20 column = 4 ) ) ) - ( code = 'UPDATE' location = VALUE #( object = dyn position = VALUE #( line = 21 column = 4 ) ) ) - ( code = 'MODIFY' location = VALUE #( object = dyn position = VALUE #( line = 22 column = 4 ) ) ) - ( code = 'DELETE' location = VALUE #( object = dyn position = VALUE #( line = 23 column = 4 ) ) ) - ( code = 'DELETE' location = VALUE #( object = dyn position = VALUE #( line = 24 column = 4 ) ) ) - ( code = 'DELETE' location = VALUE #( object = dyn position = VALUE #( line = 26 column = 4 ) ) ) - ( code = 'SELECT' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 8 column = 4 ) ) ) - ( code = 'SELECT' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 9 column = 4 ) ) ) - ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 13 column = 4 ) ) ) - ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 14 column = 4 ) ) ) - ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 15 column = 4 ) ) ) - ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 17 column = 4 ) ) ) - ( code = 'DELETE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 18 column = 4 ) ) ) - ( code = 'INSERT' parameters = VALUE #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 23 column = 4 ) ) ) - ( code = 'UPDATE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 29 column = 4 ) ) ) - ( code = 'UPDATE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 30 column = 4 ) ) ) - ( code = 'UPDATE' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 31 column = 4 ) ) ) - ( code = 'MODIFY' parameters = VALUE #( param_1 = '/CC4A/DB_TEST1' ) - location = VALUE #( object = mixed position = VALUE #( line = 33 column = 4 ) ) ) - ( code = 'WITH' parameters = VALUE #( param_1 = 'SCI_TEST_SFLIGHT' ) - location = VALUE #( object = mixed position = VALUE #( line = 46 column = 4 ) ) ) ) - asserter_config = VALUE #( + check = new lcl_atc_check_db_stmt( ) + object = value #( type = 'CLAS' name = test_class ) + expected_findings = value #( + ( code = 'DELETE' location = value #( object = dyn position = value #( line = 6 column = 4 ) ) ) + ( code = 'SELECT' location = value #( object = dyn position = value #( line = 9 column = 6 ) ) ) + ( code = 'SELECT' location = value #( object = dyn position = value #( line = 12 column = 6 ) ) ) + ( code = 'SELECT' location = value #( object = dyn position = value #( line = 14 column = 4 ) ) ) + ( code = 'SELECT' location = value #( object = dyn position = value #( line = 15 column = 4 ) ) ) + ( code = 'SELECT' location = value #( object = dyn position = value #( line = 17 column = 4 ) ) ) + ( code = 'INSERT' location = value #( object = dyn position = value #( line = 18 column = 4 ) ) ) + ( code = 'INSERT' location = value #( object = dyn position = value #( line = 19 column = 4 ) ) ) + ( code = 'UPDATE' location = value #( object = dyn position = value #( line = 20 column = 4 ) ) ) + ( code = 'UPDATE' location = value #( object = dyn position = value #( line = 21 column = 4 ) ) ) + ( code = 'MODIFY' location = value #( object = dyn position = value #( line = 22 column = 4 ) ) ) + ( code = 'DELETE' location = value #( object = dyn position = value #( line = 23 column = 4 ) ) ) + ( code = 'DELETE' location = value #( object = dyn position = value #( line = 24 column = 4 ) ) ) + ( code = 'DELETE' location = value #( object = dyn position = value #( line = 26 column = 4 ) ) ) + ( code = 'SELECT' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 8 column = 4 ) ) ) + ( code = 'SELECT' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 9 column = 4 ) ) ) + ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 13 column = 4 ) ) ) + ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 14 column = 4 ) ) ) + ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 15 column = 4 ) ) ) + ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 17 column = 4 ) ) ) + ( code = 'DELETE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 18 column = 4 ) ) ) + ( code = 'INSERT' parameters = value #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 23 column = 4 ) ) ) + ( code = 'UPDATE' parameters = value #( param_1 = '/CC4A/DB_TEST2' param_2 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 29 column = 4 ) ) ) + ( code = 'UPDATE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 30 column = 4 ) ) ) + ( code = 'UPDATE' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 31 column = 4 ) ) ) + ( code = 'MODIFY' parameters = value #( param_1 = '/CC4A/DB_TEST1' ) + location = value #( object = mixed position = value #( line = 33 column = 4 ) ) ) + ( code = 'WITH' parameters = value #( param_1 = 'SCI_TEST_SFLIGHT' ) + location = value #( object = mixed position = value #( line = 46 column = 4 ) ) ) ) + asserter_config = value #( quickfixes = abap_false ) ). - ENDMETHOD. -ENDCLASS. - -CLASS shared DEFINITION FINAL ABSTRACT. - PUBLIC SECTION. - CLASS-METHODS tokenize - IMPORTING !code TYPE string - RETURNING VALUE(statement) TYPE if_ci_atc_source_code_provider=>ty_statement. -ENDCLASS. - -CLASS shared IMPLEMENTATION. - METHOD tokenize. - SPLIT code AT space INTO TABLE DATA(tokens). - DELETE tokens WHERE table_line = '.'. - statement = VALUE #( tokens = VALUE #( FOR IN tokens ( lexeme = to_upper( ) ) ) ). + endmethod. +endclass. + +class shared definition final abstract. + public section. + class-methods tokenize + importing !code type string + returning value(statement) type if_ci_atc_source_code_provider=>ty_statement. +endclass. + +class shared implementation. + method tokenize. + split code at space into table data(tokens). + delete tokens where table_line = '.'. + statement = value #( tokens = value #( for in tokens ( lexeme = to_upper( ) ) ) ). statement-keyword = statement-tokens[ 1 ]-lexeme. - ENDMETHOD. -ENDCLASS. + endmethod. +endclass. -CLASS bracket_matching DEFINITION FINAL FOR TESTING - DURATION SHORT - RISK LEVEL HARMLESS. +class bracket_matching definition final for testing + duration short + risk level harmless. - PRIVATE SECTION. - METHODS bracket_ends FOR TESTING RAISING cx_static_check. -ENDCLASS. + private section. + methods bracket_ends for testing raising cx_static_check. +endclass. -CLASS bracket_matching IMPLEMENTATION. - METHOD bracket_ends. - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). +class bracket_matching implementation. + method bracket_ends. + data(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( act = analyzer->calculate_bracket_end( @@ -268,129 +268,129 @@ CLASS bracket_matching IMPLEMENTATION. statement = shared=>tokenize( `obj->call( )->second_call( )` ) bracket_position = 1 ) exp = 2 ). - ENDMETHOD. -ENDCLASS. + endmethod. +endclass. -CLASS method_definitions DEFINITION FINAL FOR TESTING - DURATION SHORT - RISK LEVEL HARMLESS. +class method_definitions definition final for testing + duration short + risk level harmless. - PRIVATE SECTION. - METHODS method_definitions FOR TESTING RAISING cx_static_check. -ENDCLASS. + private section. + methods method_definitions for testing raising cx_static_check. +endclass. -CLASS method_definitions IMPLEMENTATION. - METHOD method_definitions. - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). +class method_definitions implementation. + method method_definitions. + data(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth redefinition .` ) ) - exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( + exp = value /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` is_redefinition = abap_true ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth .` ) ) - exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( + exp = value /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth importing par type i .` ) ) - exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( + exp = value /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ) ) ). + parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth importing reference(par) type i .` ) ) - exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( + exp = value /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ) ) ). + parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth exporting par type i .` ) ) - exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( + exp = value /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-exporting ) ) ) ). + parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-exporting ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth changing par type i .` ) ) - exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( + exp = value /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ) ) ). + parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth changing par type i .` ) ) - exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( + exp = value /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = VALUE #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ) ) ). + parameters = value #( ( name = `PAR` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ) ) ). cl_abap_unit_assert=>assert_equals( act = analyzer->parse_method_definition( shared=>tokenize( `methods meth importing imp type i exporting reference(exp) type i changing ch type i returning value(ret) type i.` ) ) - exp = VALUE /cc4a/if_abap_analyzer=>ty_method_definition( + exp = value /cc4a/if_abap_analyzer=>ty_method_definition( name = `METH` - parameters = VALUE #( + parameters = value #( ( name = `IMP` kind = /cc4a/if_abap_analyzer=>parameter_kind-importing ) ( name = `EXP` kind = /cc4a/if_abap_analyzer=>parameter_kind-exporting ) ( name = `CH` kind = /cc4a/if_abap_analyzer=>parameter_kind-changing ) ( name = `RET` kind = /cc4a/if_abap_analyzer=>parameter_kind-returning ) ) ) ). - ENDMETHOD. -ENDCLASS. - -CLASS flatten_tokens DEFINITION FINAL FOR TESTING - DURATION SHORT - RISK LEVEL HARMLESS. - - PRIVATE SECTION. - METHODS simple_statement FOR TESTING RAISING cx_static_check. - METHODS string_template FOR TESTING RAISING cx_static_check. - METHODS nested_string_template FOR TESTING RAISING cx_static_check. - METHODS test1 FOR TESTING RAISING cx_static_check. - METHODS test_line_break FOR TESTING RAISING cx_static_check. -ENDCLASS. - -CLASS /cc4a/abap_analyzer DEFINITION LOCAL FRIENDS flatten_tokens. - -CLASS flatten_tokens IMPLEMENTATION. - METHOD test1. - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). - DATA(flat) = analyzer->flatten_tokens( tokens = VALUE #( + endmethod. +endclass. + +class flatten_tokens definition final for testing + duration short + risk level harmless. + + private section. + methods simple_statement for testing raising cx_static_check. + methods string_template for testing raising cx_static_check. + methods nested_string_template for testing raising cx_static_check. + methods test1 for testing raising cx_static_check. + methods test_line_break for testing raising cx_static_check. +endclass. + +class /cc4a/abap_analyzer definition local friends flatten_tokens. + +class flatten_tokens implementation. + method test1. + data(analyzer) = /cc4a/abap_analyzer=>create( ). + data(flat) = analyzer->flatten_tokens( tokens = value #( ( lexeme = `DATA(text)` ) ( lexeme = `=` ) ( lexeme = `method(` ) ( lexeme = `|` ) ( lexeme = '`whatsoever`' ) ( lexeme = `|` ) ( lexeme = `)` ) ) ). cl_abap_unit_assert=>assert_equals( act = flat exp = `DATA(text) = method( |whatsoever| )` ). * 123456789012345678901234567890123456 - DATA(lines) = /cc4a/abap_analyzer=>_break_into_lines( code = flat break_at = 20 ). - DATA(exp_lines) = VALUE string_table( ( `DATA(text) = method(` ) ( `|whatsoever| )` ) ). + data(lines) = /cc4a/abap_analyzer=>_break_into_lines( code = flat break_at = 20 ). + data(exp_lines) = value string_table( ( `DATA(text) = method(` ) ( `|whatsoever| )` ) ). cl_abap_unit_assert=>assert_equals( act = lines exp = exp_lines ). - ENDMETHOD. - METHOD test_line_break. - DATA lines TYPE string_table. - TRY. + endmethod. + method test_line_break. + data lines type string_table. + try. lines = /cc4a/abap_analyzer=>_break_into_lines( code = `12345678901` break_at = 10 ). cl_abap_unit_assert=>fail( `Exception expected` ). - CATCH /cc4a/cx_line_break_impossible. + catch /cc4a/cx_line_break_impossible. * expected - ENDTRY. - TRY. + endtry. + try. lines = /cc4a/abap_analyzer=>_break_into_lines( code = `1234567890 123467890123` break_at = 10 ). cl_abap_unit_assert=>fail( `Exception expected` ). - CATCH /cc4a/cx_line_break_impossible. + catch /cc4a/cx_line_break_impossible. * expected - ENDTRY. + endtry. - TRY. + try. lines = /cc4a/abap_analyzer=>_break_into_lines( code = `|23456789| blabla` break_at = 10 ). - DATA(exp_lines) = VALUE string_table( ( `|23456789|` ) ( `blabla` ) ). + data(exp_lines) = value string_table( ( `|23456789|` ) ( `blabla` ) ). cl_abap_unit_assert=>assert_equals( act = lines exp = exp_lines ). - CATCH /cc4a/cx_line_break_impossible. + catch /cc4a/cx_line_break_impossible. cl_abap_unit_assert=>fail( `No Exception expected` ). - ENDTRY. - ENDMETHOD. - METHOD simple_statement. - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). + endtry. + endmethod. + method simple_statement. + data(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( act = analyzer->flatten_tokens( shared=>tokenize( `data my_int type i.` )-tokens ) @@ -399,12 +399,12 @@ CLASS flatten_tokens IMPLEMENTATION. act = analyzer->flatten_tokens( shared=>tokenize( `obj->meth( par = val ).` )-tokens ) exp = `OBJ->METH( PAR = VAL ).` ). - ENDMETHOD. + endmethod. - METHOD string_template. - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). + method string_template. + data(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( - act = condense( analyzer->flatten_tokens( VALUE #( + act = condense( analyzer->flatten_tokens( value #( ( lexeme = `STR` ) ( lexeme = `=` ) ( lexeme = `|` ) @@ -415,12 +415,12 @@ CLASS flatten_tokens IMPLEMENTATION. ( lexeme = '`!`' ) ( lexeme = `|` ) ) ) ) exp = 'STR = |hello, { WORLD }!|' ). - ENDMETHOD. + endmethod. - METHOD nested_string_template. - DATA(analyzer) = /cc4a/abap_analyzer=>create( ). + method nested_string_template. + data(analyzer) = /cc4a/abap_analyzer=>create( ). cl_abap_unit_assert=>assert_equals( - act = condense( analyzer->flatten_tokens( VALUE #( + act = condense( analyzer->flatten_tokens( value #( ( lexeme = `STR` ) ( lexeme = `=` ) ( lexeme = `|` ) @@ -439,5 +439,5 @@ CLASS flatten_tokens IMPLEMENTATION. ( lexeme = `|` ) ) ) ) exp = 'STR = |hello, { func( |inner { TEMPLATE }| ) }!|' ). - ENDMETHOD. -ENDCLASS. + endmethod. +endclass. diff --git a/src/core/#cc4a#cx_line_break_impossible.clas.abap b/src/core/#cc4a#cx_line_break_impossible.clas.abap index 21e5cd7..d39ddbc 100644 --- a/src/core/#cc4a#cx_line_break_impossible.clas.abap +++ b/src/core/#cc4a#cx_line_break_impossible.clas.abap @@ -1,23 +1,23 @@ -CLASS /cc4a/cx_line_break_impossible DEFINITION - PUBLIC - INHERITING FROM cx_dynamic_check - FINAL - CREATE PUBLIC . +class /cc4a/cx_line_break_impossible definition + public + inheriting from cx_dynamic_check + final + create public . - PUBLIC SECTION. + public section. - METHODS constructor. - PROTECTED SECTION. - PRIVATE SECTION. -ENDCLASS. + methods constructor. + protected section. + private section. +endclass. -CLASS /cc4a/cx_line_break_impossible IMPLEMENTATION. - METHOD constructor ##ADT_SUPPRESS_GENERATION. +class /cc4a/cx_line_break_impossible implementation. + method constructor ##ADT_SUPPRESS_GENERATION. super->constructor( textid = textid previous = previous ). - ENDMETHOD. + endmethod. -ENDCLASS. +endclass. From dcbefbb8b1f1af9d39adcc353c5bb74fbb9b3d21 Mon Sep 17 00:00:00 2001 From: Bjoern Jueliger Date: Wed, 7 Feb 2024 09:19:54 +0000 Subject: [PATCH 8/9] Revert change to static methods --- src/core/#cc4a#abap_analyzer.clas.abap | 6 +++--- src/core/#cc4a#abap_analyzer.clas.testclasses.abap | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/#cc4a#abap_analyzer.clas.abap b/src/core/#cc4a#abap_analyzer.clas.abap index 058d2f9..07ecee5 100644 --- a/src/core/#cc4a#abap_analyzer.clas.abap +++ b/src/core/#cc4a#abap_analyzer.clas.abap @@ -24,15 +24,15 @@ class /cc4a/abap_analyzer definition end of ty_negation. class-data negations type table of ty_negation. - class-methods _flatten_tokens + methods _flatten_tokens changing tokens type if_ci_atc_source_code_provider=>ty_tokens returning value(flat) type string. - class-methods _flatten_template + methods _flatten_template changing tokens type if_ci_atc_source_code_provider=>ty_tokens returning value(flat) type string. - class-methods _break_into_lines + methods _break_into_lines importing value(code) type string break_at type i returning value(code_lines) type string_table diff --git a/src/core/#cc4a#abap_analyzer.clas.testclasses.abap b/src/core/#cc4a#abap_analyzer.clas.testclasses.abap index bbaa4ce..62fd9e8 100644 --- a/src/core/#cc4a#abap_analyzer.clas.testclasses.abap +++ b/src/core/#cc4a#abap_analyzer.clas.testclasses.abap @@ -362,27 +362,27 @@ class flatten_tokens implementation. act = flat exp = `DATA(text) = method( |whatsoever| )` ). * 123456789012345678901234567890123456 - data(lines) = /cc4a/abap_analyzer=>_break_into_lines( code = flat break_at = 20 ). + data(lines) = new /cc4a/abap_analyzer( )->_break_into_lines( code = flat break_at = 20 ). data(exp_lines) = value string_table( ( `DATA(text) = method(` ) ( `|whatsoever| )` ) ). cl_abap_unit_assert=>assert_equals( act = lines exp = exp_lines ). endmethod. method test_line_break. data lines type string_table. try. - lines = /cc4a/abap_analyzer=>_break_into_lines( code = `12345678901` break_at = 10 ). + lines = new /cc4a/abap_analyzer( )->_break_into_lines( code = `12345678901` break_at = 10 ). cl_abap_unit_assert=>fail( `Exception expected` ). catch /cc4a/cx_line_break_impossible. * expected endtry. try. - lines = /cc4a/abap_analyzer=>_break_into_lines( code = `1234567890 123467890123` break_at = 10 ). + lines = new /cc4a/abap_analyzer( )->_break_into_lines( code = `1234567890 123467890123` break_at = 10 ). cl_abap_unit_assert=>fail( `Exception expected` ). catch /cc4a/cx_line_break_impossible. * expected endtry. try. - lines = /cc4a/abap_analyzer=>_break_into_lines( code = `|23456789| blabla` break_at = 10 ). + lines = new /cc4a/abap_analyzer( )->_break_into_lines( code = `|23456789| blabla` break_at = 10 ). data(exp_lines) = value string_table( ( `|23456789|` ) ( `blabla` ) ). cl_abap_unit_assert=>assert_equals( act = lines exp = exp_lines ). catch /cc4a/cx_line_break_impossible. From 2842fb2f85212532062125a7f6c9161c2100326e Mon Sep 17 00:00:00 2001 From: Bjoern Jueliger Date: Wed, 7 Feb 2024 09:22:56 +0000 Subject: [PATCH 9/9] Formatting --- src/core/#cc4a#if_abap_analyzer.intf.abap | 186 ++++---- .../#cc4a#test_modern_language.clas.abap | 422 +++++++++--------- ...#test_modern_language.clas.locals_imp.abap | 10 +- 3 files changed, 307 insertions(+), 311 deletions(-) diff --git a/src/core/#cc4a#if_abap_analyzer.intf.abap b/src/core/#cc4a#if_abap_analyzer.intf.abap index 83d1349..31f92a4 100644 --- a/src/core/#cc4a#if_abap_analyzer.intf.abap +++ b/src/core/#cc4a#if_abap_analyzer.intf.abap @@ -2,11 +2,11 @@ "! "! Any logic that processes ABAP code information (e.g. parsing a specific assignment) should be located here "! so it can be accessed by any check that needs it. -INTERFACE /cc4a/if_abap_analyzer - PUBLIC . - CONSTANTS max_line_length TYPE i VALUE 255. - TYPES: - BEGIN OF ENUM ty_bracket_type STRUCTURE bracket_type, +interface /cc4a/if_abap_analyzer + public . + constants max_line_length type i value 255. + types: + begin of enum ty_bracket_type structure bracket_type, no_bracket, opening, closing, @@ -14,107 +14,107 @@ INTERFACE /cc4a/if_abap_analyzer "! obj->method_1( )->method_2( ) produces a single token `)->method_2(` that is both a closing and an "! opening bracket. clopening, - END OF ENUM ty_bracket_type STRUCTURE bracket_type. - TYPES: - BEGIN OF ty_db_statement, - is_db TYPE abap_bool, - dbtab TYPE string, - dbtab_subquery TYPE string, - END OF ty_db_statement. - TYPES: - BEGIN OF ENUM ty_parameter_kind STRUCTURE parameter_kind, + end of enum ty_bracket_type structure bracket_type. + types: + begin of ty_db_statement, + is_db type abap_bool, + dbtab type string, + dbtab_subquery type string, + end of ty_db_statement. + types: + begin of enum ty_parameter_kind structure parameter_kind, importing, exporting, changing, returning, - END OF ENUM ty_parameter_kind STRUCTURE parameter_kind. - TYPES: - BEGIN OF ty_method_parameter, - name TYPE string, - kind TYPE ty_parameter_kind, - END OF ty_method_parameter. - TYPES ty_method_parameters TYPE HASHED TABLE OF ty_method_parameter WITH UNIQUE KEY name. - TYPES: - BEGIN OF ty_method_definition, - name TYPE string, - is_redefinition TYPE abap_bool, - parameters TYPE ty_method_parameters, - END OF ty_method_definition. + end of enum ty_parameter_kind structure parameter_kind. + types: + begin of ty_method_parameter, + name type string, + kind type ty_parameter_kind, + end of ty_method_parameter. + types ty_method_parameters type hashed table of ty_method_parameter with unique key name. + types: + begin of ty_method_definition, + name type string, + is_redefinition type abap_bool, + parameters type ty_method_parameters, + end of ty_method_definition. - METHODS find_key_words - IMPORTING - key_words TYPE string_table - statement TYPE if_ci_atc_source_code_provider=>ty_statement - RETURNING - VALUE(position) TYPE i . - METHODS break_into_lines - IMPORTING code TYPE string - RETURNING VALUE(code_lines) TYPE if_ci_atc_quickfix=>ty_code - RAISING /cc4a/cx_line_break_impossible. - METHODS flatten_tokens - IMPORTING - tokens TYPE if_ci_atc_source_code_provider=>ty_tokens - RETURNING - VALUE(flat_statement) TYPE string . - METHODS is_bracket - IMPORTING - token TYPE if_ci_atc_source_code_provider=>ty_token - RETURNING - VALUE(bracket_type) TYPE ty_bracket_type . - METHODS calculate_bracket_end - IMPORTING - statement TYPE if_ci_atc_source_code_provider=>ty_statement - bracket_position TYPE i - RETURNING - VALUE(end_of_bracket) TYPE i - RAISING + methods find_key_words + importing + key_words type string_table + statement type if_ci_atc_source_code_provider=>ty_statement + returning + value(position) type i . + methods break_into_lines + importing code type string + returning value(code_lines) type if_ci_atc_quickfix=>ty_code + raising /cc4a/cx_line_break_impossible. + methods flatten_tokens + importing + tokens type if_ci_atc_source_code_provider=>ty_tokens + returning + value(flat_statement) type string . + methods is_bracket + importing + token type if_ci_atc_source_code_provider=>ty_token + returning + value(bracket_type) type ty_bracket_type . + methods calculate_bracket_end + importing + statement type if_ci_atc_source_code_provider=>ty_statement + bracket_position type i + returning + value(end_of_bracket) type i + raising /cc4a/cx_token_is_no_bracket . "! The method analyze the given token whether this is an comparison operator or not. "! Operators like +, -, * and / does not count as comparison operator. "! The following operators are currently supported: is, in, >, gt, <, lt, >=, ge, <=, le, =, eq, <>, ne - METHODS token_is_comparison_operator - IMPORTING - token TYPE if_ci_atc_source_code_provider=>ty_token - RETURNING - VALUE(is_operator) TYPE abap_bool . - METHODS negate_comparison_operator - IMPORTING - comparison_operator TYPE string - RETURNING - VALUE(negated_comparison_operator) TYPE string - RAISING + methods token_is_comparison_operator + importing + token type if_ci_atc_source_code_provider=>ty_token + returning + value(is_operator) type abap_bool . + methods negate_comparison_operator + importing + comparison_operator type string + returning + value(negated_comparison_operator) type string + raising /cc4a/cx_token_is_no_operator . - METHODS is_db_statement - IMPORTING - statement TYPE if_ci_atc_source_code_provider=>ty_statement - get_dbtab_name TYPE abap_bool DEFAULT abap_false - include_subqueries TYPE abap_bool DEFAULT abap_true - RETURNING - VALUE(result) TYPE ty_db_statement. + methods is_db_statement + importing + statement type if_ci_atc_source_code_provider=>ty_statement + get_dbtab_name type abap_bool default abap_false + include_subqueries type abap_bool default abap_true + returning + value(result) type ty_db_statement. "! The method checks if clause is contained in tokens "! if so it returns the index of the first token of the first occurrence of the clause "! otherwise token_index = 0 - METHODS find_clause_index - IMPORTING - tokens TYPE if_ci_atc_source_code_provider=>ty_tokens - clause TYPE string - start_index TYPE i DEFAULT 1 - RETURNING - VALUE(token_index) TYPE i - RAISING + methods find_clause_index + importing + tokens type if_ci_atc_source_code_provider=>ty_tokens + clause type string + start_index type i default 1 + returning + value(token_index) type i + raising /cc4a/cx_clause_is_initial . - METHODS is_token_keyword - IMPORTING - token TYPE if_ci_atc_source_code_provider=>ty_token - keyword TYPE string - RETURNING - VALUE(result) TYPE abap_bool . - METHODS is_logical_connective - IMPORTING token TYPE if_ci_atc_source_code_provider=>ty_token - RETURNING VALUE(is_logical_connective) TYPE abap_bool. - METHODS parse_method_definition - IMPORTING statement TYPE if_ci_atc_source_code_provider=>ty_statement - RETURNING VALUE(method_definition) TYPE ty_method_definition. -ENDINTERFACE. + methods is_token_keyword + importing + token type if_ci_atc_source_code_provider=>ty_token + keyword type string + returning + value(result) type abap_bool . + methods is_logical_connective + importing token type if_ci_atc_source_code_provider=>ty_token + returning value(is_logical_connective) type abap_bool. + methods parse_method_definition + importing statement type if_ci_atc_source_code_provider=>ty_statement + returning value(method_definition) type ty_method_definition. +endinterface. diff --git a/src/test_objects/#cc4a#test_modern_language.clas.abap b/src/test_objects/#cc4a#test_modern_language.clas.abap index 9c675a0..086a488 100644 --- a/src/test_objects/#cc4a#test_modern_language.clas.abap +++ b/src/test_objects/#cc4a#test_modern_language.clas.abap @@ -1,33 +1,33 @@ -CLASS /cc4a/test_modern_language DEFINITION - PUBLIC - FINAL - CREATE PUBLIC . +class /cc4a/test_modern_language definition + public + final + create public . - PUBLIC SECTION. - METHODS test_move. - METHODS test_translate. - METHODS test_read. - METHODS test_loop. - METHODS test_create_object. - METHODS test_call_method. - METHODS test_exporting_receiving. - METHODS test_text_assembly. - PROTECTED SECTION. - PRIVATE SECTION. -ENDCLASS. + public section. + methods test_move. + methods test_translate. + methods test_read. + methods test_loop. + methods test_create_object. + methods test_call_method. + methods test_exporting_receiving. + methods test_text_assembly. + protected section. + private section. +endclass. -CLASS /cc4a/test_modern_language IMPLEMENTATION. +class /cc4a/test_modern_language implementation. - METHOD test_move. - TYPES: - BEGIN OF ENUM number, + method test_move. + types: + begin of enum number, n0, n1, n2, - END OF ENUM number. + end of enum number. - DATA num TYPE number ##NEEDED. + data num type number ##NEEDED. * MOVE EXACT 1 TO num. * @@ -45,314 +45,314 @@ CLASS /cc4a/test_modern_language IMPLEMENTATION. * MOVE a TO b ##DUPLICATE_OK. * * MOVE a TO b. "#EC DEPRECATED_KEY - ENDMETHOD. + endmethod. - METHOD test_translate. - DATA(str1) = `This is Really Mixed` ##NEEDED ##NO_TEXT. - TRANSLATE str1 TO UPPER CASE. - TRANSLATE str1 TO LOWER CASE. - TRANSLATE str1 TO LOWER CASE. "#EC DEPRECATED_KEY - ENDMETHOD. + method test_translate. + data(str1) = `This is Really Mixed` ##NEEDED ##NO_TEXT. + translate str1 to upper case. + translate str1 to lower case. + translate str1 to lower case. "#EC DEPRECATED_KEY + endmethod. - METHOD test_read. - DATA itab TYPE STANDARD TABLE OF /cc4a/db_test1 WITH NON-UNIQUE SORTED KEY name COMPONENTS obj_name. + method test_read. + data itab type standard table of /cc4a/db_test1 with non-unique sorted key name components obj_name. - READ TABLE itab TRANSPORTING NO FIELDS WITH KEY pgmid = 'R3TR' object = 'CLAS' . - DATA(idx) = sy-tabix ##NEEDED. + read table itab transporting no fields with key pgmid = 'R3TR' object = 'CLAS' . + data(idx) = sy-tabix ##NEEDED. - READ TABLE itab WITH KEY pgmid = 'R3TR' object = 'CLAS' TRANSPORTING NO FIELDS . - IF sy-subrc = 0. + read table itab with key pgmid = 'R3TR' object = 'CLAS' transporting no fields . + if sy-subrc = 0. idx = sy-tabix. - DATA(exists) = abap_true. - ENDIF. + data(exists) = abap_true. + endif. "DATA(idx) = line_index( itab[ pgmid = 'R3TR' object = 'CLAS' ] ). - READ TABLE itab WITH KEY pgmid = 'R3TR' object = 'CLAS' BINARY SEARCH TRANSPORTING NO FIELDS . "no finding because of binary search - IF sy-subrc = 0. + read table itab with key pgmid = 'R3TR' object = 'CLAS' binary search transporting no fields . "no finding because of binary search + if sy-subrc = 0. idx = sy-tabix. exists = abap_true. - ENDIF. + endif. - READ TABLE itab WITH KEY name COMPONENTS obj_name = 'BLABLA' TRANSPORTING NO FIELDS. + read table itab with key name components obj_name = 'BLABLA' transporting no fields. idx = sy-tabix. - READ TABLE itab TRANSPORTING NO FIELDS WITH KEY name COMPONENTS obj_name = 'BLABLA'. - IF sy-subrc EQ 0. + read table itab transporting no fields with key name components obj_name = 'BLABLA'. + if sy-subrc eq 0. exists = abap_true. idx = sy-tabix. - ENDIF. + endif. "idx = line_index( itab[ KEY name COMPONENTS obj_name = 'BLABLA' ] ). - READ TABLE itab TRANSPORTING NO FIELDS WITH KEY name COMPONENTS obj_name = 'BLABLA'. - IF sy-subrc EQ 0. + read table itab transporting no fields with key name components obj_name = 'BLABLA'. + if sy-subrc eq 0. exists = abap_true. idx = sy-tabix. data(bla) = 'hallo' ##NO_TEXT. - ENDIF. + endif. - READ TABLE itab WITH KEY pgmid = 'R3TR' TRANSPORTING NO FIELDS. + read table itab with key pgmid = 'R3TR' transporting no fields. idx = sy-tabix. - READ TABLE itab WITH KEY pgmid = 'R3TR' TRANSPORTING NO FIELDS. - IF sy-subrc <> 0 OR exists = abap_true ##NEEDED. - ENDIF. + read table itab with key pgmid = 'R3TR' transporting no fields. + if sy-subrc <> 0 or exists = abap_true ##NEEDED. + endif. - READ TABLE itab TRANSPORTING NO FIELDS WITH KEY name COMPONENTS obj_name = 'BLUE'. - IF sy-subrc <> 0. - DATA(blue) = abap_false ##NEEDED. - ENDIF. + read table itab transporting no fields with key name components obj_name = 'BLUE'. + if sy-subrc <> 0. + data(blue) = abap_false ##NEEDED. + endif. - READ TABLE itab TRANSPORTING NO FIELDS WITH KEY name COMPONENTS obj_name = 'BLUE'. - IF sy-subrc <> 0. + read table itab transporting no fields with key name components obj_name = 'BLUE'. + if sy-subrc <> 0. blue = abap_false. idx = sy-tabix. - ENDIF. - - READ TABLE itab TRANSPORTING NO FIELDS - WITH KEY pgmid = 'R3TR'. - IF sy-tabix = 0 ##NEEDED. - ENDIF. - - READ TABLE itab TRANSPORTING NO FIELDS - WITH KEY pgmid = 'R3TR'. - IF sy-tabix IS INITIAL ##NEEDED. - ENDIF. - - READ TABLE itab TRANSPORTING NO FIELDS - WITH KEY pgmid = 'R3TR'. - IF sy-tabix IS NOT INITIAL ##NEEDED. - ENDIF. - - READ TABLE itab TRANSPORTING NO FIELDS - WITH KEY pgmid = 'R3TR'. "#EC PREF_LINE_EX - IF sy-tabix IS NOT INITIAL ##NEEDED. - ENDIF. - - DATA itab_string TYPE TABLE OF string. - READ TABLE itab_string TRANSPORTING NO FIELDS - WITH KEY table_line = 'blabla' ##NO_TEXT. + endif. + + read table itab transporting no fields + with key pgmid = 'R3TR'. + if sy-tabix = 0 ##NEEDED. + endif. + + read table itab transporting no fields + with key pgmid = 'R3TR'. + if sy-tabix is initial ##NEEDED. + endif. + + read table itab transporting no fields + with key pgmid = 'R3TR'. + if sy-tabix is not initial ##NEEDED. + endif. + + read table itab transporting no fields + with key pgmid = 'R3TR'. "#EC PREF_LINE_EX + if sy-tabix is not initial ##NEEDED. + endif. + + data itab_string type table of string. + read table itab_string transporting no fields + with key table_line = 'blabla' ##NO_TEXT. bla = 'Difference in contructor code/line' && sy-tabix ##NO_TEXT. - READ TABLE itab_string TRANSPORTING NO FIELDS - WITH KEY table_line = 'blub' ##NO_TEXT. + read table itab_string transporting no fields + with key table_line = 'blub' ##NO_TEXT. * MESSAGE i011(sci) INTO DATA(lv_dummy) WITH sy-tabix ##NEEDED. - DATA(test) = NEW lcl_test4( ). - READ TABLE itab WITH KEY pgmid = 'BLUB' TRANSPORTING NO FIELDS. - IF sy-subrc <> 0. + data(test) = new lcl_test4( ). + read table itab with key pgmid = 'BLUB' transporting no fields. + if sy-subrc <> 0. test->test( param = abap_false ). - ENDIF. - ENDMETHOD. + endif. + endmethod. - METHOD test_loop. - DATA itab TYPE STANDARD TABLE OF /cc4a/db_test1. + method test_loop. + data itab type standard table of /cc4a/db_test1. - LOOP AT itab TRANSPORTING NO FIELDS WHERE pgmid = 'R3TR' AND object = 'CLAS' . - DATA(idx) = sy-tabix ##NEEDED. - EXIT. - ENDLOOP. + loop at itab transporting no fields where pgmid = 'R3TR' and object = 'CLAS' . + data(idx) = sy-tabix ##NEEDED. + exit. + endloop. - LOOP AT itab TRANSPORTING NO FIELDS WHERE pgmid = 'R3TR' AND object = 'CLAS' . + loop at itab transporting no fields where pgmid = 'R3TR' and object = 'CLAS' . idx = sy-tabix. - DATA(exists) = abap_true ##NEEDED. - EXIT. - ENDLOOP. + data(exists) = abap_true ##NEEDED. + exit. + endloop. - LOOP AT itab INTO DATA(l_entry) WHERE obj_name = 'BLA' ##INTO_OK. "no finding because l_entry is used + loop at itab into data(l_entry) where obj_name = 'BLA' ##INTO_OK. "no finding because l_entry is used exists = abap_true. - EXIT. - ENDLOOP. + exit. + endloop. * WRITE l_entry-pgmid. - LOOP AT itab INTO l_entry WHERE obj_name = 'BLA' ##INTO_OK. + loop at itab into l_entry where obj_name = 'BLA' ##INTO_OK. exists = abap_true. - EXIT. - ENDLOOP. + exit. + endloop. - LOOP AT itab TRANSPORTING NO FIELDS WHERE obj_name = 'BLABLA' AND pgmid IS NOT INITIAL. + loop at itab transporting no fields where obj_name = 'BLABLA' and pgmid is not initial. exists = abap_true. - EXIT. - ENDLOOP. + exit. + endloop. - CONSTANTS c_where TYPE string VALUE 'blabla' ##NO_TEXT. - LOOP AT itab TRANSPORTING NO FIELDS WHERE (c_where). + constants c_where type string value 'blabla' ##NO_TEXT. + loop at itab transporting no fields where (c_where). exists = abap_true. - EXIT. - ENDLOOP. + exit. + endloop. - LOOP AT itab TRANSPORTING NO FIELDS WHERE obj_name = 'BLA'. "#EC PREF_LINE_EX + loop at itab transporting no fields where obj_name = 'BLA'. "#EC PREF_LINE_EX exists = abap_true. - EXIT. - ENDLOOP. + exit. + endloop. - ENDMETHOD. + endmethod. - METHOD test_create_object. - DATA object1 TYPE REF TO /cc4a/test_modern_language. - CREATE OBJECT object1 ##DUPLICATE_OK. + method test_create_object. + data object1 type ref to /cc4a/test_modern_language. + create object object1 ##DUPLICATE_OK. - CREATE OBJECT object1. + create object object1. - DATA class_ref TYPE REF TO lcl_test. + data class_ref type ref to lcl_test. - CREATE OBJECT class_ref - EXPORTING + create object class_ref + exporting param1 = 5 param2 = 4. - DATA class_ref1 TYPE REF TO lcl_test1. - TRY. - CREATE OBJECT class_ref1 - EXPORTING + data class_ref1 type ref to lcl_test1. + try. + create object class_ref1 + exporting param1 = 15 ##NUMBER_OK. - CATCH lcx_error ##NO_HANDLER. - ENDTRY. + catch lcx_error ##NO_HANDLER. + endtry. - DATA class_ref2 TYPE REF TO lcl_test2. - CREATE OBJECT class_ref2 - EXPORTING + data class_ref2 type ref to lcl_test2. + create object class_ref2 + exporting param1 = 13 ##NUMBER_OK - EXCEPTIONS + exceptions error = 1 ##SUBRC_OK. - IF sy-subrc <> 0 ##NEEDED. - ENDIF. + if sy-subrc <> 0 ##NEEDED. + endif. - DATA class_ref3 TYPE REF TO lcl_test3. - CREATE OBJECT class_ref3 - EXPORTING + data class_ref3 type ref to lcl_test3. + create object class_ref3 + exporting param1 = 'blabla' ##NO_TEXT param2 = |{ sy-datum } { sy-uzeit }|. - CREATE OBJECT class_ref3 - EXPORTING + create object class_ref3 + exporting param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla' ##DUPLICATE_OK. - CREATE OBJECT class_ref3 - EXPORTING + create object class_ref3 + exporting param1 = |{ sy-datum } { sy-uzeit }| param2 = 'bla'. "#EC PREF_NEW - DATA selfish TYPE REF TO lcl_test_selfish. - CREATE OBJECT selfish - EXPORTING + data selfish type ref to lcl_test_selfish. + create object selfish + exporting val = selfish->my_val. - ENDMETHOD. + endmethod. - METHOD test_call_method. - DATA test_string TYPE string. + method test_call_method. + data test_string type string. - DATA(class_ref) = NEW lcl_test( param1 = 5 param2 = 3 ). + data(class_ref) = new lcl_test( param1 = 5 param2 = 3 ). - CALL METHOD test_create_object( ). + call method test_create_object( ). - CALL METHOD test_create_object. + call method test_create_object. - CALL METHOD class_ref->test1 - EXPORTING + call method class_ref->test1 + exporting param1 = 15 ##NUMBER_OK - RECEIVING - result = DATA(result) ##NEEDED. + receiving + result = data(result) ##NEEDED. - CALL METHOD class_ref->test2 - EXPORTING + call method class_ref->test2 + exporting param1 = 'Blabla' ##NO_TEXT - IMPORTING - param2 = DATA(string_result) ##NEEDED - CHANGING + importing + param2 = data(string_result) ##NEEDED + changing param3 = test_string. - CALL METHOD class_ref->test3 "no finding because of exceptions - EXPORTING + call method class_ref->test3 "no finding because of exceptions + exporting param1 = 15 ##NUMBER_OK - RECEIVING + receiving result = result - EXCEPTIONS + exceptions error1 = 1 error2 = 2 ##SUBRC_OK. - CALL METHOD class_ref->test4 - EXPORTING + call method class_ref->test4 + exporting param1 = 1 param2 = 2 param3 = 3 - IMPORTING + importing param4 = result. - CALL METHOD class_ref->test1( param1 = 3 ). + call method class_ref->test1( param1 = 3 ). - CALL METHOD (test_string). + call method (test_string). - DATA ptab TYPE abap_parmbind_tab. - DATA xtab TYPE abap_excpbind_tab. - CALL METHOD ('class')=>('method') - PARAMETER-TABLE ptab - EXCEPTION-TABLE xtab. + data ptab type abap_parmbind_tab. + data xtab type abap_excpbind_tab. + call method ('class')=>('method') + parameter-table ptab + exception-table xtab. - CALL METHOD class_ref->test7( - EXPORTING + call method class_ref->test7( + exporting param1 = 5 - IMPORTING - param2 = DATA(testnumber1) - RECEIVING - result = DATA(testnumber2) ) ##NEEDED. + importing + param2 = data(testnumber1) + receiving + result = data(testnumber2) ) ##NEEDED. - CALL METHOD test_create_object. "#EC CALL_METH_USAGE + call method test_create_object. "#EC CALL_METH_USAGE - ENDMETHOD. + endmethod. - METHOD test_exporting_receiving. - DATA test_string TYPE string. + method test_exporting_receiving. + data test_string type string. - DATA(class_ref) = NEW lcl_test( param1 = 5 param2 = 3 ). + data(class_ref) = new lcl_test( param1 = 5 param2 = 3 ). - DATA(result) = class_ref->test1( - EXPORTING + data(result) = class_ref->test1( + exporting param1 = 15 ) ##NEEDED ##NUMBER_OK. class_ref->test2( - EXPORTING + exporting param1 = 'Blabla' ##NO_TEXT - IMPORTING - param2 = DATA(string_result) ##NEEDED - CHANGING + importing + param2 = data(string_result) ##NEEDED + changing param3 = test_string ) ##NEEDED. - result = class_ref->test3( EXPORTING param1 = 15 ) ##NUMBER_OK. + result = class_ref->test3( exporting param1 = 15 ) ##NUMBER_OK. - result = class_ref->test1( EXPORTING param1 = class_ref->test3( EXPORTING param1 = 3 ) ). + result = class_ref->test1( exporting param1 = class_ref->test3( exporting param1 = 3 ) ). * with receiving class_ref->test1( - EXPORTING + exporting param1 = 15 ##NUMBER_OK - RECEIVING result = result ). + receiving result = result ). - class_ref->test3( EXPORTING param1 = 15 RECEIVING result = result ) ##NUMBER_OK. + class_ref->test3( exporting param1 = 15 receiving result = result ) ##NUMBER_OK. - class_ref->test3( EXPORTING param1 = 15 RECEIVING result = result EXCEPTIONS error1 = 1 error2 = 2 ) ##SUBRC_OK ##NUMBER_OK. + class_ref->test3( exporting param1 = 15 receiving result = result exceptions error1 = 1 error2 = 2 ) ##SUBRC_OK ##NUMBER_OK. - class_ref->test1( EXPORTING param1 = class_ref->test3( EXPORTING param1 = 3 ) RECEIVING result = result ). + class_ref->test1( exporting param1 = class_ref->test3( exporting param1 = 3 ) receiving result = result ). class_ref->test7( "#EC OPTL_EXP - EXPORTING + exporting param1 = 5 - IMPORTING - param2 = DATA(testnumber1) ##NEEDED - RECEIVING - result = DATA(testnumber2) ) ##NEEDED. "#EC RECEIVING_USAGE + importing + param2 = data(testnumber1) ##NEEDED + receiving + result = data(testnumber2) ) ##NEEDED. "#EC RECEIVING_USAGE - ENDMETHOD. + endmethod. - METHOD test_text_assembly. - DATA class_ref TYPE REF TO lcl_test ##NEEDED. - DATA text1 TYPE string. + method test_text_assembly. + data class_ref type ref to lcl_test ##NEEDED. + data text1 type string. text1 = 'ab' && text1 && abap_true. text1 = class_ref->test5( param1 = 'a' param2 = 'b' ) && 'end'. @@ -369,15 +369,15 @@ CLASS /cc4a/test_modern_language IMPLEMENTATION. ',{}' && ']'. - DATA itab TYPE STANDARD TABLE OF /cc4a/db_test1. + data itab type standard table of /cc4a/db_test1. bla = itab[ 1 ]-object && 'a'. bla = 'a' && itab[ 1 ]-obj_name. - text1 = text1 && COND #( WHEN itab IS INITIAL THEN 'a' ELSE 'b' ). + text1 = text1 && cond #( when itab is initial then 'a' else 'b' ). text1 = `\` && text1 && `-`. bla = 'a' && 'b'. "#EC TEXT_ASSEMBLY text1 = 'abc' && new lcl_test( param1 = 4 param2 = 5 )->test5( param1 = 'bla' param2 = 'blub' ). - ENDMETHOD. -ENDCLASS. + endmethod. +endclass. diff --git a/src/test_objects/#cc4a#test_modern_language.clas.locals_imp.abap b/src/test_objects/#cc4a#test_modern_language.clas.locals_imp.abap index 5a4af1b..77025fe 100644 --- a/src/test_objects/#cc4a#test_modern_language.clas.locals_imp.abap +++ b/src/test_objects/#cc4a#test_modern_language.clas.locals_imp.abap @@ -1,7 +1,3 @@ -*"* use this source file for the definition and implementation of -*"* local helper classes, interface definitions and type -*"* declarations - CLASS lcx_error DEFINITION FINAL INHERITING FROM cx_static_check. ENDCLASS. @@ -34,9 +30,9 @@ CLASS lcl_test DEFINITION FINAL. IMPORTING param1 TYPE string param2 TYPE string RETURNING VALUE(result) TYPE string. - METHODS test6 - IMPORTING param TYPE string - RETURNING VALUE(result) TYPE string. + methods test6 + importing param type string + returning value(result) type string. METHODS test7 IMPORTING param1 TYPE i EXPORTING param2 TYPE i