ABAP Tools - Plugin ABAP Cleaner
Tired of formatting code and your colleague always does it completely differently? Today we present the ABAP Cleaner plugin, which takes a lot of work off your hands.
Table of contents
At the ABAP Development Days last week, SAP finally let the cat out of the bag and released the new feature for the ADTs for public use. The ABAP Cleaner is a plugin for Eclipse, with which you can clean up your code uniformly. You can also distribute the settings to your colleagues so that in the future the entire team will generate the same formatted code and you will be on the same page.
Introduction
But let's start from the beginning again. Since ABAP code has been developed, there have been different forms and best practices of how ABAP source code is actually formatted. In the past, a uniform Pretty Printer was used for this in most cases, but this had already reached its limits when it came to SELECT statements, how forms or method calls were defined.
In addition to the beautiful code, many new statements have been released in recent years that heralded Modern ABAP. The statements can now become quite long and can also be formatted in countless ways. In this context, the Guide for Clean ABAP was published to bring some order and best practice back into the code. In the next step, SAP worked on an extension of the ABAP Test Cockpit (ATC), the "Code pal", so that these rules can also be checked programmatically.
ABAP Cleaner
The ABAP Cleaner, a plug-in for Eclipse, which can be used together with the ABAP Development Tools (ADT), was created from all these specifications, plus a lot of old code. The ABAP Cleaner formats, changes and modernizes the ABAP code with a keyboard shortcut. The project exists as open source and together with the ABAP community, SAP would like to expand the tool and provide new functions. Issues can be opened via the Git Repository or supported directly with pull requests.
Scope
But what are all the functions in the tool? There is a detailed list of the current functions in the repository, which we would like to summarize for you here:
- Formatting - Adjust spaces or lines, align complex VALUE statements, format method calls, align assignments. Here, the majority of the ABAP code is uniformly adapted according to the style guide and no longer has to be formatted manually.
- Refactoring - The plugin's refactoring function is very powerful, so many old statements can be automatically replaced, such as comparison operators, removal of unnecessary self-reference ME, calling of methods to functional notation.
- Logic adjustment - Actually part of the refactoring, but we wanted to mention it here again. IF statements that are too long are looked at and the CHECKs are partially converted according to the new rules.
The main categories in the description are: empty lines, spaces, declarations, syntax, commands, pretty printer and alignment.
Installation
A current version of Eclipse with installed ABAP Development Tools (ADT) is required for the installation. To do this, start Eclipse and enter the current update site "https://sap.github.io/abap-cleaner/updatesite" in the menu via "Help -> Install New Software...". You can also find this in the documentation of the repository:
Then just confirm, agree to the terms of use and the license and the installation will be carried out. At the end, Eclipse has to be restarted again for the plugin to become active.
Usage
The tool can be accessed in active source code from the Source Code menu. The two options "Automatic mode" or "Interactive mode" are available here.
Alternatively and later, the function can then be triggered with the key combinations, CTRL + 4 and CTRL + SHIFT + 4 are available for this in the standard. The automatic mode applies the currently active profile directly to the selected source code and carries out the formatting. In the interactive mode you have the possibility to check all changes and see what is changed.
Example
Let's take some sample code that we prepared especially as a formatting demo. This code is working, but very poorly formatted. Using this example, we want to explain the features.
CLASS zcl_bs_demo_abap_cleaner DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
types:
td_char type c LENGTH 3,
"! Structure for data
begin of ts_data,
some_id type td_char,
some_text type string,
a_number type i,
end of ts_data,
"! Table for data
tt_data type STANDARD TABLE OF ts_data with DEFAULT KEY.
data:
mt_data type tt_data,
md_configuration type abap_bool.
methods:
"! Load intial data into table
"! @parameter rt_result | Loaded data
get_inital_data RETURNING VALUE(rt_result) type tt_data,
"! Output data into console
"! @parameter io_out | Reference for console
"! @parameter is_data | Data to be printed
output_something IMPORTING
io_out type ref to if_oo_adt_classrun_out
is_data type ts_data.
ENDCLASS.
CLASS zcl_bs_demo_abap_cleaner IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
data(lt_data) = me->get_inital_data( ).
loop at lt_data INTO data(ls_data).
check: ls_data-a_number GE 5.
output_something( EXPORTING io_out = out
is_data = ls_data
).
ENDLOOP.
ENDMETHOD.
METHOD get_inital_data.
rt_result =
value #(
( some_id = 'A' some_text = 'ABC' a_number = 2 )
( some_id = 'B' some_text = 'ABC' a_number = 10 )
( some_id = 'C' some_text = 'DEF' a_number = 8 )
( some_id = 'A' some_text = 'GIH' a_number = 7 )
).
ENDMETHOD.
METHOD output_something.
call method io_out->write
EXPORTING
data = |ID: { is_data-some_id } with Text: { is_data-some_text }|
."method call
ENDMETHOD.
ENDCLASS.
Pretty Printer
The Pretty Printer can already do a lot here and should already be firmly anchored in your development. But this only makes some indentations, the methods still look crooked.
CLASS zcl_bs_demo_abap_cleaner DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
TYPES:
td_char TYPE c LENGTH 3,
"! Structure for data
BEGIN OF ts_data,
some_id TYPE td_char,
some_text TYPE string,
a_number TYPE i,
END OF ts_data,
"! Table for data
tt_data TYPE STANDARD TABLE OF ts_data WITH DEFAULT KEY.
DATA:
mt_data TYPE tt_data,
md_configuration TYPE abap_bool.
METHODS:
"! Load intial data into table
"! @parameter rt_result | Loaded data
get_inital_data RETURNING VALUE(rt_result) TYPE tt_data,
"! Output data into console
"! @parameter io_out | Reference for console
"! @parameter is_data | Data to be printed
output_something IMPORTING
io_out TYPE REF TO if_oo_adt_classrun_out
is_data TYPE ts_data.
ENDCLASS.
CLASS zcl_bs_demo_abap_cleaner IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lt_data) = me->get_inital_data( ).
LOOP AT lt_data INTO DATA(ls_data).
CHECK: ls_data-a_number GE 5.
output_something( EXPORTING io_out = out
is_data = ls_data
).
ENDLOOP.
ENDMETHOD.
METHOD get_inital_data.
rt_result =
VALUE #(
( some_id = 'A' some_text = 'ABC' a_number = 2 )
( some_id = 'B' some_text = 'ABC' a_number = 10 )
( some_id = 'C' some_text = 'DEF' a_number = 8 )
( some_id = 'A' some_text = 'GIH' a_number = 7 )
).
ENDMETHOD.
METHOD output_something.
CALL METHOD io_out->write
EXPORTING
data = |ID: { is_data-some_id } with Text: { is_data-some_text }|
. "method call
ENDMETHOD.
ENDCLASS.
Interactive mode
Now if we mark the whole source code and start the interactive mode with CTRL + SHIFT + 4, then we get a window with new possibilities to get a preview of the changes.
What do we actually see in the window now? The typical colors for the version comparison are used in the source code. Red is removed lines, green is new lines, yellow has been changed, and gray lines do not exist in this section of code. Here is a brief explanation of the functions:
- Left side - Original source code without adjustments
- Right side - New source code after customization
- Toolbar
- Profiles - Various profiles for formatting the source code, setting the profiles and specifying the current release of the source code.
- Display - This allows specific changes to the source code to be highlighted or hidden.
- Search setting - Additional settings can be made for the search in the source code.
- Rules used - Rows or entire sections can be marked in comparison, all active rules are displayed for this section and you can deactivate your own rules for testing.
Compare
Let's take a look at a block of code and review the changes made. For this we take the loop in the example and first look at the comparison of the sections:
The check statement has disappeared and has been replaced with an IF-CONTINUE variant to be more readable for developers. The comparison operator has been replaced with the general option and is now also easier to read. When calling the method, exporting was removed, the parameters were formatted in the call, and the closing bracket is now on the last line. If we highlight the code block, we see a total of 7 different changes:
Result
Here is the final result of the class after executing the function in the "default" profile.
CLASS zcl_bs_demo_abap_cleaner DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
TYPES:
td_char TYPE c LENGTH 3,
"! Structure for data
BEGIN OF ts_data,
some_id TYPE td_char,
some_text TYPE string,
a_number TYPE i,
END OF ts_data,
"! Table for data
tt_data TYPE STANDARD TABLE OF ts_data WITH DEFAULT KEY.
DATA mt_data TYPE tt_data.
DATA md_configuration TYPE abap_bool.
"! Load initial data into table
"! @parameter rt_result | Loaded data
METHODS get_inital_data RETURNING VALUE(rt_result) TYPE tt_data.
"! Output data into console
"! @parameter io_out | Reference for console
"! @parameter is_data | Data to be printed
METHODS output_something IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out
is_data TYPE ts_data.
ENDCLASS.
CLASS zcl_bs_demo_abap_cleaner IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lt_data) = get_inital_data( ).
LOOP AT lt_data INTO DATA(ls_data).
IF ls_data-a_number < 5.
CONTINUE.
ENDIF.
output_something( io_out = out
is_data = ls_data ).
ENDLOOP.
ENDMETHOD.
METHOD get_inital_data.
rt_result =
VALUE #( ( some_id = 'A' some_text = 'ABC' a_number = 2 )
( some_id = 'B' some_text = 'ABC' a_number = 10 )
( some_id = 'C' some_text = 'DEF' a_number = 8 )
( some_id = 'A' some_text = 'GIH' a_number = 7 ) ).
ENDMETHOD.
METHOD output_something.
io_out->write( data = |ID: { is_data-some_id } with Text: { is_data-some_text }| ). " method call
ENDMETHOD.
ENDCLASS.
Configuration
The configuration of the profiles can be reached via the interactive mode (STRG + SHIFT + 4) and the button "Edit Profiles and Rules...". Here you can create new profiles and adjust the settings:
The screen is structured as follows:
- Top left - Management of profiles
- Open right - Settings for the selected rule
- Below left - Available rules and more options
- Below right - code examples for the selected rule to see the settings
Hint: To give your colleagues the same configuration, if it differs from "default", you can do it via export and import. So you can store and exchange the file centrally.
System release
Some of the rules don't work on older systems, for example when it comes to new statements. Here you should work with the interactive mode, there you can set the version of the code. Then certain rules are no longer executed and only correct changes are made:
Conclusion
The new tool can save an incredible amount of time today and ensure a uniform status in the development team. Source code that is formatted in the same way can be read by everyone equally well and reduces the effort required to familiarize yourself with new coding, as certain standards are set. At the same time, the refactoring options allow you to modernize old source code and avoid unnecessary source code.