| Title: | Find and Fix Lints in R Code |
|---|---|
| Description: | Lints are code patterns that are not optimal because they are inefficient, forget corner cases, or are less readable. 'flir' provides a small set of functions to detect those lints and automatically fix them. It builds on 'astgrepr', which itself uses the 'Rust' crate 'ast-grep' to parse and navigate R code. |
| Authors: | Etienne Bacher [aut, cre, cph], lintr authors [aut], Trevor L. Davis [ctb] (ORCID: <https://orcid.org/0000-0001-6341-4639>) |
| Maintainer: | Etienne Bacher <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.6.0 |
| Built: | 2026-05-14 08:06:18 UTC |
| Source: | https://github.com/etiennebacher/flir |
This function creates a YAML file with the placeholder text to define a new
rule. The file is stored in flir/rules/custom. You need to create the
flir folder with setup_flir() if it doesn't exist.
If you want to create a rule that users of your package will be able to
access, use export_new_rule() instead.
add_new_rule(name, path)add_new_rule(name, path)
name |
Name(s) of the rule. Cannot contain white space. |
path |
Path to package or project root. If |
Create new file(s) but doesn't return anything
anyDuplicated(x) > 0 over any(duplicated(x))
See https://lintr.r-lib.org/reference/any_duplicated_linter.
any_duplicated_linterany_duplicated_linter
The name of the linter
anyNA(x) over any(is.na(x))
See https://lintr.r-lib.org/reference/any_is_na_linter.
any_is_na_linterany_is_na_linter
The name of the linter
==
See https://lintr.r-lib.org/reference/class_equals_linter.
class_equals_linterclass_equals_linter
The name of the linter
paste() and paste0() with messaging functions using ...
See https://lintr.r-lib.org/reference/condition_message_linter.
condition_message_lintercondition_message_linter
The name of the linter
double_assignment
double_assignment_linterdouble_assignment_linter
The name of the linter
See https://lintr.r-lib.org/reference/duplicate_argument_linter.
duplicate_argument_linterduplicate_argument_linter
The name of the linter
empty_assignment
empty_assignment_linterempty_assignment_linter
The name of the linter
equal_assignment
equal_assignment_linterequal_assignment_linter
The name of the linter
See https://lintr.r-lib.org/reference/equals_na_linter.
equals_na_linterequals_na_linter
The name of the linter
expect_gt(x, y) over expect_true(x > y) (and similar)See https://lintr.r-lib.org/reference/expect_comparison_linter.
expect_comparison_linterexpect_comparison_linter
The name of the linter
expect_identical(x, y) where appropriateSee https://lintr.r-lib.org/reference/expect_identical_linter.
expect_identical_linterexpect_identical_linter
The name of the linter
expect_length(x, n) over expect_equal(length(x), n)
See https://lintr.r-lib.org/reference/expect_length_linter.
expect_length_linterexpect_length_linter
The name of the linter
expect_named(x, n) over expect_equal(names(x), n)
See https://lintr.r-lib.org/reference/expect_named_linter.
expect_named_linterexpect_named_linter
The name of the linter
expect_false(x) over expect_true(!x)
See https://lintr.r-lib.org/reference/expect_not_linter.
expect_not_linterexpect_not_linter
The name of the linter
expect_null for checking NULL
See https://lintr.r-lib.org/reference/expect_null_linter.
expect_null_linterexpect_null_linter
The name of the linter
expect_s3_class()
See https://lintr.r-lib.org/reference/expect_s3_class_linter.
expect_s3_class_linterexpect_s3_class_linter
The name of the linter
expect_s4_class(x, k) over expect_true(is(x, k))
See https://lintr.r-lib.org/reference/expect_s4_class_linter.
expect_s4_class_linterexpect_s4_class_linter
The name of the linter
expect_true(x) over expect_equal(x, TRUE)
See https://lintr.r-lib.org/reference/expect_true_false_linter.
expect_true_false_linterexpect_true_false_linter
The name of the linter
expect_type(x, type) over expect_equal(typeof(x), type)
See https://lintr.r-lib.org/reference/expect_type_linter.
expect_type_linterexpect_type_linter
The name of the linter
This function creates a YAML file with the placeholder text to define a new
rule. The file is stored in inst/flir/rules and will be available to users
of your package if they use flir.
To create a new rule that you can use in the current project only, use
add_new_rule() instead.
export_new_rule(name, path)export_new_rule(name, path)
name |
Name(s) of the rule. Cannot contain white space. |
path |
Path to package or project root. If |
Create new file(s) but doesn't return anything
fix(), fix_package(), and fix_dir() all replace lints in files. The
only difference is in the input they take:
fix() takes path to files or directories
fix_dir() takes a path to one directory
fix_package() takes a path to the root of a package and looks at the
following list of folders: R, tests, inst, vignettes, data-raw,
demo, exec.
fix_text() takes some text input. Its main interest is to be able to
quickly experiment with some lints and fixes.
fix( path, linters = NULL, exclude_path = NULL, exclude_linters = NULL, force = FALSE, verbose = TRUE, rerun = TRUE, interactive = FALSE ) fix_dir( path, linters = NULL, exclude_path = NULL, exclude_linters = NULL, force = FALSE, verbose = TRUE, rerun = TRUE, interactive = FALSE ) fix_package( path, linters = NULL, exclude_path = NULL, exclude_linters = NULL, force = FALSE, verbose = TRUE, rerun = TRUE, interactive = FALSE ) fix_text(text, linters = NULL, exclude_linters = NULL, rerun = TRUE)fix( path, linters = NULL, exclude_path = NULL, exclude_linters = NULL, force = FALSE, verbose = TRUE, rerun = TRUE, interactive = FALSE ) fix_dir( path, linters = NULL, exclude_path = NULL, exclude_linters = NULL, force = FALSE, verbose = TRUE, rerun = TRUE, interactive = FALSE ) fix_package( path, linters = NULL, exclude_path = NULL, exclude_linters = NULL, force = FALSE, verbose = TRUE, rerun = TRUE, interactive = FALSE ) fix_text(text, linters = NULL, exclude_linters = NULL, rerun = TRUE)
path |
A valid path to a file or a directory. Relative paths are
accepted. Contrarily to |
linters |
A character vector with the names of the rules to apply. See
the entire list of rules with |
exclude_path |
One or several paths that will be ignored from the |
exclude_linters |
One or several linters that will not be checked.
Values can be the names of linters (such as |
force |
Force the application of fixes on the files. This is used only in the case where Git is not detected, several files will be modified, and the code is run in a non-interactive setting. |
verbose |
Show messages. |
rerun |
Run the function several times until there are no more fixes to
apply. This is useful in the case of nested lints. If |
interactive |
Opens a Shiny app that shows a visual diff of each
modified file. This is particularly useful when you want to review the
potential fixes before accepting them. Setting this to |
text |
Text to analyze (and to fix if necessary). |
A list with as many elements as there are files to fix (in fix_text(),
the text is written to a temporary file).
Each element of the list contains the fixed text, where all fixes available have been applied.
flir supports ignoring single lines of code with # flir-ignore. For
example, this will not warn:
# flir-ignore any(duplicated(x))
However, this will warn for the second any(duplicated()):
# flir-ignore any(duplicated(x)) any(duplicated(y))
To ignore more than one line of code, use # flir-ignore-start and
# flir-ignore-end:
# flir-ignore-start any(duplicated(x)) any(duplicated(y)) # flir-ignore-end
# `fix_text()` is convenient to explore with a small example fix_text("any(duplicated(rnorm(5)))") fix_text("any(duplicated(rnorm(5))) any(is.na(x)) ") # Setup for the example with `fix()` destfile <- tempfile() cat(" x = c(1, 2, 3) any(duplicated(x), na.rm = TRUE) any(duplicated(x)) if (any(is.na(x))) { TRUE } any( duplicated(x) )", file = destfile) fix(destfile) cat(paste(readLines(destfile), collapse = "\n"))# `fix_text()` is convenient to explore with a small example fix_text("any(duplicated(rnorm(5)))") fix_text("any(duplicated(rnorm(5))) any(is.na(x)) ") # Setup for the example with `fix()` destfile <- tempfile() cat(" x = c(1, 2, 3) any(duplicated(x), na.rm = TRUE) any(duplicated(x)) if (any(is.na(x))) { TRUE } any( duplicated(x) )", file = destfile) fix(destfile) cat(paste(readLines(destfile), collapse = "\n"))
See https://lintr.r-lib.org/reference/for_loop_index_linter.
for_loop_index_linterfor_loop_index_linter
The name of the linter
See https://lintr.r-lib.org/reference/function_return_linter.
function_return_linterfunction_return_linter
The name of the linter
implicit_assignment
implicit_assignment_linterimplicit_assignment_linter
The name of the linter
is.numeric(x) || is.integer(x) to just use is.numeric(x)
See https://lintr.r-lib.org/reference/is_numeric_linter.
is_numeric_linteris_numeric_linter
The name of the linter
See https://lintr.r-lib.org/reference/length_levels_linter.
length_levels_linterlength_levels_linter
The name of the linter
See https://lintr.r-lib.org/reference/length_test_linter.
length_test_linterlength_test_linter
The name of the linter
lengths() where possibleSee https://lintr.r-lib.org/reference/lengths_linter.
lengths_linterlengths_linter
The name of the linter
See https://lintr.r-lib.org/reference/library_call_linter.
library_call_linterlibrary_call_linter
The name of the linter
lint(), lint_text(), lint_package(), and lint_dir() all produce a
data.frame containing the lints, their location, and potential fixes. The
only difference is in the input they take:
lint() takes path to files or directories
lint_text() takes some text input
lint_dir() takes a path to one directory
lint_package() takes a path to the root of a package and looks at the
following list of folders: R, tests, inst, vignettes, data-raw,
demo, exec.
lint( path = ".", linters = NULL, exclude_path = NULL, exclude_linters = NULL, open = TRUE, use_cache = TRUE, verbose = TRUE ) lint_dir( path = ".", linters = NULL, open = TRUE, exclude_path = NULL, exclude_linters = NULL, use_cache = TRUE, verbose = TRUE ) lint_package( path = ".", linters = NULL, open = TRUE, exclude_path = NULL, exclude_linters = NULL, use_cache = TRUE, verbose = TRUE ) lint_text(text, linters = NULL, exclude_linters = NULL)lint( path = ".", linters = NULL, exclude_path = NULL, exclude_linters = NULL, open = TRUE, use_cache = TRUE, verbose = TRUE ) lint_dir( path = ".", linters = NULL, open = TRUE, exclude_path = NULL, exclude_linters = NULL, use_cache = TRUE, verbose = TRUE ) lint_package( path = ".", linters = NULL, open = TRUE, exclude_path = NULL, exclude_linters = NULL, use_cache = TRUE, verbose = TRUE ) lint_text(text, linters = NULL, exclude_linters = NULL)
path |
A valid path to a file or a directory. Relative paths are
accepted. Default is |
linters |
A character vector with the names of the rules to apply. See
the entire list of rules with |
exclude_path |
One or several paths that will be ignored from the |
exclude_linters |
One or several linters that will not be checked.
Values can be the names of linters (such as |
open |
If |
use_cache |
Do not re-parse files that haven't changed since the last time this function ran. |
verbose |
Show messages. |
text |
Text to analyze. |
A dataframe where each row is a lint. The columns show the text, its location (both the position in the text and the file in which it was found) and the severity.
flir supports ignoring single lines of code with # flir-ignore. For
example, this will not warn:
# flir-ignore any(duplicated(x))
However, this will warn for the second any(duplicated()):
# flir-ignore any(duplicated(x)) any(duplicated(y))
To ignore more than one line of code, use # flir-ignore-start and
# flir-ignore-end:
# flir-ignore-start any(duplicated(x)) any(duplicated(y)) # flir-ignore-end
# `lint_text()` is convenient to explore with a small example lint_text("any(duplicated(rnorm(5)))") lint_text("any(duplicated(rnorm(5))) any(is.na(x)) ") # Setup for the example with `lint()` destfile <- tempfile() cat(" x = c(1, 2, 3) any(duplicated(x), na.rm = TRUE) any(duplicated(x)) if (any(is.na(x))) { TRUE } any( duplicated(x) )", file = destfile) lint(destfile)# `lint_text()` is convenient to explore with a small example lint_text("any(duplicated(rnorm(5)))") lint_text("any(duplicated(rnorm(5))) any(is.na(x)) ") # Setup for the example with `lint()` destfile <- tempfile() cat(" x = c(1, 2, 3) any(duplicated(x), na.rm = TRUE) any(duplicated(x)) if (any(is.na(x))) { TRUE } any( duplicated(x) )", file = destfile) lint(destfile)
See https://lintr.r-lib.org/reference/list_comparison_linter.
list_comparison_linterlist_comparison_linter
The name of the linter
flir
Get the list of linters in flir
list_linters(path = ".")list_linters(path = ".")
path |
A valid path to a file or a directory. Relative paths are
accepted. Default is |
A character vector
list_linters(".")list_linters(".")
See https://lintr.r-lib.org/reference/literal_coercion_linter.
literal_coercion_linterliteral_coercion_linter
The name of the linter
colSums(x) or rowSums(x) over apply(x, ., sum)
See https://lintr.r-lib.org/reference/matrix_apply_linter.
matrix_apply_lintermatrix_apply_linter
The name of the linter
See https://lintr.r-lib.org/reference/missing_argument_linter.
missing_argument_lintermissing_argument_linter
The name of the linter
ifelse() callsSee https://lintr.r-lib.org/reference/nested_ifelse_linter.
nested_ifelse_linternested_ifelse_linter
The name of the linter
See https://lintr.r-lib.org/reference/numeric_leading_zero_linter.
numeric_leading_zero_linternumeric_leading_zero_linter
The name of the linter
See https://lintr.r-lib.org/reference/nzchar_linter.
nzchar_linternzchar_linter
The name of the linter
!any(x) over all(!x), !all(x) over any(!x)
See https://lintr.r-lib.org/reference/outer_negation_linter.
outer_negation_linterouter_negation_linter
The name of the linter
See https://lintr.r-lib.org/reference/package_hooks_linter.
package_hooks_linterpackage_hooks_linter
The name of the linter
paste()
See https://lintr.r-lib.org/reference/paste_linter.
paste_linterpaste_linter
The name of the linter
==, != on logical vectorsSee https://lintr.r-lib.org/reference/redundant_equals_linter.
redundant_equals_linterredundant_equals_linter
The name of the linter
ifelse() from being used to produce TRUE/FALSE or 1/0
See https://lintr.r-lib.org/reference/redundant_ifelse_linter.
redundant_ifelse_linterredundant_ifelse_linter
The name of the linter
See https://lintr.r-lib.org/reference/rep_len_linter.
rep_len_linterrep_len_linter
The name of the linter
right_assignment
right_assignment_linterright_assignment_linter
The name of the linter
See https://lintr.r-lib.org/reference/sample_int_linter.
sample_int_lintersample_int_linter
The name of the linter
See https://lintr.r-lib.org/reference/seq_linter.
seq_linterseq_linter
The name of the linter
This creates a flir folder that has multiple purposes. It contains:
the file config.yml where you can define rules to keep or exclude, as
well as rules defined in other packages. More on this below;
the file cache_file_state.rds, which is used when lint_*() or fix_*()
have cache = TRUE;
an optional folder rules/custom where you can store your own rules.
This folder must live at the root of the project and cannot be renamed.
setup_flir(path)setup_flir(path)
path |
Path to package or project root. If |
The file flir/config.yml can contain three fields: keep, exclude,
and from-package.
keep and exclude are used to define the rules to keep or to exclude when
running lint_*() or fix_*().
It is possible for other packages to create their own list of rules, for
instance to detect or replace deprecated functions. In from-package, you
can list package names where flir should look for additional rules. By
default, if you list package foobar, then all rules defined in the package
foobar will be used. To ignore some of those rules, you can list
from-foobar-<rulename> in the exclude field.
See the vignette Sharing rules across packages for more information.
Imports files necessary for flir to work but doesn't return any
value in R.
flir
Create a Github Actions workflow for flir
setup_flir_gha(path, overwrite = FALSE)setup_flir_gha(path, overwrite = FALSE)
path |
Path to package or project root. If |
overwrite |
Whether to overwrite |
Creates .github/workflows/flir.yaml but doesn't return any value.
See https://lintr.r-lib.org/reference/sort_linter.
sort_lintersort_linter
The name of the linter
See https://lintr.r-lib.org/reference/stopifnot_all_linter.
stopifnot_all_linterstopifnot_all_linter
The name of the linter
T and F symbol linterSee https://lintr.r-lib.org/reference/T_and_F_symbol_linter.
T_and_F_symbol_linterT_and_F_symbol_linter
The name of the linter
See https://lintr.r-lib.org/reference/todo_comment_linter.
todo_comment_lintertodo_comment_linter
The name of the linter
See https://lintr.r-lib.org/reference/undesirable_function_linter.
undesirable_function_linterundesirable_function_linter
The name of the linter
See https://lintr.r-lib.org/reference/undesirable_operator_linter.
undesirable_operator_linterundesirable_operator_linter
The name of the linter
See https://lintr.r-lib.org/reference/unnecessary_nesting_linter.
unnecessary_nesting_linterunnecessary_nesting_linter
The name of the linter
See https://lintr.r-lib.org/reference/vector_logic_linter.
vector_logic_lintervector_logic_linter
The name of the linter
See https://lintr.r-lib.org/reference/which_grepl_linter.
which_grepl_linterwhich_grepl_linter
The name of the linter