Supported Linter rules¶
ipt has a list of linter rules builtin.
Some explanation about the short details for each rule:
Rule name |
The build in rule name that is always printed alongside the error messages |
---|---|
Fixable |
yes, if ipt can apply automatic fixes. If fixes are applied we don’t output additional linting messages. |
Severity |
The error message level that an error message will have, if this rule creates one. This can be one of:
|
Features |
The list of all features this rule supports. For a detailed description see below. none, if no features are supported. |
Note
Good Igor procedure code should have no errors or warnings when running ipt lint
.
You can selectively include or exclude specific rules that should be checked
and/or applied. Using --include ruleName
you can include a rule and using
--exclude ruleName
you can exclude one. You can also apply multiple rules
using this argument multiple times or list multiple rules separated by a comma
like --include ruleName1,ruleName2
. If no rules are explicitely included,
all rules are included. If you want to have a list of all available rules you
can call ipt lint --list
.
Some of these linting rules support multiple features. You can think of them as
if they are multiple rules but closely related together, so it’s easier to
organize them as a single one. The generated error message will always contain
the rule name and the feature name in the form of ruleName:featureName
.
You can use the same format to include/exclude them using
--include ruleName:featureName
or --exclude ruleName:featureName
.
NOLINT
will be handled the same. If you want to specify all features of a
rule, you can use the rule name itself like --include ruleName
or use *
as the feature name like --include ruleName:*
.
If you want to see the full list of supported features of a rule, you can refer
to this documentation or call ipt lint --list ruleName
. The output will
always start with the pseudo feature *
.
Bugprone: contradicting /O
and /FREE
flag¶
Rule name |
|
---|---|
Fixable |
no |
Severity |
error |
Features |
none |
Many operations like Make
allow to create global resources that are located
in the current data folder or local ones which are not attached to any data
folder. Igor Pro has the convention that the operation flag /O
overrides the specified global resource if it exists, or creates a new one if
doesn’t. The operation flag /FREE
is used to create a resource that isn’t
attached to any data folder (e.g. a free wave).
If the user provides both flags, the behavior can be unexpected and prone to bugs.
Bugprone: loop initialization assignment¶
Rule name |
|
---|---|
Fixable |
no |
Severity |
warning |
Features |
none |
Igor supports multiple assignment operators that can be used in a for loop
initializer. We recommend that you only use the standard assignment using the
=
operator to prevent unintentional bugs in your code.
Function test(variable a)
for(a += 1; a < 10; a++)
// ^^^^^^
print a
endfor
End
Using other assignment operators other than =
will update the variable
depending on its original state, which can be misleading when initialising
variables in a for loop. Usually this place is used to set a loop variable to a
fixed state which is fully dependend on the expression on the right side of
=
.
Bugprone: Missing switch default case¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
warning |
Features |
none |
Every switch
and strswitch
statement should have at least one
default
case which handles all remaining cases. Even if the switch statement
handled all known cases it is always a good practice to handle the unknown error
case.
The default case has to have at least one statement. If you want to keep your
default case empty, you can always add a single break
statement. If you have
multiple cases which share the same code like your default case, you have to
list the default case last to keep it non empty.
Function test(variable a)
switch(a)
case 1:
print "one"
break
case 2:
print "two"
break
case 3:
case 4:
default:
print "many"
break
endswitch
End
The fixing routine of this rule adds a default case to the switch statement with
a single break statement and a // FIXME(BugproneMissingSwitchDefaultClause)
comment.
Function test(variable a)
switch(a)
default:
// FIXME(BugproneMissingSwitchDefaultClause)
break
endswitch
End
Bugprone: reserved keywords as identifier¶
Rule name |
|
---|---|
Fixable |
no |
Severity |
warning |
Features |
none |
Igor Pro historically allows the use of reserved keywords as the names of functions, macros, variables, strings, etc. The use of such keywords may cause conflicts in certain scenarios where the use of such names is not allowed, or may change the behavior in an unintended way. Therefore, it’s better not to use reserved keywords as identifiers at all.
The full list of reserved keywords are: as
, ASCII85Begin
,
ASCII85End
, break
, case
, catch
, char
, complex
,
Constant
, continue
, default
, define
, DFREF
, do
,
double
, elif
, else
, else
, elseif
, End
, endfor
,
endif
, EndMacro
, EndStructure
, endswitch
, endtry
, float
,
for
, FuncRef
, FUNCREF
, Function
, if
, ifdef
, ifndef
,
include
, Inf
, int
, int16
, int32
, int64
, int8
,
Macro
, Menu
, NaN
, NVAR
, override
, Picture
, pragma
,
Proc
, return
, static
, StrConstant
, string
, strswitch
,
STRUCT
, Structure
, SubMenu
, SVAR
, switch
, threadsafe
,
try
, uchar
, uint
, uint16
, uint32
, uint64
, uint8
,
undef
, variable
, vs
, WAVE
, while
and Window
.
Codestyle: default pragmas¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
error and warning |
Features |
none |
According to our coding conventions we recommend a set of default pragmas:
#pragma TextEncoding="UTF-8"
#pragma rtGlobals=3
#pragma rtFunctionErrors=1
If some pragmas are missing, this rule will add them to the start of the file. If the pragmas exists but set to a different value, this rule will just create a warning.
This rule will only create an error message, if the value type is incorrect
(e.g. an integer for #pragma TextEncoding
) or a different text encoding than
UTF-8
was set.
Codestyle: Empty line between code blocks¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
none |
Features |
none |
Ensure that there is at least a single empty line between each code blocks, such as a function or macro. A blank line is not added between pragmas, includes, and constants.
#pragma rtGlobals=3
#pragma rtFunctionErrors=1
#include "foo"
#include "bar"
Function foo()
End
Function bar()
End
#pragma rtGlobals=3
#pragma rtFunctionErrors=1
#include "foo"
#include "bar"
Function foo()
End
Function bar()
End
This rule will attach comments to the next code block when a new empty line is inserted.
Function foo()
End
// cmt
Function bar()
End
Function foo()
End
// cmt
Function bar()
End
Codestyle: #endif
comment¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
warning |
Features |
|
Ensures that the #endif
part of an #ifdef
or #ifndef
has a correct
comment assigned.
#ifdef Foo
Function test()
#ifndef Bar
print 1
#endif
End
#endif
#ifdef Foo
Function test()
#ifndef Bar
print 1
#endif // !Bar
End
#endif // Foo
If an #endif
already contained a comment, it will be replaced with the
expected one.
The feature CodeBlock
will search for all #ifdef
and #ifndef
in the
global scope outside of functions and macros and the feature Statement
will
only search inside functions and macros.
Codestyle: Fallthrough case require comment¶
Rule name |
|
---|---|
Fixable |
no |
Severity |
warning |
Features |
none |
Every case statement in switch control flow blocks where the code block
following the case line does not have a statement that exits the block must have
a comment that starts with fallthrough
. This comment is enforced such that
the developer has to explicitly express that fallthrough is intentional.
Running ipt lint
with --fix
will add a comment
FIXME(CodeStyleFallthroughCaseRequireComment)
to those cases that should be
marked as fallthrough cases but are not.
Function test(variable a)
switch(a)
case 1:
print "apple"
case 2:
case 3: // fallthrough
case 4: // fallthrough, some other comment
case 5:
print "banana"
break
endswitch
End
Function test(variable a)
switch(a)
case 1: // FIXME(CodeStyleFallthroughCaseRequireComment)
print "apple"
case 2: // FIXME(CodeStyleFallthroughCaseRequireComment)
case 3: // fallthrough
case 4: // fallthrough, some other comment
case 5:
print "banana"
break
endswitch
End
Note
At the current state of ipt’s development only the following statements are
detected at the top level of such code blocks: break
, continue
,
return
, Abort
, Quit
and IPT_NORETURN. If such exit
statement is nested in a an inner code block, like if, then it is not
detected as a statement that exits the current code block.
The conditional operations AbortOnValue
and AbortOnRTE
are not
detected as exit statements.
Codestyle: No fixme¶
Rule name |
|
---|---|
Fixable |
no |
Severity |
warning |
Features |
none |
Will report all FIXME
comments generated by ipt as a warning. This is
helpful to find all code locations that have not been fixed. New FIXME
comments generated by the current iteration of IPT won’t be reported as a
warning.
Fix old style function argument¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
warning |
Features |
none |
This rule searches for all Igor Pro 6 and earlier style function arguments and converts them into inline style which was introduced in Igor Pro 7.
Function test(a)
variable a
print a
End
Function test(variable a)
print a
End
If the declaration contains a comment at the end, it is considered as documentation for this argument and ipt won’t transform the function signature. It is up to you, to move this comment to the function documentation and rerun ipt again.
Fix empty line after function header¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
none |
Features |
none |
Ensures that after each function declaration we always have a single empty line. This is according to our coding conventions.
Function test(variable a)
print a
End
Function test(variable a)
print a
End
Readability: Else after return¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
warning |
Features |
none |
If an if statement has two or more branches and one of its branches contains a statement that exits the control flow (e.g. a return or IPT_NORETURN), it should be refactored to have only one branch that exits the control flow instead.
Let’s say we have the following example…
Function test(variable a)
if(a > 10)
return 1
else
print "small number"
endif
End
Considering the two if branches: One success part if the condition a > 10
succeeds and one else part if the condition failed. The success part of the if
condition exits the control flow with the return
keyword. This can be
refactored into a better readible version that has only one branch:
Function test(variable a)
if(a > 10)
return 1
endif
print "small number"
End
This rule can also be applied on large if statements with multiple elseifs.
Function test(variable a)
if(a < 10)
return 1
elseif(a < 20)
print 2
else
return 3
endif
End
Function test(variable a)
if(a < 10)
return 1
endif
if(a < 20)
print 2
else
return 3
endif
End
This rule won’t touch elseifs if the branch to a preceding condition doesn’t exit the current control flow.
Function test(variable a)
// will be unchanged and no warning messages will be generated
if(a < 10)
print "small number"
elseif(a < 20)
return 2
else
print "big number"
endif
End
The output of this rule has an additional benefit: The coverage data created by
igortest is more accurate and doesn’t contain an uncovered endif
at the
end of the function block.
This rule has two features and the following NOLINT
behavior:
ReadabilityElseAfterReturn:If
will be checked at the line of each if or elseif statement that has a code block that exits the control flow. If aNOLINT
was found at this place, it won’t be fixed and further checks for additional elseifs or else won’t be done.
Note
If you have multiple nested if statements, the rule is not applied
recursively on the result of the previous iteration. This is a
limitation of ipt and will be
addressed in a future release. It is recommended to rerun ipt lint
multiple times until there is no change in the output.
Readability: Missing Parenthesis¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
warning |
Features |
|
Igor Pro provides a list of operators that can be used to calculate the result
of an expression. Some of them are pretty common like addition +
or
multiplication *
and some are rarely used like left shift <<
or bitwise
xor %^
. All of them have their own priority assigned in which order they are
executed if no parenthesis are used. Some of these priorities are intuitive (see
PEMDAS, BODMAS, BIDMAS or BEDMAS) and some are not.
This linter rule enforces parenthesis for operators which priority are not intuitive and make it visible for all readers.
Original code |
Modified code |
Explanation |
---|---|---|
|
|
Will be unchanged as PEMDAS rules apply |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The listed features defines at which places this rule will be checked:
|
Will check both children of a binary expression for parenthesis |
---|---|
|
Will check a binary expression itself |
|
Will check the children of a |
|
Will check the children of a ternary expression |
Readability: One line variable initialization¶
Rule name |
|
---|---|
Fixable |
yes |
Severity |
warning |
Features |
none |
A single declaration line can contain multiple variable declarations and/or definitions.
Function test()
// line with multiple declarations
variable a, b
// line with multiple definitions
variable c = 1, d = 2
// mixed line
variable e, f = 3, g, h
End
This rule enforces that each definition is in their own line without any other definition or declaration. You can still list multiple declarations in one line.
If a line with multiple definitions or a mixed line ends with a comment, no fix is applied.