Internally at Google we use lintr to power our in-editor and CI-based R linting tools. Over the last year+ (in addition to working directly on lintr) we have been building out a set of linters that extends the suite offered by lintr. Currently, the package has >60 such linters, almost all of which we think are widely relevant. They have all been test on & applied to existing internal R code at Google.
We are happy to contribute any subset of these to lintr. Here is a brief summary of all of them; I can elaborate more as needed:
AnyDuplicatedLinter - Require usage of anyDuplicated() > 0 over any(duplicated(.))
AnyIsNALinter - Require usage of anyNA over any(is.na(.))
ApplyAnonymousLinter - Block usage of anonymous functions in *apply functions when unnecessary New unnecessary_lambda_linter #1541
BaseOverwriteLinter - Block assigning any variables whose name clashes with a 'base' R function New object_overwrite_linter #2307
BooleanArithmeticLinter New boolean_arithmetic_linter #1579
CharacterOnlyLinter - Enforce library calls using symbols Extend library_call_linter for character.only usage #2279
ClassEqualsLinter - Block comparison of class with ==
ComparisonNegationLinter New comparison_negation_linter #2272
ConsecutiveMutateLinter New consecutive_mutate_linter #2305
ConsecutiveSuppressionLinter New consecutive_suppression_linter #2306
ElseSameLineLinter - Require else to come on the same line as
EmptyAssignmentLinter - Block assignment of {} New empty_assignment_linter #1637
ExpectComparisonLinter - Require usage of expect_gt(x, y) over expect_true(x > y) (and similar) Expect comparison #955
ExpectIdenticalLinter - Require usage of expect_identical(x, y) where appropriate New expect_identical_linter #958
ExpectIsLinter - Redirect away from deprecated testthat::expect_is() expect_is_linter, or just use undesirable_function_linter? #946
ExpectLengthLinter - Require usage of expect_length(x, n) over expect_equal(length(x), n) New expect_length_linter #950
ExpectNamedLinter - Require usage of expect_named(x, n) over expect_equal(names(x), n) New expect_named_linter #949
ExpectNotLinter - Require usage of expect_false(.) over expect_true(!.) New expect_not_linter #945
ExpectNullLinter - Require usage of expect_null(x) over expect_equal(x, NULL) and similar expect_null_linter #887
ExpectS3ClassLinter - Require usage of expect_s3_class() or expect_s4_class() where appropriate. expect_s3_class_linter and expect_s4_class_linter #943
ExpectS4ClassLinter - Require usage of expect_s4_class(x, k) over expect_true(is(x, k)) expect_s3_class_linter and expect_s4_class_linter #943
ExpectTrueFalseAndConditionLinter - Force && conditions in expect_true(), expect_false() to be written separately New conjunct_expecation_linter #948
ExpectTrueFalseLinter - Require usage of expect_true(x) over expect_equal(x, TRUE) New expect_true_false_linter #947
ExpectTypeLinter - Require usage of expect_type(x, type) over expect_equal(typeof(x), type) expect_type_linter #924
ExplicitReturnLinter Linter for explicit/implicit returns #2271
FilterAndConditionLinter extend conjunct_test_linter for dplyr::filter() #2077
FixedRegexLinter - Require usage of 'fixed=TRUE' in regular expressions where appropriate New fixed_regex_linter #1021
ForLoopIndexLinter - Block usage of for loops directly overwriting the indexing variable New for_loop_index_linter #1629
FunctionBraceLinter - Require multi-line functions to use braces
GrepSubsetLinter - Require usage of grep(value = TRUE) over xgrep(x)
IfelseCensorLinter - Block usage of ifelse where pmin or pmax is more appropriate
IfElseMatchBracesLinter - Require both or neither if/else branches to use curly braces
IfNotElseLinter if_not_else_linter() for "double negation" in if statements #2071
IfSwitchLinter - Require usage of switch() over repeated if/else blocks New if_switch_linter #2304
ImplicitElseReturnLinter New allow_implicit_else argument for return_linter #2321
InnerCombineLinter - Require c() to be applied before relatively expensive vectorized functions
InnerComparisonLinter - Require == to be used outside of sapply() when comparing to a constant Extend unnecessary_lambda_linter to look for "inner comparisons" #2300
IsNumericLinter - Redirect is.numeric(x) || is.integer(x) to just use is.numeric(x) New is_numeric_linter #1635
KeywordQuoteLinter - Block unnecessary quoting in calls keyword_quote_linter for unnecessary quoting #2030
LengthLevelsLinter - Require usage of nlevels over length(levels(.)) length_levels_linter() for length(levels(x)) --> nlevels(x) #2051
LengthsLinter New lengths_linter #1568
ListComparisonLinter New list_comparison_linter #2293
LiteralCoercionLinter - Require usage of correctly-typed literals over literal coercions
MagrittrDotLinter New unnecessary_placeholder_linter #1656
MultipleStopifnotLinter - Force consecutive stopifnot() calls into just one
NestedIfelseLinter - Block usage of nested ifelse() calls
NestedPipeLinter New nested_pipe_linter #2301
NrowSubsetLinter New nrow_subset_linter #2298
NumericLeadingZeroLinter - Require usage of a leading zero in all fractional numerics
OneCallPipeLinter New one_call_pipe_linter #2294
OuterNegationLinter - Require usage of !any(.) over all(!.), !all(.) over any(!.)
PasteFilePathLinter - Block usage of paste() with sep='/' file path detection in paste_linter #2074
PasteSepLinter - Block usage of paste() with sep=''
PasteStrrepLinter - Require usage of strrep('.', n) over paste(rep('.', n), collapse = '') extend paste_linter() for strrep() equivalents #1652
PasteToStringLinter - Block usage of paste() with collapse=', '
PipeCallLinter - Force explicit calls in magrittr pipes New pipe_call_linter enforcing calls (not symbols) in magrittr pipes #801
PipeReturnLinter New pipe_return_linter #2299
RedundantEqualsLinter New redundant_equals_linter #1556
RedundantIfelseLinter - Prevent ifelse() from being used to produce TRUE/FALSE
RepLenLinter New rep_len_linter #2286
ReturnAssignmentLinter New function_return_linter() #1569
RequireNzcharLinter - Require usage of nzchar where appropriate New nzchar_linter #2275
RoutineRegistrationLinter - Identify .Call usage to unregistered routines New routine_registration_linter #1669
SampleIntLinter - Require usage of sample.int(n, m, ...) over sample(1:n, m, ...) New sample_int_linter #2274
ScalarInLinter - Block usage like x %in% 'a' scalar_in_linter() for x %in% 1 #2084
StopifnotAllLinter New stopifnot_all_linter #2273
StopifnotAndConditionLinter - Force && conditions in stopifnot() to be written separately
StopPasteLinter - Block usage of paste() and paste0() with messaging functions using ...
StringsAsFactorsLinter - Identify cases where stringsAsFactors should be supplied explicitly
SystemFileLinter - Block usage of file.path() with system.file()
TerminalCloseLinter - Prohibit close() from terminating a function definition New terminal_close_linter #2276
UnnecessaryNestingLinter New unnecessary_nesting_linter #2302
UnreachableCodeLinter - Block unreachable code and comments following return statements
VectorLogicLinter - Enforce usage of scalar && in conditional statements
WhichGreplLinter - Require usage of grep over which(grepl(.)) New which_grepl_linter #2281
YodaTestLinter - Block obvious 'yoda tests' New yoda_test_linter #957
What do you think is the best way to decide about which are in/out of scope for lintr? Does it make sense to delay this until 3.0 is released, or push to include with the major version bump?
Internally at Google we use
lintrto power our in-editor and CI-based R linting tools. Over the last year+ (in addition to working directly onlintr) we have been building out a set of linters that extends the suite offered bylintr. Currently, the package has >60 such linters, almost all of which we think are widely relevant. They have all been test on & applied to existing internal R code at Google.We are happy to contribute any subset of these to
lintr. Here is a brief summary of all of them; I can elaborate more as needed:AnyDuplicatedLinter- Require usage of anyDuplicated() > 0 over any(duplicated(.))AnyIsNALinter- Require usage of anyNA over any(is.na(.))ApplyAnonymousLinter- Block usage of anonymous functions in *apply functions when unnecessary New unnecessary_lambda_linter #1541BaseOverwriteLinter- Block assigning any variables whose name clashes with a 'base' R function New object_overwrite_linter #2307BooleanArithmeticLinterNew boolean_arithmetic_linter #1579CharacterOnlyLinter- Enforce library calls using symbols Extend library_call_linter for character.only usage #2279ClassEqualsLinter- Block comparison of class with ==ComparisonNegationLinterNew comparison_negation_linter #2272ConsecutiveMutateLinterNew consecutive_mutate_linter #2305ConsecutiveSuppressionLinterNew consecutive_suppression_linter #2306ElseSameLineLinter- Require else to come on the same line asEmptyAssignmentLinter- Block assignment of {} New empty_assignment_linter #1637ExpectComparisonLinter- Require usage of expect_gt(x, y) over expect_true(x > y) (and similar) Expect comparison #955ExpectIdenticalLinter- Require usage of expect_identical(x, y) where appropriate New expect_identical_linter #958ExpectIsLinter- Redirect away from deprecated testthat::expect_is() expect_is_linter, or just use undesirable_function_linter? #946ExpectLengthLinter- Require usage of expect_length(x, n) over expect_equal(length(x), n) New expect_length_linter #950ExpectNamedLinter- Require usage of expect_named(x, n) over expect_equal(names(x), n) New expect_named_linter #949ExpectNotLinter- Require usage of expect_false(.) over expect_true(!.) New expect_not_linter #945ExpectNullLinter- Require usage of expect_null(x) over expect_equal(x, NULL) and similar expect_null_linter #887ExpectS3ClassLinter- Require usage of expect_s3_class() or expect_s4_class() where appropriate. expect_s3_class_linter and expect_s4_class_linter #943ExpectS4ClassLinter- Require usage of expect_s4_class(x, k) over expect_true(is(x, k)) expect_s3_class_linter and expect_s4_class_linter #943ExpectTrueFalseAndConditionLinter- Force && conditions in expect_true(), expect_false() to be written separately New conjunct_expecation_linter #948ExpectTrueFalseLinter- Require usage of expect_true(x) over expect_equal(x, TRUE) New expect_true_false_linter #947ExpectTypeLinter- Require usage of expect_type(x, type) over expect_equal(typeof(x), type) expect_type_linter #924ExplicitReturnLinterLinter for explicit/implicit returns #2271FilterAndConditionLinterextend conjunct_test_linter for dplyr::filter() #2077FixedRegexLinter- Require usage of 'fixed=TRUE' in regular expressions where appropriate New fixed_regex_linter #1021ForLoopIndexLinter- Block usage of for loops directly overwriting the indexing variable New for_loop_index_linter #1629FunctionBraceLinter- Require multi-line functions to use bracesGrepSubsetLinter- Require usage of grep(value = TRUE) over xgrep(x)IfelseCensorLinter- Block usage of ifelse where pmin or pmax is more appropriateIfElseMatchBracesLinter- Require both or neither if/else branches to use curly bracesIfNotElseLinterif_not_else_linter() for "double negation" in if statements #2071IfSwitchLinter- Require usage of switch() over repeated if/else blocks New if_switch_linter #2304ImplicitElseReturnLinterNew allow_implicit_else argument for return_linter #2321InnerCombineLinter- Require c() to be applied before relatively expensive vectorized functionsInnerComparisonLinter- Require == to be used outside of sapply() when comparing to a constant Extend unnecessary_lambda_linter to look for "inner comparisons" #2300IsNumericLinter- Redirect is.numeric(x) || is.integer(x) to just use is.numeric(x) New is_numeric_linter #1635KeywordQuoteLinter- Block unnecessary quoting in calls keyword_quote_linter for unnecessary quoting #2030LengthLevelsLinter- Require usage of nlevels over length(levels(.)) length_levels_linter() for length(levels(x)) --> nlevels(x) #2051LengthsLinterNew lengths_linter #1568ListComparisonLinterNew list_comparison_linter #2293LiteralCoercionLinter- Require usage of correctly-typed literals over literal coercionsMagrittrDotLinterNew unnecessary_placeholder_linter #1656MultipleStopifnotLinter- Force consecutive stopifnot() calls into just oneNestedIfelseLinter- Block usage of nested ifelse() callsNestedPipeLinterNew nested_pipe_linter #2301NrowSubsetLinterNew nrow_subset_linter #2298NumericLeadingZeroLinter- Require usage of a leading zero in all fractional numericsOneCallPipeLinterNew one_call_pipe_linter #2294OuterNegationLinter- Require usage of !any(.) over all(!.), !all(.) over any(!.)PasteFilePathLinter- Block usage of paste() with sep='/' file path detection in paste_linter #2074PasteSepLinter- Block usage of paste() with sep=''PasteStrrepLinter- Require usage of strrep('.', n) over paste(rep('.', n), collapse = '') extend paste_linter() for strrep() equivalents #1652PasteToStringLinter- Block usage of paste() with collapse=', 'PipeCallLinter- Force explicit calls in magrittr pipes New pipe_call_linter enforcing calls (not symbols) in magrittr pipes #801PipeReturnLinterNew pipe_return_linter #2299RedundantEqualsLinterNew redundant_equals_linter #1556RedundantIfelseLinter- Prevent ifelse() from being used to produce TRUE/FALSERepLenLinterNew rep_len_linter #2286ReturnAssignmentLinterNewfunction_return_linter()#1569RequireNzcharLinter- Require usage of nzchar where appropriate New nzchar_linter #2275RoutineRegistrationLinter- Identify .Call usage to unregistered routines New routine_registration_linter #1669SampleIntLinter- Require usage of sample.int(n, m, ...) over sample(1:n, m, ...) New sample_int_linter #2274ScalarInLinter- Block usage like x %in% 'a' scalar_in_linter() for x %in% 1 #2084StopifnotAllLinterNew stopifnot_all_linter #2273StopifnotAndConditionLinter- Force && conditions in stopifnot() to be written separatelyStopPasteLinter- Block usage of paste() and paste0() with messaging functions using ...StringsAsFactorsLinter- Identify cases where stringsAsFactors should be supplied explicitlySystemFileLinter- Block usage of file.path() with system.file()TerminalCloseLinter- Prohibit close() from terminating a function definition New terminal_close_linter #2276UnnecessaryNestingLinterNew unnecessary_nesting_linter #2302UnreachableCodeLinter- Block unreachable code and comments following return statementsVectorLogicLinter- Enforce usage of scalar && in conditional statementsWhichGreplLinter- Require usage of grep over which(grepl(.)) New which_grepl_linter #2281YodaTestLinter- Block obvious 'yoda tests' New yoda_test_linter #957What do you think is the best way to decide about which are in/out of scope for
lintr? Does it make sense to delay this until 3.0 is released, or push to include with the major version bump?