Walks the module's source via xmlparsedata, collects every reference to
sim$x / sim[["x"]] / get("x", envir = envir(sim)) and to parameters
(Par$x, P(sim)$x, params(sim)$mod$x), then compares those uses to
the module's defineModule() metadata. Reports any mismatches as a
structured tibble of findings, optionally printed as grouped tables.
Path to a module directory (containing <modName>/<modName>.R,
and optionally an R/ subfolder of helper scripts) or to a single .R
file. If a directory, the module name is the directory's basename.
Logical; print the grouped report. Default TRUE.
Optional character vectors of rule IDs to restrict
the run. See names(SpaDES.core:::.CC_RULES) for the catalogue.
A character vector of module directories (or .R files), as
accepted by path. Defaults to
dir(getOption("spades.modulePath"), full.names = TRUE).
codeCheckModule() returns a data.frame of findings (one row per
problem), invisibly; empty if the module is clean. codeCheckModules()
returns, invisibly, a named list of such data.frames (named by module).
This is the v2 implementation, selectable at simInit() time via
options(spades.codeCheckEngine = "v2") (the default). The legacy v1
checker is still available via options(spades.codeCheckEngine = "v1").
Each finding in the printed report is tagged with its rule id in
brackets, e.g. [conflicting_fn_unqualified]; that id (or the • <group>
name it is printed under) is what you reference to silence it. Findings can
be suppressed three ways (all honoured both here and during simInit()):
Inline # nolint (module developer). Put a # nolint comment on
the offending source line to silence every rule there, or
# nolint: <rule_id>[, <rule_id>] to silence only specific rules (a
group name such as globals is accepted in place of a rule id). For a
metadata finding such as in_no_default, place it anywhere within the
expectsInput() / createsOutput() / defineParameter() declaration,
e.g. expectsInput("cloudFolderID", "character", desc = "...") # nolint: in_no_default.
This travels with the module and documents the intent.
options(spades.codeChecksIgnore = ...) (module user). A named
list keyed by rule id (or group name) whose values are object names to
ignore, e.g.
options(spades.codeChecksIgnore = list(in_no_default = c("cloudFolderID", "ecoregionRst"))).
Lets someone running another author's module quiet specific findings
without editing its source.
options(spades.moduleCodeChecks = list(disable = ...)). Disable
whole rules by id (or restrict with enable = ...).
A related developer hint is # nolint: vars a, b: placed on a dynamic
bulk-assign line whose names can't be seen statically (e.g.
list2env(someList, envir(sim))), it asserts that objects a, b are
produced there, so they aren't reported as out_declared_unused.
The rule ids (printed in brackets in the report), grouped by the bucket they appear under:
inputObjects — in_declared_unused (declared input never used),
in_used_undeclared (sim$x read but not in inputObjects),
in_no_default (declared input has no default in .inputObjects()).
outputObjects — out_declared_unused (declared output never
assigned), out_used_undeclared (sim$x <- but not in outputObjects).
parameters — param_declared_unused, param_used_undeclared,
param_used_other_module.
module functions — must_return_sim (a doEvent.* must return
sim), must_assign_to_sim, module_named_object (sim$<module>
collides with the module name), clashing_module_fn.
globals — conflicting_fn_unqualified (a bare function name
collides with a raster:: namesake; qualify it, e.g. raster::scale).
unresolved — unresolved_accessor (an accessor whose name could
not be resolved statically).
codetools — codetools (findings relayed from
codetools::checkUsageEnv).
reqdPkgs — reqd_pkg_duplicate (a package declared more than
once in reqdPkgs, especially with conflicting source/version),
reqd_pkg_undeclared (a pkg::fn whose pkg is not in reqdPkgs),
reqd_pkg_no_source (best-effort, info: bare calls with no apparent
source among the declared packages — only when all declared packages are
installed).
codeCheckModule() checks a single module. codeCheckModules() is the
vectorized form: it runs codeCheckModule() on each path in paths and
returns a list of findings named by module. When paths is not supplied it
defaults to every module directory under getOption("spades.modulePath"),
so codeCheckModules() with no arguments checks the whole project. It
replaces the manual idiom
Map(codeCheckModule, dir(getOption("spades.modulePath"), full.names = TRUE)).