Sunday, April 15, 2018

Explore program source code including called repository classes


Intro

Some years ago I wrote a tiny program exploring program source code covering also all includes. Now I did a rewrite, it is a bit OOP and it offers ability to explore also repository classes used within the report.

What it offers is obvious from input selection screen





Possible options


  • Investigate transaction or program directly
    • From transaction it takes program name and continues as with ordinary program.
    • Within program it consider the following:
      • main report
      • all includes - used also for local classes
      • all repository classes defined as:
        • REF TO something  - it is further checked for class existance
        • something=>method( ) - it considers static calls as well
        • Furthermore there is an option to check just custom namespace classes + Y/Z ones. It means classes under the same namespace as main report. Otherwise it reads all the classes including SAP ones as e.g. SALV classes etc.
  • It does the same for repository class as an input.
  • You can provide free text as an input or regular expression to be checked against line of coding.


Some examples

Possible output for "select" as a free text. You can check the below picture, the pattern exists within main program and used class as well.






Free text input "auth 02"


The result



Regex - all static class calls


The result



Regex - all number from 2 up to 8 digits


The result


Source





Source code


*&---------------------------------------------------------------------*
*& Report /namespace/REPORT_REGEX_SEARCH
*-----------------------------------------------------------------------
* Purpose:  Search ABAP source code by regex
*-----------------------------------------------------------------------
REPORT /namespace/report_regex_search MESSAGE-ID 00.

INCLUDE /namespace/report_regex_search_c01.


*******************************************************************
*   SCREENS - choose transaction or program
*******************************************************************
SELECTION-SCREEN BEGIN OF BLOCK frame1 WITH FRAME TITLE TEXT-001.
" Transaction
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERSr_trans  RADIOBUTTON GROUP grp1 USER-COMMAND flagcommand1.
SELECTION-SCREEN COMMENT 3(60TEXT-002" Transaction
SELECTION-SCREEN END OF LINE.

" Program
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERSr_prog  RADIOBUTTON GROUP grp1 DEFAULT 'X'.
SELECTION-SCREEN COMMENT 3(60TEXT-003" Program
SELECTION-SCREEN END OF LINE.

" Class
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERSr_class  RADIOBUTTON GROUP grp1.
SELECTION-SCREEN COMMENT 3(60TEXT-005" Class
SELECTION-SCREEN END OF LINE.

SELECTION-SCREEN SKIP.

PARAMETERSp_tcode TYPE tstc-tcode,                                     " Transaction Code
            p_prog  TYPE trdir-name MATCHCODE OBJECT progname,           " Program name
            p_class TYPE seoclass-clsname MATCHCODE OBJECT seoclsnamef4" Class name

SELECTION-SCREEN END OF BLOCK frame1.

SELECTION-SCREEN BEGIN OF BLOCK frame2 WITH FRAME TITLE TEXT-004.

" Free text
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERSr_text  RADIOBUTTON GROUP grp2 USER-COMMAND flagcommand2 DEFAULT 'X'.
SELECTION-SCREEN COMMENT 3(60TEXT-006" Free text switch
SELECTION-SCREEN END OF LINE.

" Regular expresson
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERSr_regul RADIOBUTTON GROUP grp2.
SELECTION-SCREEN COMMENT 3(60TEXT-007" Regular expression switch
SELECTION-SCREEN END OF LINE.

SELECTION-SCREEN SKIP.

" Inputs as e.g.:
*    '^.+(\d{4}).+$'. " all four digits values in coding
*    `^[^\*].+(')(\d{4})(').+$`. " all uncommented lines
*    `^[\*].+(')(\d{4})(').+$`. " all commented lines starting with *
*    `^.+(\BTRY\B).+$`. " get TRY statement lines, here case insensitive
PARAMETERS p_patern  TYPE LENGTH 100 LOWER CASE" Pattern to be found
PARAMETERS p_own_cl  AS CHECKBOX DEFAULT 'X'" Process only own namespace classes + Y/Z ones

SELECTION-SCREEN END OF BLOCK frame2.


*******************************************************************
AT SELECTION-SCREEN OUTPUT " PBO action (hide/show)
*******************************************************************
  LOOP AT SCREEN" Hiding

    IF r_prog NE 'X' AND screen-name CS 'p_prog' ).
      screen-active 0.
      MODIFY SCREEN.
      CONTINUE.
    ENDIF.

    IF r_trans NE 'X' AND screen-name CS 'p_tcode' ).
      screen-active 0.
      MODIFY SCREEN.
      CONTINUE.
    ENDIF.

    IF r_class NE 'X' AND screen-name CS 'p_class' ).
      screen-active 0.
      MODIFY SCREEN.
      CONTINUE.
    ENDIF.

    IF r_trans NE 'X' AND r_prog NE 'X' AND  screen-name CS 'p_own_cl' ).
      screen-active 0.
      MODIFY SCREEN.
      CONTINUE.
    ENDIF.

  ENDLOOP.


*******************************************************************
AT SELECTION-SCREEN" PAI check
*******************************************************************

* Get program name out of transaction
  IF sy-ucomm EQ 'ONLI'" Check done only after pressing of submit button
    IF r_trans EQ 'X'.
      " Check transaction existance
      CONDENSE p_tcode NO-GAPS.
      CLEAR p_prog.
      SELECT SINGLE pgmna
      FROM tstc
      INTO p_prog
      WHERE tcode p_tcode.
      IF sy-subrc NE 0.
        MESSAGE e001 WITH 'Transaction does not exist : ' p_tcode.
      ENDIF.
    ELSEIF r_prog EQ 'X'.
      " Check program existance
      SELECT SINGLE name
      FROM trdir
      INTO p_prog
      WHERE name p_prog.
      IF sy-subrc NE 0.
        MESSAGE e001 WITH 'Program does not exist : ' p_prog.
      ENDIF.
    ELSEIF r_class EQ 'X'.
      CONDENSE p_class NO-GAPS.
      IF p_class IS INITIAL.
        MESSAGE e001 WITH 'There is no repository class to be processed.'.
      ENDIF.
      " Check class existance
      SELECT SINGLE clsname
      FROM seoclass
      INTO p_class
      WHERE clsname p_class.
      IF sy-subrc NE 0.
        MESSAGE e001 WITH 'Repository class does not exist : ' p_class.
      ENDIF.
    ENDIF.
  ENDIF.


*******************************************************************
START-OF-SELECTION.
*******************************************************************

  DATAgv_code_src  TYPE LENGTH 1" P - program, C - class

  IF r_trans EQ abap_true OR r_prog EQ abap_true ).
    gv_code_src 'P'" = Program
  ELSE.
    gv_code_src 'C'" = Class
*  else 'F' = function module - possibly in future etc.
  ENDIF.

  lcl_main_regex=>self->run(
    iv_code_src   gv_code_src " P - program, C - class
    iv_regex_src  r_regul     " String or Regular expression
    iv_pattern    p_patern    " Searched pattern
    iv_prog       p_prog      " Program name
    iv_class      p_class     " Repository class name
    iv_own_cl     p_own_cl    " Explore/process only classes from custom namespace (takem from program name) or Z/Y classes
  ).




*&---------------------------------------------------------------------*
*&  Include           /namespace/REPORT_REGEX_SEARCH_C01
*&---------------------------------------------------------------------*

CLASS lcl_main_regex DEFINITION CREATE PRIVATE FINAL.

  PUBLIC SECTION.

    CLASS-DATA
      self TYPE REF TO lcl_main_regex.

    CLASS-METHODS
      class_constructor.

    METHODS
      run
        IMPORTING
          iv_code_src  TYPE char1
          iv_regex_src TYPE abap_bool
          iv_pattern   TYPE clike
          iv_prog      TYPE progname
          iv_class     TYPE seoclsname
          iv_own_cl    TYPE flag.

  PRIVATE SECTION.

    TYPES:
      BEGIN OF ts_include,
        prgname TYPE progname,
      END OF ts_include,
      BEGIN OF ts_code_line,
        src_type TYPE string,
        src_name TYPE string,
        line_num TYPE i,
        src_code TYPE string,
      END OF ts_code_line,
      tt_include       TYPE STANDARD TABLE OF ts_include,
      tt_code_textpool TYPE TABLE OF textpool,
      tt_code_str      TYPE STANDARD TABLE OF string" Note: edpline (char72) is short for some cases


    CONSTANTS:
      " Get possible class from data declaration
      cv_class_ref        TYPE string VALUE '^.{0,}\s+[Rr][Ee][Ff][[:space:]]{1,}[Tt][Oo]\s+(\S*[^,\.\s]).+$',
      " Get class out of static method call
      cv_class_static     TYPE string VALUE '^.{0,}(\S*)(=>).+$',
      " Get class/program prefix - custom namespace
      cv_namespace_prefix TYPE string VALUE '^.{0,}[/](\S*)[/].+$'.

    DATA:
      v_total_line_num   TYPE i,
      v_found_flag       TYPE abap_bool,
      t_regex_class      TYPE STANDARD TABLE OF string,
      t_clsname          TYPE STANDARD TABLE OF string,
      t_target_code_line TYPE STANDARD TABLE OF ts_code_line,
      o_ref              TYPE REF TO cx_root.

    METHODS:
      convert_code_edpline
        IMPORTING it_code TYPE seop_source
        EXPORTING et_code TYPE tt_code_str,
      convert_code_textpool
        IMPORTING it_code TYPE tt_code_textpool
        EXPORTING et_code TYPE tt_code_str,
      create_regex
        IMPORTING iv_pattern      TYPE clike
        RETURNING VALUE(rv_regexTYPE string,
      check_class_exist
        IMPORTING iv_class        TYPE string
                  iv_own_cl       TYPE flag
                  iv_prog         TYPE progname
        RETURNING VALUE(rv_existTYPE abap_bool,
      process_class_includes
        IMPORTING
          iv_class TYPE string
          iv_regex TYPE clike,
      get_process_class_source
        IMPORTING
          iv_regex   TYPE clike
          iv_class   TYPE seoclskey
          iv_inctype TYPE  c,
      get_program_includes
        IMPORTING iv_prog    TYPE prgname
        EXPORTING et_include TYPE tt_include,
      process_program
        IMPORTING
          iv_prog   TYPE progname
          iv_regex  TYPE string
          iv_own_cl TYPE flag,
      process_class
        IMPORTING
          iv_class TYPE seoclsname
          iv_regex TYPE string,
      process_program_includes
        IMPORTING
          iv_prog    TYPE progname
          iv_regex   TYPE clike
          it_include TYPE tt_include,
      process_lines
        IMPORTING
          iv_regex           TYPE clike
          iv_src_type        TYPE clike
          iv_src_name        TYPE clike
          it_src_code        TYPE tt_code_str
          iv_colect_subclass TYPE abap_bool,
      process_final_alv,
      regex_classname
        IMPORTING
          iv_code_line TYPE string,
      regex_target_string
        IMPORTING
          iv_regex     TYPE clike
          iv_src_type  TYPE clike
          iv_src_name  TYPE clike
          iv_line_num  TYPE i
          iv_code_line TYPE string.

ENDCLASS.                    "lcl_main_regex DEFINITION

CLASS lcl_main_regex IMPLEMENTATION.

  METHOD class_constructor.

    CREATE OBJECT self.

    APPEND cv_class_ref TO self->t_regex_class.
    APPEND cv_class_static TO self->t_regex_class.

  ENDMETHOD.                    "class_constructor

  METHOD run.

    DATA lv_regex TYPE string.

    IF iv_regex_src EQ abap_true.
      lv_regex iv_pattern" Regular expression
    ELSE.
      lv_regex create_regexiv_pattern iv_pattern )" Free string
    ENDIF.

    IF iv_code_src 'P'" = Program
      process_program(
        iv_prog   iv_prog
        iv_regex  lv_regex
        iv_own_cl iv_own_cl
      ).
    ELSEIF iv_code_src 'C'" = Class
      process_class(
        iv_class iv_class
        iv_regex lv_regex
      ).
    ENDIF.

  ENDMETHOD.                    "run

  METHOD convert_code_edpline.

    DATA lv_code TYPE string.

    CLEAR et_code[].

    FIELD-SYMBOLS <f_code> LIKE LINE OF it_code.

    LOOP AT it_code ASSIGNING <f_code>.
      CLEAR lv_code.
      lv_code <f_code>" edpline to string
      APPEND lv_code TO et_code.
    ENDLOOP.

  ENDMETHOD.

  METHOD convert_code_textpool.

    DATA lv_code TYPE string.

    CLEAR et_code[].

    FIELD-SYMBOLS <f_code> LIKE LINE OF it_code.

    LOOP AT it_code ASSIGNING <f_code>.
      CLEAR lv_code.
      lv_code <f_code>-entry.
      APPEND lv_code TO et_code.
    ENDLOOP.

  ENDMETHOD.

  METHOD create_regex.

    DATA:
      lt_line    TYPE STANDARD TABLE OF string,
      lv_pattern TYPE string.

    lv_pattern iv_pattern.
    CONDENSE lv_pattern.
    SPLIT lv_pattern AT space INTO TABLE lt_line.

    rv_regex '^'.

    FIELD-SYMBOLS<f_line> LIKE LINE OF lt_line.
    LOOP AT lt_line ASSIGNING <f_line>.

      " Escape stars: e.g for searchings like: "SELECT *"
      IF <f_line> EQ '*'.
        <f_line> '\*'.
      ENDIF.

      CONCATENATE rv_regex '.{0,}(' <f_line> '){1,}' INTO rv_regex.
    ENDLOOP.

    CONCATENATE rv_regex '.{0,}$' INTO rv_regex.

  ENDMETHOD.

  METHOD check_class_exist.

    DATA:
      lv_class      TYPE seoclsname,
      lv_prefix_cl  TYPE string,
      lv_prefix_prg TYPE string.

    rv_exist abap_false.
    lv_class iv_class.
    TRANSLATE lv_class TO UPPER CASE.

    " Check class custom/own namespace
    IF iv_own_cl EQ abap_true.

      CLEAR lv_prefix_cl.
      FIND REGEX cv_namespace_prefix
      IN iv_class IGNORING CASE
      SUBMATCHES lv_prefix_cl.
      CONDENSE lv_prefix_cl.

      CLEAR lv_prefix_prg.
      FIND REGEX cv_namespace_prefix
      IN iv_prog IGNORING CASE
      SUBMATCHES lv_prefix_prg.
      CONDENSE lv_prefix_prg.

      TRANSLATE lv_prefix_prg  TO UPPER CASE.
      TRANSLATE lv_prefix_cl   TO UPPER CASE.

      IF lv_prefix_prg IS NOT INITIAL AND lv_prefix_cl IS NOT INITIAL )
         AND lv_prefix_prg NE lv_prefix_cl ).
        RETURN.
      ENDIF.

      " Check Z/Y classes
      IF lv_prefix_cl IS INITIAL AND lv_class NP 'Z*' AND lv_class NP 'Y*' ).
        RETURN.
      ENDIF.

    ENDIF.

    " Check class existence in database
    SELECT COUNT)
      FROM seoclass
      WHERE clsname lv_class.
    IF sy-subrc EQ 0.
      rv_exist abap_true.
    ENDIF.

  ENDMETHOD.

  METHOD process_class_includes.

    " Inspiration taken from: http://www.sapnet.ru/viewtopic.php?p=7706

    DATA:
      lv_classkey     TYPE seoclskey,
      lv_class_src    TYPE string,
      lt_text         TYPE TABLE OF textpool,
      lt_types        TYPE seoo_types_r,
      lt_include      TYPE seop_methods_w_include,
      lt_source       TYPE seop_source,
      ls_typkey       TYPE seocmpkey,
      lt_code_edp     TYPE seop_source,
      lt_code_str     TYPE tt_code_str,
      lv_include_name TYPE programm.

    FIELD-SYMBOLS:
      <fs_type>    TYPE seoo_type_r,
      <fs_include> TYPE LINE OF seop_methods_w_include.

    lv_classkey  iv_class.
    TRANSLATE lv_classkey TO UPPER CASE.

    " Get class description
    CALL FUNCTION 'SEO_CLASS_TYPEINFO_GET'
      EXPORTING
        clskey            lv_classkey
        version           seoc_version_active
        with_descriptions 'X'
      IMPORTING
        types             lt_types
      EXCEPTIONS
        not_existing      1
        is_interface      2
        model_only        3
        OTHERS            4.

    IF sy-subrc NE 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
      WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.

    " Gathering together internal type source
    LOOP AT lt_types ASSIGNING <fs_type>.

      ls_typkey-clsname <fs_type>-clsname.
      ls_typkey-cmpname <fs_type>-cmpname.

      CLEAR lt_code_edp[].
      CALL FUNCTION 'SEO_CLASS_GET_TYPE_SOURCE'
        EXPORTING
          typkey                       ls_typkey
        IMPORTING
          source                       lt_code_edp
        EXCEPTIONS
          _internal_class_not_existing 1
          not_existing                 2
          not_edited                   3
          OTHERS                       4.

      CHECK sy-subrc AND lt_code_edp[] IS NOT INITIAL.

      convert_code_edpline(
        EXPORTING it_code lt_code_edp[]
        IMPORTING et_code lt_code_str
      ).

      CLEAR lv_class_src.
      CONCATENATE <fs_type>-clsname <fs_type>-cmpname INTO lv_class_src.
      CONDENSE lv_class_src.

      process_lines(
        iv_regex    iv_regex
        iv_src_type 'CLASS_DEF:'
        iv_src_name lv_class_src
        it_src_code lt_code_str
        iv_colect_subclass abap_false
      ).
    ENDLOOP.
    FREE lt_code_str.
    FREE lt_code_edp[].

    " Extract local definitions (classes, macros)
    CALL FUNCTION 'SEO_CLASS_GET_INCLUDE_BY_NAME'
      EXPORTING
        clskey   lv_classkey
        limu     seok_limu_locals
      IMPORTING
        progname lv_include_name.

    get_process_class_source(
      iv_regex   iv_regex
      iv_class   lv_classkey
      iv_inctype lv_include_name
    ).

    get_process_class_source(
      iv_regex   iv_regex
      iv_class   lv_classkey
      iv_inctype seop_ext_class_locals_def
    ).

    get_process_class_source(
      iv_regex   iv_regex
      iv_class   lv_classkey
      iv_inctype seop_ext_class_locals_imp
    ).

    get_process_class_source(
      iv_regex   iv_regex
      iv_class   lv_classkey
      iv_inctype seop_ext_class_macros
    ).

    " Process texts
    CLEAR lv_include_name.
    CALL FUNCTION 'SEO_CLASS_GET_INCLUDE_BY_NAME'
      EXPORTING
        clskey   lv_classkey
      IMPORTING
        progname lv_include_name.

    DATA lv_lang TYPE spras.
    SELECT spras FROM t002 INTO lv_lang.
      REFRESH lt_text.
      READ TEXTPOOL lv_include_name INTO lt_text LANGUAGE lv_lang.

      CHECK sy-subrc 0.

      convert_code_textpool(
        EXPORTING it_code lt_text
        IMPORTING et_code lt_code_str
      ).

      process_lines(
        iv_regex    iv_regex
        iv_src_type 'CLASS_TEXT:'
        iv_src_name lv_classkey
        it_src_code lt_code_str
        iv_colect_subclass abap_false
      ).
    ENDSELECT.

    " Load all method includes
    CALL FUNCTION 'SEO_CLASS_GET_METHOD_INCLUDES'
      EXPORTING
        clskey                       lv_classkey
      IMPORTING
        includes                     lt_include
      EXCEPTIONS
        _internal_class_not_existing 1
        OTHERS                       2.

    IF sy-subrc NE 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
      WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.

    LOOP AT lt_include ASSIGNING <fs_include>.

      CLEAR lt_source[].
      CALL FUNCTION 'SEO_METHOD_GET_SOURCE'
        EXPORTING
          mtdkey                        <fs_include>-cpdkey
          state                         'A'
        IMPORTING
          source                        lt_source
        EXCEPTIONS
          _internal_method_not_existing 1
          _internal_class_not_existing  2
          version_not_existing          3
          inactive_new                  4
          inactive_deleted              5
          OTHERS                        6.

      CHECK sy-subrc 0.

      convert_code_edpline(
        EXPORTING it_code lt_source[]
        IMPORTING et_code lt_code_str
      ).

      process_lines(
        iv_regex    iv_regex
        iv_src_type 'CLASS_INC2:'
        iv_src_name <fs_include>-cpdkey
        it_src_code lt_code_str
        iv_colect_subclass abap_false
      ).
    ENDLOOP.

    IF sy-subrc NE 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
      WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.

  ENDMETHOD.

  METHOD get_process_class_source.

    DATA:
      lt_code_edp  TYPE seop_source,
      lt_code_str  TYPE tt_code_str,
      lv_class_src TYPE string.

    CALL FUNCTION 'SEO_CLASS_GET_INCLUDE_SOURCE'
      EXPORTING
        clskey                       iv_class
        inctype                      iv_inctype
      IMPORTING
        source                       lt_code_edp
      EXCEPTIONS
        _internal_class_not_existing 0
        not_existing                 0
        OTHERS                       0.

    convert_code_edpline(
      EXPORTING it_code lt_code_edp
      IMPORTING et_code lt_code_str
    ).

    CONCATENATE iv_class iv_inctype INTO lv_class_src.
    CONDENSE lv_class_src.

    process_lines(
      iv_regex    iv_regex
      iv_src_type 'CLASS_INC:'
      iv_src_name lv_class_src
      it_src_code lt_code_str
      iv_colect_subclass abap_false
    ).

    FREE lt_code_edp.
    FREE lt_code_str.

  ENDMETHOD.

  METHOD get_program_includes.

    " Get include list of program
    CALL FUNCTION 'GET_INCLUDETAB'
      EXPORTING
        progname iv_prog
      TABLES
        incltab  et_include.

    " Add main program itself
    APPEND iv_prog TO et_include.

  ENDMETHOD.

  METHOD process_program.

    DATA lt_include  TYPE STANDARD TABLE OF ts_include.

    CLEAR t_clsname.

    get_program_includes(
      EXPORTING iv_prog iv_prog
      IMPORTING et_include lt_include
    ).

    process_program_includes(
      iv_prog    iv_prog
      iv_regex   iv_regex
      it_include lt_include
    ).

    " Process program repository classes
    FIELD-SYMBOLS <f_class> LIKE LINE OF t_clsname.
    LOOP AT t_clsname ASSIGNING <f_class>.

      IF check_class_exist(
          iv_class <f_class>
          iv_own_cl iv_own_cl
          iv_prog iv_prog
        EQ abap_true.
        process_class_includes(
          iv_class <f_class>
          iv_regex iv_regex
        ).
      ENDIF.
    ENDLOOP.

    process_final_alv).

  ENDMETHOD.

  METHOD process_class.

    DATA lv_class TYPE string.
    lv_class iv_class.

    process_class_includes(
      iv_class lv_class
      iv_regex iv_regex
    ).

    process_final_alv).

  ENDMETHOD.

  METHOD process_program_includes.

    DATA:
      lv_srctype TYPE string,
      lt_code    TYPE tt_code_str.

    FIELD-SYMBOLS:
      <f_include> LIKE LINE OF it_include.

    " Get includes content
    LOOP AT it_include ASSIGNING <f_include>.

      " Set source type
      CLEAR lv_srctype.
      IF <f_include>-prgname EQ iv_prog.
        lv_srctype 'MAIN_PROG:'.
      ELSE.
        lv_srctype 'INCLUDE:'.
      ENDIF.

      " Load code lines
      READ REPORT <f_include>-prgname INTO lt_code.

      process_lines(
        iv_regex           iv_regex
        iv_src_type        lv_srctype
        iv_src_name        <f_include>-prgname
        it_src_code        lt_code
        iv_colect_subclass abap_true
      ).
      FREE lt_code[].
    ENDLOOP.

  ENDMETHOD.

  METHOD process_lines.

    DATA:
      lv_line_num     TYPE i.

    FIELD-SYMBOLS:
      <f_code_line>   LIKE LINE OF it_src_code.

    LOOP AT it_src_code ASSIGNING <f_code_line>.

      " Line counters
      lv_line_num lv_line_num + 1.
      v_total_line_num v_total_line_num + 1.

      " Does string match the pattern for class declaration or static usage?
      IF iv_colect_subclass EQ abap_true.
        regex_classnameiv_code_line <f_code_line> ).
      ENDIF.

      " Does string match the regex pattern?
      regex_target_string(
        iv_regex     iv_regex
        iv_src_type  iv_src_type
        iv_src_name  iv_src_name
        iv_line_num  lv_line_num
        iv_code_line <f_code_line>
      ).

    ENDLOOP" lines

  ENDMETHOD.

  METHOD process_final_alv.

    IF v_found_flag NE abap_true.
      WRITE 'Pattern WAS NOT FOUND within the source code.'.
    ELSE.

      DATA:
        lo_salv TYPE REF TO cl_salv_table,
        lo_cols TYPE REF TO cl_salv_columns,
        lo_col  TYPE REF TO cl_salv_column.

      TRY.
          CALL METHOD cl_salv_table=>factory
            EXPORTING
              list_display if_salv_c_bool_sap=>true
            IMPORTING
              r_salv_table lo_salv
            CHANGING
              t_table      t_target_code_line.
        CATCH cx_root INTO o_ref.
          WRITE:'ALV error occured : 'o_ref->get_text).
          RETURN.
      ENDTRY.

      lo_cols lo_salv->get_columns).
      lo_cols->set_optimizeif_salv_c_bool_sap=>true ).

      TRY.
          lo_col lo_cols->get_column'SRC_TYPE' ).
          lo_col->set_medium_text'Source' ).

          lo_col lo_cols->get_column'SRC_NAME' ).
          lo_col->set_medium_text'Name' ).

          lo_col lo_cols->get_column'LINE_NUM' ).
          lo_col->set_medium_text'Line' ).

          lo_col lo_cols->get_column'SRC_CODE' ).
          lo_col->set_medium_text'Coding' ).

        CATCH cx_root INTO o_ref.
          WRITE:'ALV columns error occured : 'o_ref->get_text).
          RETURN.
      ENDTRY.

      lo_salv->display).

    ENDIF.

    WRITE:/,'Total number of explored lines: ',  v_total_line_num.

  ENDMETHOD.

  METHOD regex_classname.

    DATA:
      lv_clsname         TYPE string.

    FIELD-SYMBOLS:
      <f_regex_class> LIKE LINE OF t_regex_class.

    LOOP AT t_regex_class ASSIGNING <f_regex_class>.

      CLEAR lv_clsname.

      FIND REGEX <f_regex_class>
      IN iv_code_line IGNORING CASE
      SUBMATCHES lv_clsname.

      CONDENSE lv_clsname.

      IF lv_clsname IS NOT INITIAL.
        APPEND lv_clsname TO t_clsname.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.

  METHOD regex_target_string.

    DATA:
      lo_matcher     TYPE REF TO cl_abap_matcher,
      lv_match       TYPE LENGTH 1,
      lv_regex       TYPE string,
      ls_target_line TYPE ts_code_line.

    " Input searched regex
    MOVE iv_regex TO lv_regex.

    " Does string match the regex pattern?
    lv_match abap_false.
    TRY.
        FREE lo_matcher.
        lo_matcher cl_abap_matcher=>create(
          pattern     lv_regex
          ignore_case abap_true
          text        iv_code_line
        ).
        lv_match lo_matcher->match).
      CATCH cx_root INTO o_ref.
        WRITE:'Input regex error occured : 'o_ref->get_text).
        RETURN.
    ENDTRY.
    IF lv_match EQ abap_true.
      CLEAR ls_target_line.

      ls_target_line-src_type iv_src_type.
      ls_target_line-src_name iv_src_name.
      ls_target_line-line_num iv_line_num.
      ls_target_line-src_code iv_code_line.

      CONDENSE ls_target_line-src_type.
      CONDENSE ls_target_line-src_name.

      APPEND ls_target_line TO t_target_code_line.

      v_found_flag abap_true" General flag
    ENDIF.

  ENDMETHOD.

ENDCLASS.