Path to this page:
Subject: CVS commit: pkgsrc/devel/R-lintr
From: Makoto Fujiwara
Date: 2025-02-16 01:20:00
Message id: 20250216002000.C0F7CFBE0@cvs.NetBSD.org
Log Message:
(devel/R-lintr) Updated 3.1.2 to 3.2.0
# lintr (development version)
## Deprecations & breaking changes
* Various things marked deprecated since {lintr} 3.0.0 have been fully
deprecated. They will be completely removed in the subsequent
release. See previous NEWS for advice on how to replace them.
+ `source_file=` argument to `ids_with_token()` and `with_id()`.
+ Passing linters by name or as non-`"linter"`-classed functions.
+ `linter=` argument of `Lint()`.
+ `with_defaults()`.
+ Linters `closed_curly_linter()`, `open_curly_linter()`,
`paren_brace_linter()`, and `semicolon_terminator_linter()`.
+ Helper `with_defaults()`.
* `all_linters()` has signature `all_linters(..., packages)` rather
than `all_linters(packages, ...)` (#2332, @MichaelChirico). This
forces `packages=` to be supplied by name and will break users who
rely on supplying `packages=` positionally, of which we found none
searching GitHub.
* Adjusted various lint messages for consistency and readability
(#1330, @MichaelChirico). In general, we favor lint messages to be
phrased like "Action, reason" to put the "what" piece of \
the message
front-and-center. This may be a breaking change for code that tests
the specific phrasing of lints.
* `extraction_operator_linter()` is deprecated. Although switching
from `$` to `[[` has some robustness benefits for package code, it
can lead to non-idiomatic code in many contexts (e.g. R6 classes,
Shiny applications, etc.) (#2409, @IndrajeetPatil). One reason to
avoid `$` is that it allows partial matching where `[[` does
not. Use `options(warnPartialMatchDollar = TRUE)` to disable this
feature and restore some parity to using `$` vs. `[[`.
* `unnecessary_nested_if_linter()` is deprecated and subsumed into the
new/more general `unnecessary_nesting_linter()`.
* Dropped support for posting GitHub comments from inside GitHub
comment bot, Travis, Wercker, and Jenkins CI tools (spurred by
#2148, @MichaelChirico). We rely on GitHub Actions for linting in
CI, and don't see any active users relying on these alternatives. We
welcome and encourage community contributions to get support for
different CI systems going again.
* `cyclocomp_linter()` is no longer part of the default linters
(#2555, @IndrajeetPatil) because the tidyverse style guide doesn't
contain any guidelines on meeting certain complexity
requirements. With this, we also downgrade {cyclocomp} from
`Imports:` to `Suggests:`. Note that users with `cyclocomp_linter()`
; in their configs may now need to install {cyclocomp} intentionally,
in particular in CI/CD pipelines.
* `scalar_in_linter()` is now configurable to allow other `%in%`-like
operators to be linted. The data.table operator `%chin%` is no
longer linted by default; use `in_operators = "%chin%"` to continue
linting it. (@F-Noelle)
* `lint()` and friends now normalize paths to forward slashes on
Windows (@olivroy, #2613).
* `undesirable_function_linter()`, `undesirable_operator_linter()`,
and `list_comparison_linter()` were removed from the tag
`efficiency` (@IndrajeetPatil, #2655). If you use
`linters_with_tags("efficiency")` to include these linters, you'll
need to adjust your config to keep linting your code against
them. We did not find any such users on GitHub.
* Arguments `allow_cascading_assign=`, `allow_right_assign=`, and
`allow_pipe_assign=` to `assignment_linter()` are all deprecated in
favor of the new `operator=` argument. Usage of a positional first
argument like `assignment_linter(TRUE)`, of which we found zero
cases on GitHub, is totally deprecated to allow `operator=` to be
positionally first. See below about the new argument.
## Bug fixes
* `expect_identical_linter()` also skips `expect_equal()` comparison
to _negative_ non-integers like `-1.034` (#2411, @Bisaloo). This is
a parity fix since _positive_ reals have always been skipped because
"high-precision" comparisons are typically done to get tests within
`tolerance`, so `expect_identical()` is not a great substitution.
* `object_name_linter()` no longer errors when user-supplied
`regexes=` have capture groups (#2188, @MichaelChirico).
* `.lintr` config validation correctly accepts regular expressions
which only compile under `perl = TRUE` (#2375,
@MichaelChirico). These have always been valid (since
`rex::re_matches()`, which powers the lint exclusion logic, also
uses this setting), but the new up-front validation in v3.1.1
incorrectly used `perl = FALSE`.
* `.lintr` configs set by option `lintr.linter_file` or environment
variable `R_LINTR_LINTER_FILE` can point to subdirectories (#2512,
@MichaelChirico).
* `indentation_linter()` returns lints with `ranges[1L]==1L` when the
offending line has 0 spaces (#2550, @MichaelChirico).
* `literal_coercion_linter()` doesn't surface a warning about `NA`s
during coercion for code like `as.integer("a")` (#2566,
@MichaelChirico).
## Changes to default linters
* New default linter `return_linter()` for the style guide rule that
terminal returns should be left implicit (#1100, #2343, #2354, and
#2356, @MEO265 and @MichaelChirico).
## New and improved features
* New function node caching for big efficiency gains to most linters
(e.g. overall `lint_package()` improvement of 14-27% and core
linting improvement up to 30%; #2357, @AshesITR). Most linters are
written around function usage, and XPath performance searching for
many functions is poor. The new `xml_find_function_calls()` entry in
the `get_source_expressions()` output caches all function call nodes
instead. See the vignette on creating linters for more details on
how to use it.
* `Linter()` has a new argument `linter_level=` (default `NA`). This
is used by `lint()` to more efficiently check for expression levels
than the idiom `if (!is_lint_level(...)) { return(list()) }` (#2351,
@AshesITR).
* New `return_linter()` also has arguments for fine-tuning which
functions get linted:
+ `return_style=` (`"implicit"` by default) which checks that all
functions confirm to the specified return style of `"implicit"` or
`"explicit"` (#2271 and part of #884, @MichaelChirico, @AshesITR and
@MEO265).
+ `allow_implicit_else=` (default `TRUE`) which, when `FALSE`,
checks that all terminal `if` statements are paired with a
corresponding `else` statement (part of #884, @MichaelChirico).
+ `return_functions=` to customize which functions are equivalent to
`return()` as "exit" clauses, e.g. `rlang::abort()` can be
considered in addition to the default functions like `stop()` and
`q()` from base (#2271 and part of #884, @MichaelChirico and
@MEO265).
+ `except=` to customize which functions are ignored entirely (i.e.,
whether they have a return of the specified style is not checked;
#2271 and part of #884, @MichaelChirico and @MEO265). Namespace
hooks like `.onAttach()` and `.onLoad()` are always ignored.
+ `except_regex=`, the same purpose as `except=`, but filters
functions by pattern. This is motivated by {RUnit}, where test
suites are based on unit test functions matched by pattern,
e.g. `^Test`, and where explicit return may be awkward (#2335,
@MichaelChirico).
* `assignment_linter()` can be fully customized with the new
`operator=` argument to specify an exact vector of assignment
operators to allow (#2441, @MichaelChirico and @J-Moravec). The
default is `<-` and `<<-`; authors wishing to use `=` (only) for
assignment in their codebase can use `operator = "="`. This
supersedes several old arguments: to accomplish
`allow_cascading_assign=TRUE`, add `"<<-"` (and/or \
`"->>"`) to
`operator=`; for `allow_right_assign=TRUE`, add `"->"` (and/or
`"->>"`) to `operator=`; for `allow_pipe_assign=TRUE`, add \
`"%<>%"`
to `operator=`. Use `operator = "any"` to denote "ignore all
assignment operators"; in this case, only the value of
`allow_trailing=` matters. Implicit assignments with `<-` are always
ignored by `assignment_linter()`; use `implicit_assignment_linter()`
to handle linting these.
* More helpful errors for invalid configs (#2253, @MichaelChirico).
* `library_call_linter()` is extended
+ to encourage all packages to be attached with `library(symbol)`,
not `library("symbol", character.only = TRUE)` or "vectorized"
approaches looping over package names (part of #884,
@MichaelChirico).
+ to discourage many consecutive calls to `suppressMessages()` or
`suppressPackageStartupMessages()` (part of #884, @MichaelChirico).
* `unnecessary_lambda_linter()` is extended to encourage vectorized
comparisons where possible, e.g. `sapply(x, sum) > 0` instead of
`sapply(x, function(x) sum(x) > 0)` (part of #884,
@MichaelChirico). Toggle this behavior with argument
`allow_comparison=`.
* `backport_linter()` is slightly faster by moving expensive
computations outside the linting function (#2339, #2348, @AshesITR
and @MichaelChirico).
* `string_boundary_linter()` recognizes regular expression calls like
`grepl("^abc$", x)` that can be replaced by using `==` instead
(#1613, @MichaelChirico).
* `unreachable_code_linter()` has an argument `allow_comment_regex=`
for customizing which "terminal" comments to exclude (#2327,
@MichaelChirico). Exclusion comments from {lintr} and {covr}
(e.g. `# nocov end`) are always excluded.
* `format()` and `print()` methods for `lint` and `lints` classes get
a new option `width=` to control the printing width of lint messages
(#1884, @MichaelChirico). The default is controlled by a new option
`lintr.format_width`; if unset, no wrapping occurs (matching earlier
behavior).
* `implicit_assignment_linter()` gets a custom message for the case of
using `(` to induce printing like `(x <- foo())`; use an explicit
call to `print()` for clarity (#2257, @MichaelChirico).
* `todo_comment_linter()` has a new argument `except_regex=` for
setting _valid_ TODO comments, e.g. for forcing TODO comments to be
linked to GitHub issues like `TODO(#154)` (#2047, @MichaelChirico).
* `vector_logic_linter()` is extended to recognize incorrect usage of
scalar operators `&&` and `||` inside subsetting expressions like
`dplyr::filter(x, A && B)` (#2166, @MichaelChirico).
* `any_is_na_linter()` is extended to catch the unusual usage `NA %in%
x` (#2113, @MichaelChirico).
* `make_linter_from_xpath()` errors up front when `lint_message=` is
missing (instead of delaying this error until the linter is used,
#2541, @MichaelChirico).
* `paste_linter()` is extended to recommend using `paste()` instead of
`paste0()` for simply aggregating a character vector with
`collapse=`, i.e., when `sep=` is irrelevant (#1108,
@MichaelChirico).
* `expect_no_lint()` was added as new function to cover the typical
use case of expecting no lint message, akin to the recent {testthat}
functions like `expect_no_warning()` (#2580, @F-Noelle).
* `lint()` and friends emit a message if no lints are found (#2643,
@IndrajeetPatil).
* `commented_code_linter()` can detect commented code that ends with a
pipe (#2671, @jcken95)
### New linters
* `condition_call_linter()` for ensuring consistent use of `call.` in
`warning()` and `stop()`. The default `call. = FALSE` follows the
tidyverse guidance of not displaying the call (#2226, @Bisaloo)
* `sample_int_linter()` for encouraging `sample.int(n, ...)` over
equivalents like `sample(1:n, ...)` (part of #884, @MichaelChirico).
* `stopifnot_all_linter()` discourages tests with `all()` like
`stopifnot(all(x > 0))`; `stopifnot()` runs `all()` itself, and
signals a better error message (part of #884, @MichaelChirico).
* `comparison_negation_linter()` for discouraging negated comparisons
when a direct negation is preferable, e.g. `!(x == y)` could be `x
!= y` (part of #884, @MichaelChirico).
* `nzchar_linter()` for encouraging `nzchar()` to test for empty
strings, e.g. `nchar(x) > 0` can be `nzchar(x)` (part of #884,
@MichaelChirico).
* `terminal_close_linter()` for discouraging using `close()` to end
functions (part of #884, @MichaelChirico). Such usages are not
robust to errors, where `close()` will not be run as intended. Put
`close()` in an `on.exit()` hook, or use {withr} to manage
connections with proper cleanup.
* `rep_len_linter()` for encouraging use of `rep_len()` directly
instead of `rep(x, length.out = n)` (part of #884,
@MichaelChirico). Note that in older versions of R (e.g. pre-4.0),
`rep_len()` may not copy attributes as expected.
* `which_grepl_linter()` for discouraging `which(grepl(ptn, x))` in
favor of directly using `grep(ptn, x)` (part of #884,
@MichaelChirico).
* `list_comparison_linter()` for discouraging comparisons on the
output of `lapply()`, e.g. `lapply(x, sum) > 10` (part of #884,
@MichaelChirico).
* `print_linter()` for discouraging usage of `print()` on string
literals like `print("Reached here")` or `print(paste("Found",
nrow(DF), "rows."))` (#1894, @MichaelChirico).
* `unnecessary_nesting_linter()` for discouraging overly-nested code
where an early return or eliminated sub-expression (inside `{`) is
preferable (#2317, #2334 and part of #884, @MichaelChirico).
* `consecutive_mutate_linter()` for encouraging consecutive calls to
`dplyr::mutate()` to be combined (part of #884, @MichaelChirico).
* `if_switch_linter()` for encouraging `switch()` over repeated
`if`/`else` tests (#2322 and part of #884, @MichaelChirico).
* `nested_pipe_linter()` for discouraging pipes within pipes,
e.g. `df1 %>% inner_join(df2 %>% select(a, b))` (part of #884,
@MichaelChirico).
* `nrow_subset_linter()` for discouraging usage like `nrow(subset(x,
conditions))` in favor of something like `with(x, sum(conditions))`
which doesn't require a full subset of `x` (#2313, #2314 and part of
#884, @MichaelChirico).
* `pipe_return_linter()` for discouraging usage of `return()` inside a
{magrittr} pipeline (part of #884, @MichaelChirico).
* `one_call_pipe_linter()` for discouraging one-step pipelines like `x
|> as.character()` (#2330 and part of #884, @MichaelChirico).
* `object_overwrite_linter()` for discouraging re-use of upstream
package exports as local variables (#2344, #2346 and part of #884,
@MichaelChirico and @AshesITR).
### Lint accuracy fixes: removing false positives
* `object_name_linter()` and `object_length_linter()` ignore {rlang}
name injection like `x |> mutate("{new_name}" := foo(col))` (#1926,
@MichaelChirico). No checking is applied in such cases. {data.table}
in-place assignments like `DT[, "sPoNGeBob" := "friend"]` \
are still
eligible for lints.
* `object_usage_linter()` finds global variables assigned with `=` or
`->`, which avoids some issues around "undefined global variables"
in scripts (#2654, @MichaelChirico).
## Notes
* `{lintr}` now has a hex sticker
(https://github.com/rstudio/hex-stickers/pull/110). Thank you,
@gregswinehart!
* All user-facing messages (including progress bars) are now prepared
using the `{cli}` package (#2418 and #2641, @IndrajeetPatil). As
noted above, all messages have been reviewed and updated to be more
informative and consistent.
* File locations in lints and error messages contain clickable
hyperlinks to improve code navigation (#2645, #2588, @olivroy).
* {lintr} now depends on R version 4.0.0. It already does so
implicitly due to recursive upstream dependencies requiring this
version; we've simply made that dependency explicit and up-front
(#2569, @MichaelChirico).
* Some code with parameters accepting regular expressions is less
strict about whether there are capture groups (#2678,
@MichaelChirico). In particular, this affects
`unreachable_code_linter(allow_comment_regex=)` and
`expect_lint(checks=)`.
Files: