The Fortitude Linter
The Fortitude linter is a very fast Fortran linter heavily inspired by and built on the Ruff linter for Python. If you've ever used Ruff, Fortitude should feel very familiar.
fortitude check
fortitude check is the main feature of Fortitude, taking a list of files and/or
directories, and checking all discovered Fortran files for common (and less common!)
errors and style violations, optionally fixing any that are fixable. Fortitude searches
directories recursively for any Fortran files:
$ fortitude check # Lint Fortran files in current directory
$ fortitude check --fix # Lint and fix files in current directory
$ fortitude check path/to/source/ # Lint Fortran files in `path/to/source/`
You can see the list of all available options with fortitude check
--help.
Rule selection
The set of enabled rules is controlled via the check.select,
check.extend-select, and check.ignore settings.
Like Ruff and Flake8, Fortitude gives each rule a short code (for example, C003)
consisting of a one-to-three letter prefix (for the category) followed by three
digits. Fortitude also gives each rule a more human-readable English name, such as
implicit-external-procedures, which can always be used instead of the short code in
places like check.select and check.ignore.
Rule selectors like check.select and check.ignore
accept any combination of the following:
- category prefixes like
C, - category names like
correctness, - rule short codes like
C003, - rule names like
implicit-external-procedures.
For example, in the following configuration file:
Fortitude would enable all rules in the correctness (C) and style (S) categories,
except for implicit-external-procedures (C003) and line-too-long (S001).
Like Ruff, Fortitude also has the special ALL code, which enables all rules. This should
be used with discretion as it will implicitly enable any new rules whenever you upgrade
Fortitude.
As a guideline, prefer using check.select over
check.extend-select to make your rule set explicit in your
configuration file.
Setting --select on the command line will override
check.select in the configuration file. For example, given the
configuration file above, running fortitude check --select S001 will select only
S001 (line-too-long).
If instead you want to select additional rules from the command line, use
--extend-select. Running fortitude check --extend-select
obsolescent in combination with the settings file above will result in Fortitude
enforcing all rules in the correctness, style, and obsolescent categories, except
for C003 and S001.
Preview rules
New rules and other features may be in 'preview' mode while they undergo further review
and testing. To activate them, use the --preview flag:
For more details on how preview works, see Preview.
Fixes
For some lint errors, Fortitude supports automatic fixes, such as rewriting some deprecated syntax, remove/add whitespace, add missing construct names, and so on.
To apply these fixes, pass --fix to fortitude check:
To see which rules Fortitude can automatically fix, see Rules.
You can use the --diff flag to see exactly what Fortitude would change:
$ fortitude check --diff
--- test.f90
+++ test.f90
@@ -1,5 +1,6 @@
subroutine test()
use, intrinsic :: iso_fortran_env, dp => real64
- real(kind=dp) x, y
+ real(kind=dp) :: x, y
y = ASIN(x)
Would fix 1 error.
Indentation
For rules such as superfluous-else-return, where the fix may
move code out of the else branch of an if statement for example,
Fortitude will also attempt to fix the indentation of the moved code. This
can be hampered by tab characters (but see invalid-tab),
or "under-indented" code, comments, or continuation characters. We will give
a "best effort" formatting of the code in these cases, but Fortitude will
always make sure that the code remains syntactically and semantically valid.
Fix safety
Another concept Fortitude borrows from Ruff is that of fix safety: fixes are labelled as either "safe" or "unsafe". Safe fixes will not change the meaning or intent of your code, while unsafe fixes may change the meaning.
For example, implicit-typing (C001) checks for missing
implicit none statements, common in older code, and a frequent source of bugs. However,
for codes that are relying on implicit typing, this is not a sufficient fix (as variables
will need to be explicitly declared as well), so it is not always safe to apply.
Fortitude only enables safe fixes by default. Unsafe fixes can be enabled by settings
unsafe-fixes in your configuration file or passing the
--unsafe-fixes flag to fortitude check:
# Show unsafe fixes
fortitude check --unsafe-fixes
# Apply unsafe fixes
fortitude check --fix --unsafe-fixes
By default, Fortitude will display a hint when unsafe fixes are available but not
enabled. The suggestion can be silenced by setting the
unsafe-fixes setting to false or using the
--no-unsafe-fixes flag.
Error suppression
Fortitude has several ways of suppressing lint errors, whether they're false positives or permissible in context.
To globally ignore a rule, add it to the check.ignore list,
either on the command line for a one-off check, or in your configuration file
for a more permanent suppression for a project.
For slightly more fine-grained control, rules can be ignored for individual files through
the check.per-file-ignores setting in your
configuration file.
For the most fine-grained control, rules can be suppressed in the source code too, which
is useful for allowing individual exceptions for whatever reason. Fortitude deviates from
how Ruff works here, and instead uses something like Rust's
approach, by using an
allow or "suppression" comment before the statement. This allow comment then applies
to the whole of the next statement, which could be an entire module, for example:
! allow(superfluous-implicit-none)
module numbers
! allow(use-all)
use, intrinsic :: iso_fortran_env
implicit none
contains
subroutine greater_than_five(x)
use some_other_module
implicit none
...
Here, the superfluous-implicit-none check is disabled for all procedures in the whole
numbers module, including in greater_than_five, while use-all is disabled
only for the iso_fortran_env import and will still apply to some_other_module.
Multiple rules can be in an allow comment, separated by commas, and you can use the
typical rule selection naming:
will allow all style and modernisation rules, as well as FORT002
(unused-allow-comment) and implicit-real-kind (C022).
Unused allow comments
By default, Fortitude will detect "unused" allow comments via
unused-allow-comment: that is, if a suppression comment
says it allows a given warning, then the statement(s) it applies to should generate
those warnings (and then be allowed by the comment).
Fortitude can automatically remove unused allow comments.
You can also temporarily ignore these suppression comments with --ignore-allow-comments
on the command line.
Running fortitude on only modified files
Introduced in 0.9.0
Rather than running Fortitude on all the files in a project, you may wish to restrict it to only those files which have been modified, for example when starting to use Fortitude on an existing project. For this, there are two command line flags you can use:
--git-stagedwill only run Fortitude on those lines in files which have been staged in a git repository--git-since <commit>will run Fortitude on lines in files have been modified since the given commit/branch/reference -- for example,main,01c34f,HEAD~
There is also --line-filter for advanced users, which lets you specify exactly
which lines of which files to run on.
These flags work with the passed set of paths, so it's possible to filter to files that have been staged in a given directory, for example:
# Run only on lines in files in `subdir` that have been staged
$ fortitude check --git-staged subdir/
# Run only on those lines in `foo.f90` that have been modified since `main`
$ fortitude check --git-since main foo.f90
Learning more about a rule
The explain command can be used to get extra information about any rules. Without any
arguments, it returns information on all rules; otherwise you can pass it any number of
rules or categories, following the usual rule selection
naming:
# Print extra information for all rules
$ fortitude explain
# Only get information for selected rules, by code or by name
$ fortitude explain C001 trailing-whitespace
# Print information on all style rules
$ fortitude explain style
Exit codes
By default, fortitude check exits with the following status codes:
0if no violations were found, or if all present violations were fixed automatically.1if violations were found.2if Fortitude terminates abnormally due to invalid configuration, invalid CLI options, or an internal error.
This convention mirrors that of tools like ESLint, Prettier, and RuboCop.
fortitude check supports two command-line flags that alter its exit code behavior:
--exit-zerowill cause Fortitude to exit with a status code of0even if violations were found. Note that Fortitude will still exit with a status code of2if it terminates abnormally.--exit-non-zero-on-fixwill cause Fortitude to exit with a status code of1if violations were found, even if all such violations were fixed automatically. Note that the use of--exit-non-zero-on-fixcan result in a non-zero exit code even if no violations remain after fixing.