From 4de229f55e9387379beb42f61c235266bbc68dcd Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Thu, 31 Oct 2024 23:44:17 -0700 Subject: [PATCH 1/7] Don't package testthat-problems.rds (#2682) --- .Rbuildignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.Rbuildignore b/.Rbuildignore index 257a729632..23f41e938b 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -23,6 +23,7 @@ ^bench$ ^tests/testthat/dummy_packages/package/[.]Rbuildignore$ ^tests/testthat/dummy_packages/cp1252/[.]Rbuildignore$ +testthat-problems[.]rds$ ^_pkgdown\.yaml$ ^docs$ ^pkgdown$ From ed2473f81e7bb3dbf7daf16945757e2d6a373671 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:03:43 -0800 Subject: [PATCH 2/7] Bump JamesIves/github-pages-deploy-action from 4.6.8 to 4.6.9 (#2686) Bumps [JamesIves/github-pages-deploy-action](https://github.com/jamesives/github-pages-deploy-action) from 4.6.8 to 4.6.9. - [Release notes](https://github.com/jamesives/github-pages-deploy-action/releases) - [Commits](https://github.com/jamesives/github-pages-deploy-action/compare/v4.6.8...v4.6.9) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pkgdown.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 4e77b61ebb..466abf1e08 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -39,7 +39,7 @@ jobs: - name: Deploy to GitHub pages 🚀 if: github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4.6.8 + uses: JamesIves/github-pages-deploy-action@v4.6.9 with: clean: false branch: gh-pages From 9d58027882db0dcced8fbb2fd3d583ca0cc6315c Mon Sep 17 00:00:00 2001 From: Indrajeet Patil Date: Mon, 18 Nov 2024 21:12:23 +0100 Subject: [PATCH 3/7] Add utils to check for lint and error classes (#2681) --- R/extract.R | 2 +- R/get_source_expressions.R | 6 +++--- R/lint.R | 2 +- R/utils.R | 5 ++++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/R/extract.R b/R/extract.R index c9aa57b70d..edd12a4567 100644 --- a/R/extract.R +++ b/R/extract.R @@ -9,7 +9,7 @@ extract_r_source <- function(filename, lines, error = identity) { output <- rep.int(NA_character_, length(lines)) chunks <- tryCatch(get_chunk_positions(pattern = pattern, lines = lines), error = error) - if (inherits(chunks, "error") || inherits(chunks, "lint")) { + if (is_error(chunks) || is_lint(chunks)) { assign("e", chunks, envir = parent.frame()) # error, so return empty code return(output) diff --git a/R/get_source_expressions.R b/R/get_source_expressions.R index ec8a4d4065..3f1817023e 100644 --- a/R/get_source_expressions.R +++ b/R/get_source_expressions.R @@ -86,7 +86,7 @@ get_source_expressions <- function(filename, lines = NULL) { source_expression$content <- get_content(source_expression$lines) parsed_content <- get_source_expression(source_expression, error = function(e) lint_parse_error(e, source_expression)) - if (inherits(e, "lint") && (is.na(e$line) || !nzchar(e$line) || e$message == "unexpected end of input")) { + if (is_lint(e) && (is.na(e$line) || !nzchar(e$line) || e$message == "unexpected end of input")) { # Don't create expression list if it's unreliable (invalid encoding or unhandled parse error) expressions <- list() } else { @@ -502,7 +502,7 @@ get_source_expression <- function(source_expression, error = identity) { error = error ) - if (inherits(parsed_content, c("error", "lint"))) { + if (is_error(parsed_content) || is_lint(parsed_content)) { assign("e", parsed_content, envir = parent.frame()) parse_error <- TRUE } @@ -513,7 +513,7 @@ get_source_expression <- function(source_expression, error = identity) { error = error ) - if (inherits(parsed_content, c("error", "lint"))) { + if (is_error(parsed_content) || is_lint(parsed_content)) { # Let parse errors take precedence over encoding problems if (!parse_error) assign("e", parsed_content, envir = parent.frame()) return() # parsed_content is unreliable if encoding is invalid diff --git a/R/lint.R b/R/lint.R index 042fbeacae..1961acb056 100644 --- a/R/lint.R +++ b/R/lint.R @@ -696,7 +696,7 @@ maybe_report_progress <- function(pb) { } maybe_append_error_lint <- function(lints, error, lint_cache, filename) { - if (inherits(error, "lint")) { + if (is_lint(error)) { error$linter <- "error" lints[[length(lints) + 1L]] <- error diff --git a/R/utils.R b/R/utils.R index d23fc89023..acdf2c521d 100644 --- a/R/utils.R +++ b/R/utils.R @@ -245,9 +245,12 @@ get_r_string <- function(s, xpath = NULL) { } is_linter <- function(x) inherits(x, "linter") +is_lint <- function(x) inherits(x, "lint") + +is_error <- function(x) inherits(x, "error") is_tainted <- function(lines) { - inherits(tryCatch(nchar(lines), error = identity), "error") + is_error(tryCatch(nchar(lines), error = identity)) } #' Check that the entries in ... are valid From 5c72a1ce8cf88fffe270ef6be90d278786e41b42 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Tue, 26 Nov 2024 11:31:58 -0800 Subject: [PATCH 4/7] Emphasize S3-S4 difference in recommendation for how to fix class_equals_linter() (#2688) * Emphasize S3-S4 difference in recommendation * Update in tests * One more --- R/class_equals_linter.R | 7 ++++--- tests/testthat/test-class_equals_linter.R | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/R/class_equals_linter.R b/R/class_equals_linter.R index 2dd24b83dd..1f3483e9bf 100644 --- a/R/class_equals_linter.R +++ b/R/class_equals_linter.R @@ -48,9 +48,10 @@ class_equals_linter <- function() { bad_expr <- xml_find_all(xml_calls, xpath) operator <- xml_find_chr(bad_expr, "string(*[2])") - lint_message <- sprintf( - "Use inherits(x, 'class-name'), is. or is(x, 'class') instead of comparing class(x) with %s.", - operator + lint_message <- paste0( + "Use inherits(x, 'class-name'), is. for S3 classes, ", + "or is(x, 'S4Class') for S4 classes, ", + "instead of comparing class(x) with ", operator, "." ) xml_nodes_to_lints( bad_expr, diff --git a/tests/testthat/test-class_equals_linter.R b/tests/testthat/test-class_equals_linter.R index fb640e4489..cc4495ec3c 100644 --- a/tests/testthat/test-class_equals_linter.R +++ b/tests/testthat/test-class_equals_linter.R @@ -11,7 +11,7 @@ test_that("class_equals_linter skips allowed usages", { test_that("class_equals_linter blocks simple disallowed usages", { linter <- class_equals_linter() - lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. or is(x, 'class')") + lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes") expect_lint("if (class(x) == 'character') stop('no')", lint_msg, linter) expect_lint("is_regression <- class(x) == 'lm'", lint_msg, linter) @@ -20,7 +20,7 @@ test_that("class_equals_linter blocks simple disallowed usages", { test_that("class_equals_linter blocks usage of %in% for checking class", { linter <- class_equals_linter() - lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. or is(x, 'class')") + lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes") expect_lint("if ('character' %in% class(x)) stop('no')", lint_msg, linter) expect_lint("if (class(x) %in% 'character') stop('no')", lint_msg, linter) @@ -29,7 +29,7 @@ test_that("class_equals_linter blocks usage of %in% for checking class", { test_that("class_equals_linter blocks class(x) != 'klass'", { expect_lint( "if (class(x) != 'character') TRUE", - rex::rex("Use inherits(x, 'class-name'), is. or is(x, 'class')"), + rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes"), class_equals_linter() ) }) @@ -43,13 +43,13 @@ test_that("class_equals_linter skips usage for subsetting", { # but not further nesting expect_lint( "x[if (class(x) == 'foo') 1 else 2]", - rex::rex("Use inherits(x, 'class-name'), is. or is(x, 'class')"), + rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes"), linter ) }) test_that("lints vectorize", { - lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. or is(x, 'class')") + lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes") expect_lint( trim_some("{ From 57a9778f897529de2acde3592325df8e1fa5b281 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 06:17:55 +0100 Subject: [PATCH 5/7] Bump JamesIves/github-pages-deploy-action from 4.6.9 to 4.7.1 (#2689) --- .github/workflows/pkgdown.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 466abf1e08..cc8ffb62f3 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -39,7 +39,7 @@ jobs: - name: Deploy to GitHub pages 🚀 if: github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4.6.9 + uses: JamesIves/github-pages-deploy-action@v4.7.1 with: clean: false branch: gh-pages From b7cd0f69621604916469aa88c2a17a444a2be451 Mon Sep 17 00:00:00 2001 From: Indrajeet Patil Date: Mon, 2 Dec 2024 06:39:47 +0100 Subject: [PATCH 6/7] Fix missing character issue in JOSS's PDF output (#2669) --- paper/paper.Rmd | 3 ++- paper/paper.md | 7 +------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/paper/paper.Rmd b/paper/paper.Rmd index e6f08cb0bb..f6f73cb49d 100644 --- a/paper/paper.Rmd +++ b/paper/paper.Rmd @@ -59,7 +59,8 @@ knitr::opts_chunk$set( library(lintr) withr::local_options(list( - lintr.format_width = 60L + lintr.format_width = 60L, + cli.condition_unicode_bullets = FALSE )) ``` diff --git a/paper/paper.md b/paper/paper.md index 27793ea758..5637cb7691 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -1,6 +1,6 @@ --- title: "Static Code Analysis for R" -date: "2024-10-02" +date: "2024-11-28" tags: ["R", "linter", "tidyverse"] authors: - name: Jim Hester @@ -120,7 +120,6 @@ lint( text = "x >= 2.5", linters = redundant_ifelse_linter() ) -#> ℹ No lints found. ``` - **Efficiency** @@ -153,7 +152,6 @@ lint( text = "anyNA(x)", linters = any_is_na_linter() ) -#> ℹ No lints found. ``` - **Readability** @@ -186,7 +184,6 @@ lint( text = "x != 2", linters = comparison_negation_linter() ) -#> ℹ No lints found. ``` - **Tidyverse style** @@ -214,7 +211,6 @@ lint( text = "my_var <- 1L", linters = object_name_linter() ) -#> ℹ No lints found. ``` - **Common mistakes** @@ -288,7 +284,6 @@ lint( text = "my.var <- 1L", linters = object_name_linter(styles = "dotted.case") ) -#> ℹ No lints found. ``` - Create new linters (by leveraging functions like From 0ec3122686335bdada4012a8fcc5f46076201d73 Mon Sep 17 00:00:00 2001 From: Indrajeet Patil Date: Mon, 2 Dec 2024 07:39:23 +0100 Subject: [PATCH 7/7] Address feedback from reviewer-2 (#2683) * Address feedback from reviewer-2 * Create CONTRIBUTING.md * Add a note about avoiding 'main' * Update .github/CONTRIBUTING.md Co-authored-by: Michael Chirico * Update .github/CONTRIBUTING.md Co-authored-by: Michael Chirico * Remove unnecessary newlines in contributing.md * add cite to wiki page on linting * emphasize why 'Fixes #' in description * Add note about extended Descriptions when needed, and hint at chains. * clarify the audience of NEWS entries * tweak --------- Co-authored-by: Michael Chirico --- .github/CONTRIBUTING.md | 39 +++++++++++++++++++++++++++++++++++++++ paper/paper.Rmd | 4 ++-- paper/paper.bib | 12 ++++++++++-- paper/paper.md | 33 ++++++++++++++++++--------------- 4 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 .github/CONTRIBUTING.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000000..10289cd352 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# Contributing to `{lintr}` + +This outlines how to propose a change to `{lintr}`. For a detailed discussion on contributing to this, r-lib, and other tidyverse packages, please see the [development contributing guide](https://rstd.io/tidy-contrib) and our [code review principles](https://code-review.tidyverse.org/). + +## Fixing typos + +You can fix typos, spelling mistakes, or grammatical errors in the documentation directly using the GitHub web interface, as long as the changes are made in the _source_ file. This generally means you'll need to edit [roxygen2 comments](https://roxygen2.r-lib.org/articles/roxygen2.html) in an `.R`, not a `.Rd` file. You can find the `.R` file that generates the `.Rd` by reading the comment in the first line. + +## Bigger changes + +If you want to make a bigger change, it's a good idea to first file an issue and make sure someone from the team agrees that it’s needed. If you’ve found a bug, please file an issue that illustrates the bug with a minimal [reprex](https://www.tidyverse.org/help/#reprex) (this will also help you write a unit test, if needed). See the tidyverse guide on [how to create a great issue](https://code-review.tidyverse.org/issues/) for more advice. + +### Adding a new linter + +If you wish to contribute a new linter, the [Creating new linters](https://lintr.r-lib.org/articles/creating_linters.html) article serves as a comprehensive guide. + +### Pull request process + +* Fork the package and clone onto your computer. If you haven't done this before, we recommend using `usethis::create_from_github("r-lib/lintr", fork = TRUE)`. + +* Install all development dependencies with `devtools::install_dev_deps()`, and then make sure the package passes R CMD check by running `devtools::check()`. If R CMD check doesn't pass cleanly, it's a good idea to ask for help before continuing. + +* Create a Git branch for your pull request (PR). We recommend using `usethis::pr_init("brief-description-of-change")`. At a minimum, please avoid submitting PRs from your fork's `main` branch` as this can make the review process more complicated. + +* Make your changes, commit them to Git, and create a PR using `usethis::pr_push()`. Follow the prompts in your browser to complete the process. Use a concise title for your PR that summarizes the change, and include `Fixes #issue-number` in the PR _description_. Doing so will automatically close the linked issue when the PR is merged. For complicated changes, add a textual overview of what your PR does in the description. Consider breaking up large PRs into a chain of more digestible+focused smaller PRs. + +* For user-facing changes, add a bullet appropriately in the top section of `NEWS.md` (i.e. below the first header). Follow the style described in . Most importantly, your audience for NEWS items is a package user, i.e., _not_ a package developer. + +### Code style + +* New code should follow the tidyverse [style guide](https://style.tidyverse.org). You can use the [styler](https://CRAN.R-project.org/package=styler) package to apply these styles. + +* We use [roxygen2](https://cran.r-project.org/package=roxygen2), with [Markdown syntax](https://cran.r-project.org/web/packages/roxygen2/vignettes/rd-formatting.html), for documentation. + +* We use [testthat](https://cran.r-project.org/package=testthat) for unit tests. Contributions with test cases included are easier to accept. + +## Code of Conduct + +Please note that the lintr project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to this project you agree to abide by its terms. diff --git a/paper/paper.Rmd b/paper/paper.Rmd index f6f73cb49d..072cb1ef59 100644 --- a/paper/paper.Rmd +++ b/paper/paper.Rmd @@ -66,7 +66,7 @@ withr::local_options(list( # Statement of Need -A linter is a tool that analyzes code to identify potential errors, stylistic issues, or deviations from coding standards. It helps ensure consistency, readability, and best practices by flagging common mistakes, such as syntax errors, unused variables, or improper formatting. Linters are essential for improving code quality, preventing bugs, and maintaining a clean codebase, especially in collaborative development environments [@enwiki:1218663830]. `{lintr}` is an open-source package that provides linters for the R programming language, which is an interpreted, dynamically-typed programming language [@base2023], and is used by a wide range of researchers and data scientists. `{lintr}` can thus act as a valuable tool for R users to help improve the quality and reliability of their code. +In computer programming, "linting" is the process of analyzing the source code to identify possible programming and stylistic problems [@enwiki:1260589258] and a linter is a tool used for linting. A linter analyzes code to identify potential errors, stylistic issues, or deviations from coding standards. It helps ensure consistency, readability, and best practices by flagging common mistakes, such as syntax errors, unused variables, or improper formatting. Linters are essential for improving code quality, preventing bugs, and maintaining a clean codebase, especially in collaborative development environments [@enwiki:1218663830]. `{lintr}` is an open-source package that provides linters for the R programming language, which is an interpreted, dynamically-typed programming language [@base2023], and is used by a wide range of researchers and data scientists. `{lintr}` can thus act as a valuable tool for R users to help improve the quality and reliability of their code. # Features @@ -80,7 +80,7 @@ library(lintr) length(all_linters()) ``` -Naturally, we can't discuss all of them here. To see details about all available linters, we encourage readers to see . +Naturally, we can't discuss all of them here. To see the most up-to-date details about all the available linters, we encourage readers to visit . We will showcase one linter for each kind of common problem found in R code. diff --git a/paper/paper.bib b/paper/paper.bib index 329f7c4032..5b8e8db9ec 100644 --- a/paper/paper.bib +++ b/paper/paper.bib @@ -32,12 +32,20 @@ @book{mcconnell2004code publisher={Pearson Education} } -@misc{ enwiki:1218663830, +@misc{enwiki:1218663830, author = "{Wikipedia contributors}", title = "Static program analysis --- {Wikipedia}{,} The Free Encyclopedia", year = "2024", url = "https://en.wikipedia.org/w/index.php?title=Static_program_analysis&oldid=1218663830", - note = "[Online; accessed 7-May-2024]" + note = "[Online; accessed 2-December-2024]" + } + +@misc{enwiki:1260589258, + author = "{Wikipedia contributors}", + title = "Lint (software) --- {Wikipedia}{,} The Free Encyclopedia", + year = "2024", + url = "https://en.wikipedia.org/w/index.php?title=Lint_(software)&oldid=1260589258", + note = "[Online; accessed 2-December-2024]" } @Manual{Tierney2024, diff --git a/paper/paper.md b/paper/paper.md index 5637cb7691..c7a35d6582 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -1,6 +1,6 @@ --- title: "Static Code Analysis for R" -date: "2024-11-28" +date: "2024-12-02" tags: ["R", "linter", "tidyverse"] authors: - name: Jim Hester @@ -51,18 +51,21 @@ link-citations: true # Statement of Need -A linter is a tool that analyzes code to identify potential errors, -stylistic issues, or deviations from coding standards. It helps ensure -consistency, readability, and best practices by flagging common -mistakes, such as syntax errors, unused variables, or improper -formatting. Linters are essential for improving code quality, preventing -bugs, and maintaining a clean codebase, especially in collaborative -development environments [@enwiki:1218663830]. `{lintr}` is an -open-source package that provides linters for the R programming -language, which is an interpreted, dynamically-typed programming -language [@base2023], and is used by a wide range of researchers and -data scientists. `{lintr}` can thus act as a valuable tool for R users -to help improve the quality and reliability of their code. +In computer programming, "linting" is the process of analyzing the +source code to identify possible programming and stylistic problems +[@enwiki:1260589258] and a linter is a tool used for linting. A linter +analyzes code to identify potential errors, stylistic issues, or +deviations from coding standards. It helps ensure consistency, +readability, and best practices by flagging common mistakes, such as +syntax errors, unused variables, or improper formatting. Linters are +essential for improving code quality, preventing bugs, and maintaining a +clean codebase, especially in collaborative development environments +[@enwiki:1218663830]. `{lintr}` is an open-source package that provides +linters for the R programming language, which is an interpreted, +dynamically-typed programming language [@base2023], and is used by a +wide range of researchers and data scientists. `{lintr}` can thus act as +a valuable tool for R users to help improve the quality and reliability +of their code. # Features @@ -86,8 +89,8 @@ length(all_linters()) #> [1] 113 ``` -Naturally, we can't discuss all of them here. To see details about all -available linters, we encourage readers to see +Naturally, we can't discuss all of them here. To see the most up-to-date +details about all the available linters, we encourage readers to visit . We will showcase one linter for each kind of common problem found in R