Skip to end of metadata
Go to start of metadata
Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
************************************************************************
* ZBI_ABAP_ROUTINES_ANALYZE
* BI: Analyze ABAP Routines
*
* (c) SAP AG 2005                                    MFB, SAP Labs, LLC
* created:     2005-08-30
* last update: 2008-08-13
************************************************************************
* Selection texts:
* P_ANAL    Highlight ABAP Coding
* P_DISP    Display ABAP Coding
* P_VERS_A  Current Version
* P_VERS_D  Comparison Version
* S_CODEID  ABAP code ID
************************************************************************
* This tool displays one or several ABAP routines. If two different
* object versions are selected, then a code comparison is performed.
* This way you can easily see differences for example between "Active"
* and "BI Content" version of the code.
*
* The highlight option will color critical pieces of the code:
* - CALL FUNCTION and PERFORM statements
*   (green - potential for bad performance in function or form routine)
* - SELECT and SELECT SINGLE statements
*   (yellow - potential for bad performance)
* - INSERT, UPDATE, MODIFY, DELETE statements
*   (red - potential for data inconsistency -> Use APIs!)
************************************************************************

REPORT zbi_abap_routines_analyze LINE-SIZE 255.

TYPE-POOLS: rs, rsaa, icon.

TABLES:
  rsarout,
  rsaabap,
  rsaabapinv.

SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME.
SELECT-OPTIONS:
  s_codeid FOR rsarout-codeid.
SELECTION-SCREEN END OF BLOCK b1.

SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME.
PARAMETERS:
  p_vers_a TYPE rsobjvers DEFAULT 'A',
  p_vers_d TYPE rsobjvers DEFAULT 'D',
  p_disp   AS CHECKBOX    DEFAULT 'X',
  p_anal   AS CHECKBOX    DEFAULT space.
SELECTION-SCREEN END OF BLOCK b2.

TYPES:
  BEGIN OF ys_line,
    line TYPE edpline,
  END OF ys_line,
  yt_line TYPE TABLE OF ys_line.

DATA:
  gs_codeid   TYPE rsaa_s_codeid,
  gt_codeid   TYPE rsaa_t_codeid,
  g_tabix_a   TYPE sy-tabix,
  g_tabix_d   TYPE sy-tabix,
  g_tabix_e   TYPE sy-tabix,
  g_offset_a  TYPE sy-tabix,
  g_offset_d  TYPE sy-tabix,
  g_offset    TYPE sy-tabix,
  g_line      TYPE sy-lisel,
  g_count(6)  TYPE n,
  g_diff      TYPE rs_bool.

DATA:
  gs_rout_a      TYPE rsaa_s_arout,
  gs_rout_d      TYPE rsaa_s_arout,
  gt_rout_a      TYPE rsaa_t_arout,
  gt_rout_d      TYPE rsaa_t_arout,
  gs_text_a      TYPE rsaa_s_aroutt,
  gs_text_d      TYPE rsaa_s_aroutt,
  gt_text_a      TYPE rsaa_t_aroutt,
  gt_text_d      TYPE rsaa_t_aroutt,
  gt_abap_a      TYPE rsaa_t_aabap,
  gt_abap_d      TYPE rsaa_t_aabap,
  gt_abapinv_a   TYPE rsaa_t_aabap,
  gt_abapinv_d   TYPE rsaa_t_aabap,
  gs_code_a      TYPE rsaa_s_aabap,
  gs_code_d      TYPE rsaa_s_aabap,
  gt_code_a      TYPE rsaa_t_aabap,
  gt_code_d      TYPE rsaa_t_aabap,
  gs_line_a      TYPE ys_line,
  gs_line_d      TYPE ys_line,
  gt_line_a      TYPE yt_line,
  gt_line_d      TYPE yt_line.

*----------------------------------------------------------------------
DEFINE write_version.
  case &1.
    when 'A'.
      write: icon_led_green    as icon, 'Active Version'.
    when 'D'.
      write: icon_sap          as icon, 'Content Version'.
    when 'M'.
      write: icon_led_yellow   as icon, 'Revised Version'.
    when 'N'.
      write: icon_led_inactive as icon, 'New Version'.
  endcase.
END-OF-DEFINITION.

DEFINE write_code.
  if &2-line_no is initial and
   ( &4-line_no is initial or g_diff = rs_c_false ).
    skip.
  endif.

  new-line.
  clear g_line.
  case &1.
    when 'A'.
      write: at 01 &2-line_no+2(4) color col_key,
             at 06 &2-line         color &3 intensified off.

      g_line+00(04) = &2-line_no+2(4).
      g_line+06(72) = &2-line.
    when 'D'.
      write: at 80 &4-line_no+2(4) color col_key,
             at 85 &4-line         color &5 intensified off.
    when 'AD'.
      write: at 01 &2-line_no+2(4) color col_key,
             at 06 &2-line         color &3 intensified off,
             at 80 &4-line_no+2(4) color col_key,
             at 85 &4-line         color &5 intensified off.

      g_line+00(04) = &2-line_no+2(4).
      g_line+06(72) = &2-line.
  endcase.

  if p_anal = rs_c_true and g_line+06(1) <> '*'.

*   DML statements (red)
    search g_line for 'INSERT'.
    if sy-subrc = 0.
      g_offset = sy-fdpos - 1.
      if g_line+g_offset(1) = space or g_line+g_offset(1) = '.'.
        write at sy-fdpos 'INSERT' color col_negative.
      endif.
    endif.
    search g_line for 'UPDATE'.
    if sy-subrc = 0.
      g_offset = sy-fdpos - 1.
      if g_line+g_offset(1) = space or g_line+g_offset(1) = '.'.
        write at sy-fdpos 'UPDATE' color col_negative.
      endif.
    endif.
    search g_line for 'MODIFY'.
    if sy-subrc = 0.
      g_offset = sy-fdpos - 1.
      if g_line+g_offset(1) = space or g_line+g_offset(1) = '.'.
        write at sy-fdpos 'MODIFY' color col_negative.
      endif.
    endif.
    search g_line for 'DELETE'.
    if sy-subrc = 0.
      g_offset = sy-fdpos - 1.
      if g_line+g_offset(1) = space or g_line+g_offset(1) = '.'.
        write at sy-fdpos 'DELETE' color col_negative.
      endif.
    endif.

*   Select statements (yellow)
    search g_line for 'SELECT'.
    if sy-subrc = 0.
      g_offset = sy-fdpos - 1.
      if g_line+g_offset(1) = space or g_line+g_offset(1) = '.'.
        write at sy-fdpos 'SELECT' color col_negative.
      endif.
    endif.
    search g_line for 'SELECT SINGLE'.
    if sy-subrc = 0.
      write at sy-fdpos 'SELECT SINGLE' color col_total.
    endif.

*   External calls (green)
    search g_line for 'CALL FUNCTION'.
    if sy-subrc = 0.
      write at sy-fdpos 'CALL FUNCTION' color col_positive.
    endif.
    search g_line for 'PERFORM'.
    if sy-subrc = 0.
      g_offset = sy-fdpos - 1.
      if g_line+g_offset(1) = space or g_line+g_offset(1) = '.'.
        write at sy-fdpos 'PERFORM' color col_positive.
      endif.
    endif.

  endif.
END-OF-DEFINITION.

*----------------------------------------------------------------------
INITIALIZATION.

  IF p_anal = rs_c_true.
    p_disp = rs_c_true.
    p_vers_d = p_vers_a.
  ENDIF.

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

* Read routines
  REFRESH gt_codeid.
  SELECT * FROM rsarout
    WHERE codeid IN s_codeid AND objvers = p_vers_a.
    CLEAR gs_codeid.
    gs_codeid-sign   = 'I'.
    gs_codeid-option = 'EQ'.
    gs_codeid-low    = rsarout-codeid.
    COLLECT gs_codeid INTO gt_codeid.
  ENDSELECT.

  PERFORM analyze_routines
    USING gt_codeid p_vers_a p_vers_d p_disp p_anal 0 'X'.

*&--------------------------------------------------------------------*
*&      Form  analyze_routine
*&--------------------------------------------------------------------*
FORM analyze_routine
  USING
    p_codeid  TYPE rscodeid
    p_vers_a  TYPE rsobjvers
    p_vers_d  TYPE rsobjvers
    p_disp    TYPE c
    p_anal    TYPE c
    p_indent  TYPE i
    p_text    TYPE c.

  REFRESH gt_codeid.
  CLEAR gs_codeid.
  gs_codeid-sign   = 'I'.
  gs_codeid-option = 'EQ'.
  gs_codeid-low    = p_codeid.
  COLLECT gs_codeid INTO gt_codeid.

  PERFORM analyze_routines
    USING gt_codeid p_vers_a p_vers_d p_disp p_anal p_indent p_text.

ENDFORM.                    "analyze_routine
*&--------------------------------------------------------------------*
*&      Form  analyze_routine
*&--------------------------------------------------------------------*
FORM analyze_routines
  USING
    pt_codeid TYPE rsaa_t_codeid
    p_vers_a  TYPE rsobjvers
    p_vers_d  TYPE rsobjvers
    p_disp    TYPE c
    p_anal    TYPE c
    p_indent  TYPE i
    p_text    TYPE c.

  REFRESH: gt_rout_a, gt_rout_d, gt_abap_a, gt_abap_d.
  REFRESH: gt_abapinv_a, gt_abapinv_d, gt_text_a, gt_text_d.

  CALL FUNCTION 'RSAA_ROUTINE_MULTI_GET'
    EXPORTING
      i_objvers              = p_vers_a
      i_t_codeid             = pt_codeid
      i_all_languages        = rs_c_false
    IMPORTING
      e_t_arout              = gt_rout_a
      e_t_aabap              = gt_abap_a
      e_t_aabapinv           = gt_abapinv_a
      e_t_aroutt             = gt_text_a
    EXCEPTIONS
      no_code_present        = 1
      wrong_import_parameter = 2
      OTHERS                 = 3.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    EXIT.
  ENDIF.

  CALL FUNCTION 'RSAA_ROUTINE_MULTI_GET'
    EXPORTING
      i_objvers              = p_vers_d
      i_t_codeid             = pt_codeid
      i_all_languages        = rs_c_false
    IMPORTING
      e_t_arout              = gt_rout_d
      e_t_aabap              = gt_abap_d
      e_t_aabapinv           = gt_abapinv_d
      e_t_aroutt             = gt_text_d
    EXCEPTIONS
      no_code_present        = 1
      wrong_import_parameter = 2
      OTHERS                 = 3.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    EXIT.
  ENDIF.

* Process routines
  LOOP AT gt_rout_a INTO gs_rout_a.

    g_count = sy-tabix.

*   Header
    CLEAR gs_text_a.
    READ TABLE gt_text_a INTO gs_text_a WITH KEY
      langu   = sy-langu
      codeid  = gs_rout_a-codeid
      objvers = p_vers_a.

    IF p_text = 'X'.
      FORMAT COLOR COL_NORMAL INTENSIFIED ON.
      WRITE: AT /p_indent icon_abap AS ICON, 'ABAP Routine:'.
      IF gs_text_a-txtlg IS INITIAL.
        WRITE: AT 40 'Global Data Definition', AT 99 space.
      ELSE.
        WRITE: AT 40 gs_text_a-txtlg.
      ENDIF.
      SKIP.
    ENDIF.

    FORMAT COLOR OFF.
    WRITE: AT /p_indent 'Code Type:'.
    CASE gs_rout_a-codetp.
      WHEN 'TR'.
        WRITE: AT 40 'Transfer Rule'.
      WHEN 'UR'.
        WRITE: AT 40 'Update Rule'.
      WHEN 'TC'.
        WRITE: AT 40 'Time Conversion'.
      WHEN 'IC'.
        WRITE: AT 40 'InfoObject Conversion'.
      WHEN 'GR'.
        WRITE: AT 40 'Global Routine'.
      WHEN 'S1'.
        WRITE: AT 40 'Deletion Routine'.
      WHEN 'TF'.
        WRITE: AT 40 'Transformation'.
      WHEN space.
        WRITE: AT 40 'Formula Routine (generated)'.
      WHEN OTHERS.
        WRITE: AT 40 'Unknown Type of Routine'.
    ENDCASE.

    WRITE: AT /p_indent 'Code ID:', AT 40 gs_rout_a-codeid.
    WRITE: AT /p_indent 'Version Comparison:', AT 38 space.

*   Get coding
    PERFORM get_code
      USING
         gs_rout_a-codeid
         gs_rout_a-codetp
         gt_abap_a
         gt_abapinv_a
      CHANGING
         gt_code_a
         gt_line_a.

*   Compare coding
    CLEAR g_diff.

    READ TABLE gt_rout_d INTO gs_rout_d
      WITH KEY codeid  = gs_rout_a-codeid.
    IF sy-subrc = 0.
      PERFORM get_code
        USING
           gs_rout_d-codeid
           gs_rout_d-codetp
           gt_abap_d
           gt_abapinv_d
        CHANGING
           gt_code_d
           gt_line_d.

      IF gt_line_a[] = gt_line_d[].
        write_version p_vers_a.
        WRITE: icon_equal AS ICON.
        write_version p_vers_d.
      ELSE.
        write_version p_vers_a.
        WRITE: icon_not_equal_red AS ICON.
        write_version p_vers_d.

        g_diff = rs_c_true.
      ENDIF.
    ELSE.
      write_version p_vers_a.
      WRITE: '(No Content Version)'.
    ENDIF.

*   Display coding
    IF p_disp = rs_c_true.

      IF g_diff = rs_c_false.
        SKIP.
        FORMAT COLOR OFF.
        NEW-LINE.
        write_version p_vers_a.
        SKIP.

        LOOP AT gt_code_a INTO gs_code_a.
          write_code 'A' gs_code_a 2 gs_code_d 1.
        ENDLOOP.
      ELSE.
        SKIP.
        FORMAT COLOR OFF.
        NEW-LINE.
        write_version p_vers_a.
        WRITE: AT 79 space.
        write_version p_vers_d.
        SKIP.

        g_offset_a = 0.
        g_offset_d = 0.
        LOOP AT gt_code_a INTO gs_code_a.

          g_tabix_a = sy-tabix.
          g_tabix_d = g_tabix_a + g_offset_d.

          READ TABLE gt_code_d INTO gs_code_d INDEX g_tabix_d.
          IF sy-subrc = 0 AND g_offset_a = 0.
            gs_line_a = gs_code_a-line.
            TRANSLATE gs_line_a TO UPPER CASE.
            CONDENSE gs_line_a.

            gs_line_d = gs_code_d-line.
            TRANSLATE gs_line_d TO UPPER CASE.
            CONDENSE gs_line_d.

            IF gs_line_a = gs_line_d.
*             Identical lines (A = D)
              write_code 'AD' gs_code_a 2 gs_code_d 2.
            ELSE.
              gs_line_a = gs_code_a-line.
              IF gs_line_a(1) = '*'.
                SHIFT gs_line_a LEFT.
              ENDIF.

              gs_line_d = gs_code_d-line.
              IF gs_line_d(1) = '*'.
                SHIFT gs_line_d LEFT.
              ENDIF.

*             Different lines (A <> D)
              SEARCH gt_code_d FOR gs_line_a STARTING AT g_tabix_d.
              IF sy-subrc = 0.
*               Additional lines in D
                g_tabix_e = sy-tabix.

                LOOP AT gt_code_d INTO gs_code_d
                  FROM g_tabix_d TO g_tabix_e.
                  IF sy-tabix < g_tabix_e.
                    write_code 'D' gs_code_a 1 gs_code_d 7.
                  ELSE.
                    write_code 'AD' gs_code_a 2 gs_code_d 2.
                  ENDIF.
                ENDLOOP.

                g_offset_d = ( g_tabix_e - g_tabix_a ).
              ELSE.
                SEARCH gt_code_a FOR gs_line_d STARTING AT g_tabix_a.
                IF sy-subrc = 0.
*                 Additional lines in A
                  g_tabix_e = sy-tabix.

                  write_code 'A' gs_code_a 7 gs_code_d 1.

                  g_offset_a = ( g_tabix_e - g_tabix_a ) - 1.

                  g_offset_d = ( g_tabix_d - g_tabix_e ).
                ELSE.
                  write_code 'AD' gs_code_a 2 gs_code_d 7.
                ENDIF.

              ENDIF.

            ENDIF.

          ELSE.
*           Additional lines in A
            IF g_offset_a > 0.
              g_offset_a = g_offset_a - 1.
            ENDIF.

            write_code 'A' gs_code_a 7 gs_code_d 1.
          ENDIF.

        ENDLOOP.

*       Additional lines in D
        g_tabix_d = g_tabix_d + 1.

        LOOP AT gt_code_d INTO gs_code_d FROM g_tabix_d.
          write_code 'D' gs_code_a 1 gs_code_d 7.
        ENDLOOP.

      ENDIF.

    ENDIF.

    SKIP.

  ENDLOOP.                  "next routine

  IF sy-subrc <> 0.
    SKIP.
    FORMAT COLOR OFF.
    WRITE: AT /p_indent 'No routine found.'.
    SKIP.
  ENDIF.

ENDFORM.                    "analyze_routine

*&--------------------------------------------------------------------*
*&      Form  get_code
*&--------------------------------------------------------------------*
FORM get_code
  USING
    i_codeid   TYPE rscodeid
    i_codetp   TYPE rscodetp
    it_abap    TYPE rsaa_t_aabap
    it_abapinv TYPE rsaa_t_aabap
  CHANGING
    et_code    TYPE rsaa_t_aabap
    et_line    TYPE yt_line.

  DATA:
    ls_code  TYPE rsaa_s_aabap,
    ls_line  TYPE ys_line,
    l_trules TYPE rs_bool.

  REFRESH et_code.
  LOOP AT it_abap INTO ls_code WHERE codeid = i_codeid.
    APPEND ls_code TO et_code.
  ENDLOOP.

  READ TABLE it_abapinv TRANSPORTING NO FIELDS
    WITH KEY codeid = i_codeid.
  IF sy-subrc = 0.
    CLEAR ls_code.
    ls_code-line_no = '000000'.
    ls_code-line    = '* Inverse Routine:'.
    APPEND ls_code TO et_code.

    LOOP AT it_abapinv INTO ls_code WHERE codeid = i_codeid.
      APPEND ls_code TO et_code.
    ENDLOOP.
  ENDIF.

  IF i_codetp = 'TR'.
    l_trules = rs_c_true.
  ELSE.
    l_trules = rs_c_false.
  ENDIF.

  CALL FUNCTION 'RSAA_TRANSLATE_VARS_IN_ABAP'
    EXPORTING
      i_translate_back = rs_c_false
      i_for_transrules = l_trules
    CHANGING
      c_t_aabap        = et_code.

  REFRESH et_line.
  LOOP AT et_code INTO ls_code.
    ls_line = ls_code-line.
    TRANSLATE ls_line TO UPPER CASE.
    CONDENSE ls_line.
    IF NOT ls_line IS INITIAL.
      APPEND ls_line TO et_line.
    ENDIF.
  ENDLOOP.

ENDFORM.                    "get_code