‎2023 Nov 06 8:58 AM
Hello,
The Check Variant of ATC/Code Inspector can be displayed and maintained, but I'd like to print its details into a PDF file, with all the details (see screenshots below).
The question is not about printing the results of Code Inspector, but only about printing the details of the checks done.
Is it possible? Did someone create a program? A SAP GUI Scripting script to share maybe?
Thanks a lot.
Sandra



‎2023 Nov 06 9:41 AM
Each time I did it manually to fit the Development rules and the checks done on the system. If you find it ...
‎2023 Nov 06 12:43 PM
I'd love to have that option as well but when I did some digging during setting up our ATC-systems, I didn't find anything to get a listing. And seeing that package S_CODE_INSPECTOR contains - among others - Cluster table for Check Variant Parameters (SCICHKV_PA) doesn't make me too hopeful that something exists or could easily be created.
Getting curious, I quickly ran ATC via SAT to see where that cluster table gets accessed to add a breakpoint at the "import from database" statement. This is how the retrieved data looks internally:

So, the selected checks for the variant are legible but their respective details and attributes not so much.
Sorry to not have better news for you!
‎2023 Nov 06 4:44 PM
Thanks frdric.girod and 8b889d0e8e6f4ed39f6c58e35664518f for your feedback. Alas, the parameters of each CI Check are compressed and can only be decoded by their corresponding CI Check class. I'll wait for good answers or do same as Frederic suggested 😉
‎2023 Nov 06 5:07 PM
This code snippet is a starting point. Not a satisfactory answer though, because it doesn't output the checks without parameters and I had an exception which forced me to debug and skip the wrong case (a parameter being an internal table, in CL_CI_TEST_EMPTY_UNUSED_PROCS). Test in ABAP 7.56.
baerbelwinkler For information.
TRY.
cl_ci_checkvariant=>get_ref(
EXPORTING
p_user = space " space for global variant
p_name = 'Z_GLOBAL_VARIANT'
RECEIVING
p_ref = DATA(variant)
EXCEPTIONS
chkv_not_exists = 1
missing_parameter = 2
broken_variant = 3
OTHERS = 4 ).
IF sy-subrc <> 0.
LEAVE PROGRAM.
ENDIF.
DATA(config) = NEW cl_ci_variant_configuration( ).
config->variant_to_xml(
EXPORTING
variant = variant
RECEIVING
xml = DATA(xml) ).
CATCH cx_root INTO DATA(error).
ASSERT 1 = 1. " debugger
ENDTRY.
The final XML:

‎2023 Nov 06 8:33 PM - edited ‎2025 Apr 19 6:16 PM
Here's a program which does a clean "print" of the details of a Code Inspector variant. It generates an intermediate XML containing the variant tests and selected attributes, convert the XML into an ABAP internal table via a Simple Transformation Z_CI_XML_TO_ITAB, and the internal table is output as a text with indented hierarchy.
*&---------------------------------------------------------------------*
*& Report z_export_variante_ci
*&---------------------------------------------------------------------*
*&
*& https://community.sap.com/t5/application-development-and-automation-discussions/print-details-of-an-atc-code-inspector-check-variant-not-the-results/td-p/12804009
*&
*&---------------------------------------------------------------------*
REPORT z_export_variante_ci LINE-SIZE 1023.
CLASS lcl_app DEFINITION DEFERRED.
PARAMETERS variname TYPE sci_chkv OBLIGATORY DEFAULT 'ZCHECK_PROGRAM'.
SELECTION-SCREEN BEGIN OF SCREEN 1001.
PARAMETERS dummy.
SELECTION-SCREEN END OF SCREEN 1001.
AT SELECTION-SCREEN OUTPUT.
CASE sy-dynnr.
WHEN '1001'.
" Use of PBO to make warning SCI144 (CL_CI_TESTS=>GET_INITIAL_TREE) displayed
" as status message to not interrupt the logic (as done in SCI).
CALL METHOD lcl_app=>('CALCULATE_VARIANT_OUTPUT').
LEAVE TO SCREEN 0.
ENDCASE.
START-OF-SELECTION.
TRY.
CALL SELECTION-SCREEN 1001.
CALL METHOD lcl_app=>('RENDER_VARIANT_OUTPUT').
ASSERT 1 = 1. " dummy statement for setting a breakpoint (if debug needed)
CATCH cx_root INTO DATA(error).
MESSAGE error TYPE 'I' DISPLAY LIKE 'E'.
ENDTRY.
CLASS lcx_system_message DEFINITION INHERITING FROM cx_no_check FINAL.
PUBLIC SECTION.
METHODS constructor.
METHODS get_text REDEFINITION.
METHODS get_longtext REDEFINITION.
PRIVATE SECTION.
DATA text TYPE string.
ENDCLASS.
CLASS lcx_no_check DEFINITION INHERITING FROM cx_no_check FINAL.
PUBLIC SECTION.
METHODS constructor IMPORTING !text TYPE csequence.
METHODS get_text REDEFINITION.
METHODS get_longtext REDEFINITION.
PRIVATE SECTION.
DATA text TYPE string.
ENDCLASS.
CLASS lcl_app DEFINITION FINAL CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS calculate_variant_output.
CLASS-METHODS render_variant_output.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_parameter,
value TYPE string,
description TYPE string,
END OF ty_parameter.
TYPES ty_parameters TYPE STANDARD TABLE OF ty_parameter WITH EMPTY KEY.
TYPES:
BEGIN OF ty_group,
description TYPE string,
parameters TYPE ty_parameters,
END OF ty_group.
TYPES ty_groups TYPE STANDARD TABLE OF ty_group WITH EMPTY KEY.
TYPES:
BEGIN OF ty_check,
check_class_name TYPE seoclsname,
has_attributes TYPE abap_bool,
parameters TYPE ty_parameters,
groups TYPE ty_groups,
END OF ty_check.
TYPES ty_checks TYPE STANDARD TABLE OF ty_check WITH EMPTY KEY.
CLASS-DATA checks TYPE lcl_app=>ty_checks.
CLASS-DATA tests TYPE sci_tabtest.
CLASS-DATA result TYPE string_table.
CLASS-METHODS export_category
IMPORTING category TYPE REF TO if_ci_test
RETURNING VALUE(result) TYPE string_table.
CLASS-METHODS get_variant_tree
RETURNING VALUE(r_hier) TYPE REF TO cl_ci_tests
RAISING cx_parameter_invalid_range
cx_parameter_invalid_type
cx_sy_codepage_converter_init
cx_sy_conversion_codepage.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
METHOD calculate_variant_output.
DATA(tree) = get_variant_tree( ).
" Export the top test category. It's a recursive method to export the child categories.
result = export_category( tree->tree ).
ENDMETHOD.
METHOD render_variant_output.
LOOP AT result REFERENCE INTO DATA(line).
WRITE / line->*.
ENDLOOP.
ENDMETHOD.
METHOD get_variant_tree.
cl_ci_checkvariant=>get_ref( EXPORTING p_user = space " space for global variant
p_name = variname
RECEIVING p_ref = DATA(variant)
EXCEPTIONS chkv_not_exists = 1
missing_parameter = 2
broken_variant = 3
OTHERS = 4 ).
CASE sy-subrc.
WHEN 0. " ##NO_HANDLER.
WHEN 1.
RAISE EXCEPTION TYPE lcx_no_check
EXPORTING text = 'Variant does not exist'.
WHEN OTHERS.
RAISE EXCEPTION TYPE lcx_system_message.
ENDCASE.
DATA(config) = NEW cl_ci_variant_configuration( ).
DATA(xml) = config->variant_to_xml( variant = variant ).
" Needed for ADT 3.48 debugger because of" missing "Wrap Text" feature in XSTRING XML Viewer.
IF 0 = 1.
DATA(xml_2) = cl_abap_codepage=>convert_from( xml ) ##NEEDED.
ENDIF.
checks = VALUE ty_checks( ).
CALL TRANSFORMATION z_ci_xml_to_itab
SOURCE XML xml
RESULT checks = checks.
" GET INSTANCES OF ALL TEST CLASSES SELECTED IN THE VARIANT
variant->get_info( EXCEPTIONS could_not_read_variant = 1
OTHERS = 2 ).
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE lcx_no_check
EXPORTING text = 'Error of IMPORT FROM DATABASE SCICHKV_PA(AR)'.
ENDIF.
" ADD MISSING TESTS (those with no attributes)
" This call is a complement of VARIANT_TO_XML which doesn't fill XML for tests without attributes.
" NB: GET_LIST works only if called after GET_INFO.
cl_ci_tests=>get_list( EXPORTING p_variant = variant->variant
RECEIVING p_result = DATA(collection_of_variant_tests)
EXCEPTIONS invalid_version = 1
OTHERS = 2 ).
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE lcx_no_check
EXPORTING text = 'Version incorrecte du test dans la variante'.
ENDIF.
LOOP AT collection_of_variant_tests->give_list( ) INTO DATA(test)
WHERE table_line->has_attributes = abap_false.
INSERT VALUE #( check_class_name = test->name )
INTO TABLE checks.
ENDLOOP.
" NEED TO RUN GET_TREE INSIDE DYNPRO (dynpro 1001 here) BECAUSE IT RUNS MESSAGE W144 (otherwise that stops a non-background process).
cl_ci_tests=>get_tree( EXPORTING p_variant = variant->variant
p_transport = abap_false
RECEIVING p_result = r_hier
EXCEPTIONS invalid_category = 1
invalid_class_name = 2
OTHERS = 3 ).
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE lcx_system_message.
ENDIF.
ENDMETHOD.
METHOD export_category.
LOOP AT category->childs INTO DATA(child_test_or_category_2).
IF child_test_or_category_2 IS INSTANCE OF cl_ci_category_root.
DATA(intermediate_result) = export_category( child_test_or_category_2 ).
INSERT LINES OF intermediate_result INTO TABLE result.
ELSE.
DATA(check) = REF #( checks[ check_class_name = child_test_or_category_2->name ] OPTIONAL ).
IF check IS NOT BOUND.
CONTINUE.
ENDIF.
INSERT |{ check->check_class_name } { child_test_or_category_2->description }| INTO TABLE result.
IF check->has_attributes = abap_false.
INSERT | No attribute| INTO TABLE result.
ELSE.
LOOP AT check->parameters REFERENCE INTO DATA(parameter).
INSERT | {
COND #( WHEN parameter->description IS NOT INITIAL
THEN parameter->description
ELSE '(no parameter description)' )
} : {
COND #( WHEN parameter->value IS NOT INITIAL
THEN parameter->value
ELSE '(no value or false)' )
} {
child_test_or_category_2->description }|
INTO TABLE result.
ENDLOOP.
LOOP AT check->groups REFERENCE INTO DATA(group).
INSERT | {
COND #( WHEN group->description IS NOT INITIAL
THEN group->description
ELSE '(no group description)' ) }|
INTO TABLE result.
LOOP AT group->parameters REFERENCE INTO parameter.
INSERT | {
COND #( WHEN parameter->description IS NOT INITIAL
THEN parameter->description
ELSE '(no parameter description)' )
} : {
COND #( WHEN parameter->value IS NOT INITIAL
THEN parameter->value
ELSE '(no value or false)' ) }|
INTO TABLE result.
ENDLOOP.
ENDLOOP.
ENDIF.
ENDIF.
ENDLOOP.
IF result IS NOT INITIAL.
LOOP AT result REFERENCE INTO DATA(result_line).
result_line->* = | { result_line->* }|.
ENDLOOP.
INSERT |{ category->name } { category->description }| INTO result INDEX 1.
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS lcx_system_message IMPLEMENTATION.
METHOD constructor.
super->constructor( textid = textid
previous = previous ).
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO text.
ENDMETHOD.
METHOD get_longtext.
result = text.
ENDMETHOD.
METHOD get_text.
result = text.
ENDMETHOD.
ENDCLASS.
CLASS lcx_no_check IMPLEMENTATION.
METHOD constructor.
super->constructor( textid = textid
previous = previous ).
me->text = text.
ENDMETHOD.
METHOD get_longtext.
result = text.
ENDMETHOD.
METHOD get_text.
result = text.
ENDMETHOD.
ENDCLASS.Simple Transformation Z_CI_XML_TO_ITAB:
<!-- https://community.sap.com/t5/application-development-and-automation-discussions/print-details-of-an-atc-code-inspector-check-variant-not-the-results/td-p/12804009 -->
<?sap.transform simple?>
<tt:transform
xmlns:tt="http://www.sap.com/transformation-templates"
xmlns:ci="https://www.sap.com/adt/codeinspector/checkvariant">
<tt:root name="CHECKS"/>
<tt:template>
<ci:variant tt:extensible="deep-dynamic">
<tt:loop ref="CHECKS">
<check>
<tt:attribute name="technicalName" value-ref="CHECK_CLASS_NAME"/>
<tt:assign to-ref="HAS_ATTRIBUTES" val="'X'"/>
<tt:loop ref="PARAMETERS">
<parameter>
<tt:cond>
<tt:attribute name="value" value-ref="VALUE"/>
</tt:cond>
<tt:cond>
<tt:attribute name="description" value-ref="DESCRIPTION"/>
</tt:cond>
</parameter>
</tt:loop>
<tt:loop ref="GROUPS">
<group>
<tt:attribute name="description" value-ref="DESCRIPTION"/>
<tt:loop ref="PARAMETERS">
<parameter>
<tt:cond>
<tt:attribute name="value" value-ref="VALUE"/>
</tt:cond>
<tt:cond>
<tt:attribute name="description" value-ref="DESCRIPTION"/>
</tt:cond>
</parameter>
</tt:loop>
</group>
</tt:loop>
</check>
</tt:loop>
</ci:variant>
</tt:template>
</tt:transform>Final result in an ABAP List (ABAP WRITE) / truncated to fit forum maximum:
CL_CI_CATEGORY_ABAP_COMPILER
CL_CI_TEST_ABAP_GENERATE Generate ABAP Programs
Generate only if necessary : false
CL_CI_TEST_EXPORT_COMP_PROCS_E Export of Program Information
Export Using RFC : false
RFC Destination : (no value or false)
With Call Level : 0
Force Generation : false
CL_CI_TEST_EXTENDED_CHECK Extended Program Check (SLIN)
(no parameter description) : 1
(no group description)
PERFORM/FORM Interfaces : true
CALL FUNCTION/METHOD Interfaces : true
CL_CI_TEST_SYNTAX_CHECK Syntax Check
More than one error : true
Warnings : true
Message Codes : (no value or false)
CL_CI_CATEGORY_SECURITY
CL_CI_TEST_CRITICAL_STATEMENTS Critical Statements
Calls
C-CALLs : true
SYSTEM-CALL : true
Database
ROLLBACK WORK : true
Dynamic Program Editing
GENERATE ... : true
READ REPORT : false
INSERT/DELETE REPORT : true
CL_CI_TEST_FIND_DYN_SQL Use of ADBC Interface
Find uses of ...
... ADBC classes : true
... other classes : (no value or false)
One message per ...
(no parameter description) : 1
CL_CI_TEST_SHO_CLIENT Client-Specific Shared Objects Methods
Attach Class Methods
ATTACH_FOR_READ : true
ATTACH_FOR_WRITE : true
ATTACH_FOR_UPDATE : true
Detach Class Methods
DETACH_AREA : true
DETACH_ALL_AREAS : true
CL_CI_CATEGORY_ROBUSTNESS
CL_CI_TEST_INT8 Test to check handling of type INT8
Analyze only local procedures : true
Non-local analysis depth : 1
(no group description)
Show detail information : false
Inverted check : false
‎2023 Nov 07 6:42 AM
Very good job Sandra !
if you are playing with ATC, I have created a specfic control to check object name (class, prog, ..)
‎2023 Nov 07 8:17 AM
frdric.girod Thanks. A standard check of program names already exists. Don't hesitate to share it with the community!
‎2023 Nov 07 9:45 AM
sandra.rossi these rules already exist ?

(I never been able to understand GitHub 😉 )
‎2025 Apr 18 10:25 AM
Yes for function group, program, function module, class, interface > Extended naming convention (see below screenshots).
No for the rest. But I have published a custom Code Inspector Check which checks DDIC Object Naming Convention, at Github with MIT license. The information is in this answer: Solved: Please any custom ABAP code to check DDIC object n... - SAP Community.
Feel free to publish your tool, too.
‎2023 Nov 07 9:37 AM
Why do you want to *print* a check variant? I feel there's another underlying problem here which should have a different solution.