diff --git a/NEWS.md b/NEWS.md index bb8417f87..1d0f8209d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -76,6 +76,7 @@ files in Windows (#2882, @Bisaloo). * `T_and_F_symbol_linter()` ignores `T` and `F` used as symbols in formulas (`y ~ T + F`), which can represent variables in data not controlled by the author (#2637, @MichaelChirico). * `T_and_F_symbol_linter()` ignores `T` and `F` if followed by `[` or `[[` (#2944, @mcol). * `implicit_assignment_linter()` with `allow_scoped=TRUE` doesn't lint for `if (a <- 1) print(a)` (#2913, @MichaelChirico). +* `paste_linter()` doesn't lint `expression(paste(., sep = ""))` (#2945, @mcol). ### Lint accuracy fixes: removing false negatives diff --git a/R/paste_linter.R b/R/paste_linter.R index 89ecc8bfc..fb107bffa 100644 --- a/R/paste_linter.R +++ b/R/paste_linter.R @@ -75,6 +75,11 @@ #' ) #' #' lint( +#' text = 'expression(paste("a", "b", sep = ""))', +#' linters = paste_linter() +#' ) +#' +#' lint( #' text = 'toString(c("a", "b"))', #' linters = paste_linter() #' ) @@ -118,7 +123,8 @@ paste_linter <- function(allow_empty_sep = FALSE, check_file_paths <- allow_file_path %in% c("double_slash", "never") paste_sep_xpath <- " - following-sibling::SYMBOL_SUB[text() = 'sep' and following-sibling::expr[1][STR_CONST]] + following-sibling::SYMBOL_SUB[text() = 'sep' and following-sibling::expr[1][STR_CONST] + and not(parent::expr/preceding-sibling::expr/SYMBOL_FUNCTION_CALL[text() = 'expression'])] /parent::expr " diff --git a/man/paste_linter.Rd b/man/paste_linter.Rd index 8139cd605..53f4ec73b 100644 --- a/man/paste_linter.Rd +++ b/man/paste_linter.Rd @@ -86,6 +86,11 @@ lint( linters = paste_linter(allow_empty_sep = TRUE) ) +lint( + text = 'expression(paste("a", "b", sep = ""))', + linters = paste_linter() +) + lint( text = 'toString(c("a", "b"))', linters = paste_linter() diff --git a/tests/testthat/test-paste_linter.R b/tests/testthat/test-paste_linter.R index b2409692f..6bebd6d76 100644 --- a/tests/testthat/test-paste_linter.R +++ b/tests/testthat/test-paste_linter.R @@ -8,6 +8,7 @@ test_that("paste_linter skips allowed usages for sep=''", { expect_no_lint("sep <- ''; paste('a', sep)", linter) expect_no_lint("paste(sep = ',', '', 'a')", linter) expect_no_lint("paste0('a', 'b', 'c')", linter) + expect_no_lint("expression(paste('a', b, sep = ''))", linter) }) test_that("paste_linter blocks simple disallowed usages for sep=''", { @@ -22,6 +23,18 @@ test_that("paste_linter blocks simple disallowed usages for sep=''", { rex::rex('paste0(...) is better than paste(..., sep = "").'), paste_linter() ) + + expect_lint( + "paste('a', 'b', expression(2), sep = '')", + rex::rex('paste0(...) is better than paste(..., sep = "").'), + paste_linter() + ) + + expect_lint( + "c(expression(2), paste('a', 'b', sep = ''))", + rex::rex('paste0(...) is better than paste(..., sep = "").'), + paste_linter() + ) }) test_that("paste_linter skips allowed usages for collapse=', '", {