-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New linters and bug fixes #214
Conversation
…nportable_path_linter() with a "lax" option for fewer false positibe lints.
…_terminator_linter() * find some trailing semicolons not previously detected * find compound semicolons, i.e. semicolon between two statements on the same line * "type" option to lint "trailing" and/or "compound" semicolons
* features of the linter described at r-lib#194 * default_linters() changed accordingly (enforce lowerCamelCase) * refactored make_object_linter() since it returned too many objects that were out of the scope, and failed to return some that were
* Do not lint comments within roxygen blocks (this follows the linter's description, strictly speaking). This allows to write comments that show the expected result in @example roxygen blocks, e.g.: #' @examples #' foo(1) ## list(1) * Do not consider "-" an R operator to avoid too many false positives, e.g. in "# Non-existent"
* do not display markers when check is NULL * fixed malformed error messages * more consistent errors messages * check validity of Lint fields in 'checks' * return invisible(NULL), just like expect_error() * doc update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to deprecate the removed functions with .Deprecated()
for at least one release, for the object linters like snake_case_linter I think you can just have it call object_name_linter("snake_case")
internally.
More generally I think we should move away from using regular expressions if possible and towards using the token dataframe or more ideally XPath expressions on the XML versions of the parse tokens.
The regular expressions and custom logic make the function definitions pretty hard to follow and maintain, having each use a (perhaps complex) XPath expression could potentially homogenize the implementations.
R/undesirable_function_linter.R
Outdated
"detach"="use roxygen2's @importFrom statement in packages, or `::` in scripts", | ||
"library"= "use roxygen2's @importFrom statement in packages, or `::` in scripts", | ||
"require"= "use roxygen2's @importFrom statement in packages, or `::` in scripts", | ||
"loadNamespace"="use `::` or requireNamespace()", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think loadNamespace
should be linted, I actually prefer using it in most cases, most of the time you use it for suggested packages and do want to throw an error if a package is not installed. See http://r-pkgs.had.co.nz/namespace.html#search-path for a discussion of the differences.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you are generally aiming to follow Hadley's style and guidelines, loadNamespace
should be left in by default.
R/undesirable_function_linter.R
Outdated
"source"=NA, | ||
"sapply"="use vapply() or lapply()", | ||
"mapply"="use Map()", | ||
"ifelse"="use an if () {} else {} block", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While it is true some (most?) of the time people use ifelse when it would be better to use if()
there are cases where you do want to branch on a vectorized conditional, I think it is too aggressive to lint this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll remove it from the default. I will likely make it available a set of extended defaults for those that prefer to lint aggressively.
R/undesirable_function_linter.R
Outdated
"sapply"="use vapply() or lapply()", | ||
"mapply"="use Map()", | ||
"ifelse"="use an if () {} else {} block", | ||
"return"="let the last value of a function automatically be returned", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return()
is still very useful for early returns, you would need to only lint this at the end of a function body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that just reflected my preference. I will remove if from the defaults. In the case of return
, a separate linter would be preferable anyway,
R/undesirable_function_linter.R
Outdated
"mapply"="use Map()", | ||
"ifelse"="use an if () {} else {} block", | ||
"return"="let the last value of a function automatically be returned", | ||
"substring"="use substr()" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I think this is also too aggressive, substring recycles its first argument, which makes it useful for some things.
substring("abcdefghijklmnop", seq(1, 15, 5))
#> [1] "abcdefghijklmnop" "fghijklmnop" "klmnop"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries. Again, this only reflected my own personal biases.
R/path_linters.R
Outdated
) | ||
} | ||
|
||
is_long_path <- function(str) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think path
is a better name for this argument in all of these path functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The three functions is_valid_path()
, is_long_path()
and is_valid_long_path()
do indeed expect some sort of path as input. It makes sense to change the argument name as you suggested.
I am not so convinced about changing the argument name for the four functions is_absolute_path()
, is_root_path()
, is_relative_path()
, is_path()
because the input is a string and the functions determine if this is a path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine, split_path()
arguments need to be path
and sep
though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we were splitting hairs, so I changed it to "path" anyway.
I will do the same for split_path
as well.
R/object_name_linters.R
Outdated
#' @param style UpperCamelCase, lowerCamelCase, alllowercase, ALLUPPERCASE, snake_case or | ||
#' dotted.case | ||
#' @export | ||
object_name_linter <- function(style = "lowerCamelCase") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default needs to be snake_case
.
R/comment_linters.R
Outdated
code_locs <<- register_code_locations(source_file, code_locs) | ||
} else { | ||
# non-code section: detect and report TODOs | ||
if (length(file_lines) == 0L) {file_lines <- ""} # workaround rex bug goo.gl/2rbZDy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather have a full link rather than short url, as the full link contains information that can be used to retrieve the issue even if the link breaks in the future, such as repo username and issue number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is understandable.
#' @describeIn linters Check that the source contains no TODO comments (case-insensitive). | ||
#' @param todo Vector of strings that identify TODO comments. | ||
#' @export | ||
todo_comment_linter <- function(todo=c("todo", "fixme")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this function should just use the getParseData()
and check for a COMMENT
token that has text ^#[[:spaces:]]TODO
, why is all this complication needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is more complicated than anticipated because not all comments are reported within source_file$parsed_content
.
# TODO 1
x <- 3 # TODO 2
foo <- function(x) { # TODO 3
# TODO 4
x * 2 # TODO 5
}
y <- foo(x) # TODO 6
# TODO 7
In the example above, only TODO 3-5 are returned as tokens. In semicolon_terminator_linter()
, there is a similar issue that is addressed by the locate_other_sc
function.
…fault lintr naming style
Deprecated function / replacement function / alias: * camel_case_linter / object_name_linter / - * snake_case_linter/ object_name_linter / - * multiple_dots_linter / object_name_linter / - * trailing_semicolons_linter / semicolon_terminator_linter / semicolon_terminator_linter(type = "trailing) * absolute_paths_linter / absolute_path_linter / absolute_path_linter(lax = TRUE)
Use lintr:::expect_lint() instead of expect_lint() because it is a private function
Yes this is true, we will probably need to keep the old definitions around until these functions are completely deprecated and gone then. |
R/path_linters.R
Outdated
) | ||
} | ||
|
||
is_long_path <- function(str) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine, split_path()
arguments need to be path
and sep
though.
R/path_linters.R
Outdated
for (q in type) { | ||
str <- re_substitutes(str, rex(start, q, capture(zero_or_more(any)), q, end), "\\1") | ||
} | ||
stringi::stri_unescape_unicode(str) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot depend on stringi, you can look at base alternatives if you need this http://stackoverflow.com/a/25310392/2055486
I have implemented an |
Codecov Report
@@ Coverage Diff @@
## master #214 +/- ##
==========================================
+ Coverage 81.31% 85.65% +4.33%
==========================================
Files 30 37 +7
Lines 1702 2133 +431
==========================================
+ Hits 1384 1827 +443
+ Misses 318 306 -12
Continue to review full report at Codecov.
|
Ok I think all that is left is updating the NEWS file and README explaining the changes / listing the new linters added. |
This is done. It is a minor commit, so, I merging this PR now. |
Please let me merge major things like this. |
Ok, sorry for my impatience. Thank you, Jim. |
No description provided.