diff --git a/NEWS.md b/NEWS.md index 2f5dc967a..fcff5cde8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -43,6 +43,7 @@ `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) diff --git a/R/object_usage_linter.R b/R/object_usage_linter.R index eba9e10d5..479ba664c 100644 --- a/R/object_usage_linter.R +++ b/R/object_usage_linter.R @@ -37,12 +37,12 @@ object_usage_linter <- function(interpret_glue = TRUE, skip_with = TRUE) { # TODO(#1106): use //[...] to capture assignments in more scopes xpath_function_assignment <- paste( # direct assignments - "expr[LEFT_ASSIGN or EQ_ASSIGN]/expr[2][FUNCTION]", - "expr_or_assign_or_help[EQ_ASSIGN]/expr[2][FUNCTION]", - "equal_assign[EQ_ASSIGN]/expr[2][FUNCTION]", + "expr[LEFT_ASSIGN or EQ_ASSIGN]/expr[2][FUNCTION or OP-LAMBDA]", + "expr_or_assign_or_help[EQ_ASSIGN]/expr[2][FUNCTION or OP-LAMBDA]", + "equal_assign[EQ_ASSIGN]/expr[2][FUNCTION or OP-LAMBDA]", # assign() and setMethod() assignments - "//SYMBOL_FUNCTION_CALL[text() = 'assign']/parent::expr/following-sibling::expr[2][FUNCTION]", - "//SYMBOL_FUNCTION_CALL[text() = 'setMethod']/parent::expr/following-sibling::expr[3][FUNCTION]", + "//SYMBOL_FUNCTION_CALL[text() = 'assign']/parent::expr/following-sibling::expr[2][FUNCTION or OP-LAMBDA]", + "//SYMBOL_FUNCTION_CALL[text() = 'setMethod']/parent::expr/following-sibling::expr[3][FUNCTION or OP-LAMBDA]", sep = " | " ) diff --git a/tests/testthat/test-object_usage_linter.R b/tests/testthat/test-object_usage_linter.R index 1f6532d6a..a8329a5ca 100644 --- a/tests/testthat/test-object_usage_linter.R +++ b/tests/testthat/test-object_usage_linter.R @@ -638,3 +638,17 @@ test_that("messages without a quoted name are caught", { object_usage_linter() ) }) + +test_that("functional lambda definitions are also caught", { + skip_if_not_r_version("4.1.0") + + expect_lint( + trim_some(" + fun <- \\() { + a <- 1 + } + "), + rex::rex("local variable", anything, "assigned but may not be used"), + object_usage_linter() + ) +})