These two rules share the same code base, but the warnings are separated into
major warnings (from ifindent1) and
minor warnings (from ifindent2).
This allows the more important warnings to have a higher severity.
If you want to run both rules "ifindent1" and "ifindent2", you might as well run rule ifindent instead to double the performance.
The rules output a variety of warnings for different situations. The major,
or 100-level, warnings will generally indicate either possible bugs or bad
indenting, and the minor, or 200-level, warnings generally do not indicate
bugs, but rather are IF statements which for various reasons cannot be checked
for potential bugs.
how these rules work
These rules have a somewhat complicated implementation. What they do is assess
your code in the same manner that the compiler will with regard to the grouping
of IF and ELSE blocks. What the compiler does may not be what you intended,
but at runtime, that is what will happen. Your indentation suggests how you
intended for your code to work, so we compare how the compiler will look at
it versus what your indentation implies, and report the differences.
This rule tests that all children nodes of an IF node have a greater than
or equal indent to the IF node, and also tests the next statement after
the IF to make sure it has an indent equal to the IF's indent. These two
checks ensure that the statements controlled by the IF block (as determined
by the compiler) are indented from it, and the statements outside and
following the IF block (as determined by the compiler) are not controlled
by the IF block. Note that this approach can occasionally result in more
than one warning being given for a particular line.
An example of the kinds of bugs found by this rule:
IF ok = TRUE THEN ASSIGN c1 = "correct". IF other = TRUE THEN RETURN. ELSE /* Should be for "ok = TRUE" but actually is for "other = TRUE" */ ASSIGN c1 = "oops". IF other THEN ASSIGN v1 = "Hello". |
In this example, Prolint will give three warnings:
IF
at line 3 is not controlled by the IF ok = TRUE
ELSE
on line 4. It occurs because the IF other
IF
that the ELSE
on line 4 is pairedIF other
's currentELSE
on line 4 for it should alsoDO... END.
statements to the IF ok = TRUE
on line 1 will result inELSE
being correctly paired to the IF
on line 1.
IF
onIF
s, so its' indentIF
on line 3. This warningDO
.
the risc:
It is not really clear that the ELSE
on line 4 is paired to the IF
on line 3, which causes a bug by changing the conditional execution of the code.
how to solve this:
If the programmer fixes the blocking by adding in the missing DO...END
, all
of these messages will go away without any changes to the indenting. Alternately,
the programmer could try fixing the first indent to the recommended amount,
then rerunning the rule to see if this has removed the rest of the warnings.
The corrected code:
IF ok = TRUE THEN DO: ASSIGN c1 = "correct". IF other = TRUE THEN RETURN. END. ELSE /* Is now for "ok = TRUE" as intended */ ASSIGN c1 = "oops". IF other THEN ASSIGN v1 = "Hello". |
After this correction, all warnings are prevented.
indent suggestions
These rules' suggested indents aren't enforcing a particular indenting
standard, but are simply the suggestions which would result in the indenting
being consistent with the blocking the compiler will use. It is assumed that
the program's indenting reflects the following model:
warning messages given
If it's hard to see why the rules are giving a certain warning, try changing
the code's indent as it suggests which may cause the problem/possible
bug to become obvious.
Alternately, you can run the program through COMPILE...PREPROCESS
then have a look at the code where the warning comes up - the problem
may then become apparent.
known problems
Tabs:
Prolint treats Tab characters as only one single character, although they should contribute to a larger indent. We can fix that if you want.
false positives
Preprocessing:
As with all rules which use Proparse, this rule operates against code
which is effectively preprocessed. Code which contains preprocessor
directives will frequently cause false positives, due to the
programmer's indenting in from the &IF etc. for readability. In the
resulting preprocessed code, these just look like their indents are
wrong. The number of false positives is reduced by omitting indent
checks on AppBuilder-generated code, but some will still remain.
Preprocessors can also cause false positives when a preprocessor
is defined to contain more than one Progress statement. If the rule
tries to calculate the indent of the second statement in the preprocessor,
it will have some huge indent like 497, and this may cause warnings.
For example:
&scop PART1 IF TRUE THEN FIND FIRST order NO-LOCK NO-ERROR. &scop PART2 IF AVAILABLE order THEN MESSAGE "avail order" VIEW-AS ALERT-BOX. &scop ALLPARTS {&PART1} {&PART2} IF TRUE THEN DO: MESSAGE "TRUE" VIEW-AS ALERT-BOX. END. ELSE DO: {&ALLPARTS} END. |
The IF statement contained in &PART2 has an indent of about 50,
because after the preprocessing has been done, this IF is on the
same line as the IF from &PART1.
Bad Indenting:
These are probably when the developer didn't notice the indenting wasn't quite right.
Tabs:
(As above) Prolint treats Tab characters as only one single character, although they appear much wider to the user. We can fix that if you want.
Include Files:
Occasional false positives occur on nodes either at the beginning of,
or immediately after, include files. This occurs because of the way
the white space is handled when entering or leaving includes.
more examples
An example of a warning from the rules that doesn't quite tell you the correct problem,
just that there is one here:
RUN myProg(var1,var2,OUTPUT retvar). IF retvar <> 0 THEN MESSAGE("Failed.") VIEW-AS ALERT-BOX. RUN yourProg (var3, OUTPUT retvar). |
The warning given for this code is that the indent is expected to be 8 but is 4,
for node RUN
on line 4. This is because we're only checking
indents on IF
nodes, their subnodes, and their next statement node after.
We aren't checking that the IF
has a sensible indent in the first place,
but we're able to see that the second RUN
(IF
's
next statement following) doesn't have a sensible indent when compared to
the IF
.
what's not checked by the rule
IF functions. This rule only checks IF statements.
Indents of nodes in different files:
It's pretty meaningless to try to check any indents of subnodes which are
in a different file. If they're subnodes of the IF, they're in some
include and could have any indenting scheme, and since they may
not be stand-alone statements, there's nothing to compare indents
to. Also, some programmers will write portions of a statement in one
include and other portions in another include or the main procedure.
Therefore, indents are not checked across files - if an IF is in
one file and some of its' children statements in the block are
in another file (an include), these children are ignored.
In this example, we can check the indent of the ASSIGN node, but not of any of the nodes inside the {someinclude.i}.
IF ... THEN DO: ASSIGN var = "blue". {someinclude.i} END. |
How to suppress these warnings:
You can put the directive {&_proparse_ prolint-nowarn(ifindent1)} or
directly before {&_proparse_ prolint-nowarn(ifindent2)}
the statement. See also: suppress warnings.
This page is only a quick overview of this rule, for more details see "ifindent-details".
Rule "ifindent" will by default not run, because it is not listed in file prolint/rules/rules.d.
Instead, the rules ifindent1 and
ifindent2 are listed by default, these two rules include the entire source of "ifindent".
If you plan to use both "ifindent1" and "ifindent2", you may consider to use "ifindent" instead because it will perform better.
In that case, follow these steps:
How to suppress warnings:
You can put the directive {&_proparse_ prolint-nowarn(ifindent)} directly before
the IF statement. See also: suppress warnings.
implementation:
This rule is implemented in Turbolint.
This page is only a quick overview of this rule, for more details see "ifindent-details".
When you run rule "infindent1", you are actually running rule "infindent" but without the informational warning messages.
Rule "ifindent1" gives this warning when it finds an IF statement with confusing indentation.
IF ready THEN ASSIGN a = x b = y. c = z. |
It looks like the second statement ( "c = z." ) will only be executed when the IF-condition is true.
the risc:
Confusing layout, the compiler may not do what the programmer intended
how to solve this:
In the given example, the statement "c = z." should have less indentation - same as the IF keyword.
How to suppress these warnings:
You can put the directive {&_proparse_ prolint-nowarn(ifindent1)} directly before
the IF statement. See also: suppress warnings.
implementation:
This rule is implemented in Turbolint.
This page is only a quick overview of this rule, for more details see "ifindent-details".
When you run rule "infindent2", you are actually running rule "infindent" but only for the informational warning messages.
warning messages given
How to suppress these warnings:
You can put the directive {&_proparse_ prolint-nowarn(ifindent2)} directly before
the IF statement. See also: suppress warnings.
implementation:
This rule is implemented in Turbolint.