Prolint

Prolint is a tool for automated source code review of Progress 4GL code. It reads one or more sourcefiles and examines it for bad programming practice
When you are interested Prolint, you are encouraged to subscribe to this group where you find the on-line tools to collaborate and discuss Prolint. There is a discussion forum, you can submit issues (for bugs and enhancement requests), you can modify the on-line documentation. So subscribe, and then don't forget to go to your subscription details to enable the e-mail notification!


use-index

avoid using USE-INDEX

Rule "use-index" gives this warning whenever it finds
the USE-INDEX keyword in the source.

the risc:

If you specify USE-INDEX, Progress will not
automatically select an index for you. The automatic
index selector is believed to be very good.

Even if you manually picked the best index there is
still a risc: this index will still be used after the
database schema gets changed, even if another index would
be better at that time.

As I understand it (correct me if I am wrong) there
are two query engines in Progress: the "old" one (already existed in V6) and the "new" one which is highly
optimized for joins and supports multi-bracketing.
If you specify USE-INDEX you
force Progress to use the "old" query engine, so
performance may actually be worse than without the USE-INDEX
option. There are even folks who say that if Progress would
automatically pick a different index than you would,
then either you picked the wrong one or the indexes
in the database schema are not well-defined...

how to solve this:


emptyblock

empty code block

Rule "emptyblock" searches for code blocks that do not have any code in them. For example, there may be a a repeat block where the import statement has been commented out.


REPEAT: 
/* 
  CREATE customer. 
  IMPORT customer. 
*/ 
END. 

Technically speaking, this rule belongs to an existing rule that checks for code that has no effect - but in this case, the warning message is more detailed, providing info on the type of a block that is empty.

Notes:

  • The program locates 'Code_block' node and checks that node's first

version

Expected proparse version X, found version Y

Prolint was tested on version X of proparse.dll but you have version Y. There is no way of predicting how Prolint will behave, but Prolint will try to continue anyway.

If version X is newer than Y you can upgrade proparse, see download proparse.

If version X is older than Y you should download the matching version of Prolint.


backslash

backslash in string "&1" (not Unix-compatible)

Rule "backslash" gives this warning when it finds a string that contains a backslash, but ignores backslashes if they are preceeded by a tilde.

the risc:

String will behave strange on Unix, because backslash is an escape-character on Unix.

how to solve this:

Escape the backslash with a tilde, or replace the backslash by a forwardslash.

backslash in filename "&1" (not Unix-compatible)

Rule "backslash" gives this warning when it finds a filename that contains a backslash.

the risc:


endtype

Type of END statement not qualified in PROCEDURE, FUNCTION, or CASE

Rule "endtype" gives this warning when it finds END statements for procedure, function, or case statements that do not have the end type specified. For example:

PROCEDURE pTest: 
   .... 
END. /* Rewrite to END PROCEDURE. */
CASE x:
    WHEN '1' THEN MESSAGE x.
END. /* Rewrite to END CASE. */

the risc:

None. This is really more of a question of company standards or coding style, where we want to be explicit in identification of END type.


undoretry

"UNDO" defaults to "UNDO, RETRY"

Rule "undoretry" gives this warning when it finds an UNDO statement without options like RETRY/LEAVE/UNDO/NEXT.

the risc:

"UNDO" behaves like "UNDO, RETRY" but RETRY is almost never desired.

How to suppress these warnings:

You should specify at least something like "UNDO, LEAVE labelname", or even "UNDO, RETRY" to confirm the default.


See also: suppress warnings.


idiskeyword

name of [variable|parameter|temp-table|field] &1 is a keyword

Rule "idiskeyword" gives this warning when you define a variable (or parameter, or anything else) and give it a name which is also a valid Progress keyword.
Some examples:

   /* x is a keyword */
   define variable x as integer no-undo.
   /* object, code and width are keywords */
   define temp-table object
      field code as character 
      field width as decimal.

the risc:


messagetype

ALERT BOX is missing alert type

Rule "messagetype" gives this warning when it finds a MESSAGE VIEW-AS ALERT-BOX statement that does not specify a messagetype like ERROR, WARNING, INFORMATION, QUESTION or MESSAGE.

the risc:

Not really a risc, but the MessageBox does not have an icon.

How to suppress these warnings:

You can put directive {&_proparse_ prolint-nowarn(messagetype)} directly before
the MESSAGE statement.
See also: suppress warnings.


do1

"DO:" contains only one statement

Rule "do1" gives this warning when it finds a DO: ... END block that contains only one statement.
The statement will work without the DO/END block around it.

Actually, the rule only looks at DO/END blocks in the THEN or ELSE branches of an IF statement:

IF condition THEN DO:
   /* this block is inspected */
END.
ELSE DO:
   /* this block is also inspected */
END.
DO:
  /* this block is not inspected because it is
     not in a THEN or ELSE branch. */
END.

when

wrong usage of ASSIGN..WHEN.. statement

Rule "when" gives this warning when it finds an ASSIGN statement with a WHEN clause, if the WHEN clause reads variables that are assigned to in that same ASSIGN statement.

DEFINE VARIABLE a AS INTEGER INITIAL 1.
DEFINE VARIABLE b AS INTEGER INITIAL 2.
DEFINE VARIABLE c AS INTEGER INITIAL 3.
DEFINE VARIABLE d AS INTEGER INITIAL 4.
ASSIGN 
   a = b
   c = 100 WHEN (a = b).
/* c is now still 3 */
ASSIGN 
   a = b
   c = 200 WHEN (d = 4).

You might expect that (a = b) is True after executing the first line, so c will be assigned the value 100.


dbtrigger

DISABLE TRIGGERS used - investigate

Rule "dbtrigger" gives this warning when it finds a DISABLE TRIGGERS statement.

the risc:

Schema triggers are defined to guarantee data consistency and are part of the data model.
An application should (normally) have no reasons to disable schema triggers, although some exceptions
are probably valid. Anyway, the use of DISABLE TRIGGERS is considered a red flag that needs to be reviewed.

How to suppress these warnings:

You can put directive {&_proparse_ prolint-nowarn(dbtrigger)} directly before


noundo

variable/temp-table/parameter [name] defined without NO-UNDO

Rule "noundo" gives this warning when it finds a "DEFINE VARIABLE" or "DEFINE TEMP-TABLE" statement without NO-UNDO.

the risc:

Slower performance, more IO to the LBI-file.

known issue:

A temp-table might be NO-UNDO without explicit definition. For example:

   DEFINE TEMP-TABLE tt_testB LIKE tt_testA.

In this example, temp-table tt_testB is implicitly NO-UNDO if tt_testA was explicitly defined with NO-UNDO.
We can't verify this in this little code snippet, but Prolint might have been able to figure it out... but Prolint doesn't care. It simply
will raise the warning "temp-table 'tt_testB' defined without NO-UNDO".

Personally I don't believe this is a bug in Prolint. After all, tt_testB may be NO-UNDO but it really is defined without NO-UNDO, isn't it?

how to solve this:


uninproc

internal procedure [name] is not used

Rule "uninproc" gives this warning when it finds an internal procedure that is never called from inside the compilation unit.

the risc:

Internal procedures that are never called, obscure the sourcefile and waste memory at run-time.

known issues:

The rule can not really know for sure if an internal procedure is never called: because a rule can only look at one compilation unit at a time, it can not see if the I.P. is called from an other external procedure.


i18nlength

LENGTH, OVERLAY, or SUBSTRING called without TYPE parameter

Rule "i18nlength" gives this warning when it finds a call to
LENGTH, OVERLAY, or SUBSTRING which did not provide the
"type" parameter: "CHARACTER," "RAW," or "COLUMN".

(the SUBSTRING function can also take a value of "FIXED")

the risc:

The source is not ready to support Unicode.

how to solve this:

Provide the "type" parameter.

How to suppress these warnings:

You can put directive {&_proparse_ prolint-nowarn(i18nlength)}
directly before the statement that contains the offending function.


weakchar

the "Weak Character" test

Rule "weakchar" gives this warning when it finds an ' IF charvar="" '
test that does not take into consideration that charvar might also
have the UNKNOWN value.

   IF AVAILABLE customer THEN
      IF customer.e-mail <> "" THEN
         RUN SendMail (customer.e-mail, subject, body).
      ELSE
         IF customer.fax <> "" THEN
            RUN SendFax (customer.fax, subject, body).

Trouble will happen if customer.e-mail happens to have the UNKNOWN value. The IF
condition did not check that.

So what is the proper way to check if a character field is not blanc
or unknown? You can think of several solutions, it is a matter of
taste or style, or perhaps even code-religion to pick the best. Here are a couple of
possible solutions:

   IF customer.e-mail > "" THEN ...

   IF NOT (customer.e-mail LE "") THEN ...
   
   IF NOT (customer.e-mail="" or customer.e-mail=?) THEN ...

   IF customer.e-mail<>"" AND customer.e-mail<>? THEN ...

This prolint rule gives probably many false positives and false negatives, it
needs improvement. One difficult issue is: what about the ELSE branche
of the IF statement?

How to suppress these warnings:


#
Syndicate content