Skip to content

Commit ac74b25

Browse files
Fix false positive in if_switch_linter() for empty strings
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
1 parent 6afb72d commit ac74b25

File tree

3 files changed

+14
-1
lines changed

3 files changed

+14
-1
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* Excluding `cyclocomp_linter()` in `available_linters()` or `linters_with_tags()`, which requires the weak dependency {cyclocomp}, no longer emits a warning (#2909, @MichaelChirico).
1212
* `repeat_linter()` no longer errors when `while` is in a column to the right of `}` (#2828, @MichaelChirico).
1313
* `undesirable_operator_linter(call_is_undesirable = FALSE)` now correctly skips prefix notation like `` `:::`(pkg, fun) `` (#2999, @emmanuel-ferdman).
14+
* `if_switch_linter()` no longer produces a false positive when comparing to empty strings (`""` or `''`), which cannot be used as `switch()` case names (#2835, @emmanuel-ferdman).
1415

1516
## New and improved features
1617

R/if_switch_linter.R

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
#' @seealso [linters] for a complete list of linters available in lintr.
160160
#' @export
161161
if_switch_linter <- function(max_branch_lines = 0L, max_branch_expressions = 0L) {
162-
equal_str_cond <- "expr[1][EQ and expr/STR_CONST]"
162+
equal_str_cond <- "expr[1][EQ and expr/STR_CONST[string-length(text()) > 2]]"
163163

164164
if (max_branch_lines > 0L || max_branch_expressions > 0L) {
165165
complexity_cond <- xp_or(c(
@@ -191,6 +191,10 @@ if_switch_linter <- function(max_branch_lines = 0L, max_branch_expressions = 0L)
191191
# NB: IF AND {...} AND ELSE/... implies >= 3 equality conditions are present
192192
# .//expr/IF/...: the expr in `==` that's _not_ the STR_CONST
193193
# not(preceding::IF): prevent nested matches which might be incorrect globally
194+
empty_string_cond <- paste0(
195+
".//ELSE/following-sibling::expr/IF/following-sibling::expr[1][EQ]",
196+
"/expr/STR_CONST[string-length(text()) = 2]"
197+
)
194198
if_xpath <- glue("
195199
//IF
196200
/parent::expr[
@@ -202,6 +206,7 @@ if_switch_linter <- function(max_branch_lines = 0L, max_branch_expressions = 0L)
202206
and ELSE/following-sibling::expr[IF and {equal_str_cond}]
203207
]
204208
and not({ max_lines_cond })
209+
and not({ empty_string_cond })
205210
]
206211
")
207212

tests/testthat/test-if_switch_linter.R

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ test_that("if_switch_linter skips allowed usages", {
1919
expect_no_lint("if (x == 'a') 1 else if (x == 'b') 2", linter)
2020
# still no third if() clause
2121
expect_no_lint("if (x == 'a') 1 else if (x == 'b') 2 else 3", linter)
22+
23+
# empty string comparisons can't use switch()
24+
expect_no_lint("if (x == '') 1 else if (x == 'a') 2 else if (x == 'b') 3", linter)
25+
expect_no_lint('if (x == "") 1 else if (x == "a") 2 else if (x == "b") 3', linter)
26+
expect_no_lint("if (x == 'a') 1 else if (x == '') 2 else if (x == 'b') 3", linter)
27+
expect_no_lint("if (x == 'a') 1 else if (x == 'b') 2 else if (x == '') 3", linter)
28+
expect_no_lint("if (x == 'a') 1 else if (x == 'b') 2 else if (x == 'c') 3 else if (x == '') 4", linter)
2229
})
2330

2431
test_that("if_switch_linter blocks simple disallowed usages", {

0 commit comments

Comments
 (0)