Static Analysis in R and for Bioconductor
Bioconductor TAB meeting 02/2026
February 5, 2026
Definition
Static code analysis and linting refer to the concept of detecting incorrect, suboptimal or dangerous code patterns without executing the code , only by analysing the code syntax tree.
Rationale
Static analysis:
may catch bugs early
may improve code readability, maintainability, performance
Benefits over testing
fast: even for packages doing heavy computations
safe: untrusted, potentially unsafe code, doesn’t need to be executed
robust: non-reproducible code or incomplete code (e.g., missing data) can be analyzed as long as it’s valid code.
Static analysis frameworks in the R ecosystem
R CMD check
✔
✔
✔
biocCheck
✔
❌
❌
rchk
❌
✔
❌
lintr ( / flir / jarl )
❌
❌
(✔ *)
*: during initial onboarding only
biocCheck
Focused on Bioconductor best practices.
Well-known to this group.
lintr
Not just style!
[1] "best_practices" "common_mistakes" "configurable"
[4] "consistency" "correctness" "default"
[7] "efficiency" "executing" "package_development"
[10] "pkg_testthat" "readability" "regex"
[13] "robustness" "style" "tidy_design"
lintr:: lint (
text = "length(x == 0)" ,
linters = lintr:: length_test_linter ()
)
::warning file=<text>,line=1,col=1::file=<text>,line=1,col=1,[length_test_linter] Checking the length of a logical vector is likely a mistake. Did you mean `length(x) == 0`?
lintr:: lint (
text = "x == NA" ,
linters = lintr:: equals_na_linter ()
)
::warning file=<text>,line=1,col=1::file=<text>,line=1,col=1,[equals_na_linter] Use is.na() instead of x == NA
lintr vs biocCheck
vapply() instead of sapply()
undesirable_function_linter()
seq_len() or seq_along() instead of 1:length()
seq_linter()
pkg:fun() instead of pkg::fun()
No
Download links to GitHub/GitLab/BitBucket
No
download.file() in onLoad()
No
paste() in condition messages
condition_message_linter()
message() instead of cat()/print()
print_linter()
<- instead of =
assignment_linter()
No .Deprecated/.Defunct/etc.
No
TRUE/FALSE instead of T/F
T_and_F_symbol_linter()
is() instead of class() ==
class_equals_linter()
sytem2() instead of system()
No
No set.seed()
No
No direct slot access (@)
No
No browser()
undesirable_function_linter()
No <<-
undesirable_operator_linter()
No Sys.setenv()
undesirable_function_linter()
No suppressWarnings()
No
All missing linters could very easily be implemented!
lintr vs biocCheck proposal
Opportunity: Cross-pollination between biocCheck and lintr:
reduce maintenance burden
increase user base (= more test cases, more feedback)
make Bioconductor checks available to the wider R community
Proposal: bioconductor category
lintr:: lint_package (linters = lintr:: linters_with_tags ("bioconductor" ))
R CMD check vs biocCheck
Some shared checks, such as:
Not necessarily an issue(?)
rchk: static analysis for C code in R packages
PROTECT() / UNPROTECT() balance and common mistakes in C code interacting with the R C API.
Additional resources:
rchk in CRAN & Bioconductor
Example in a recent submission:
> library(testthat)
> library(redacted)
>
> test_check("redacted")
Warning: stack imbalance in '::', 79 then 81
Warning: stack imbalance in '<-', 77 then 79
Warning: stack imbalance in '{', 73 then 75
Saving _problems/test-PlotExpression-83.R
[ FAIL 1 | WARN 0 | SKIP 0 | PASS 108 ]
Value of rchk for Bioconductor
Value for our community:
Available to individual developers as a Docker image or as a GitHub Action via R-hub
May be hard to set up
Upstream Docker image not compatible with latest Bioconductor releases
Bioconductor has a lot of native C code
Proposal 1: new checks on Bioconductor
R CMD check
✔
✔
✔
biocCheck
✔
❌
❌
rchk
💡
✔
❌
lintr ( / flir / jarl )
💡 (via biocCheck)
❌
(✔ *)
New runners for checks could be hosted at EMBL, since:
proposed checks are entirely independent from BBS
we already have a full copy of the sources
Proposal 2: integration of lintr in biocCheck
Share some code components between biocCheck and lintr:
reduce maintenance burden
increase user base (= more test cases, more feedback)
make Bioconductor checks available to the wider R community