| author | bors <bors@rust-lang.org> 2025-06-27 20:07:50 UTC |
| committer | bors <bors@rust-lang.org> 2025-06-27 20:07:50 UTC |
| log | bdaba05a953eb5abeba0011cdda2560d157aed2e |
| tree | bbdaecd0be314a364edfdd760923b4b2b9967d4b |
| parent | fe5f3dedf7b4d6bea2cadb17343f747d70b4c66b |
| parent | d9a4fd5d51d7c93d8c8b759c656395a0ccade198 |
Clippy subtree update
r? `@Manishearth`
Cargo.lock update due to version bump157 files changed, 3174 insertions(+), 850 deletions(-)
Cargo.lock+10-4| ... | ... | @@ -537,7 +537,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" |
| 537 | 537 | |
| 538 | 538 | [[package]] |
| 539 | 539 | name = "clippy" |
| 540 | version = "0.1.89" | |
| 540 | version = "0.1.90" | |
| 541 | 541 | dependencies = [ |
| 542 | 542 | "anstream", |
| 543 | 543 | "askama", |
| ... | ... | @@ -547,6 +547,7 @@ dependencies = [ |
| 547 | 547 | "clippy_lints_internal", |
| 548 | 548 | "clippy_utils", |
| 549 | 549 | "color-print", |
| 550 | "declare_clippy_lint", | |
| 550 | 551 | "filetime", |
| 551 | 552 | "futures", |
| 552 | 553 | "if_chain", |
| ... | ... | @@ -569,7 +570,7 @@ dependencies = [ |
| 569 | 570 | |
| 570 | 571 | [[package]] |
| 571 | 572 | name = "clippy_config" |
| 572 | version = "0.1.89" | |
| 573 | version = "0.1.90" | |
| 573 | 574 | dependencies = [ |
| 574 | 575 | "clippy_utils", |
| 575 | 576 | "itertools", |
| ... | ... | @@ -592,12 +593,13 @@ dependencies = [ |
| 592 | 593 | |
| 593 | 594 | [[package]] |
| 594 | 595 | name = "clippy_lints" |
| 595 | version = "0.1.89" | |
| 596 | version = "0.1.90" | |
| 596 | 597 | dependencies = [ |
| 597 | 598 | "arrayvec", |
| 598 | 599 | "cargo_metadata 0.18.1", |
| 599 | 600 | "clippy_config", |
| 600 | 601 | "clippy_utils", |
| 602 | "declare_clippy_lint", | |
| 601 | 603 | "itertools", |
| 602 | 604 | "quine-mc_cluskey", |
| 603 | 605 | "regex-syntax 0.8.5", |
| ... | ... | @@ -622,7 +624,7 @@ dependencies = [ |
| 622 | 624 | |
| 623 | 625 | [[package]] |
| 624 | 626 | name = "clippy_utils" |
| 625 | version = "0.1.89" | |
| 627 | version = "0.1.90" | |
| 626 | 628 | dependencies = [ |
| 627 | 629 | "arrayvec", |
| 628 | 630 | "itertools", |
| ... | ... | @@ -931,6 +933,10 @@ dependencies = [ |
| 931 | 933 | "winapi", |
| 932 | 934 | ] |
| 933 | 935 | |
| 936 | [[package]] | |
| 937 | name = "declare_clippy_lint" | |
| 938 | version = "0.1.90" | |
| 939 | ||
| 934 | 940 | [[package]] |
| 935 | 941 | name = "derive-where" |
| 936 | 942 | version = "1.4.0" |
compiler/rustc_codegen_gcc/src/intrinsic/simd.rs+3-2| ... | ... | @@ -61,7 +61,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( |
| 61 | 61 | let (len, _) = args[1].layout.ty.simd_size_and_type(bx.tcx()); |
| 62 | 62 | |
| 63 | 63 | let expected_int_bits = (len.max(8) - 1).next_power_of_two(); |
| 64 | let expected_bytes = len / 8 + ((len % 8 > 0) as u64); | |
| 64 | let expected_bytes = len / 8 + ((!len.is_multiple_of(8)) as u64); | |
| 65 | 65 | |
| 66 | 66 | let mask_ty = args[0].layout.ty; |
| 67 | 67 | let mut mask = match *mask_ty.kind() { |
| ... | ... | @@ -676,7 +676,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( |
| 676 | 676 | let elem_type = vector_type.get_element_type(); |
| 677 | 677 | |
| 678 | 678 | let expected_int_bits = in_len.max(8); |
| 679 | let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); | |
| 679 | let expected_bytes = | |
| 680 | expected_int_bits / 8 + ((!expected_int_bits.is_multiple_of(8)) as u64); | |
| 680 | 681 | |
| 681 | 682 | // FIXME(antoyo): that's not going to work for masks bigger than 128 bits. |
| 682 | 683 | let result_type = bx.type_ix(expected_int_bits); |
src/bootstrap/src/utils/render_tests.rs+3-1| ... | ... | @@ -202,7 +202,9 @@ impl<'a> Renderer<'a> { |
| 202 | 202 | } |
| 203 | 203 | |
| 204 | 204 | fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, test: &TestOutcome) { |
| 205 | if self.terse_tests_in_line != 0 && self.terse_tests_in_line % TERSE_TESTS_PER_LINE == 0 { | |
| 205 | if self.terse_tests_in_line != 0 | |
| 206 | && self.terse_tests_in_line.is_multiple_of(TERSE_TESTS_PER_LINE) | |
| 207 | { | |
| 206 | 208 | if let Some(total) = self.tests_count { |
| 207 | 209 | let total = total.to_string(); |
| 208 | 210 | let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len()); |
src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml+3-1| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | 1 | name: New lint suggestion |
| 2 | description: Suggest a new Clippy lint. | |
| 2 | description: | | |
| 3 | Suggest a new Clippy lint (currently not accepting new lints) | |
| 4 | Check out the Clippy book for more information about the feature freeze. | |
| 3 | 5 | labels: ["A-lint"] |
| 4 | 6 | body: |
| 5 | 7 | - type: markdown |
src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md+4| ... | ... | @@ -32,6 +32,10 @@ order to get feedback. |
| 32 | 32 | |
| 33 | 33 | Delete this line and everything above before opening your PR. |
| 34 | 34 | |
| 35 | Note that we are currently not taking in new PRs that add new lints. We are in a | |
| 36 | feature freeze. Check out the book for more information. If you open a | |
| 37 | feature-adding pull request, its review will be delayed. | |
| 38 | ||
| 35 | 39 | --- |
| 36 | 40 | |
| 37 | 41 | *Please write a short comment explaining your change (or "none" for internal only changes)* |
src/tools/clippy/.github/workflows/feature_freeze.yml created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | name: Feature freeze check | |
| 2 | ||
| 3 | on: | |
| 4 | pull_request: | |
| 5 | paths: | |
| 6 | - 'clippy_lints/src/declared_lints.rs' | |
| 7 | ||
| 8 | jobs: | |
| 9 | auto-comment: | |
| 10 | runs-on: ubuntu-latest | |
| 11 | ||
| 12 | steps: | |
| 13 | - name: Check PR Changes | |
| 14 | id: pr-changes | |
| 15 | run: echo "::set-output name=changes::${{ toJson(github.event.pull_request.changed_files) }}" | |
| 16 | ||
| 17 | - name: Create Comment | |
| 18 | if: steps.pr-changes.outputs.changes != '[]' | |
| 19 | run: | | |
| 20 | # Use GitHub API to create a comment on the PR | |
| 21 | PR_NUMBER=${{ github.event.pull_request.number }} | |
| 22 | COMMENT="**Seems that you are trying to add a new lint!**\nWe are currently in a [feature freeze](https://doc.rust-lang.org/nightly/clippy/development/feature_freeze.html), so we are delaying all lint-adding PRs to August 1st and focusing on bugfixes.\nThanks a lot for your contribution, and sorry for the inconvenience.\nWith ❤ from the Clippy team" | |
| 23 | GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} | |
| 24 | COMMENT_URL="https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" | |
| 25 | curl -s -H "Authorization: token ${GITHUB_TOKEN}" -X POST $COMMENT_URL -d "{\"body\":\"$COMMENT\"}" |
src/tools/clippy/CHANGELOG.md+90-1| ... | ... | @@ -6,7 +6,94 @@ document. |
| 6 | 6 | |
| 7 | 7 | ## Unreleased / Beta / In Rust Nightly |
| 8 | 8 | |
| 9 | [1e5237f4...master](https://github.com/rust-lang/rust-clippy/compare/1e5237f4...master) | |
| 9 | [03a5b6b9...master](https://github.com/rust-lang/rust-clippy/compare/03a5b6b9...master) | |
| 10 | ||
| 11 | ## Rust 1.88 | |
| 12 | ||
| 13 | Current stable, released 2025-06-26 | |
| 14 | ||
| 15 | [View all 126 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-03-21T10%3A30%3A57Z..2025-05-01T08%3A03%3A26Z+base%3Amaster) | |
| 16 | ||
| 17 | ### New Lints | |
| 18 | ||
| 19 | * Added [`swap_with_temporary`] to `complexity` [#14046](https://github.com/rust-lang/rust-clippy/pull/14046) | |
| 20 | * Added [`redundant_test_prefix`] to `restriction` [#13710](https://github.com/rust-lang/rust-clippy/pull/13710) | |
| 21 | * Added [`manual_dangling_ptr`] to `style` [#14107](https://github.com/rust-lang/rust-clippy/pull/14107) | |
| 22 | * Added [`char_indices_as_byte_indices`] to `correctness` [#13435](https://github.com/rust-lang/rust-clippy/pull/13435) | |
| 23 | * Added [`manual_abs_diff`] to `complexity` [#14482](https://github.com/rust-lang/rust-clippy/pull/14482) | |
| 24 | * Added [`ignore_without_reason`] to `pedantic` [#13931](https://github.com/rust-lang/rust-clippy/pull/13931) | |
| 25 | ||
| 26 | ### Moves and Deprecations | |
| 27 | ||
| 28 | * Moved [`uninlined_format_args`] to `style` (from `pedantic`) | |
| 29 | [#14160](https://github.com/rust-lang/rust-clippy/pull/14160) | |
| 30 | * [`match_on_vec_items`] deprecated in favor of [`indexing_slicing`] | |
| 31 | [#14217](https://github.com/rust-lang/rust-clippy/pull/14217) | |
| 32 | * Removed superseded lints: `transmute_float_to_int`, `transmute_int_to_char`, | |
| 33 | `transmute_int_to_float`, `transmute_num_to_bytes` (now in rustc) | |
| 34 | [#14703](https://github.com/rust-lang/rust-clippy/pull/14703) | |
| 35 | ||
| 36 | ### Enhancements | |
| 37 | ||
| 38 | * Configuration renamed from `lint-inconsistent-struct-field-initializers` | |
| 39 | to `check-inconsistent-struct-field-initializers` | |
| 40 | [#14280](https://github.com/rust-lang/rust-clippy/pull/14280) | |
| 41 | * Paths in `disallowed_*` configurations are now validated | |
| 42 | [#14397](https://github.com/rust-lang/rust-clippy/pull/14397) | |
| 43 | * [`borrow_as_ptr`] now lints implicit casts as well | |
| 44 | [#14408](https://github.com/rust-lang/rust-clippy/pull/14408) | |
| 45 | * [`iter_kv_map`] now recognizes references on maps | |
| 46 | [#14596](https://github.com/rust-lang/rust-clippy/pull/14596) | |
| 47 | * [`empty_enum_variants_with_brackets`] no longer lints reachable enums or enums used | |
| 48 | as functions within same crate [#12971](https://github.com/rust-lang/rust-clippy/pull/12971) | |
| 49 | * [`needless_lifetimes`] now checks for lifetime uses in closures | |
| 50 | [#14608](https://github.com/rust-lang/rust-clippy/pull/14608) | |
| 51 | * [`wildcard_imports`] now lints on `pub use` when `warn_on_all_wildcard_imports` is enabled | |
| 52 | [#14182](https://github.com/rust-lang/rust-clippy/pull/14182) | |
| 53 | * [`collapsible_if`] now recognizes the `let_chains` feature | |
| 54 | [#14481](https://github.com/rust-lang/rust-clippy/pull/14481) | |
| 55 | * [`match_single_binding`] now allows macros in scrutinee and patterns | |
| 56 | [#14635](https://github.com/rust-lang/rust-clippy/pull/14635) | |
| 57 | * [`needless_borrow`] does not contradict the compiler's | |
| 58 | `dangerous_implicit_autorefs` lint even though the references | |
| 59 | are not mandatory | |
| 60 | [#14810](https://github.com/rust-lang/rust-clippy/pull/14810) | |
| 61 | ||
| 62 | ### False Positive Fixes | |
| 63 | ||
| 64 | * [`double_ended_iterator_last`] and [`needless_collect`] fixed FP when iter has side effects | |
| 65 | [#14490](https://github.com/rust-lang/rust-clippy/pull/14490) | |
| 66 | * [`mut_from_ref`] fixed FP where lifetimes nested in types were not considered | |
| 67 | [#14471](https://github.com/rust-lang/rust-clippy/pull/14471) | |
| 68 | * [`redundant_clone`] fixed FP in overlapping lifetime | |
| 69 | [#14237](https://github.com/rust-lang/rust-clippy/pull/14237) | |
| 70 | * [`map_entry`] fixed FP where lint would trigger without insert calls present | |
| 71 | [#14568](https://github.com/rust-lang/rust-clippy/pull/14568) | |
| 72 | * [`iter_cloned_collect`] fixed FP with custom `From`/`IntoIterator` impl | |
| 73 | [#14473](https://github.com/rust-lang/rust-clippy/pull/14473) | |
| 74 | * [`shadow_unrelated`] fixed FP in destructuring assignments | |
| 75 | [#14381](https://github.com/rust-lang/rust-clippy/pull/14381) | |
| 76 | * [`redundant_clone`] fixed FP on enum cast | |
| 77 | [#14395](https://github.com/rust-lang/rust-clippy/pull/14395) | |
| 78 | * [`collapsible_if`] fixed FP on block stmt before expr | |
| 79 | [#14730](https://github.com/rust-lang/rust-clippy/pull/14730) | |
| 80 | ||
| 81 | ### ICE Fixes | |
| 82 | ||
| 83 | * [`missing_const_for_fn`] fix ICE with `-Z validate-mir` compilation option | |
| 84 | [#14776](https://github.com/rust-lang/rust-clippy/pull/14776) | |
| 85 | ||
| 86 | ### Documentation Improvements | |
| 87 | ||
| 88 | * [`missing_asserts_for_indexing`] improved documentation and examples | |
| 89 | [#14108](https://github.com/rust-lang/rust-clippy/pull/14108) | |
| 90 | ||
| 91 | ### Others | |
| 92 | ||
| 93 | * We're testing with edition 2024 now | |
| 94 | [#14602](https://github.com/rust-lang/rust-clippy/pull/14602) | |
| 95 | * Don't warn about unloaded crates in `clippy.toml` disallowed paths | |
| 96 | [#14733](https://github.com/rust-lang/rust-clippy/pull/14733) | |
| 10 | 97 | |
| 11 | 98 | ## Rust 1.87 |
| 12 | 99 | |
| ... | ... | @@ -5729,6 +5816,7 @@ Released 2018-09-13 |
| 5729 | 5816 | [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type |
| 5730 | 5817 | [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types |
| 5731 | 5818 | [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression |
| 5819 | [`doc_broken_link`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_broken_link | |
| 5732 | 5820 | [`doc_comment_double_space_linebreaks`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_comment_double_space_linebreaks |
| 5733 | 5821 | [`doc_include_without_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_include_without_cfg |
| 5734 | 5822 | [`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation |
| ... | ... | @@ -5967,6 +6055,7 @@ Released 2018-09-13 |
| 5967 | 6055 | [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check |
| 5968 | 6056 | [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite |
| 5969 | 6057 | [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite |
| 6058 | [`manual_is_multiple_of`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_multiple_of | |
| 5970 | 6059 | [`manual_is_power_of_two`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two |
| 5971 | 6060 | [`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and |
| 5972 | 6061 | [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else |
src/tools/clippy/Cargo.toml+2-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | [package] |
| 2 | 2 | name = "clippy" |
| 3 | version = "0.1.89" | |
| 3 | version = "0.1.90" | |
| 4 | 4 | description = "A bunch of helpful lints to avoid common pitfalls in Rust" |
| 5 | 5 | repository = "https://github.com/rust-lang/rust-clippy" |
| 6 | 6 | readme = "README.md" |
| ... | ... | @@ -24,6 +24,7 @@ path = "src/driver.rs" |
| 24 | 24 | clippy_config = { path = "clippy_config" } |
| 25 | 25 | clippy_lints = { path = "clippy_lints" } |
| 26 | 26 | clippy_utils = { path = "clippy_utils" } |
| 27 | declare_clippy_lint = { path = "declare_clippy_lint" } | |
| 27 | 28 | rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } |
| 28 | 29 | clippy_lints_internal = { path = "clippy_lints_internal", optional = true } |
| 29 | 30 | tempfile = { version = "3.20", optional = true } |
src/tools/clippy/book/src/README.md+4| ... | ... | @@ -1,5 +1,9 @@ |
| 1 | 1 | # Clippy |
| 2 | 2 | |
| 3 | [### IMPORTANT NOTE FOR CONTRIBUTORS ================](development/feature_freeze.md) | |
| 4 | ||
| 5 | ---- | |
| 6 | ||
| 3 | 7 | [](https://github.com/rust-lang/rust-clippy#license) |
| 4 | 8 | |
| 5 | 9 | A collection of lints to catch common mistakes and improve your |
src/tools/clippy/book/src/SUMMARY.md+1| ... | ... | @@ -13,6 +13,7 @@ |
| 13 | 13 | - [GitLab CI](continuous_integration/gitlab.md) |
| 14 | 14 | - [Travis CI](continuous_integration/travis.md) |
| 15 | 15 | - [Development](development/README.md) |
| 16 | - [IMPORTANT: FEATURE FREEZE](development/feature_freeze.md) | |
| 16 | 17 | - [Basics](development/basics.md) |
| 17 | 18 | - [Adding Lints](development/adding_lints.md) |
| 18 | 19 | - [Defining Lints](development/defining_lints.md) |
src/tools/clippy/book/src/development/adding_lints.md+3| ... | ... | @@ -1,5 +1,8 @@ |
| 1 | 1 | # Adding a new lint |
| 2 | 2 | |
| 3 | [### IMPORTANT NOTE FOR CONTRIBUTORS ================](feature_freeze.md) | |
| 4 | ||
| 5 | ||
| 3 | 6 | You are probably here because you want to add a new lint to Clippy. If this is |
| 4 | 7 | the first time you're contributing to Clippy, this document guides you through |
| 5 | 8 | creating an example lint from scratch. |
src/tools/clippy/book/src/development/feature_freeze.md created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | # IMPORTANT: FEATURE FREEZE | |
| 2 | ||
| 3 | This is a temporary notice. | |
| 4 | ||
| 5 | From the 26th of June until the 18th of September we will perform a feature freeze. Only bugfix PRs will be reviewed | |
| 6 | except already open ones. Every feature-adding PR opened in between those dates will be moved into a | |
| 7 | milestone to be reviewed separately at another time. | |
| 8 | ||
| 9 | We do this because of the long backlog of bugs that need to be addressed | |
| 10 | in order to continue being the state-of-the-art linter that Clippy has become known for being. | |
| 11 | ||
| 12 | ## For contributors | |
| 13 | ||
| 14 | If you are a contributor or are planning to become one, **please do not open a lint-adding PR**, we have lots of open | |
| 15 | bugs of all levels of difficulty that you can address instead! | |
| 16 | ||
| 17 | We currently have about 800 lints, each one posing a maintainability challenge that needs to account to every possible | |
| 18 | use case of the whole ecosystem. Bugs are natural in every software, but the Clippy team considers that Clippy needs a | |
| 19 | refinement period. | |
| 20 | ||
| 21 | If you open a PR at this time, we will not review it but push it into a milestone until the refinement period ends, | |
| 22 | adding additional load into our reviewing schedules. | |
| 23 | ||
| 24 | ## I want to help, what can I do | |
| 25 | ||
| 26 | Thanks a lot to everyone who wants to help Clippy become better software in this feature freeze period! | |
| 27 | If you'd like to help, making a bugfix, making sure that it works, and opening a PR is a great step! | |
| 28 | ||
| 29 | To find things to fix, go to the [tracking issue][tracking_issue], find an issue that you like, go there and claim that | |
| 30 | issue with `@rustbot claim`. | |
| 31 | ||
| 32 | As a general metric and always taking into account your skill and knowledge level, you can use this guide: | |
| 33 | ||
| 34 | - 🟥 [ICEs][search_ice], these are compiler errors that causes Clippy to panic and crash. Usually involves high-level | |
| 35 | debugging, sometimes interacting directly with the upstream compiler. Difficult to fix but a great challenge that | |
| 36 | improves a lot developer workflows! | |
| 37 | ||
| 38 | - 🟧 [Suggestion causes bug][sugg_causes_bug], Clippy suggested code that changed logic in some silent way. | |
| 39 | Unacceptable, as this may have disastrous consequences. Easier to fix than ICEs | |
| 40 | ||
| 41 | - 🟨 [Suggestion causes error][sugg_causes_error], Clippy suggested code snippet that caused a compiler error | |
| 42 | when applied. We need to make sure that Clippy doesn't suggest using a variable twice at the same time or similar | |
| 43 | easy-to-happen occurrences. | |
| 44 | ||
| 45 | - 🟩 [False positives][false_positive], a lint should not have fired, the easiest of them all, as this is "just" | |
| 46 | identifying the root of a false positive and making an exception for those cases. | |
| 47 | ||
| 48 | Note that false negatives do not have priority unless the case is very clear, as they are a feature-request in a | |
| 49 | trench coat. | |
| 50 | ||
| 51 | [search_ice]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc+state%3Aopen+label%3A%22I-ICE%22 | |
| 52 | [sugg_causes_bug]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-suggestion-causes-bug | |
| 53 | [sugg_causes_error]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-suggestion-causes-error%20 | |
| 54 | [false_positive]: https://github.com/rust-lang/rust-clippy/issues?q=sort%3Aupdated-desc%20state%3Aopen%20label%3AI-false-positive | |
| 55 | [tracking_issue]: https://github.com/rust-lang/rust-clippy/issues/15086 |
src/tools/clippy/book/src/lint_configuration.md+23-1| ... | ... | @@ -488,6 +488,13 @@ The maximum cognitive complexity a function can have |
| 488 | 488 | ## `disallowed-macros` |
| 489 | 489 | The list of disallowed macros, written as fully qualified paths. |
| 490 | 490 | |
| 491 | **Fields:** | |
| 492 | - `path` (required): the fully qualified path to the macro that should be disallowed | |
| 493 | - `reason` (optional): explanation why this macro is disallowed | |
| 494 | - `replacement` (optional): suggested alternative macro | |
| 495 | - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry | |
| 496 | if the path doesn't exist, instead of emitting an error | |
| 497 | ||
| 491 | 498 | **Default Value:** `[]` |
| 492 | 499 | |
| 493 | 500 | --- |
| ... | ... | @@ -498,6 +505,13 @@ The list of disallowed macros, written as fully qualified paths. |
| 498 | 505 | ## `disallowed-methods` |
| 499 | 506 | The list of disallowed methods, written as fully qualified paths. |
| 500 | 507 | |
| 508 | **Fields:** | |
| 509 | - `path` (required): the fully qualified path to the method that should be disallowed | |
| 510 | - `reason` (optional): explanation why this method is disallowed | |
| 511 | - `replacement` (optional): suggested alternative method | |
| 512 | - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry | |
| 513 | if the path doesn't exist, instead of emitting an error | |
| 514 | ||
| 501 | 515 | **Default Value:** `[]` |
| 502 | 516 | |
| 503 | 517 | --- |
| ... | ... | @@ -520,6 +534,13 @@ default configuration of Clippy. By default, any configuration will replace the |
| 520 | 534 | ## `disallowed-types` |
| 521 | 535 | The list of disallowed types, written as fully qualified paths. |
| 522 | 536 | |
| 537 | **Fields:** | |
| 538 | - `path` (required): the fully qualified path to the type that should be disallowed | |
| 539 | - `reason` (optional): explanation why this type is disallowed | |
| 540 | - `replacement` (optional): suggested alternative type | |
| 541 | - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry | |
| 542 | if the path doesn't exist, instead of emitting an error | |
| 543 | ||
| 523 | 544 | **Default Value:** `[]` |
| 524 | 545 | |
| 525 | 546 | --- |
| ... | ... | @@ -651,13 +672,14 @@ The maximum size of the `Err`-variant in a `Result` returned from a function |
| 651 | 672 | |
| 652 | 673 | |
| 653 | 674 | ## `lint-commented-code` |
| 654 | Whether collapsible `if` chains are linted if they contain comments inside the parts | |
| 675 | Whether collapsible `if` and `else if` chains are linted if they contain comments inside the parts | |
| 655 | 676 | that would be collapsed. |
| 656 | 677 | |
| 657 | 678 | **Default Value:** `false` |
| 658 | 679 | |
| 659 | 680 | --- |
| 660 | 681 | **Affected lints:** |
| 682 | * [`collapsible_else_if`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if) | |
| 661 | 683 | * [`collapsible_if`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if) |
| 662 | 684 | |
| 663 | 685 |
src/tools/clippy/clippy_config/Cargo.toml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | [package] |
| 2 | 2 | name = "clippy_config" |
| 3 | version = "0.1.89" | |
| 3 | version = "0.1.90" | |
| 4 | 4 | edition = "2024" |
| 5 | 5 | publish = false |
| 6 | 6 |
src/tools/clippy/clippy_config/src/conf.rs+23-2| ... | ... | @@ -575,10 +575,24 @@ define_Conf! { |
| 575 | 575 | #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] |
| 576 | 576 | cyclomatic_complexity_threshold: u64 = 25, |
| 577 | 577 | /// The list of disallowed macros, written as fully qualified paths. |
| 578 | /// | |
| 579 | /// **Fields:** | |
| 580 | /// - `path` (required): the fully qualified path to the macro that should be disallowed | |
| 581 | /// - `reason` (optional): explanation why this macro is disallowed | |
| 582 | /// - `replacement` (optional): suggested alternative macro | |
| 583 | /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry | |
| 584 | /// if the path doesn't exist, instead of emitting an error | |
| 578 | 585 | #[disallowed_paths_allow_replacements = true] |
| 579 | 586 | #[lints(disallowed_macros)] |
| 580 | 587 | disallowed_macros: Vec<DisallowedPath> = Vec::new(), |
| 581 | 588 | /// The list of disallowed methods, written as fully qualified paths. |
| 589 | /// | |
| 590 | /// **Fields:** | |
| 591 | /// - `path` (required): the fully qualified path to the method that should be disallowed | |
| 592 | /// - `reason` (optional): explanation why this method is disallowed | |
| 593 | /// - `replacement` (optional): suggested alternative method | |
| 594 | /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry | |
| 595 | /// if the path doesn't exist, instead of emitting an error | |
| 582 | 596 | #[disallowed_paths_allow_replacements = true] |
| 583 | 597 | #[lints(disallowed_methods)] |
| 584 | 598 | disallowed_methods: Vec<DisallowedPath> = Vec::new(), |
| ... | ... | @@ -588,6 +602,13 @@ define_Conf! { |
| 588 | 602 | #[lints(disallowed_names)] |
| 589 | 603 | disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(), |
| 590 | 604 | /// The list of disallowed types, written as fully qualified paths. |
| 605 | /// | |
| 606 | /// **Fields:** | |
| 607 | /// - `path` (required): the fully qualified path to the type that should be disallowed | |
| 608 | /// - `reason` (optional): explanation why this type is disallowed | |
| 609 | /// - `replacement` (optional): suggested alternative type | |
| 610 | /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry | |
| 611 | /// if the path doesn't exist, instead of emitting an error | |
| 591 | 612 | #[disallowed_paths_allow_replacements = true] |
| 592 | 613 | #[lints(disallowed_types)] |
| 593 | 614 | disallowed_types: Vec<DisallowedPath> = Vec::new(), |
| ... | ... | @@ -641,9 +662,9 @@ define_Conf! { |
| 641 | 662 | /// The maximum size of the `Err`-variant in a `Result` returned from a function |
| 642 | 663 | #[lints(result_large_err)] |
| 643 | 664 | large_error_threshold: u64 = 128, |
| 644 | /// Whether collapsible `if` chains are linted if they contain comments inside the parts | |
| 665 | /// Whether collapsible `if` and `else if` chains are linted if they contain comments inside the parts | |
| 645 | 666 | /// that would be collapsed. |
| 646 | #[lints(collapsible_if)] | |
| 667 | #[lints(collapsible_else_if, collapsible_if)] | |
| 647 | 668 | lint_commented_code: bool = false, |
| 648 | 669 | /// Whether to suggest reordering constructor fields when initializers are present. |
| 649 | 670 | /// DEPRECATED CONFIGURATION: lint-inconsistent-struct-field-initializers |
src/tools/clippy/clippy_dev/src/lint.rs+2-2| ... | ... | @@ -13,7 +13,7 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String> |
| 13 | 13 | |
| 14 | 14 | if is_file { |
| 15 | 15 | exit_if_err( |
| 16 | Command::new(env::var("CARGO").unwrap_or("cargo".into())) | |
| 16 | Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) | |
| 17 | 17 | .args(["run", "--bin", "clippy-driver", "--"]) |
| 18 | 18 | .args(["-L", "./target/debug"]) |
| 19 | 19 | .args(["-Z", "no-codegen"]) |
| ... | ... | @@ -26,7 +26,7 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String> |
| 26 | 26 | ); |
| 27 | 27 | } else { |
| 28 | 28 | exit_if_err( |
| 29 | Command::new(env::var("CARGO").unwrap_or("cargo".into())) | |
| 29 | Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) | |
| 30 | 30 | .arg("build") |
| 31 | 31 | .status(), |
| 32 | 32 | ); |
src/tools/clippy/clippy_dev/src/release.rs+1| ... | ... | @@ -5,6 +5,7 @@ static CARGO_TOML_FILES: &[&str] = &[ |
| 5 | 5 | "clippy_config/Cargo.toml", |
| 6 | 6 | "clippy_lints/Cargo.toml", |
| 7 | 7 | "clippy_utils/Cargo.toml", |
| 8 | "declare_clippy_lint/Cargo.toml", | |
| 8 | 9 | "Cargo.toml", |
| 9 | 10 | ]; |
| 10 | 11 |
src/tools/clippy/clippy_dev/src/serve.rs+1-1| ... | ... | @@ -28,7 +28,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! { |
| 28 | 28 | .map(mtime); |
| 29 | 29 | |
| 30 | 30 | if times.iter().any(|&time| index_time < time) { |
| 31 | Command::new(env::var("CARGO").unwrap_or("cargo".into())) | |
| 31 | Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) | |
| 32 | 32 | .arg("collect-metadata") |
| 33 | 33 | .spawn() |
| 34 | 34 | .unwrap() |
src/tools/clippy/clippy_dev/src/update_lints.rs+170-121| ... | ... | @@ -2,11 +2,11 @@ use crate::utils::{ |
| 2 | 2 | ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, expect_action, update_text_region_fn, |
| 3 | 3 | }; |
| 4 | 4 | use itertools::Itertools; |
| 5 | use rustc_lexer::{LiteralKind, TokenKind, tokenize}; | |
| 6 | 5 | use std::collections::HashSet; |
| 7 | 6 | use std::fmt::Write; |
| 7 | use std::fs; | |
| 8 | 8 | use std::ops::Range; |
| 9 | use std::path::{Path, PathBuf}; | |
| 9 | use std::path::{self, Path, PathBuf}; | |
| 10 | 10 | use walkdir::{DirEntry, WalkDir}; |
| 11 | 11 | |
| 12 | 12 | const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\ |
| ... | ... | @@ -37,123 +37,164 @@ pub fn generate_lint_files( |
| 37 | 37 | deprecated: &[DeprecatedLint], |
| 38 | 38 | renamed: &[RenamedLint], |
| 39 | 39 | ) { |
| 40 | FileUpdater::default().update_files_checked( | |
| 40 | let mut updater = FileUpdater::default(); | |
| 41 | updater.update_file_checked( | |
| 41 | 42 | "cargo dev update_lints", |
| 42 | 43 | update_mode, |
| 43 | &mut [ | |
| 44 | ( | |
| 45 | "README.md", | |
| 46 | &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { | |
| 47 | write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); | |
| 48 | }), | |
| 49 | ), | |
| 50 | ( | |
| 51 | "book/src/README.md", | |
| 52 | &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { | |
| 53 | write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); | |
| 54 | }), | |
| 55 | ), | |
| 56 | ( | |
| 57 | "CHANGELOG.md", | |
| 58 | &mut update_text_region_fn( | |
| 59 | "<!-- begin autogenerated links to lint list -->\n", | |
| 60 | "<!-- end autogenerated links to lint list -->", | |
| 61 | |dst| { | |
| 62 | for lint in lints | |
| 63 | .iter() | |
| 64 | .map(|l| &*l.name) | |
| 65 | .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) | |
| 66 | .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::"))) | |
| 67 | .sorted() | |
| 68 | { | |
| 69 | writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); | |
| 70 | } | |
| 71 | }, | |
| 72 | ), | |
| 73 | ), | |
| 74 | ( | |
| 75 | "clippy_lints/src/lib.rs", | |
| 76 | &mut update_text_region_fn( | |
| 77 | "// begin lints modules, do not remove this comment, it's used in `update_lints`\n", | |
| 78 | "// end lints modules, do not remove this comment, it's used in `update_lints`", | |
| 79 | |dst| { | |
| 80 | for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() { | |
| 81 | writeln!(dst, "mod {lint_mod};").unwrap(); | |
| 82 | } | |
| 83 | }, | |
| 84 | ), | |
| 85 | ), | |
| 86 | ("clippy_lints/src/declared_lints.rs", &mut |_, src, dst| { | |
| 87 | dst.push_str(GENERATED_FILE_COMMENT); | |
| 88 | dst.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); | |
| 89 | for (module_name, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() { | |
| 90 | writeln!(dst, " crate::{module_name}::{lint_name}_INFO,").unwrap(); | |
| 91 | } | |
| 92 | dst.push_str("];\n"); | |
| 93 | UpdateStatus::from_changed(src != dst) | |
| 94 | }), | |
| 95 | ("clippy_lints/src/deprecated_lints.rs", &mut |_, src, dst| { | |
| 96 | let mut searcher = RustSearcher::new(src); | |
| 97 | assert!( | |
| 98 | searcher.find_token(Token::Ident("declare_with_version")) | |
| 99 | && searcher.find_token(Token::Ident("declare_with_version")), | |
| 100 | "error reading deprecated lints" | |
| 101 | ); | |
| 102 | dst.push_str(&src[..searcher.pos() as usize]); | |
| 103 | dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n"); | |
| 104 | for lint in deprecated { | |
| 105 | write!( | |
| 106 | dst, | |
| 107 | " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", | |
| 108 | lint.version, lint.name, lint.reason, | |
| 109 | ) | |
| 110 | .unwrap(); | |
| 44 | "README.md", | |
| 45 | &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { | |
| 46 | write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); | |
| 47 | }), | |
| 48 | ); | |
| 49 | updater.update_file_checked( | |
| 50 | "cargo dev update_lints", | |
| 51 | update_mode, | |
| 52 | "book/src/README.md", | |
| 53 | &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { | |
| 54 | write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); | |
| 55 | }), | |
| 56 | ); | |
| 57 | updater.update_file_checked( | |
| 58 | "cargo dev update_lints", | |
| 59 | update_mode, | |
| 60 | "CHANGELOG.md", | |
| 61 | &mut update_text_region_fn( | |
| 62 | "<!-- begin autogenerated links to lint list -->\n", | |
| 63 | "<!-- end autogenerated links to lint list -->", | |
| 64 | |dst| { | |
| 65 | for lint in lints | |
| 66 | .iter() | |
| 67 | .map(|l| &*l.name) | |
| 68 | .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) | |
| 69 | .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::"))) | |
| 70 | .sorted() | |
| 71 | { | |
| 72 | writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); | |
| 111 | 73 | } |
| 112 | dst.push_str( | |
| 113 | "]}\n\n\ | |
| 74 | }, | |
| 75 | ), | |
| 76 | ); | |
| 77 | updater.update_file_checked( | |
| 78 | "cargo dev update_lints", | |
| 79 | update_mode, | |
| 80 | "clippy_lints/src/deprecated_lints.rs", | |
| 81 | &mut |_, src, dst| { | |
| 82 | let mut searcher = RustSearcher::new(src); | |
| 83 | assert!( | |
| 84 | searcher.find_token(Token::Ident("declare_with_version")) | |
| 85 | && searcher.find_token(Token::Ident("declare_with_version")), | |
| 86 | "error reading deprecated lints" | |
| 87 | ); | |
| 88 | dst.push_str(&src[..searcher.pos() as usize]); | |
| 89 | dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n"); | |
| 90 | for lint in deprecated { | |
| 91 | write!( | |
| 92 | dst, | |
| 93 | " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", | |
| 94 | lint.version, lint.name, lint.reason, | |
| 95 | ) | |
| 96 | .unwrap(); | |
| 97 | } | |
| 98 | dst.push_str( | |
| 99 | "]}\n\n\ | |
| 114 | 100 | #[rustfmt::skip]\n\ |
| 115 | 101 | declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\ |
| 116 | 102 | ", |
| 117 | ); | |
| 118 | for lint in renamed { | |
| 119 | write!( | |
| 120 | dst, | |
| 121 | " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", | |
| 122 | lint.version, lint.old_name, lint.new_name, | |
| 123 | ) | |
| 124 | .unwrap(); | |
| 103 | ); | |
| 104 | for lint in renamed { | |
| 105 | write!( | |
| 106 | dst, | |
| 107 | " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", | |
| 108 | lint.version, lint.old_name, lint.new_name, | |
| 109 | ) | |
| 110 | .unwrap(); | |
| 111 | } | |
| 112 | dst.push_str("]}\n"); | |
| 113 | UpdateStatus::from_changed(src != dst) | |
| 114 | }, | |
| 115 | ); | |
| 116 | updater.update_file_checked( | |
| 117 | "cargo dev update_lints", | |
| 118 | update_mode, | |
| 119 | "tests/ui/deprecated.rs", | |
| 120 | &mut |_, src, dst| { | |
| 121 | dst.push_str(GENERATED_FILE_COMMENT); | |
| 122 | for lint in deprecated { | |
| 123 | writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap(); | |
| 124 | } | |
| 125 | dst.push_str("\nfn main() {}\n"); | |
| 126 | UpdateStatus::from_changed(src != dst) | |
| 127 | }, | |
| 128 | ); | |
| 129 | updater.update_file_checked( | |
| 130 | "cargo dev update_lints", | |
| 131 | update_mode, | |
| 132 | "tests/ui/rename.rs", | |
| 133 | &mut move |_, src, dst| { | |
| 134 | let mut seen_lints = HashSet::new(); | |
| 135 | dst.push_str(GENERATED_FILE_COMMENT); | |
| 136 | dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); | |
| 137 | for lint in renamed { | |
| 138 | if seen_lints.insert(&lint.new_name) { | |
| 139 | writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); | |
| 125 | 140 | } |
| 126 | dst.push_str("]}\n"); | |
| 127 | UpdateStatus::from_changed(src != dst) | |
| 128 | }), | |
| 129 | ("tests/ui/deprecated.rs", &mut |_, src, dst| { | |
| 130 | dst.push_str(GENERATED_FILE_COMMENT); | |
| 131 | for lint in deprecated { | |
| 132 | writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap(); | |
| 141 | } | |
| 142 | seen_lints.clear(); | |
| 143 | for lint in renamed { | |
| 144 | if seen_lints.insert(&lint.old_name) { | |
| 145 | writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); | |
| 133 | 146 | } |
| 134 | dst.push_str("\nfn main() {}\n"); | |
| 135 | UpdateStatus::from_changed(src != dst) | |
| 136 | }), | |
| 137 | ("tests/ui/rename.rs", &mut move |_, src, dst| { | |
| 138 | let mut seen_lints = HashSet::new(); | |
| 139 | dst.push_str(GENERATED_FILE_COMMENT); | |
| 140 | dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); | |
| 141 | for lint in renamed { | |
| 142 | if seen_lints.insert(&lint.new_name) { | |
| 143 | writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); | |
| 147 | } | |
| 148 | dst.push_str("\nfn main() {}\n"); | |
| 149 | UpdateStatus::from_changed(src != dst) | |
| 150 | }, | |
| 151 | ); | |
| 152 | for (crate_name, lints) in lints.iter().into_group_map_by(|&l| { | |
| 153 | let Some(path::Component::Normal(name)) = l.path.components().next() else { | |
| 154 | // All paths should start with `{crate_name}/src` when parsed from `find_lint_decls` | |
| 155 | panic!("internal error: can't read crate name from path `{}`", l.path.display()); | |
| 156 | }; | |
| 157 | name | |
| 158 | }) { | |
| 159 | updater.update_file_checked( | |
| 160 | "cargo dev update_lints", | |
| 161 | update_mode, | |
| 162 | Path::new(crate_name).join("src/lib.rs"), | |
| 163 | &mut update_text_region_fn( | |
| 164 | "// begin lints modules, do not remove this comment, it's used in `update_lints`\n", | |
| 165 | "// end lints modules, do not remove this comment, it's used in `update_lints`", | |
| 166 | |dst| { | |
| 167 | for lint_mod in lints | |
| 168 | .iter() | |
| 169 | .filter(|l| !l.module.is_empty()) | |
| 170 | .map(|l| l.module.split_once("::").map_or(&*l.module, |x| x.0)) | |
| 171 | .sorted() | |
| 172 | .dedup() | |
| 173 | { | |
| 174 | writeln!(dst, "mod {lint_mod};").unwrap(); | |
| 144 | 175 | } |
| 145 | } | |
| 146 | seen_lints.clear(); | |
| 147 | for lint in renamed { | |
| 148 | if seen_lints.insert(&lint.old_name) { | |
| 149 | writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); | |
| 176 | }, | |
| 177 | ), | |
| 178 | ); | |
| 179 | updater.update_file_checked( | |
| 180 | "cargo dev update_lints", | |
| 181 | update_mode, | |
| 182 | Path::new(crate_name).join("src/declared_lints.rs"), | |
| 183 | &mut |_, src, dst| { | |
| 184 | dst.push_str(GENERATED_FILE_COMMENT); | |
| 185 | dst.push_str("pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[\n"); | |
| 186 | for (module_path, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() { | |
| 187 | if module_path.is_empty() { | |
| 188 | writeln!(dst, " crate::{lint_name}_INFO,").unwrap(); | |
| 189 | } else { | |
| 190 | writeln!(dst, " crate::{module_path}::{lint_name}_INFO,").unwrap(); | |
| 150 | 191 | } |
| 151 | 192 | } |
| 152 | dst.push_str("\nfn main() {}\n"); | |
| 193 | dst.push_str("];\n"); | |
| 153 | 194 | UpdateStatus::from_changed(src != dst) |
| 154 | }), | |
| 155 | ], | |
| 156 | ); | |
| 195 | }, | |
| 196 | ); | |
| 197 | } | |
| 157 | 198 | } |
| 158 | 199 | |
| 159 | 200 | fn round_to_fifty(count: usize) -> usize { |
| ... | ... | @@ -187,13 +228,25 @@ pub struct RenamedLint { |
| 187 | 228 | pub fn find_lint_decls() -> Vec<Lint> { |
| 188 | 229 | let mut lints = Vec::with_capacity(1000); |
| 189 | 230 | let mut contents = String::new(); |
| 190 | for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) { | |
| 191 | parse_clippy_lint_decls( | |
| 192 | file.path(), | |
| 193 | File::open_read_to_cleared_string(file.path(), &mut contents), | |
| 194 | &module, | |
| 195 | &mut lints, | |
| 196 | ); | |
| 231 | for e in expect_action(fs::read_dir("."), ErrAction::Read, ".") { | |
| 232 | let e = expect_action(e, ErrAction::Read, "."); | |
| 233 | if !expect_action(e.file_type(), ErrAction::Read, ".").is_dir() { | |
| 234 | continue; | |
| 235 | } | |
| 236 | let Ok(mut name) = e.file_name().into_string() else { | |
| 237 | continue; | |
| 238 | }; | |
| 239 | if name.starts_with("clippy_lints") && name != "clippy_lints_internal" { | |
| 240 | name.push_str("/src"); | |
| 241 | for (file, module) in read_src_with_module(name.as_ref()) { | |
| 242 | parse_clippy_lint_decls( | |
| 243 | file.path(), | |
| 244 | File::open_read_to_cleared_string(file.path(), &mut contents), | |
| 245 | &module, | |
| 246 | &mut lints, | |
| 247 | ); | |
| 248 | } | |
| 249 | } | |
| 197 | 250 | } |
| 198 | 251 | lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); |
| 199 | 252 | lints |
| ... | ... | @@ -205,7 +258,7 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirE |
| 205 | 258 | let e = expect_action(e, ErrAction::Read, src_root); |
| 206 | 259 | let path = e.path().as_os_str().as_encoded_bytes(); |
| 207 | 260 | if let Some(path) = path.strip_suffix(b".rs") |
| 208 | && let Some(path) = path.get("clippy_lints/src/".len()..) | |
| 261 | && let Some(path) = path.get(src_root.as_os_str().len() + 1..) | |
| 209 | 262 | { |
| 210 | 263 | if path == b"lib" { |
| 211 | 264 | Some((e, String::new())) |
| ... | ... | @@ -333,17 +386,13 @@ pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) { |
| 333 | 386 | |
| 334 | 387 | /// Removes the line splices and surrounding quotes from a string literal |
| 335 | 388 | fn parse_str_lit(s: &str) -> String { |
| 336 | let (s, mode) = if let Some(s) = s.strip_prefix("r") { | |
| 337 | (s.trim_matches('#'), rustc_literal_escaper::Mode::RawStr) | |
| 338 | } else { | |
| 339 | (s, rustc_literal_escaper::Mode::Str) | |
| 340 | }; | |
| 389 | let s = s.strip_prefix("r").unwrap_or(s).trim_matches('#'); | |
| 341 | 390 | let s = s |
| 342 | 391 | .strip_prefix('"') |
| 343 | 392 | .and_then(|s| s.strip_suffix('"')) |
| 344 | 393 | .unwrap_or_else(|| panic!("expected quoted string, found `{s}`")); |
| 345 | 394 | let mut res = String::with_capacity(s.len()); |
| 346 | rustc_literal_escaper::unescape_str(s, |range, ch| { | |
| 395 | rustc_literal_escaper::unescape_str(s, &mut |_, ch| { | |
| 347 | 396 | if let Ok(ch) = ch { |
| 348 | 397 | res.push(ch); |
| 349 | 398 | } |
src/tools/clippy/clippy_dev/src/utils.rs-15| ... | ... | @@ -383,21 +383,6 @@ impl FileUpdater { |
| 383 | 383 | self.update_file_checked_inner(tool, mode, path.as_ref(), update); |
| 384 | 384 | } |
| 385 | 385 | |
| 386 | #[expect(clippy::type_complexity)] | |
| 387 | pub fn update_files_checked( | |
| 388 | &mut self, | |
| 389 | tool: &str, | |
| 390 | mode: UpdateMode, | |
| 391 | files: &mut [( | |
| 392 | impl AsRef<Path>, | |
| 393 | &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus, | |
| 394 | )], | |
| 395 | ) { | |
| 396 | for (path, update) in files { | |
| 397 | self.update_file_checked_inner(tool, mode, path.as_ref(), update); | |
| 398 | } | |
| 399 | } | |
| 400 | ||
| 401 | 386 | pub fn update_file( |
| 402 | 387 | &mut self, |
| 403 | 388 | path: impl AsRef<Path>, |
src/tools/clippy/clippy_lints/Cargo.toml+2-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | [package] |
| 2 | 2 | name = "clippy_lints" |
| 3 | version = "0.1.89" | |
| 3 | version = "0.1.90" | |
| 4 | 4 | description = "A bunch of helpful lints to avoid common pitfalls in Rust" |
| 5 | 5 | repository = "https://github.com/rust-lang/rust-clippy" |
| 6 | 6 | readme = "README.md" |
| ... | ... | @@ -13,6 +13,7 @@ arrayvec = { version = "0.7", default-features = false } |
| 13 | 13 | cargo_metadata = "0.18" |
| 14 | 14 | clippy_config = { path = "../clippy_config" } |
| 15 | 15 | clippy_utils = { path = "../clippy_utils" } |
| 16 | declare_clippy_lint = { path = "../declare_clippy_lint" } | |
| 16 | 17 | itertools = "0.12" |
| 17 | 18 | quine-mc_cluskey = "0.2" |
| 18 | 19 | regex-syntax = "0.8" |
src/tools/clippy/clippy_lints/src/attrs/inline_always.rs+2-2| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | use super::INLINE_ALWAYS; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint; |
| 3 | use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr}; | |
| 3 | use rustc_attr_data_structures::{AttributeKind, InlineAttr, find_attr}; | |
| 4 | 4 | use rustc_hir::Attribute; |
| 5 | 5 | use rustc_lint::LateContext; |
| 6 | use rustc_span::symbol::Symbol; | |
| 7 | 6 | use rustc_span::Span; |
| 7 | use rustc_span::symbol::Symbol; | |
| 8 | 8 | |
| 9 | 9 | pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { |
| 10 | 10 | if span.from_expansion() { |
src/tools/clippy/clippy_lints/src/attrs/mod.rs+1-1| ... | ... | @@ -207,7 +207,7 @@ declare_clippy_lint! { |
| 207 | 207 | declare_clippy_lint! { |
| 208 | 208 | /// ### What it does |
| 209 | 209 | /// Checks for usage of the `#[allow]` attribute and suggests replacing it with |
| 210 | /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) | |
| 210 | /// the `#[expect]` attribute (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) | |
| 211 | 211 | /// |
| 212 | 212 | /// This lint only warns outer attributes (`#[allow]`), as inner attributes |
| 213 | 213 | /// (`#![allow]`) are usually used to enable or disable lints on a global scale. |
src/tools/clippy/clippy_lints/src/attrs/utils.rs+7-5| ... | ... | @@ -46,11 +46,13 @@ pub(super) fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> b |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | 48 | fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool { |
| 49 | block.stmts.first().map_or( | |
| 50 | block | |
| 51 | .expr | |
| 52 | .as_ref() | |
| 53 | .is_some_and(|e| is_relevant_expr(cx, typeck_results, e)), | |
| 49 | block.stmts.first().map_or_else( | |
| 50 | || { | |
| 51 | block | |
| 52 | .expr | |
| 53 | .as_ref() | |
| 54 | .is_some_and(|e| is_relevant_expr(cx, typeck_results, e)) | |
| 55 | }, | |
| 54 | 56 | |stmt| match &stmt.kind { |
| 55 | 57 | StmtKind::Let(_) => true, |
| 56 | 58 | StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), |
src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs+12-3| ... | ... | @@ -2,9 +2,9 @@ use crate::reference::DEREF_ADDROF; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | 3 | use clippy_utils::source::SpanRangeExt; |
| 4 | 4 | use clippy_utils::ty::implements_trait; |
| 5 | use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed, is_mutable}; | |
| 5 | use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable}; | |
| 6 | 6 | use rustc_errors::Applicability; |
| 7 | use rustc_hir::{BorrowKind, ExprKind, UnOp}; | |
| 7 | use rustc_hir::{BorrowKind, Expr, ExprKind, Node, UnOp}; | |
| 8 | 8 | use rustc_lint::{LateContext, LateLintPass}; |
| 9 | 9 | use rustc_middle::mir::Mutability; |
| 10 | 10 | use rustc_middle::ty; |
| ... | ... | @@ -48,7 +48,7 @@ declare_clippy_lint! { |
| 48 | 48 | declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); |
| 49 | 49 | |
| 50 | 50 | impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { |
| 51 | fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) { | |
| 51 | fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) { | |
| 52 | 52 | if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, addrof_target) = e.kind |
| 53 | 53 | && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind |
| 54 | 54 | && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) |
| ... | ... | @@ -76,6 +76,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { |
| 76 | 76 | && let e_ty = cx.typeck_results().expr_ty_adjusted(e) |
| 77 | 77 | // check if the reference is coercing to a mutable reference |
| 78 | 78 | && (!matches!(e_ty.kind(), ty::Ref(_, _, Mutability::Mut)) || is_mutable(cx, deref_target)) |
| 79 | // If the new borrow might be itself borrowed mutably and the original reference is not a temporary | |
| 80 | // value, do not propose to use it directly. | |
| 81 | && (is_expr_temporary_value(cx, deref_target) || !potentially_bound_to_mutable_ref(cx, e)) | |
| 79 | 82 | && let Some(deref_text) = deref_target.span.get_source_text(cx) |
| 80 | 83 | { |
| 81 | 84 | span_lint_and_then( |
| ... | ... | @@ -110,3 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { |
| 110 | 113 | } |
| 111 | 114 | } |
| 112 | 115 | } |
| 116 | ||
| 117 | /// Checks if `expr` is used as part of a `let` statement containing a `ref mut` binding. | |
| 118 | fn potentially_bound_to_mutable_ref<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { | |
| 119 | matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::LetStmt(let_stmt) | |
| 120 | if let_stmt.pat.contains_explicit_ref_binding() == Some(Mutability::Mut)) | |
| 121 | } |
src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs+1-1| ... | ... | @@ -168,7 +168,7 @@ fn pow_call_result_sign(cx: &LateContext<'_>, base: &Expr<'_>, exponent: &Expr<' |
| 168 | 168 | |
| 169 | 169 | // Rust's integer pow() functions take an unsigned exponent. |
| 170 | 170 | let exponent_val = get_const_unsigned_int_eval(cx, exponent, None); |
| 171 | let exponent_is_even = exponent_val.map(|val| val % 2 == 0); | |
| 171 | let exponent_is_even = exponent_val.map(|val| val.is_multiple_of(2)); | |
| 172 | 172 | |
| 173 | 173 | match (base_sign, exponent_is_even) { |
| 174 | 174 | // Non-negative bases always return non-negative results, ignoring overflow. |
src/tools/clippy/clippy_lints/src/collapsible_if.rs+93-34| ... | ... | @@ -1,13 +1,16 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; | |
| 2 | use clippy_utils::diagnostics::span_lint_and_then; | |
| 3 | 3 | use clippy_utils::msrvs::{self, Msrv}; |
| 4 | use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block, snippet_block_with_applicability}; | |
| 4 | use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; | |
| 5 | use clippy_utils::{span_contains_non_whitespace, tokenize_with_text}; | |
| 5 | 6 | use rustc_ast::BinOpKind; |
| 6 | 7 | use rustc_errors::Applicability; |
| 7 | 8 | use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; |
| 9 | use rustc_lexer::TokenKind; | |
| 8 | 10 | use rustc_lint::{LateContext, LateLintPass}; |
| 9 | 11 | use rustc_session::impl_lint_pass; |
| 10 | use rustc_span::Span; | |
| 12 | use rustc_span::source_map::SourceMap; | |
| 13 | use rustc_span::{BytePos, Span}; | |
| 11 | 14 | |
| 12 | 15 | declare_clippy_lint! { |
| 13 | 16 | /// ### What it does |
| ... | ... | @@ -90,35 +93,74 @@ impl CollapsibleIf { |
| 90 | 93 | } |
| 91 | 94 | } |
| 92 | 95 | |
| 93 | fn check_collapsible_else_if(cx: &LateContext<'_>, then_span: Span, else_block: &Block<'_>) { | |
| 94 | if !block_starts_with_comment(cx, else_block) | |
| 95 | && let Some(else_) = expr_block(else_block) | |
| 96 | fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_block: &Block<'_>) { | |
| 97 | if let Some(else_) = expr_block(else_block) | |
| 96 | 98 | && cx.tcx.hir_attrs(else_.hir_id).is_empty() |
| 97 | 99 | && !else_.span.from_expansion() |
| 98 | && let ExprKind::If(..) = else_.kind | |
| 100 | && let ExprKind::If(else_if_cond, ..) = else_.kind | |
| 101 | && !block_starts_with_significant_tokens(cx, else_block, else_, self.lint_commented_code) | |
| 99 | 102 | { |
| 100 | // Prevent "elseif" | |
| 101 | // Check that the "else" is followed by whitespace | |
| 102 | let up_to_else = then_span.between(else_block.span); | |
| 103 | let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { | |
| 104 | !c.is_whitespace() | |
| 105 | } else { | |
| 106 | false | |
| 107 | }; | |
| 108 | ||
| 109 | let mut applicability = Applicability::MachineApplicable; | |
| 110 | span_lint_and_sugg( | |
| 103 | span_lint_and_then( | |
| 111 | 104 | cx, |
| 112 | 105 | COLLAPSIBLE_ELSE_IF, |
| 113 | 106 | else_block.span, |
| 114 | 107 | "this `else { if .. }` block can be collapsed", |
| 115 | "collapse nested if block", | |
| 116 | format!( | |
| 117 | "{}{}", | |
| 118 | if requires_space { " " } else { "" }, | |
| 119 | snippet_block_with_applicability(cx, else_.span, "..", Some(else_block.span), &mut applicability) | |
| 120 | ), | |
| 121 | applicability, | |
| 108 | |diag| { | |
| 109 | let up_to_else = then_span.between(else_block.span); | |
| 110 | let else_before_if = else_.span.shrink_to_lo().with_hi(else_if_cond.span.lo() - BytePos(1)); | |
| 111 | if self.lint_commented_code | |
| 112 | && let Some(else_keyword_span) = | |
| 113 | span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else") | |
| 114 | && let Some(else_if_keyword_span) = | |
| 115 | span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if") | |
| 116 | { | |
| 117 | let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span(); | |
| 118 | let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span(); | |
| 119 | let else_closing_bracket = { | |
| 120 | let end = else_block.span.shrink_to_hi(); | |
| 121 | end.with_lo(end.lo() - BytePos(1)) | |
| 122 | .with_leading_whitespace(cx) | |
| 123 | .into_span() | |
| 124 | }; | |
| 125 | let sugg = vec![ | |
| 126 | // Remove the outer else block `else` | |
| 127 | (else_keyword_span, String::new()), | |
| 128 | // Replace the inner `if` by `else if` | |
| 129 | (else_if_keyword_span, String::from("else if")), | |
| 130 | // Remove the outer else block `{` | |
| 131 | (else_open_bracket, String::new()), | |
| 132 | // Remove the outer else block '}' | |
| 133 | (else_closing_bracket, String::new()), | |
| 134 | ]; | |
| 135 | diag.multipart_suggestion("collapse nested if block", sugg, Applicability::MachineApplicable); | |
| 136 | return; | |
| 137 | } | |
| 138 | ||
| 139 | // Prevent "elseif" | |
| 140 | // Check that the "else" is followed by whitespace | |
| 141 | let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { | |
| 142 | !c.is_whitespace() | |
| 143 | } else { | |
| 144 | false | |
| 145 | }; | |
| 146 | let mut applicability = Applicability::MachineApplicable; | |
| 147 | diag.span_suggestion( | |
| 148 | else_block.span, | |
| 149 | "collapse nested if block", | |
| 150 | format!( | |
| 151 | "{}{}", | |
| 152 | if requires_space { " " } else { "" }, | |
| 153 | snippet_block_with_applicability( | |
| 154 | cx, | |
| 155 | else_.span, | |
| 156 | "..", | |
| 157 | Some(else_block.span), | |
| 158 | &mut applicability | |
| 159 | ) | |
| 160 | ), | |
| 161 | applicability, | |
| 162 | ); | |
| 163 | }, | |
| 122 | 164 | ); |
| 123 | 165 | } |
| 124 | 166 | } |
| ... | ... | @@ -130,7 +172,7 @@ impl CollapsibleIf { |
| 130 | 172 | && self.eligible_condition(cx, check_inner) |
| 131 | 173 | && let ctxt = expr.span.ctxt() |
| 132 | 174 | && inner.span.ctxt() == ctxt |
| 133 | && (self.lint_commented_code || !block_starts_with_comment(cx, then)) | |
| 175 | && !block_starts_with_significant_tokens(cx, then, inner, self.lint_commented_code) | |
| 134 | 176 | { |
| 135 | 177 | span_lint_and_then( |
| 136 | 178 | cx, |
| ... | ... | @@ -141,7 +183,7 @@ impl CollapsibleIf { |
| 141 | 183 | let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span(); |
| 142 | 184 | let then_closing_bracket = { |
| 143 | 185 | let end = then.span.shrink_to_hi(); |
| 144 | end.with_lo(end.lo() - rustc_span::BytePos(1)) | |
| 186 | end.with_lo(end.lo() - BytePos(1)) | |
| 145 | 187 | .with_leading_whitespace(cx) |
| 146 | 188 | .into_span() |
| 147 | 189 | }; |
| ... | ... | @@ -179,7 +221,7 @@ impl LateLintPass<'_> for CollapsibleIf { |
| 179 | 221 | if let Some(else_) = else_ |
| 180 | 222 | && let ExprKind::Block(else_, None) = else_.kind |
| 181 | 223 | { |
| 182 | Self::check_collapsible_else_if(cx, then.span, else_); | |
| 224 | self.check_collapsible_else_if(cx, then.span, else_); | |
| 183 | 225 | } else if else_.is_none() |
| 184 | 226 | && self.eligible_condition(cx, cond) |
| 185 | 227 | && let ExprKind::Block(then, None) = then.kind |
| ... | ... | @@ -190,12 +232,16 @@ impl LateLintPass<'_> for CollapsibleIf { |
| 190 | 232 | } |
| 191 | 233 | } |
| 192 | 234 | |
| 193 | fn block_starts_with_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool { | |
| 194 | // We trim all opening braces and whitespaces and then check if the next string is a comment. | |
| 195 | let trimmed_block_text = snippet_block(cx, block.span, "..", None) | |
| 196 | .trim_start_matches(|c: char| c.is_whitespace() || c == '{') | |
| 197 | .to_owned(); | |
| 198 | trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*") | |
| 235 | // Check that nothing significant can be found but whitespaces between the initial `{` of `block` | |
| 236 | // and the beginning of `stop_at`. | |
| 237 | fn block_starts_with_significant_tokens( | |
| 238 | cx: &LateContext<'_>, | |
| 239 | block: &Block<'_>, | |
| 240 | stop_at: &Expr<'_>, | |
| 241 | lint_commented_code: bool, | |
| 242 | ) -> bool { | |
| 243 | let span = block.span.split_at(1).1.until(stop_at.span); | |
| 244 | span_contains_non_whitespace(cx, span, lint_commented_code) | |
| 199 | 245 | } |
| 200 | 246 | |
| 201 | 247 | /// If `block` is a block with either one expression or a statement containing an expression, |
| ... | ... | @@ -226,3 +272,16 @@ fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> { |
| 226 | 272 | vec![] |
| 227 | 273 | } |
| 228 | 274 | } |
| 275 | ||
| 276 | fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option<Span> { | |
| 277 | let snippet = sm.span_to_snippet(span).ok()?; | |
| 278 | tokenize_with_text(&snippet) | |
| 279 | .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword)) | |
| 280 | .map(|(_, _, inner)| { | |
| 281 | span.split_at(u32::try_from(inner.start).unwrap()) | |
| 282 | .1 | |
| 283 | .split_at(u32::try_from(inner.end - inner.start).unwrap()) | |
| 284 | .0 | |
| 285 | }) | |
| 286 | .next() | |
| 287 | } |
src/tools/clippy/clippy_lints/src/copies.rs+16-2| ... | ... | @@ -11,7 +11,7 @@ use clippy_utils::{ |
| 11 | 11 | use core::iter; |
| 12 | 12 | use core::ops::ControlFlow; |
| 13 | 13 | use rustc_errors::Applicability; |
| 14 | use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind, intravisit}; | |
| 14 | use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit}; | |
| 15 | 15 | use rustc_lint::{LateContext, LateLintPass}; |
| 16 | 16 | use rustc_middle::ty::TyCtxt; |
| 17 | 17 | use rustc_session::impl_lint_pass; |
| ... | ... | @@ -295,7 +295,7 @@ fn lint_branches_sharing_code<'tcx>( |
| 295 | 295 | sugg, |
| 296 | 296 | Applicability::Unspecified, |
| 297 | 297 | ); |
| 298 | if !cx.typeck_results().expr_ty(expr).is_unit() { | |
| 298 | if is_expr_parent_assignment(cx, expr) || !cx.typeck_results().expr_ty(expr).is_unit() { | |
| 299 | 299 | diag.note("the end suggestion probably needs some adjustments to use the expression result correctly"); |
| 300 | 300 | } |
| 301 | 301 | } |
| ... | ... | @@ -660,3 +660,17 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { |
| 660 | 660 | ); |
| 661 | 661 | } |
| 662 | 662 | } |
| 663 | ||
| 664 | fn is_expr_parent_assignment(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | |
| 665 | let parent = cx.tcx.parent_hir_node(expr.hir_id); | |
| 666 | if let Node::LetStmt(LetStmt { init: Some(e), .. }) | |
| 667 | | Node::Expr(Expr { | |
| 668 | kind: ExprKind::Assign(_, e, _), | |
| 669 | .. | |
| 670 | }) = parent | |
| 671 | { | |
| 672 | return e.hir_id == expr.hir_id; | |
| 673 | } | |
| 674 | ||
| 675 | false | |
| 676 | } |
src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs deleted-168| ... | ... | @@ -1,168 +0,0 @@ |
| 1 | #[macro_export] | |
| 2 | #[allow(clippy::crate_in_macro_def)] | |
| 3 | macro_rules! declare_clippy_lint { | |
| 4 | (@ | |
| 5 | $(#[doc = $lit:literal])* | |
| 6 | pub $lint_name:ident, | |
| 7 | $level:ident, | |
| 8 | $lintcategory:expr, | |
| 9 | $desc:literal, | |
| 10 | $version_expr:expr, | |
| 11 | $version_lit:literal | |
| 12 | $(, $eval_always: literal)? | |
| 13 | ) => { | |
| 14 | rustc_session::declare_tool_lint! { | |
| 15 | $(#[doc = $lit])* | |
| 16 | #[clippy::version = $version_lit] | |
| 17 | pub clippy::$lint_name, | |
| 18 | $level, | |
| 19 | $desc, | |
| 20 | report_in_external_macro:true | |
| 21 | $(, @eval_always = $eval_always)? | |
| 22 | } | |
| 23 | ||
| 24 | pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo { | |
| 25 | lint: &$lint_name, | |
| 26 | category: $lintcategory, | |
| 27 | explanation: concat!($($lit,"\n",)*), | |
| 28 | location: concat!(file!(), "#L", line!()), | |
| 29 | version: $version_expr | |
| 30 | }; | |
| 31 | }; | |
| 32 | ( | |
| 33 | $(#[doc = $lit:literal])* | |
| 34 | #[clippy::version = $version:literal] | |
| 35 | pub $lint_name:ident, | |
| 36 | restriction, | |
| 37 | $desc:literal | |
| 38 | $(, @eval_always = $eval_always: literal)? | |
| 39 | ) => { | |
| 40 | declare_clippy_lint! {@ | |
| 41 | $(#[doc = $lit])* | |
| 42 | pub $lint_name, Allow, crate::LintCategory::Restriction, $desc, | |
| 43 | Some($version), $version | |
| 44 | $(, $eval_always)? | |
| 45 | } | |
| 46 | }; | |
| 47 | ( | |
| 48 | $(#[doc = $lit:literal])* | |
| 49 | #[clippy::version = $version:literal] | |
| 50 | pub $lint_name:ident, | |
| 51 | style, | |
| 52 | $desc:literal | |
| 53 | $(, @eval_always = $eval_always: literal)? | |
| 54 | ) => { | |
| 55 | declare_clippy_lint! {@ | |
| 56 | $(#[doc = $lit])* | |
| 57 | pub $lint_name, Warn, crate::LintCategory::Style, $desc, | |
| 58 | Some($version), $version | |
| 59 | $(, $eval_always)? | |
| 60 | } | |
| 61 | }; | |
| 62 | ( | |
| 63 | $(#[doc = $lit:literal])* | |
| 64 | #[clippy::version = $version:literal] | |
| 65 | pub $lint_name:ident, | |
| 66 | correctness, | |
| 67 | $desc:literal | |
| 68 | $(, @eval_always = $eval_always: literal)? | |
| 69 | ) => { | |
| 70 | declare_clippy_lint! {@ | |
| 71 | $(#[doc = $lit])* | |
| 72 | pub $lint_name, Deny, crate::LintCategory::Correctness, $desc, | |
| 73 | Some($version), $version | |
| 74 | $(, $eval_always)? | |
| 75 | ||
| 76 | } | |
| 77 | }; | |
| 78 | ( | |
| 79 | $(#[doc = $lit:literal])* | |
| 80 | #[clippy::version = $version:literal] | |
| 81 | pub $lint_name:ident, | |
| 82 | perf, | |
| 83 | $desc:literal | |
| 84 | $(, @eval_always = $eval_always: literal)? | |
| 85 | ) => { | |
| 86 | declare_clippy_lint! {@ | |
| 87 | $(#[doc = $lit])* | |
| 88 | pub $lint_name, Warn, crate::LintCategory::Perf, $desc, | |
| 89 | Some($version), $version | |
| 90 | $(, $eval_always)? | |
| 91 | } | |
| 92 | }; | |
| 93 | ( | |
| 94 | $(#[doc = $lit:literal])* | |
| 95 | #[clippy::version = $version:literal] | |
| 96 | pub $lint_name:ident, | |
| 97 | complexity, | |
| 98 | $desc:literal | |
| 99 | $(, @eval_always = $eval_always: literal)? | |
| 100 | ) => { | |
| 101 | declare_clippy_lint! {@ | |
| 102 | $(#[doc = $lit])* | |
| 103 | pub $lint_name, Warn, crate::LintCategory::Complexity, $desc, | |
| 104 | Some($version), $version | |
| 105 | $(, $eval_always)? | |
| 106 | } | |
| 107 | }; | |
| 108 | ( | |
| 109 | $(#[doc = $lit:literal])* | |
| 110 | #[clippy::version = $version:literal] | |
| 111 | pub $lint_name:ident, | |
| 112 | suspicious, | |
| 113 | $desc:literal | |
| 114 | $(, @eval_always = $eval_always: literal)? | |
| 115 | ) => { | |
| 116 | declare_clippy_lint! {@ | |
| 117 | $(#[doc = $lit])* | |
| 118 | pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc, | |
| 119 | Some($version), $version | |
| 120 | $(, $eval_always)? | |
| 121 | } | |
| 122 | }; | |
| 123 | ( | |
| 124 | $(#[doc = $lit:literal])* | |
| 125 | #[clippy::version = $version:literal] | |
| 126 | pub $lint_name:ident, | |
| 127 | nursery, | |
| 128 | $desc:literal | |
| 129 | $(, @eval_always = $eval_always: literal)? | |
| 130 | ) => { | |
| 131 | declare_clippy_lint! {@ | |
| 132 | $(#[doc = $lit])* | |
| 133 | pub $lint_name, Allow, crate::LintCategory::Nursery, $desc, | |
| 134 | Some($version), $version | |
| 135 | $(, $eval_always)? | |
| 136 | } | |
| 137 | }; | |
| 138 | ( | |
| 139 | $(#[doc = $lit:literal])* | |
| 140 | #[clippy::version = $version:literal] | |
| 141 | pub $lint_name:ident, | |
| 142 | pedantic, | |
| 143 | $desc:literal | |
| 144 | $(, @eval_always = $eval_always: literal)? | |
| 145 | ) => { | |
| 146 | declare_clippy_lint! {@ | |
| 147 | $(#[doc = $lit])* | |
| 148 | pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc, | |
| 149 | Some($version), $version | |
| 150 | $(, $eval_always)? | |
| 151 | } | |
| 152 | }; | |
| 153 | ( | |
| 154 | $(#[doc = $lit:literal])* | |
| 155 | #[clippy::version = $version:literal] | |
| 156 | pub $lint_name:ident, | |
| 157 | cargo, | |
| 158 | $desc:literal | |
| 159 | $(, @eval_always = $eval_always: literal)? | |
| 160 | ) => { | |
| 161 | declare_clippy_lint! {@ | |
| 162 | $(#[doc = $lit])* | |
| 163 | pub $lint_name, Allow, crate::LintCategory::Cargo, $desc, | |
| 164 | Some($version), $version | |
| 165 | $(, $eval_always)? | |
| 166 | } | |
| 167 | }; | |
| 168 | } |
src/tools/clippy/clippy_lints/src/declared_lints.rs+3-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // Use that command to update this file and do not edit by hand. |
| 3 | 3 | // Manual edits will be overwritten. |
| 4 | 4 | |
| 5 | pub static LINTS: &[&crate::LintInfo] = &[ | |
| 5 | pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ | |
| 6 | 6 | crate::absolute_paths::ABSOLUTE_PATHS_INFO, |
| 7 | 7 | crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, |
| 8 | 8 | crate::approx_const::APPROX_CONSTANT_INFO, |
| ... | ... | @@ -112,6 +112,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ |
| 112 | 112 | crate::disallowed_names::DISALLOWED_NAMES_INFO, |
| 113 | 113 | crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO, |
| 114 | 114 | crate::disallowed_types::DISALLOWED_TYPES_INFO, |
| 115 | crate::doc::DOC_BROKEN_LINK_INFO, | |
| 115 | 116 | crate::doc::DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS_INFO, |
| 116 | 117 | crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO, |
| 117 | 118 | crate::doc::DOC_LAZY_CONTINUATION_INFO, |
| ... | ... | @@ -590,6 +591,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ |
| 590 | 591 | crate::operators::IMPOSSIBLE_COMPARISONS_INFO, |
| 591 | 592 | crate::operators::INEFFECTIVE_BIT_MASK_INFO, |
| 592 | 593 | crate::operators::INTEGER_DIVISION_INFO, |
| 594 | crate::operators::MANUAL_IS_MULTIPLE_OF_INFO, | |
| 593 | 595 | crate::operators::MANUAL_MIDPOINT_INFO, |
| 594 | 596 | crate::operators::MISREFACTORED_ASSIGN_OP_INFO, |
| 595 | 597 | crate::operators::MODULO_ARITHMETIC_INFO, |
src/tools/clippy/clippy_lints/src/disallowed_macros.rs+3| ... | ... | @@ -40,6 +40,9 @@ declare_clippy_lint! { |
| 40 | 40 | /// # When using an inline table, can add a `reason` for why the macro |
| 41 | 41 | /// # is disallowed. |
| 42 | 42 | /// { path = "serde::Serialize", reason = "no serializing" }, |
| 43 | /// # This would normally error if the path is incorrect, but with `allow-invalid` = `true`, | |
| 44 | /// # it will be silently ignored | |
| 45 | /// { path = "std::invalid_macro", reason = "use alternative instead", allow-invalid = true } | |
| 43 | 46 | /// ] |
| 44 | 47 | /// ``` |
| 45 | 48 | /// ```no_run |
src/tools/clippy/clippy_lints/src/disallowed_methods.rs+3| ... | ... | @@ -34,6 +34,9 @@ declare_clippy_lint! { |
| 34 | 34 | /// { path = "std::vec::Vec::leak", reason = "no leaking memory" }, |
| 35 | 35 | /// # Can also add a `replacement` that will be offered as a suggestion. |
| 36 | 36 | /// { path = "std::sync::Mutex::new", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex::new" }, |
| 37 | /// # This would normally error if the path is incorrect, but with `allow-invalid` = `true`, | |
| 38 | /// # it will be silently ignored | |
| 39 | /// { path = "std::fs::InvalidPath", reason = "use alternative instead", allow-invalid = true }, | |
| 37 | 40 | /// ] |
| 38 | 41 | /// ``` |
| 39 | 42 | /// |
src/tools/clippy/clippy_lints/src/disallowed_types.rs+3| ... | ... | @@ -35,6 +35,9 @@ declare_clippy_lint! { |
| 35 | 35 | /// { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" }, |
| 36 | 36 | /// # Can also add a `replacement` that will be offered as a suggestion. |
| 37 | 37 | /// { path = "std::sync::Mutex", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex" }, |
| 38 | /// # This would normally error if the path is incorrect, but with `allow-invalid` = `true`, | |
| 39 | /// # it will be silently ignored | |
| 40 | /// { path = "std::invalid::Type", reason = "use alternative instead", allow-invalid = true } | |
| 38 | 41 | /// ] |
| 39 | 42 | /// ``` |
| 40 | 43 | /// |
src/tools/clippy/clippy_lints/src/doc/broken_link.rs created+83| ... | ... | @@ -0,0 +1,83 @@ |
| 1 | use clippy_utils::diagnostics::span_lint; | |
| 2 | use pulldown_cmark::BrokenLink as PullDownBrokenLink; | |
| 3 | use rustc_lint::LateContext; | |
| 4 | use rustc_resolve::rustdoc::{DocFragment, source_span_for_markdown_range}; | |
| 5 | use rustc_span::{BytePos, Pos, Span}; | |
| 6 | ||
| 7 | use super::DOC_BROKEN_LINK; | |
| 8 | ||
| 9 | /// Scan and report broken link on documents. | |
| 10 | /// It ignores false positives detected by `pulldown_cmark`, and only | |
| 11 | /// warns users when the broken link is consider a URL. | |
| 12 | // NOTE: We don't check these other cases because | |
| 13 | // rustdoc itself will check and warn about it: | |
| 14 | // - When a link url is broken across multiple lines in the URL path part | |
| 15 | // - When a link tag is missing the close parenthesis character at the end. | |
| 16 | // - When a link has whitespace within the url link. | |
| 17 | pub fn check(cx: &LateContext<'_>, bl: &PullDownBrokenLink<'_>, doc: &str, fragments: &[DocFragment]) { | |
| 18 | warn_if_broken_link(cx, bl, doc, fragments); | |
| 19 | } | |
| 20 | ||
| 21 | fn warn_if_broken_link(cx: &LateContext<'_>, bl: &PullDownBrokenLink<'_>, doc: &str, fragments: &[DocFragment]) { | |
| 22 | if let Some((span, _)) = source_span_for_markdown_range(cx.tcx, doc, &bl.span, fragments) { | |
| 23 | let mut len = 0; | |
| 24 | ||
| 25 | // grab raw link data | |
| 26 | let (_, raw_link) = doc.split_at(bl.span.start); | |
| 27 | ||
| 28 | // strip off link text part | |
| 29 | let raw_link = match raw_link.split_once(']') { | |
| 30 | None => return, | |
| 31 | Some((prefix, suffix)) => { | |
| 32 | len += prefix.len() + 1; | |
| 33 | suffix | |
| 34 | }, | |
| 35 | }; | |
| 36 | ||
| 37 | let raw_link = match raw_link.split_once('(') { | |
| 38 | None => return, | |
| 39 | Some((prefix, suffix)) => { | |
| 40 | if !prefix.is_empty() { | |
| 41 | // there is text between ']' and '(' chars, so it is not a valid link | |
| 42 | return; | |
| 43 | } | |
| 44 | len += prefix.len() + 1; | |
| 45 | suffix | |
| 46 | }, | |
| 47 | }; | |
| 48 | ||
| 49 | if raw_link.starts_with("(http") { | |
| 50 | // reduce chances of false positive reports | |
| 51 | // by limiting this checking only to http/https links. | |
| 52 | return; | |
| 53 | } | |
| 54 | ||
| 55 | for c in raw_link.chars() { | |
| 56 | if c == ')' { | |
| 57 | // it is a valid link | |
| 58 | return; | |
| 59 | } | |
| 60 | ||
| 61 | if c == '\n' { | |
| 62 | report_broken_link(cx, span, len); | |
| 63 | break; | |
| 64 | } | |
| 65 | ||
| 66 | len += 1; | |
| 67 | } | |
| 68 | } | |
| 69 | } | |
| 70 | ||
| 71 | fn report_broken_link(cx: &LateContext<'_>, frag_span: Span, offset: usize) { | |
| 72 | let start = frag_span.lo(); | |
| 73 | let end = start + BytePos::from_usize(offset); | |
| 74 | ||
| 75 | let span = Span::new(start, end, frag_span.ctxt(), frag_span.parent()); | |
| 76 | ||
| 77 | span_lint( | |
| 78 | cx, | |
| 79 | DOC_BROKEN_LINK, | |
| 80 | span, | |
| 81 | "possible broken doc link: broken across multiple lines", | |
| 82 | ); | |
| 83 | } |
src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs+1-5| ... | ... | @@ -49,11 +49,7 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F |
| 49 | 49 | .filter(|attr| attr.span().overlaps(this_fragment.span)) |
| 50 | 50 | .rev() |
| 51 | 51 | .find_map(|attr| { |
| 52 | Some(( | |
| 53 | attr, | |
| 54 | attr.doc_str_and_comment_kind()?, | |
| 55 | attr.doc_resolution_scope()?, | |
| 56 | )) | |
| 52 | Some((attr, attr.doc_str_and_comment_kind()?, attr.doc_resolution_scope()?)) | |
| 57 | 53 | }) |
| 58 | 54 | .unwrap(); |
| 59 | 55 | let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) { |
src/tools/clippy/clippy_lints/src/doc/mod.rs+43-7| ... | ... | @@ -24,6 +24,7 @@ use rustc_span::edition::Edition; |
| 24 | 24 | use std::ops::Range; |
| 25 | 25 | use url::Url; |
| 26 | 26 | |
| 27 | mod broken_link; | |
| 27 | 28 | mod doc_comment_double_space_linebreaks; |
| 28 | 29 | mod doc_suspicious_footnotes; |
| 29 | 30 | mod include_in_doc_without_cfg; |
| ... | ... | @@ -292,6 +293,34 @@ declare_clippy_lint! { |
| 292 | 293 | "possible typo for an intra-doc link" |
| 293 | 294 | } |
| 294 | 295 | |
| 296 | declare_clippy_lint! { | |
| 297 | /// ### What it does | |
| 298 | /// Checks the doc comments have unbroken links, mostly caused | |
| 299 | /// by bad formatted links such as broken across multiple lines. | |
| 300 | /// | |
| 301 | /// ### Why is this bad? | |
| 302 | /// Because documentation generated by rustdoc will be broken | |
| 303 | /// since expected links won't be links and just text. | |
| 304 | /// | |
| 305 | /// ### Examples | |
| 306 | /// This link is broken: | |
| 307 | /// ```no_run | |
| 308 | /// /// [example of a bad link](https:// | |
| 309 | /// /// github.com/rust-lang/rust-clippy/) | |
| 310 | /// pub fn do_something() {} | |
| 311 | /// ``` | |
| 312 | /// | |
| 313 | /// It shouldn't be broken across multiple lines to work: | |
| 314 | /// ```no_run | |
| 315 | /// /// [example of a good link](https://github.com/rust-lang/rust-clippy/) | |
| 316 | /// pub fn do_something() {} | |
| 317 | /// ``` | |
| 318 | #[clippy::version = "1.84.0"] | |
| 319 | pub DOC_BROKEN_LINK, | |
| 320 | pedantic, | |
| 321 | "broken document link" | |
| 322 | } | |
| 323 | ||
| 295 | 324 | declare_clippy_lint! { |
| 296 | 325 | /// ### What it does |
| 297 | 326 | /// Checks for the doc comments of publicly visible |
| ... | ... | @@ -656,6 +685,7 @@ impl Documentation { |
| 656 | 685 | impl_lint_pass!(Documentation => [ |
| 657 | 686 | DOC_LINK_CODE, |
| 658 | 687 | DOC_LINK_WITH_QUOTES, |
| 688 | DOC_BROKEN_LINK, | |
| 659 | 689 | DOC_MARKDOWN, |
| 660 | 690 | DOC_NESTED_REFDEFS, |
| 661 | 691 | MISSING_SAFETY_DOC, |
| ... | ... | @@ -786,9 +816,9 @@ struct DocHeaders { |
| 786 | 816 | /// back in the various late lint pass methods if they need the final doc headers, like "Safety" or |
| 787 | 817 | /// "Panics" sections. |
| 788 | 818 | fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> { |
| 789 | /// We don't want the parser to choke on intra doc links. Since we don't | |
| 790 | /// actually care about rendering them, just pretend that all broken links | |
| 791 | /// point to a fake address. | |
| 819 | // We don't want the parser to choke on intra doc links. Since we don't | |
| 820 | // actually care about rendering them, just pretend that all broken links | |
| 821 | // point to a fake address. | |
| 792 | 822 | #[expect(clippy::unnecessary_wraps)] // we're following a type signature |
| 793 | 823 | fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> { |
| 794 | 824 | Some(("fake".into(), "fake".into())) |
| ... | ... | @@ -828,14 +858,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[ |
| 828 | 858 | return Some(DocHeaders::default()); |
| 829 | 859 | } |
| 830 | 860 | |
| 831 | let mut cb = fake_broken_link_callback; | |
| 832 | ||
| 833 | 861 | check_for_code_clusters( |
| 834 | 862 | cx, |
| 835 | 863 | pulldown_cmark::Parser::new_with_broken_link_callback( |
| 836 | 864 | &doc, |
| 837 | 865 | main_body_opts() - Options::ENABLE_SMART_PUNCTUATION, |
| 838 | Some(&mut cb), | |
| 866 | Some(&mut fake_broken_link_callback), | |
| 839 | 867 | ) |
| 840 | 868 | .into_offset_iter(), |
| 841 | 869 | &doc, |
| ... | ... | @@ -845,9 +873,17 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[ |
| 845 | 873 | }, |
| 846 | 874 | ); |
| 847 | 875 | |
| 876 | // NOTE: check_doc uses it own cb function, | |
| 877 | // to avoid causing duplicated diagnostics for the broken link checker. | |
| 878 | let mut full_fake_broken_link_callback = |bl: BrokenLink<'_>| -> Option<(CowStr<'_>, CowStr<'_>)> { | |
| 879 | broken_link::check(cx, &bl, &doc, &fragments); | |
| 880 | Some(("fake".into(), "fake".into())) | |
| 881 | }; | |
| 882 | ||
| 848 | 883 | // disable smart punctuation to pick up ['link'] more easily |
| 849 | 884 | let opts = main_body_opts() - Options::ENABLE_SMART_PUNCTUATION; |
| 850 | let parser = pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut cb)); | |
| 885 | let parser = | |
| 886 | pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut full_fake_broken_link_callback)); | |
| 851 | 887 | |
| 852 | 888 | Some(check_doc( |
| 853 | 889 | cx, |
src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs+24-3| ... | ... | @@ -71,6 +71,7 @@ pub fn check( |
| 71 | 71 | if !ignore { |
| 72 | 72 | get_test_spans(&item, *ident, &mut test_attr_spans); |
| 73 | 73 | } |
| 74 | ||
| 74 | 75 | let is_async = matches!(sig.header.coroutine_kind, Some(CoroutineKind::Async { .. })); |
| 75 | 76 | let returns_nothing = match &sig.decl.output { |
| 76 | 77 | FnRetTy::Default(..) => true, |
| ... | ... | @@ -89,9 +90,14 @@ pub fn check( |
| 89 | 90 | // Another function was found; this case is ignored for needless_doctest_main |
| 90 | 91 | ItemKind::Fn(fn_) => { |
| 91 | 92 | eligible = false; |
| 92 | if !ignore { | |
| 93 | get_test_spans(&item, fn_.ident, &mut test_attr_spans); | |
| 93 | if ignore { | |
| 94 | // If ignore is active invalidating one lint, | |
| 95 | // and we already found another function thus | |
| 96 | // invalidating the other one, we have no | |
| 97 | // business continuing. | |
| 98 | return (false, test_attr_spans); | |
| 94 | 99 | } |
| 100 | get_test_spans(&item, fn_.ident, &mut test_attr_spans); | |
| 95 | 101 | }, |
| 96 | 102 | // Tests with one of these items are ignored |
| 97 | 103 | ItemKind::Static(..) |
| ... | ... | @@ -104,7 +110,10 @@ pub fn check( |
| 104 | 110 | }, |
| 105 | 111 | Ok(None) => break, |
| 106 | 112 | Err(e) => { |
| 107 | e.cancel(); | |
| 113 | // See issue #15041. When calling `.cancel()` on the `Diag`, Clippy will unexpectedly panic | |
| 114 | // when the `Diag` is unwinded. Meanwhile, we can just call `.emit()`, since the `DiagCtxt` | |
| 115 | // is just a sink, nothing will be printed. | |
| 116 | e.emit(); | |
| 108 | 117 | return (false, test_attr_spans); |
| 109 | 118 | }, |
| 110 | 119 | } |
| ... | ... | @@ -119,6 +128,18 @@ pub fn check( |
| 119 | 128 | |
| 120 | 129 | let trailing_whitespace = text.len() - text.trim_end().len(); |
| 121 | 130 | |
| 131 | // We currently only test for "fn main". Checking for the real | |
| 132 | // entrypoint (with tcx.entry_fn(())) in each block would be unnecessarily | |
| 133 | // expensive, as those are probably intended and relevant. Same goes for | |
| 134 | // macros and other weird ways of declaring a main function. | |
| 135 | // | |
| 136 | // Also, as we only check for attribute names and don't do macro expansion, | |
| 137 | // we can check only for #[test] | |
| 138 | ||
| 139 | if !((text.contains("main") && text.contains("fn")) || text.contains("#[test]")) { | |
| 140 | return; | |
| 141 | } | |
| 142 | ||
| 122 | 143 | // Because of the global session, we need to create a new session in a different thread with |
| 123 | 144 | // the edition we need. |
| 124 | 145 | let text = text.to_owned(); |
src/tools/clippy/clippy_lints/src/empty_line_after.rs+57-7| ... | ... | @@ -10,7 +10,7 @@ use rustc_errors::{Applicability, Diag, SuggestionStyle}; |
| 10 | 10 | use rustc_lexer::TokenKind; |
| 11 | 11 | use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; |
| 12 | 12 | use rustc_session::impl_lint_pass; |
| 13 | use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, kw}; | |
| 13 | use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, kw, sym}; | |
| 14 | 14 | |
| 15 | 15 | declare_clippy_lint! { |
| 16 | 16 | /// ### What it does |
| ... | ... | @@ -129,10 +129,55 @@ struct Stop { |
| 129 | 129 | kind: StopKind, |
| 130 | 130 | first: usize, |
| 131 | 131 | last: usize, |
| 132 | name: Option<Symbol>, | |
| 132 | 133 | } |
| 133 | 134 | |
| 134 | 135 | impl Stop { |
| 135 | fn convert_to_inner(&self) -> (Span, String) { | |
| 136 | fn is_outer_attr_only(&self) -> bool { | |
| 137 | let Some(name) = self.name else { | |
| 138 | return false; | |
| 139 | }; | |
| 140 | // Check if the attribute only has effect when as an outer attribute | |
| 141 | // The below attributes are collected from the builtin attributes of The Rust Reference | |
| 142 | // https://doc.rust-lang.org/reference/attributes.html#r-attributes.builtin | |
| 143 | // And the comments below are from compiler errors and warnings | |
| 144 | matches!( | |
| 145 | name, | |
| 146 | // Cannot be used at crate level | |
| 147 | sym::repr | sym::test | sym::derive | sym::automatically_derived | sym::path | sym::global_allocator | | |
| 148 | // Only has an effect on macro definitions | |
| 149 | sym::macro_export | | |
| 150 | // Only be applied to trait definitions | |
| 151 | sym::on_unimplemented | | |
| 152 | // Only be placed on trait implementations | |
| 153 | sym::do_not_recommend | | |
| 154 | // Only has an effect on items | |
| 155 | sym::ignore | sym::should_panic | sym::proc_macro | sym::proc_macro_derive | sym::proc_macro_attribute | | |
| 156 | // Has no effect when applied to a module | |
| 157 | sym::must_use | | |
| 158 | // Should be applied to a foreign function or static | |
| 159 | sym::link_name | sym::link_ordinal | sym::link_section | | |
| 160 | // Should be applied to an `extern crate` item | |
| 161 | sym::no_link | | |
| 162 | // Should be applied to a free function, impl method or static | |
| 163 | sym::export_name | sym::no_mangle | | |
| 164 | // Should be applied to a `static` variable | |
| 165 | sym::used | | |
| 166 | // Should be applied to function or closure | |
| 167 | sym::inline | | |
| 168 | // Should be applied to a function definition | |
| 169 | sym::cold | sym::target_feature | sym::track_caller | sym::instruction_set | | |
| 170 | // Should be applied to a struct or enum | |
| 171 | sym::non_exhaustive | | |
| 172 | // Note: No any warning when it as an inner attribute, but it has no effect | |
| 173 | sym::panic_handler | |
| 174 | ) | |
| 175 | } | |
| 176 | ||
| 177 | fn convert_to_inner(&self) -> Option<(Span, String)> { | |
| 178 | if self.is_outer_attr_only() { | |
| 179 | return None; | |
| 180 | } | |
| 136 | 181 | let inner = match self.kind { |
| 137 | 182 | // #![...] |
| 138 | 183 | StopKind::Attr => InnerSpan::new(1, 1), |
| ... | ... | @@ -140,7 +185,7 @@ impl Stop { |
| 140 | 185 | // ^ ^ |
| 141 | 186 | StopKind::Doc(_) => InnerSpan::new(2, 3), |
| 142 | 187 | }; |
| 143 | (self.span.from_inner(inner), "!".into()) | |
| 188 | Some((self.span.from_inner(inner), "!".into())) | |
| 144 | 189 | } |
| 145 | 190 | |
| 146 | 191 | fn comment_out(&self, cx: &EarlyContext<'_>, suggestions: &mut Vec<(Span, String)>) { |
| ... | ... | @@ -177,6 +222,7 @@ impl Stop { |
| 177 | 222 | }, |
| 178 | 223 | first: file.lookup_line(file.relative_position(lo))?, |
| 179 | 224 | last: file.lookup_line(file.relative_position(hi))?, |
| 225 | name: attr.name(), | |
| 180 | 226 | }) |
| 181 | 227 | } |
| 182 | 228 | } |
| ... | ... | @@ -356,6 +402,12 @@ impl EmptyLineAfter { |
| 356 | 402 | if let Some(parent) = self.items.iter().rev().nth(1) |
| 357 | 403 | && (parent.kind == "module" || parent.kind == "crate") |
| 358 | 404 | && parent.mod_items == Some(id) |
| 405 | && let suggestions = gaps | |
| 406 | .iter() | |
| 407 | .flat_map(|gap| gap.prev_chunk) | |
| 408 | .filter_map(Stop::convert_to_inner) | |
| 409 | .collect::<Vec<_>>() | |
| 410 | && !suggestions.is_empty() | |
| 359 | 411 | { |
| 360 | 412 | let desc = if parent.kind == "module" { |
| 361 | 413 | "parent module" |
| ... | ... | @@ -367,10 +419,7 @@ impl EmptyLineAfter { |
| 367 | 419 | StopKind::Attr => format!("if the attribute should apply to the {desc} use an inner attribute"), |
| 368 | 420 | StopKind::Doc(_) => format!("if the comment should document the {desc} use an inner doc comment"), |
| 369 | 421 | }, |
| 370 | gaps.iter() | |
| 371 | .flat_map(|gap| gap.prev_chunk) | |
| 372 | .map(Stop::convert_to_inner) | |
| 373 | .collect(), | |
| 422 | suggestions, | |
| 374 | 423 | Applicability::MaybeIncorrect, |
| 375 | 424 | ); |
| 376 | 425 | } |
| ... | ... | @@ -425,6 +474,7 @@ impl EmptyLineAfter { |
| 425 | 474 | first: line.line, |
| 426 | 475 | // last doesn't need to be accurate here, we don't compare it with anything |
| 427 | 476 | last: line.line, |
| 477 | name: None, | |
| 428 | 478 | }); |
| 429 | 479 | } |
| 430 | 480 |
src/tools/clippy/clippy_lints/src/eta_reduction.rs+53-39| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; | |
| 1 | use clippy_utils::diagnostics::span_lint_hir_and_then; | |
| 2 | 2 | use clippy_utils::higher::VecArgs; |
| 3 | 3 | use clippy_utils::source::{snippet_opt, snippet_with_applicability}; |
| 4 | 4 | use clippy_utils::ty::get_type_diagnostic_name; |
| ... | ... | @@ -109,14 +109,20 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx |
| 109 | 109 | { |
| 110 | 110 | let vec_crate = if is_no_std_crate(cx) { "alloc" } else { "std" }; |
| 111 | 111 | // replace `|| vec![]` with `Vec::new` |
| 112 | span_lint_and_sugg( | |
| 112 | span_lint_hir_and_then( | |
| 113 | 113 | cx, |
| 114 | 114 | REDUNDANT_CLOSURE, |
| 115 | expr.hir_id, | |
| 115 | 116 | expr.span, |
| 116 | 117 | "redundant closure", |
| 117 | "replace the closure with `Vec::new`", | |
| 118 | format!("{vec_crate}::vec::Vec::new"), | |
| 119 | Applicability::MachineApplicable, | |
| 118 | |diag| { | |
| 119 | diag.span_suggestion( | |
| 120 | expr.span, | |
| 121 | "replace the closure with `Vec::new`", | |
| 122 | format!("{vec_crate}::vec::Vec::new"), | |
| 123 | Applicability::MachineApplicable, | |
| 124 | ); | |
| 125 | }, | |
| 120 | 126 | ); |
| 121 | 127 | } |
| 122 | 128 | // skip `foo(|| macro!())` |
| ... | ... | @@ -198,41 +204,48 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx |
| 198 | 204 | // For now ignore all callee types which reference a type parameter. |
| 199 | 205 | && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_))) |
| 200 | 206 | { |
| 201 | span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { | |
| 202 | if let Some(mut snippet) = snippet_opt(cx, callee.span) { | |
| 203 | if path_to_local(callee).is_some_and(|l| { | |
| 204 | // FIXME: Do we really need this `local_used_in` check? | |
| 205 | // Isn't it checking something like... `callee(callee)`? | |
| 206 | // If somehow this check is needed, add some test for it, | |
| 207 | // 'cuz currently nothing changes after deleting this check. | |
| 208 | local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) | |
| 209 | }) { | |
| 210 | match cx | |
| 211 | .tcx | |
| 212 | .infer_ctxt() | |
| 213 | .build(cx.typing_mode()) | |
| 214 | .err_ctxt() | |
| 215 | .type_implements_fn_trait( | |
| 216 | cx.param_env, | |
| 217 | Binder::bind_with_vars(callee_ty_adjusted, List::empty()), | |
| 218 | ty::PredicatePolarity::Positive, | |
| 219 | ) { | |
| 220 | // Mutable closure is used after current expr; we cannot consume it. | |
| 221 | Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"), | |
| 222 | Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => { | |
| 223 | snippet = format!("&{snippet}"); | |
| 224 | }, | |
| 225 | _ => (), | |
| 207 | span_lint_hir_and_then( | |
| 208 | cx, | |
| 209 | REDUNDANT_CLOSURE, | |
| 210 | expr.hir_id, | |
| 211 | expr.span, | |
| 212 | "redundant closure", | |
| 213 | |diag| { | |
| 214 | if let Some(mut snippet) = snippet_opt(cx, callee.span) { | |
| 215 | if path_to_local(callee).is_some_and(|l| { | |
| 216 | // FIXME: Do we really need this `local_used_in` check? | |
| 217 | // Isn't it checking something like... `callee(callee)`? | |
| 218 | // If somehow this check is needed, add some test for it, | |
| 219 | // 'cuz currently nothing changes after deleting this check. | |
| 220 | local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) | |
| 221 | }) { | |
| 222 | match cx | |
| 223 | .tcx | |
| 224 | .infer_ctxt() | |
| 225 | .build(cx.typing_mode()) | |
| 226 | .err_ctxt() | |
| 227 | .type_implements_fn_trait( | |
| 228 | cx.param_env, | |
| 229 | Binder::bind_with_vars(callee_ty_adjusted, List::empty()), | |
| 230 | ty::PredicatePolarity::Positive, | |
| 231 | ) { | |
| 232 | // Mutable closure is used after current expr; we cannot consume it. | |
| 233 | Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"), | |
| 234 | Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => { | |
| 235 | snippet = format!("&{snippet}"); | |
| 236 | }, | |
| 237 | _ => (), | |
| 238 | } | |
| 226 | 239 | } |
| 240 | diag.span_suggestion( | |
| 241 | expr.span, | |
| 242 | "replace the closure with the function itself", | |
| 243 | snippet, | |
| 244 | Applicability::MachineApplicable, | |
| 245 | ); | |
| 227 | 246 | } |
| 228 | diag.span_suggestion( | |
| 229 | expr.span, | |
| 230 | "replace the closure with the function itself", | |
| 231 | snippet, | |
| 232 | Applicability::MachineApplicable, | |
| 233 | ); | |
| 234 | } | |
| 235 | }); | |
| 247 | }, | |
| 248 | ); | |
| 236 | 249 | } |
| 237 | 250 | }, |
| 238 | 251 | ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => { |
| ... | ... | @@ -245,9 +258,10 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx |
| 245 | 258 | Some(span) => format!("::{}", snippet_with_applicability(cx, span, "<..>", &mut app)), |
| 246 | 259 | None => String::new(), |
| 247 | 260 | }; |
| 248 | span_lint_and_then( | |
| 261 | span_lint_hir_and_then( | |
| 249 | 262 | cx, |
| 250 | 263 | REDUNDANT_CLOSURE_FOR_METHOD_CALLS, |
| 264 | expr.hir_id, | |
| 251 | 265 | expr.span, |
| 252 | 266 | "redundant closure", |
| 253 | 267 | |diag| { |
src/tools/clippy/clippy_lints/src/exhaustive_items.rs+1-1| ... | ... | @@ -76,7 +76,7 @@ impl LateLintPass<'_> for ExhaustiveItems { |
| 76 | 76 | "exported enums should not be exhaustive", |
| 77 | 77 | [].as_slice(), |
| 78 | 78 | ), |
| 79 | ItemKind::Struct(_, _, v) => ( | |
| 79 | ItemKind::Struct(_, _, v) if v.fields().iter().all(|f| f.default.is_none()) => ( | |
| 80 | 80 | EXHAUSTIVE_STRUCTS, |
| 81 | 81 | "exported structs should not be exhaustive", |
| 82 | 82 | v.fields(), |
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs+1-2| ... | ... | @@ -5,14 +5,13 @@ use clippy_utils::{ |
| 5 | 5 | eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate, |
| 6 | 6 | numeric_literal, peel_blocks, sugg, sym, |
| 7 | 7 | }; |
| 8 | use rustc_ast::ast; | |
| 8 | 9 | use rustc_errors::Applicability; |
| 9 | 10 | use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; |
| 10 | 11 | use rustc_lint::{LateContext, LateLintPass}; |
| 11 | 12 | use rustc_middle::ty; |
| 12 | 13 | use rustc_session::declare_lint_pass; |
| 13 | 14 | use rustc_span::source_map::Spanned; |
| 14 | ||
| 15 | use rustc_ast::ast; | |
| 16 | 15 | use std::f32::consts as f32_consts; |
| 17 | 16 | use std::f64::consts as f64_consts; |
| 18 | 17 | use sugg::Sugg; |
src/tools/clippy/clippy_lints/src/functions/must_use.rs+40-13| ... | ... | @@ -14,9 +14,9 @@ use clippy_utils::source::SpanRangeExt; |
| 14 | 14 | use clippy_utils::ty::is_must_use_ty; |
| 15 | 15 | use clippy_utils::visitors::for_each_expr_without_closures; |
| 16 | 16 | use clippy_utils::{return_ty, trait_ref_of_method}; |
| 17 | use rustc_trait_selection::error_reporting::InferCtxtErrorExt; | |
| 18 | use rustc_span::Symbol; | |
| 19 | 17 | use rustc_attr_data_structures::{AttributeKind, find_attr}; |
| 18 | use rustc_span::Symbol; | |
| 19 | use rustc_trait_selection::error_reporting::InferCtxtErrorExt; | |
| 20 | 20 | |
| 21 | 21 | use core::ops::ControlFlow; |
| 22 | 22 | |
| ... | ... | @@ -34,7 +34,17 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> |
| 34 | 34 | let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); |
| 35 | 35 | let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); |
| 36 | 36 | if let Some((attr_span, reason)) = attr { |
| 37 | check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); | |
| 37 | check_needless_must_use( | |
| 38 | cx, | |
| 39 | sig.decl, | |
| 40 | item.owner_id, | |
| 41 | item.span, | |
| 42 | fn_header_span, | |
| 43 | *attr_span, | |
| 44 | *reason, | |
| 45 | attrs, | |
| 46 | sig, | |
| 47 | ); | |
| 38 | 48 | } else if is_public && !is_proc_macro(attrs) && !find_attr!(attrs, AttributeKind::NoMangle(..)) { |
| 39 | 49 | check_must_use_candidate( |
| 40 | 50 | cx, |
| ... | ... | @@ -54,9 +64,20 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp |
| 54 | 64 | let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); |
| 55 | 65 | let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); |
| 56 | 66 | let attrs = cx.tcx.hir_attrs(item.hir_id()); |
| 57 | let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); | |
| 67 | let attr = | |
| 68 | find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); | |
| 58 | 69 | if let Some((attr_span, reason)) = attr { |
| 59 | check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); | |
| 70 | check_needless_must_use( | |
| 71 | cx, | |
| 72 | sig.decl, | |
| 73 | item.owner_id, | |
| 74 | item.span, | |
| 75 | fn_header_span, | |
| 76 | *attr_span, | |
| 77 | *reason, | |
| 78 | attrs, | |
| 79 | sig, | |
| 80 | ); | |
| 60 | 81 | } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() { |
| 61 | 82 | check_must_use_candidate( |
| 62 | 83 | cx, |
| ... | ... | @@ -77,9 +98,20 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr |
| 77 | 98 | let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); |
| 78 | 99 | |
| 79 | 100 | let attrs = cx.tcx.hir_attrs(item.hir_id()); |
| 80 | let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); | |
| 101 | let attr = | |
| 102 | find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); | |
| 81 | 103 | if let Some((attr_span, reason)) = attr { |
| 82 | check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); | |
| 104 | check_needless_must_use( | |
| 105 | cx, | |
| 106 | sig.decl, | |
| 107 | item.owner_id, | |
| 108 | item.span, | |
| 109 | fn_header_span, | |
| 110 | *attr_span, | |
| 111 | *reason, | |
| 112 | attrs, | |
| 113 | sig, | |
| 114 | ); | |
| 83 | 115 | } else if let hir::TraitFn::Provided(eid) = *eid { |
| 84 | 116 | let body = cx.tcx.hir_body(eid); |
| 85 | 117 | if attr.is_none() && is_public && !is_proc_macro(attrs) { |
| ... | ... | @@ -121,12 +153,7 @@ fn check_needless_must_use( |
| 121 | 153 | fn_header_span, |
| 122 | 154 | "this unit-returning function has a `#[must_use]` attribute", |
| 123 | 155 | |diag| { |
| 124 | diag.span_suggestion( | |
| 125 | attr_span, | |
| 126 | "remove the attribute", | |
| 127 | "", | |
| 128 | Applicability::MachineApplicable, | |
| 129 | ); | |
| 156 | diag.span_suggestion(attr_span, "remove the attribute", "", Applicability::MachineApplicable); | |
| 130 | 157 | }, |
| 131 | 158 | ); |
| 132 | 159 | } else { |
src/tools/clippy/clippy_lints/src/if_not_else.rs+2-9| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | use clippy_utils::consts::{ConstEvalCtxt, Constant}; | |
| 1 | use clippy_utils::consts::is_zero_integer_const; | |
| 2 | 2 | use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; |
| 3 | 3 | use clippy_utils::is_else_clause; |
| 4 | 4 | use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet}; |
| ... | ... | @@ -48,13 +48,6 @@ declare_clippy_lint! { |
| 48 | 48 | |
| 49 | 49 | declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]); |
| 50 | 50 | |
| 51 | fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool { | |
| 52 | if let Some(value) = ConstEvalCtxt::new(cx).eval_simple(expr) { | |
| 53 | return Constant::Int(0) == value; | |
| 54 | } | |
| 55 | false | |
| 56 | } | |
| 57 | ||
| 58 | 51 | impl LateLintPass<'_> for IfNotElse { |
| 59 | 52 | fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { |
| 60 | 53 | if let ExprKind::If(cond, cond_inner, Some(els)) = e.kind |
| ... | ... | @@ -68,7 +61,7 @@ impl LateLintPass<'_> for IfNotElse { |
| 68 | 61 | ), |
| 69 | 62 | // Don't lint on `… != 0`, as these are likely to be bit tests. |
| 70 | 63 | // For example, `if foo & 0x0F00 != 0 { … } else { … }` is already in the "proper" order. |
| 71 | ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_const(rhs, cx) => ( | |
| 64 | ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_integer_const(cx, rhs) => ( | |
| 72 | 65 | "unnecessary `!=` operation", |
| 73 | 66 | "change to `==` and swap the blocks of the `if`/`else`", |
| 74 | 67 | ), |
src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs+5-5| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::sugg::DiagExt; |
| 3 | use rustc_attr_data_structures::{find_attr, AttributeKind}; | |
| 3 | use rustc_attr_data_structures::{AttributeKind, find_attr}; | |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; |
| 6 | 6 | use rustc_lint::{LateContext, LateLintPass}; |
| ... | ... | @@ -33,10 +33,10 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { |
| 33 | 33 | fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { |
| 34 | 34 | if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind |
| 35 | 35 | && let Some(attr_span) = find_attr!(cx |
| 36 | .tcx | |
| 37 | .hir_attrs(item.hir_id()), | |
| 38 | AttributeKind::Inline(_, span) => *span | |
| 39 | ) | |
| 36 | .tcx | |
| 37 | .hir_attrs(item.hir_id()), | |
| 38 | AttributeKind::Inline(_, span) => *span | |
| 39 | ) | |
| 40 | 40 | { |
| 41 | 41 | span_lint_and_then( |
| 42 | 42 | cx, |
src/tools/clippy/clippy_lints/src/lib.rs+4-122| ... | ... | @@ -59,10 +59,10 @@ extern crate smallvec; |
| 59 | 59 | extern crate thin_vec; |
| 60 | 60 | |
| 61 | 61 | #[macro_use] |
| 62 | mod declare_clippy_lint; | |
| 62 | extern crate clippy_utils; | |
| 63 | 63 | |
| 64 | 64 | #[macro_use] |
| 65 | extern crate clippy_utils; | |
| 65 | extern crate declare_clippy_lint; | |
| 66 | 66 | |
| 67 | 67 | mod utils; |
| 68 | 68 | |
| ... | ... | @@ -411,108 +411,9 @@ mod zombie_processes; |
| 411 | 411 | use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; |
| 412 | 412 | use clippy_utils::macros::FormatArgsStorage; |
| 413 | 413 | use rustc_data_structures::fx::FxHashSet; |
| 414 | use rustc_lint::{Lint, LintId}; | |
| 414 | use rustc_lint::Lint; | |
| 415 | 415 | use utils::attr_collector::{AttrCollector, AttrStorage}; |
| 416 | 416 | |
| 417 | #[derive(Default)] | |
| 418 | struct RegistrationGroups { | |
| 419 | all: Vec<LintId>, | |
| 420 | cargo: Vec<LintId>, | |
| 421 | complexity: Vec<LintId>, | |
| 422 | correctness: Vec<LintId>, | |
| 423 | nursery: Vec<LintId>, | |
| 424 | pedantic: Vec<LintId>, | |
| 425 | perf: Vec<LintId>, | |
| 426 | restriction: Vec<LintId>, | |
| 427 | style: Vec<LintId>, | |
| 428 | suspicious: Vec<LintId>, | |
| 429 | } | |
| 430 | ||
| 431 | impl RegistrationGroups { | |
| 432 | #[rustfmt::skip] | |
| 433 | fn register(self, store: &mut rustc_lint::LintStore) { | |
| 434 | store.register_group(true, "clippy::all", Some("clippy_all"), self.all); | |
| 435 | store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo); | |
| 436 | store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity); | |
| 437 | store.register_group(true, "clippy::correctness", Some("clippy_correctness"), self.correctness); | |
| 438 | store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery); | |
| 439 | store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic); | |
| 440 | store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf); | |
| 441 | store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction); | |
| 442 | store.register_group(true, "clippy::style", Some("clippy_style"), self.style); | |
| 443 | store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious); | |
| 444 | } | |
| 445 | } | |
| 446 | ||
| 447 | #[derive(Copy, Clone, Debug)] | |
| 448 | pub(crate) enum LintCategory { | |
| 449 | Cargo, | |
| 450 | Complexity, | |
| 451 | Correctness, | |
| 452 | Nursery, | |
| 453 | Pedantic, | |
| 454 | Perf, | |
| 455 | Restriction, | |
| 456 | Style, | |
| 457 | Suspicious, | |
| 458 | } | |
| 459 | ||
| 460 | #[allow(clippy::enum_glob_use)] | |
| 461 | use LintCategory::*; | |
| 462 | ||
| 463 | impl LintCategory { | |
| 464 | fn is_all(self) -> bool { | |
| 465 | matches!(self, Correctness | Suspicious | Style | Complexity | Perf) | |
| 466 | } | |
| 467 | ||
| 468 | fn group(self, groups: &mut RegistrationGroups) -> &mut Vec<LintId> { | |
| 469 | match self { | |
| 470 | Cargo => &mut groups.cargo, | |
| 471 | Complexity => &mut groups.complexity, | |
| 472 | Correctness => &mut groups.correctness, | |
| 473 | Nursery => &mut groups.nursery, | |
| 474 | Pedantic => &mut groups.pedantic, | |
| 475 | Perf => &mut groups.perf, | |
| 476 | Restriction => &mut groups.restriction, | |
| 477 | Style => &mut groups.style, | |
| 478 | Suspicious => &mut groups.suspicious, | |
| 479 | } | |
| 480 | } | |
| 481 | } | |
| 482 | ||
| 483 | pub struct LintInfo { | |
| 484 | /// Double reference to maintain pointer equality | |
| 485 | pub lint: &'static &'static Lint, | |
| 486 | category: LintCategory, | |
| 487 | pub explanation: &'static str, | |
| 488 | /// e.g. `clippy_lints/src/absolute_paths.rs#43` | |
| 489 | pub location: &'static str, | |
| 490 | pub version: Option<&'static str>, | |
| 491 | } | |
| 492 | ||
| 493 | impl LintInfo { | |
| 494 | /// Returns the lint name in lowercase without the `clippy::` prefix | |
| 495 | #[allow(clippy::missing_panics_doc)] | |
| 496 | pub fn name_lower(&self) -> String { | |
| 497 | self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase() | |
| 498 | } | |
| 499 | ||
| 500 | /// Returns the name of the lint's category in lowercase (`style`, `pedantic`) | |
| 501 | pub fn category_str(&self) -> &'static str { | |
| 502 | match self.category { | |
| 503 | Cargo => "cargo", | |
| 504 | Complexity => "complexity", | |
| 505 | Correctness => "correctness", | |
| 506 | Nursery => "nursery", | |
| 507 | Pedantic => "pedantic", | |
| 508 | Perf => "perf", | |
| 509 | Restriction => "restriction", | |
| 510 | Style => "style", | |
| 511 | Suspicious => "suspicious", | |
| 512 | } | |
| 513 | } | |
| 514 | } | |
| 515 | ||
| 516 | 417 | pub fn explain(name: &str) -> i32 { |
| 517 | 418 | let target = format!("clippy::{}", name.to_ascii_uppercase()); |
| 518 | 419 | |
| ... | ... | @@ -535,30 +436,11 @@ pub fn explain(name: &str) -> i32 { |
| 535 | 436 | } |
| 536 | 437 | } |
| 537 | 438 | |
| 538 | fn register_categories(store: &mut rustc_lint::LintStore) { | |
| 539 | let mut groups = RegistrationGroups::default(); | |
| 540 | ||
| 541 | for LintInfo { lint, category, .. } in declared_lints::LINTS { | |
| 542 | if category.is_all() { | |
| 543 | groups.all.push(LintId::of(lint)); | |
| 544 | } | |
| 545 | ||
| 546 | category.group(&mut groups).push(LintId::of(lint)); | |
| 547 | } | |
| 548 | ||
| 549 | let lints: Vec<&'static Lint> = declared_lints::LINTS.iter().map(|info| *info.lint).collect(); | |
| 550 | ||
| 551 | store.register_lints(&lints); | |
| 552 | groups.register(store); | |
| 553 | } | |
| 554 | ||
| 555 | 439 | /// Register all lints and lint groups with the rustc lint store |
| 556 | 440 | /// |
| 557 | 441 | /// Used in `./src/driver.rs`. |
| 558 | 442 | #[expect(clippy::too_many_lines)] |
| 559 | pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { | |
| 560 | register_categories(store); | |
| 561 | ||
| 443 | pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Conf) { | |
| 562 | 444 | for (old_name, new_name) in deprecated_lints::RENAMED { |
| 563 | 445 | store.register_renamed(old_name, new_name); |
| 564 | 446 | } |
src/tools/clippy/clippy_lints/src/loops/same_item_push.rs+7-8| ... | ... | @@ -163,15 +163,14 @@ impl<'tcx> Visitor<'tcx> for SameItemPushVisitor<'_, 'tcx> { |
| 163 | 163 | StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(expr), |
| 164 | 164 | _ => {}, |
| 165 | 165 | } |
| 166 | } | |
| 167 | // Current statement is a push ...check whether another | |
| 168 | // push had been previously done | |
| 169 | else if self.vec_push.is_none() { | |
| 170 | self.vec_push = vec_push_option; | |
| 166 | 171 | } else { |
| 167 | // Current statement is a push ...check whether another | |
| 168 | // push had been previously done | |
| 169 | if self.vec_push.is_none() { | |
| 170 | self.vec_push = vec_push_option; | |
| 171 | } else { | |
| 172 | // There are multiple pushes ... don't lint | |
| 173 | self.multiple_pushes = true; | |
| 174 | } | |
| 172 | // There are multiple pushes ... don't lint | |
| 173 | self.multiple_pushes = true; | |
| 175 | 174 | } |
| 176 | 175 | } |
| 177 | 176 | } |
src/tools/clippy/clippy_lints/src/manual_let_else.rs-1| ... | ... | @@ -13,7 +13,6 @@ use rustc_errors::Applicability; |
| 13 | 13 | use rustc_hir::def::{CtorOf, DefKind, Res}; |
| 14 | 14 | use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind}; |
| 15 | 15 | use rustc_lint::{LateContext, LintContext}; |
| 16 | ||
| 17 | 16 | use rustc_span::Span; |
| 18 | 17 | use rustc_span::symbol::{Symbol, sym}; |
| 19 | 18 | use std::slice; |
src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs+17-3| ... | ... | @@ -1,9 +1,9 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::source::{indent_of, reindent_multiline}; |
| 3 | 3 | use clippy_utils::sugg::Sugg; |
| 4 | use clippy_utils::ty::option_arg_ty; | |
| 4 | use clippy_utils::ty::{option_arg_ty, peel_mid_ty_refs_is_mutable}; | |
| 5 | 5 | use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res, peel_blocks, span_contains_comment}; |
| 6 | use rustc_ast::BindingMode; | |
| 6 | use rustc_ast::{BindingMode, Mutability}; | |
| 7 | 7 | use rustc_errors::Applicability; |
| 8 | 8 | use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr}; |
| 9 | 9 | use rustc_hir::def::{DefKind, Res}; |
| ... | ... | @@ -133,7 +133,21 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok |
| 133 | 133 | Applicability::MachineApplicable |
| 134 | 134 | }; |
| 135 | 135 | let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren(); |
| 136 | let sugg = format!("{scrut}.{method}()"); | |
| 136 | ||
| 137 | let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee); | |
| 138 | let (_, n_ref, mutability) = peel_mid_ty_refs_is_mutable(scrutinee_ty); | |
| 139 | let prefix = if n_ref > 0 { | |
| 140 | if mutability == Mutability::Mut { | |
| 141 | ".as_mut()" | |
| 142 | } else { | |
| 143 | ".as_ref()" | |
| 144 | } | |
| 145 | } else { | |
| 146 | "" | |
| 147 | }; | |
| 148 | ||
| 149 | let sugg = format!("{scrut}{prefix}.{method}()"); | |
| 150 | ||
| 137 | 151 | // If the expression being expanded is the `if …` part of an `else if …`, it must be blockified. |
| 138 | 152 | let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) |
| 139 | 153 | && let ExprKind::If(_, _, Some(else_part)) = parent_expr.kind |
src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs+8-6| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | 3 | use clippy_utils::ty::is_type_diagnostic_item; |
| 3 | 4 | use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns}; |
| 4 | 5 | use rustc_errors::Applicability; |
| ... | ... | @@ -116,11 +117,12 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { |
| 116 | 117 | let format_suggestion = |variant: &VariantDef| { |
| 117 | 118 | format!( |
| 118 | 119 | "{}{}{}{}", |
| 119 | if let Some(ident) = wildcard_ident { | |
| 120 | format!("{} @ ", ident.name) | |
| 121 | } else { | |
| 122 | String::new() | |
| 123 | }, | |
| 120 | wildcard_ident.map_or(String::new(), |ident| { | |
| 121 | ident | |
| 122 | .span | |
| 123 | .get_source_text(cx) | |
| 124 | .map_or_else(|| format!("{} @ ", ident.name), |s| format!("{s} @ ")) | |
| 125 | }), | |
| 124 | 126 | if let CommonPrefixSearcher::Path(path_prefix) = path_prefix { |
| 125 | 127 | let mut s = String::new(); |
| 126 | 128 | for seg in path_prefix { |
| ... | ... | @@ -138,7 +140,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { |
| 138 | 140 | Some(CtorKind::Fn) if variant.fields.len() == 1 => "(_)", |
| 139 | 141 | Some(CtorKind::Fn) => "(..)", |
| 140 | 142 | Some(CtorKind::Const) => "", |
| 141 | None => "{ .. }", | |
| 143 | None => " { .. }", | |
| 142 | 144 | } |
| 143 | 145 | ) |
| 144 | 146 | }; |
src/tools/clippy/clippy_lints/src/methods/mod.rs+1-1| ... | ... | @@ -4426,7 +4426,7 @@ declare_clippy_lint! { |
| 4426 | 4426 | /// ```no_run |
| 4427 | 4427 | /// use std::io::{BufReader, Read}; |
| 4428 | 4428 | /// use std::fs::File; |
| 4429 | /// let file = BufReader::new(std::fs::File::open("./bytes.txt").unwrap()); | |
| 4429 | /// let file = BufReader::new(File::open("./bytes.txt").unwrap()); | |
| 4430 | 4430 | /// file.bytes(); |
| 4431 | 4431 | /// ``` |
| 4432 | 4432 | #[clippy::version = "1.87.0"] |
src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs+6-5| ... | ... | @@ -136,7 +136,7 @@ pub(super) fn check<'tcx>( |
| 136 | 136 | fun_span: Option<Span>, |
| 137 | 137 | ) -> bool { |
| 138 | 138 | // (path, fn_has_argument, methods, suffix) |
| 139 | const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 4] = [ | |
| 139 | const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 5] = [ | |
| 140 | 140 | (sym::BTreeEntry, false, &[sym::or_insert], "with"), |
| 141 | 141 | (sym::HashMapEntry, false, &[sym::or_insert], "with"), |
| 142 | 142 | ( |
| ... | ... | @@ -145,16 +145,17 @@ pub(super) fn check<'tcx>( |
| 145 | 145 | &[sym::map_or, sym::ok_or, sym::or, sym::unwrap_or], |
| 146 | 146 | "else", |
| 147 | 147 | ), |
| 148 | (sym::Result, true, &[sym::or, sym::unwrap_or], "else"), | |
| 148 | (sym::Option, false, &[sym::get_or_insert], "with"), | |
| 149 | (sym::Result, true, &[sym::map_or, sym::or, sym::unwrap_or], "else"), | |
| 149 | 150 | ]; |
| 150 | 151 | |
| 151 | 152 | if KNOW_TYPES.iter().any(|k| k.2.contains(&name)) |
| 152 | 153 | && switch_to_lazy_eval(cx, arg) |
| 153 | 154 | && !contains_return(arg) |
| 154 | 155 | && let self_ty = cx.typeck_results().expr_ty(self_expr) |
| 155 | && let Some(&(_, fn_has_arguments, poss, suffix)) = | |
| 156 | KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0)) | |
| 157 | && poss.contains(&name) | |
| 156 | && let Some(&(_, fn_has_arguments, _, suffix)) = KNOW_TYPES | |
| 157 | .iter() | |
| 158 | .find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0) && i.2.contains(&name)) | |
| 158 | 159 | { |
| 159 | 160 | let ctxt = span.ctxt(); |
| 160 | 161 | let mut app = Applicability::HasPlaceholders; |
src/tools/clippy/clippy_lints/src/missing_inline.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint; |
| 2 | use rustc_attr_data_structures::{find_attr, AttributeKind}; | |
| 2 | use rustc_attr_data_structures::{AttributeKind, find_attr}; | |
| 3 | 3 | use rustc_hir as hir; |
| 4 | 4 | use rustc_hir::Attribute; |
| 5 | 5 | use rustc_lint::{LateContext, LateLintPass, LintContext}; |
src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs+6-6| ... | ... | @@ -161,7 +161,7 @@ fn path_has_args(p: &QPath<'_>) -> bool { |
| 161 | 161 | /// - `Copy` itself, or |
| 162 | 162 | /// - the only use of a mutable reference, or |
| 163 | 163 | /// - not a variable (created by a function call) |
| 164 | #[expect(clippy::too_many_arguments)] | |
| 164 | #[expect(clippy::too_many_arguments, clippy::too_many_lines)] | |
| 165 | 165 | fn needless_borrow_count<'tcx>( |
| 166 | 166 | cx: &LateContext<'tcx>, |
| 167 | 167 | possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, |
| ... | ... | @@ -232,11 +232,11 @@ fn needless_borrow_count<'tcx>( |
| 232 | 232 | let mut args_with_referent_ty = callee_args.to_vec(); |
| 233 | 233 | |
| 234 | 234 | let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| { |
| 235 | if let ExprKind::Field(base, _) = &referent.kind { | |
| 236 | let base_ty = cx.typeck_results().expr_ty(base); | |
| 237 | if drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[])) { | |
| 238 | return false; | |
| 239 | } | |
| 235 | if let ExprKind::Field(base, _) = &referent.kind | |
| 236 | && let base_ty = cx.typeck_results().expr_ty(base) | |
| 237 | && drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[])) | |
| 238 | { | |
| 239 | return false; | |
| 240 | 240 | } |
| 241 | 241 | |
| 242 | 242 | let referent_ty = cx.typeck_results().expr_ty(referent); |
src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs-1| ... | ... | @@ -5,7 +5,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; |
| 5 | 5 | use rustc_ast::ast; |
| 6 | 6 | use rustc_errors::Applicability; |
| 7 | 7 | use rustc_hir::{Expr, ExprKind}; |
| 8 | ||
| 9 | 8 | use rustc_lint::{LateContext, LateLintPass}; |
| 10 | 9 | use rustc_session::declare_lint_pass; |
| 11 | 10 |
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs+4-2| ... | ... | @@ -124,8 +124,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { |
| 124 | 124 | // Note that we do not want to deal with qualified predicates here. |
| 125 | 125 | match pred.kind().no_bound_vars() { |
| 126 | 126 | Some(ty::ClauseKind::Trait(pred)) |
| 127 | if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait | |
| 128 | => Some(pred), | |
| 127 | if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait => | |
| 128 | { | |
| 129 | Some(pred) | |
| 130 | }, | |
| 129 | 131 | _ => None, |
| 130 | 132 | } |
| 131 | 133 | }) |
src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs+2-3| ... | ... | @@ -1,13 +1,12 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::source::{snippet, snippet_with_applicability}; |
| 3 | 3 | use rustc_abi::ExternAbi; |
| 4 | use rustc_attr_data_structures::AttributeKind; | |
| 4 | 5 | use rustc_errors::Applicability; |
| 5 | use rustc_hir::{Item, ItemKind}; | |
| 6 | use rustc_hir::{Attribute, Item, ItemKind}; | |
| 6 | 7 | use rustc_lint::{LateContext, LateLintPass}; |
| 7 | 8 | use rustc_session::declare_lint_pass; |
| 8 | 9 | use rustc_span::{BytePos, Pos}; |
| 9 | use rustc_attr_data_structures::AttributeKind; | |
| 10 | use rustc_hir::Attribute; | |
| 11 | 10 | |
| 12 | 11 | declare_clippy_lint! { |
| 13 | 12 | /// ### What it does |
src/tools/clippy/clippy_lints/src/non_copy_const.rs+1-1| ... | ... | @@ -617,7 +617,7 @@ impl<'tcx> NonCopyConst<'tcx> { |
| 617 | 617 | |
| 618 | 618 | // Then a type check. Note we only check the type here as the result |
| 619 | 619 | // gets cached. |
| 620 | let ty = EarlyBinder::bind(typeck.expr_ty(src_expr)).instantiate(tcx, init_args); | |
| 620 | let ty = typeck.expr_ty(src_expr); | |
| 621 | 621 | // Normalized as we need to check if this is an array later. |
| 622 | 622 | let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); |
| 623 | 623 | if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() { |
src/tools/clippy/clippy_lints/src/operators/identity_op.rs+67-9| ... | ... | @@ -1,12 +1,13 @@ |
| 1 | use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt}; | |
| 1 | use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt, integer_const, is_zero_integer_const}; | |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 3 | 3 | use clippy_utils::source::snippet_with_applicability; |
| 4 | use clippy_utils::{clip, peel_hir_expr_refs, unsext}; | |
| 4 | use clippy_utils::{ExprUseNode, clip, expr_use_ctxt, peel_hir_expr_refs, unsext}; | |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | use rustc_hir::{BinOpKind, Expr, ExprKind, Node}; | |
| 6 | use rustc_hir::def::{DefKind, Res}; | |
| 7 | use rustc_hir::{BinOpKind, Expr, ExprKind, Node, Path, QPath}; | |
| 7 | 8 | use rustc_lint::LateContext; |
| 8 | 9 | use rustc_middle::ty; |
| 9 | use rustc_span::Span; | |
| 10 | use rustc_span::{Span, kw}; | |
| 10 | 11 | |
| 11 | 12 | use super::IDENTITY_OP; |
| 12 | 13 | |
| ... | ... | @@ -17,7 +18,7 @@ pub(crate) fn check<'tcx>( |
| 17 | 18 | left: &'tcx Expr<'_>, |
| 18 | 19 | right: &'tcx Expr<'_>, |
| 19 | 20 | ) { |
| 20 | if !is_allowed(cx, op, left, right) { | |
| 21 | if !is_allowed(cx, expr, op, left, right) { | |
| 21 | 22 | return; |
| 22 | 23 | } |
| 23 | 24 | |
| ... | ... | @@ -165,14 +166,27 @@ fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, child: &Expr<'_>) |
| 165 | 166 | Parens::Needed |
| 166 | 167 | } |
| 167 | 168 | |
| 168 | fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> bool { | |
| 169 | fn is_allowed<'tcx>( | |
| 170 | cx: &LateContext<'tcx>, | |
| 171 | expr: &'tcx Expr<'tcx>, | |
| 172 | cmp: BinOpKind, | |
| 173 | left: &Expr<'tcx>, | |
| 174 | right: &Expr<'tcx>, | |
| 175 | ) -> bool { | |
| 176 | // Exclude case where the left or right side is associated function call returns a type which is | |
| 177 | // `Self` that is not given explicitly, and the expression is not a let binding's init | |
| 178 | // expression and the let binding has a type annotation, or a function's return value. | |
| 179 | if (is_assoc_fn_without_type_instance(cx, left) || is_assoc_fn_without_type_instance(cx, right)) | |
| 180 | && !is_expr_used_with_type_annotation(cx, expr) | |
| 181 | { | |
| 182 | return false; | |
| 183 | } | |
| 184 | ||
| 169 | 185 | // This lint applies to integers and their references |
| 170 | 186 | cx.typeck_results().expr_ty(left).peel_refs().is_integral() |
| 171 | 187 | && cx.typeck_results().expr_ty(right).peel_refs().is_integral() |
| 172 | 188 | // `1 << 0` is a common pattern in bit manipulation code |
| 173 | && !(cmp == BinOpKind::Shl | |
| 174 | && ConstEvalCtxt::new(cx).eval_simple(right) == Some(Constant::Int(0)) | |
| 175 | && ConstEvalCtxt::new(cx).eval_simple(left) == Some(Constant::Int(1))) | |
| 189 | && !(cmp == BinOpKind::Shl && is_zero_integer_const(cx, right) && integer_const(cx, left) == Some(1)) | |
| 176 | 190 | } |
| 177 | 191 | |
| 178 | 192 | fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span: Span, arg: Span) { |
| ... | ... | @@ -234,3 +248,47 @@ fn span_ineffective_operation( |
| 234 | 248 | applicability, |
| 235 | 249 | ); |
| 236 | 250 | } |
| 251 | ||
| 252 | fn is_expr_used_with_type_annotation<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { | |
| 253 | match expr_use_ctxt(cx, expr).use_node(cx) { | |
| 254 | ExprUseNode::LetStmt(letstmt) => letstmt.ty.is_some(), | |
| 255 | ExprUseNode::Return(_) => true, | |
| 256 | _ => false, | |
| 257 | } | |
| 258 | } | |
| 259 | ||
| 260 | /// Check if the expression is an associated function without a type instance. | |
| 261 | /// Example: | |
| 262 | /// ``` | |
| 263 | /// trait Def { | |
| 264 | /// fn def() -> Self; | |
| 265 | /// } | |
| 266 | /// impl Def for usize { | |
| 267 | /// fn def() -> Self { | |
| 268 | /// 0 | |
| 269 | /// } | |
| 270 | /// } | |
| 271 | /// fn test() { | |
| 272 | /// let _ = 0usize + &Default::default(); | |
| 273 | /// let _ = 0usize + &Def::def(); | |
| 274 | /// } | |
| 275 | /// ``` | |
| 276 | fn is_assoc_fn_without_type_instance<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { | |
| 277 | if let ExprKind::Call(func, _) = peel_hir_expr_refs(expr).0.kind | |
| 278 | && let ExprKind::Path(QPath::Resolved( | |
| 279 | // If it's not None, don't need to go further. | |
| 280 | None, | |
| 281 | Path { | |
| 282 | res: Res::Def(DefKind::AssocFn, def_id), | |
| 283 | .. | |
| 284 | }, | |
| 285 | )) = func.kind | |
| 286 | && let output_ty = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output() | |
| 287 | && let ty::Param(ty::ParamTy { | |
| 288 | name: kw::SelfUpper, .. | |
| 289 | }) = output_ty.kind() | |
| 290 | { | |
| 291 | return true; | |
| 292 | } | |
| 293 | false | |
| 294 | } |
src/tools/clippy/clippy_lints/src/operators/manual_is_multiple_of.rs created+66| ... | ... | @@ -0,0 +1,66 @@ |
| 1 | use clippy_utils::consts::is_zero_integer_const; | |
| 2 | use clippy_utils::diagnostics::span_lint_and_sugg; | |
| 3 | use clippy_utils::msrvs::{self, Msrv}; | |
| 4 | use clippy_utils::sugg::Sugg; | |
| 5 | use rustc_ast::BinOpKind; | |
| 6 | use rustc_errors::Applicability; | |
| 7 | use rustc_hir::{Expr, ExprKind}; | |
| 8 | use rustc_lint::LateContext; | |
| 9 | use rustc_middle::ty; | |
| 10 | ||
| 11 | use super::MANUAL_IS_MULTIPLE_OF; | |
| 12 | ||
| 13 | pub(super) fn check<'tcx>( | |
| 14 | cx: &LateContext<'tcx>, | |
| 15 | expr: &Expr<'_>, | |
| 16 | op: BinOpKind, | |
| 17 | lhs: &'tcx Expr<'tcx>, | |
| 18 | rhs: &'tcx Expr<'tcx>, | |
| 19 | msrv: Msrv, | |
| 20 | ) { | |
| 21 | if msrv.meets(cx, msrvs::UNSIGNED_IS_MULTIPLE_OF) | |
| 22 | && let Some(operand) = uint_compare_to_zero(cx, op, lhs, rhs) | |
| 23 | && let ExprKind::Binary(operand_op, operand_left, operand_right) = operand.kind | |
| 24 | && operand_op.node == BinOpKind::Rem | |
| 25 | { | |
| 26 | let mut app = Applicability::MachineApplicable; | |
| 27 | let divisor = Sugg::hir_with_applicability(cx, operand_right, "_", &mut app); | |
| 28 | span_lint_and_sugg( | |
| 29 | cx, | |
| 30 | MANUAL_IS_MULTIPLE_OF, | |
| 31 | expr.span, | |
| 32 | "manual implementation of `.is_multiple_of()`", | |
| 33 | "replace with", | |
| 34 | format!( | |
| 35 | "{}{}.is_multiple_of({divisor})", | |
| 36 | if op == BinOpKind::Eq { "" } else { "!" }, | |
| 37 | Sugg::hir_with_applicability(cx, operand_left, "_", &mut app).maybe_paren() | |
| 38 | ), | |
| 39 | app, | |
| 40 | ); | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 44 | // If we have a `x == 0`, `x != 0` or `x > 0` (or the reverted ones), return the non-zero operand | |
| 45 | fn uint_compare_to_zero<'tcx>( | |
| 46 | cx: &LateContext<'tcx>, | |
| 47 | op: BinOpKind, | |
| 48 | lhs: &'tcx Expr<'tcx>, | |
| 49 | rhs: &'tcx Expr<'tcx>, | |
| 50 | ) -> Option<&'tcx Expr<'tcx>> { | |
| 51 | let operand = if matches!(lhs.kind, ExprKind::Binary(..)) | |
| 52 | && matches!(op, BinOpKind::Eq | BinOpKind::Ne | BinOpKind::Gt) | |
| 53 | && is_zero_integer_const(cx, rhs) | |
| 54 | { | |
| 55 | lhs | |
| 56 | } else if matches!(rhs.kind, ExprKind::Binary(..)) | |
| 57 | && matches!(op, BinOpKind::Eq | BinOpKind::Ne | BinOpKind::Lt) | |
| 58 | && is_zero_integer_const(cx, lhs) | |
| 59 | { | |
| 60 | rhs | |
| 61 | } else { | |
| 62 | return None; | |
| 63 | }; | |
| 64 | ||
| 65 | matches!(cx.typeck_results().expr_ty_adjusted(operand).kind(), ty::Uint(_)).then_some(operand) | |
| 66 | } |
src/tools/clippy/clippy_lints/src/operators/mod.rs+33| ... | ... | @@ -11,6 +11,7 @@ mod float_cmp; |
| 11 | 11 | mod float_equality_without_abs; |
| 12 | 12 | mod identity_op; |
| 13 | 13 | mod integer_division; |
| 14 | mod manual_is_multiple_of; | |
| 14 | 15 | mod manual_midpoint; |
| 15 | 16 | mod misrefactored_assign_op; |
| 16 | 17 | mod modulo_arithmetic; |
| ... | ... | @@ -830,12 +831,42 @@ declare_clippy_lint! { |
| 830 | 831 | "manual implementation of `midpoint` which can overflow" |
| 831 | 832 | } |
| 832 | 833 | |
| 834 | declare_clippy_lint! { | |
| 835 | /// ### What it does | |
| 836 | /// Checks for manual implementation of `.is_multiple_of()` on | |
| 837 | /// unsigned integer types. | |
| 838 | /// | |
| 839 | /// ### Why is this bad? | |
| 840 | /// `a.is_multiple_of(b)` is a clearer way to check for divisibility | |
| 841 | /// of `a` by `b`. This expression can never panic. | |
| 842 | /// | |
| 843 | /// ### Example | |
| 844 | /// ```no_run | |
| 845 | /// # let (a, b) = (3u64, 4u64); | |
| 846 | /// if a % b == 0 { | |
| 847 | /// println!("{a} is divisible by {b}"); | |
| 848 | /// } | |
| 849 | /// ``` | |
| 850 | /// Use instead: | |
| 851 | /// ```no_run | |
| 852 | /// # let (a, b) = (3u64, 4u64); | |
| 853 | /// if a.is_multiple_of(b) { | |
| 854 | /// println!("{a} is divisible by {b}"); | |
| 855 | /// } | |
| 856 | /// ``` | |
| 857 | #[clippy::version = "1.89.0"] | |
| 858 | pub MANUAL_IS_MULTIPLE_OF, | |
| 859 | complexity, | |
| 860 | "manual implementation of `.is_multiple_of()`" | |
| 861 | } | |
| 862 | ||
| 833 | 863 | pub struct Operators { |
| 834 | 864 | arithmetic_context: numeric_arithmetic::Context, |
| 835 | 865 | verbose_bit_mask_threshold: u64, |
| 836 | 866 | modulo_arithmetic_allow_comparison_to_zero: bool, |
| 837 | 867 | msrv: Msrv, |
| 838 | 868 | } |
| 869 | ||
| 839 | 870 | impl Operators { |
| 840 | 871 | pub fn new(conf: &'static Conf) -> Self { |
| 841 | 872 | Self { |
| ... | ... | @@ -874,6 +905,7 @@ impl_lint_pass!(Operators => [ |
| 874 | 905 | NEEDLESS_BITWISE_BOOL, |
| 875 | 906 | SELF_ASSIGNMENT, |
| 876 | 907 | MANUAL_MIDPOINT, |
| 908 | MANUAL_IS_MULTIPLE_OF, | |
| 877 | 909 | ]); |
| 878 | 910 | |
| 879 | 911 | impl<'tcx> LateLintPass<'tcx> for Operators { |
| ... | ... | @@ -891,6 +923,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators { |
| 891 | 923 | identity_op::check(cx, e, op.node, lhs, rhs); |
| 892 | 924 | needless_bitwise_bool::check(cx, e, op.node, lhs, rhs); |
| 893 | 925 | manual_midpoint::check(cx, e, op.node, lhs, rhs, self.msrv); |
| 926 | manual_is_multiple_of::check(cx, e, op.node, lhs, rhs, self.msrv); | |
| 894 | 927 | } |
| 895 | 928 | self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs); |
| 896 | 929 | bit_mask::check(cx, e, op.node, lhs, rhs); |
src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs+2-2| ... | ... | @@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; |
| 3 | 3 | use clippy_utils::source::snippet; |
| 4 | 4 | use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; |
| 5 | 5 | use clippy_utils::{is_self, is_self_ty}; |
| 6 | use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr}; | |
| 7 | use rustc_data_structures::fx::FxHashSet; | |
| 8 | 6 | use core::ops::ControlFlow; |
| 9 | 7 | use rustc_abi::ExternAbi; |
| 8 | use rustc_attr_data_structures::{AttributeKind, InlineAttr, find_attr}; | |
| 9 | use rustc_data_structures::fx::FxHashSet; | |
| 10 | 10 | use rustc_errors::Applicability; |
| 11 | 11 | use rustc_hir as hir; |
| 12 | 12 | use rustc_hir::intravisit::FnKind; |
src/tools/clippy/clippy_lints/src/question_mark.rs+1| ... | ... | @@ -142,6 +142,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { |
| 142 | 142 | && let Some(ret) = find_let_else_ret_expression(els) |
| 143 | 143 | && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret) |
| 144 | 144 | && !span_contains_comment(cx.tcx.sess.source_map(), els.span) |
| 145 | && !span_contains_cfg(cx, els.span) | |
| 145 | 146 | { |
| 146 | 147 | let mut applicability = Applicability::MaybeIncorrect; |
| 147 | 148 | let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren(); |
src/tools/clippy/clippy_lints/src/question_mark_used.rs-1| ... | ... | @@ -1,5 +1,4 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | ||
| 3 | 2 | use clippy_utils::macros::span_is_local; |
| 4 | 3 | use rustc_hir::{Expr, ExprKind, MatchSource}; |
| 5 | 4 | use rustc_lint::{LateContext, LateLintPass}; |
src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs+1-2| ... | ... | @@ -3,11 +3,10 @@ use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; |
| 3 | 3 | use clippy_utils::source::snippet; |
| 4 | 4 | use clippy_utils::{get_enclosing_block, sym}; |
| 5 | 5 | |
| 6 | use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind}; | |
| 7 | 6 | use rustc_errors::Applicability; |
| 8 | use rustc_hir as hir; | |
| 9 | 7 | use rustc_hir::def::Res; |
| 10 | 8 | use rustc_hir::intravisit::{Visitor, walk_expr}; |
| 9 | use rustc_hir::{self as hir, Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind}; | |
| 11 | 10 | use rustc_lint::{LateContext, LateLintPass}; |
| 12 | 11 | use rustc_session::declare_lint_pass; |
| 13 | 12 |
src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs+2-3| ... | ... | @@ -1,14 +1,13 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_help; |
| 2 | 2 | use clippy_utils::ty::is_must_use_ty; |
| 3 | 3 | use clippy_utils::{nth_arg, return_ty}; |
| 4 | use rustc_attr_data_structures::{AttributeKind, find_attr}; | |
| 4 | 5 | use rustc_hir::def_id::LocalDefId; |
| 5 | 6 | use rustc_hir::intravisit::FnKind; |
| 6 | 7 | use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; |
| 7 | 8 | use rustc_lint::{LateContext, LateLintPass, LintContext}; |
| 8 | 9 | use rustc_session::declare_lint_pass; |
| 9 | use rustc_span::{Span}; | |
| 10 | use rustc_attr_data_structures::AttributeKind; | |
| 11 | use rustc_attr_data_structures::find_attr; | |
| 10 | use rustc_span::Span; | |
| 12 | 11 | |
| 13 | 12 | declare_clippy_lint! { |
| 14 | 13 | /// ### What it does |
src/tools/clippy/clippy_lints/src/single_component_path_imports.rs+14-15| ... | ... | @@ -219,22 +219,21 @@ impl SingleComponentPathImports { |
| 219 | 219 | } |
| 220 | 220 | } |
| 221 | 221 | } |
| 222 | } else { | |
| 223 | // keep track of `use self::some_module` usages | |
| 224 | if segments[0].ident.name == kw::SelfLower { | |
| 225 | // simple case such as `use self::module::SomeStruct` | |
| 226 | if segments.len() > 1 { | |
| 227 | imports_reused_with_self.push(segments[1].ident.name); | |
| 228 | return; | |
| 229 | } | |
| 222 | } | |
| 223 | // keep track of `use self::some_module` usages | |
| 224 | else if segments[0].ident.name == kw::SelfLower { | |
| 225 | // simple case such as `use self::module::SomeStruct` | |
| 226 | if segments.len() > 1 { | |
| 227 | imports_reused_with_self.push(segments[1].ident.name); | |
| 228 | return; | |
| 229 | } | |
| 230 | 230 | |
| 231 | // nested case such as `use self::{module1::Struct1, module2::Struct2}` | |
| 232 | if let UseTreeKind::Nested { items, .. } = &use_tree.kind { | |
| 233 | for tree in items { | |
| 234 | let segments = &tree.0.prefix.segments; | |
| 235 | if !segments.is_empty() { | |
| 236 | imports_reused_with_self.push(segments[0].ident.name); | |
| 237 | } | |
| 231 | // nested case such as `use self::{module1::Struct1, module2::Struct2}` | |
| 232 | if let UseTreeKind::Nested { items, .. } = &use_tree.kind { | |
| 233 | for tree in items { | |
| 234 | let segments = &tree.0.prefix.segments; | |
| 235 | if !segments.is_empty() { | |
| 236 | imports_reused_with_self.push(segments[0].ident.name); | |
| 238 | 237 | } |
| 239 | 238 | } |
| 240 | 239 | } |
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs+22-23| ... | ... | @@ -606,32 +606,31 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span |
| 606 | 606 | let ctxt = span.ctxt(); |
| 607 | 607 | if ctxt == SyntaxContext::root() { |
| 608 | 608 | HasSafetyComment::Maybe |
| 609 | } else { | |
| 610 | // From a macro expansion. Get the text from the start of the macro declaration to start of the | |
| 611 | // unsafe block. | |
| 612 | // macro_rules! foo { () => { stuff }; (x) => { unsafe { stuff } }; } | |
| 613 | // ^--------------------------------------------^ | |
| 614 | if let Ok(unsafe_line) = source_map.lookup_line(span.lo()) | |
| 615 | && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo()) | |
| 616 | && Arc::ptr_eq(&unsafe_line.sf, &macro_line.sf) | |
| 617 | && let Some(src) = unsafe_line.sf.src.as_deref() | |
| 618 | { | |
| 619 | if macro_line.line < unsafe_line.line { | |
| 620 | match text_has_safety_comment( | |
| 621 | src, | |
| 622 | &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line], | |
| 623 | unsafe_line.sf.start_pos, | |
| 624 | ) { | |
| 625 | Some(b) => HasSafetyComment::Yes(b), | |
| 626 | None => HasSafetyComment::No, | |
| 627 | } | |
| 628 | } else { | |
| 629 | HasSafetyComment::No | |
| 609 | } | |
| 610 | // From a macro expansion. Get the text from the start of the macro declaration to start of the | |
| 611 | // unsafe block. | |
| 612 | // macro_rules! foo { () => { stuff }; (x) => { unsafe { stuff } }; } | |
| 613 | // ^--------------------------------------------^ | |
| 614 | else if let Ok(unsafe_line) = source_map.lookup_line(span.lo()) | |
| 615 | && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo()) | |
| 616 | && Arc::ptr_eq(&unsafe_line.sf, &macro_line.sf) | |
| 617 | && let Some(src) = unsafe_line.sf.src.as_deref() | |
| 618 | { | |
| 619 | if macro_line.line < unsafe_line.line { | |
| 620 | match text_has_safety_comment( | |
| 621 | src, | |
| 622 | &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line], | |
| 623 | unsafe_line.sf.start_pos, | |
| 624 | ) { | |
| 625 | Some(b) => HasSafetyComment::Yes(b), | |
| 626 | None => HasSafetyComment::No, | |
| 630 | 627 | } |
| 631 | 628 | } else { |
| 632 | // Problem getting source text. Pretend a comment was found. | |
| 633 | HasSafetyComment::Maybe | |
| 629 | HasSafetyComment::No | |
| 634 | 630 | } |
| 631 | } else { | |
| 632 | // Problem getting source text. Pretend a comment was found. | |
| 633 | HasSafetyComment::Maybe | |
| 635 | 634 | } |
| 636 | 635 | } |
| 637 | 636 |
src/tools/clippy/clippy_utils/Cargo.toml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | [package] |
| 2 | 2 | name = "clippy_utils" |
| 3 | version = "0.1.89" | |
| 3 | version = "0.1.90" | |
| 4 | 4 | edition = "2024" |
| 5 | 5 | description = "Helpful tools for writing lints, provided as they are used in Clippy" |
| 6 | 6 | repository = "https://github.com/rust-lang/rust-clippy" |
src/tools/clippy/clippy_utils/README.md+1-1| ... | ... | @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: |
| 8 | 8 | |
| 9 | 9 | <!-- begin autogenerated nightly --> |
| 10 | 10 | ``` |
| 11 | nightly-2025-06-12 | |
| 11 | nightly-2025-06-26 | |
| 12 | 12 | ``` |
| 13 | 13 | <!-- end autogenerated nightly --> |
| 14 | 14 |
src/tools/clippy/clippy_utils/src/consts.rs+15| ... | ... | @@ -958,3 +958,18 @@ fn field_of_struct<'tcx>( |
| 958 | 958 | None |
| 959 | 959 | } |
| 960 | 960 | } |
| 961 | ||
| 962 | /// If `expr` evaluates to an integer constant, return its value. | |
| 963 | pub fn integer_const(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> { | |
| 964 | if let Some(Constant::Int(value)) = ConstEvalCtxt::new(cx).eval_simple(expr) { | |
| 965 | Some(value) | |
| 966 | } else { | |
| 967 | None | |
| 968 | } | |
| 969 | } | |
| 970 | ||
| 971 | /// Check if `expr` evaluates to an integer constant of 0. | |
| 972 | #[inline] | |
| 973 | pub fn is_zero_integer_const(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | |
| 974 | integer_const(cx, expr) == Some(0) | |
| 975 | } |
src/tools/clippy/clippy_utils/src/diagnostics.rs+3-3| ... | ... | @@ -109,7 +109,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult |
| 109 | 109 | }); |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | /// Same as `span_lint` but with an extra `help` message. | |
| 112 | /// Same as [`span_lint`] but with an extra `help` message. | |
| 113 | 113 | /// |
| 114 | 114 | /// Use this if you want to provide some general help but |
| 115 | 115 | /// can't provide a specific machine applicable suggestion. |
| ... | ... | @@ -166,7 +166,7 @@ pub fn span_lint_and_help<T: LintContext>( |
| 166 | 166 | }); |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | /// Like `span_lint` but with a `note` section instead of a `help` message. | |
| 169 | /// Like [`span_lint`] but with a `note` section instead of a `help` message. | |
| 170 | 170 | /// |
| 171 | 171 | /// The `note` message is presented separately from the main lint message |
| 172 | 172 | /// and is attached to a specific span: |
| ... | ... | @@ -226,7 +226,7 @@ pub fn span_lint_and_note<T: LintContext>( |
| 226 | 226 | }); |
| 227 | 227 | } |
| 228 | 228 | |
| 229 | /// Like `span_lint` but allows to add notes, help and suggestions using a closure. | |
| 229 | /// Like [`span_lint`] but allows to add notes, help and suggestions using a closure. | |
| 230 | 230 | /// |
| 231 | 231 | /// If you need to customize your lint output a lot, use this function. |
| 232 | 232 | /// If you change the signature, remember to update the internal lint `CollapsibleCalls` |
src/tools/clippy/clippy_utils/src/lib.rs+16-6| ... | ... | @@ -122,7 +122,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind}; |
| 122 | 122 | use rustc_span::source_map::SourceMap; |
| 123 | 123 | use rustc_span::symbol::{Ident, Symbol, kw}; |
| 124 | 124 | use rustc_span::{InnerSpan, Span}; |
| 125 | use source::walk_span_to_context; | |
| 125 | use source::{SpanRangeExt, walk_span_to_context}; | |
| 126 | 126 | use visitors::{Visitable, for_each_unconsumed_temporary}; |
| 127 | 127 | |
| 128 | 128 | use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; |
| ... | ... | @@ -1886,10 +1886,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { |
| 1886 | 1886 | _ => None, |
| 1887 | 1887 | }; |
| 1888 | 1888 | |
| 1889 | did.is_some_and(|did| find_attr!( | |
| 1890 | cx.tcx.get_all_attrs(did), | |
| 1891 | AttributeKind::MustUse { ..} | |
| 1892 | )) | |
| 1889 | did.is_some_and(|did| find_attr!(cx.tcx.get_all_attrs(did), AttributeKind::MustUse { .. })) | |
| 1893 | 1890 | } |
| 1894 | 1891 | |
| 1895 | 1892 | /// Checks if a function's body represents the identity function. Looks for bodies of the form: |
| ... | ... | @@ -2713,7 +2710,7 @@ impl<'tcx> ExprUseNode<'tcx> { |
| 2713 | 2710 | } |
| 2714 | 2711 | |
| 2715 | 2712 | /// Gets the context an expression's value is used in. |
| 2716 | pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprUseCtxt<'tcx> { | |
| 2713 | pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtxt<'tcx> { | |
| 2717 | 2714 | let mut adjustments = [].as_slice(); |
| 2718 | 2715 | let mut is_ty_unified = false; |
| 2719 | 2716 | let mut moved_before_use = false; |
| ... | ... | @@ -2790,6 +2787,19 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { |
| 2790 | 2787 | }); |
| 2791 | 2788 | } |
| 2792 | 2789 | |
| 2790 | /// Checks whether a given span has any significant token. A significant token is a non-whitespace | |
| 2791 | /// token, including comments unless `skip_comments` is set. | |
| 2792 | /// This is useful to determine if there are any actual code tokens in the span that are omitted in | |
| 2793 | /// the late pass, such as platform-specific code. | |
| 2794 | pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool { | |
| 2795 | matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)| | |
| 2796 | match token { | |
| 2797 | TokenKind::Whitespace => false, | |
| 2798 | TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments, | |
| 2799 | _ => true, | |
| 2800 | } | |
| 2801 | )) | |
| 2802 | } | |
| 2793 | 2803 | /// Returns all the comments a given span contains |
| 2794 | 2804 | /// |
| 2795 | 2805 | /// Comments are returned wrapped with their relevant delimiters |
src/tools/clippy/clippy_utils/src/msrvs.rs+2-1| ... | ... | @@ -24,7 +24,7 @@ macro_rules! msrv_aliases { |
| 24 | 24 | // names may refer to stabilized feature flags or library items |
| 25 | 25 | msrv_aliases! { |
| 26 | 26 | 1,88,0 { LET_CHAINS } |
| 27 | 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT } | |
| 27 | 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF } | |
| 28 | 28 | 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL } |
| 29 | 29 | 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } |
| 30 | 30 | 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } |
| ... | ... | @@ -42,6 +42,7 @@ msrv_aliases! { |
| 42 | 42 | 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } |
| 43 | 43 | 1,63,0 { CLONE_INTO, CONST_SLICE_FROM_REF } |
| 44 | 44 | 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN } |
| 45 | 1,61,0 { CONST_FN_TRAIT_BOUND } | |
| 45 | 46 | 1,60,0 { ABS_DIFF } |
| 46 | 47 | 1,59,0 { THREAD_LOCAL_CONST_INIT } |
| 47 | 48 | 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } |
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs+15| ... | ... | @@ -32,6 +32,21 @@ pub fn is_min_const_fn<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, msrv: Ms |
| 32 | 32 | for local in &body.local_decls { |
| 33 | 33 | check_ty(cx, local.ty, local.source_info.span, msrv)?; |
| 34 | 34 | } |
| 35 | if !msrv.meets(cx, msrvs::CONST_FN_TRAIT_BOUND) | |
| 36 | && let Some(sized_did) = cx.tcx.lang_items().sized_trait() | |
| 37 | && let Some(meta_sized_did) = cx.tcx.lang_items().meta_sized_trait() | |
| 38 | && cx.tcx.param_env(def_id).caller_bounds().iter().any(|bound| { | |
| 39 | bound.as_trait_clause().is_some_and(|clause| { | |
| 40 | let did = clause.def_id(); | |
| 41 | did != sized_did && did != meta_sized_did | |
| 42 | }) | |
| 43 | }) | |
| 44 | { | |
| 45 | return Err(( | |
| 46 | body.span, | |
| 47 | "non-`Sized` trait clause before `const_fn_trait_bound` is stabilized".into(), | |
| 48 | )); | |
| 49 | } | |
| 35 | 50 | // impl trait is gone in MIR, so check the return type manually |
| 36 | 51 | check_ty( |
| 37 | 52 | cx, |
src/tools/clippy/clippy_utils/src/sugg.rs+21-1| ... | ... | @@ -494,7 +494,17 @@ impl<T: Display> Display for ParenHelper<T> { |
| 494 | 494 | /// operators have the same |
| 495 | 495 | /// precedence. |
| 496 | 496 | pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> { |
| 497 | Sugg::MaybeParen(format!("{op}{}", expr.maybe_paren()).into()) | |
| 497 | // If the `expr` starts with `op` already, do not add wrap it in | |
| 498 | // parentheses. | |
| 499 | let expr = if let Sugg::MaybeParen(ref sugg) = expr | |
| 500 | && !has_enclosing_paren(sugg) | |
| 501 | && sugg.starts_with(op) | |
| 502 | { | |
| 503 | expr | |
| 504 | } else { | |
| 505 | expr.maybe_paren() | |
| 506 | }; | |
| 507 | Sugg::MaybeParen(format!("{op}{expr}").into()) | |
| 498 | 508 | } |
| 499 | 509 | |
| 500 | 510 | /// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary. |
| ... | ... | @@ -1016,6 +1026,16 @@ mod test { |
| 1016 | 1026 | let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "(1 + 1)".into(), "(1 + 1)".into()); |
| 1017 | 1027 | assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_paren().to_string()); |
| 1018 | 1028 | } |
| 1029 | ||
| 1030 | #[test] | |
| 1031 | fn unop_parenthesize() { | |
| 1032 | let sugg = Sugg::NonParen("x".into()).mut_addr(); | |
| 1033 | assert_eq!("&mut x", sugg.to_string()); | |
| 1034 | let sugg = sugg.mut_addr(); | |
| 1035 | assert_eq!("&mut &mut x", sugg.to_string()); | |
| 1036 | assert_eq!("(&mut &mut x)", sugg.maybe_paren().to_string()); | |
| 1037 | } | |
| 1038 | ||
| 1019 | 1039 | #[test] |
| 1020 | 1040 | fn not_op() { |
| 1021 | 1041 | use ast::BinOpKind::{Add, And, Eq, Ge, Gt, Le, Lt, Ne, Or}; |
src/tools/clippy/clippy_utils/src/sym.rs+1-4| ... | ... | @@ -46,7 +46,6 @@ generate! { |
| 46 | 46 | DOUBLE_QUOTE: "\"", |
| 47 | 47 | Deserialize, |
| 48 | 48 | EarlyLintPass, |
| 49 | ErrorKind, | |
| 50 | 49 | IntoIter, |
| 51 | 50 | Itertools, |
| 52 | 51 | LF: "\n", |
| ... | ... | @@ -65,7 +64,6 @@ generate! { |
| 65 | 64 | RegexBuilder, |
| 66 | 65 | RegexSet, |
| 67 | 66 | Start, |
| 68 | Step, | |
| 69 | 67 | Symbol, |
| 70 | 68 | SyntaxContext, |
| 71 | 69 | TBD, |
| ... | ... | @@ -158,7 +156,6 @@ generate! { |
| 158 | 156 | from_ne_bytes, |
| 159 | 157 | from_ptr, |
| 160 | 158 | from_raw, |
| 161 | from_ref, | |
| 162 | 159 | from_str, |
| 163 | 160 | from_str_radix, |
| 164 | 161 | fs, |
| ... | ... | @@ -166,6 +163,7 @@ generate! { |
| 166 | 163 | futures_util, |
| 167 | 164 | get, |
| 168 | 165 | get_mut, |
| 166 | get_or_insert, | |
| 169 | 167 | get_or_insert_with, |
| 170 | 168 | get_unchecked, |
| 171 | 169 | get_unchecked_mut, |
| ... | ... | @@ -216,7 +214,6 @@ generate! { |
| 216 | 214 | max_by_key, |
| 217 | 215 | max_value, |
| 218 | 216 | maximum, |
| 219 | mem, | |
| 220 | 217 | min, |
| 221 | 218 | min_by, |
| 222 | 219 | min_by_key, |
src/tools/clippy/clippy_utils/src/ty/mod.rs+10-14| ... | ... | @@ -6,6 +6,7 @@ use core::ops::ControlFlow; |
| 6 | 6 | use itertools::Itertools; |
| 7 | 7 | use rustc_abi::VariantIdx; |
| 8 | 8 | use rustc_ast::ast::Mutability; |
| 9 | use rustc_attr_data_structures::{AttributeKind, find_attr}; | |
| 9 | 10 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
| 10 | 11 | use rustc_hir as hir; |
| 11 | 12 | use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; |
| ... | ... | @@ -20,8 +21,8 @@ use rustc_middle::traits::EvaluationResult; |
| 20 | 21 | use rustc_middle::ty::layout::ValidityRequirement; |
| 21 | 22 | use rustc_middle::ty::{ |
| 22 | 23 | self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, |
| 23 | GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, | |
| 24 | TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, | |
| 24 | GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, | |
| 25 | TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, | |
| 25 | 26 | }; |
| 26 | 27 | use rustc_span::symbol::Ident; |
| 27 | 28 | use rustc_span::{DUMMY_SP, Span, Symbol, sym}; |
| ... | ... | @@ -31,8 +32,6 @@ use rustc_trait_selection::traits::{Obligation, ObligationCause}; |
| 31 | 32 | use std::assert_matches::debug_assert_matches; |
| 32 | 33 | use std::collections::hash_map::Entry; |
| 33 | 34 | use std::iter; |
| 34 | use rustc_attr_data_structures::find_attr; | |
| 35 | use rustc_attr_data_structures::AttributeKind; | |
| 36 | 35 | |
| 37 | 36 | use crate::path_res; |
| 38 | 37 | use crate::paths::{PathNS, lookup_path_str}; |
| ... | ... | @@ -328,14 +327,8 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { |
| 328 | 327 | // Returns whether the type has #[must_use] attribute |
| 329 | 328 | pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { |
| 330 | 329 | match ty.kind() { |
| 331 | ty::Adt(adt, _) => find_attr!( | |
| 332 | cx.tcx.get_all_attrs(adt.did()), | |
| 333 | AttributeKind::MustUse { ..} | |
| 334 | ), | |
| 335 | ty::Foreign(did) => find_attr!( | |
| 336 | cx.tcx.get_all_attrs(*did), | |
| 337 | AttributeKind::MustUse { ..} | |
| 338 | ), | |
| 330 | ty::Adt(adt, _) => find_attr!(cx.tcx.get_all_attrs(adt.did()), AttributeKind::MustUse { .. }), | |
| 331 | ty::Foreign(did) => find_attr!(cx.tcx.get_all_attrs(*did), AttributeKind::MustUse { .. }), | |
| 339 | 332 | ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => { |
| 340 | 333 | // for the Array case we don't need to care for the len == 0 case |
| 341 | 334 | // because we don't want to lint functions returning empty arrays |
| ... | ... | @@ -345,7 +338,10 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { |
| 345 | 338 | ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => { |
| 346 | 339 | for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() { |
| 347 | 340 | if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() |
| 348 | && find_attr!(cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id), AttributeKind::MustUse { ..}) | |
| 341 | && find_attr!( | |
| 342 | cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id), | |
| 343 | AttributeKind::MustUse { .. } | |
| 344 | ) | |
| 349 | 345 | { |
| 350 | 346 | return true; |
| 351 | 347 | } |
| ... | ... | @@ -355,7 +351,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { |
| 355 | 351 | ty::Dynamic(binder, _, _) => { |
| 356 | 352 | for predicate in *binder { |
| 357 | 353 | if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() |
| 358 | && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { ..}) | |
| 354 | && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { .. }) | |
| 359 | 355 | { |
| 360 | 356 | return true; |
| 361 | 357 | } |
src/tools/clippy/declare_clippy_lint/Cargo.toml created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | [package] | |
| 2 | name = "declare_clippy_lint" | |
| 3 | version = "0.1.90" | |
| 4 | edition = "2024" | |
| 5 | repository = "https://github.com/rust-lang/rust-clippy" | |
| 6 | license = "MIT OR Apache-2.0" | |
| 7 | ||
| 8 | [package.metadata.rust-analyzer] | |
| 9 | # This crate uses #[feature(rustc_private)] | |
| 10 | rustc_private = true |
src/tools/clippy/declare_clippy_lint/src/lib.rs created+280| ... | ... | @@ -0,0 +1,280 @@ |
| 1 | #![feature(macro_metavar_expr_concat, rustc_private)] | |
| 2 | ||
| 3 | extern crate rustc_lint; | |
| 4 | ||
| 5 | use rustc_lint::{Lint, LintId, LintStore}; | |
| 6 | ||
| 7 | // Needed by `declare_clippy_lint!`. | |
| 8 | pub extern crate rustc_session; | |
| 9 | ||
| 10 | #[derive(Default)] | |
| 11 | pub struct LintListBuilder { | |
| 12 | lints: Vec<&'static Lint>, | |
| 13 | all: Vec<LintId>, | |
| 14 | cargo: Vec<LintId>, | |
| 15 | complexity: Vec<LintId>, | |
| 16 | correctness: Vec<LintId>, | |
| 17 | nursery: Vec<LintId>, | |
| 18 | pedantic: Vec<LintId>, | |
| 19 | perf: Vec<LintId>, | |
| 20 | restriction: Vec<LintId>, | |
| 21 | style: Vec<LintId>, | |
| 22 | suspicious: Vec<LintId>, | |
| 23 | } | |
| 24 | impl LintListBuilder { | |
| 25 | pub fn insert(&mut self, lints: &[&LintInfo]) { | |
| 26 | #[allow(clippy::enum_glob_use)] | |
| 27 | use LintCategory::*; | |
| 28 | ||
| 29 | self.lints.extend(lints.iter().map(|&x| x.lint)); | |
| 30 | for &&LintInfo { lint, category, .. } in lints { | |
| 31 | let (all, cat) = match category { | |
| 32 | Complexity => (Some(&mut self.all), &mut self.complexity), | |
| 33 | Correctness => (Some(&mut self.all), &mut self.correctness), | |
| 34 | Perf => (Some(&mut self.all), &mut self.perf), | |
| 35 | Style => (Some(&mut self.all), &mut self.style), | |
| 36 | Suspicious => (Some(&mut self.all), &mut self.suspicious), | |
| 37 | Cargo => (None, &mut self.cargo), | |
| 38 | Nursery => (None, &mut self.nursery), | |
| 39 | Pedantic => (None, &mut self.pedantic), | |
| 40 | Restriction => (None, &mut self.restriction), | |
| 41 | }; | |
| 42 | if let Some(all) = all { | |
| 43 | all.push(LintId::of(lint)); | |
| 44 | } | |
| 45 | cat.push(LintId::of(lint)); | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | pub fn register(self, store: &mut LintStore) { | |
| 50 | store.register_lints(&self.lints); | |
| 51 | store.register_group(true, "clippy::all", Some("clippy_all"), self.all); | |
| 52 | store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo); | |
| 53 | store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity); | |
| 54 | store.register_group( | |
| 55 | true, | |
| 56 | "clippy::correctness", | |
| 57 | Some("clippy_correctness"), | |
| 58 | self.correctness, | |
| 59 | ); | |
| 60 | store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery); | |
| 61 | store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic); | |
| 62 | store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf); | |
| 63 | store.register_group( | |
| 64 | true, | |
| 65 | "clippy::restriction", | |
| 66 | Some("clippy_restriction"), | |
| 67 | self.restriction, | |
| 68 | ); | |
| 69 | store.register_group(true, "clippy::style", Some("clippy_style"), self.style); | |
| 70 | store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious); | |
| 71 | } | |
| 72 | } | |
| 73 | ||
| 74 | #[derive(Copy, Clone, Debug)] | |
| 75 | pub enum LintCategory { | |
| 76 | Cargo, | |
| 77 | Complexity, | |
| 78 | Correctness, | |
| 79 | Nursery, | |
| 80 | Pedantic, | |
| 81 | Perf, | |
| 82 | Restriction, | |
| 83 | Style, | |
| 84 | Suspicious, | |
| 85 | } | |
| 86 | impl LintCategory { | |
| 87 | #[must_use] | |
| 88 | pub fn name(self) -> &'static str { | |
| 89 | match self { | |
| 90 | Self::Cargo => "cargo", | |
| 91 | Self::Complexity => "complexity", | |
| 92 | Self::Correctness => "correctness", | |
| 93 | Self::Nursery => "nursery", | |
| 94 | Self::Pedantic => "pedantic", | |
| 95 | Self::Perf => "perf", | |
| 96 | Self::Restriction => "restriction", | |
| 97 | Self::Style => "style", | |
| 98 | Self::Suspicious => "suspicious", | |
| 99 | } | |
| 100 | } | |
| 101 | } | |
| 102 | ||
| 103 | pub struct LintInfo { | |
| 104 | pub lint: &'static Lint, | |
| 105 | pub category: LintCategory, | |
| 106 | pub explanation: &'static str, | |
| 107 | /// e.g. `clippy_lints/src/absolute_paths.rs#43` | |
| 108 | pub location: &'static str, | |
| 109 | pub version: &'static str, | |
| 110 | } | |
| 111 | ||
| 112 | impl LintInfo { | |
| 113 | /// Returns the lint name in lowercase without the `clippy::` prefix | |
| 114 | #[must_use] | |
| 115 | #[expect(clippy::missing_panics_doc)] | |
| 116 | pub fn name_lower(&self) -> String { | |
| 117 | self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase() | |
| 118 | } | |
| 119 | } | |
| 120 | ||
| 121 | #[macro_export] | |
| 122 | macro_rules! declare_clippy_lint_inner { | |
| 123 | ( | |
| 124 | $(#[doc = $docs:literal])* | |
| 125 | #[clippy::version = $version:literal] | |
| 126 | $vis:vis $lint_name:ident, | |
| 127 | $level:ident, | |
| 128 | $category:ident, | |
| 129 | $desc:literal | |
| 130 | $(, @eval_always = $eval_always:literal)? | |
| 131 | ) => { | |
| 132 | $crate::rustc_session::declare_tool_lint! { | |
| 133 | $(#[doc = $docs])* | |
| 134 | #[clippy::version = $version] | |
| 135 | $vis clippy::$lint_name, | |
| 136 | $level, | |
| 137 | $desc, | |
| 138 | report_in_external_macro:true | |
| 139 | $(, @eval_always = $eval_always)? | |
| 140 | } | |
| 141 | ||
| 142 | pub(crate) static ${concat($lint_name, _INFO)}: &'static $crate::LintInfo = &$crate::LintInfo { | |
| 143 | lint: $lint_name, | |
| 144 | category: $crate::LintCategory::$category, | |
| 145 | explanation: concat!($($docs,"\n",)*), | |
| 146 | location: concat!(file!(), "#L", line!()), | |
| 147 | version: $version, | |
| 148 | }; | |
| 149 | }; | |
| 150 | } | |
| 151 | ||
| 152 | #[macro_export] | |
| 153 | macro_rules! declare_clippy_lint { | |
| 154 | ( | |
| 155 | $(#[$($meta:tt)*])* | |
| 156 | $vis:vis $lint_name:ident, | |
| 157 | correctness, | |
| 158 | $($rest:tt)* | |
| 159 | ) => { | |
| 160 | $crate::declare_clippy_lint_inner! { | |
| 161 | $(#[$($meta)*])* | |
| 162 | $vis $lint_name, | |
| 163 | Deny, | |
| 164 | Correctness, | |
| 165 | $($rest)* | |
| 166 | } | |
| 167 | }; | |
| 168 | ( | |
| 169 | $(#[$($meta:tt)*])* | |
| 170 | $vis:vis $lint_name:ident, | |
| 171 | complexity, | |
| 172 | $($rest:tt)* | |
| 173 | ) => { | |
| 174 | $crate::declare_clippy_lint_inner! { | |
| 175 | $(#[$($meta)*])* | |
| 176 | $vis $lint_name, | |
| 177 | Warn, | |
| 178 | Complexity, | |
| 179 | $($rest)* | |
| 180 | } | |
| 181 | }; | |
| 182 | ( | |
| 183 | $(#[$($meta:tt)*])* | |
| 184 | $vis:vis $lint_name:ident, | |
| 185 | perf, | |
| 186 | $($rest:tt)* | |
| 187 | ) => { | |
| 188 | $crate::declare_clippy_lint_inner! { | |
| 189 | $(#[$($meta)*])* | |
| 190 | $vis $lint_name, | |
| 191 | Warn, | |
| 192 | Perf, | |
| 193 | $($rest)* | |
| 194 | } | |
| 195 | }; | |
| 196 | ( | |
| 197 | $(#[$($meta:tt)*])* | |
| 198 | $vis:vis $lint_name:ident, | |
| 199 | style, | |
| 200 | $($rest:tt)* | |
| 201 | ) => { | |
| 202 | $crate::declare_clippy_lint_inner! { | |
| 203 | $(#[$($meta)*])* | |
| 204 | $vis $lint_name, | |
| 205 | Warn, | |
| 206 | Style, | |
| 207 | $($rest)* | |
| 208 | } | |
| 209 | }; | |
| 210 | ( | |
| 211 | $(#[$($meta:tt)*])* | |
| 212 | $vis:vis $lint_name:ident, | |
| 213 | suspicious, | |
| 214 | $($rest:tt)* | |
| 215 | ) => { | |
| 216 | $crate::declare_clippy_lint_inner! { | |
| 217 | $(#[$($meta)*])* | |
| 218 | $vis $lint_name, | |
| 219 | Warn, | |
| 220 | Suspicious, | |
| 221 | $($rest)* | |
| 222 | } | |
| 223 | }; | |
| 224 | ( | |
| 225 | $(#[$($meta:tt)*])* | |
| 226 | $vis:vis $lint_name:ident, | |
| 227 | cargo, | |
| 228 | $($rest:tt)* | |
| 229 | ) => { | |
| 230 | $crate::declare_clippy_lint_inner! { | |
| 231 | $(#[$($meta)*])* | |
| 232 | $vis $lint_name, | |
| 233 | Allow, | |
| 234 | Cargo, | |
| 235 | $($rest)* | |
| 236 | } | |
| 237 | }; | |
| 238 | ( | |
| 239 | $(#[$($meta:tt)*])* | |
| 240 | $vis:vis $lint_name:ident, | |
| 241 | nursery, | |
| 242 | $($rest:tt)* | |
| 243 | ) => { | |
| 244 | $crate::declare_clippy_lint_inner! { | |
| 245 | $(#[$($meta)*])* | |
| 246 | $vis $lint_name, | |
| 247 | Allow, | |
| 248 | Nursery, | |
| 249 | $($rest)* | |
| 250 | } | |
| 251 | }; | |
| 252 | ( | |
| 253 | $(#[$($meta:tt)*])* | |
| 254 | $vis:vis $lint_name:ident, | |
| 255 | pedantic, | |
| 256 | $($rest:tt)* | |
| 257 | ) => { | |
| 258 | $crate::declare_clippy_lint_inner! { | |
| 259 | $(#[$($meta)*])* | |
| 260 | $vis $lint_name, | |
| 261 | Allow, | |
| 262 | Pedantic, | |
| 263 | $($rest)* | |
| 264 | } | |
| 265 | }; | |
| 266 | ( | |
| 267 | $(#[$($meta:tt)*])* | |
| 268 | $vis:vis $lint_name:ident, | |
| 269 | restriction, | |
| 270 | $($rest:tt)* | |
| 271 | ) => { | |
| 272 | $crate::declare_clippy_lint_inner! { | |
| 273 | $(#[$($meta)*])* | |
| 274 | $vis $lint_name, | |
| 275 | Allow, | |
| 276 | Restriction, | |
| 277 | $($rest)* | |
| 278 | } | |
| 279 | }; | |
| 280 | } |
src/tools/clippy/lintcheck/src/main.rs+1-1| ... | ... | @@ -45,7 +45,7 @@ use rayon::prelude::*; |
| 45 | 45 | |
| 46 | 46 | #[must_use] |
| 47 | 47 | pub fn target_dir() -> String { |
| 48 | env::var("CARGO_TARGET_DIR").unwrap_or("target".to_owned()) | |
| 48 | env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target".to_owned()) | |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | fn lintcheck_sources() -> String { |
src/tools/clippy/rust-toolchain.toml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | [toolchain] |
| 2 | 2 | # begin autogenerated nightly |
| 3 | channel = "nightly-2025-06-12" | |
| 3 | channel = "nightly-2025-06-26" | |
| 4 | 4 | # end autogenerated nightly |
| 5 | 5 | components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] |
| 6 | 6 | profile = "minimal" |
src/tools/clippy/src/driver.rs+7-1| ... | ... | @@ -19,6 +19,7 @@ extern crate rustc_span; |
| 19 | 19 | extern crate tikv_jemalloc_sys as jemalloc_sys; |
| 20 | 20 | |
| 21 | 21 | use clippy_utils::sym; |
| 22 | use declare_clippy_lint::LintListBuilder; | |
| 22 | 23 | use rustc_interface::interface; |
| 23 | 24 | use rustc_session::EarlyDiagCtxt; |
| 24 | 25 | use rustc_session::config::ErrorOutputType; |
| ... | ... | @@ -156,8 +157,13 @@ impl rustc_driver::Callbacks for ClippyCallbacks { |
| 156 | 157 | (previous)(sess, lint_store); |
| 157 | 158 | } |
| 158 | 159 | |
| 160 | let mut list_builder = LintListBuilder::default(); | |
| 161 | list_builder.insert(clippy_lints::declared_lints::LINTS); | |
| 162 | list_builder.register(lint_store); | |
| 163 | ||
| 159 | 164 | let conf = clippy_config::Conf::read(sess, &conf_path); |
| 160 | clippy_lints::register_lints(lint_store, conf); | |
| 165 | clippy_lints::register_lint_passes(lint_store, conf); | |
| 166 | ||
| 161 | 167 | #[cfg(feature = "internal")] |
| 162 | 168 | clippy_lints_internal::register_lints(lint_store); |
| 163 | 169 | })); |
src/tools/clippy/src/main.rs+1-1| ... | ... | @@ -107,7 +107,7 @@ impl ClippyCmd { |
| 107 | 107 | } |
| 108 | 108 | |
| 109 | 109 | fn into_std_cmd(self) -> Command { |
| 110 | let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into())); | |
| 110 | let mut cmd = Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())); | |
| 111 | 111 | let clippy_args: String = self |
| 112 | 112 | .clippy_args |
| 113 | 113 | .iter() |
src/tools/clippy/tests/compile-test.rs+3-3| ... | ... | @@ -7,9 +7,9 @@ use askama::filters::Safe; |
| 7 | 7 | use cargo_metadata::Message; |
| 8 | 8 | use cargo_metadata::diagnostic::{Applicability, Diagnostic}; |
| 9 | 9 | use clippy_config::ClippyConfiguration; |
| 10 | use clippy_lints::LintInfo; | |
| 11 | 10 | use clippy_lints::declared_lints::LINTS; |
| 12 | 11 | use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; |
| 12 | use declare_clippy_lint::LintInfo; | |
| 13 | 13 | use pulldown_cmark::{Options, Parser, html}; |
| 14 | 14 | use serde::Deserialize; |
| 15 | 15 | use test_utils::IS_RUSTC_TEST_SUITE; |
| ... | ... | @@ -568,10 +568,10 @@ impl LintMetadata { |
| 568 | 568 | Self { |
| 569 | 569 | id: name, |
| 570 | 570 | id_location: Some(lint.location), |
| 571 | group: lint.category_str(), | |
| 571 | group: lint.category.name(), | |
| 572 | 572 | level: lint.lint.default_level.as_str(), |
| 573 | 573 | docs, |
| 574 | version: lint.version.unwrap(), | |
| 574 | version: lint.version, | |
| 575 | 575 | applicability, |
| 576 | 576 | } |
| 577 | 577 | } |
src/tools/clippy/tests/dogfood.rs+1| ... | ... | @@ -40,6 +40,7 @@ fn dogfood() { |
| 40 | 40 | "clippy_lints", |
| 41 | 41 | "clippy_utils", |
| 42 | 42 | "clippy_config", |
| 43 | "declare_clippy_lint", | |
| 43 | 44 | "lintcheck", |
| 44 | 45 | "rustc_tools_util", |
| 45 | 46 | ] { |
src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.fixed created+50| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | #![allow(clippy::eq_op, clippy::nonminimal_bool)] | |
| 2 | ||
| 3 | #[rustfmt::skip] | |
| 4 | #[warn(clippy::collapsible_if)] | |
| 5 | fn main() { | |
| 6 | let (x, y) = ("hello", "world"); | |
| 7 | ||
| 8 | if x == "hello" { | |
| 9 | todo!() | |
| 10 | } | |
| 11 | // Comment must be kept | |
| 12 | else if y == "world" { | |
| 13 | println!("Hello world!"); | |
| 14 | } | |
| 15 | //~^^^^^^ collapsible_else_if | |
| 16 | ||
| 17 | if x == "hello" { | |
| 18 | todo!() | |
| 19 | } // Inner comment | |
| 20 | else if y == "world" { | |
| 21 | println!("Hello world!"); | |
| 22 | } | |
| 23 | //~^^^^^ collapsible_else_if | |
| 24 | ||
| 25 | if x == "hello" { | |
| 26 | todo!() | |
| 27 | } | |
| 28 | /* Inner comment */ | |
| 29 | else if y == "world" { | |
| 30 | println!("Hello world!"); | |
| 31 | } | |
| 32 | //~^^^^^^ collapsible_else_if | |
| 33 | ||
| 34 | if x == "hello" { | |
| 35 | todo!() | |
| 36 | } /* Inner comment */ | |
| 37 | else if y == "world" { | |
| 38 | println!("Hello world!"); | |
| 39 | } | |
| 40 | //~^^^^^ collapsible_else_if | |
| 41 | ||
| 42 | if x == "hello" { | |
| 43 | todo!() | |
| 44 | } /* This should not be removed */ /* So does this */ | |
| 45 | // Comment must be kept | |
| 46 | else if y == "world" { | |
| 47 | println!("Hello world!"); | |
| 48 | } | |
| 49 | //~^^^^^^ collapsible_else_if | |
| 50 | } |
src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.rs created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | #![allow(clippy::eq_op, clippy::nonminimal_bool)] | |
| 2 | ||
| 3 | #[rustfmt::skip] | |
| 4 | #[warn(clippy::collapsible_if)] | |
| 5 | fn main() { | |
| 6 | let (x, y) = ("hello", "world"); | |
| 7 | ||
| 8 | if x == "hello" { | |
| 9 | todo!() | |
| 10 | } else { | |
| 11 | // Comment must be kept | |
| 12 | if y == "world" { | |
| 13 | println!("Hello world!"); | |
| 14 | } | |
| 15 | } | |
| 16 | //~^^^^^^ collapsible_else_if | |
| 17 | ||
| 18 | if x == "hello" { | |
| 19 | todo!() | |
| 20 | } else { // Inner comment | |
| 21 | if y == "world" { | |
| 22 | println!("Hello world!"); | |
| 23 | } | |
| 24 | } | |
| 25 | //~^^^^^ collapsible_else_if | |
| 26 | ||
| 27 | if x == "hello" { | |
| 28 | todo!() | |
| 29 | } else { | |
| 30 | /* Inner comment */ | |
| 31 | if y == "world" { | |
| 32 | println!("Hello world!"); | |
| 33 | } | |
| 34 | } | |
| 35 | //~^^^^^^ collapsible_else_if | |
| 36 | ||
| 37 | if x == "hello" { | |
| 38 | todo!() | |
| 39 | } else { /* Inner comment */ | |
| 40 | if y == "world" { | |
| 41 | println!("Hello world!"); | |
| 42 | } | |
| 43 | } | |
| 44 | //~^^^^^ collapsible_else_if | |
| 45 | ||
| 46 | if x == "hello" { | |
| 47 | todo!() | |
| 48 | } /* This should not be removed */ else /* So does this */ { | |
| 49 | // Comment must be kept | |
| 50 | if y == "world" { | |
| 51 | println!("Hello world!"); | |
| 52 | } | |
| 53 | } | |
| 54 | //~^^^^^^ collapsible_else_if | |
| 55 | } |
src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_else_if.stderr created+105| ... | ... | @@ -0,0 +1,105 @@ |
| 1 | error: this `else { if .. }` block can be collapsed | |
| 2 | --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:10:12 | |
| 3 | | | |
| 4 | LL | } else { | |
| 5 | | ____________^ | |
| 6 | LL | | // Comment must be kept | |
| 7 | LL | | if y == "world" { | |
| 8 | LL | | println!("Hello world!"); | |
| 9 | LL | | } | |
| 10 | LL | | } | |
| 11 | | |_____^ | |
| 12 | | | |
| 13 | = note: `-D clippy::collapsible-else-if` implied by `-D warnings` | |
| 14 | = help: to override `-D warnings` add `#[allow(clippy::collapsible_else_if)]` | |
| 15 | help: collapse nested if block | |
| 16 | | | |
| 17 | LL ~ } | |
| 18 | LL | // Comment must be kept | |
| 19 | LL ~ else if y == "world" { | |
| 20 | LL | println!("Hello world!"); | |
| 21 | LL ~ } | |
| 22 | | | |
| 23 | ||
| 24 | error: this `else { if .. }` block can be collapsed | |
| 25 | --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:20:12 | |
| 26 | | | |
| 27 | LL | } else { // Inner comment | |
| 28 | | ____________^ | |
| 29 | LL | | if y == "world" { | |
| 30 | LL | | println!("Hello world!"); | |
| 31 | LL | | } | |
| 32 | LL | | } | |
| 33 | | |_____^ | |
| 34 | | | |
| 35 | help: collapse nested if block | |
| 36 | | | |
| 37 | LL ~ } // Inner comment | |
| 38 | LL ~ else if y == "world" { | |
| 39 | LL | println!("Hello world!"); | |
| 40 | LL ~ } | |
| 41 | | | |
| 42 | ||
| 43 | error: this `else { if .. }` block can be collapsed | |
| 44 | --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:29:12 | |
| 45 | | | |
| 46 | LL | } else { | |
| 47 | | ____________^ | |
| 48 | LL | | /* Inner comment */ | |
| 49 | LL | | if y == "world" { | |
| 50 | LL | | println!("Hello world!"); | |
| 51 | LL | | } | |
| 52 | LL | | } | |
| 53 | | |_____^ | |
| 54 | | | |
| 55 | help: collapse nested if block | |
| 56 | | | |
| 57 | LL ~ } | |
| 58 | LL | /* Inner comment */ | |
| 59 | LL ~ else if y == "world" { | |
| 60 | LL | println!("Hello world!"); | |
| 61 | LL ~ } | |
| 62 | | | |
| 63 | ||
| 64 | error: this `else { if .. }` block can be collapsed | |
| 65 | --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:39:12 | |
| 66 | | | |
| 67 | LL | } else { /* Inner comment */ | |
| 68 | | ____________^ | |
| 69 | LL | | if y == "world" { | |
| 70 | LL | | println!("Hello world!"); | |
| 71 | LL | | } | |
| 72 | LL | | } | |
| 73 | | |_____^ | |
| 74 | | | |
| 75 | help: collapse nested if block | |
| 76 | | | |
| 77 | LL ~ } /* Inner comment */ | |
| 78 | LL ~ else if y == "world" { | |
| 79 | LL | println!("Hello world!"); | |
| 80 | LL ~ } | |
| 81 | | | |
| 82 | ||
| 83 | error: this `else { if .. }` block can be collapsed | |
| 84 | --> tests/ui-toml/collapsible_if/collapsible_else_if.rs:48:64 | |
| 85 | | | |
| 86 | LL | } /* This should not be removed */ else /* So does this */ { | |
| 87 | | ________________________________________________________________^ | |
| 88 | LL | | // Comment must be kept | |
| 89 | LL | | if y == "world" { | |
| 90 | LL | | println!("Hello world!"); | |
| 91 | LL | | } | |
| 92 | LL | | } | |
| 93 | | |_____^ | |
| 94 | | | |
| 95 | help: collapse nested if block | |
| 96 | | | |
| 97 | LL ~ } /* This should not be removed */ /* So does this */ | |
| 98 | LL | // Comment must be kept | |
| 99 | LL ~ else if y == "world" { | |
| 100 | LL | println!("Hello world!"); | |
| 101 | LL ~ } | |
| 102 | | | |
| 103 | ||
| 104 | error: aborting due to 5 previous errors | |
| 105 |
src/tools/clippy/tests/ui/borrow_deref_ref.fixed+47| ... | ... | @@ -124,3 +124,50 @@ mod issue_11346 { |
| 124 | 124 | //~^ borrow_deref_ref |
| 125 | 125 | } |
| 126 | 126 | } |
| 127 | ||
| 128 | fn issue_14934() { | |
| 129 | let x: &'static str = "x"; | |
| 130 | let y = "y".to_string(); | |
| 131 | { | |
| 132 | #[expect(clippy::toplevel_ref_arg)] | |
| 133 | let ref mut x = &*x; // Do not lint | |
| 134 | *x = &*y; | |
| 135 | } | |
| 136 | { | |
| 137 | let mut x = x; | |
| 138 | //~^ borrow_deref_ref | |
| 139 | x = &*y; | |
| 140 | } | |
| 141 | { | |
| 142 | #[expect(clippy::toplevel_ref_arg, clippy::needless_borrow)] | |
| 143 | let ref x = x; | |
| 144 | //~^ borrow_deref_ref | |
| 145 | } | |
| 146 | { | |
| 147 | #[expect(clippy::toplevel_ref_arg)] | |
| 148 | let ref mut x = std::convert::identity(x); | |
| 149 | //~^ borrow_deref_ref | |
| 150 | *x = &*y; | |
| 151 | } | |
| 152 | { | |
| 153 | #[derive(Clone)] | |
| 154 | struct S(&'static str); | |
| 155 | let s = S("foo"); | |
| 156 | #[expect(clippy::toplevel_ref_arg)] | |
| 157 | let ref mut x = &*s.0; // Do not lint | |
| 158 | *x = "bar"; | |
| 159 | #[expect(clippy::toplevel_ref_arg)] | |
| 160 | let ref mut x = s.clone().0; | |
| 161 | //~^ borrow_deref_ref | |
| 162 | *x = "bar"; | |
| 163 | #[expect(clippy::toplevel_ref_arg)] | |
| 164 | let ref mut x = &*std::convert::identity(&s).0; | |
| 165 | *x = "bar"; | |
| 166 | } | |
| 167 | { | |
| 168 | let y = &1; | |
| 169 | #[expect(clippy::toplevel_ref_arg)] | |
| 170 | let ref mut x = { y }; | |
| 171 | //~^ borrow_deref_ref | |
| 172 | } | |
| 173 | } |
src/tools/clippy/tests/ui/borrow_deref_ref.rs+47| ... | ... | @@ -124,3 +124,50 @@ mod issue_11346 { |
| 124 | 124 | //~^ borrow_deref_ref |
| 125 | 125 | } |
| 126 | 126 | } |
| 127 | ||
| 128 | fn issue_14934() { | |
| 129 | let x: &'static str = "x"; | |
| 130 | let y = "y".to_string(); | |
| 131 | { | |
| 132 | #[expect(clippy::toplevel_ref_arg)] | |
| 133 | let ref mut x = &*x; // Do not lint | |
| 134 | *x = &*y; | |
| 135 | } | |
| 136 | { | |
| 137 | let mut x = &*x; | |
| 138 | //~^ borrow_deref_ref | |
| 139 | x = &*y; | |
| 140 | } | |
| 141 | { | |
| 142 | #[expect(clippy::toplevel_ref_arg, clippy::needless_borrow)] | |
| 143 | let ref x = &*x; | |
| 144 | //~^ borrow_deref_ref | |
| 145 | } | |
| 146 | { | |
| 147 | #[expect(clippy::toplevel_ref_arg)] | |
| 148 | let ref mut x = &*std::convert::identity(x); | |
| 149 | //~^ borrow_deref_ref | |
| 150 | *x = &*y; | |
| 151 | } | |
| 152 | { | |
| 153 | #[derive(Clone)] | |
| 154 | struct S(&'static str); | |
| 155 | let s = S("foo"); | |
| 156 | #[expect(clippy::toplevel_ref_arg)] | |
| 157 | let ref mut x = &*s.0; // Do not lint | |
| 158 | *x = "bar"; | |
| 159 | #[expect(clippy::toplevel_ref_arg)] | |
| 160 | let ref mut x = &*s.clone().0; | |
| 161 | //~^ borrow_deref_ref | |
| 162 | *x = "bar"; | |
| 163 | #[expect(clippy::toplevel_ref_arg)] | |
| 164 | let ref mut x = &*std::convert::identity(&s).0; | |
| 165 | *x = "bar"; | |
| 166 | } | |
| 167 | { | |
| 168 | let y = &1; | |
| 169 | #[expect(clippy::toplevel_ref_arg)] | |
| 170 | let ref mut x = { &*y }; | |
| 171 | //~^ borrow_deref_ref | |
| 172 | } | |
| 173 | } |
src/tools/clippy/tests/ui/borrow_deref_ref.stderr+31-1| ... | ... | @@ -25,5 +25,35 @@ error: deref on an immutable reference |
| 25 | 25 | LL | (&*s).foo(); |
| 26 | 26 | | ^^^^^ help: if you would like to reborrow, try removing `&*`: `s` |
| 27 | 27 | |
| 28 | error: aborting due to 4 previous errors | |
| 28 | error: deref on an immutable reference | |
| 29 | --> tests/ui/borrow_deref_ref.rs:137:21 | |
| 30 | | | |
| 31 | LL | let mut x = &*x; | |
| 32 | | ^^^ help: if you would like to reborrow, try removing `&*`: `x` | |
| 33 | ||
| 34 | error: deref on an immutable reference | |
| 35 | --> tests/ui/borrow_deref_ref.rs:143:21 | |
| 36 | | | |
| 37 | LL | let ref x = &*x; | |
| 38 | | ^^^ help: if you would like to reborrow, try removing `&*`: `x` | |
| 39 | ||
| 40 | error: deref on an immutable reference | |
| 41 | --> tests/ui/borrow_deref_ref.rs:148:25 | |
| 42 | | | |
| 43 | LL | let ref mut x = &*std::convert::identity(x); | |
| 44 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `std::convert::identity(x)` | |
| 45 | ||
| 46 | error: deref on an immutable reference | |
| 47 | --> tests/ui/borrow_deref_ref.rs:160:25 | |
| 48 | | | |
| 49 | LL | let ref mut x = &*s.clone().0; | |
| 50 | | ^^^^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `s.clone().0` | |
| 51 | ||
| 52 | error: deref on an immutable reference | |
| 53 | --> tests/ui/borrow_deref_ref.rs:170:27 | |
| 54 | | | |
| 55 | LL | let ref mut x = { &*y }; | |
| 56 | | ^^^ help: if you would like to reborrow, try removing `&*`: `y` | |
| 57 | ||
| 58 | error: aborting due to 9 previous errors | |
| 29 | 59 |
src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs+16| ... | ... | @@ -218,4 +218,20 @@ fn main() { |
| 218 | 218 | let _ = &S::VALUE.1; //~ borrow_interior_mutable_const |
| 219 | 219 | let _ = &S::VALUE.2; |
| 220 | 220 | } |
| 221 | { | |
| 222 | pub struct Foo<T, const N: usize>(pub Entry<N>, pub T); | |
| 223 | ||
| 224 | pub struct Entry<const N: usize>(pub Cell<[u32; N]>); | |
| 225 | ||
| 226 | impl<const N: usize> Entry<N> { | |
| 227 | const INIT: Self = Self(Cell::new([42; N])); | |
| 228 | } | |
| 229 | ||
| 230 | impl<T, const N: usize> Foo<T, N> { | |
| 231 | pub fn make_foo(v: T) -> Self { | |
| 232 | // Used to ICE due to incorrect instantiation. | |
| 233 | Foo(Entry::INIT, v) | |
| 234 | } | |
| 235 | } | |
| 236 | } | |
| 221 | 237 | } |
src/tools/clippy/tests/ui/box_default.fixed+1-1| ... | ... | @@ -126,7 +126,7 @@ fn issue_10381() { |
| 126 | 126 | impl Bar for Foo {} |
| 127 | 127 | |
| 128 | 128 | fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> { |
| 129 | if i % 2 == 0 { | |
| 129 | if i.is_multiple_of(2) { | |
| 130 | 130 | Some(Box::new(Foo::default())) |
| 131 | 131 | } else { |
| 132 | 132 | None |
src/tools/clippy/tests/ui/box_default.rs+1-1| ... | ... | @@ -126,7 +126,7 @@ fn issue_10381() { |
| 126 | 126 | impl Bar for Foo {} |
| 127 | 127 | |
| 128 | 128 | fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> { |
| 129 | if i % 2 == 0 { | |
| 129 | if i.is_multiple_of(2) { | |
| 130 | 130 | Some(Box::new(Foo::default())) |
| 131 | 131 | } else { |
| 132 | 132 | None |
src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs+24| ... | ... | @@ -276,3 +276,27 @@ mod issue14873 { |
| 276 | 276 | } |
| 277 | 277 | } |
| 278 | 278 | } |
| 279 | ||
| 280 | fn issue15004() { | |
| 281 | let a = 12u32; | |
| 282 | let b = 13u32; | |
| 283 | let mut c = 8u32; | |
| 284 | ||
| 285 | let mut result = if b > a { | |
| 286 | c += 1; | |
| 287 | 0 | |
| 288 | } else { | |
| 289 | c += 2; | |
| 290 | 0 | |
| 291 | //~^ branches_sharing_code | |
| 292 | }; | |
| 293 | ||
| 294 | result = if b > a { | |
| 295 | c += 1; | |
| 296 | 1 | |
| 297 | } else { | |
| 298 | c += 2; | |
| 299 | 1 | |
| 300 | //~^ branches_sharing_code | |
| 301 | }; | |
| 302 | } |
src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr+31-1| ... | ... | @@ -172,5 +172,35 @@ LL ~ } |
| 172 | 172 | LL + let y = 1; |
| 173 | 173 | | |
| 174 | 174 | |
| 175 | error: aborting due to 10 previous errors | |
| 175 | error: all if blocks contain the same code at the end | |
| 176 | --> tests/ui/branches_sharing_code/shared_at_bottom.rs:290:5 | |
| 177 | | | |
| 178 | LL | / 0 | |
| 179 | LL | | | |
| 180 | LL | | }; | |
| 181 | | |_____^ | |
| 182 | | | |
| 183 | = note: the end suggestion probably needs some adjustments to use the expression result correctly | |
| 184 | help: consider moving these statements after the if | |
| 185 | | | |
| 186 | LL ~ } | |
| 187 | LL ~ 0; | |
| 188 | | | |
| 189 | ||
| 190 | error: all if blocks contain the same code at the end | |
| 191 | --> tests/ui/branches_sharing_code/shared_at_bottom.rs:299:5 | |
| 192 | | | |
| 193 | LL | / 1 | |
| 194 | LL | | | |
| 195 | LL | | }; | |
| 196 | | |_____^ | |
| 197 | | | |
| 198 | = note: the end suggestion probably needs some adjustments to use the expression result correctly | |
| 199 | help: consider moving these statements after the if | |
| 200 | | | |
| 201 | LL ~ } | |
| 202 | LL ~ 1; | |
| 203 | | | |
| 204 | ||
| 205 | error: aborting due to 12 previous errors | |
| 176 | 206 |
src/tools/clippy/tests/ui/collapsible_else_if.fixed+18| ... | ... | @@ -86,3 +86,21 @@ fn issue_7318() { |
| 86 | 86 | }else if false {} |
| 87 | 87 | //~^^^ collapsible_else_if |
| 88 | 88 | } |
| 89 | ||
| 90 | fn issue14799() { | |
| 91 | use std::ops::ControlFlow; | |
| 92 | ||
| 93 | let c: ControlFlow<_, ()> = ControlFlow::Break(Some(42)); | |
| 94 | if let ControlFlow::Break(Some(_)) = c { | |
| 95 | todo!(); | |
| 96 | } else { | |
| 97 | #[cfg(target_os = "freebsd")] | |
| 98 | todo!(); | |
| 99 | ||
| 100 | if let ControlFlow::Break(None) = c { | |
| 101 | todo!(); | |
| 102 | } else { | |
| 103 | todo!(); | |
| 104 | } | |
| 105 | } | |
| 106 | } |
src/tools/clippy/tests/ui/collapsible_else_if.rs+18| ... | ... | @@ -102,3 +102,21 @@ fn issue_7318() { |
| 102 | 102 | } |
| 103 | 103 | //~^^^ collapsible_else_if |
| 104 | 104 | } |
| 105 | ||
| 106 | fn issue14799() { | |
| 107 | use std::ops::ControlFlow; | |
| 108 | ||
| 109 | let c: ControlFlow<_, ()> = ControlFlow::Break(Some(42)); | |
| 110 | if let ControlFlow::Break(Some(_)) = c { | |
| 111 | todo!(); | |
| 112 | } else { | |
| 113 | #[cfg(target_os = "freebsd")] | |
| 114 | todo!(); | |
| 115 | ||
| 116 | if let ControlFlow::Break(None) = c { | |
| 117 | todo!(); | |
| 118 | } else { | |
| 119 | todo!(); | |
| 120 | } | |
| 121 | } | |
| 122 | } |
src/tools/clippy/tests/ui/collapsible_if.fixed+9| ... | ... | @@ -154,3 +154,12 @@ fn issue14722() { |
| 154 | 154 | None |
| 155 | 155 | }; |
| 156 | 156 | } |
| 157 | ||
| 158 | fn issue14799() { | |
| 159 | if true { | |
| 160 | #[cfg(target_os = "freebsd")] | |
| 161 | todo!(); | |
| 162 | ||
| 163 | if true {} | |
| 164 | }; | |
| 165 | } |
src/tools/clippy/tests/ui/collapsible_if.rs+9| ... | ... | @@ -164,3 +164,12 @@ fn issue14722() { |
| 164 | 164 | None |
| 165 | 165 | }; |
| 166 | 166 | } |
| 167 | ||
| 168 | fn issue14799() { | |
| 169 | if true { | |
| 170 | #[cfg(target_os = "freebsd")] | |
| 171 | todo!(); | |
| 172 | ||
| 173 | if true {} | |
| 174 | }; | |
| 175 | } |
src/tools/clippy/tests/ui/doc/needless_doctest_main.rs+110-2| ... | ... | @@ -1,5 +1,3 @@ |
| 1 | //@ check-pass | |
| 2 | ||
| 3 | 1 | #![warn(clippy::needless_doctest_main)] |
| 4 | 2 | //! issue 10491: |
| 5 | 3 | //! ```rust,no_test |
| ... | ... | @@ -19,4 +17,114 @@ |
| 19 | 17 | /// ``` |
| 20 | 18 | fn foo() {} |
| 21 | 19 | |
| 20 | #[rustfmt::skip] | |
| 21 | /// Description | |
| 22 | /// ```rust | |
| 23 | /// fn main() { | |
| 24 | //~^ error: needless `fn main` in doctest | |
| 25 | /// let a = 0; | |
| 26 | /// } | |
| 27 | /// ``` | |
| 28 | fn mulpipulpi() {} | |
| 29 | ||
| 30 | #[rustfmt::skip] | |
| 31 | /// With a `#[no_main]` | |
| 32 | /// ```rust | |
| 33 | /// #[no_main] | |
| 34 | /// fn a() { | |
| 35 | /// let _ = 0; | |
| 36 | /// } | |
| 37 | /// ``` | |
| 38 | fn pulpimulpi() {} | |
| 39 | ||
| 40 | // Without a `#[no_main]` attribute | |
| 41 | /// ```rust | |
| 42 | /// fn a() { | |
| 43 | /// let _ = 0; | |
| 44 | /// } | |
| 45 | /// ``` | |
| 46 | fn plumilupi() {} | |
| 47 | ||
| 48 | #[rustfmt::skip] | |
| 49 | /// Additional function, shouldn't trigger | |
| 50 | /// ```rust | |
| 51 | /// fn additional_function() { | |
| 52 | /// let _ = 0; | |
| 53 | /// // Thus `fn main` is actually relevant! | |
| 54 | /// } | |
| 55 | /// fn main() { | |
| 56 | /// let _ = 0; | |
| 57 | /// } | |
| 58 | /// ``` | |
| 59 | fn mlupipupi() {} | |
| 60 | ||
| 61 | #[rustfmt::skip] | |
| 62 | /// Additional function AFTER main, shouldn't trigger | |
| 63 | /// ```rust | |
| 64 | /// fn main() { | |
| 65 | /// let _ = 0; | |
| 66 | /// } | |
| 67 | /// fn additional_function() { | |
| 68 | /// let _ = 0; | |
| 69 | /// // Thus `fn main` is actually relevant! | |
| 70 | /// } | |
| 71 | /// ``` | |
| 72 | fn lumpimupli() {} | |
| 73 | ||
| 74 | #[rustfmt::skip] | |
| 75 | /// Ignore code block, should not lint at all | |
| 76 | /// ```rust, ignore | |
| 77 | /// fn main() { | |
| 78 | //~^ error: needless `fn main` in doctest | |
| 79 | /// // Hi! | |
| 80 | /// let _ = 0; | |
| 81 | /// } | |
| 82 | /// ``` | |
| 83 | fn mpulpilumi() {} | |
| 84 | ||
| 85 | #[rustfmt::skip] | |
| 86 | /// Spaces in weird positions (including an \u{A0} after `main`) | |
| 87 | /// ```rust | |
| 88 | /// fn main (){ | |
| 89 | //~^ error: needless `fn main` in doctest | |
| 90 | /// let _ = 0; | |
| 91 | /// } | |
| 92 | /// ``` | |
| 93 | fn plumpiplupi() {} | |
| 94 | ||
| 95 | /// 4 Functions, this should not lint because there are several function | |
| 96 | /// | |
| 97 | /// ```rust | |
| 98 | /// fn a() {let _ = 0; } | |
| 99 | /// fn b() {let _ = 0; } | |
| 100 | /// fn main() { let _ = 0; } | |
| 101 | /// fn d() { let _ = 0; } | |
| 102 | /// ``` | |
| 103 | fn pulmipulmip() {} | |
| 104 | ||
| 105 | /// 3 Functions but main is first, should also not lint | |
| 106 | /// | |
| 107 | ///```rust | |
| 108 | /// fn main() { let _ = 0; } | |
| 109 | /// fn b() { let _ = 0; } | |
| 110 | /// fn c() { let _ = 0; } | |
| 111 | /// ``` | |
| 112 | fn pmuplimulip() {} | |
| 113 | ||
| 22 | 114 | fn main() {} |
| 115 | ||
| 116 | fn issue8244() -> Result<(), ()> { | |
| 117 | //! ```compile_fail | |
| 118 | //! fn test() -> Result< {} | |
| 119 | //! ``` | |
| 120 | Ok(()) | |
| 121 | } | |
| 122 | ||
| 123 | /// # Examples | |
| 124 | /// | |
| 125 | /// ``` | |
| 126 | /// use std::error::Error; | |
| 127 | /// fn main() -> Result<(), Box<dyn Error>/* > */ { | |
| 128 | /// } | |
| 129 | /// ``` | |
| 130 | fn issue15041() {} |
src/tools/clippy/tests/ui/doc/needless_doctest_main.stderr created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | error: needless `fn main` in doctest | |
| 2 | --> tests/ui/doc/needless_doctest_main.rs:23:5 | |
| 3 | | | |
| 4 | LL | /// fn main() { | |
| 5 | | _____^ | |
| 6 | LL | | | |
| 7 | LL | | /// let a = 0; | |
| 8 | LL | | /// } | |
| 9 | | |_____^ | |
| 10 | | | |
| 11 | = note: `-D clippy::needless-doctest-main` implied by `-D warnings` | |
| 12 | = help: to override `-D warnings` add `#[allow(clippy::needless_doctest_main)]` | |
| 13 | ||
| 14 | error: needless `fn main` in doctest | |
| 15 | --> tests/ui/doc/needless_doctest_main.rs:77:5 | |
| 16 | | | |
| 17 | LL | /// fn main() { | |
| 18 | | _____^ | |
| 19 | LL | | | |
| 20 | LL | | /// // Hi! | |
| 21 | LL | | /// let _ = 0; | |
| 22 | LL | | /// } | |
| 23 | | |_____^ | |
| 24 | ||
| 25 | error: needless `fn main` in doctest | |
| 26 | --> tests/ui/doc/needless_doctest_main.rs:88:5 | |
| 27 | | | |
| 28 | LL | /// fn main (){ | |
| 29 | | _____^ | |
| 30 | LL | | | |
| 31 | LL | | /// let _ = 0; | |
| 32 | LL | | /// } | |
| 33 | | |_____^ | |
| 34 | ||
| 35 | error: aborting due to 3 previous errors | |
| 36 |
src/tools/clippy/tests/ui/doc_broken_link.rs created+72| ... | ... | @@ -0,0 +1,72 @@ |
| 1 | #![warn(clippy::doc_broken_link)] | |
| 2 | ||
| 3 | fn main() {} | |
| 4 | ||
| 5 | pub struct FakeType {} | |
| 6 | ||
| 7 | /// This might be considered a link false positive | |
| 8 | /// and should be ignored by this lint rule: | |
| 9 | /// Example of referencing some code with brackets [FakeType]. | |
| 10 | pub fn doc_ignore_link_false_positive_1() {} | |
| 11 | ||
| 12 | /// This might be considered a link false positive | |
| 13 | /// and should be ignored by this lint rule: | |
| 14 | /// [`FakeType`]. Continue text after brackets, | |
| 15 | /// then (something in | |
| 16 | /// parenthesis). | |
| 17 | pub fn doc_ignore_link_false_positive_2() {} | |
| 18 | ||
| 19 | /// Test valid link, whole link single line. | |
| 20 | /// [doc valid link](https://test.fake/doc_valid_link) | |
| 21 | pub fn doc_valid_link() {} | |
| 22 | ||
| 23 | /// Test valid link, whole link single line but it has special chars such as brackets and | |
| 24 | /// parenthesis. [doc invalid link url invalid char](https://test.fake/doc_valid_link_url_invalid_char?foo[bar]=1&bar(foo)=2) | |
| 25 | pub fn doc_valid_link_url_invalid_char() {} | |
| 26 | ||
| 27 | /// Test valid link, text tag broken across multiple lines. | |
| 28 | /// [doc valid link broken | |
| 29 | /// text](https://test.fake/doc_valid_link_broken_text) | |
| 30 | pub fn doc_valid_link_broken_text() {} | |
| 31 | ||
| 32 | /// Test valid link, url tag broken across multiple lines, but | |
| 33 | /// the whole url part in a single line. | |
| 34 | /// [doc valid link broken url tag two lines first](https://test.fake/doc_valid_link_broken_url_tag_two_lines_first | |
| 35 | /// ) | |
| 36 | pub fn doc_valid_link_broken_url_tag_two_lines_first() {} | |
| 37 | ||
| 38 | /// Test valid link, url tag broken across multiple lines, but | |
| 39 | /// the whole url part in a single line. | |
| 40 | /// [doc valid link broken url tag two lines second]( | |
| 41 | /// https://test.fake/doc_valid_link_broken_url_tag_two_lines_second) | |
| 42 | pub fn doc_valid_link_broken_url_tag_two_lines_second() {} | |
| 43 | ||
| 44 | /// Test valid link, url tag broken across multiple lines, but | |
| 45 | /// the whole url part in a single line, but the closing pharentesis | |
| 46 | /// in a third line. | |
| 47 | /// [doc valid link broken url tag three lines]( | |
| 48 | /// https://test.fake/doc_valid_link_broken_url_tag_three_lines | |
| 49 | /// ) | |
| 50 | pub fn doc_valid_link_broken_url_tag_three_lines() {} | |
| 51 | ||
| 52 | /// Test invalid link, url part broken across multiple lines. | |
| 53 | /// [doc invalid link broken url scheme part](https:// | |
| 54 | /// test.fake/doc_invalid_link_broken_url_scheme_part) | |
| 55 | //~^^ ERROR: possible broken doc link: broken across multiple lines | |
| 56 | pub fn doc_invalid_link_broken_url_scheme_part() {} | |
| 57 | ||
| 58 | /// Test invalid link, url part broken across multiple lines. | |
| 59 | /// [doc invalid link broken url host part](https://test | |
| 60 | /// .fake/doc_invalid_link_broken_url_host_part) | |
| 61 | //~^^ ERROR: possible broken doc link: broken across multiple lines | |
| 62 | pub fn doc_invalid_link_broken_url_host_part() {} | |
| 63 | ||
| 64 | /// Test invalid link, for multiple urls in the same block of comment. | |
| 65 | /// There is a [fist link - invalid](https://test | |
| 66 | /// .fake) then it continues | |
| 67 | //~^^ ERROR: possible broken doc link: broken across multiple lines | |
| 68 | /// with a [second link - valid](https://test.fake/doc_valid_link) and another [third link - invalid](https://test | |
| 69 | /// .fake). It ends with another | |
| 70 | //~^^ ERROR: possible broken doc link: broken across multiple lines | |
| 71 | /// line of comment. | |
| 72 | pub fn doc_multiple_invalid_link_broken_url() {} |
src/tools/clippy/tests/ui/doc_broken_link.stderr created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | error: possible broken doc link: broken across multiple lines | |
| 2 | --> tests/ui/doc_broken_link.rs:53:5 | |
| 3 | | | |
| 4 | LL | /// [doc invalid link broken url scheme part](https:// | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: `-D clippy::doc-broken-link` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::doc_broken_link)]` | |
| 9 | ||
| 10 | error: possible broken doc link: broken across multiple lines | |
| 11 | --> tests/ui/doc_broken_link.rs:59:5 | |
| 12 | | | |
| 13 | LL | /// [doc invalid link broken url host part](https://test | |
| 14 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 15 | ||
| 16 | error: possible broken doc link: broken across multiple lines | |
| 17 | --> tests/ui/doc_broken_link.rs:65:16 | |
| 18 | | | |
| 19 | LL | /// There is a [fist link - invalid](https://test | |
| 20 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 21 | ||
| 22 | error: possible broken doc link: broken across multiple lines | |
| 23 | --> tests/ui/doc_broken_link.rs:68:80 | |
| 24 | | | |
| 25 | LL | /// with a [second link - valid](https://test.fake/doc_valid_link) and another [third link - invalid](https://test | |
| 26 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 27 | ||
| 28 | error: aborting due to 4 previous errors | |
| 29 |
src/tools/clippy/tests/ui/empty_line_after/outer_attribute.1.fixed+9| ... | ... | @@ -105,4 +105,13 @@ second line |
| 105 | 105 | ")] |
| 106 | 106 | pub struct Args; |
| 107 | 107 | |
| 108 | mod issue_14980 { | |
| 109 | //~v empty_line_after_outer_attr | |
| 110 | #[repr(align(536870912))] | |
| 111 | enum Aligned { | |
| 112 | Zero = 0, | |
| 113 | One = 1, | |
| 114 | } | |
| 115 | } | |
| 116 | ||
| 108 | 117 | fn main() {} |
src/tools/clippy/tests/ui/empty_line_after/outer_attribute.2.fixed+9| ... | ... | @@ -108,4 +108,13 @@ second line |
| 108 | 108 | ")] |
| 109 | 109 | pub struct Args; |
| 110 | 110 | |
| 111 | mod issue_14980 { | |
| 112 | //~v empty_line_after_outer_attr | |
| 113 | #[repr(align(536870912))] | |
| 114 | enum Aligned { | |
| 115 | Zero = 0, | |
| 116 | One = 1, | |
| 117 | } | |
| 118 | } | |
| 119 | ||
| 111 | 120 | fn main() {} |
src/tools/clippy/tests/ui/empty_line_after/outer_attribute.rs+10| ... | ... | @@ -116,4 +116,14 @@ second line |
| 116 | 116 | ")] |
| 117 | 117 | pub struct Args; |
| 118 | 118 | |
| 119 | mod issue_14980 { | |
| 120 | //~v empty_line_after_outer_attr | |
| 121 | #[repr(align(536870912))] | |
| 122 | ||
| 123 | enum Aligned { | |
| 124 | Zero = 0, | |
| 125 | One = 1, | |
| 126 | } | |
| 127 | } | |
| 128 | ||
| 119 | 129 | fn main() {} |
src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr+12-1| ... | ... | @@ -111,5 +111,16 @@ LL | pub fn isolated_comment() {} |
| 111 | 111 | | |
| 112 | 112 | = help: if the empty lines are unintentional, remove them |
| 113 | 113 | |
| 114 | error: aborting due to 9 previous errors | |
| 114 | error: empty line after outer attribute | |
| 115 | --> tests/ui/empty_line_after/outer_attribute.rs:121:5 | |
| 116 | | | |
| 117 | LL | / #[repr(align(536870912))] | |
| 118 | LL | | | |
| 119 | | |_^ | |
| 120 | LL | enum Aligned { | |
| 121 | | ------------ the attribute applies to this enum | |
| 122 | | | |
| 123 | = help: if the empty line is unintentional, remove it | |
| 124 | ||
| 125 | error: aborting due to 10 previous errors | |
| 115 | 126 |
src/tools/clippy/tests/ui/eta.fixed+18| ... | ... | @@ -543,3 +543,21 @@ mod issue_13073 { |
| 543 | 543 | //~^ redundant_closure |
| 544 | 544 | } |
| 545 | 545 | } |
| 546 | ||
| 547 | fn issue_14789() { | |
| 548 | _ = Some(1u8).map( | |
| 549 | #[expect(clippy::redundant_closure)] | |
| 550 | |a| foo(a), | |
| 551 | ); | |
| 552 | ||
| 553 | _ = Some("foo").map( | |
| 554 | #[expect(clippy::redundant_closure_for_method_calls)] | |
| 555 | |s| s.to_owned(), | |
| 556 | ); | |
| 557 | ||
| 558 | let _: Vec<u8> = None.map_or_else( | |
| 559 | #[expect(clippy::redundant_closure)] | |
| 560 | || vec![], | |
| 561 | std::convert::identity, | |
| 562 | ); | |
| 563 | } |
src/tools/clippy/tests/ui/eta.rs+18| ... | ... | @@ -543,3 +543,21 @@ mod issue_13073 { |
| 543 | 543 | //~^ redundant_closure |
| 544 | 544 | } |
| 545 | 545 | } |
| 546 | ||
| 547 | fn issue_14789() { | |
| 548 | _ = Some(1u8).map( | |
| 549 | #[expect(clippy::redundant_closure)] | |
| 550 | |a| foo(a), | |
| 551 | ); | |
| 552 | ||
| 553 | _ = Some("foo").map( | |
| 554 | #[expect(clippy::redundant_closure_for_method_calls)] | |
| 555 | |s| s.to_owned(), | |
| 556 | ); | |
| 557 | ||
| 558 | let _: Vec<u8> = None.map_or_else( | |
| 559 | #[expect(clippy::redundant_closure)] | |
| 560 | || vec![], | |
| 561 | std::convert::identity, | |
| 562 | ); | |
| 563 | } |
src/tools/clippy/tests/ui/exhaustive_items.fixed+7| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | #![feature(default_field_values)] | |
| 1 | 2 | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] |
| 2 | 3 | #![allow(unused)] |
| 3 | 4 | |
| ... | ... | @@ -90,3 +91,9 @@ pub mod structs { |
| 90 | 91 | pub bar: String, |
| 91 | 92 | } |
| 92 | 93 | } |
| 94 | ||
| 95 | pub mod issue14992 { | |
| 96 | pub struct A { | |
| 97 | pub a: isize = 42, | |
| 98 | } | |
| 99 | } |
src/tools/clippy/tests/ui/exhaustive_items.rs+7| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | #![feature(default_field_values)] | |
| 1 | 2 | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] |
| 2 | 3 | #![allow(unused)] |
| 3 | 4 | |
| ... | ... | @@ -87,3 +88,9 @@ pub mod structs { |
| 87 | 88 | pub bar: String, |
| 88 | 89 | } |
| 89 | 90 | } |
| 91 | ||
| 92 | pub mod issue14992 { | |
| 93 | pub struct A { | |
| 94 | pub a: isize = 42, | |
| 95 | } | |
| 96 | } |
src/tools/clippy/tests/ui/exhaustive_items.stderr+5-5| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: exported enums should not be exhaustive |
| 2 | --> tests/ui/exhaustive_items.rs:9:5 | |
| 2 | --> tests/ui/exhaustive_items.rs:10:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | / pub enum Exhaustive { |
| 5 | 5 | LL | | |
| ... | ... | @@ -11,7 +11,7 @@ LL | | } |
| 11 | 11 | | |_____^ |
| 12 | 12 | | |
| 13 | 13 | note: the lint level is defined here |
| 14 | --> tests/ui/exhaustive_items.rs:1:9 | |
| 14 | --> tests/ui/exhaustive_items.rs:2:9 | |
| 15 | 15 | | |
| 16 | 16 | LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] |
| 17 | 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -22,7 +22,7 @@ LL ~ pub enum Exhaustive { |
| 22 | 22 | | |
| 23 | 23 | |
| 24 | 24 | error: exported enums should not be exhaustive |
| 25 | --> tests/ui/exhaustive_items.rs:19:5 | |
| 25 | --> tests/ui/exhaustive_items.rs:20:5 | |
| 26 | 26 | | |
| 27 | 27 | LL | / pub enum ExhaustiveWithAttrs { |
| 28 | 28 | LL | | |
| ... | ... | @@ -40,7 +40,7 @@ LL ~ pub enum ExhaustiveWithAttrs { |
| 40 | 40 | | |
| 41 | 41 | |
| 42 | 42 | error: exported structs should not be exhaustive |
| 43 | --> tests/ui/exhaustive_items.rs:55:5 | |
| 43 | --> tests/ui/exhaustive_items.rs:56:5 | |
| 44 | 44 | | |
| 45 | 45 | LL | / pub struct Exhaustive { |
| 46 | 46 | LL | | |
| ... | ... | @@ -50,7 +50,7 @@ LL | | } |
| 50 | 50 | | |_____^ |
| 51 | 51 | | |
| 52 | 52 | note: the lint level is defined here |
| 53 | --> tests/ui/exhaustive_items.rs:1:35 | |
| 53 | --> tests/ui/exhaustive_items.rs:2:35 | |
| 54 | 54 | | |
| 55 | 55 | LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] |
| 56 | 56 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ |
src/tools/clippy/tests/ui/identity_op.fixed+46| ... | ... | @@ -312,3 +312,49 @@ fn issue_13470() { |
| 312 | 312 | let _: u64 = 1u64 + ((x as i32 + y as i32) as u64); |
| 313 | 313 | //~^ identity_op |
| 314 | 314 | } |
| 315 | ||
| 316 | fn issue_14932() { | |
| 317 | let _ = 0usize + &Default::default(); // no error | |
| 318 | ||
| 319 | 0usize + &Default::default(); // no error | |
| 320 | ||
| 321 | <usize as Default>::default(); | |
| 322 | //~^ identity_op | |
| 323 | ||
| 324 | let _ = usize::default(); | |
| 325 | //~^ identity_op | |
| 326 | ||
| 327 | let _n: usize = Default::default(); | |
| 328 | //~^ identity_op | |
| 329 | } | |
| 330 | ||
| 331 | // Expr's type can be inferred by the function's return type | |
| 332 | fn issue_14932_2() -> usize { | |
| 333 | Default::default() | |
| 334 | //~^ identity_op | |
| 335 | } | |
| 336 | ||
| 337 | trait Def { | |
| 338 | fn def() -> Self; | |
| 339 | } | |
| 340 | ||
| 341 | impl Def for usize { | |
| 342 | fn def() -> Self { | |
| 343 | 0 | |
| 344 | } | |
| 345 | } | |
| 346 | ||
| 347 | fn issue_14932_3() { | |
| 348 | let _ = 0usize + &Def::def(); // no error | |
| 349 | ||
| 350 | 0usize + &Def::def(); // no error | |
| 351 | ||
| 352 | <usize as Def>::def(); | |
| 353 | //~^ identity_op | |
| 354 | ||
| 355 | let _ = usize::def(); | |
| 356 | //~^ identity_op | |
| 357 | ||
| 358 | let _n: usize = Def::def(); | |
| 359 | //~^ identity_op | |
| 360 | } |
src/tools/clippy/tests/ui/identity_op.rs+46| ... | ... | @@ -312,3 +312,49 @@ fn issue_13470() { |
| 312 | 312 | let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64); |
| 313 | 313 | //~^ identity_op |
| 314 | 314 | } |
| 315 | ||
| 316 | fn issue_14932() { | |
| 317 | let _ = 0usize + &Default::default(); // no error | |
| 318 | ||
| 319 | 0usize + &Default::default(); // no error | |
| 320 | ||
| 321 | 0usize + &<usize as Default>::default(); | |
| 322 | //~^ identity_op | |
| 323 | ||
| 324 | let _ = 0usize + &usize::default(); | |
| 325 | //~^ identity_op | |
| 326 | ||
| 327 | let _n: usize = 0usize + &Default::default(); | |
| 328 | //~^ identity_op | |
| 329 | } | |
| 330 | ||
| 331 | // Expr's type can be inferred by the function's return type | |
| 332 | fn issue_14932_2() -> usize { | |
| 333 | 0usize + &Default::default() | |
| 334 | //~^ identity_op | |
| 335 | } | |
| 336 | ||
| 337 | trait Def { | |
| 338 | fn def() -> Self; | |
| 339 | } | |
| 340 | ||
| 341 | impl Def for usize { | |
| 342 | fn def() -> Self { | |
| 343 | 0 | |
| 344 | } | |
| 345 | } | |
| 346 | ||
| 347 | fn issue_14932_3() { | |
| 348 | let _ = 0usize + &Def::def(); // no error | |
| 349 | ||
| 350 | 0usize + &Def::def(); // no error | |
| 351 | ||
| 352 | 0usize + &<usize as Def>::def(); | |
| 353 | //~^ identity_op | |
| 354 | ||
| 355 | let _ = 0usize + &usize::def(); | |
| 356 | //~^ identity_op | |
| 357 | ||
| 358 | let _n: usize = 0usize + &Def::def(); | |
| 359 | //~^ identity_op | |
| 360 | } |
src/tools/clippy/tests/ui/identity_op.stderr+43-1| ... | ... | @@ -379,5 +379,47 @@ error: this operation has no effect |
| 379 | 379 | LL | let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64); |
| 380 | 380 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x as i32 + y as i32) as u64)` |
| 381 | 381 | |
| 382 | error: aborting due to 63 previous errors | |
| 382 | error: this operation has no effect | |
| 383 | --> tests/ui/identity_op.rs:321:5 | |
| 384 | | | |
| 385 | LL | 0usize + &<usize as Default>::default(); | |
| 386 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `<usize as Default>::default()` | |
| 387 | ||
| 388 | error: this operation has no effect | |
| 389 | --> tests/ui/identity_op.rs:324:13 | |
| 390 | | | |
| 391 | LL | let _ = 0usize + &usize::default(); | |
| 392 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `usize::default()` | |
| 393 | ||
| 394 | error: this operation has no effect | |
| 395 | --> tests/ui/identity_op.rs:327:21 | |
| 396 | | | |
| 397 | LL | let _n: usize = 0usize + &Default::default(); | |
| 398 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Default::default()` | |
| 399 | ||
| 400 | error: this operation has no effect | |
| 401 | --> tests/ui/identity_op.rs:333:5 | |
| 402 | | | |
| 403 | LL | 0usize + &Default::default() | |
| 404 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Default::default()` | |
| 405 | ||
| 406 | error: this operation has no effect | |
| 407 | --> tests/ui/identity_op.rs:352:5 | |
| 408 | | | |
| 409 | LL | 0usize + &<usize as Def>::def(); | |
| 410 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `<usize as Def>::def()` | |
| 411 | ||
| 412 | error: this operation has no effect | |
| 413 | --> tests/ui/identity_op.rs:355:13 | |
| 414 | | | |
| 415 | LL | let _ = 0usize + &usize::def(); | |
| 416 | | ^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `usize::def()` | |
| 417 | ||
| 418 | error: this operation has no effect | |
| 419 | --> tests/ui/identity_op.rs:358:21 | |
| 420 | | | |
| 421 | LL | let _n: usize = 0usize + &Def::def(); | |
| 422 | | ^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `Def::def()` | |
| 423 | ||
| 424 | error: aborting due to 70 previous errors | |
| 383 | 425 |
src/tools/clippy/tests/ui/infinite_iter.rs+1-1| ... | ... | @@ -38,7 +38,7 @@ fn infinite_iters() { |
| 38 | 38 | //~^ infinite_iter |
| 39 | 39 | |
| 40 | 40 | // infinite iter |
| 41 | (0_u64..).filter(|x| x % 2 == 0).last(); | |
| 41 | (0_u64..).filter(|x| x.is_multiple_of(2)).last(); | |
| 42 | 42 | //~^ infinite_iter |
| 43 | 43 | |
| 44 | 44 | // not an infinite, because ranges are double-ended |
src/tools/clippy/tests/ui/infinite_iter.stderr+2-2| ... | ... | @@ -42,8 +42,8 @@ LL | (0_usize..).flat_map(|x| 0..x).product::<usize>(); |
| 42 | 42 | error: infinite iteration detected |
| 43 | 43 | --> tests/ui/infinite_iter.rs:41:5 |
| 44 | 44 | | |
| 45 | LL | (0_u64..).filter(|x| x % 2 == 0).last(); | |
| 46 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 45 | LL | (0_u64..).filter(|x| x.is_multiple_of(2)).last(); | |
| 46 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 47 | 47 | |
| 48 | 48 | error: possible infinite iteration detected |
| 49 | 49 | --> tests/ui/infinite_iter.rs:53:5 |
src/tools/clippy/tests/ui/iter_kv_map.fixed+14-6| ... | ... | @@ -30,15 +30,19 @@ fn main() { |
| 30 | 30 | |
| 31 | 31 | let _ = map.clone().values().collect::<Vec<_>>(); |
| 32 | 32 | //~^ iter_kv_map |
| 33 | let _ = map.keys().filter(|x| *x % 2 == 0).count(); | |
| 33 | let _ = map.keys().filter(|x| x.is_multiple_of(2)).count(); | |
| 34 | 34 | //~^ iter_kv_map |
| 35 | 35 | |
| 36 | 36 | // Don't lint |
| 37 | let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); | |
| 37 | let _ = map | |
| 38 | .iter() | |
| 39 | .filter(|(_, val)| val.is_multiple_of(2)) | |
| 40 | .map(|(key, _)| key) | |
| 41 | .count(); | |
| 38 | 42 | let _ = map.iter().map(get_key).collect::<Vec<_>>(); |
| 39 | 43 | |
| 40 | 44 | // Linting the following could be an improvement to the lint |
| 41 | // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); | |
| 45 | // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count(); | |
| 42 | 46 | |
| 43 | 47 | // Lint |
| 44 | 48 | let _ = map.keys().map(|key| key * 9).count(); |
| ... | ... | @@ -84,15 +88,19 @@ fn main() { |
| 84 | 88 | |
| 85 | 89 | let _ = map.clone().values().collect::<Vec<_>>(); |
| 86 | 90 | //~^ iter_kv_map |
| 87 | let _ = map.keys().filter(|x| *x % 2 == 0).count(); | |
| 91 | let _ = map.keys().filter(|x| x.is_multiple_of(2)).count(); | |
| 88 | 92 | //~^ iter_kv_map |
| 89 | 93 | |
| 90 | 94 | // Don't lint |
| 91 | let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); | |
| 95 | let _ = map | |
| 96 | .iter() | |
| 97 | .filter(|(_, val)| val.is_multiple_of(2)) | |
| 98 | .map(|(key, _)| key) | |
| 99 | .count(); | |
| 92 | 100 | let _ = map.iter().map(get_key).collect::<Vec<_>>(); |
| 93 | 101 | |
| 94 | 102 | // Linting the following could be an improvement to the lint |
| 95 | // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); | |
| 103 | // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count(); | |
| 96 | 104 | |
| 97 | 105 | // Lint |
| 98 | 106 | let _ = map.keys().map(|key| key * 9).count(); |
src/tools/clippy/tests/ui/iter_kv_map.rs+14-6| ... | ... | @@ -30,15 +30,19 @@ fn main() { |
| 30 | 30 | |
| 31 | 31 | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>(); |
| 32 | 32 | //~^ iter_kv_map |
| 33 | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | |
| 33 | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count(); | |
| 34 | 34 | //~^ iter_kv_map |
| 35 | 35 | |
| 36 | 36 | // Don't lint |
| 37 | let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); | |
| 37 | let _ = map | |
| 38 | .iter() | |
| 39 | .filter(|(_, val)| val.is_multiple_of(2)) | |
| 40 | .map(|(key, _)| key) | |
| 41 | .count(); | |
| 38 | 42 | let _ = map.iter().map(get_key).collect::<Vec<_>>(); |
| 39 | 43 | |
| 40 | 44 | // Linting the following could be an improvement to the lint |
| 41 | // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); | |
| 45 | // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count(); | |
| 42 | 46 | |
| 43 | 47 | // Lint |
| 44 | 48 | let _ = map.iter().map(|(key, _value)| key * 9).count(); |
| ... | ... | @@ -86,15 +90,19 @@ fn main() { |
| 86 | 90 | |
| 87 | 91 | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>(); |
| 88 | 92 | //~^ iter_kv_map |
| 89 | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | |
| 93 | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count(); | |
| 90 | 94 | //~^ iter_kv_map |
| 91 | 95 | |
| 92 | 96 | // Don't lint |
| 93 | let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); | |
| 97 | let _ = map | |
| 98 | .iter() | |
| 99 | .filter(|(_, val)| val.is_multiple_of(2)) | |
| 100 | .map(|(key, _)| key) | |
| 101 | .count(); | |
| 94 | 102 | let _ = map.iter().map(get_key).collect::<Vec<_>>(); |
| 95 | 103 | |
| 96 | 104 | // Linting the following could be an improvement to the lint |
| 97 | // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count(); | |
| 105 | // map.iter().filter_map(|(_, val)| (val.is_multiple_of(2)).then(val * 17)).count(); | |
| 98 | 106 | |
| 99 | 107 | // Lint |
| 100 | 108 | let _ = map.iter().map(|(key, _value)| key * 9).count(); |
src/tools/clippy/tests/ui/iter_kv_map.stderr+32-32| ... | ... | @@ -52,29 +52,29 @@ LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>(); |
| 52 | 52 | error: iterating on a map's keys |
| 53 | 53 | --> tests/ui/iter_kv_map.rs:33:13 |
| 54 | 54 | | |
| 55 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | |
| 55 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count(); | |
| 56 | 56 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` |
| 57 | 57 | |
| 58 | 58 | error: iterating on a map's keys |
| 59 | --> tests/ui/iter_kv_map.rs:44:13 | |
| 59 | --> tests/ui/iter_kv_map.rs:48:13 | |
| 60 | 60 | | |
| 61 | 61 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); |
| 62 | 62 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` |
| 63 | 63 | |
| 64 | 64 | error: iterating on a map's values |
| 65 | --> tests/ui/iter_kv_map.rs:46:13 | |
| 65 | --> tests/ui/iter_kv_map.rs:50:13 | |
| 66 | 66 | | |
| 67 | 67 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); |
| 68 | 68 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` |
| 69 | 69 | |
| 70 | 70 | error: iterating on a map's values |
| 71 | --> tests/ui/iter_kv_map.rs:50:13 | |
| 71 | --> tests/ui/iter_kv_map.rs:54:13 | |
| 72 | 72 | | |
| 73 | 73 | LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); |
| 74 | 74 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` |
| 75 | 75 | |
| 76 | 76 | error: iterating on a map's values |
| 77 | --> tests/ui/iter_kv_map.rs:54:13 | |
| 77 | --> tests/ui/iter_kv_map.rs:58:13 | |
| 78 | 78 | | |
| 79 | 79 | LL | let _ = map |
| 80 | 80 | | _____________^ |
| ... | ... | @@ -97,85 +97,85 @@ LL + }) |
| 97 | 97 | | |
| 98 | 98 | |
| 99 | 99 | error: iterating on a map's values |
| 100 | --> tests/ui/iter_kv_map.rs:65:13 | |
| 100 | --> tests/ui/iter_kv_map.rs:69:13 | |
| 101 | 101 | | |
| 102 | 102 | LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); |
| 103 | 103 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` |
| 104 | 104 | |
| 105 | 105 | error: iterating on a map's keys |
| 106 | --> tests/ui/iter_kv_map.rs:70:13 | |
| 106 | --> tests/ui/iter_kv_map.rs:74:13 | |
| 107 | 107 | | |
| 108 | 108 | LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); |
| 109 | 109 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` |
| 110 | 110 | |
| 111 | 111 | error: iterating on a map's values |
| 112 | --> tests/ui/iter_kv_map.rs:72:13 | |
| 112 | --> tests/ui/iter_kv_map.rs:76:13 | |
| 113 | 113 | | |
| 114 | 114 | LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); |
| 115 | 115 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` |
| 116 | 116 | |
| 117 | 117 | error: iterating on a map's values |
| 118 | --> tests/ui/iter_kv_map.rs:74:13 | |
| 118 | --> tests/ui/iter_kv_map.rs:78:13 | |
| 119 | 119 | | |
| 120 | 120 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); |
| 121 | 121 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` |
| 122 | 122 | |
| 123 | 123 | error: iterating on a map's keys |
| 124 | --> tests/ui/iter_kv_map.rs:77:13 | |
| 124 | --> tests/ui/iter_kv_map.rs:81:13 | |
| 125 | 125 | | |
| 126 | 126 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>(); |
| 127 | 127 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` |
| 128 | 128 | |
| 129 | 129 | error: iterating on a map's keys |
| 130 | --> tests/ui/iter_kv_map.rs:79:13 | |
| 130 | --> tests/ui/iter_kv_map.rs:83:13 | |
| 131 | 131 | | |
| 132 | 132 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>(); |
| 133 | 133 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` |
| 134 | 134 | |
| 135 | 135 | error: iterating on a map's values |
| 136 | --> tests/ui/iter_kv_map.rs:82:13 | |
| 136 | --> tests/ui/iter_kv_map.rs:86:13 | |
| 137 | 137 | | |
| 138 | 138 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>(); |
| 139 | 139 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` |
| 140 | 140 | |
| 141 | 141 | error: iterating on a map's values |
| 142 | --> tests/ui/iter_kv_map.rs:84:13 | |
| 142 | --> tests/ui/iter_kv_map.rs:88:13 | |
| 143 | 143 | | |
| 144 | 144 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>(); |
| 145 | 145 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` |
| 146 | 146 | |
| 147 | 147 | error: iterating on a map's values |
| 148 | --> tests/ui/iter_kv_map.rs:87:13 | |
| 148 | --> tests/ui/iter_kv_map.rs:91:13 | |
| 149 | 149 | | |
| 150 | 150 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>(); |
| 151 | 151 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` |
| 152 | 152 | |
| 153 | 153 | error: iterating on a map's keys |
| 154 | --> tests/ui/iter_kv_map.rs:89:13 | |
| 154 | --> tests/ui/iter_kv_map.rs:93:13 | |
| 155 | 155 | | |
| 156 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | |
| 156 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count(); | |
| 157 | 157 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` |
| 158 | 158 | |
| 159 | 159 | error: iterating on a map's keys |
| 160 | --> tests/ui/iter_kv_map.rs:100:13 | |
| 160 | --> tests/ui/iter_kv_map.rs:108:13 | |
| 161 | 161 | | |
| 162 | 162 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); |
| 163 | 163 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` |
| 164 | 164 | |
| 165 | 165 | error: iterating on a map's values |
| 166 | --> tests/ui/iter_kv_map.rs:102:13 | |
| 166 | --> tests/ui/iter_kv_map.rs:110:13 | |
| 167 | 167 | | |
| 168 | 168 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); |
| 169 | 169 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` |
| 170 | 170 | |
| 171 | 171 | error: iterating on a map's values |
| 172 | --> tests/ui/iter_kv_map.rs:106:13 | |
| 172 | --> tests/ui/iter_kv_map.rs:114:13 | |
| 173 | 173 | | |
| 174 | 174 | LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); |
| 175 | 175 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` |
| 176 | 176 | |
| 177 | 177 | error: iterating on a map's values |
| 178 | --> tests/ui/iter_kv_map.rs:110:13 | |
| 178 | --> tests/ui/iter_kv_map.rs:118:13 | |
| 179 | 179 | | |
| 180 | 180 | LL | let _ = map |
| 181 | 181 | | _____________^ |
| ... | ... | @@ -198,73 +198,73 @@ LL + }) |
| 198 | 198 | | |
| 199 | 199 | |
| 200 | 200 | error: iterating on a map's values |
| 201 | --> tests/ui/iter_kv_map.rs:121:13 | |
| 201 | --> tests/ui/iter_kv_map.rs:129:13 | |
| 202 | 202 | | |
| 203 | 203 | LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); |
| 204 | 204 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` |
| 205 | 205 | |
| 206 | 206 | error: iterating on a map's keys |
| 207 | --> tests/ui/iter_kv_map.rs:137:13 | |
| 207 | --> tests/ui/iter_kv_map.rs:145:13 | |
| 208 | 208 | | |
| 209 | 209 | LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); |
| 210 | 210 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` |
| 211 | 211 | |
| 212 | 212 | error: iterating on a map's values |
| 213 | --> tests/ui/iter_kv_map.rs:140:13 | |
| 213 | --> tests/ui/iter_kv_map.rs:148:13 | |
| 214 | 214 | | |
| 215 | 215 | LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); |
| 216 | 216 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` |
| 217 | 217 | |
| 218 | 218 | error: iterating on a map's values |
| 219 | --> tests/ui/iter_kv_map.rs:143:13 | |
| 219 | --> tests/ui/iter_kv_map.rs:151:13 | |
| 220 | 220 | | |
| 221 | 221 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); |
| 222 | 222 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` |
| 223 | 223 | |
| 224 | 224 | error: iterating on a map's keys |
| 225 | --> tests/ui/iter_kv_map.rs:152:13 | |
| 225 | --> tests/ui/iter_kv_map.rs:160:13 | |
| 226 | 226 | | |
| 227 | 227 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>(); |
| 228 | 228 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` |
| 229 | 229 | |
| 230 | 230 | error: iterating on a map's keys |
| 231 | --> tests/ui/iter_kv_map.rs:155:13 | |
| 231 | --> tests/ui/iter_kv_map.rs:163:13 | |
| 232 | 232 | | |
| 233 | 233 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>(); |
| 234 | 234 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` |
| 235 | 235 | |
| 236 | 236 | error: iterating on a map's values |
| 237 | --> tests/ui/iter_kv_map.rs:158:13 | |
| 237 | --> tests/ui/iter_kv_map.rs:166:13 | |
| 238 | 238 | | |
| 239 | 239 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>(); |
| 240 | 240 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` |
| 241 | 241 | |
| 242 | 242 | error: iterating on a map's values |
| 243 | --> tests/ui/iter_kv_map.rs:161:13 | |
| 243 | --> tests/ui/iter_kv_map.rs:169:13 | |
| 244 | 244 | | |
| 245 | 245 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>(); |
| 246 | 246 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` |
| 247 | 247 | |
| 248 | 248 | error: iterating on a map's keys |
| 249 | --> tests/ui/iter_kv_map.rs:164:13 | |
| 249 | --> tests/ui/iter_kv_map.rs:172:13 | |
| 250 | 250 | | |
| 251 | 251 | LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); |
| 252 | 252 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` |
| 253 | 253 | |
| 254 | 254 | error: iterating on a map's values |
| 255 | --> tests/ui/iter_kv_map.rs:167:13 | |
| 255 | --> tests/ui/iter_kv_map.rs:175:13 | |
| 256 | 256 | | |
| 257 | 257 | LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); |
| 258 | 258 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` |
| 259 | 259 | |
| 260 | 260 | error: iterating on a map's values |
| 261 | --> tests/ui/iter_kv_map.rs:170:13 | |
| 261 | --> tests/ui/iter_kv_map.rs:178:13 | |
| 262 | 262 | | |
| 263 | 263 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); |
| 264 | 264 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` |
| 265 | 265 | |
| 266 | 266 | error: iterating on a map's values |
| 267 | --> tests/ui/iter_kv_map.rs:185:13 | |
| 267 | --> tests/ui/iter_kv_map.rs:193:13 | |
| 268 | 268 | | |
| 269 | 269 | LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>(); |
| 270 | 270 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()` |
src/tools/clippy/tests/ui/let_unit.fixed+1-1| ... | ... | @@ -61,7 +61,7 @@ fn multiline_sugg() { |
| 61 | 61 | //~^ let_unit_value |
| 62 | 62 | .into_iter() |
| 63 | 63 | .map(|i| i * 2) |
| 64 | .filter(|i| i % 2 == 0) | |
| 64 | .filter(|i| i.is_multiple_of(2)) | |
| 65 | 65 | .map(|_| ()) |
| 66 | 66 | .next() |
| 67 | 67 | .unwrap(); |
src/tools/clippy/tests/ui/let_unit.rs+1-1| ... | ... | @@ -61,7 +61,7 @@ fn multiline_sugg() { |
| 61 | 61 | //~^ let_unit_value |
| 62 | 62 | .into_iter() |
| 63 | 63 | .map(|i| i * 2) |
| 64 | .filter(|i| i % 2 == 0) | |
| 64 | .filter(|i| i.is_multiple_of(2)) | |
| 65 | 65 | .map(|_| ()) |
| 66 | 66 | .next() |
| 67 | 67 | .unwrap(); |
src/tools/clippy/tests/ui/let_unit.stderr+1-1| ... | ... | @@ -25,7 +25,7 @@ LL ~ v |
| 25 | 25 | LL + |
| 26 | 26 | LL + .into_iter() |
| 27 | 27 | LL + .map(|i| i * 2) |
| 28 | LL + .filter(|i| i % 2 == 0) | |
| 28 | LL + .filter(|i| i.is_multiple_of(2)) | |
| 29 | 29 | LL + .map(|_| ()) |
| 30 | 30 | LL + .next() |
| 31 | 31 | LL + .unwrap(); |
src/tools/clippy/tests/ui/manual_contains.fixed+1-1| ... | ... | @@ -58,7 +58,7 @@ fn should_not_lint() { |
| 58 | 58 | |
| 59 | 59 | let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6]; |
| 60 | 60 | let values = &vec[..]; |
| 61 | let _ = values.iter().any(|&v| v % 2 == 0); | |
| 61 | let _ = values.iter().any(|&v| v.is_multiple_of(2)); | |
| 62 | 62 | let _ = values.iter().any(|&v| v * 2 == 6); |
| 63 | 63 | let _ = values.iter().any(|&v| v == v); |
| 64 | 64 | let _ = values.iter().any(|&v| 4 == 4); |
src/tools/clippy/tests/ui/manual_contains.rs+1-1| ... | ... | @@ -58,7 +58,7 @@ fn should_not_lint() { |
| 58 | 58 | |
| 59 | 59 | let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6]; |
| 60 | 60 | let values = &vec[..]; |
| 61 | let _ = values.iter().any(|&v| v % 2 == 0); | |
| 61 | let _ = values.iter().any(|&v| v.is_multiple_of(2)); | |
| 62 | 62 | let _ = values.iter().any(|&v| v * 2 == 6); |
| 63 | 63 | let _ = values.iter().any(|&v| v == v); |
| 64 | 64 | let _ = values.iter().any(|&v| 4 == 4); |
src/tools/clippy/tests/ui/manual_find_fixable.fixed+2-2| ... | ... | @@ -11,7 +11,7 @@ fn lookup(n: u32) -> Option<u32> { |
| 11 | 11 | } |
| 12 | 12 | |
| 13 | 13 | fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> { |
| 14 | arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0) | |
| 14 | arr.into_iter().map(|(a, _)| a).find(|&a| a.is_multiple_of(2)) | |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | struct Data { |
| ... | ... | @@ -63,7 +63,7 @@ fn with_side_effects(arr: Vec<u32>) -> Option<u32> { |
| 63 | 63 | |
| 64 | 64 | fn with_else(arr: Vec<u32>) -> Option<u32> { |
| 65 | 65 | for el in arr { |
| 66 | if el % 2 == 0 { | |
| 66 | if el.is_multiple_of(2) { | |
| 67 | 67 | return Some(el); |
| 68 | 68 | } else { |
| 69 | 69 | println!("{}", el); |
src/tools/clippy/tests/ui/manual_find_fixable.rs+2-2| ... | ... | @@ -19,7 +19,7 @@ fn lookup(n: u32) -> Option<u32> { |
| 19 | 19 | fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> { |
| 20 | 20 | for (a, _) in arr { |
| 21 | 21 | //~^ manual_find |
| 22 | if a % 2 == 0 { | |
| 22 | if a.is_multiple_of(2) { | |
| 23 | 23 | return Some(a); |
| 24 | 24 | } |
| 25 | 25 | } |
| ... | ... | @@ -111,7 +111,7 @@ fn with_side_effects(arr: Vec<u32>) -> Option<u32> { |
| 111 | 111 | |
| 112 | 112 | fn with_else(arr: Vec<u32>) -> Option<u32> { |
| 113 | 113 | for el in arr { |
| 114 | if el % 2 == 0 { | |
| 114 | if el.is_multiple_of(2) { | |
| 115 | 115 | return Some(el); |
| 116 | 116 | } else { |
| 117 | 117 | println!("{}", el); |
src/tools/clippy/tests/ui/manual_find_fixable.stderr+2-2| ... | ... | @@ -17,11 +17,11 @@ error: manual implementation of `Iterator::find` |
| 17 | 17 | | |
| 18 | 18 | LL | / for (a, _) in arr { |
| 19 | 19 | LL | | |
| 20 | LL | | if a % 2 == 0 { | |
| 20 | LL | | if a.is_multiple_of(2) { | |
| 21 | 21 | LL | | return Some(a); |
| 22 | 22 | ... | |
| 23 | 23 | LL | | None |
| 24 | | |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)` | |
| 24 | | |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a.is_multiple_of(2))` | |
| 25 | 25 | |
| 26 | 26 | error: manual implementation of `Iterator::find` |
| 27 | 27 | --> tests/ui/manual_find_fixable.rs:34:5 |
src/tools/clippy/tests/ui/manual_is_multiple_of.fixed created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | //@aux-build: proc_macros.rs | |
| 2 | #![warn(clippy::manual_is_multiple_of)] | |
| 3 | ||
| 4 | fn main() {} | |
| 5 | ||
| 6 | #[clippy::msrv = "1.87"] | |
| 7 | fn f(a: u64, b: u64) { | |
| 8 | let _ = a.is_multiple_of(b); //~ manual_is_multiple_of | |
| 9 | let _ = (a + 1).is_multiple_of(b + 1); //~ manual_is_multiple_of | |
| 10 | let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of | |
| 11 | let _ = !(a + 1).is_multiple_of(b + 1); //~ manual_is_multiple_of | |
| 12 | ||
| 13 | let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of | |
| 14 | let _ = !a.is_multiple_of(b); //~ manual_is_multiple_of | |
| 15 | ||
| 16 | proc_macros::external! { | |
| 17 | let a: u64 = 23424; | |
| 18 | let _ = a % 4096 == 0; | |
| 19 | } | |
| 20 | } | |
| 21 | ||
| 22 | #[clippy::msrv = "1.86"] | |
| 23 | fn g(a: u64, b: u64) { | |
| 24 | let _ = a % b == 0; | |
| 25 | } |
src/tools/clippy/tests/ui/manual_is_multiple_of.rs created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | //@aux-build: proc_macros.rs | |
| 2 | #![warn(clippy::manual_is_multiple_of)] | |
| 3 | ||
| 4 | fn main() {} | |
| 5 | ||
| 6 | #[clippy::msrv = "1.87"] | |
| 7 | fn f(a: u64, b: u64) { | |
| 8 | let _ = a % b == 0; //~ manual_is_multiple_of | |
| 9 | let _ = (a + 1) % (b + 1) == 0; //~ manual_is_multiple_of | |
| 10 | let _ = a % b != 0; //~ manual_is_multiple_of | |
| 11 | let _ = (a + 1) % (b + 1) != 0; //~ manual_is_multiple_of | |
| 12 | ||
| 13 | let _ = a % b > 0; //~ manual_is_multiple_of | |
| 14 | let _ = 0 < a % b; //~ manual_is_multiple_of | |
| 15 | ||
| 16 | proc_macros::external! { | |
| 17 | let a: u64 = 23424; | |
| 18 | let _ = a % 4096 == 0; | |
| 19 | } | |
| 20 | } | |
| 21 | ||
| 22 | #[clippy::msrv = "1.86"] | |
| 23 | fn g(a: u64, b: u64) { | |
| 24 | let _ = a % b == 0; | |
| 25 | } |
src/tools/clippy/tests/ui/manual_is_multiple_of.stderr created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | error: manual implementation of `.is_multiple_of()` | |
| 2 | --> tests/ui/manual_is_multiple_of.rs:8:13 | |
| 3 | | | |
| 4 | LL | let _ = a % b == 0; | |
| 5 | | ^^^^^^^^^^ help: replace with: `a.is_multiple_of(b)` | |
| 6 | | | |
| 7 | = note: `-D clippy::manual-is-multiple-of` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::manual_is_multiple_of)]` | |
| 9 | ||
| 10 | error: manual implementation of `.is_multiple_of()` | |
| 11 | --> tests/ui/manual_is_multiple_of.rs:9:13 | |
| 12 | | | |
| 13 | LL | let _ = (a + 1) % (b + 1) == 0; | |
| 14 | | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(a + 1).is_multiple_of(b + 1)` | |
| 15 | ||
| 16 | error: manual implementation of `.is_multiple_of()` | |
| 17 | --> tests/ui/manual_is_multiple_of.rs:10:13 | |
| 18 | | | |
| 19 | LL | let _ = a % b != 0; | |
| 20 | | ^^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)` | |
| 21 | ||
| 22 | error: manual implementation of `.is_multiple_of()` | |
| 23 | --> tests/ui/manual_is_multiple_of.rs:11:13 | |
| 24 | | | |
| 25 | LL | let _ = (a + 1) % (b + 1) != 0; | |
| 26 | | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `!(a + 1).is_multiple_of(b + 1)` | |
| 27 | ||
| 28 | error: manual implementation of `.is_multiple_of()` | |
| 29 | --> tests/ui/manual_is_multiple_of.rs:13:13 | |
| 30 | | | |
| 31 | LL | let _ = a % b > 0; | |
| 32 | | ^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)` | |
| 33 | ||
| 34 | error: manual implementation of `.is_multiple_of()` | |
| 35 | --> tests/ui/manual_is_multiple_of.rs:14:13 | |
| 36 | | | |
| 37 | LL | let _ = 0 < a % b; | |
| 38 | | ^^^^^^^^^ help: replace with: `!a.is_multiple_of(b)` | |
| 39 | ||
| 40 | error: aborting due to 6 previous errors | |
| 41 |
src/tools/clippy/tests/ui/manual_is_variant_and.fixed+4-4| ... | ... | @@ -77,7 +77,7 @@ fn option_methods() { |
| 77 | 77 | let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint |
| 78 | 78 | |
| 79 | 79 | // Should not lint. |
| 80 | let _ = Foo::<u32>(0).map(|x| x % 2 == 0) == Some(true); | |
| 80 | let _ = Foo::<u32>(0).map(|x| x.is_multiple_of(2)) == Some(true); | |
| 81 | 81 | let _ = Some(2).map(|x| x % 2 == 0) != foo(); |
| 82 | 82 | let _ = mac!(eq Some(2).map(|x| x % 2 == 0), Some(true)); |
| 83 | 83 | let _ = mac!(some 2).map(|x| x % 2 == 0) == Some(true); |
| ... | ... | @@ -96,11 +96,11 @@ fn result_methods() { |
| 96 | 96 | }); |
| 97 | 97 | let _ = res.is_ok_and(|x| x > 1); |
| 98 | 98 | |
| 99 | let _ = Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0); | |
| 99 | let _ = Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2)); | |
| 100 | 100 | //~^ manual_is_variant_and |
| 101 | let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0); | |
| 101 | let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2)); | |
| 102 | 102 | //~^ manual_is_variant_and |
| 103 | let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0); | |
| 103 | let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2)); | |
| 104 | 104 | //~^ manual_is_variant_and |
| 105 | 105 | |
| 106 | 106 | // won't fix because the return type of the closure is not `bool` |
src/tools/clippy/tests/ui/manual_is_variant_and.rs+4-4| ... | ... | @@ -83,7 +83,7 @@ fn option_methods() { |
| 83 | 83 | let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint |
| 84 | 84 | |
| 85 | 85 | // Should not lint. |
| 86 | let _ = Foo::<u32>(0).map(|x| x % 2 == 0) == Some(true); | |
| 86 | let _ = Foo::<u32>(0).map(|x| x.is_multiple_of(2)) == Some(true); | |
| 87 | 87 | let _ = Some(2).map(|x| x % 2 == 0) != foo(); |
| 88 | 88 | let _ = mac!(eq Some(2).map(|x| x % 2 == 0), Some(true)); |
| 89 | 89 | let _ = mac!(some 2).map(|x| x % 2 == 0) == Some(true); |
| ... | ... | @@ -105,11 +105,11 @@ fn result_methods() { |
| 105 | 105 | //~^ manual_is_variant_and |
| 106 | 106 | .unwrap_or_default(); |
| 107 | 107 | |
| 108 | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) == Ok(true); | |
| 108 | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) == Ok(true); | |
| 109 | 109 | //~^ manual_is_variant_and |
| 110 | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true); | |
| 110 | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true); | |
| 111 | 111 | //~^ manual_is_variant_and |
| 112 | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true); | |
| 112 | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true); | |
| 113 | 113 | //~^ manual_is_variant_and |
| 114 | 114 | |
| 115 | 115 | // won't fix because the return type of the closure is not `bool` |
src/tools/clippy/tests/ui/manual_is_variant_and.stderr+6-6| ... | ... | @@ -105,20 +105,20 @@ LL | | .unwrap_or_default(); |
| 105 | 105 | error: called `.map() == Ok()` |
| 106 | 106 | --> tests/ui/manual_is_variant_and.rs:108:13 |
| 107 | 107 | | |
| 108 | LL | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) == Ok(true); | |
| 109 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)` | |
| 108 | LL | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) == Ok(true); | |
| 109 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))` | |
| 110 | 110 | |
| 111 | 111 | error: called `.map() != Ok()` |
| 112 | 112 | --> tests/ui/manual_is_variant_and.rs:110:13 |
| 113 | 113 | | |
| 114 | LL | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true); | |
| 115 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)` | |
| 114 | LL | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true); | |
| 115 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))` | |
| 116 | 116 | |
| 117 | 117 | error: called `.map() != Ok()` |
| 118 | 118 | --> tests/ui/manual_is_variant_and.rs:112:13 |
| 119 | 119 | | |
| 120 | LL | let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true); | |
| 121 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)` | |
| 120 | LL | let _ = Ok::<usize, ()>(2).map(|x| x.is_multiple_of(2)) != Ok(true); | |
| 121 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x.is_multiple_of(2))` | |
| 122 | 122 | |
| 123 | 123 | error: called `map(<f>).unwrap_or_default()` on a `Result` value |
| 124 | 124 | --> tests/ui/manual_is_variant_and.rs:119:18 |
src/tools/clippy/tests/ui/manual_ok_err.fixed+24| ... | ... | @@ -103,3 +103,27 @@ fn issue14239() { |
| 103 | 103 | }; |
| 104 | 104 | //~^^^^^ manual_ok_err |
| 105 | 105 | } |
| 106 | ||
| 107 | mod issue15051 { | |
| 108 | struct Container { | |
| 109 | field: Result<bool, ()>, | |
| 110 | } | |
| 111 | ||
| 112 | #[allow(clippy::needless_borrow)] | |
| 113 | fn with_addr_of(x: &Container) -> Option<&bool> { | |
| 114 | (&x.field).as_ref().ok() | |
| 115 | } | |
| 116 | ||
| 117 | fn from_fn(x: &Container) -> Option<&bool> { | |
| 118 | let result_with_ref = || &x.field; | |
| 119 | result_with_ref().as_ref().ok() | |
| 120 | } | |
| 121 | ||
| 122 | fn result_with_ref_mut(x: &mut Container) -> &mut Result<bool, ()> { | |
| 123 | &mut x.field | |
| 124 | } | |
| 125 | ||
| 126 | fn from_fn_mut(x: &mut Container) -> Option<&mut bool> { | |
| 127 | result_with_ref_mut(x).as_mut().ok() | |
| 128 | } | |
| 129 | } |
src/tools/clippy/tests/ui/manual_ok_err.rs+36| ... | ... | @@ -141,3 +141,39 @@ fn issue14239() { |
| 141 | 141 | }; |
| 142 | 142 | //~^^^^^ manual_ok_err |
| 143 | 143 | } |
| 144 | ||
| 145 | mod issue15051 { | |
| 146 | struct Container { | |
| 147 | field: Result<bool, ()>, | |
| 148 | } | |
| 149 | ||
| 150 | #[allow(clippy::needless_borrow)] | |
| 151 | fn with_addr_of(x: &Container) -> Option<&bool> { | |
| 152 | match &x.field { | |
| 153 | //~^ manual_ok_err | |
| 154 | Ok(panel) => Some(panel), | |
| 155 | Err(_) => None, | |
| 156 | } | |
| 157 | } | |
| 158 | ||
| 159 | fn from_fn(x: &Container) -> Option<&bool> { | |
| 160 | let result_with_ref = || &x.field; | |
| 161 | match result_with_ref() { | |
| 162 | //~^ manual_ok_err | |
| 163 | Ok(panel) => Some(panel), | |
| 164 | Err(_) => None, | |
| 165 | } | |
| 166 | } | |
| 167 | ||
| 168 | fn result_with_ref_mut(x: &mut Container) -> &mut Result<bool, ()> { | |
| 169 | &mut x.field | |
| 170 | } | |
| 171 | ||
| 172 | fn from_fn_mut(x: &mut Container) -> Option<&mut bool> { | |
| 173 | match result_with_ref_mut(x) { | |
| 174 | //~^ manual_ok_err | |
| 175 | Ok(panel) => Some(panel), | |
| 176 | Err(_) => None, | |
| 177 | } | |
| 178 | } | |
| 179 | } |
src/tools/clippy/tests/ui/manual_ok_err.stderr+31-1| ... | ... | @@ -111,5 +111,35 @@ LL + "1".parse::<u8>().ok() |
| 111 | 111 | LL ~ }; |
| 112 | 112 | | |
| 113 | 113 | |
| 114 | error: aborting due to 9 previous errors | |
| 114 | error: manual implementation of `ok` | |
| 115 | --> tests/ui/manual_ok_err.rs:152:9 | |
| 116 | | | |
| 117 | LL | / match &x.field { | |
| 118 | LL | | | |
| 119 | LL | | Ok(panel) => Some(panel), | |
| 120 | LL | | Err(_) => None, | |
| 121 | LL | | } | |
| 122 | | |_________^ help: replace with: `(&x.field).as_ref().ok()` | |
| 123 | ||
| 124 | error: manual implementation of `ok` | |
| 125 | --> tests/ui/manual_ok_err.rs:161:9 | |
| 126 | | | |
| 127 | LL | / match result_with_ref() { | |
| 128 | LL | | | |
| 129 | LL | | Ok(panel) => Some(panel), | |
| 130 | LL | | Err(_) => None, | |
| 131 | LL | | } | |
| 132 | | |_________^ help: replace with: `result_with_ref().as_ref().ok()` | |
| 133 | ||
| 134 | error: manual implementation of `ok` | |
| 135 | --> tests/ui/manual_ok_err.rs:173:9 | |
| 136 | | | |
| 137 | LL | / match result_with_ref_mut(x) { | |
| 138 | LL | | | |
| 139 | LL | | Ok(panel) => Some(panel), | |
| 140 | LL | | Err(_) => None, | |
| 141 | LL | | } | |
| 142 | | |_________^ help: replace with: `result_with_ref_mut(x).as_mut().ok()` | |
| 143 | ||
| 144 | error: aborting due to 12 previous errors | |
| 115 | 145 |
src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed+1-1| ... | ... | @@ -25,7 +25,7 @@ const fn can_be_const() { |
| 25 | 25 | 0u64.method(); |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | // False negative, see FIXME comment in `clipy_utils::qualify_min_const` | |
| 28 | // False negative, see FIXME comment in `clippy_utils::qualify_min_const_fn` | |
| 29 | 29 | fn could_be_const_but_does_not_trigger<T>(t: T) |
| 30 | 30 | where |
| 31 | 31 | T: const ConstTrait, |
src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs+1-1| ... | ... | @@ -25,7 +25,7 @@ fn can_be_const() { |
| 25 | 25 | 0u64.method(); |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | // False negative, see FIXME comment in `clipy_utils::qualify_min_const` | |
| 28 | // False negative, see FIXME comment in `clippy_utils::qualify_min_const_fn` | |
| 29 | 29 | fn could_be_const_but_does_not_trigger<T>(t: T) |
| 30 | 30 | where |
| 31 | 31 | T: const ConstTrait, |
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed+57| ... | ... | @@ -221,3 +221,60 @@ const fn mut_add(x: &mut i32) { |
| 221 | 221 | //~^ missing_const_for_fn |
| 222 | 222 | *x += 1; |
| 223 | 223 | } |
| 224 | ||
| 225 | mod issue_15079 { | |
| 226 | pub trait Trait {} | |
| 227 | ||
| 228 | pub struct Struct<T: Trait> { | |
| 229 | _t: Option<T>, | |
| 230 | } | |
| 231 | ||
| 232 | impl<T: Trait> Struct<T> { | |
| 233 | #[clippy::msrv = "1.60"] | |
| 234 | pub fn new_1_60() -> Self { | |
| 235 | Self { _t: None } | |
| 236 | } | |
| 237 | ||
| 238 | #[clippy::msrv = "1.61"] | |
| 239 | pub const fn new_1_61() -> Self { | |
| 240 | //~^ missing_const_for_fn | |
| 241 | Self { _t: None } | |
| 242 | } | |
| 243 | } | |
| 244 | ||
| 245 | pub struct S2<T> { | |
| 246 | _t: Option<T>, | |
| 247 | } | |
| 248 | ||
| 249 | impl<T> S2<T> { | |
| 250 | #[clippy::msrv = "1.60"] | |
| 251 | pub const fn new_1_60() -> Self { | |
| 252 | //~^ missing_const_for_fn | |
| 253 | Self { _t: None } | |
| 254 | } | |
| 255 | ||
| 256 | #[clippy::msrv = "1.61"] | |
| 257 | pub const fn new_1_61() -> Self { | |
| 258 | //~^ missing_const_for_fn | |
| 259 | Self { _t: None } | |
| 260 | } | |
| 261 | } | |
| 262 | ||
| 263 | pub struct S3<T: ?Sized + 'static> { | |
| 264 | _t: Option<&'static T>, | |
| 265 | } | |
| 266 | ||
| 267 | impl<T: ?Sized + 'static> S3<T> { | |
| 268 | #[clippy::msrv = "1.60"] | |
| 269 | pub const fn new_1_60() -> Self { | |
| 270 | //~^ missing_const_for_fn | |
| 271 | Self { _t: None } | |
| 272 | } | |
| 273 | ||
| 274 | #[clippy::msrv = "1.61"] | |
| 275 | pub const fn new_1_61() -> Self { | |
| 276 | //~^ missing_const_for_fn | |
| 277 | Self { _t: None } | |
| 278 | } | |
| 279 | } | |
| 280 | } |
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs+57| ... | ... | @@ -221,3 +221,60 @@ fn mut_add(x: &mut i32) { |
| 221 | 221 | //~^ missing_const_for_fn |
| 222 | 222 | *x += 1; |
| 223 | 223 | } |
| 224 | ||
| 225 | mod issue_15079 { | |
| 226 | pub trait Trait {} | |
| 227 | ||
| 228 | pub struct Struct<T: Trait> { | |
| 229 | _t: Option<T>, | |
| 230 | } | |
| 231 | ||
| 232 | impl<T: Trait> Struct<T> { | |
| 233 | #[clippy::msrv = "1.60"] | |
| 234 | pub fn new_1_60() -> Self { | |
| 235 | Self { _t: None } | |
| 236 | } | |
| 237 | ||
| 238 | #[clippy::msrv = "1.61"] | |
| 239 | pub fn new_1_61() -> Self { | |
| 240 | //~^ missing_const_for_fn | |
| 241 | Self { _t: None } | |
| 242 | } | |
| 243 | } | |
| 244 | ||
| 245 | pub struct S2<T> { | |
| 246 | _t: Option<T>, | |
| 247 | } | |
| 248 | ||
| 249 | impl<T> S2<T> { | |
| 250 | #[clippy::msrv = "1.60"] | |
| 251 | pub fn new_1_60() -> Self { | |
| 252 | //~^ missing_const_for_fn | |
| 253 | Self { _t: None } | |
| 254 | } | |
| 255 | ||
| 256 | #[clippy::msrv = "1.61"] | |
| 257 | pub fn new_1_61() -> Self { | |
| 258 | //~^ missing_const_for_fn | |
| 259 | Self { _t: None } | |
| 260 | } | |
| 261 | } | |
| 262 | ||
| 263 | pub struct S3<T: ?Sized + 'static> { | |
| 264 | _t: Option<&'static T>, | |
| 265 | } | |
| 266 | ||
| 267 | impl<T: ?Sized + 'static> S3<T> { | |
| 268 | #[clippy::msrv = "1.60"] | |
| 269 | pub fn new_1_60() -> Self { | |
| 270 | //~^ missing_const_for_fn | |
| 271 | Self { _t: None } | |
| 272 | } | |
| 273 | ||
| 274 | #[clippy::msrv = "1.61"] | |
| 275 | pub fn new_1_61() -> Self { | |
| 276 | //~^ missing_const_for_fn | |
| 277 | Self { _t: None } | |
| 278 | } | |
| 279 | } | |
| 280 | } |
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr+71-1| ... | ... | @@ -332,5 +332,75 @@ help: make the function `const` |
| 332 | 332 | LL | const fn mut_add(x: &mut i32) { |
| 333 | 333 | | +++++ |
| 334 | 334 | |
| 335 | error: aborting due to 25 previous errors | |
| 335 | error: this could be a `const fn` | |
| 336 | --> tests/ui/missing_const_for_fn/could_be_const.rs:239:9 | |
| 337 | | | |
| 338 | LL | / pub fn new_1_61() -> Self { | |
| 339 | LL | | | |
| 340 | LL | | Self { _t: None } | |
| 341 | LL | | } | |
| 342 | | |_________^ | |
| 343 | | | |
| 344 | help: make the function `const` | |
| 345 | | | |
| 346 | LL | pub const fn new_1_61() -> Self { | |
| 347 | | +++++ | |
| 348 | ||
| 349 | error: this could be a `const fn` | |
| 350 | --> tests/ui/missing_const_for_fn/could_be_const.rs:251:9 | |
| 351 | | | |
| 352 | LL | / pub fn new_1_60() -> Self { | |
| 353 | LL | | | |
| 354 | LL | | Self { _t: None } | |
| 355 | LL | | } | |
| 356 | | |_________^ | |
| 357 | | | |
| 358 | help: make the function `const` | |
| 359 | | | |
| 360 | LL | pub const fn new_1_60() -> Self { | |
| 361 | | +++++ | |
| 362 | ||
| 363 | error: this could be a `const fn` | |
| 364 | --> tests/ui/missing_const_for_fn/could_be_const.rs:257:9 | |
| 365 | | | |
| 366 | LL | / pub fn new_1_61() -> Self { | |
| 367 | LL | | | |
| 368 | LL | | Self { _t: None } | |
| 369 | LL | | } | |
| 370 | | |_________^ | |
| 371 | | | |
| 372 | help: make the function `const` | |
| 373 | | | |
| 374 | LL | pub const fn new_1_61() -> Self { | |
| 375 | | +++++ | |
| 376 | ||
| 377 | error: this could be a `const fn` | |
| 378 | --> tests/ui/missing_const_for_fn/could_be_const.rs:269:9 | |
| 379 | | | |
| 380 | LL | / pub fn new_1_60() -> Self { | |
| 381 | LL | | | |
| 382 | LL | | Self { _t: None } | |
| 383 | LL | | } | |
| 384 | | |_________^ | |
| 385 | | | |
| 386 | help: make the function `const` | |
| 387 | | | |
| 388 | LL | pub const fn new_1_60() -> Self { | |
| 389 | | +++++ | |
| 390 | ||
| 391 | error: this could be a `const fn` | |
| 392 | --> tests/ui/missing_const_for_fn/could_be_const.rs:275:9 | |
| 393 | | | |
| 394 | LL | / pub fn new_1_61() -> Self { | |
| 395 | LL | | | |
| 396 | LL | | Self { _t: None } | |
| 397 | LL | | } | |
| 398 | | |_________^ | |
| 399 | | | |
| 400 | help: make the function `const` | |
| 401 | | | |
| 402 | LL | pub const fn new_1_61() -> Self { | |
| 403 | | +++++ | |
| 404 | ||
| 405 | error: aborting due to 30 previous errors | |
| 336 | 406 |
src/tools/clippy/tests/ui/nonminimal_bool.stderr+2-2| ... | ... | @@ -179,7 +179,7 @@ error: inequality checks against true can be replaced by a negation |
| 179 | 179 | --> tests/ui/nonminimal_bool.rs:186:8 |
| 180 | 180 | | |
| 181 | 181 | LL | if !b != true {} |
| 182 | | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)` | |
| 182 | | ^^^^^^^^^^ help: try simplifying it as shown: `!!b` | |
| 183 | 183 | |
| 184 | 184 | error: this boolean expression can be simplified |
| 185 | 185 | --> tests/ui/nonminimal_bool.rs:189:8 |
| ... | ... | @@ -209,7 +209,7 @@ error: inequality checks against true can be replaced by a negation |
| 209 | 209 | --> tests/ui/nonminimal_bool.rs:193:8 |
| 210 | 210 | | |
| 211 | 211 | LL | if true != !b {} |
| 212 | | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)` | |
| 212 | | ^^^^^^^^^^ help: try simplifying it as shown: `!!b` | |
| 213 | 213 | |
| 214 | 214 | error: this boolean expression can be simplified |
| 215 | 215 | --> tests/ui/nonminimal_bool.rs:196:8 |
src/tools/clippy/tests/ui/or_fun_call.fixed+30| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | clippy::uninlined_format_args, |
| 6 | 6 | clippy::unnecessary_wraps, |
| 7 | 7 | clippy::unnecessary_literal_unwrap, |
| 8 | clippy::unnecessary_result_map_or_else, | |
| 8 | 9 | clippy::useless_vec |
| 9 | 10 | )] |
| 10 | 11 | |
| ... | ... | @@ -409,4 +410,33 @@ fn fn_call_in_nested_expr() { |
| 409 | 410 | //~^ or_fun_call |
| 410 | 411 | } |
| 411 | 412 | |
| 413 | mod result_map_or { | |
| 414 | fn g() -> i32 { | |
| 415 | 3 | |
| 416 | } | |
| 417 | ||
| 418 | fn f(n: i32) -> i32 { | |
| 419 | n | |
| 420 | } | |
| 421 | ||
| 422 | fn test_map_or() { | |
| 423 | let x: Result<i32, ()> = Ok(4); | |
| 424 | let _ = x.map_or_else(|_| g(), |v| v); | |
| 425 | //~^ or_fun_call | |
| 426 | let _ = x.map_or_else(|_| g(), f); | |
| 427 | //~^ or_fun_call | |
| 428 | let _ = x.map_or(0, f); | |
| 429 | } | |
| 430 | } | |
| 431 | ||
| 432 | fn test_option_get_or_insert() { | |
| 433 | // assume that this is slow call | |
| 434 | fn g() -> u8 { | |
| 435 | 99 | |
| 436 | } | |
| 437 | let mut x = Some(42_u8); | |
| 438 | let _ = x.get_or_insert_with(g); | |
| 439 | //~^ or_fun_call | |
| 440 | } | |
| 441 | ||
| 412 | 442 | fn main() {} |
src/tools/clippy/tests/ui/or_fun_call.rs+30| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | clippy::uninlined_format_args, |
| 6 | 6 | clippy::unnecessary_wraps, |
| 7 | 7 | clippy::unnecessary_literal_unwrap, |
| 8 | clippy::unnecessary_result_map_or_else, | |
| 8 | 9 | clippy::useless_vec |
| 9 | 10 | )] |
| 10 | 11 | |
| ... | ... | @@ -409,4 +410,33 @@ fn fn_call_in_nested_expr() { |
| 409 | 410 | //~^ or_fun_call |
| 410 | 411 | } |
| 411 | 412 | |
| 413 | mod result_map_or { | |
| 414 | fn g() -> i32 { | |
| 415 | 3 | |
| 416 | } | |
| 417 | ||
| 418 | fn f(n: i32) -> i32 { | |
| 419 | n | |
| 420 | } | |
| 421 | ||
| 422 | fn test_map_or() { | |
| 423 | let x: Result<i32, ()> = Ok(4); | |
| 424 | let _ = x.map_or(g(), |v| v); | |
| 425 | //~^ or_fun_call | |
| 426 | let _ = x.map_or(g(), f); | |
| 427 | //~^ or_fun_call | |
| 428 | let _ = x.map_or(0, f); | |
| 429 | } | |
| 430 | } | |
| 431 | ||
| 432 | fn test_option_get_or_insert() { | |
| 433 | // assume that this is slow call | |
| 434 | fn g() -> u8 { | |
| 435 | 99 | |
| 436 | } | |
| 437 | let mut x = Some(42_u8); | |
| 438 | let _ = x.get_or_insert(g()); | |
| 439 | //~^ or_fun_call | |
| 440 | } | |
| 441 | ||
| 412 | 442 | fn main() {} |
src/tools/clippy/tests/ui/or_fun_call.stderr+57-39| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: function call inside of `unwrap_or` |
| 2 | --> tests/ui/or_fun_call.rs:52:22 | |
| 2 | --> tests/ui/or_fun_call.rs:53:22 | |
| 3 | 3 | | |
| 4 | 4 | LL | with_constructor.unwrap_or(make()); |
| 5 | 5 | | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)` |
| ... | ... | @@ -8,7 +8,7 @@ LL | with_constructor.unwrap_or(make()); |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]` |
| 9 | 9 | |
| 10 | 10 | error: use of `unwrap_or` to construct default value |
| 11 | --> tests/ui/or_fun_call.rs:56:14 | |
| 11 | --> tests/ui/or_fun_call.rs:57:14 | |
| 12 | 12 | | |
| 13 | 13 | LL | with_new.unwrap_or(Vec::new()); |
| 14 | 14 | | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| ... | ... | @@ -17,199 +17,199 @@ LL | with_new.unwrap_or(Vec::new()); |
| 17 | 17 | = help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]` |
| 18 | 18 | |
| 19 | 19 | error: function call inside of `unwrap_or` |
| 20 | --> tests/ui/or_fun_call.rs:60:21 | |
| 20 | --> tests/ui/or_fun_call.rs:61:21 | |
| 21 | 21 | | |
| 22 | 22 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); |
| 23 | 23 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))` |
| 24 | 24 | |
| 25 | 25 | error: function call inside of `unwrap_or` |
| 26 | --> tests/ui/or_fun_call.rs:64:14 | |
| 26 | --> tests/ui/or_fun_call.rs:65:14 | |
| 27 | 27 | | |
| 28 | 28 | LL | with_err.unwrap_or(make()); |
| 29 | 29 | | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())` |
| 30 | 30 | |
| 31 | 31 | error: function call inside of `unwrap_or` |
| 32 | --> tests/ui/or_fun_call.rs:68:19 | |
| 32 | --> tests/ui/or_fun_call.rs:69:19 | |
| 33 | 33 | | |
| 34 | 34 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); |
| 35 | 35 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))` |
| 36 | 36 | |
| 37 | 37 | error: use of `unwrap_or` to construct default value |
| 38 | --> tests/ui/or_fun_call.rs:72:24 | |
| 38 | --> tests/ui/or_fun_call.rs:73:24 | |
| 39 | 39 | | |
| 40 | 40 | LL | with_default_trait.unwrap_or(Default::default()); |
| 41 | 41 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 42 | 42 | |
| 43 | 43 | error: use of `unwrap_or` to construct default value |
| 44 | --> tests/ui/or_fun_call.rs:76:23 | |
| 44 | --> tests/ui/or_fun_call.rs:77:23 | |
| 45 | 45 | | |
| 46 | 46 | LL | with_default_type.unwrap_or(u64::default()); |
| 47 | 47 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 48 | 48 | |
| 49 | 49 | error: function call inside of `unwrap_or` |
| 50 | --> tests/ui/or_fun_call.rs:80:18 | |
| 50 | --> tests/ui/or_fun_call.rs:81:18 | |
| 51 | 51 | | |
| 52 | 52 | LL | self_default.unwrap_or(<FakeDefault>::default()); |
| 53 | 53 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)` |
| 54 | 54 | |
| 55 | 55 | error: use of `unwrap_or` to construct default value |
| 56 | --> tests/ui/or_fun_call.rs:84:18 | |
| 56 | --> tests/ui/or_fun_call.rs:85:18 | |
| 57 | 57 | | |
| 58 | 58 | LL | real_default.unwrap_or(<FakeDefault as Default>::default()); |
| 59 | 59 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 60 | 60 | |
| 61 | 61 | error: use of `unwrap_or` to construct default value |
| 62 | --> tests/ui/or_fun_call.rs:88:14 | |
| 62 | --> tests/ui/or_fun_call.rs:89:14 | |
| 63 | 63 | | |
| 64 | 64 | LL | with_vec.unwrap_or(vec![]); |
| 65 | 65 | | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 66 | 66 | |
| 67 | 67 | error: function call inside of `unwrap_or` |
| 68 | --> tests/ui/or_fun_call.rs:92:21 | |
| 68 | --> tests/ui/or_fun_call.rs:93:21 | |
| 69 | 69 | | |
| 70 | 70 | LL | without_default.unwrap_or(Foo::new()); |
| 71 | 71 | | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)` |
| 72 | 72 | |
| 73 | 73 | error: use of `or_insert` to construct default value |
| 74 | --> tests/ui/or_fun_call.rs:96:19 | |
| 74 | --> tests/ui/or_fun_call.rs:97:19 | |
| 75 | 75 | | |
| 76 | 76 | LL | map.entry(42).or_insert(String::new()); |
| 77 | 77 | | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` |
| 78 | 78 | |
| 79 | 79 | error: use of `or_insert` to construct default value |
| 80 | --> tests/ui/or_fun_call.rs:100:23 | |
| 80 | --> tests/ui/or_fun_call.rs:101:23 | |
| 81 | 81 | | |
| 82 | 82 | LL | map_vec.entry(42).or_insert(vec![]); |
| 83 | 83 | | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` |
| 84 | 84 | |
| 85 | 85 | error: use of `or_insert` to construct default value |
| 86 | --> tests/ui/or_fun_call.rs:104:21 | |
| 86 | --> tests/ui/or_fun_call.rs:105:21 | |
| 87 | 87 | | |
| 88 | 88 | LL | btree.entry(42).or_insert(String::new()); |
| 89 | 89 | | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` |
| 90 | 90 | |
| 91 | 91 | error: use of `or_insert` to construct default value |
| 92 | --> tests/ui/or_fun_call.rs:108:25 | |
| 92 | --> tests/ui/or_fun_call.rs:109:25 | |
| 93 | 93 | | |
| 94 | 94 | LL | btree_vec.entry(42).or_insert(vec![]); |
| 95 | 95 | | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` |
| 96 | 96 | |
| 97 | 97 | error: use of `unwrap_or` to construct default value |
| 98 | --> tests/ui/or_fun_call.rs:112:21 | |
| 98 | --> tests/ui/or_fun_call.rs:113:21 | |
| 99 | 99 | | |
| 100 | 100 | LL | let _ = stringy.unwrap_or(String::new()); |
| 101 | 101 | | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 102 | 102 | |
| 103 | 103 | error: function call inside of `ok_or` |
| 104 | --> tests/ui/or_fun_call.rs:117:17 | |
| 104 | --> tests/ui/or_fun_call.rs:118:17 | |
| 105 | 105 | | |
| 106 | 106 | LL | let _ = opt.ok_or(format!("{} world.", hello)); |
| 107 | 107 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))` |
| 108 | 108 | |
| 109 | 109 | error: function call inside of `unwrap_or` |
| 110 | --> tests/ui/or_fun_call.rs:122:21 | |
| 110 | --> tests/ui/or_fun_call.rs:123:21 | |
| 111 | 111 | | |
| 112 | 112 | LL | let _ = Some(1).unwrap_or(map[&1]); |
| 113 | 113 | | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` |
| 114 | 114 | |
| 115 | 115 | error: function call inside of `unwrap_or` |
| 116 | --> tests/ui/or_fun_call.rs:125:21 | |
| 116 | --> tests/ui/or_fun_call.rs:126:21 | |
| 117 | 117 | | |
| 118 | 118 | LL | let _ = Some(1).unwrap_or(map[&1]); |
| 119 | 119 | | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` |
| 120 | 120 | |
| 121 | 121 | error: function call inside of `or` |
| 122 | --> tests/ui/or_fun_call.rs:150:35 | |
| 122 | --> tests/ui/or_fun_call.rs:151:35 | |
| 123 | 123 | | |
| 124 | 124 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); |
| 125 | 125 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))` |
| 126 | 126 | |
| 127 | 127 | error: function call inside of `unwrap_or` |
| 128 | --> tests/ui/or_fun_call.rs:193:18 | |
| 128 | --> tests/ui/or_fun_call.rs:194:18 | |
| 129 | 129 | | |
| 130 | 130 | LL | None.unwrap_or(ptr_to_ref(s)); |
| 131 | 131 | | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))` |
| 132 | 132 | |
| 133 | 133 | error: function call inside of `unwrap_or` |
| 134 | --> tests/ui/or_fun_call.rs:201:14 | |
| 134 | --> tests/ui/or_fun_call.rs:202:14 | |
| 135 | 135 | | |
| 136 | 136 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); |
| 137 | 137 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` |
| 138 | 138 | |
| 139 | 139 | error: function call inside of `unwrap_or` |
| 140 | --> tests/ui/or_fun_call.rs:204:14 | |
| 140 | --> tests/ui/or_fun_call.rs:205:14 | |
| 141 | 141 | | |
| 142 | 142 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); |
| 143 | 143 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` |
| 144 | 144 | |
| 145 | 145 | error: function call inside of `map_or` |
| 146 | --> tests/ui/or_fun_call.rs:280:25 | |
| 146 | --> tests/ui/or_fun_call.rs:281:25 | |
| 147 | 147 | | |
| 148 | 148 | LL | let _ = Some(4).map_or(g(), |v| v); |
| 149 | 149 | | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)` |
| 150 | 150 | |
| 151 | 151 | error: function call inside of `map_or` |
| 152 | --> tests/ui/or_fun_call.rs:282:25 | |
| 152 | --> tests/ui/or_fun_call.rs:283:25 | |
| 153 | 153 | | |
| 154 | 154 | LL | let _ = Some(4).map_or(g(), f); |
| 155 | 155 | | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)` |
| 156 | 156 | |
| 157 | 157 | error: use of `unwrap_or_else` to construct default value |
| 158 | --> tests/ui/or_fun_call.rs:314:18 | |
| 158 | --> tests/ui/or_fun_call.rs:315:18 | |
| 159 | 159 | | |
| 160 | 160 | LL | with_new.unwrap_or_else(Vec::new); |
| 161 | 161 | | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 162 | 162 | |
| 163 | 163 | error: use of `unwrap_or_else` to construct default value |
| 164 | --> tests/ui/or_fun_call.rs:318:28 | |
| 164 | --> tests/ui/or_fun_call.rs:319:28 | |
| 165 | 165 | | |
| 166 | 166 | LL | with_default_trait.unwrap_or_else(Default::default); |
| 167 | 167 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 168 | 168 | |
| 169 | 169 | error: use of `unwrap_or_else` to construct default value |
| 170 | --> tests/ui/or_fun_call.rs:322:27 | |
| 170 | --> tests/ui/or_fun_call.rs:323:27 | |
| 171 | 171 | | |
| 172 | 172 | LL | with_default_type.unwrap_or_else(u64::default); |
| 173 | 173 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 174 | 174 | |
| 175 | 175 | error: use of `unwrap_or_else` to construct default value |
| 176 | --> tests/ui/or_fun_call.rs:326:22 | |
| 176 | --> tests/ui/or_fun_call.rs:327:22 | |
| 177 | 177 | | |
| 178 | 178 | LL | real_default.unwrap_or_else(<FakeDefault as Default>::default); |
| 179 | 179 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 180 | 180 | |
| 181 | 181 | error: use of `or_insert_with` to construct default value |
| 182 | --> tests/ui/or_fun_call.rs:330:23 | |
| 182 | --> tests/ui/or_fun_call.rs:331:23 | |
| 183 | 183 | | |
| 184 | 184 | LL | map.entry(42).or_insert_with(String::new); |
| 185 | 185 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` |
| 186 | 186 | |
| 187 | 187 | error: use of `or_insert_with` to construct default value |
| 188 | --> tests/ui/or_fun_call.rs:334:25 | |
| 188 | --> tests/ui/or_fun_call.rs:335:25 | |
| 189 | 189 | | |
| 190 | 190 | LL | btree.entry(42).or_insert_with(String::new); |
| 191 | 191 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` |
| 192 | 192 | |
| 193 | 193 | error: use of `unwrap_or_else` to construct default value |
| 194 | --> tests/ui/or_fun_call.rs:338:25 | |
| 194 | --> tests/ui/or_fun_call.rs:339:25 | |
| 195 | 195 | | |
| 196 | 196 | LL | let _ = stringy.unwrap_or_else(String::new); |
| 197 | 197 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 198 | 198 | |
| 199 | 199 | error: function call inside of `unwrap_or` |
| 200 | --> tests/ui/or_fun_call.rs:380:17 | |
| 200 | --> tests/ui/or_fun_call.rs:381:17 | |
| 201 | 201 | | |
| 202 | 202 | LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` |
| 203 | 203 | | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)` |
| 204 | 204 | |
| 205 | 205 | error: function call inside of `unwrap_or` |
| 206 | --> tests/ui/or_fun_call.rs:385:17 | |
| 206 | --> tests/ui/or_fun_call.rs:386:17 | |
| 207 | 207 | | |
| 208 | 208 | LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` |
| 209 | 209 | | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)` |
| 210 | 210 | |
| 211 | 211 | error: function call inside of `unwrap_or` |
| 212 | --> tests/ui/or_fun_call.rs:390:17 | |
| 212 | --> tests/ui/or_fun_call.rs:391:17 | |
| 213 | 213 | | |
| 214 | 214 | LL | let _ = opt.unwrap_or({ |
| 215 | 215 | | _________________^ |
| ... | ... | @@ -229,22 +229,40 @@ LL ~ }); |
| 229 | 229 | | |
| 230 | 230 | |
| 231 | 231 | error: function call inside of `map_or` |
| 232 | --> tests/ui/or_fun_call.rs:396:17 | |
| 232 | --> tests/ui/or_fun_call.rs:397:17 | |
| 233 | 233 | | |
| 234 | 234 | LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` |
| 235 | 235 | | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)` |
| 236 | 236 | |
| 237 | 237 | error: use of `unwrap_or` to construct default value |
| 238 | --> tests/ui/or_fun_call.rs:401:17 | |
| 238 | --> tests/ui/or_fun_call.rs:402:17 | |
| 239 | 239 | | |
| 240 | 240 | LL | let _ = opt.unwrap_or({ i32::default() }); |
| 241 | 241 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` |
| 242 | 242 | |
| 243 | 243 | error: function call inside of `unwrap_or` |
| 244 | --> tests/ui/or_fun_call.rs:408:21 | |
| 244 | --> tests/ui/or_fun_call.rs:409:21 | |
| 245 | 245 | | |
| 246 | 246 | LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() }); |
| 247 | 247 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })` |
| 248 | 248 | |
| 249 | error: aborting due to 38 previous errors | |
| 249 | error: function call inside of `map_or` | |
| 250 | --> tests/ui/or_fun_call.rs:424:19 | |
| 251 | | | |
| 252 | LL | let _ = x.map_or(g(), |v| v); | |
| 253 | | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), |v| v)` | |
| 254 | ||
| 255 | error: function call inside of `map_or` | |
| 256 | --> tests/ui/or_fun_call.rs:426:19 | |
| 257 | | | |
| 258 | LL | let _ = x.map_or(g(), f); | |
| 259 | | ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)` | |
| 260 | ||
| 261 | error: function call inside of `get_or_insert` | |
| 262 | --> tests/ui/or_fun_call.rs:438:15 | |
| 263 | | | |
| 264 | LL | let _ = x.get_or_insert(g()); | |
| 265 | | ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)` | |
| 266 | ||
| 267 | error: aborting due to 41 previous errors | |
| 250 | 268 |
src/tools/clippy/tests/ui/question_mark.fixed+12| ... | ... | @@ -453,3 +453,15 @@ fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> { |
| 453 | 453 | |
| 454 | 454 | None |
| 455 | 455 | } |
| 456 | ||
| 457 | fn issue_13642(x: Option<i32>) -> Option<()> { | |
| 458 | let Some(x) = x else { | |
| 459 | #[cfg(false)] | |
| 460 | panic!(); | |
| 461 | ||
| 462 | #[cfg(true)] | |
| 463 | return None; | |
| 464 | }; | |
| 465 | ||
| 466 | None | |
| 467 | } |
src/tools/clippy/tests/ui/question_mark.rs+12| ... | ... | @@ -549,3 +549,15 @@ fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> { |
| 549 | 549 | |
| 550 | 550 | None |
| 551 | 551 | } |
| 552 | ||
| 553 | fn issue_13642(x: Option<i32>) -> Option<()> { | |
| 554 | let Some(x) = x else { | |
| 555 | #[cfg(false)] | |
| 556 | panic!(); | |
| 557 | ||
| 558 | #[cfg(true)] | |
| 559 | return None; | |
| 560 | }; | |
| 561 | ||
| 562 | None | |
| 563 | } |
src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs+13| ... | ... | @@ -21,3 +21,16 @@ fn main() { |
| 21 | 21 | let _: String = format!("{:?}", os_str); //~ unnecessary_debug_formatting |
| 22 | 22 | let _: String = format!("{:?}", os_string); //~ unnecessary_debug_formatting |
| 23 | 23 | } |
| 24 | ||
| 25 | #[clippy::msrv = "1.86"] | |
| 26 | fn msrv_1_86() { | |
| 27 | let os_str = OsStr::new("test"); | |
| 28 | println!("{:?}", os_str); | |
| 29 | } | |
| 30 | ||
| 31 | #[clippy::msrv = "1.87"] | |
| 32 | fn msrv_1_87() { | |
| 33 | let os_str = OsStr::new("test"); | |
| 34 | println!("{:?}", os_str); | |
| 35 | //~^ unnecessary_debug_formatting | |
| 36 | } |
src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr+10-1| ... | ... | @@ -54,5 +54,14 @@ LL | let _: String = format!("{:?}", os_string); |
| 54 | 54 | = help: use `Display` formatting and change this to `os_string.display()` |
| 55 | 55 | = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed |
| 56 | 56 | |
| 57 | error: aborting due to 6 previous errors | |
| 57 | error: unnecessary `Debug` formatting in `println!` args | |
| 58 | --> tests/ui/unnecessary_os_str_debug_formatting.rs:34:22 | |
| 59 | | | |
| 60 | LL | println!("{:?}", os_str); | |
| 61 | | ^^^^^^ | |
| 62 | | | |
| 63 | = help: use `Display` formatting and change this to `os_str.display()` | |
| 64 | = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed | |
| 65 | ||
| 66 | error: aborting due to 7 previous errors | |
| 58 | 67 |
src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed+29| ... | ... | @@ -90,6 +90,21 @@ fn main() { |
| 90 | 90 | _ => {}, |
| 91 | 91 | } |
| 92 | 92 | |
| 93 | { | |
| 94 | pub enum Enum { | |
| 95 | A, | |
| 96 | B, | |
| 97 | C(u8), | |
| 98 | D(u8, u8), | |
| 99 | E { e: u8 }, | |
| 100 | }; | |
| 101 | match Enum::A { | |
| 102 | Enum::A => (), | |
| 103 | Enum::B | Enum::C(_) | Enum::D(..) | Enum::E { .. } => (), | |
| 104 | //~^ wildcard_enum_match_arm | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 93 | 108 | { |
| 94 | 109 | #![allow(clippy::manual_non_exhaustive)] |
| 95 | 110 | pub enum Enum { |
| ... | ... | @@ -105,3 +120,17 @@ fn main() { |
| 105 | 120 | } |
| 106 | 121 | } |
| 107 | 122 | } |
| 123 | ||
| 124 | fn issue15091() { | |
| 125 | enum Foo { | |
| 126 | A, | |
| 127 | B, | |
| 128 | C, | |
| 129 | } | |
| 130 | ||
| 131 | match Foo::A { | |
| 132 | Foo::A => {}, | |
| 133 | r#type @ Foo::B | r#type @ Foo::C => {}, | |
| 134 | //~^ wildcard_enum_match_arm | |
| 135 | } | |
| 136 | } |
src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs+29| ... | ... | @@ -90,6 +90,21 @@ fn main() { |
| 90 | 90 | _ => {}, |
| 91 | 91 | } |
| 92 | 92 | |
| 93 | { | |
| 94 | pub enum Enum { | |
| 95 | A, | |
| 96 | B, | |
| 97 | C(u8), | |
| 98 | D(u8, u8), | |
| 99 | E { e: u8 }, | |
| 100 | }; | |
| 101 | match Enum::A { | |
| 102 | Enum::A => (), | |
| 103 | _ => (), | |
| 104 | //~^ wildcard_enum_match_arm | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 93 | 108 | { |
| 94 | 109 | #![allow(clippy::manual_non_exhaustive)] |
| 95 | 110 | pub enum Enum { |
| ... | ... | @@ -105,3 +120,17 @@ fn main() { |
| 105 | 120 | } |
| 106 | 121 | } |
| 107 | 122 | } |
| 123 | ||
| 124 | fn issue15091() { | |
| 125 | enum Foo { | |
| 126 | A, | |
| 127 | B, | |
| 128 | C, | |
| 129 | } | |
| 130 | ||
| 131 | match Foo::A { | |
| 132 | Foo::A => {}, | |
| 133 | r#type => {}, | |
| 134 | //~^ wildcard_enum_match_arm | |
| 135 | } | |
| 136 | } |
src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr+13-1| ... | ... | @@ -37,8 +37,20 @@ LL | _ => {}, |
| 37 | 37 | error: wildcard match will also match any future added variants |
| 38 | 38 | --> tests/ui/wildcard_enum_match_arm.rs:103:13 |
| 39 | 39 | | |
| 40 | LL | _ => (), | |
| 41 | | ^ help: try: `Enum::B | Enum::C(_) | Enum::D(..) | Enum::E { .. }` | |
| 42 | ||
| 43 | error: wildcard match will also match any future added variants | |
| 44 | --> tests/ui/wildcard_enum_match_arm.rs:118:13 | |
| 45 | | | |
| 40 | 46 | LL | _ => (), |
| 41 | 47 | | ^ help: try: `Enum::B | Enum::__Private` |
| 42 | 48 | |
| 43 | error: aborting due to 6 previous errors | |
| 49 | error: wildcard match will also match any future added variants | |
| 50 | --> tests/ui/wildcard_enum_match_arm.rs:133:9 | |
| 51 | | | |
| 52 | LL | r#type => {}, | |
| 53 | | ^^^^^^ help: try: `r#type @ Foo::B | r#type @ Foo::C` | |
| 54 | ||
| 55 | error: aborting due to 8 previous errors | |
| 44 | 56 |
src/tools/clippy/tests/versioncheck.rs+1| ... | ... | @@ -27,6 +27,7 @@ fn consistent_clippy_crate_versions() { |
| 27 | 27 | "clippy_config/Cargo.toml", |
| 28 | 28 | "clippy_lints/Cargo.toml", |
| 29 | 29 | "clippy_utils/Cargo.toml", |
| 30 | "declare_clippy_lint/Cargo.toml", | |
| 30 | 31 | ]; |
| 31 | 32 | |
| 32 | 33 | for path in paths { |
src/tools/clippy/triagebot.toml+3| ... | ... | @@ -17,6 +17,9 @@ allow-unauthenticated = [ |
| 17 | 17 | |
| 18 | 18 | [issue-links] |
| 19 | 19 | |
| 20 | [mentions."clippy_lints/src/doc"] | |
| 21 | cc = ["@notriddle"] | |
| 22 | ||
| 20 | 23 | # Prevents mentions in commits to avoid users being spammed |
| 21 | 24 | [no-mentions] |
| 22 | 25 |
src/tools/clippy/util/versions.py+3-3| ... | ... | @@ -6,11 +6,11 @@ import os |
| 6 | 6 | import sys |
| 7 | 7 | |
| 8 | 8 | def key(v): |
| 9 | if v == "master": | |
| 10 | return sys.maxsize | |
| 11 | 9 | if v == "stable": |
| 12 | return sys.maxsize - 1 | |
| 10 | return sys.maxsize | |
| 13 | 11 | if v == "beta": |
| 12 | return sys.maxsize - 1 | |
| 13 | if v == "master": | |
| 14 | 14 | return sys.maxsize - 2 |
| 15 | 15 | if v == "pre-1.29.0": |
| 16 | 16 | return -1 |