Skip to Content
Technical Articles
Author's profile photo Somnath Paul

ABAP CDS View Where used List – A simple utility

Hello,

Introduction:

CDS doesn’t need any introduction so let’s get to the core of the topic for which I am writing this blog post.

I was investigating on certain CDS annotations and I was missing something called “where used” option for CDS, this is a feature which we ABAPers use almost every day! But when comes to this CDS, no such option I could find. If you are using DDIC view instead of DDLS Entity then probably you can, but that is NOT the right approach and with “define view entity” syntax you wouldn’t get any DDIC view generated, right?

updates: This “where used” feature is available from S4 onwards, which I missed to add before.

So let’s build it, the good point is SAP keeps everything in some table at the end. The utility can search:

  1. Any programs which might be using the CDS you have entered as an input
  2. Any parent CDS (VDM) which is using the input CDS

Disclaimer: The coding may have bugs and have ample scopes of improvement, so feel free to get this tuned / tailored, the way you want. 

 

REPORT zcds_utility.

TYPES:BEGIN OF ty_ddls_w,
        ddls     TYPE ddlname,
        o_type   TYPE trobjtype,
        obj_name TYPE progname,
      END OF ty_ddls_w,

      BEGIN OF ty_funcm,
        funcname TYPE rs38l_fnam,
        pname    TYPE pname,
      END OF ty_funcm,

      ty_ddls_t  TYPE STANDARD TABLE OF ty_ddls_w WITH EMPTY KEY,
      ty_funcm_t TYPE STANDARD TABLE OF ty_funcm WITH EMPTY KEY.

DATA:w_ddls_f TYPE string,
     t_ddls_w TYPE ty_ddls_t,
     t_func   TYPE ty_funcm_t.

SELECTION-SCREEN: BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.

SELECTION-SCREEN SKIP 1.

SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS:p_rad1 RADIOBUTTON GROUP rb1.
SELECTION-SCREEN COMMENT 5(20) comment1.
PARAMETERS: p_ddls1  TYPE ddlname.
SELECTION-SCREEN END OF LINE.

SELECTION-SCREEN SKIP 1.

SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS:p_rad2 RADIOBUTTON GROUP rb1.
SELECTION-SCREEN COMMENT 5(20) comment2.
PARAMETERS: p_ddls2  TYPE ddlname.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN:END OF BLOCK b1.

AT SELECTION-SCREEN OUTPUT.

  comment1 = 'CDS Where Used:'.
  comment2 = 'CDS Components:'.

CLASS lcl_event_handler DEFINITION.

  PUBLIC SECTION.

    TYPES:BEGIN OF lty_source_code,
            src_cd TYPE char1000_idoc,
          END OF lty_source_code.

    DATA:
      lo_alv TYPE REF TO cl_salv_table,
      lt_alv TYPE ty_ddls_t.


    METHODS constructor
      IMPORTING
        i_alv TYPE REF TO cl_salv_table.

    METHODS on_double_click
      FOR EVENT if_salv_events_actions_table~double_click
                OF cl_salv_events_table
      IMPORTING row column.

ENDCLASS.

CLASS lcl_event_handler IMPLEMENTATION.

  METHOD constructor.
    lo_alv = i_alv.
  ENDMETHOD.

  METHOD on_double_click.

    DATA: lt_source_cd TYPE STANDARD TABLE OF lty_source_code,
          l_obj_name   TYPE progname,
          l_type       TYPE trobjtype,
          l_ddls       TYPE ddlname.

    CHECK column = 'OBJ_NAME'.

    l_obj_name = lt_alv[ row ]-obj_name.
    l_type = lt_alv[ row ]-o_type.
    l_ddls = lt_alv[ row ]-ddls.

    CASE l_type.

      WHEN 'DDLS'.

        TRY.
            cl_dd_ddl_handler_factory=>create( )->read(
                  EXPORTING
                    name         = CONV ddlname( to_upper( l_obj_name ) )
                  IMPORTING
                    ddddlsrcv_wa = DATA(ddlsrcv_wa) ).
          CATCH cx_dd_ddl_read INTO DATA(exc).
            cl_demo_output=>display( exc->get_text( ) ).
        ENDTRY.
        IF ddlsrcv_wa-source IS INITIAL.
          cl_demo_output=>display( |Nothing found| ).
          RETURN.
        ENDIF.

        cl_demo_output=>display( replace( val = ddlsrcv_wa-source
                                          sub = |\n|
                                          with = ``
                                          occ = 0 ) ).

      WHEN OTHERS.

*---get the source code (other then DDLS)
        READ REPORT l_obj_name  INTO lt_source_cd.
        IF sy-subrc EQ 0.

          DATA(l_source_code) = REDUCE string( INIT lv_src TYPE string
*---Don't consider ANY commented code
                                        FOR lw_source IN lt_source_cd
                                    INDEX INTO lv_index
                                      WHERE ( table_line+0(1) NE '*' )
                              NEXT lv_src = to_upper( lv_src ) &&
                              space && to_upper( lw_source-src_cd )  && | LINE#: { lv_index }#|   ).

          CLEAR lt_source_cd.

          DATA(l_search_pattern) = `(?:LINE#: (\d)+)(?=#[\w\s]+` && |{  l_ddls  }| && `)`.
          DATA(lv_result) = match(  val = l_source_code
                                               regex = l_search_pattern
                                               case = abap_false    ).
          IF lv_result IS NOT INITIAL.
            DATA(lv_line) = match(
                                     val = lv_result
                                    regex = `(?:LINE#:\s)([0-9]+)`
                                    case = abap_false
                                     ).
            SPLIT lv_line AT ':' INTO DATA(l_part1) DATA(l_part2).
            CONDENSE l_part2 NO-GAPS.


          ELSE.
            MESSAGE |Object: { l_ddls }, has no direct usage| TYPE 'S'.
          ENDIF.

        ENDIF.
        CALL FUNCTION 'RS_TOOL_ACCESS'
          EXPORTING
            operation           = 'SHOW'
            object_name         = l_obj_name
            object_type         = l_type
            position            = COND char10( WHEN l_part2 = 0 THEN space ELSE ( l_part2 + 1 ) )
          EXCEPTIONS
            not_executed        = 1
            invalid_object_type = 2
            OTHERS              = 3.
        IF sy-subrc <> 0.
* Implement suitable error handling here
        ENDIF.
    ENDCASE.
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

  CASE abap_true.

    WHEN p_rad1.

      IF p_ddls1 IS INITIAL.
        MESSAGE 'Enter a CDS View to proceed!' TYPE 'S'.
        LEAVE LIST-PROCESSING.
      ENDIF.

      w_ddls_f = '\TY:' && p_ddls1.

*---Find parent DDLS (if any)
      SELECT * FROM ddls_ris_index
      INTO TABLE @DATA(t_ddls_where_used)
      WHERE used_artifact_fullname = @w_ddls_f.
      IF sy-subrc EQ 0.
        LOOP AT t_ddls_where_used REFERENCE INTO DATA(lo_ddls).
          APPEND INITIAL LINE TO t_ddls_w REFERENCE INTO DATA(lo_ddls_wu).
          SPLIT lo_ddls->used_artifact_fullname AT ':' INTO DATA(w_part1) DATA(w_part2).

          lo_ddls_wu->ddls = w_part2.
          lo_ddls_wu->o_type = 'DDLS'.
          lo_ddls_wu->obj_name = lo_ddls->ddlsrc_name.
        ENDLOOP.
      ENDIF.

*----find all other ABAP Objects where input DDLS been used
      SELECT name,
             include,
             CASE repo~subc

             WHEN '1' THEN 'REPS'
             WHEN 'K' THEN 'CLAS'
             WHEN 'I' THEN 'INCL'
             WHEN 'F' THEN 'FUGR'
             ELSE 'UN'
             END  AS o_type

          FROM wbcrossgt AS wb
          LEFT OUTER JOIN reposrc AS repo
          ON wb~include = repo~progname
      INTO TABLE @DATA(lt_wbcrossgt)
      WHERE otype = 'TY'
      AND name = @p_ddls1
      AND indirect = @space.
      IF sy-subrc EQ 0.
        SORT lt_wbcrossgt BY name include o_type.

*---Check for Function Modules
        LOOP AT lt_wbcrossgt REFERENCE INTO DATA(lo_wbcross) WHERE o_type = 'UN'.
          APPEND INITIAL LINE TO t_func REFERENCE INTO DATA(lo_func).
          lo_func->funcname = lo_wbcross->include.
        ENDLOOP.

        IF t_func IS NOT INITIAL.
          SELECT  funcname,
                  pname
            FROM tfdir INTO TABLE @DATA(t_tfdir)
            FOR ALL ENTRIES IN @t_func
            WHERE funcname = @t_func-funcname.
          IF sy-subrc EQ 0.
            SORT t_tfdir BY funcname.
          ENDIF.
        ENDIF.

        LOOP AT lt_wbcrossgt REFERENCE INTO lo_wbcross.
          APPEND INITIAL LINE TO t_ddls_w REFERENCE INTO lo_ddls_wu.

          IF lo_wbcross->o_type = 'UN' AND line_exists( t_tfdir[ funcname = lo_wbcross->include ] ).
            lo_ddls_wu->ddls = p_ddls1.
            lo_ddls_wu->o_type = 'FUNC'.
            lo_ddls_wu->obj_name = lo_wbcross->include.
          ELSE.

            lo_ddls_wu->ddls = p_ddls1.
            lo_ddls_wu->o_type = lo_wbcross->o_type.
            lo_ddls_wu->obj_name = lo_wbcross->include.
          ENDIF.

        ENDLOOP.

      ENDIF.


    WHEN p_rad2.
      MESSAGE 'This feature, not yet Supported' TYPE 'S'.
      LEAVE LIST-PROCESSING.
  ENDCASE.

  IF t_ddls_w IS NOT INITIAL.

    CALL METHOD cl_salv_table=>factory
      IMPORTING
        r_salv_table = DATA(lo_alv1)
      CHANGING
        t_table      = t_ddls_w.

    IF lo_alv1 IS BOUND.
      lo_alv1->get_functions( )->set_all( abap_true ).
      lo_alv1->get_columns( )->set_optimize( abap_true ).

      DATA(lo_evt_handler) = NEW lcl_event_handler( lo_alv1 ).
      DATA(lo_events) = lo_alv1->get_event( ).
      SET HANDLER lo_evt_handler->on_double_click FOR lo_events.

      lo_evt_handler->lt_alv = t_ddls_w.
      lo_alv1->display( ).
    ENDIF.

  ELSE.

    MESSAGE 'No records found!' TYPE 'S'.
    LEAVE LIST-PROCESSING.

  ENDIF.

Conclusion:

This utility perhaps can save some time and get you to the right piece of program / DDLS where the CDS being used. Double clicking will open the exact line of code or DDLS which you were looking for.

Please share your feedback and any issues you have encountered while using it. As I said, I didn’t test all the possible ways so good to know from you.

Thanks,

Somnath

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Sugato Biswas
      Sugato Biswas

      Hi Somnath,

      This tool is very much useful and really time saver for developers who are working on Suite on Hana. As you rightly said this feature is integrated in S4 Hana which enables us to find "where used" list of DDLS object from SE11 transaction itself.

      Regards,

      Sugato

       

      Author's profile photo Somnath Paul
      Somnath Paul
      Blog Post Author

      Thanks Sugato for the feedback, yes this feature is missing on lower ABAP release and many projects running still on ECC / Suite on HANA  where they are using ABAP CDS, can use this utility as a work around.