Skip to contents

Excessive nesting harms readability. Use helper functions or early returns to reduce nesting wherever possible.

Usage

unnecessary_nesting_linter(
  allow_assignment = TRUE,
  allow_functions = c("switch", "try", "tryCatch", "withCallingHandlers", "quote",
    "expression", "bquote", "substitute", "with_parameters_test_that", "reactive",
    "observe", "observeEvent", "renderCachedPlot", "renderDataTable", "renderImage",
    "renderPlot", "renderPrint", "renderTable", "renderText", "renderUI")
)

Arguments

allow_assignment

Logical, default TRUE, in which case braced expressions consisting only of a single assignment are skipped. if FALSE, all braced expressions with only one child expression are linted. The TRUE case facilitates interaction with implicit_assignment_linter() for certain cases where an implicit assignment is necessary, so a braced assignment is used to further distinguish the assignment. See examples.

allow_functions

Character vector of functions which always allow one-child braced expressions. testthat::test_that() is always allowed because testthat requires a braced expression in its code argument. The other defaults similarly compute on expressions in a way which is worth highlighting by em-bracing them, even if there is only one expression, while switch() is allowed for its use as a control flow analogous to if/else.

See also

  • cyclocomp_linter() for another linter that penalizes overly complex code.

  • linters for a complete list of linters available in lintr.

Examples

# will produce lints
code <- "if (A) {\n  stop('A is bad!')\n} else {\n  do_good()\n}"
writeLines(code)
#> if (A) {
#>   stop('A is bad!')
#> } else {
#>   do_good()
#> }
lint(
  text = code,
  linters = unnecessary_nesting_linter()
)
#> <text>:1:1: warning: [unnecessary_nesting_linter] Reduce the nesting of this if/else statement by unnesting the portion without an exit clause (i.e., stop(), return(), abort(), quit(), q()).
#> if (A) {
#> ^~~~~~~~

code <- "tryCatch(\n  {\n    foo()\n  },\n  error = identity\n)"
writeLines(code)
#> tryCatch(
#>   {
#>     foo()
#>   },
#>   error = identity
#> )
lint(
  text = code,
  linters = unnecessary_nesting_linter()
)
#>  No lints found.

code <- "expect_warning(\n  {\n    x <- foo()\n  },\n  'warned'\n)"
writeLines(code)
#> expect_warning(
#>   {
#>     x <- foo()
#>   },
#>   'warned'
#> )
lint(
  text = code,
  linters = unnecessary_nesting_linter(allow_assignment = FALSE)
)
#> <text>:2:3: warning: [unnecessary_nesting_linter] Reduce the nesting of this statement by removing the braces {}.
#>   {
#>   ^

writeLines("if (x) { \n  if (y) { \n   return(1L) \n  } \n}")
#> if (x) { 
#>   if (y) { 
#>    return(1L) 
#>   } 
#> }
lint(
  text = "if (x) { \n  if (y) { \n   return(1L) \n  } \n}",
  linters = unnecessary_nesting_linter()
)
#> <text>:2:3: warning: [unnecessary_nesting_linter] Don't use nested `if` statements, where a single `if` with the combined conditional expression will do. For example, instead of `if (x) { if (y) { ... }}`, use `if (x && y) { ... }`.
#>   if (y) { 
#>   ^~~~~~~~~

lint(
  text = "my_quote({x})",
  linters = unnecessary_nesting_linter()
)
#>  No lints found.

# okay
code <- "if (A) {\n  stop('A is bad because a.')\n} else {\n  stop('!A is bad too.')\n}"
writeLines(code)
#> if (A) {
#>   stop('A is bad because a.')
#> } else {
#>   stop('!A is bad too.')
#> }
lint(
  text = code,
  linters = unnecessary_nesting_linter()
)
#>  No lints found.

code <- "capture.output({\n  foo()\n})"
writeLines(code)
#> capture.output({
#>   foo()
#> })
lint(
  text = code,
  linters = unnecessary_nesting_linter()
)
#>  No lints found.

code <- "expect_warning(\n  {\n    x <- foo()\n  },\n  'warned'\n)"
writeLines(code)
#> expect_warning(
#>   {
#>     x <- foo()
#>   },
#>   'warned'
#> )
lint(
  text = code,
  linters = unnecessary_nesting_linter()
)
#>  No lints found.

writeLines("if (x && y) { \n  return(1L) \n}")
#> if (x && y) { 
#>   return(1L) 
#> }
lint(
  text = "if (x && y) { \n  return(1L) \n}",
  linters = unnecessary_nesting_linter()
)
#>  No lints found.

writeLines("if (x) { \n  y <- x + 1L\n  if (y) { \n   return(1L) \n  } \n}")
#> if (x) { 
#>   y <- x + 1L
#>   if (y) { 
#>    return(1L) 
#>   } 
#> }
lint(
  text = "if (x) { \n  y <- x + 1L\n  if (y) { \n   return(1L) \n  } \n}",
  linters = unnecessary_nesting_linter()
)
#>  No lints found.

lint(
  text = "my_quote({x})",
  linters = unnecessary_nesting_linter(allow_functions = "my_quote")
)
#>  No lints found.