Path to this page:
Subject: CVS commit: pkgsrc/devel/R-lintr
From: Makoto Fujiwara
Date: 2024-01-21 03:37:52
Message id: 20240121023752.7398FFA42@cvs.NetBSD.org
Log Message:
(devel/R-lintr) Updated 3.0.2 to 3.1.1
# lintr 3.1.1
## Breaking changes
* `infix_spaces_linter()` distinguishes `<-`, `:=`, `<<-` and `->`,
`->>`, i.e. `infix_spaces_linter(exclude_operators = "->")` \
will no
longer exclude `->>` (#2115, @MichaelChirico). This change is
breaking for users relying on manually-supplied `exclude_operators`
containing `"<-"` to also exclude `:=` and `<<-`. The fix is to
manually supply `":="` and `"<<-"` as well. We don't \
expect this
change to affect many users, the fix is simple, and the new behavior
is much more transparent, so we are including this breakage in a
minor release.
* Removed `find_line()` and `find_column()` entries from
`get_source_expressions()` expression-level objects. These have been
marked deprecated since version 3.0.0. No users were found on
GitHub.
* There is experimental support for writing config in plain R scripts
(as opposed to DCF files; #1210, @MichaelChirico). The script is run
in a new environment and variables matching settings
(`?default_settings`) are copied over. In particular, this removes
the need to write R code in a DCF-friendly way, and allows normal R
syntax highlighting in the saved file. We may eventually deprecate
the DCF approach in favor of this one; user feedback is welcome on
strong preferences for either approach, or for a different approach
like YAML. Generally you should be able to convert your existing
`.lintr` file to an equivalent R config by replacing the `:`
key-value separators with assignments (`<-`). By default, such a
config is searched for in a file named '.lintr.R'. This is a mildly
breaking change if you happened to be keeping a file '.lintr.R'
around since that file is given precedence over '.lintr'.
+ We also validate config files up-front make it clearer when
invalid configs are present (#2195, @MichaelChirico). There is a
warning for "invalid" settings, i.e., settings not part of
`?default_settings`. We think this is more likely to affect users
declaring settings in R, since any variable defined in the config
that's not a setting must be removed to make it clearer which
variables are settings vs. ancillary.
## Bug fixes
* `sprintf_linter()` doesn't error in cases where whitespace in `...`
arguments is significant, e.g. `sprintf("%s", if (A) "" \
else y)`,
which won't parse if whitespace is removed (#2131, @MichaelChirico).
## Changes to default linters
* `assignment_linter()` lints the {magrittr} assignment pipe `%<>%`
(#2008, @MichaelChirico). This can be deactivated by setting the new
argument `allow_pipe_assign` to `TRUE`.
* `object_usage_linter()`:
+ assumes `glue()` is `glue::glue()` when `interpret_glue=TRUE`
(#2032, @MichaelChirico).
+ finds function usages, including infix usage, inside `glue()`
calls to avoid false positives for "unused objects" (#2029 and
#2069, @MichaelChirico).
* `object_name_linter()` no longer attempts to lint strings in
function calls on the LHS of assignments (#1466, @MichaelChirico).
* `infix_spaces_linter()` allows finer control for linting `=` in
different scenarios using parse tags `EQ_ASSIGN`, `EQ_SUB`, and
`EQ_FORMALS` (#1977, @MichaelChirico).
* `equals_na_linter()` checks for `x %in% NA`, which is a more
convoluted form of `is.na(x)` (#2088, @MichaelChirico).
## New and improved features
* New exclusion sentinel `# nolint next` to signify the next line
should skip linting (#1791, @MichaelChirico). The usual rules apply
for excluding specific linters, e.g. `# nolint next:
assignment_linter.`. The exact string used to match a
subsequent-line exclusion is controlled by the `exclude_next` config
entry or R option `"lintr.exclude_next"`.
* New `xp_call_name()` helper to facilitate writing custom linters
(#2023, @MichaelChirico). This helper converts a matched XPath to
the R function to which it corresponds. This is useful for including
the "offending" function in the lint's message.
* New `make_linter_from_xpath()` to facilitate making simple linters
directly from a single XPath (#2064, @MichaelChirico). This is
especially helpful for making on-the-fly/exploratory linters, but
also extends to any case where the linter can be fully defined from
a static lint message and single XPath.
* Toggle lint progress indicators with argument `show_progress` to
`lint_dir()` and `lint_package()` (#972, @MichaelChirico). The
default is still to show progress in `interactive()`
sessions. Progress is also now shown with a "proper" progress bar
(`utils::txtProgressBar()`), which in particular solves the issue of
progress `.` spilling well past the width of the screen in large
directories.
* `lint()`, `lint_dir()`, and `lint_package()` fail more gracefully
when the user mis-spells an argument name (#2134, @MichaelChirico).
* Quarto files (.qmd) are included by `lint_dir()` by default (#2150, @dave-lovell).
### New linters
* `library_call_linter()` can detect if all library/require calls are
not at the top of your script (#2027, #2043, #2163, and #2170,
@nicholas-masel and @MichaelChirico).
* `keyword_quote_linter()` for finding unnecessary or discouraged
quoting of symbols in assignment, function arguments, or extraction
(part of #884, @MichaelChirico). Quoting is unnecessary when the
target is a valid R name, e.g. `c("a" = 1)` can be `c(a = 1)`. The
same goes to assignment (`"a" <- 1`) and extraction \
(`x$"a"`). Where
quoting is necessary, the linter encourages doing so with backticks
(e.g. `` x$`a b` `` instead of `x$"a b"`).
* `length_levels_linter()` for using the specific function `nlevels()`
instead of checking `length(levels(x))` (part of #884,
@MichaelChirico).
* `scalar_in_linter()` for discouraging `%in%` when the right-hand
side is a scalar, e.g. `x %in% 1` (part of #884, @MichaelChirico).
* `if_not_else_linter()` for encouraging `if` statements to be
structured as `if (A) x else y` instead of `if (!A) y else x` (part
of #884, @MichaelChirico).
* `repeat_linter()` for encouraging `repeat` for infinite loops
instead of `while (TRUE)` (#2106, @MEO265).
* `length_test_linter()` detects the common mistake `length(x == 0)`
which is meant to be `length(x) == 0` (#1991, @MichaelChirico).
### Extensions to existing linters
* `fixed_regex_linter()` gains an option `allow_unescaped` (default
`FALSE`) to toggle linting regexes not requiring any escapes or
character classes (#1689, @MichaelChirico). Thus
`fixed_regex_linter(allow_unescaped = TRUE)` would lint on
`grepl("[$]", x)` but not on `grepl("a", x)` since the \
latter does
not use any regex special characters.
* `line_length_linter()` helpfully includes the line length in the
lint message (#2057, @MichaelChirico).
* `conjunct_test_linter()` also lints usage like `dplyr::filter(x, A &
B)` in favor of using `dplyr::filter(x, A, B)` (part of #884; #2110
and #2078, @salim-b and @MichaelChirico). Option `allow_filter`
toggles when this applies. `allow_filter = "always"` drops such
lints entirely, while `"not_dplyr"` only lints calls explicitly
qualified as `dplyr::filter()`. The default, `"never"`, assumes all
unqualified calls to `filter()` are `dplyr::filter()`.
* `sort_linter()` checks for code like `x == sort(x)` which is better
served by using the function `is.unsorted()` (part of #884,
@MichaelChirico).
* `paste_linter()` gains detection for file paths that are better
constructed with `file.path()`, e.g. `paste0(dir, "/", file)` would
be better as `file.path(dir, file)` (part of #884, #2082,
@MichaelChirico). What exactly gets linted here can be fine-tuned
with the `allow_file_path` option (`"double_slash"` by default, with
alternatives `"never"` and `"always"`). When \
`"always"`, these rules
are ignored. When `"double_slash"`, paths appearing to construct a
URL that have consecutive forward slashes (`/`) are skipped. When
`"never"`, even URLs should be constructed with `file.path()`.
* `seq_linter()` recommends `rev()` in the lint message for lints like
`nrow(x):1` (#1542, @MichaelChirico).
* `function_argument_linter()` detects usage of `missing()` for the
linted argument (#1546, @MichaelChirico). The simplest fix for
`function_argument_linter()` lints is typically to set that argument
to `NULL` by default, in which case it's usually preferable to
update function logic checking `missing()` to check `is.null()`
instead.
* `commas_linter()` gains an option `allow_trailing` (default `FALSE`)
to allow trailing commas while indexing. (#2104, @MEO265)
* `unreachable_code_linter()`
+ checks for code inside `if (FALSE)` and other conditional loops
with deterministically false conditions (#1428, @ME0265).
+ checks for unreachable code inside `if`, `else`, `for`, `while`,
and `repeat` blocks, including combinations with `break` and `next`
statements. (#2105, @ME0265).
* `implicit_assignment_linter()` gains an argument `allow_lazy`
(default `FALSE`) that allows optionally skipping lazy assignments
like `A && (B <- foo(A))` (#2016, @MichaelChirico).
* `unused_import_linter()` gains an argument `interpret_glue` (default
`TRUE`) paralleling that in `object_usage_linter()` to toggle
whether `glue::glue()` expressions should be inspected for exported
object usage (#2042, @MichaelChirico).
* `default_undesirable_functions` is updated to also include
`Sys.unsetenv()` and `structure()` (#2192 and #2228, @IndrajeetPatil
and @MichaelChirico).
* Linters with logic around the magrittr pipe `%>%` consistently apply
it to the other pipes `%!>%`, `%T>%`, `%<>%` (and possibly `%$%`)
where appropriate (#2008, @MichaelChirico).
+ `brace_linter()`
+ `pipe_call_linter()`
+ `pipe_continuation_linter()`
+ `unnecessary_concatenation_linter()`
+ `unnecessary_placeholder_linter()`
* Linters with logic around function declarations consistently include
the R 4.0.0 shorthand `\()` (#2190, @MichaelChirico).
+ `brace_linter()`
+ `function_left_parentheses_linter()`
+ `indentation_linter()`
+ `object_length_linter()`
+ `object_name_linter()`
+ `package_hooks_linter()`
+ `paren_body_linter()`
+ `unnecessary_lambda_linter()`
+ `unreachable_code_linter()`
### Lint accuracy fixes: removing false positives
* `fixed_regex_linter()`
+ Is pipe-aware, in particular removing false positives around
piping into {stringr} functions like `x |> str_replace(fixed("a"),
"b")` (#1811, @MichaelChirico).
+ Ignores non-string inputs to `pattern=` as a keyword argument
(#2159, @MichaelChirico). * Several linters avoiding false positives
in `$` extractions get the same exceptions for `@` extractions,
e.g. `S4@T` will no longer throw a `T_and_F_symbol_linter()` hit
(#2039, @MichaelChirico).
+ `T_and_F_symbol_linter()`
+ `for_loop_index_linter()`
+ `literal_coercion_linter()`
+ `object_name_linter()`
+ `undesirable_function_linter()`
+ `unreachable_code_linter()`
+ `yoda_test_linter()`
* `sprintf_linter()` is pipe-aware, so that `x %>% sprintf(fmt =
"%s")` no longer lints (#1943, @MichaelChirico).
* `condition_message_linter()` ignores usages of extracted calls like
`env$stop(paste(a, b))` (#1455, @MichaelChirico).
* `inner_combine_linter()` no longer throws on length-1 calls to `c()`
like `c(exp(2))` or `c(log(3))` (#2017, @MichaelChirico). Such usage
is discouraged by `unnecessary_concatenation_linter()`, but
`inner_combine_linter()` _per se_ does not apply.
* `sort_linter()` only lints on `order()` of a single vector,
excluding e.g. `x[order(x, y)]` and `x[order(y, x)]` (#2156,
@MichaelChirico).
* `redundant_ifelse_linter()` is aware of `dplyr::if_else()`'s
`missing=` argument, so that `if_else(A, TRUE, FALSE, missing =
FALSE)` doesn't lint, but `if_else(A, TRUE, FALSE, NA)` does (#1941,
@MichaelChirico). Note that `dplyr::coalesce()` or
`tidyr::replace_na()` may still be preferable.
### Lint accuracy fixes: removing false negatives
* `unreachable_code_linter()` finds unreachable code even in the
presence of a comment or semicolon after `return()` or `stop()`
(#2127, @MEO265).
* `implicit_assignment_linter()`
+ finds assignments in call arguments besides the first one (#2136, \
@MichaelChirico).
+ finds assignments in parenthetical expressions like `if (A && (B
<- foo(A))) { }` (#2138, @MichaelChirico).
* `unnecessary_lambda_linter()` checks for cases using explicit
returns, e.g. `lapply(x, \(xi) return(sum(xi)))` (#1567,
@MichaelChirico).
+ thanks to @Bisaloo and @strengejacke for detecting a regression in the \
original fix (#2231, #2247).
# lintr 3.1.0
## Deprecations & Breaking Changes
* `.lintr` files can now be kept in the directory `.github/linters`
for better compatibility with Super-Linter. Note that this may be a
breaking change if you already have a config in `.github/linters`
inside a subdirectory as well as in your R project's root, since the
former will now be discovered first where it was ignored
before. Please see `vignette("lintr")` for details on how configs
are discovered (#1746, @tonyk7440 and @klmr).
* `single_quotes_linter()` is deprecated in favor of the more
generalizable `quotes_linter()` (#1729, @MichaelChirico).
* `unneeded_concatentation_linter()` is deprecated in favor of
`unnecessary_concatenation_linter()` for naming consistency (#1707,
@IndrajeetPatil).
* `consecutive_stopifnot_linter()` is deprecated in favor of the more
general (see below) `consecutive_assertion_linter()` (#1604,
@MichaelChirico).
* `no_tab_linter()` is deprecated in favor of `whitespace_linter()`
for naming consistency and future generalization (#1954,
@MichaelChirico).
* `available_linters()` prioritizes `tags` over `exclude_tags` in the
case of overlap, i.e., tags listed in both arguments are included,
not excluded. We don't expect many people to be affected by this,
and the old behavior was not made explicit in the documentation, but
make note of it here since it required changing a test in lintr's
own suite where `linters_with_tags()` implicitly assumed this
behavior.
* `lint()`, `lint_dir()`, and `lint_package()` no longer accept
certain arguments (`cache=` for `lint()`, `relative_path=` for the
latter two) positionally. The `warning()` since 3.0.0 has been
upgraded to an error.
## Bug fixes
* `linters_with_tags()` now includes the previously missing spaces
around "and" when listing missing linters advertised by
`available_linters()`. This error message may appear e.g. when you
update lintr to a version with new linters but don't restart your R
session (#1946, @Bisaloo)
* `fixed_regex_linter()` is more robust to errors stemming from
unrecognized escapes (#1545, #1845, @IndrajeetPatil).
* `get_source_expressions()` can handle Sweave/Rmarkdown documents
with reference chunks like `<<ref_file>>` (#779, @MichaelChirico).
Note that these are simply skipped, rather than attempting to
retrieve the reference and also lint it.
* `assignment_linter()` no longer lints assignments in braces that
include comments when `allow_trailing = FALSE` (#1701, @ashbaldry)
* `object_usage_linter()`
+ No longer silently ignores usage warnings that don't contain a
quoted name (#1714, @AshesITR)
+ No longer fails on code with comments inside a multi-line call to
`glue::glue()` (#1919, @MichaelChirico)
* `namespace_linter()` correctly recognizes backticked operators to be
exported from respective namespaces (like `` rlang::`%||%` ``)
(#1752, @IndrajeetPatil)
* `lint_package()` correctly finds a package from within a subdir if
the `path` points to anywhere within the package (#1759, @AshesITR)
* Improved error behavior in `Lint()`, `lint()` and
`xml_nodes_to_lints()` (#1427, #763, @AshesITR) + `Lint()` validates
its inputs more thoroughly, preventing errors during `print.Lints`
like "Error in rep.int(character, length) : invalid 'times' value:".
+ `lint()` no longer tries to create an expression tree with
unexpected end of input errors, because they can be broken. +
`xml_nodes_to_lints()` warns if it can't find lint locations and
uses dummy locations as a fallback.
* `linters_with_defaults()` no longer erroneously marks linter
factories as linters (#1725, @AshesITR).
* Row names for `available_linters()` data frame are now contiguous
(#1781, @IndrajeetPatil).
* `object_name_linter()` allows all S3 group Generics (see
`?base::groupGeneric`) and S3 generics defined in a different file
in the same package (#1808, #1841, @AshesITR)
* `object_usage_linter()` improves identification of the exact source of a lint
+ for undefined variables in expressions with where the variable is
used as a symbol in a usual way, for example in a formula or in an
extraction with `$` (#1914, @MichaelChirico).
+ for general usage warnings without location info (#1986 and #1917, @AshesITR)
* `function_left_parentheses_linter()` produces a more specific lint
(and no longer fails) when the opening parenthesis is on a different
line than `function` or the call name (#1953,
@MichaelChirico). Thanks also to @IndrajeetPatil and @lorenzwalthert
for identifying a regression in the initial fix, #1963.
## Changes to defaults
* Set the default for the `except` argument in
`duplicate_argument_linter()` to `c("mutate", \
"transmute")`. This
allows sequential updates like `x |> mutate(a = b + 1, a = log(a))`
(#1345, @IndrajeetPatil).
* `object_usage_linter()`
+ gains `skip_with` argument to skip code in `with()`
expressions. To be consistent with `R CMD check`, it defaults to
`TRUE` (#941, #1458, @IndrajeetPatil).
+ Handles backticked symbols inside {glue} expressions correctly,
e.g. ``glue("{`x`}")`` correctly determines `x` was used (#1619,
@MichaelChirico)
+ Detects problems inside R4.1.0+ lambda functions (`\(...)`) (#1933, \
@MichaelChirico)
* `spaces_inside_linter()` allows terminal missing keyword arguments
(e.g. `alist(arg = )`; #540, @MichaelChirico)
* `brace_linter()` allows empty braced expression on the same line
(e.g. `while (updating_condition()) { }`) regardless of
`allow_single_line` to match the corresponding behavior in
{styler}. This is an expedient while the style guide on handling
this case awaits clarification:
https://github.com/tidyverse/style/issues/191. (#1346,
@MichaelChirico)
* `undesirable_function_linter()` and `undesirable_operator_linter()`
now produce an error if empty vector of undesirable functions or
operators is provided (#1867, @IndrajeetPatil).
* New linters which are also included as defaults (see "New linters" \
for more details):
+ `indentation_linter()`
+ `quotes_linter()`
+ `unnecessary_concatenation_linter()`
+ `whitespace_linter()`
* `lint_package()` also looks for files in `exec/` (#1950, @jmaspons).
## New and improved features
* New `get_r_string()` helper to get the R-equivalent value of a
string, especially useful for R-4-style raw strings. Previously an
internal `lintr` helper, now exported to facilitate writing custom
linters (#1493, @MichaelChirico).
* `object_usage_linter()` improves lint metadata when detecting
undefined infix operators, e.g. `%>%` or `:=` (#1497,
@MichaelChirico)
* `unused_import_linter()` can detect datasets from imported packages
and no longer warns when a package is imported only for its datasets
(#1545, @IndrajeetPatil).
* When a linter triggers an error, `lint()` will provide a more
actionable summary of where the error occurred, particularly useful
for cases like `lint_package()` where both the responsible file and
the responsible linter would be unknown (@MichaelChirico).
Typically, linters should not themselves cause R to stop -- syntax
errors lead to error lints, for example. Please report such failures
as they are likely bugs.
* `pipe_continuation_linter()` recognizes violations involving the
native R pipe `|>` (#1609, @MichaelChirico)
* `paste_linter()` also catches usages like `paste(rep("*", 10L),
collapse = "")` that can be written more concisely as \
`strrep("*",
10L)` (#1108, @MichaelChirico)
* `spaces_inside_linter()` produces lints for spaces inside `[[`
(#1673, @IndrajeetPatil).
* `sprintf_linter()` also applies to `gettextf()` (#1677,
@MichaelChirico)
* Documentation for all linters contains examples of code that does
and does not produce lints (#1492, @IndrajeetPatil).
* `implicit_integer_linter()` gains parameter `allow_colon` to skip
lints on expressions like `1:10` (#1155, @MichaelChirico)
* `infix_spaces_linter()` supports the native R pipe `|>` (#1793, @AshesITR)
* `unnecessary_concatenation_linter()`
(f.k.a. `unneeded_concatenation_linter()`) no longer lints on
`c(...)` (i.e., passing `...` in a function call) when
`allow_single_expression = FALSE` (#1696, @MichaelChirico)
* `object_name_linter()` gains parameter `regexes` to allow custom
naming conventions (#822, #1421, @AshesITR)
* `literal_coercion_linter()` reports a replacement in the lint
message, e.g. code like `as.integer(1)` will suggest using `1L`
instead, and code like `as.numeric(NA)` will suggest using
`NA_real_` instead (#1439, @MichaelChirico)
* Added `format()` functions for `lint` and `lints` (#1784, @AshesITR)
* `all_linters()` function provides an easy way to access all
available linters (#1843, @IndrajeetPatil)
* `missing_argument_linter()` allows missing arguments in `quote()`
calls (#1889, @IndrajeetPatil).
* `get_source_expressions()` correctly extracts indented code chunks
from R Markdown documents, which helps avoid spurious lints related
to whitespace (#1945, @MichaelChirico). The convention taken is
that, within each chunk, all code is anchored relative to the
leftmost non-whitespace column.
* `available_linters()` gives priority to `tags` over `exclude_tags`
in the case of overlap. In particular, this means that
`available_linters(tags = "deprecated")` will work to return
deprecated linters without needing to specify `exclude_tags` (#1959,
@MichaelChirico).
* The {lintr} configuration file is now searched in the system's user
configuration path; the lintr config filename can also be configured
explicitly by setting the environment variable `R_LINTR_LINTER_FILE`
(#460, @klmr)
* Errors in the {lintr} configuration file now produce more
informative error messages (#886, @AshesITR)
### New linters
* `matrix_apply_linter()` recommends use of dedicated `rowSums()`,
`colSums()`, `colMeans()`, `rowMeans()` over `apply(., MARGIN, sum)`
or `apply(., MARGIN, mean)`. The recommended alternative is much
more efficient and more readable (#1869, @Bisaloo).
* `unnecessary_lambda_linter()`: detect unnecessary lambdas (anonymous
functions), e.g. `lapply(x, function(xi) sum(xi))` can be
`lapply(x, sum)` and `purrr::map(x, ~quantile(.x, 0.75, na.rm =
TRUE))` can be `purrr::map(x, quantile, 0.75, na.rm = TRUE)`. Naming
`probs = 0.75` can further improve readability (#1531, #1866,
@MichaelChirico, @Bisaloo).
* `redundant_equals_linter()` for redundant comparisons to `TRUE` or
`FALSE` like `is_treatment == TRUE` (#1500, @MichaelChirico)
* `lengths_linter()` for encouraging usage of `lengths(x)` instead of
`sapply(x, length)` (and similar)
* `function_return_linter()` for handling issues in function
`return()` statements. Currently handles assignments within the
`return()` clause, e.g. `return(x <- foo())` (@MichaelChirico)
* `boolean_arithmetic_linter()` for identifying places where logical
aggregations are more appropriate, e.g. `length(which(x == y)) ==
0` is the same as `!any(x == y)` or even `all(x != y)`
(@MichaelChirico)
* `for_loop_index_linter()` to prevent overwriting local variables in
a `for` loop declared like `for (x in x) { ... }` (@MichaelChirico)
* `is_numeric_linter()` for redundant checks equivalent to
`is.numeric(x)` such as `is.numeric(x) || is.integer(x)` or
`class(x) %in% c("numeric", "integer")` (@MichaelChirico)
* `empty_assignment_linter()` for identifying empty assignments like
`x = {}` that are more clearly written as `x = NULL`
(@MichaelChirico)
* `unnecessary_placeholder_linter()` for identifying where usage of
the {magrittr} placeholder `.` could be omitted (@MichaelChirico)
* `routine_registration_linter()` for identifying native routines that
don't use registration (`useDynLib` in the `NAMESPACE`;
@MichaelChirico)
* `indentation_linter()` for checking that the indentation conforms to
2-space Tidyverse-style (@AshesITR and @dgkf, #1411, #1792, #1898).
* `unnecessary_nested_if_linter()` for checking unnecessary nested
`if` statements where a single `if` statement with appropriate
conditional expression would suffice (@IndrajeetPatil and @AshesITR,
#1778).
* `implicit_assignment_linter()` for checking implicit assignments in
function calls (@IndrajeetPatil and @AshesITR, #1777).
* `quotes_linter()` is a generalized version of (now deprecated)
`single_quotes_linter()`. It accepts an argument `delimiter` to
specify whether `"` or `'` should be the accepted method for
delimiting character literals. The default, `"`, reflects the
Tidyverse style guide recommendation and matches the behavior of
`single_quotes_linter()`.
* `unnecessary_concatenation_linter()` is simply
`unneeded_concatenation_linter()`, renamed.
* `consecutive_assertion_linter()`
(f.k.a. `consecutive_stopifnot_linter()`) now lints for consecutive
calls to `assertthat::assert_that()` (as long as the `msg=` argument
is not used; #1604, @MichaelChirico).
* `whitespace_linter()` is simply `no_tab_linter()`, renamed. In the
future, we plan to extend it to work for different whitespace
preferences.
## Notes
* {lintr} now depends on R version 3.5.0, in line with the tidyverse
policy for R version compatibility.
* `lint()` continues to support Rmarkdown documents. For users of
custom .Rmd engines, e.g. `marginformat` from {tufte} or `theorem`
from {bookdown}, note that those engines must be registered in
{knitr} prior to running `lint()` in order for {lintr} to behave as
expected, i.e., they should be shown as part of
`knitr::knit_engines$get()`.
For {tufte} and {bookdown} in particular, one only needs to load the
package namespace to accomplish this (i.e., minimally
`loadNamespace("tufte")` or `loadNamespace("bookdown")`,
respectively, will register those packages' custom engines; since
`library()` also runs `loadNamespace()`, running `library()` will
also work). Note further that {tufte} only added this code to their
`.onLoad()` recently after our request to do so (see
https://github.com/rstudio/tufte/issues/117). Therefore, ensure
you're using a more recent version to get the behavior described
here for {tufte}.
More generally, there is no requirement that `loadNamespace()` will
register a package's custom {knitr} engines, so you may need to work
with other package authors to figure out a solution for other
engines.
Thanks to Yihui and other developers for their helpful discussions
around this issue (#797, @IndrajeetPatil).
* The output of `lint()` and `Lint()` gain S3 class `"list"` to assist
with S3 dispatch (#1494, @MichaelChirico)
+ As a corollary, we now register an `as_tibble` method for class
`lints`, conditional on {tibble} availability, to avoid dispatching
to the `list` method which does not work with `lint()` output
(#1997, @MichaelChirico)
* `object_usage_linter()` gives a more helpful warning when a `glue()`
expression fails to evaluate (#1985, @MichaelChirico)
* The documentation of `object_name_linter()` now describes how `"symbols"`
works when passed to the `styles` parameter (#1924, @hedsnz).
Files: