Lint Rules
fobis lint has 105 rules. Rules marked default run unless a selection is given; opt-in rules run only when selected (--select COR003, a prefix like --select COR, or ALL). Run fobis lint --explain <ID> for the same documentation in the terminal. How to run, select and suppress rules: Code quality.
Correctness (COR)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| COR001 | implicit-typing | warning | yes | C001 | A module, program or external procedure has no implicit none. |
| COR002 | interface-implicit-typing | warning | yes | C002 | An interface body has no implicit none. |
| COR003 | implicit-external-procedures | warning | opt-in | C003 | implicit none does not forbid implicit external procedures (implicit none (type, external)). |
| COR010 | missing-intent | warning | yes | C061 | A dummy argument has no intent. |
| COR011 | assumed-size | warning | yes | C071 | A dummy array is assumed-size (a(*), a(n,*)). |
| COR020 | initialisation-in-declaration | warning | yes | C081 | A procedure's local variable is initialised in its declaration, which implies save. |
| COR021 | pointer-initialisation-in-declaration | warning | yes | C082 | A procedure's local pointer is initialised in its declaration (=> null()), which implies save. |
| COR022 | missing-default-pointer-initialisation | warning | yes | C101 | A pointer component of a derived type has no default initialisation (=> null()). |
| COR030 | external-procedure | warning | yes | C091 | A procedure is declared external. |
| COR031 | procedure-not-in-module | warning | yes | C092 | A subroutine or function is defined outside a module (an external procedure). |
| COR040 | use-all | warning | yes | C121 | A use statement imports everything (no only: list). |
| COR041 | missing-intrinsic | warning | yes | C122 | An intrinsic module is used without the intrinsic keyword. |
| COR050 | missing-accessibility-statement | warning | yes | C131 | A module has no default accessibility statement (private or public). |
| COR060 | unchecked-stat | warning | yes | C181 | The stat= variable of an allocate/deallocate is never read afterwards. |
| COR061 | multiple-allocations-with-stat | warning | yes | C182 | One allocate/deallocate with stat= handles several objects. |
| COR062 | stat-without-errmsg | warning | opt-in | C183 | An allocate/deallocate has stat= but no errmsg=. |
| COR070 | missing-default-case | warning | yes | C011 | A select case construct has no case default. |
| COR071 | missing-class-default | warning | opt-in | - | A select type construct has no class default. |
| COR072 | missing-rank-default | warning | opt-in | - | A select rank construct has no rank default. |
| COR080 | magic-number-in-array-size | warning | opt-in | C031 | An array is declared with a literal size other than 0 or 1. |
| COR081 | magic-io-unit | warning | opt-in | C032 | An I/O statement uses a literal unit number. |
| COR082 | missing-action-specifier | warning | opt-in | C043 | An open statement has no action= specifier. |
| COR090 | missing-exit-or-cycle-label | warning | yes | C141 | An exit or cycle inside a named DO loop does not name the loop. |
| COR091 | exit-or-cycle-in-unlabelled-loop | warning | opt-in | C142 | An exit or cycle appears in a DO loop that has no construct name. |
| COR092 | missing-end-label | error | yes | C143 | The end statement of a named construct does not repeat the construct name. |
| COR100 | misleading-inline-if-semicolon | warning | yes | C151 | A statement follows a one-line if after a semicolon: it is not conditional. |
| COR101 | misleading-inline-if-continuation | warning | yes | C152 | A one-line if continues its action on the next line. |
| COR110 | nonportable-shortcircuit-inquiry | warning | yes | C161 | A condition tests present/allocated/associated and uses the same entity in one expression. |
| COR120 | unreachable-statement | warning | yes | C191 | A statement follows return, stop, exit, cycle or go to in the same block: it never runs. |
Obsolescent (OBS)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| OBS001 | common-block | warning | yes | OB011 | A common block. |
| OBS002 | equivalence-statement | warning | yes | OB012 | An equivalence statement. |
| OBS003 | block-data | warning | yes | OB013 | A block data program unit. |
| OBS004 | entry-statement | warning | yes | OB021 | An entry statement. |
| OBS005 | specific-intrinsic-name | warning | yes | OB031 | A specific intrinsic name (dsqrt, dabs, amax1, float ...) instead of the generic one. |
| OBS006 | computed-go-to | warning | yes | OB041 | A computed go to (l1, l2, ...), i. |
| OBS007 | pause-statement | warning | yes | OB051 | A pause statement. |
| OBS008 | deprecated-character-syntax | warning | yes | OB061 | Old-style character length character*n / character*(*). |
| OBS009 | forall | warning | yes | OB071 | A forall statement or construct. |
| OBS010 | arithmetic-if | warning | yes | OB081 | An arithmetic if (x) l1, l2, l3. |
| OBS011 | labelled-do-loop | warning | yes | OB091 | A labelled do 10 i = ... loop. |
| OBS012 | shared-do-termination | warning | yes | OB092 | Several do loops end on the same labelled statement. |
| OBS013 | bad-do-termination | warning | yes | OB093 | A labelled do loop ends on a statement other than continue or end do. |
| OBS014 | goto-end-do | warning | yes | OB094 | A go to jumps to the end do of a loop. |
| OBS020 | deprecated-mpi-include | warning | yes | OB201 | include 'mpif.h' instead of the mpi_f08 module. |
| OBS021 | deprecated-omp-include | warning | yes | OB211 | include 'omp_lib.h' instead of the omp_lib module. |
Modernisation (MDN)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| MDN001 | double-precision | warning | opt-in | MOD001 | A double precision (or double complex) declaration. |
| MDN002 | double-precision-literal | warning | opt-in | MOD002 | A double precision literal with exponent letter d (1.0d0). |
| MDN011 | old-style-array-constructor | warning | yes | MOD011 | An array constructor written (/ ... /) instead of [ ... ]. |
| MDN021 | deprecated-relational-operator | warning | yes | MOD021 | A relational operator written .eq., .ne., .lt., .le., .gt., .ge.. |
| MDN031 | include-statement | warning | opt-in | MOD031 | A Fortran include line. |
| MDN041 | out-of-line-attribute | warning | yes | MOD041 | An attribute given in a separate statement (dimension a(n), intent(in) :: x, parameter (...)). |
| MDN051 | superfluous-save | warning | yes | MOD051 | save in a module specification part. |
| MDN201 | old-mpi-module | warning | opt-in | MOD201 | use mpi instead of use mpi_f08. |
Portability (PRT)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| PRT011 | literal-kind | warning | yes | PORT011 | A kind given as a number in a type declaration (real(8), integer(kind=4)). |
| PRT012 | literal-kind-suffix | warning | yes | PORT012 | A literal with a numeric kind suffix (1.0_8, 10_4). |
| PRT021 | star-kind | warning | yes | PORT021 | A non-standard type*size declaration (real*8, integer*4). |
| PRT031 | invalid-tab | warning | yes | PORT031 | Tab characters in Fortran code (reported once per file). |
| PRT061 | non-portable-system-call | warning | opt-in | PORT061 | system() (a compiler extension) runs a shell command. |
| PRT062 | gfortran-random-extension | warning | opt-in | PORT062 | The extensions rand, srand, irand generate random numbers. |
Style (STY)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| STY001 | multiple-modules | warning | opt-in | S211 | A file defines more than one module or submodule. |
| STY002 | program-with-module | warning | opt-in | S212 | A file defines both a program and a module. |
| STY003 | function-missing-result | warning | opt-in | S221 | A function has no result(...) clause. |
| STY010 | inconsistent-array-declaration | warning | yes | S261 | A declaration has a dimension attribute and an entity with its own shape. |
| STY011 | mixed-scalar-array-declaration | warning | opt-in | S262 | One declaration statement declares both scalars and arrays. |
| STY020 | too-complex | warning | opt-in | S901 | A procedure's cyclomatic complexity exceeds 10. |
| STY021 | too-many-arguments | warning | opt-in | S902 | A procedure has more than 8 dummy arguments. |
Fortran practice (FOR)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| FOR001 | saved-local-in-parallel-procedure | warning | yes | - | A procedure that runs in parallel has a saved local variable (one copy shared by all threads). |
| FOR002 | loop-order-not-column-major | warning | opt-in | - | The innermost loop runs over a non-leading array dimension while an outer loop runs over the leading one. |
| FOR003 | lower-bounds-lost-in-assumed-shape | warning | opt-in | - | An array with non-default lower bounds is passed to an assumed-shape dummy: inside, its bounds restart at 1. |
| FOR004 | function-result-component | error | yes | - | A component of a function result is referenced directly: f(x)%c. |
| FOR005 | cpu-time-for-wall-clock | warning | yes | - | cpu_time measures time in code that runs in parallel (OpenMP, OpenACC, MPI). |
| FOR006 | array-of-finalizable-type-not-finalised | warning | yes | - | An array of a derived type with final procedures, none of which finalises arrays of that rank. |
| FOR007 | default-real-literal-precision-loss | warning | yes | - | A real literal without kind is assigned to a higher-precision real and cannot be represented in default precision. |
OpenMP (OMP)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| OMP001 | shared-scalar-written-in-parallel-region | warning | yes | - | A shared scalar is assigned inside an OpenMP parallel region: a data race. |
| OMP002 | accumulation-without-reduction | warning | yes | - | A shared scalar is accumulated inside an OpenMP parallel region without reduction. |
| OMP003 | collapse-imperfect-nest | error | yes | - | collapse(n) on OpenMP loops that are not tightly nested. |
| OMP004 | nowait-dependent-read | warning | opt-in | - | Data written by a nowait worksharing construct is read before the next barrier. |
| OMP005 | serialisation-in-innermost-loop | warning | yes | - | An OpenMP critical or atomic is inside the innermost loop of a parallel loop. |
| OMP006 | target-map-in-loop | warning | opt-in | - | An OpenMP target region inside a loop maps data on every iteration, with no target data around it. |
| OMP007 | mpi-in-threaded-region-without-thread-support | warning | yes | - | MPI is called inside an OpenMP parallel region but initialised with mpi_init, not mpi_init_thread. |
| OMP008 | implicit-target-map | warning | yes | - | The compiler maps data implicitly for an OpenMP target region (nvfortran: 'Generating implicit map'). |
OpenACC (ACC)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| ACC001 | implicit-data-movement | warning | yes | - | The compiler moves data implicitly for an OpenACC compute region (nvfortran: 'Generating implicit copy'). |
| ACC002 | atomic-in-compute-region | warning | yes | - | An !$acc atomic inside an OpenACC compute region or device routine. |
| ACC003 | firstprivate-associate-name | warning | yes | - | An associate name appears in an OpenACC firstprivate clause. |
| ACC004 | reduction-into-device-module-variable | error | yes | - | An OpenACC reduction targets a module allocatable declared !$acc declare create. |
| ACC005 | strided-section-argument-in-kernel | warning | yes | - | A non-contiguous section of a shared array is passed to a procedure inside OpenACC device code. |
| ACC006 | missing-acc-routine | warning | yes | - | A project procedure is called inside an OpenACC compute region but has no !$acc routine. |
| ACC007 | device-routine-assumed-shape-lower-bound | warning | opt-in | - | A device routine has an assumed-shape dummy with a non-default lower bound (q(0:), q(1-ng:)). |
| ACC008 | timer-without-acc-wait | warning | yes | - | A timer is read while asynchronous OpenACC work may still be running. |
| ACC009 | mpi-on-device-data-without-update | warning | opt-in | - | MPI sends or receives a device-resident array with no host update around the call and no host_data. |
| ACC010 | private-array-in-contained-kernel | info | opt-in | - | A compute region of a contained (internal) procedure has a private array. |
| ACC011 | acc-collapse-imperfect-nest | error | yes | - | collapse(n) on OpenACC loops that are not tightly nested. |
| ACC012 | sequential-device-loop | warning | yes | - | A loop in an OpenACC compute region runs sequentially: the compiler found a loop-carried dependence. |
MPI (MPI)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| MPI001 | request-never-completed | warning | yes | - | A non-blocking MPI operation stores its request in a local variable that is never completed. |
| MPI002 | isend-buffer-modified-before-completion | warning | yes | - | The buffer of a pending mpi_isend is written before the request is completed. |
| MPI003 | irecv-buffer-used-before-completion | warning | yes | - | The buffer of a pending mpi_irecv is used before the request is completed. |
| MPI004 | collective-in-rank-branch | warning | yes | - | An MPI collective is called inside a branch that depends on the rank. |
| MPI005 | blocking-send-before-receive | warning | opt-in | - | Every rank does a blocking mpi_send and then the matching mpi_recv: a deadlock for large messages. |
| MPI006 | any-source-order-dependent-sum | info | opt-in | - | Messages received from MPI_ANY_SOURCE are summed in arrival order: the result is not reproducible. |
Performance (PRF)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| PRF001 | loop-not-vectorized | info | opt-in | - | gfortran could not vectorise a loop (-fopt-info-vec-missed). |
Numerics (NUM)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| NUM001 | uncompensated-global-sum | info | opt-in | - | A diagnostic quantity (residual, norm, mass, energy ...) is summed across ranks with MPI_SUM. |
Linter (LNT)
| Rule | Name | Severity | Default | Fortitude | Reports |
|---|---|---|---|---|---|
| LNT001 | suppression-without-reason | warning | yes | - | An inline suppression ! fobis: ignore[ID] gives no reason. |
| LNT002 | unused-suppression | warning | yes | - | An inline suppression silences nothing. |
| LNT003 | unknown-rule-in-suppression | warning | yes | - | An inline suppression names a rule that does not exist. |
| LNT004 | preprocessor-assumption | info | yes | - | A preprocessor condition could not be evaluated and was assumed true. |
Relation to Fortitude
The generic rules (COR, OBS, MDN, PRT, STY) are a native reimplementation, in FoBiS's own words and on its own source analysis, of rules catalogued by Fortitude (PlasmaFAIR, MIT licence), whose rule set served as the reference. The Fortitude column gives the matching Fortitude code, for users who know it. FoBiS does not depend on Fortitude. The FOR, NUM, OMP, ACC, MPI and PRF rules are FoBiS's own, distilled from the OpenMP, OpenACC and MPI specifications and from HPC practice.
Not reimplemented: Fortitude's formatting rules (line length, whitespace, keyword case, quotes: formatters own them) and S263 (a project-configured preference between dimension(n) and x(n)). The thresholds of STY020 and STY021 are fixed (complexity 10, 8 arguments).