Download Latest Version v3.4.0 source code.zip (9.7 MB) Google Add to Preferred Sources
Home / v3.4.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-07-16 6.2 kB
v3.4.0 source code.tar.gz 2026-07-16 9.4 MB
v3.4.0 source code.zip 2026-07-16 9.7 MB
Totals: 3 Items   19.0 MB 2

Deprecations & breaking changes

  • Six linters fully deprecated in the previous release are now removed: consecutive_stopifnot_linter(), extraction_operator_linter(), no_tab_linter(), single_quotes_linter(), unnecessary_nested_if_linter(), and unneeded_concatenation_linter().
  • assignment_linter() only allows <- by default, i.e., <<- is now excluded (consistent with the defaults for undesirable_operator_linter(); [#2717], @MichaelChirico).
  • Arguments allow_cascading_assign=, allow_right_assign=, and allow_pipe_assign= to assignment_linter() are now removed. Use operator= instead.
  • Argument interpret_glue to object_usage_linter(), marked deprecated in the previous release, is now defunct. Use interpret_extensions= instead; see the 3.3.0-1 release notes and ?object_usage_linter for more.

Bug fixes

  • Excluding cyclocomp_linter() in available_linters() or linters_with_tags(), which requires the weak dependency {cyclocomp}, no longer emits a warning if {cyclocomp} is not available (#2909, @MichaelChirico).
  • repeat_linter() no longer errors when while in while (TRUE) is in a column to the right of } (#2828, @MichaelChirico).
  • get_source_expression(lines=) and lint(text=) correctly handle text with unmarked encoding (#3046, @MichaelChirico).
  • lint(exclude=) doesn't fail cryptically when provided a regex with capture groups (#2831, @MichaelChirico).

New and improved features

  • Rmd files with explicit eval=FALSE chunks are skipped (#1964, @MichaelChirico). Complex cases like eval=obj where obj=FALSE and opts_chunk$set(eval = FALSE) are not yet supported; the former likely never will be. This obviates the previous workaround requiring such chunks to use plain markdown highlighting gates like ```r (i.e., without {knitr} mark-up).

Linter improvements

  • indentation_linter() correctly enforces the updated Tidyverse guidelines around multi-line function definitions, namely that double-indented functions are no longer recommended, in favor of single-indented formals separated from the function body by a line with ) { (#2830, @MichaelChirico).
  • sort_linter()
  • recommends usage of !is.unsorted(x) over identical(x, sort(x)) (#2921, @Bisaloo).
  • recommends usage of sort(x, decreasing = TRUE) over rev(sort(x)) (#3066, @Bisaloo).
  • paste_linter()
  • lints expression(paste(., sep = "")) because the paste inside an expression doesn't support the sep argument (#2945, @mcol).
  • recommends deparse1(x) in favor of paste(deparse(x), collapse = ...) (#2615, @emmanuel-ferdman).
  • namespace_linter() detects functions accessed with :: or ::: when they are already imported into the package's NAMESPACE (#2081, @MichaelChirico).
  • backport_linter() now exhaustively covers all exported symbols introduced throughout R's history back to R 3.0.0, including many symbols never mentioned in NEWS.
  • General handling of logic around where comments can appear in code has been improved (#2822, @MichaelChirico). In many cases, this is a tiny robustness fix for weird edge cases unlikely to be found in practice, but in others, this improves practical linter precision (reduced false positives and/or false negatives). The affected linters (with annotations for changes noteworthy enough to have gotten a dedicated bug) are:
  • brace_linter()
  • coalesce_linter()
  • comparison_negation_linter() [#2826]
  • conjunct_test_linter() [#2827]
  • empty_assignment_linter()
  • expect_comparison_linter()
  • fixed_regex_linter() [#2827]
  • if_switch_linter()
  • ifelse_censor_linter() [#2826]
  • implicit_assignment_linter()
  • length_test_linter()
  • literal_coercion_linter() [#2824]
  • matrix_apply_linter() [#2825]
  • nzchar_linter() [#2826]
  • object_length_linter() [#2827]
  • object_name_linter() [#2827]
  • object_usage_linter()
  • outer_negation_linter() [#2827]
  • redundant_equals_linter()
  • regex_subset_linter()
  • seq_linter()
  • sort_linter()
  • sprintf_linter() [#2827]
  • string_boundary_linter()
  • strings_as_factors_linter()
  • unnecessary_concatenation_linter() [#2827]
  • unnecessary_lambda_linter() [#2827]
  • unnecessary_nesting_linter() [#2827]
  • unnecessary_placeholder_linter()
  • unreachable_code_linter() [#2827]
  • vector_logic_linter() [#2826]

Lint accuracy fixes: removing false positives

  • if_switch_linter()
  • no longer produces a false positive when comparing to empty strings ("", '', or raw strings like R"()"), which cannot be used as switch() case names (#2835, @emmanuel-ferdman).
  • handles expressions/branches without { correctly (#3042, @MichaelChirico)
  • undesirable_operator_linter(call_is_undesirable = FALSE) now correctly skips prefix notation like `:::`(pkg, fun) (#2999, @emmanuel-ferdman).
  • unnecessary_nesting_linter() treats = assignment the same as <- for several pieces of logic (#2245 and [#2829], @MichaelChirico).
  • vector_logic_linter() ignores scalar operators (&&/||) inside anonymous functions within filter()/subset() (#2935, @emmanuel-ferdman).
  • unnecessary_lambda_linter() skips lambdas with an outer unary operator like sapply(x, \(xi) !all(xi)) (#2742, @MichaelChirico).

Notes

  • {lintr} now requires R 4.1.0
  • Internal code is refactored to avoid xml2::xml_ns() for e.g. 5-30% end-to-end speed improvement in lint_package()

New Contributors

Full Changelog: https://github.com/r-lib/lintr/compare/v3.2.0...v3.4.0

Source: README.md, updated 2026-07-16