Skip to content

Commit 02fb726

Browse files
Merge branch 'main' into 1650_broken_ns
2 parents e9df966 + 80c38c5 commit 02fb726

31 files changed

+864
-143
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ Collate:
106106
'infix_spaces_linter.R'
107107
'inner_combine_linter.R'
108108
'is_lint_level.R'
109+
'is_numeric_linter.R'
109110
'lengths_linter.R'
110111
'line_length_linter.R'
111112
'lint.R'

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export(implicit_integer_linter)
7070
export(infix_spaces_linter)
7171
export(inner_combine_linter)
7272
export(is_lint_level)
73+
export(is_numeric_linter)
7374
export(lengths_linter)
7475
export(line_length_linter)
7576
export(lint)

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@
5353

5454
* `for_loop_index_linter()` to prevent overwriting local variables in a `for` loop declared like `for (x in x) { ... }` (@MichaelChirico)
5555

56+
* `is_numeric_linter()` for redundant checks equivalent to `is.numeric(x)` such as `is.numeric(x) || is.integer(x)` or
57+
`class(x) %in% c("numeric", "integer")` (@MichaelChirico)
58+
5659
* `empty_assignment_linter()` for identifying empty assignments like `x = {}` that are more clearly written as `x = NULL` (@MichaelChirico)
5760

5861
## Notes

R/function_argument_linter.R

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,44 @@
11
#' Function argument linter
22
#'
3-
#' Check that arguments with defaults come last in all function declarations, as per the tidyverse design guide.
3+
#' @description
4+
#' Check that arguments with defaults come last in all function declarations,
5+
#' as per the tidyverse design guide.
6+
#'
7+
#' Changing the argument order can be a breaking change. An alternative to changing the argument order
8+
#' is to instead set the default for such arguments to `NULL`.
9+
#'
10+
#' @examples
11+
#' # will produce lints
12+
#' lint(
13+
#' text = "function(y = 1, z = 2, x) {}",
14+
#' linters = function_argument_linter()
15+
#' )
16+
#'
17+
#' lint(
18+
#' text = "function(x, y, z = 1, ..., w) {}",
19+
#' linters = function_argument_linter()
20+
#' )
21+
#'
22+
#' # okay
23+
#' lint(
24+
#' text = "function(x, y = 1, z = 2) {}",
25+
#' linters = function_argument_linter()
26+
#' )
27+
#'
28+
#' lint(
29+
#' text = "function(x, y, w, z = 1, ...) {}",
30+
#' linters = function_argument_linter()
31+
#' )
32+
#'
33+
#' lint(
34+
#' text = "function(y = 1, z = 2, x = NULL) {}",
35+
#' linters = function_argument_linter()
36+
#' )
37+
#'
38+
#' lint(
39+
#' text = "function(x, y, z = 1, ..., w = NULL) {}",
40+
#' linters = function_argument_linter()
41+
#' )
442
#'
543
#' @evalRd rd_tags("function_argument_linter")
644
#' @seealso

R/function_left_parentheses_linter.R

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,43 @@
11
#' Function left parentheses linter
22
#'
33
#' Check that all left parentheses in a function call do not have spaces before them
4-
#' (e.g. `mean (1:3)`). Although this is syntactically valid, it makes the code
5-
#' difficult to read.
4+
#' (e.g. `mean (1:3)`). Although this is syntactically valid, it makes the code
5+
#' difficult to read.
6+
#'
7+
#' Exceptions are made for control flow functions (`if`, `for`, etc.).
8+
#'
9+
#' @examples
10+
#' # will produce lints
11+
#' lint(
12+
#' text = "mean (x)",
13+
#' linters = function_left_parentheses_linter()
14+
#' )
15+
#'
16+
#' lint(
17+
#' text = "stats::sd(c (x, y, z))",
18+
#' linters = function_left_parentheses_linter()
19+
#' )
20+
#'
21+
#' # okay
22+
#' lint(
23+
#' text = "mean(x)",
24+
#' linters = function_left_parentheses_linter()
25+
#' )
26+
#'
27+
#' lint(
28+
#' text = "stats::sd(c(x, y, z))",
29+
#' linters = function_left_parentheses_linter()
30+
#' )
31+
#'
32+
#' lint(
33+
#' text = "if (TRUE) x else y",
34+
#' linters = function_left_parentheses_linter()
35+
#' )
36+
#'
37+
#' lint(
38+
#' text = "foo <- function(x) (x + 1)",
39+
#' linters = function_left_parentheses_linter()
40+
#' )
641
#'
742
#' @evalRd rd_tags("function_left_parentheses_linter")
843
#' @seealso

R/function_return_linter.R

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,54 @@
44
#' confusing (because assigning to `x` has some side effect that is muddled
55
#' by the dual-purpose expression).
66
#'
7+
#' @examples
8+
#' # will produce lints
9+
#' lint(
10+
#' text = "foo <- function(x) return(y <- x + 1)",
11+
#' linters = function_return_linter()
12+
#' )
13+
#'
14+
#' lint(
15+
#' text = "foo <- function(x) return(x <<- x + 1)",
16+
#' linters = function_return_linter()
17+
#' )
18+
#'
19+
#' cat("e <- new.env() \nfoo <- function(x) return(e$val <- x + 1)")
20+
#' lint(
21+
#' text = "e <- new.env() \nfoo <- function(x) return(e$val <- x + 1)",
22+
#' linters = function_return_linter()
23+
#' )
24+
#'
25+
#' # okay
26+
#' lint(
27+
#' text = "foo <- function(x) return(x + 1)",
28+
#' linters = function_return_linter()
29+
#' )
30+
#'
31+
#' code_lines <- "
32+
#' foo <- function(x) {
33+
#' x <<- x + 1
34+
#' return(x)
35+
#' }
36+
#' "
37+
#' lint(
38+
#' text = code_lines,
39+
#' linters = function_return_linter()
40+
#' )
41+
#'
42+
#' code_lines <- "
43+
#' e <- new.env()
44+
#' foo <- function(x) {
45+
#' e$val <- x + 1
46+
#' return(e$val)
47+
#' }
48+
#' "
49+
#' cat(code_lines)
50+
#' lint(
51+
#' text = code_lines,
52+
#' linters = function_return_linter()
53+
#' )
54+
#'
755
#' @evalRd rd_tags("function_return_linter")
856
#' @seealso [linters] for a complete list of linters available in lintr.
957
#' @export

R/ifelse_censor_linter.R

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,29 @@
88
#' `ifelse(x < m, m, x)` is `pmax(x, m)`, and
99
#' `ifelse(x >= m, x, m)` is `pmax(x, m)`.
1010
#'
11+
#' @examples
12+
#' # will produce lints
13+
#' lint(
14+
#' text = "ifelse(5:1 < pi, 5:1, pi)",
15+
#' linters = ifelse_censor_linter()
16+
#' )
17+
#'
18+
#' lint(
19+
#' text = "ifelse(x > 0, x, 0)",
20+
#' linters = ifelse_censor_linter()
21+
#' )
22+
#'
23+
#' # okay
24+
#' lint(
25+
#' text = "pmin(5:1, pi)",
26+
#' linters = ifelse_censor_linter()
27+
#' )
28+
#'
29+
#' lint(
30+
#' text = "pmax(x, 0)",
31+
#' linters = ifelse_censor_linter()
32+
#' )
33+
#'
1134
#' @evalRd rd_tags("ifelse_censor_linter")
1235
#' @seealso [linters] for a complete list of linters available in lintr.
1336
#' @export

R/implicit_integer_linter.R

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@
22
#'
33
#' Check that integers are explicitly typed using the form `1L` instead of `1`.
44
#'
5+
#' @examples
6+
#' # will produce lints
7+
#' lint(
8+
#' text = "x <- 1",
9+
#' linters = implicit_integer_linter()
10+
#' )
11+
#'
12+
#' lint(
13+
#' text = "x[2]",
14+
#' linters = implicit_integer_linter()
15+
#' )
16+
#'
17+
#' # okay
18+
#' lint(
19+
#' text = "x <- 1.0",
20+
#' linters = implicit_integer_linter()
21+
#' )
22+
#'
23+
#' lint(
24+
#' text = "x <- 1L",
25+
#' linters = implicit_integer_linter()
26+
#' )
27+
#'
28+
#' lint(
29+
#' text = "x[2L]",
30+
#' linters = implicit_integer_linter()
31+
#' )
32+
#'
533
#' @evalRd rd_tags("implicit_integer_linter")
634
#' @seealso [linters] for a complete list of linters available in lintr.
735
#' @export

R/infix_spaces_linter.R

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,47 @@
44
# NB: this metadata is used elsewhere in lintr, e.g. spaces_left_parentheses_linter.
55
# because of that, even though some rows of this table are currently unused, but
66
# we keep them around because it's useful to keep this info in one place.
7+
8+
# styler: off
79
infix_metadata <- data.frame(stringsAsFactors = FALSE, matrix(byrow = TRUE, ncol = 2L, c(
8-
"OP-PLUS", "+",
9-
"OP-MINUS", "-",
10-
"OP-TILDE", "~",
11-
"GT", ">",
12-
"GE", ">=",
13-
"LT", "<",
14-
"LE", "<=",
15-
"EQ", "==",
16-
"NE", "!=",
17-
"AND", "&",
18-
"OR", "|",
19-
"AND2", "&&",
20-
"OR2", "||",
21-
"LEFT_ASSIGN", "<-", # also includes := and <<-
22-
"RIGHT_ASSIGN", "->", # also includes ->>
23-
"EQ_ASSIGN", "=",
24-
"EQ_SUB", "=", # in calls: foo(x = 1)
25-
"EQ_FORMALS", "=", # in definitions: function(x = 1)
26-
"SPECIAL", "%%",
27-
"OP-SLASH", "/",
28-
"OP-STAR", "*",
29-
"OP-COMMA", ",",
30-
"OP-CARET", "^", # also includes **
31-
"OP-AT", "@",
32-
"OP-EXCLAMATION", "!",
33-
"OP-COLON", ":",
34-
"NS_GET", "::",
35-
"NS_GET_INT", ":::",
36-
"OP-LEFT-BRACE", "{",
10+
"OP-PLUS", "+",
11+
"OP-MINUS", "-",
12+
"OP-TILDE", "~",
13+
"GT", ">",
14+
"GE", ">=",
15+
"LT", "<",
16+
"LE", "<=",
17+
"EQ", "==",
18+
"NE", "!=",
19+
"AND", "&",
20+
"OR", "|",
21+
"AND2", "&&",
22+
"OR2", "||",
23+
"LEFT_ASSIGN", "<-", # also includes := and <<-
24+
"RIGHT_ASSIGN", "->", # also includes ->>
25+
"EQ_ASSIGN", "=",
26+
"EQ_SUB", "=", # in calls: foo(x = 1)
27+
"EQ_FORMALS", "=", # in definitions: function(x = 1)
28+
"SPECIAL", "%%",
29+
"OP-SLASH", "/",
30+
"OP-STAR", "*",
31+
"OP-COMMA", ",",
32+
"OP-CARET", "^", # also includes **
33+
"OP-AT", "@",
34+
"OP-EXCLAMATION", "!",
35+
"OP-COLON", ":",
36+
"NS_GET", "::",
37+
"NS_GET_INT", ":::",
38+
"OP-LEFT-BRACE", "{",
3739
"OP-LEFT-BRACKET", "[",
38-
"LBB", "[[",
39-
"OP-LEFT-PAREN", "(",
40-
"OP-QUESTION", "?",
41-
"OP-DOLLAR", "$",
40+
"LBB", "[[",
41+
"OP-LEFT-PAREN", "(",
42+
"OP-QUESTION", "?",
43+
"OP-DOLLAR", "$",
4244
NULL
4345
)))
46+
# styler: on
47+
4448
names(infix_metadata) <- c("xml_tag", "string_value")
4549
# utils::getParseData()'s designation for the tokens wouldn't be valid as XML tags
4650
infix_metadata$parse_tag <- ifelse(
@@ -70,7 +74,7 @@ infix_overload <- data.frame(
7074
#' Check that infix operators are surrounded by spaces. Enforces the corresponding Tidyverse style guide rule;
7175
#' see <https://style.tidyverse.org/syntax.html#infix-operators>.
7276
#'
73-
#' @param exclude_operators Character vector of operators to exlude from consideration for linting.
77+
#' @param exclude_operators Character vector of operators to exclude from consideration for linting.
7478
#' Default is to include the following "low-precedence" operators:
7579
#' `+`, `-`, `~`, `>`, `>=`, `<`, `<=`, `==`, `!=`, `&`, `&&`, `|`, `||`, `<-`, `:=`, `<<-`, `->`, `->>`,
7680
#' `=`, `/`, `*`, and any infix operator (exclude infixes by passing `"%%"`). Note that `<-`, `:=`, and `<<-`
@@ -79,6 +83,45 @@ infix_overload <- data.frame(
7983
#' @param allow_multiple_spaces Logical, default `TRUE`. If `FALSE`, usage like `x = 2` will also be linted;
8084
#' excluded by default because such usage can sometimes be used for better code alignment, as is allowed
8185
#' by the style guide.
86+
#'
87+
#' @examples
88+
#' # will produce lints
89+
#' lint(
90+
#' text = "x<-1L",
91+
#' linters = infix_spaces_linter()
92+
#' )
93+
#'
94+
#' lint(
95+
#' text = "1:4 %>%sum()",
96+
#' linters = infix_spaces_linter()
97+
#' )
98+
#'
99+
#' # okay
100+
#' lint(
101+
#' text = "x <- 1L",
102+
#' linters = infix_spaces_linter()
103+
#' )
104+
#'
105+
#' lint(
106+
#' text = "1:4 %>% sum()",
107+
#' linters = infix_spaces_linter()
108+
#' )
109+
#'
110+
#' code_lines <- "
111+
#' ab <- 1L
112+
#' abcdef <- 2L
113+
#' "
114+
#' cat(code_lines)
115+
#' lint(
116+
#' text = code_lines,
117+
#' linters = infix_spaces_linter(allow_multiple_spaces = TRUE)
118+
#' )
119+
#'
120+
#' lint(
121+
#' text = "a||b",
122+
#' linters = infix_spaces_linter(exclude_operators = "||")
123+
#' )
124+
#'
82125
#' @evalRd rd_tags("infix_spaces_linter")
83126
#' @seealso
84127
#' [linters] for a complete list of linters available in lintr. \cr
@@ -132,6 +175,11 @@ infix_spaces_linter <- function(exclude_operators = NULL, allow_multiple_spaces
132175
xml <- source_expression$xml_parsed_content
133176
bad_expr <- xml2::xml_find_all(xml, xpath)
134177

135-
xml_nodes_to_lints(bad_expr, source_expression = source_expression, lint_message = lint_message, type = "style")
178+
xml_nodes_to_lints(
179+
bad_expr,
180+
source_expression = source_expression,
181+
lint_message = lint_message,
182+
type = "style"
183+
)
136184
})
137185
}

0 commit comments

Comments
 (0)