Skip to content

Commit 2813b6d

Browse files
cleanup internal namespace, use shared_constants.R for shared objects (#2056)
1 parent f8bb91e commit 2813b6d

16 files changed

+289
-298
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ Collate:
153153
'seq_linter.R'
154154
'settings.R'
155155
'settings_utils.R'
156+
'shared_constants.R'
156157
'sort_linter.R'
157158
'spaces_inside_linter.R'
158159
'spaces_left_parentheses_linter.R'

R/expect_s3_class_linter.R

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,21 @@ expect_s3_class_linter <- function() {
4545
]
4646
/parent::expr[not(SYMBOL_SUB[text() = 'info' or text() = 'label' or text() = 'expected.label'])]
4747
"
48+
# NB: there is no easy way to make an exhaustive list of places where an
49+
# is.<x> call can be replaced by expect_s3_class(); this list was manually
50+
# populated from the default R packages by inspection. For example,
51+
# is.matrix(x) cannot be replaced by expect_s3_class(x, "matrix") because
52+
# it is not actually an S3 class (is.object(x) is not TRUE).
53+
# Further, there are functions named is.<x> that have nothing to do with
54+
# object type, e.g. is.finite(), is.nan(), or is.R().
55+
is_s3_class_calls <- paste0("is.", c(
56+
# base
57+
"data.frame", "factor", "numeric_version", "ordered", "package_version", "qr", "table",
58+
# utils grDevices tcltk tcltk grid grid
59+
"relistable", "raster", "tclObj", "tkwin", "grob", "unit",
60+
# stats
61+
"mts", "stepfun", "ts", "tskernel"
62+
))
4863
is_class_call <- xp_text_in_table(c(is_s3_class_calls, "inherits"))
4964
expect_true_xpath <- glue("
5065
//SYMBOL_FUNCTION_CALL[text() = 'expect_true']
@@ -76,19 +91,3 @@ expect_s3_class_linter <- function() {
7691
)
7792
})
7893
}
79-
80-
# NB: there is no easy way to make an exhaustive list of places where an
81-
# is.<x> call can be replaced by expect_s3_class(); this list was manually
82-
# populated from the default R packages by inspection. For example,
83-
# is.matrix(x) cannot be replaced by expect_s3_class(x, "matrix") because
84-
# it is not actually an S3 class (is.object(x) is not TRUE).
85-
# Further, there are functions named is.<x> that have nothing to do with
86-
# object type, e.g. is.finite(), is.nan(), or is.R().
87-
is_s3_class_calls <- paste0("is.", c(
88-
# base
89-
"data.frame", "factor", "numeric_version", "ordered", "package_version", "qr", "table",
90-
# utils grDevices tcltk tcltk grid grid
91-
"relistable", "raster", "tclObj", "tkwin", "grob", "unit",
92-
# stats
93-
"mts", "stepfun", "ts", "tskernel"
94-
))

R/expect_type_linter.R

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@
2727
#' @seealso [linters] for a complete list of linters available in lintr.
2828
#' @export
2929
expect_type_linter <- function() {
30+
# NB: the full list of values that can arise from `typeof(x)` is available
31+
# in ?typeof (or, slightly more robustly, in the R source: src/main/util.c.
32+
# Not all of them are available in is.<type> form, e.g. 'any' or
33+
# 'special'. 'builtin' and 'closure' are special cases, corresponding to
34+
# is.primitive and is.function (essentially).
35+
base_types <- c(
36+
"raw", "logical", "integer", "double", "complex", "character", "list",
37+
"numeric", "function", "primitive", "environment", "pairlist", "promise",
38+
# Per ?is.language, it's the same as is.call || is.name || is.expression.
39+
# so by blocking it, we're forcing more precise tests of one of
40+
# those directly ("language", "symbol", and "expression", resp.)
41+
# NB: is.name and is.symbol are identical.
42+
"language", "call", "name", "symbol", "expression"
43+
)
3044
base_type_tests <- xp_text_in_table(paste0("is.", base_types))
3145
expect_equal_identical_xpath <- "
3246
//SYMBOL_FUNCTION_CALL[text() = 'expect_equal' or text() = 'expect_identical']
@@ -67,18 +81,3 @@ expect_type_linter <- function() {
6781
)
6882
})
6983
}
70-
71-
# NB: the full list of values that can arise from `typeof(x)` is available
72-
# in ?typeof (or, slightly more robustly, in the R source: src/main/util.c.
73-
# Not all of them are available in is.<type> form, e.g. 'any' or
74-
# 'special'. 'builtin' and 'closure' are special cases, corresponding to
75-
# is.primitive and is.function (essentially).
76-
base_types <- c(
77-
"raw", "logical", "integer", "double", "complex", "character", "list",
78-
"numeric", "function", "primitive", "environment", "pairlist", "promise",
79-
# Per ?is.language, it's the same as is.call || is.name || is.expression.
80-
# so by blocking it, we're forcing more precise tests of one of
81-
# those directly ("language", "symbol", and "expression", resp.)
82-
# NB: is.name and is.symbol are identical.
83-
"language", "call", "name", "symbol", "expression"
84-
)

R/fixed_regex_linter.R

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -141,104 +141,3 @@ fixed_regex_linter <- function() {
141141
)
142142
})
143143
}
144-
145-
rx_non_active_char <- rex::rex(none_of("^${(.*+?|[\\"))
146-
rx_static_escape <- local({
147-
rx_char_escape <- rex::rex(or(
148-
group("\\", none_of(alnum)),
149-
group("\\x", between(xdigit, 1L, 2L)),
150-
group("\\", between("0":"7", 1L, 3L)),
151-
group("\\u{", between(xdigit, 1L, 4L), "}"),
152-
group("\\u", between(xdigit, 1L, 4L)),
153-
group("\\U{", between(xdigit, 1L, 8L), "}"),
154-
group("\\U", between(xdigit, 1L, 8L))
155-
))
156-
rx_trivial_char_group <- rex::rex(
157-
"[",
158-
or(
159-
any,
160-
group("\\", none_of("dswDSW")), # character classes, e.g. \d are enabled in [] too if perl = TRUE
161-
rx_char_escape
162-
),
163-
"]"
164-
)
165-
rex::rex(or(
166-
capture(rx_char_escape, name = "char_escape"),
167-
capture(rx_trivial_char_group, name = "trivial_char_group")
168-
))
169-
})
170-
171-
rx_static_token <- local({
172-
rex::rex(or(
173-
rx_non_active_char,
174-
rx_static_escape
175-
))
176-
})
177-
178-
rx_static_regex <- paste0("(?s)", rex::rex(start, zero_or_more(rx_static_token), end))
179-
rx_first_static_token <- paste0("(?s)", rex::rex(start, zero_or_more(rx_non_active_char), rx_static_escape))
180-
181-
#' Determine whether a regex pattern actually uses regex patterns
182-
#'
183-
#' Note that is applies to the strings that are found on the XML parse tree,
184-
#' _not_ plain strings. This is important for backslash escaping, which
185-
#' happens at different layers of escaping than one might expect. So testing
186-
#' this function is best done through testing the expected results of a lint
187-
#' on a given file, rather than passing strings to this function, which can
188-
#' be confusing.
189-
#'
190-
#' @param str A character vector.
191-
#' @return A logical vector, `TRUE` wherever `str` could be replaced by a
192-
#' string with `fixed = TRUE`.
193-
#' @noRd
194-
is_not_regex <- function(str) {
195-
# need to add single-line option to allow literal newlines
196-
grepl(rx_static_regex, str, perl = TRUE)
197-
}
198-
199-
#' Compute a fixed string equivalent to a static regular expression
200-
#'
201-
#' @param static_regex A regex for which `is_not_regex()` returns `TRUE`
202-
#' @return A string such that `grepl(static_regex, x)` is equivalent to
203-
#' `grepl(get_fixed_string(static_regex), x, fixed = TRUE)`
204-
#'
205-
#' @noRd
206-
get_fixed_string <- function(static_regex) {
207-
if (length(static_regex) == 0L) {
208-
return(character())
209-
} else if (length(static_regex) > 1L) {
210-
return(vapply(static_regex, get_fixed_string, character(1L)))
211-
}
212-
fixed_string <- ""
213-
current_match <- regexpr(rx_first_static_token, static_regex, perl = TRUE)
214-
while (current_match != -1L) {
215-
token_type <- attr(current_match, "capture.names")[attr(current_match, "capture.start") > 0L]
216-
token_start <- max(attr(current_match, "capture.start"))
217-
if (token_start > 1L) {
218-
fixed_string <- paste0(fixed_string, substr(static_regex, 1L, token_start - 1L))
219-
}
220-
consume_to <- attr(current_match, "match.length")
221-
token_content <- substr(static_regex, token_start, consume_to)
222-
fixed_string <- paste0(fixed_string, get_token_replacement(token_content, token_type))
223-
static_regex <- substr(static_regex, start = consume_to + 1L, stop = nchar(static_regex))
224-
current_match <- regexpr(rx_first_static_token, static_regex, perl = TRUE)
225-
}
226-
paste0(fixed_string, static_regex)
227-
}
228-
229-
get_token_replacement <- function(token_content, token_type) {
230-
if (token_type == "trivial_char_group") {
231-
token_content <- substr(token_content, start = 2L, stop = nchar(token_content) - 1L)
232-
if (startsWith(token_content, "\\")) { # escape within trivial char group
233-
get_token_replacement(token_content, "char_escape")
234-
} else {
235-
token_content
236-
}
237-
} else { # char_escape token
238-
if (rex::re_matches(token_content, rex::rex("\\", one_of("^${}().*+?|[]\\<>=:;/_-!@#%&,~")))) {
239-
substr(token_content, start = 2L, stop = nchar(token_content))
240-
} else {
241-
eval(parse(text = paste0('"', token_content, '"')))
242-
}
243-
}
244-
}

R/indentation_linter.R

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,11 @@ indentation_linter <- function(indent = 2L, hanging_indent_style = c("tidy", "al
130130

131131
hanging_indent_style <- match.arg(hanging_indent_style)
132132

133-
if (hanging_indent_style == "tidy") {
134-
find_indent_type <- build_indentation_style_tidy()
135-
} else if (hanging_indent_style == "always") {
136-
find_indent_type <- build_indentation_style_always()
137-
} else { # "never"
138-
find_indent_type <- function(change) {
139-
"block"
140-
}
141-
}
133+
find_indent_type <- switch(hanging_indent_style,
134+
tidy = build_indentation_style_tidy(),
135+
always = build_indentation_style_always(),
136+
never = function(change) "block"
137+
)
142138

143139
if (isTRUE(assignment_as_infix)) {
144140
suppressing_tokens <- c("LEFT_ASSIGN", "EQ_ASSIGN", "EQ_SUB", "EQ_FORMALS")
@@ -313,15 +309,12 @@ indentation_linter <- function(indent = 2L, hanging_indent_style = c("tidy", "al
313309
}
314310

315311
find_new_indent <- function(current_indent, change_type, indent, hanging_indent) {
316-
if (change_type == "suppress") {
317-
current_indent
318-
} else if (change_type == "hanging") {
319-
hanging_indent
320-
} else if (change_type == "double") {
321-
current_indent + 2L * indent
322-
} else {
323-
current_indent + indent
324-
}
312+
switch(change_type,
313+
suppress = current_indent,
314+
hanging = hanging_indent,
315+
double = current_indent + 2L * indent,
316+
block = current_indent + indent
317+
)
325318
}
326319

327320
build_indentation_style_tidy <- function() {

R/infix_spaces_linter.R

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,3 @@
1-
# some metadata about infix operators on the R parse tree.
2-
# xml_tag gives the XML tag as returned by xmlparsedata::xml_parse_data().
3-
# r_string gives the operator as you would write it in R code.
4-
# NB: this metadata is used elsewhere in lintr, e.g. spaces_left_parentheses_linter.
5-
# because of that, even though some rows of this table are currently unused, but
6-
# we keep them around because it's useful to keep this info in one place.
7-
8-
# styler: off
9-
infix_metadata <- data.frame(stringsAsFactors = FALSE, matrix(byrow = TRUE, ncol = 2L, c(
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-
"PIPE", "|>",
29-
"SPECIAL", "%%",
30-
"OP-SLASH", "/",
31-
"OP-STAR", "*",
32-
"OP-COMMA", ",",
33-
"OP-CARET", "^", # also includes **
34-
"OP-AT", "@",
35-
"OP-EXCLAMATION", "!",
36-
"OP-COLON", ":",
37-
"NS_GET", "::",
38-
"NS_GET_INT", ":::",
39-
"OP-LEFT-BRACE", "{",
40-
"OP-LEFT-BRACKET", "[",
41-
"LBB", "[[",
42-
"OP-LEFT-PAREN", "(",
43-
"OP-QUESTION", "?",
44-
"OP-DOLLAR", "$",
45-
NULL
46-
)))
47-
# styler: on
48-
49-
names(infix_metadata) <- c("xml_tag", "string_value")
50-
# utils::getParseData()'s designation for the tokens wouldn't be valid as XML tags
51-
infix_metadata$parse_tag <- ifelse(
52-
startsWith(infix_metadata$xml_tag, "OP-"),
53-
quote_wrap(infix_metadata$string_value, "'"),
54-
infix_metadata$xml_tag
55-
)
56-
# treated separately because spacing rules are different for unary operators
57-
infix_metadata$unary <- infix_metadata$xml_tag %in% c("OP-PLUS", "OP-MINUS", "OP-TILDE")
58-
# high-precedence operators are ignored by this linter; see
59-
# https://style.tidyverse.org/syntax.html#infix-operators
60-
infix_metadata$low_precedence <- infix_metadata$string_value %in% c(
61-
"+", "-", "~", ">", ">=", "<", "<=", "==", "!=", "&", "&&", "|", "||", "<-", "->", "=", "%%", "/", "*", "|>"
62-
)
63-
# comparators come up in several lints
64-
infix_metadata$comparator <- infix_metadata$string_value %in% c("<", "<=", ">", ">=", "==", "!=")
65-
66-
# undesirable_operator_linter needs to distinguish
67-
infix_overload <- data.frame(
68-
exact_string_value = c("<-", "<<-", "=", "->", "->>", "^", "**"),
69-
xml_tag = rep(c("LEFT_ASSIGN", "RIGHT_ASSIGN", "OP-CARET"), c(3L, 2L, 2L)),
70-
stringsAsFactors = FALSE
71-
)
72-
731
#' Infix spaces linter
742
#'
753
#' Check that infix operators are surrounded by spaces. Enforces the corresponding Tidyverse style guide rule;

R/keyword_quote_linter.R

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
# //expr[expr[SYMBOL_FUNCTION_CALL]]/SYMBOL_SUB[starts-with(text(), '`')]
5353
# //expr[expr[SYMBOL_FUNCTION_CALL]]/STR_CONST[{is_quoted(text())}]
5454
keyword_quote_linter <- function() {
55+
# Check if a string could be assigned as an R variable.
56+
#
57+
# See [make.names()] for the description of syntactically valid names in R.
58+
is_valid_r_name <- function(x) make.names(x) == x
59+
5560
# NB: xml2 uses xpath 1.0 which doesn't support matches() for regex, so we
5661
# have to jump out of xpath to complete this lint.
5762
# It's also a bit tough to get the escaping through R and then xpath to
@@ -157,10 +162,3 @@ keyword_quote_linter <- function() {
157162
c(call_arg_lints, string_assignment_lints, assignment_lints, string_extraction_lints, extraction_lints)
158163
})
159164
}
160-
161-
#' Check if a string could be assigned as an R variable.
162-
#'
163-
#' See [make.names()] for the description of syntactically valid names in R.
164-
#'
165-
#' @noRd
166-
is_valid_r_name <- function(x) make.names(x) == x

R/matrix_apply_linter.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,5 +149,5 @@ craft_colsums_rowsums_msg <- function(var, margin, fun, narm_val) {
149149
# It's easier to remove this after the fact, rather than having never ending if/elses
150150
reco <- gsub(", dims = 1", "", reco, fixed = TRUE)
151151

152-
return(reco)
152+
reco
153153
}

R/nested_ifelse_linter.R

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,3 @@ nested_ifelse_linter <- function() {
5959
xml_nodes_to_lints(bad_expr, source_expression, lint_message, type = "warning")
6060
})
6161
}
62-
63-
# functions equivalent to base::ifelse() for linting purposes
64-
# NB: this is re-used elsewhere, e.g. in ifelse_censor_linter
65-
ifelse_funs <- c("ifelse", "if_else", "fifelse")

0 commit comments

Comments
 (0)