Block instances of unnecessary nesting
Source:R/unnecessary_nesting_linter.R
unnecessary_nesting_linter.Rd
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. ifFALSE
, all braced expressions with only one child expression are linted. TheTRUE
case facilitates interaction withimplicit_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 itscode
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, whileswitch()
is allowed for its use as a control flow analogous toif
/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.