Get Started
- CodeAnt AI
- Control Center
- Pull Request Review
- IDE
- Compliance
- Anti-Patterns
- Code Governance
- Infrastructure Security Database
- Application Security Database
Abap
A BREAK-POINT
statement is used when debugging an application with help of the ABAP Debugger. But such debugging statements could make an application vulnerable to attackers, and should not be left in the source code.
IF wv_parallel EQ 'X'.
BREAK-POINT.
WAIT UNTIL g_nb_return EQ wv_nb_call.
ENDIF.
Jump statements, such as CHECK and CONTINUE
let you change the default flow of program execution, but jump statements that direct the control flow to the original direction are just a waste of keystrokes.
LOOP AT myTable.
PERFORM form_open USING ...
CHECK retcode = 0.
...
perform form_close.
CHECK retcode = 0. "Noncompliant; whatever the result of the check, the loop will continue to the next iteration
ENDLOOP.
Calling DELETE ADJACENT DUPLICATES won’t reliably do any good if the table hasn’t first been sorted to put duplicates side by side, since the ADJACENT
part of the command looks for multiple rows side-by-side with the same content.
DELETE ADJACENT DUPLICATES FROM ITAB COMPARING LAND.
Procedural development in general, and FORM… ENDFORM, and PERFORM
specifically, have been been classified as obsolete by SAP and should be avoided. Classes and methods should be used for all new development.
FORM fill_table USING wa TYPE any
CHANGING ptab TYPE INDEX TABLE.
APPEND wa TO ptab.
ENDFORM.
* ...
PERFORM fill_table IN PROGRAM my_prog.
Using `LOOP…INTO with MODIFY statements will put the required record in a work area, process it and put it back in the internal table. It is more efficient to modify the internal table directly by using LOOP…ASSIGNING and field-symbols.
This rule raises an issue when a LOOP…INTO contains one or more MODIFY` statements.
LOOP AT i_bseg INTO wa_bseg.
...
wa_bseg-sgtxt = 'VALUE'.
MODIFY i_bseg FROM wa_bseg.
ENDLOOP.
The `READ TABLE … WITH KEY … statement performs a linear search of STANDARD tables, which is very inefficient in most cases.
This rule raises an issue when a READ TABLE … WITH KEY … statement does not finish with BINARY SEARCH. No issue will be raised for HASHED and SORTED` tables.
TYPES BEGIN OF t_mytable,
myfield TYPE i
END OF t_mytable.
DATA myworkarea TYPE t_mytable.
DATA mytable TYPE STANDARD TABLE OF t_mytable.
SORT mytable BY myfield.
READ TABLE mytable
WITH KEY myfield = 42
INTO myworkarea. " Noncompliant
Modifying SAP standard tables via an Open SQL statement can result in data corruption and unexpected behavior. This is because a direct modification bypasses all validation mechanisms.
Instead, the use of standard functions or SAP Business Add-Ins (BAdIs) is recommended.
This rule raises an issue on Open SQL statements INSERT, UPDATE, MODIFY, or SELECT … FOR UPDATE
which target an SAP table, i.e. a table with a name starting with a character between “A” and “X”, case insensitive.
SELECT my_col FROM my_system_table WHERE my_id = 123 FOR UPDATE. " Noncompliant
SELECT my_col FROM z_custom_table WHERE my_id = 123 FOR UPDATE. " Ignored; modifies a custom table
The ABAP documentation is pretty clear on this subject :
SYSTEM-CALL CREATE CLASS c.
The complexity of an expression is defined by the number of AND, OR, XOR and EQUIV
operators it contains.
A single expression’s complexity should not become too high to keep the code readable.
IF ((condition1 AND condition2) OR (condition3 AND condition4)) AND condition5.
...
ENDIF.
`JOIN bypasses the SAP table buffer. Buffered tables should be accessed with the simplest SELECT statements possible so as not to risk bypassing the buffer.
If one of the tables in a JOIN is buffered, it would be an advantage to first import the required entries using a SELECT into an internal table itab, and then for example, using the statement SELECT … FOR ALL ENTRIES IN itab` to access further tables.
SELECT s~carrid s~carrname p~connid
INTO CORRESPONDING FIELDS OF TABLE itab
FROM scarr AS s
LEFT OUTER JOIN spfli AS p ON s~carrid = p~carrid
AND p~cityfrom = p_cityfr.
For readability, SAP recommends that asterisks (*) only be used to comment out header lines and code. Commentary should be commented using a double quote (“
)
* GAC - 13 June 13 - output user data
* WRITE: / 'Firstname'.
In SELECT … FOR ALL ENTRIES
queries there are two internal tables: the driver internal table, and the target internal table. For each entry in the driver table some data from a database table is stored in the target internal table.
Most of the time, starting by sorting the content of the driver internal table offers improved performance. Indeed in such cases, from one request to another, the data read from the database tends to be much the same, and so for instance the use of database caching is maximised.
SELECT carrid , connid , seatsocc FROM flights
INTO TABLE seatsocc_tab
FOR ALL ENTRIES IN conn_tab
WHERE carrid = conn_tab-carrid
AND connid = conn_tab-connid
This BYPASSING BUFFER clause explicitly switches off SAP table buffering, so the SELECT
reads data directly from the database.
By definition, using this clause can lead to performance issues, which is why its use must be strongly indicated.
SELECT *
INTO US_PERSONS
FROM PERSONS
BYPASSING BUFFER
WHERE CITY EQ 'US'
Restricting the number of `CONTINUE, EXIT and CHECK statements in a loop is done in the interest of good structured programming.
One CONTINUE, EXIT and CHECK` statement is acceptable in a loop, since it facilitates optimal coding. If there is more than one, the code should be refactored to increase readability.
DO counter TIMES.
IF sy-index = 2.
CONTINUE.
ENDIF.
IF sy-index = 10.
EXIT.
ENDIF.
WRITE sy-index.
ENDDO.
SELECT INTO TABLE is much more efficient than SELECT … ENDSELECT. SELECT INTO TABLE
needs more memory to hold the result set, but in normal situations, this is not a concern. When memory is a concern, the result set can be divided into smaller sets.
SELECT * FROM T006 INTO X006_WA.
...
ENDSELECT.
Leaving a CATCH
block empty means that the exception in question is neither handled nor passed forward to callers for handling at a higher level. Suppressing errors rather than handling them could lead to unpredictable system behavior and should be avoided.
try.
if ABS( NUMBER ) > 100.
write / 'Number is large'.
endif.
catch CX_SY_ARITHMETIC_ERROR into OREF.
endtry.
A loop with at most one iteration is equivalent to the use of an `IF statement to conditionally execute one piece of code. No developer expects to find such usage of a loop statement. If the initial intention of the author was really to conditionally execute one piece of code, an IF statement should be used in place.
At worst that was not the initial intention of the author and so the body of the loop should be fixed to use the nested STOP, RETURN or EXIT` statements in a more appropriate way.
DATA remainder TYPE i.
DO 20 TIMES.
remainder = sy-index MOD 2.
cl_demo_output=>write_text().
EXIT. " noncompliant, loop only executes once
ENDDO.
SELECT with JOIN
always performs better than nested selects.
SELECT * FROM SPFL INTO SPFLI_WA.
SELECT * FROM SFLOGHT INTO SFLIGHT_WA
WHERE CARRID = SPFLI_WA-CARRID
AND CONNID = SPFLIGHT_WA_CONNID.
ENDSELECT.
ENDSELECT.
Removing duplicate entries from driver tables enables OPEN SQL
to generate fewer queries for getting the same data, giving a performance boost.
SELECT carrid , connid , seatsocc FROM flights
INTO TABLE seatsocc_tab
FOR ALL ENTRIES IN conn_tab
WHERE carrid = conn_tab-carrid
AND connid = conn_tab-connid.
Using EXIT and CHECK in SELECT statements to stop the execution of SELECT loop is an expensive and ineffective way to filter data. Filtering should be part of the SELECT loop themselves. Most of the time conditions located in a CHECK statement should be moved to the WHERE clause, and the EXIT statement should typically be replaced by an UP TO 1 ROW
clause.
SELECT * FROM SBOOK INTO SBOOK_WA.
CHECK: SBOOK_WAS-CARRID = 'LH' AND SBOOK_WAS-CONNID = '0400'. "Noncompliant
ENDSELECT.
Internal tables can quickly become a source of performance problems if not accessed correctly, SORTED and HASHED
tables should always be accessed with the appropriate key or partial key.
READ TABLE it INTO work_area INDEX 1.
Internal tables can be sorted without specifying the specific fields on which to sort. However, doing so is inefficient because when a sort key is not specified, the entire row is used in the sort, which can be markedly inefficient.
SORT ITAB.
Every subroutine(FORM
) should be commented to explain its goal and how it works. This comment can be located just before or after the form definition.
FORM my_form.
...
ENDFORM
Checking logged users’ permissions by comparing their name to a hardcoded string can create security vulnerabilities. It prevents system administrators from changing users’ permissions when needed (example: when their account has been compromised). Thus system fields `SY-UNAME and SYST-UNAME should not be compared to hardcoded strings. Use instead AUTHORITY-CHECK to check users’ permissions.
This rule raises an issue when either of the system fields SY-UNAME or SYST-UNAME are compared to a hardcoded value in a CASE statement or using one of the following operators: =, EQ, <>, NE`.
IF SY-UNAME = 'ALICE'. " Noncompliant
ENDIF.
CASE SY-UNAME.
WHEN 'A'. " Noncompliant
ENDCASE.
When several lines must be inserted/updated into an internal table, instead of doing those changes line by line, mass operations should be used because they offer better performance by design.
This rule raises an issue when a single line operation like APPEND, CONCATENATE, and INSERT
is performed on an internal table in a loop.
LOOP AT ITAB1 INTO WA.
APPEND WA TO ITAB2.
ENDLOOP.
`CASE can contain a WHEN OTHERS clause for various reasons: to handle unexpected values, to show that all the cases were properly considered, etc.
For readability purposes, to help a developer quickly spot the default behavior of a CASE statement, it is recommended to put the WHEN OTHERS clause at the end of the CASE statement.
This rule raises an issue if the WHEN OTHERS clause is not the last one of the CASE’s cases.
CASE SY-INDEX.
WHEN OTHERS. // Noncompliant; WHEN OTHERS should be the last statement
WRITE 'Unexpected result'
WHEN ONE.
WRITE 'One'.
WHEN 2.
WRITE 'Two'.
ENDCASE.
According to the SAP documentation:
So calling system C functions using a CALL
statement should be avoided.
CALL 'MULTIPLY' ID 'P1' FIELD '9999'
ID 'P2' FIELD '9999'
ID 'RES' FIELD RESULT.
Using the = operator to copy the content of an internal table is more efficient than using LOOP + APPEND
statements.
REFRESH ITAB2.
LOOP AT ITAB1 INTO WA.
APPEND WA TO ITAB2.
ENDLOOP.
Every AUTHORITY-CHECK statement sets the fields SY-SUBRC (also accessible as SYST-SUBRC) to the authorization check result. Thus SY-SUBRC value should be checked just after every AUTHORITY-CHECK
statement.
AUTHORITY-CHECK OBJECT 'S_MYOBJ' "Noncompliant
ID 'ID1' FIELD myvalue.
Because CX_ROOT is the base exception type, catching it directly probably casts a wider net than you intended. Catching CX_ROOT could mask far more serious system errors that your CATCH
logic was intended to deal with.
Some smaller, more specific exception type should be caught instead.
try.
if ABS( NUMBER ) > 100.
write / 'Number is large'.
endif.
catch CX_ROOT into OREF.
write / OREF->GET_TEXT( ).
endtry.
Passing parameters by reference instead of by value avoids the overhead of making a copy. Passing arguments via copy should only be done when it is technically mandated, as it is for example with RFC function modules.
PERFORM subr USING a1 a2 a3 a4 a5.
Shared naming conventions allow teams to collaborate efficiently. This rule checks that all method parameters follow a naming convention.
METHODS m_fact IMPORTING i1 TYPE i
value(i2) TYPE i
RETURNING value(factorial) TYPE i.
Whenever more than one line needs to be read, inserted or deleted from a database table, it is more efficient to work with an internal table than to read, insert or delete the lines one by one inside a loop.
LOOP AT TAB INTO TAB_WA.
INSERT INTO CUSTOMERS VALUES TAB_WA.
ENDLOOP.
`CASE statements are useful when there are many different cases depending on the value of the same expression.
For just one or two cases however, the code will be more readable with IF` statements.
CASE SY-INDEX.
WHEN ONE.
WRITE 'One'.
WHEN 2.
WRITE 'Two'.
ENDCASE.
This rule applies whenever an `IF statement is followed by one or
more ELSEIF statements; the final ELSEIF should be followed by an ELSE statement.
The requirement for a final ELSE statement is defensive programming.
The ELSE statement should either take appropriate action or contain
a suitable comment as to why no action is taken. This is consistent with the
requirement to have a final OTHERS clause in a CASE`
statement.
IF RESULT > 0.
PERFORM do_something.
ELSEIF RESULT = 0.
PERFORM do_something_else.
ENDIF.
DATA BEGIN OF … OCCURS
has been deprecated and will eventually be removed. All usages should be replaced.
DATA BEGIN OF itab OCCURS n. "Noncompliant
...
DATA END OF itab [VALID BETWEEN intlim1 AND intlim2].
Shared naming conventions allow teams to collaborate efficiently.
This rule raises an issue when a method name does not match a provided regular expression.
For example, with the default provided regular expression ^([A-Z0-9_]|[a-z0-9_])$, the method:
METHOD MyMethod "Noncompliant
...
ENDMETHOD.
Nested control flow statements IF, CASE, DO, LOOP, SELECT, WHILE and PROVIDE
are often key ingredients in creating
what’s known as “Spaghetti code”. This code smell can make your program difficult to understand and maintain.
When numerous control structures are placed inside one another, the code becomes a tangled, complex web. This significantly reduces the code’s readability and maintainability, and it also complicates the testing process.
IF param1 = 2.
IF param2 = 4.
DO 3 TIMES. "Compliant - depth = 3, not exceeding the limit
IF sy-index = 2. "Noncompliant - depth = 4
CONTINUE.
ENDIF.
WRITE sy-index.
ENDDO.
ENDIF.
ENDIF.
Every function should be commented to explain its goal and how it works. This non-empty comment must be located before the function definition.
FUNCTION my_function.
...
ENDFUNCTION.
The system field `SY-SUBRC must be tested immediately after any statement setting this variable. Reading this variable informs on previous operation success or errors. Such errors should be handled properly so that the program continues in a consistent state.
This rule raises an issue when the field SY-SUBRC is not checked just after performing one of the following operations:
Calling a function or method which can throw exceptions.
Calling one of the file access operation OPEN DATASET, READ DATASET or DELETE DATASET.
SY-SUBRC check must be done either with the CASE, IF or CHECK` statement.
CALL FUNCTION 'STRING_SPLIT'
EXPORTING
DELIMITER = ':'
STRING = FELD
IMPORTING
HEAD = HEAD
TAIL = TAIL
EXCEPTIONS
NOT_FOUND = 1
OTHERS = 2.
This statement deletes all rows of an internal table itab. This REFRESH
statement is deprecated and usage should be avoided.
REFRESH itab.
Naming conventions are an important tool in efficient team collaboration. This rule checks that all form names match a regular expression naming convention.
FORM MyForm.
...
ENDFORM.
UPDATE dbtab SET … without a WHERE condition changes all the entries of the table. Check whether dataset to be changed can be limited by a suitable WHERE
condition.
UPDATE COUNTRIES SET NAME=country_name.
Using keywords as variable names may yield incomprehensible code, and should be avoided.
DATA: wa_struct TYPE struct,
name TYPE string,
dob TYPE string,
aliases TYPE string, " ALIASES is a keyword
Using an empty driver table in a SELECT/FOR ALL ENTRIES table has a very important side effect: the complete WHERE clause is not taken into account because a NO WHERE
condition is generated. Thus a full table scan is unexpectedly executed.
SELECT carrid , connid , seatsocc FROM flights
INTO TABLE seatsocc_tab
FOR ALL ENTRIES IN conn_tab " Noncompliant; conn_tab may be empty.
WHERE carrid = conn_tab-carrid
AND connid = conn_tab-connid.
Every macro should be commented to explain its goal and how it works. This comment can be located just before or after the macro definition.
DEFINE my_macro.
...
END-OF-DEFINITION.
ABAP provides the ability to manipulate programs dynamically during execution for instance with statements like `INSERT REPORT and GENERATE SUBROUTINE POOL. Most of those statements are for internal use within SAP Technology Development and incompatible changes are possible at any time without prior warning or notice.
This rule raises an issue when any of the following source code processing statements is used: INSERT REPORT, READ REPORT, DELETE REPORT, EDITOR-CALL FOR REPORT, SYNTAX-CHECK FOR itab, GENERATE REPORT/SUBROUTINE POOL, LOAD REPORT, SCAN, INSERT TEXTPOOL, READ TEXTPOOL, DELETE TEXTPOOL, EXPORT DYNPRO, IMPORT DYNPRO, DELETE DYNPRO, SYNTAX-CHECK FOR DYNPRO, and GENERATE DYNPRO`.
GENERATE REPORT MY_PROG.
DELETE FROM dbtab without a WHERE
condition deletes all the entries of the table. Check whether dataset to be deleted can be limited by a suitable WHERE condition.
DELETE FROM COUNTRIES.
” statements without an authority check is security sensitive. Its access should be restricted to specific users.
This rule raises when a `CALL TRANSACTION has no explicit authorization check, i.e. when:
the CALL TRANSACTION statement is not followed by WITH AUTHORITY-CHECK.
the CALL TRANSACTION statement is not following an AUTHORITY-CHECK statement.
the CALL TRANSACTION statement is not following a call to the AUTHORITY_CHECK_TCODE` function.
AUTHORITY-CHECK OBJECT 'S_DIAGID'
ID 'ACTVT' FIELD '03'.
IF sy-subrc <> 0.
" show an error message...
ENDIF.
CALL TRANSACTION 'MY_DIALOG'. " Ok but obsolete since ABAP 7.4.
This variant of the `REFRESH statement is deprecated and should be avoided.
This REFRESH statement initializes the internal table itab, reads several rows from the database table dbtab, and adds their contents to the internal table itab. A SELECT` statement should be used instead.
TABLES t100.
DATA itab TYPE STANDARD TABLE OF t100.
t100-sprsl = 'E'.
t100-arbgb = 'BC'.
REFRESH itab FROM TABLE t100.
SQL COUNT(..), MIN(..), MAX(..), SUM(..), AVG(..)
aggregate functions cause the SAP table buffer to be bypassed, so the use of these functions can lead to performance issues.
SELECT COUNT(*)
FROM persons
INTO count
WHERE city = 'NEW YORK'.
Having all branches of a CASE or IF chain with the same implementation indicates a problem.
In the following code:
IF a >0. "Noncompliant
doSomething.
ELSE IF b> 0.
doSomething.
ELSE.
doSomething.
ENDIF.
CASE i. "Noncompliant
WHEN 1 OR 3.
doSomething.
WHEN 2.
doSomething.
WHEN OTHERS.
doSomething.
ENDCASE.
When there is only one statement in a chain, the chain syntax can be omitted, which simplifies the code.
CLEAR: w_alvvr.
The `EXEC SQL … END-EXEC statement can be used to embed Native SQL statically in ABAP programs.
According to the SAP documentation:
EXEC SQL.
CREATE TABLE abap_docu_demo_mytab (
val1 char(10) NOT NULL,
val2 char(10) NOT NULL,
PRIMARY KEY (val1) )
ENDEXEC.
ABAP hints can be used to override the default behavior of the SAP Cost Based Optimizer (CBO). When the execution plan provided by the CBO is not optimal, it is possible to “drive” the CBO by providing the main index to be used to filter rows.
Such optimizations are not portable from one database to another, such as when migrating from Oracle to DB2. Therefore hard coding an optimization should be done only when it is strongly indicated.
select MY_COLUMN
into it_data
from MY_TABLE
WHERE FILTERING_COLUMN = '0'
%_HINTS ORACLE 'INDEX("MY_TABLE" "MY_INDEX")'.
The main reason for using chained statements is to increase readability, but when used with operational statements, chaining can have the opposite effect. Even worse, it can lead to unexpected program behavior.
TRY.
...
CATCH: cx_1, cx_2, cx_3. " only cx_3 gets the following CATCH block
"exception handling
...
ENDTRY.
An Open SQL SELECT statement without an explicit ORDER BY clause will retrieve rows in an unpredictable order. On pool/cluster tables, the current implementation of Open SQL SELECT returns the result set in the primary key order, but that’s not the case for transparent tables. That’s why it’s safer to always use an ORDER BY
clause.
OPEN CURSOR C FOR SELECT * FROM SBOOK WHERE CARRID = 'LH '. "NonCompliant
SELECT * FROM FLIGHTS WHERE FLIGHT_NUMBER = 'LH '."NonCompliant
SAP recommends to keep the result set of any request as small as possible for performance reasons.
A `SELECT…ENDSELECT request will retrieve multiple records at the same time. Stopping immediately such a request with a CHECK, RETURN or EXIT statement will not reduce the number of retrieved records. If the goal is to retrieve a single record, or check that at least one record exists, it is recommended to add UP TO 1 ROWS or to use SELECT SINGLE.
Even if the request already retrieved only one record, adding UP TO 1 ROWS or to using SELECT SINGLE will make the code easier to read.
This rule raises an issue when a SELECT…ENDSELECT which has neither SINGLE nor UP TO 1 ROWS and:
contains only one statement and it is a CHECK, RETURN or EXIT`
or when it is completely empty.
SELECT * FROM sbook INTO ls_book WHERE carrid EQ l_carrid.
EXIT.
ENDSELECT.
IF sy-subrc NE 0.
WRITE:/ 'NO RECORD FOUND'.
ENDIF.
The requirement for an OTHERS
clause is defensive programming. The clause should either take appropriate action, or contain a suitable comment as to why no action is taken.
CASE SY-INDEX. // Noncompliant; missing WHEN OTHERS clause
WHEN ONE.
WRITE 'One'.
WHEN 2.
WRITE 'Two'.
ENDCASE.
DISTINCT operator causes the SELECT
statement to avoid the SAP buffering and to read directly from the database and not from the buffer on the application server.
SELECT DISTINCT carrid
FROM spfli
INTO count
WHERE cityto = 'NEW YORK'.
Putting multiple statements on a single line lowers the code readability and makes debugging the code more complex.
Unresolved directive in <stdin> - include::{noncompliant}[]
Write one statement per line to improve readability.
Unresolved directive in <stdin> - include::{compliant}[]
WRITE 'Hello '. WRITE 'World'. "Noncompliant
When handling a caught exception, the original exception’s message and stack trace should be logged or passed forward.
try.
if ABS( NUMBER ) > 100.
write / 'Number is large'.
endif.
catch CX_SY_ARITHMETIC_ERROR into OREF.
endtry.
Magic numbers make the code more complex to understand as it requires the reader to have knowledge about the global context to understand the number itself. Their usage may seem obvious when writing the code, but it may not be the case for another developer or later once the context faded away. -1, 0, and 1 are not considered magic numbers.
IF sy-subrc EQ 42. " Noncompliant - 5 is a magic number
screen-request = 'OK'.
ENDIF.
SQL queries that use EXISTS subqueries are inefficient because the subquery is re-run for every row in the outer query’s table. There are more efficient ways to write most queries, ways that do not use the EXISTS
condition.
SELECT name
FROM employee
WHERE EXISTS (SELECT * FROM department WHERE department_id = id AND name = 'Marketing');
Nested code - blocks of code inside blocks of code - is eventually necessary, but increases complexity. This is why keeping the code as flat as possible, by avoiding unnecessary nesting, is considered a good practice.
Merging if statements when possible will decrease the nesting of the code and improve its readability.
IF something.
IF somethingElse. " Noncompliant
WRITE / 'hello'.
ENDIF.
ENDIF.
Sharing some naming conventions is a key point to make it possible for a team to efficiently collaborate. This rule allows to check that all macro names match a provided regular expression.
DEFINE MyMacro.
...
END-OF-DEFINITION.
The use of parentheses, even those not required to enforce a desired order of operations, can clarify the intent behind a piece of code. However, redundant pairs of parentheses could be misleading and should be removed.
CHECK (SY-SUBRC NE 0). "compliant even if ignored by compiler
IF ((SY-SUBRC EQ 0)). "Noncompliant
Arbitrary OS command injection vulnerabilities are more likely when a shell is spawned rather than a new process, indeed shell meta-chars can be used (when parameters are user-controlled for instance) to inject OS commands.
CALL 'SYSTEM' ID 'COMMAND' FIELD "/usr/bin/file.exe" ID 'TAB' FIELD TAB1. " Compliant
A chain of if/else if statements is evaluated from top to bottom. At most, only one branch will be executed: the first one with a condition that evaluates to true.
Therefore, duplicating a condition automatically leads to dead code. Usually, this is due to a copy/paste error. At best, it’s simply dead code and at worst, it’s a bug that is likely to induce further bugs as the code is maintained, and obviously it could lead to unexpected behavior.
if param = 1.
Statement.
elseif param = 2.
Statement.
elseif param = 1. // Noncompliant
Statement.
endif.
Shared naming conventions allow teams to collaborate efficiently.
This rule raises an issue when a class name does not match a provided regular expression.
CLASS MyClass DEFINITION. "Noncompliant
...
ENDCLASS.
Sharing some naming conventions is a key point to make it possible for a team to efficiently collaborate. This rule allows to check that all variable names match a provided regular expression.
DATA: MyText TYPE string.
Duplicated string literals make the process of refactoring complex and error-prone, as any change would need to be propagated on all occurrences.
WRITE: / 'Firstname'.
*...
WRITE: / 'Firstname'.
*...
WRITE: / 'Firstname'.
The switch statement should be used only to clearly define some new branches in the control flow. As soon as a case clause contains too many statements this highly decreases the readability of the overall control flow statement. In such case, the content of the case
clause should be extracted into a dedicated method.
CASE SY-INDEX.
WHEN ONE. // 6 lines till next WHEN
PERFORM sub1.
PERFORM sub2.
PERFORM sub3.
PERFORM sub4.
PERFORM sub5.
WHEN 2.
...
ENDCASE.
Shared coding conventions allow teams to collaborate efficiently. This rule checks that all function names match a provided regular expression.
FUNCTION MyFunction.
...
ENDFUNCTION.
Hardcoding IP addresses is security-sensitive. It has led in the past to the following vulnerabilities:
Today’s services have an ever-changing architecture due to their scaling and redundancy needs. It is a mistake to think that a service will always have the same IP address. When it does change, the hardcoded IP will have to be modified too. This will have an impact on the product development, delivery, and deployment:
The developers will have to do a rapid fix every time this happens, instead of having an operation team change a configuration file.
It misleads to use the same address in every environment (dev, sys, qa, prod).
Last but not least it has an effect on application security. Attackers might be able to decompile the code and thereby discover a potentially sensitive address. They can perform a Denial of Service attack on the service, try to get access to the system, or try to spoof the IP address to bypass security checks. Such attacks can always be possible, but in the case of a hardcoded IP address solving the issue will take more time, which will increase an attack’s impact.
READ DATASET file INTO ip MAXIMUM LENGTH len.
Sharing some naming conventions is a key point to make it possible for a team to efficiently collaborate. This rule allows to check that all interface names match a provided regular expression.
INTERFACE MyInterface. "Noncompliant
...
ENDINTERFACE.
An unused local variable is a variable that has been declared but is not used anywhere in the block of code where it is defined. It is dead code, contributing to unnecessary complexity and leading to confusion when reading the code. Therefore, it should be removed from your code to maintain clarity and efficiency.
FUNCTION f.
DATA: LOCAL_1 LIKE BAR.
DATA: LOCAL_2 LIKE BAR. "Noncompliant - LOCAL_2 is unused
SELECT * FROM LOCAL_1.
ENDFUNCTION.
Consistent indentation is a simple and effective way to improve the code’s readability. It reduces the differences that are committed to source control systems, making code reviews easier.
This rule raises an issue when the indentation does not match the configured value. Only the first line of a badly indented section is reported.
CLASS counter IMPLEMENTATION.
METHOD set.
count = set_value. " Noncompliant, expected to start at column 4
ENDMETHOD. " Noncompliant, expected to start at column 2
METHOD increment.
ADD 1 TO count.
ENDMETHOD.
METHOD get.
get_value = count.
ENDMETHOD. " Noncompliant, expected to start at column 2
ENDCLASS.
Having two WHEN in a CASE statement or two branches in an IF chain with the same implementation is at best duplicate code, and at worst a coding error.
IF a >= 0 AND a < 10.
doFirst.
doTheThing.
ELSEIF a >= 10 AND a < 20.
doTheOtherThing.
ELSEIF a >= 20 AND a < 50.
doFirst. // Noncompliant; duplicates first condition
doTheThing.
ENDIF.