r-lib / lintr

Static Code Analysis for R
https://lintr.r-lib.org
Other
1.2k stars 187 forks source link

New linter for unnamed arguments combined with `...` #2627

Open teunbrand opened 4 months ago

teunbrand commented 4 months ago

I thought it might be handy to have a linter that checks for the pattern fun(x, y, ...) where x and y are unnamed arguments and are matched to fun() based on their position. This is risky to combine with ... as a named argument in ... might supplant x or y and shift subsequent arguments.

To illustrate, this piece of code with named arguments correctly gives the 'matched by multiple arguments' error:

inner <- function(str, num, lgl) {
  stopifnot(is.character(str), is.numeric(num), is.logical(lgl))
  "succes"
}

outer <- function(...) inner(str = "a", num = 4, ...)

outer(TRUE)
#> [1] "succes"
outer(num = 5)
#> Error in inner(str = "a", num = 4, ...): formal argument "num" matched by multiple actual arguments

However, if we don't use named arguments we get into the following trouble. Note that num = 5 is passed through ... which means that the 2nd default argument (4) that is supposed to be the num argument is now shifted to the lgl argument.

outer <- function(...) inner("a", 4, ...)

outer(TRUE)
#> [1] "succes"
outer(num = 5)
#> Error in inner("a", 4, ...): is.logical(lgl) is not TRUE

Created on 2024-07-10 with reprex v2.1.0

For this reason, I think it'd be good to recommend naming arguments when combined with ....

MichaelChirico commented 4 months ago

Agree it's a good idea for a linter, but will be ~relatively tough to implement -- really it's something {codetools} is best suited for since it requires a strong sense of scope to get match.fun() working with sufficient accuracy to be useful (I reckon). Then like object_usage_linter() we'd pull out info from the codetools report.