| author | bors <bors@rust-lang.org> 2026-06-26 10:54:14 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-26 10:54:14 UTC |
| log | eb6346c659ccb0468a1477c716ca5450a1fa9ba1 |
| tree | 7c7221bb5a863bc8e05ff7b9ceecbde0c1f237a8 |
| parent | 40557f6225e337d68c8d4f086557ce54135f5dd9 |
| parent | 91c04dfcad15fc8d72681f5578a1183f5f29b332 |
Clippy subtree update
r? Manishearth 347 files changed, 5183 insertions(+), 3269 deletions(-)
compiler/rustc_codegen_gcc/src/common.rs+18-6| ... | ... | @@ -58,13 +58,19 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> |
| 58 | 58 | // or is it using a more efficient representation? |
| 59 | 59 | match bytes.len() % 8 { |
| 60 | 60 | 0 => { |
| 61 | debug_assert_eq!( | |
| 62 | bytes.len() % 8, | |
| 63 | 0, | |
| 64 | "bytes length is not a multiple of 8, so bytes.as_chunks will have a remainder" | |
| 65 | ); | |
| 61 | 66 | let context = &cx.context; |
| 62 | 67 | let byte_type = context.new_type::<u64>(); |
| 63 | 68 | let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 8); |
| 64 | 69 | let elements: Vec<_> = bytes |
| 65 | .chunks_exact(8) | |
| 66 | .map(|arr| { | |
| 67 | let arr: [u8; 8] = arr.try_into().unwrap(); | |
| 70 | .as_chunks::<8>() | |
| 71 | .0 | |
| 72 | .iter() | |
| 73 | .map(|&arr| { | |
| 68 | 74 | context.new_rvalue_from_long( |
| 69 | 75 | byte_type, |
| 70 | 76 | // Since we are representing arbitrary byte runs as integers, we need to follow the target |
| ... | ... | @@ -79,13 +85,19 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> |
| 79 | 85 | context.new_array_constructor(None, typ, &elements) |
| 80 | 86 | } |
| 81 | 87 | 4 => { |
| 88 | debug_assert_eq!( | |
| 89 | bytes.len() % 4, | |
| 90 | 0, | |
| 91 | "bytes length is not a multiple of 4, so bytes.as_chunks will have a remainder" | |
| 92 | ); | |
| 82 | 93 | let context = &cx.context; |
| 83 | 94 | let byte_type = context.new_type::<u32>(); |
| 84 | 95 | let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 4); |
| 85 | 96 | let elements: Vec<_> = bytes |
| 86 | .chunks_exact(4) | |
| 87 | .map(|arr| { | |
| 88 | let arr: [u8; 4] = arr.try_into().unwrap(); | |
| 97 | .as_chunks::<4>() | |
| 98 | .0 | |
| 99 | .iter() | |
| 100 | .map(|&arr| { | |
| 89 | 101 | context.new_rvalue_from_int( |
| 90 | 102 | byte_type, |
| 91 | 103 | match cx.sess().target.options.endian { |
src/tools/clippy/.github/FUNDING.yml created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | github: rustfoundation | |
| 2 | custom: [ "rust-lang.org/funding" ] |
src/tools/clippy/.github/workflows/clippy_dev.yml+1-1| ... | ... | @@ -16,7 +16,7 @@ jobs: |
| 16 | 16 | steps: |
| 17 | 17 | # Setup |
| 18 | 18 | - name: Checkout |
| 19 | uses: actions/checkout@v6 | |
| 19 | uses: actions/checkout@v7 | |
| 20 | 20 | with: |
| 21 | 21 | # Unsetting this would make so that any malicious package could get our Github Token |
| 22 | 22 | persist-credentials: false |
src/tools/clippy/.github/workflows/clippy_mq.yml+4-4| ... | ... | @@ -34,7 +34,7 @@ jobs: |
| 34 | 34 | steps: |
| 35 | 35 | # Setup |
| 36 | 36 | - name: Checkout |
| 37 | uses: actions/checkout@v6 | |
| 37 | uses: actions/checkout@v7 | |
| 38 | 38 | with: |
| 39 | 39 | persist-credentials: false |
| 40 | 40 | |
| ... | ... | @@ -94,7 +94,7 @@ jobs: |
| 94 | 94 | steps: |
| 95 | 95 | # Setup |
| 96 | 96 | - name: Checkout |
| 97 | uses: actions/checkout@v6 | |
| 97 | uses: actions/checkout@v7 | |
| 98 | 98 | with: |
| 99 | 99 | persist-credentials: false |
| 100 | 100 | |
| ... | ... | @@ -112,7 +112,7 @@ jobs: |
| 112 | 112 | steps: |
| 113 | 113 | # Setup |
| 114 | 114 | - name: Checkout |
| 115 | uses: actions/checkout@v6 | |
| 115 | uses: actions/checkout@v7 | |
| 116 | 116 | with: |
| 117 | 117 | persist-credentials: false |
| 118 | 118 | |
| ... | ... | @@ -168,7 +168,7 @@ jobs: |
| 168 | 168 | steps: |
| 169 | 169 | # Setup |
| 170 | 170 | - name: Checkout |
| 171 | uses: actions/checkout@v6 | |
| 171 | uses: actions/checkout@v7 | |
| 172 | 172 | with: |
| 173 | 173 | persist-credentials: false |
| 174 | 174 |
src/tools/clippy/.github/workflows/clippy_pr.yml+1-1| ... | ... | @@ -24,7 +24,7 @@ jobs: |
| 24 | 24 | steps: |
| 25 | 25 | # Setup |
| 26 | 26 | - name: Checkout |
| 27 | uses: actions/checkout@v6 | |
| 27 | uses: actions/checkout@v7 | |
| 28 | 28 | with: |
| 29 | 29 | # Unsetting this would make so that any malicious package could get our Github Token |
| 30 | 30 | persist-credentials: false |
src/tools/clippy/.github/workflows/deploy.yml+2-2| ... | ... | @@ -25,13 +25,13 @@ jobs: |
| 25 | 25 | steps: |
| 26 | 26 | # Setup |
| 27 | 27 | - name: Checkout |
| 28 | uses: actions/checkout@v6 | |
| 28 | uses: actions/checkout@v7 | |
| 29 | 29 | with: |
| 30 | 30 | # Unsetting this would make so that any malicious package could get our Github Token |
| 31 | 31 | persist-credentials: false |
| 32 | 32 | |
| 33 | 33 | - name: Checkout |
| 34 | uses: actions/checkout@v6 | |
| 34 | uses: actions/checkout@v7 | |
| 35 | 35 | with: |
| 36 | 36 | ref: ${{ env.TARGET_BRANCH }} |
| 37 | 37 | path: 'out' |
src/tools/clippy/.github/workflows/lintcheck.yml+3-3| ... | ... | @@ -24,7 +24,7 @@ jobs: |
| 24 | 24 | |
| 25 | 25 | steps: |
| 26 | 26 | - name: Checkout |
| 27 | uses: actions/checkout@v6 | |
| 27 | uses: actions/checkout@v7 | |
| 28 | 28 | with: |
| 29 | 29 | fetch-depth: 2 |
| 30 | 30 | # Unsetting this would make so that any malicious package could get our Github Token |
| ... | ... | @@ -80,7 +80,7 @@ jobs: |
| 80 | 80 | |
| 81 | 81 | steps: |
| 82 | 82 | - name: Checkout |
| 83 | uses: actions/checkout@v6 | |
| 83 | uses: actions/checkout@v7 | |
| 84 | 84 | with: |
| 85 | 85 | # Unsetting this would make so that any malicious package could get our Github Token |
| 86 | 86 | persist-credentials: false |
| ... | ... | @@ -113,7 +113,7 @@ jobs: |
| 113 | 113 | |
| 114 | 114 | steps: |
| 115 | 115 | - name: Checkout |
| 116 | uses: actions/checkout@v6 | |
| 116 | uses: actions/checkout@v7 | |
| 117 | 117 | with: |
| 118 | 118 | # Unsetting this would make so that any malicious package could get our Github Token |
| 119 | 119 | persist-credentials: false |
src/tools/clippy/.github/workflows/remark.yml+1-1| ... | ... | @@ -14,7 +14,7 @@ jobs: |
| 14 | 14 | steps: |
| 15 | 15 | # Setup |
| 16 | 16 | - name: Checkout |
| 17 | uses: actions/checkout@v6 | |
| 17 | uses: actions/checkout@v7 | |
| 18 | 18 | with: |
| 19 | 19 | # Unsetting this would make so that any malicious package could get our Github Token |
| 20 | 20 | persist-credentials: false |
src/tools/clippy/CHANGELOG.md+4-1| ... | ... | @@ -6670,6 +6670,7 @@ Released 2018-09-13 |
| 6670 | 6670 | [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local |
| 6671 | 6671 | [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code |
| 6672 | 6672 | [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow |
| 6673 | [`by_ref_peekable_peek`]: https://rust-lang.github.io/rust-clippy/master/index.html#by_ref_peekable_peek | |
| 6673 | 6674 | [`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices |
| 6674 | 6675 | [`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len |
| 6675 | 6676 | [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth |
| ... | ... | @@ -6694,6 +6695,7 @@ Released 2018-09-13 |
| 6694 | 6695 | [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp |
| 6695 | 6696 | [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp |
| 6696 | 6697 | [`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions |
| 6698 | [`chunks_exact_to_as_chunks`]: https://rust-lang.github.io/rust-clippy/master/index.html#chunks_exact_to_as_chunks | |
| 6697 | 6699 | [`clear_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#clear_with_drain |
| 6698 | 6700 | [`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref |
| 6699 | 6701 | [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy |
| ... | ... | @@ -7457,6 +7459,7 @@ Released 2018-09-13 |
| 7457 | 7459 | [`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned |
| 7458 | 7460 | [`unnecessary_trailing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_trailing_comma |
| 7459 | 7461 | [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap |
| 7462 | [`unnecessary_unwrap_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap_unchecked | |
| 7460 | 7463 | [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps |
| 7461 | 7464 | [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern |
| 7462 | 7465 | [`unneeded_struct_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_struct_pattern |
| ... | ... | @@ -7571,6 +7574,7 @@ Released 2018-09-13 |
| 7571 | 7574 | [`avoid-breaking-exported-api`]: https://doc.rust-lang.org/clippy/lint_configuration.html#avoid-breaking-exported-api |
| 7572 | 7575 | [`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types |
| 7573 | 7576 | [`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish |
| 7577 | [`check-grouped-late-init`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-grouped-late-init | |
| 7574 | 7578 | [`check-incompatible-msrv-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-incompatible-msrv-in-tests |
| 7575 | 7579 | [`check-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-inconsistent-struct-field-initializers |
| 7576 | 7580 | [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items |
| ... | ... | @@ -7608,7 +7612,6 @@ Released 2018-09-13 |
| 7608 | 7612 | [`module-items-ordered-within-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-items-ordered-within-groupings |
| 7609 | 7613 | [`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv |
| 7610 | 7614 | [`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit |
| 7611 | [`profiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#profiles | |
| 7612 | 7615 | [`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior |
| 7613 | 7616 | [`recursive-self-in-type-definitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#recursive-self-in-type-definitions |
| 7614 | 7617 | [`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline |
src/tools/clippy/book/src/continuous_integration/github_actions.md+1-1| ... | ... | @@ -15,7 +15,7 @@ jobs: |
| 15 | 15 | clippy_check: |
| 16 | 16 | runs-on: ubuntu-latest |
| 17 | 17 | steps: |
| 18 | - uses: actions/checkout@v6 | |
| 18 | - uses: actions/checkout@v7 | |
| 19 | 19 | - name: Run Clippy |
| 20 | 20 | run: cargo clippy --all-targets --all-features |
| 21 | 21 | ``` |
src/tools/clippy/book/src/lint_configuration.md+31-22| ... | ... | @@ -452,6 +452,37 @@ For internal testing only, ignores the current `publish` settings in the Cargo m |
| 452 | 452 | * [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata) |
| 453 | 453 | |
| 454 | 454 | |
| 455 | ## `check-grouped-late-init` | |
| 456 | Whether to check for grouped late initializations from multiple `let` statements. | |
| 457 | ||
| 458 | #### Example | |
| 459 | ```rust | |
| 460 | let a; | |
| 461 | let b; | |
| 462 | if true { | |
| 463 | a = 1; | |
| 464 | b = 2; | |
| 465 | } else { | |
| 466 | a = 3; | |
| 467 | b = 4; | |
| 468 | } | |
| 469 | ``` | |
| 470 | Use instead: | |
| 471 | ```rust | |
| 472 | let (a, b) = if true { | |
| 473 | (1, 2) | |
| 474 | } else { | |
| 475 | (3, 4) | |
| 476 | }; | |
| 477 | ``` | |
| 478 | ||
| 479 | **Default Value:** `true` | |
| 480 | ||
| 481 | --- | |
| 482 | **Affected lints:** | |
| 483 | * [`needless_late_init`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init) | |
| 484 | ||
| 485 | ||
| 455 | 486 | ## `check-incompatible-msrv-in-tests` |
| 456 | 487 | Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code. |
| 457 | 488 | |
| ... | ... | @@ -986,28 +1017,6 @@ The minimum size (in bytes) to consider a type for passing by reference instead |
| 986 | 1017 | * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) |
| 987 | 1018 | |
| 988 | 1019 | |
| 989 | ## `profiles` | |
| 990 | Named profiles of disallowed items (unrelated to Cargo build profiles). | |
| 991 | ||
| 992 | #### Example | |
| 993 | ||
| 994 | ```toml | |
| 995 | [profiles.persistent] | |
| 996 | disallowed-methods = [{ path = "std::env::temp_dir" }] | |
| 997 | disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }] | |
| 998 | ||
| 999 | [profiles.single_threaded] | |
| 1000 | disallowed-methods = [{ path = "std::thread::spawn" }] | |
| 1001 | ``` | |
| 1002 | ||
| 1003 | **Default Value:** `{}` | |
| 1004 | ||
| 1005 | --- | |
| 1006 | **Affected lints:** | |
| 1007 | * [`disallowed_methods`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) | |
| 1008 | * [`disallowed_types`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) | |
| 1009 | ||
| 1010 | ||
| 1011 | 1020 | ## `pub-underscore-fields-behavior` |
| 1012 | 1021 | Lint "public" fields in a struct that are prefixed with an underscore based on their |
| 1013 | 1022 | exported visibility, or whether they are marked as "pub". |
src/tools/clippy/clippy_config/src/conf.rs+28-207| ... | ... | @@ -1,13 +1,12 @@ |
| 1 | 1 | use crate::ClippyConfiguration; |
| 2 | 2 | use crate::types::{ |
| 3 | DisallowedPath, DisallowedPathWithoutReplacement, DisallowedProfile, InherentImplLintScope, MacroMatcher, | |
| 4 | MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, | |
| 3 | DisallowedPath, DisallowedPathWithoutReplacement, InherentImplLintScope, MacroMatcher, MatchLintBehaviour, | |
| 4 | PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory, | |
| 5 | 5 | SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, |
| 6 | 6 | SourceItemOrderingTraitAssocItemKinds, SourceItemOrderingWithinModuleItemGroupings, |
| 7 | 7 | }; |
| 8 | 8 | use clippy_utils::msrvs::Msrv; |
| 9 | 9 | use itertools::Itertools; |
| 10 | use rustc_data_structures::fx::FxHashMap; | |
| 11 | 10 | use rustc_errors::Applicability; |
| 12 | 11 | use rustc_session::Session; |
| 13 | 12 | use rustc_span::edit_distance::edit_distance; |
| ... | ... | @@ -223,74 +222,12 @@ macro_rules! deserialize { |
| 223 | 222 | }}; |
| 224 | 223 | } |
| 225 | 224 | |
| 226 | macro_rules! parse_conf_value { | |
| 227 | ( | |
| 228 | $map:expr, | |
| 229 | $ty:ty, | |
| 230 | $errors:expr, | |
| 231 | $file:expr, | |
| 232 | $field_span:expr, | |
| 233 | profiles @[$($profiles:expr)?], | |
| 234 | disallowed @[$($disallowed:expr)?] | |
| 235 | ) => { | |
| 236 | parse_conf_value_impl!( | |
| 237 | $map, | |
| 238 | $ty, | |
| 239 | $errors, | |
| 240 | $file, | |
| 241 | $field_span, | |
| 242 | ($($profiles)?), | |
| 243 | ($($disallowed)?) | |
| 244 | ) | |
| 245 | }; | |
| 246 | } | |
| 247 | ||
| 248 | macro_rules! parse_conf_value_impl { | |
| 249 | ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, (), ()) => {{ | |
| 250 | let _ = &$field_span; | |
| 251 | deserialize!($map, $ty, $errors, $file) | |
| 252 | }}; | |
| 253 | ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, ($profiles:expr), ()) => {{ | |
| 254 | let raw_value = $map.next_value::<toml::Value>()?; | |
| 255 | let value_span = $field_span.clone(); | |
| 256 | let toml::Value::Table(table) = raw_value else { | |
| 257 | $errors.push(ConfError::spanned( | |
| 258 | $file, | |
| 259 | "expected table with named profiles", | |
| 260 | None, | |
| 261 | value_span.clone(), | |
| 262 | )); | |
| 263 | continue; | |
| 264 | }; | |
| 265 | ||
| 266 | let map = parse_profiles(table, $file, value_span.clone(), &mut $errors); | |
| 267 | ||
| 268 | (map, value_span) | |
| 269 | }}; | |
| 270 | ($map:expr, $ty:ty, $errors:expr, $file:expr, $field_span:expr, (), ($disallowed:expr)) => {{ | |
| 271 | let _ = &$field_span; | |
| 272 | deserialize!($map, $ty, $errors, $file, $disallowed) | |
| 273 | }}; | |
| 274 | ( | |
| 275 | $map:expr, | |
| 276 | $ty:ty, | |
| 277 | $errors:expr, | |
| 278 | $file:expr, | |
| 279 | $field_span:expr, | |
| 280 | ($profiles:expr), | |
| 281 | ($disallowed:expr) | |
| 282 | ) => { | |
| 283 | compile_error!("field cannot specify both profiles and disallowed-paths attributes") | |
| 284 | }; | |
| 285 | } | |
| 286 | ||
| 287 | 225 | macro_rules! define_Conf { |
| 288 | 226 | ($( |
| 289 | 227 | $(#[doc = $doc:literal])+ |
| 290 | 228 | $(#[conf_deprecated($dep:literal, $new_conf:ident)])? |
| 291 | 229 | $(#[default_text = $default_text:expr])? |
| 292 | 230 | $(#[disallowed_paths_allow_replacements = $replacements_allowed:expr])? |
| 293 | $(#[profiles = $profiles:expr])? | |
| 294 | 231 | $(#[lints($($for_lints:ident),* $(,)?)])? |
| 295 | 232 | $name:ident: $ty:ty = $default:expr, |
| 296 | 233 | )*) => { |
| ... | ... | @@ -345,20 +282,10 @@ macro_rules! define_Conf { |
| 345 | 282 | |
| 346 | 283 | match field { |
| 347 | 284 | $(Field::$name => { |
| 348 | let field_span = name.span(); | |
| 349 | 285 | // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning. |
| 350 | 286 | $(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), None, name.span()));)? |
| 351 | let (value, value_span) = parse_conf_value!( | |
| 352 | map, | |
| 353 | $ty, | |
| 354 | errors, | |
| 355 | self.0, | |
| 356 | field_span, | |
| 357 | // Disallowed-profile table parsing is special-cased to preserve spans for | |
| 358 | // diagnostics in disallowed-path entries. | |
| 359 | profiles @[$($profiles)?], | |
| 360 | disallowed @[$($replacements_allowed)?] | |
| 361 | ); | |
| 287 | let (value, value_span) = | |
| 288 | deserialize!(map, $ty, errors, self.0 $(, $replacements_allowed)?); | |
| 362 | 289 | // Was this field set previously? |
| 363 | 290 | if $name.is_some() { |
| 364 | 291 | errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span())); |
| ... | ... | @@ -415,121 +342,6 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span { |
| 415 | 342 | ) |
| 416 | 343 | } |
| 417 | 344 | |
| 418 | fn parse_profiles( | |
| 419 | table: toml::value::Table, | |
| 420 | file: &SourceFile, | |
| 421 | value_span: Range<usize>, | |
| 422 | errors: &mut Vec<ConfError>, | |
| 423 | ) -> FxHashMap<String, DisallowedProfile> { | |
| 424 | let mut profiles = FxHashMap::default(); | |
| 425 | let config_span = span_from_toml_range(file, value_span.clone()); | |
| 426 | ||
| 427 | for (profile_name, profile_value) in table { | |
| 428 | let toml::Value::Table(mut profile_table) = profile_value else { | |
| 429 | errors.push(ConfError::spanned( | |
| 430 | file, | |
| 431 | format!("invalid profile `{profile_name}`: expected table"), | |
| 432 | None, | |
| 433 | value_span.clone(), | |
| 434 | )); | |
| 435 | continue; | |
| 436 | }; | |
| 437 | ||
| 438 | let disallowed_methods = match profile_table | |
| 439 | .remove("disallowed-methods") | |
| 440 | .or_else(|| profile_table.remove("disallowed_methods")) | |
| 441 | { | |
| 442 | Some(value) => parse_profile_list( | |
| 443 | file, | |
| 444 | &profile_name, | |
| 445 | "disallowed-methods", | |
| 446 | value, | |
| 447 | value_span.clone(), | |
| 448 | config_span, | |
| 449 | errors, | |
| 450 | ), | |
| 451 | None => Vec::new(), | |
| 452 | }; | |
| 453 | ||
| 454 | let disallowed_types = match profile_table | |
| 455 | .remove("disallowed-types") | |
| 456 | .or_else(|| profile_table.remove("disallowed_types")) | |
| 457 | { | |
| 458 | Some(value) => parse_profile_list( | |
| 459 | file, | |
| 460 | &profile_name, | |
| 461 | "disallowed-types", | |
| 462 | value, | |
| 463 | value_span.clone(), | |
| 464 | config_span, | |
| 465 | errors, | |
| 466 | ), | |
| 467 | None => Vec::new(), | |
| 468 | }; | |
| 469 | ||
| 470 | if !profile_table.is_empty() { | |
| 471 | let keys = profile_table.keys().map(String::as_str).collect::<Vec<_>>().join(", "); | |
| 472 | errors.push(ConfError::spanned( | |
| 473 | file, | |
| 474 | format!("profile `{profile_name}` has unknown keys: {keys}"), | |
| 475 | None, | |
| 476 | value_span.clone(), | |
| 477 | )); | |
| 478 | } | |
| 479 | ||
| 480 | profiles.insert( | |
| 481 | profile_name, | |
| 482 | DisallowedProfile { | |
| 483 | disallowed_methods, | |
| 484 | disallowed_types, | |
| 485 | }, | |
| 486 | ); | |
| 487 | } | |
| 488 | ||
| 489 | profiles | |
| 490 | } | |
| 491 | ||
| 492 | fn parse_profile_list( | |
| 493 | file: &SourceFile, | |
| 494 | profile_name: &str, | |
| 495 | key_name: &str, | |
| 496 | value: toml::Value, | |
| 497 | value_span: Range<usize>, | |
| 498 | config_span: Span, | |
| 499 | errors: &mut Vec<ConfError>, | |
| 500 | ) -> Vec<DisallowedPath> { | |
| 501 | let toml::Value::Array(entries) = value else { | |
| 502 | errors.push(ConfError::spanned( | |
| 503 | file, | |
| 504 | format!("profile `{profile_name}`: `{key_name}` must be an array"), | |
| 505 | None, | |
| 506 | value_span, | |
| 507 | )); | |
| 508 | return Vec::new(); | |
| 509 | }; | |
| 510 | ||
| 511 | let mut disallowed = Vec::with_capacity(entries.len()); | |
| 512 | for entry in entries { | |
| 513 | match DisallowedPath::deserialize(entry.clone()) { | |
| 514 | Ok(mut path) => { | |
| 515 | path.set_span(config_span); | |
| 516 | disallowed.push(path); | |
| 517 | }, | |
| 518 | Err(err) => errors.push(ConfError::spanned( | |
| 519 | file, | |
| 520 | format!( | |
| 521 | "profile `{profile_name}`: {}", | |
| 522 | err.to_string().replace('\n', " ").trim() | |
| 523 | ), | |
| 524 | None, | |
| 525 | value_span.clone(), | |
| 526 | )), | |
| 527 | } | |
| 528 | } | |
| 529 | ||
| 530 | disallowed | |
| 531 | } | |
| 532 | ||
| 533 | 345 | define_Conf! { |
| 534 | 346 | /// Which crates to allow absolute paths from |
| 535 | 347 | #[lints(absolute_paths)] |
| ... | ... | @@ -742,6 +554,30 @@ define_Conf! { |
| 742 | 554 | /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. |
| 743 | 555 | #[lints(cargo_common_metadata)] |
| 744 | 556 | cargo_ignore_publish: bool = false, |
| 557 | /// Whether to check for grouped late initializations from multiple `let` statements. | |
| 558 | /// | |
| 559 | /// #### Example | |
| 560 | /// ```rust | |
| 561 | /// let a; | |
| 562 | /// let b; | |
| 563 | /// if true { | |
| 564 | /// a = 1; | |
| 565 | /// b = 2; | |
| 566 | /// } else { | |
| 567 | /// a = 3; | |
| 568 | /// b = 4; | |
| 569 | /// } | |
| 570 | /// ``` | |
| 571 | /// Use instead: | |
| 572 | /// ```rust | |
| 573 | /// let (a, b) = if true { | |
| 574 | /// (1, 2) | |
| 575 | /// } else { | |
| 576 | /// (3, 4) | |
| 577 | /// }; | |
| 578 | /// ``` | |
| 579 | #[lints(needless_late_init)] | |
| 580 | check_grouped_late_init: bool = true, | |
| 745 | 581 | /// Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code. |
| 746 | 582 | #[lints(incompatible_msrv)] |
| 747 | 583 | check_incompatible_msrv_in_tests: bool = false, |
| ... | ... | @@ -1029,21 +865,6 @@ define_Conf! { |
| 1029 | 865 | /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. |
| 1030 | 866 | #[lints(large_types_passed_by_value)] |
| 1031 | 867 | pass_by_value_size_limit: u64 = 256, |
| 1032 | /// Named profiles of disallowed items (unrelated to Cargo build profiles). | |
| 1033 | /// | |
| 1034 | /// #### Example | |
| 1035 | /// | |
| 1036 | /// ```toml | |
| 1037 | /// [profiles.persistent] | |
| 1038 | /// disallowed-methods = [{ path = "std::env::temp_dir" }] | |
| 1039 | /// disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }] | |
| 1040 | /// | |
| 1041 | /// [profiles.single_threaded] | |
| 1042 | /// disallowed-methods = [{ path = "std::thread::spawn" }] | |
| 1043 | /// ``` | |
| 1044 | #[profiles = true] | |
| 1045 | #[lints(disallowed_methods, disallowed_types)] | |
| 1046 | profiles: FxHashMap<String, DisallowedProfile> = FxHashMap::default(), | |
| 1047 | 868 | /// Lint "public" fields in a struct that are prefixed with an underscore based on their |
| 1048 | 869 | /// exported visibility, or whether they are marked as "pub". |
| 1049 | 870 | #[lints(pub_underscore_fields)] |
src/tools/clippy/clippy_config/src/types.rs-9| ... | ... | @@ -57,15 +57,6 @@ impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath<R |
| 57 | 57 | } |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | #[derive(Debug, Default, Deserialize, Serialize)] | |
| 61 | #[serde(deny_unknown_fields, rename_all = "kebab-case")] | |
| 62 | pub struct DisallowedProfile { | |
| 63 | #[serde(default, alias = "disallowed_methods")] | |
| 64 | pub disallowed_methods: Vec<DisallowedPath>, | |
| 65 | #[serde(default, alias = "disallowed_types")] | |
| 66 | pub disallowed_types: Vec<DisallowedPath>, | |
| 67 | } | |
| 68 | ||
| 69 | 60 | // `DisallowedPathEnum` is an implementation detail to enable the `Deserialize` implementation just |
| 70 | 61 | // above. `DisallowedPathEnum` is not meant to be used outside of this file. |
| 71 | 62 | #[derive(Debug, Deserialize, Serialize)] |
src/tools/clippy/clippy_lints/src/absolute_paths.rs+1-1| ... | ... | @@ -12,7 +12,7 @@ use rustc_span::symbol::kw; |
| 12 | 12 | |
| 13 | 13 | declare_clippy_lint! { |
| 14 | 14 | /// ### What it does |
| 15 | /// Checks for usage of items through absolute paths, like `std::env::current_dir`. | |
| 15 | /// Checks for usage of items through absolute paths, like `std::f64::consts::PI`. | |
| 16 | 16 | /// |
| 17 | 17 | /// ### Why restrict this? |
| 18 | 18 | /// Many codebases have their own style when it comes to importing, but one that is seldom used |
src/tools/clippy/clippy_lints/src/assertions_on_constants.rs+3-1| ... | ... | @@ -52,7 +52,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { |
| 52 | 52 | _ => return, |
| 53 | 53 | } |
| 54 | 54 | && let Some((condition, _)) = find_assert_args(cx, e, macro_call.expn) |
| 55 | && is_const_evaluatable(cx, condition) | |
| 55 | // Check if the whole expression can be moved into a const context. | |
| 56 | // Note that const eval can evaluate things which cannot be moved (e.g. `false && x`). | |
| 57 | && is_const_evaluatable(cx.tcx, cx.typeck_results(), condition) | |
| 56 | 58 | && let Some((Constant::Bool(assert_val), const_src)) = |
| 57 | 59 | ConstEvalCtxt::new(cx).eval_with_source(condition, macro_call.span.ctxt()) |
| 58 | 60 | && let in_const_context = is_inside_always_const_context(cx.tcx, e.hir_id) |
src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use super::{Attribute, NON_MINIMAL_CFG}; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use rustc_ast::{MetaItemInner, MetaItemKind}; |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_lint::EarlyContext; |
| ... | ... | @@ -29,7 +29,7 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[MetaItemInner]) { |
| 29 | 29 | meta.span, |
| 30 | 30 | "unneeded sub `cfg` when there is only one condition", |
| 31 | 31 | |diag| { |
| 32 | if let Some(snippet) = list[0].span().get_source_text(cx) { | |
| 32 | if let Some(snippet) = list[0].span().get_text(cx) { | |
| 33 | 33 | diag.span_suggestion( |
| 34 | 34 | meta.span, |
| 35 | 35 | "try", |
src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use super::{Attribute, UNNECESSARY_CLIPPY_CFG}; |
| 2 | 2 | use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use itertools::Itertools; |
| 5 | 5 | use rustc_ast::AttrStyle; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -32,7 +32,7 @@ pub(super) fn check( |
| 32 | 32 | return; |
| 33 | 33 | } |
| 34 | 34 | if nb_items == clippy_lints.len() { |
| 35 | if let Some(snippet) = behind_cfg_attr.span.get_source_text(cx) { | |
| 35 | if let Some(snippet) = behind_cfg_attr.span.get_text(cx) { | |
| 36 | 36 | span_lint_and_sugg( |
| 37 | 37 | cx, |
| 38 | 38 | UNNECESSARY_CLIPPY_CFG, |
| ... | ... | @@ -48,7 +48,7 @@ pub(super) fn check( |
| 48 | 48 | ); |
| 49 | 49 | } |
| 50 | 50 | } else { |
| 51 | let snippet = clippy_lints.iter().filter_map(|sp| sp.get_source_text(cx)).join(","); | |
| 51 | let snippet = clippy_lints.iter().filter_map(|sp| sp.get_text(cx)).join(","); | |
| 52 | 52 | span_lint_and_note( |
| 53 | 53 | cx, |
| 54 | 54 | UNNECESSARY_CLIPPY_CFG, |
src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use super::USELESS_ATTRIBUTE; |
| 2 | 2 | use super::utils::{is_lint_level, is_word, namespace_and_lint}; |
| 3 | 3 | use clippy_utils::diagnostics::span_lint_and_then; |
| 4 | use clippy_utils::source::{SpanRangeExt, first_line_of_span}; | |
| 4 | use clippy_utils::source::{SpanExt, first_line_of_span}; | |
| 5 | 5 | use clippy_utils::sym; |
| 6 | 6 | use rustc_ast::{Attribute, Item, ItemKind}; |
| 7 | 7 | use rustc_errors::Applicability; |
| ... | ... | @@ -74,7 +74,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { |
| 74 | 74 | } |
| 75 | 75 | let line_span = first_line_of_span(cx, attr.span); |
| 76 | 76 | |
| 77 | if let Some(src) = line_span.get_source_text(cx) | |
| 77 | if let Some(src) = line_span.get_text(cx) | |
| 78 | 78 | && src.contains("#[") |
| 79 | 79 | { |
| 80 | 80 | #[expect(clippy::collapsible_span_lint_calls)] |
src/tools/clippy/clippy_lints/src/booleans.rs+12-19| ... | ... | @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; |
| 3 | 3 | use clippy_utils::higher::has_let_expr; |
| 4 | 4 | use clippy_utils::msrvs::{self, Msrv}; |
| 5 | 5 | use clippy_utils::res::MaybeDef; |
| 6 | use clippy_utils::source::{SpanRangeExt, snippet_with_context}; | |
| 6 | use clippy_utils::source::{SpanExt, snippet_with_context}; | |
| 7 | 7 | use clippy_utils::sugg::Sugg; |
| 8 | 8 | use clippy_utils::ty::implements_trait; |
| 9 | 9 | use clippy_utils::{eq_expr_value, sym}; |
| ... | ... | @@ -157,30 +157,30 @@ fn check_inverted_bool_in_condition( |
| 157 | 157 | |
| 158 | 158 | let suggestion = match (left.kind, right.kind) { |
| 159 | 159 | (ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => { |
| 160 | let Some(left) = left_sub.span.get_source_text(cx) else { | |
| 160 | let Some(left) = left_sub.span.get_text(cx) else { | |
| 161 | 161 | return; |
| 162 | 162 | }; |
| 163 | let Some(right) = right_sub.span.get_source_text(cx) else { | |
| 163 | let Some(right) = right_sub.span.get_text(cx) else { | |
| 164 | 164 | return; |
| 165 | 165 | }; |
| 166 | 166 | let Some(op) = bin_op_eq_str(op) else { return }; |
| 167 | 167 | format!("{left} {op} {right}") |
| 168 | 168 | }, |
| 169 | 169 | (ExprKind::Unary(UnOp::Not, left_sub), _) => { |
| 170 | let Some(left) = left_sub.span.get_source_text(cx) else { | |
| 170 | let Some(left) = left_sub.span.get_text(cx) else { | |
| 171 | 171 | return; |
| 172 | 172 | }; |
| 173 | let Some(right) = right.span.get_source_text(cx) else { | |
| 173 | let Some(right) = right.span.get_text(cx) else { | |
| 174 | 174 | return; |
| 175 | 175 | }; |
| 176 | 176 | let Some(op) = inverted_bin_op_eq_str(op) else { return }; |
| 177 | 177 | format!("{left} {op} {right}") |
| 178 | 178 | }, |
| 179 | 179 | (_, ExprKind::Unary(UnOp::Not, right_sub)) => { |
| 180 | let Some(left) = left.span.get_source_text(cx) else { | |
| 180 | let Some(left) = left.span.get_text(cx) else { | |
| 181 | 181 | return; |
| 182 | 182 | }; |
| 183 | let Some(right) = right_sub.span.get_source_text(cx) else { | |
| 183 | let Some(right) = right_sub.span.get_text(cx) else { | |
| 184 | 184 | return; |
| 185 | 185 | }; |
| 186 | 186 | let Some(op) = inverted_bin_op_eq_str(op) else { return }; |
| ... | ... | @@ -392,12 +392,8 @@ impl SuggestContext<'_, '_, '_> { |
| 392 | 392 | } |
| 393 | 393 | }, |
| 394 | 394 | &Term(n) => { |
| 395 | self.output.push_str( | |
| 396 | &self.terminals[n as usize] | |
| 397 | .span | |
| 398 | .source_callsite() | |
| 399 | .get_source_text(self.cx)?, | |
| 400 | ); | |
| 395 | self.output | |
| 396 | .push_str(&self.terminals[n as usize].span.source_callsite().get_text(self.cx)?); | |
| 401 | 397 | }, |
| 402 | 398 | } |
| 403 | 399 | Some(()) |
| ... | ... | @@ -452,10 +448,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio |
| 452 | 448 | .map(|arg| simplify_not(cx, curr_msrv, arg)) |
| 453 | 449 | .collect::<Option<Vec<_>>>()? |
| 454 | 450 | .join(", "); |
| 455 | Some(format!( | |
| 456 | "{}.{neg_method}({negated_args})", | |
| 457 | receiver.span.get_source_text(cx)? | |
| 458 | )) | |
| 451 | Some(format!("{}.{neg_method}({negated_args})", receiver.span.get_text(cx)?)) | |
| 459 | 452 | }) |
| 460 | 453 | }, |
| 461 | 454 | ExprKind::Closure(closure) => { |
| ... | ... | @@ -463,13 +456,13 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio |
| 463 | 456 | let params = body |
| 464 | 457 | .params |
| 465 | 458 | .iter() |
| 466 | .map(|param| param.span.get_source_text(cx).map(|t| t.to_string())) | |
| 459 | .map(|param| param.span.get_text(cx).map(|t| t.to_string())) | |
| 467 | 460 | .collect::<Option<Vec<_>>>()? |
| 468 | 461 | .join(", "); |
| 469 | 462 | let negated = simplify_not(cx, curr_msrv, body.value)?; |
| 470 | 463 | Some(format!("|{params}| {negated}")) |
| 471 | 464 | }, |
| 472 | ExprKind::Unary(UnOp::Not, expr) => expr.span.get_source_text(cx).map(|t| t.to_string()), | |
| 465 | ExprKind::Unary(UnOp::Not, expr) => expr.span.get_text(cx).map(|t| t.to_string()), | |
| 473 | 466 | _ => None, |
| 474 | 467 | } |
| 475 | 468 | } |
src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use crate::reference::DEREF_ADDROF; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::ty::implements_trait; |
| 5 | 5 | use clippy_utils::{ |
| 6 | 6 | get_enclosing_closure, get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable, |
| ... | ... | @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { |
| 82 | 82 | // If the new borrow might be itself borrowed mutably and the original reference is not a temporary |
| 83 | 83 | // value, do not propose to use it directly. |
| 84 | 84 | && (is_expr_temporary_value(cx, deref_target) || !potentially_bound_to_mutable_ref(cx, e)) |
| 85 | && let Some(deref_text) = deref_target.span.get_source_text(cx) | |
| 85 | && let Some(deref_text) = deref_target.span.get_text(cx) | |
| 86 | 86 | { |
| 87 | 87 | // `&*x` can be needed to shorten the borrow of `x`. Replacing it with `x` can be |
| 88 | 88 | // incorrect when `x` is a closure-captured upvar (e.g. a closure returning another |
src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use clippy_utils::sym; |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_hir::{Expr, ExprKind}; |
| ... | ... | @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, |
| 20 | 20 | && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity().skip_norm_wip() |
| 21 | 21 | && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() |
| 22 | 22 | && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() |
| 23 | && let Some(recv) = receiver.span.get_source_text(cx) | |
| 23 | && let Some(recv) = receiver.span.get_text(cx) | |
| 24 | 24 | { |
| 25 | 25 | // `as_mut_ptr` might not exist |
| 26 | 26 | let applicability = Applicability::MaybeIncorrect; |
src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::is_in_const_context; |
| 3 | 3 | use clippy_utils::msrvs::{self, Msrv}; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use clippy_utils::sugg::Sugg; |
| 6 | 6 | use clippy_utils::ty::is_isize_or_usize; |
| 7 | 7 | use rustc_errors::Applicability; |
| ... | ... | @@ -40,7 +40,7 @@ pub(super) fn check( |
| 40 | 40 | diag.help("an `as` cast can become silently lossy if the types change in the future"); |
| 41 | 41 | let mut applicability = Applicability::MachineApplicable; |
| 42 | 42 | let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "<from>", &mut applicability); |
| 43 | let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_source_text(cx) else { | |
| 43 | let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_text(cx) else { | |
| 44 | 44 | return; |
| 45 | 45 | }; |
| 46 | 46 | match cast_to_hir.kind { |
src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::res::{MaybeDef, MaybeResPath}; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::{expr_or_init, std_or_core, sym}; |
| 5 | 5 | use rustc_ast::LitKind; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: |
| 25 | 25 | |
| 26 | 26 | let sugg = if let TyKind::Infer(()) = ptr_ty.ty.kind { |
| 27 | 27 | format!("{std_or_core}::{sugg_fn}()") |
| 28 | } else if let Some(mut_ty_snip) = ptr_ty.ty.span.get_source_text(cx) { | |
| 28 | } else if let Some(mut_ty_snip) = ptr_ty.ty.span.get_text(cx) { | |
| 29 | 29 | format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") |
| 30 | 30 | } else { |
| 31 | 31 | return; |
src/tools/clippy/clippy_lints/src/casts/needless_type_cast.rs+1-1| ... | ... | @@ -249,7 +249,7 @@ fn can_coerce_to_target_type(expr: &Expr<'_>) -> bool { |
| 249 | 249 | fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) { |
| 250 | 250 | let mut usages = Vec::new(); |
| 251 | 251 | |
| 252 | for_each_expr(cx, body.value, |expr| { | |
| 252 | for_each_expr(cx.tcx, body.value, |expr| { | |
| 253 | 253 | if let ExprKind::Path(ref qpath) = expr.kind |
| 254 | 254 | && !expr.span.from_expansion() |
| 255 | 255 | && let Res::Local(id) = cx.qpath_res(qpath, expr.hir_id) |
src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs+5-5| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::numeric_literal::NumericLiteral; |
| 3 | 3 | use clippy_utils::res::MaybeResPath as _; |
| 4 | use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; | |
| 4 | use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; | |
| 5 | 5 | use clippy_utils::sugg::has_enclosing_paren; |
| 6 | 6 | use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; |
| 7 | 7 | use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, sym}; |
| ... | ... | @@ -113,7 +113,7 @@ pub(super) fn check<'tcx>( |
| 113 | 113 | let literal_str = &cast_str; |
| 114 | 114 | |
| 115 | 115 | if let LitKind::Int(n, _) = lit.node |
| 116 | && let Some(src) = cast_expr.span.get_source_text(cx) | |
| 116 | && let Some(src) = cast_expr.span.get_text(cx) | |
| 117 | 117 | && cast_to.is_floating_point() |
| 118 | 118 | && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) |
| 119 | 119 | && let from_nbits = 128 - n.get().leading_zeros() |
| ... | ... | @@ -140,7 +140,7 @@ pub(super) fn check<'tcx>( |
| 140 | 140 | | LitKind::Float(_, LitFloatType::Suffixed(_)) |
| 141 | 141 | if cast_from.kind() == cast_to.kind() => |
| 142 | 142 | { |
| 143 | if let Some(src) = cast_expr.span.get_source_text(cx) | |
| 143 | if let Some(src) = cast_expr.span.get_text(cx) | |
| 144 | 144 | && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) |
| 145 | 145 | { |
| 146 | 146 | lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); |
| ... | ... | @@ -232,7 +232,7 @@ fn lint_unnecessary_cast( |
| 232 | 232 | // (-1).foo() instead of -1.foo()) |
| 233 | 233 | let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) |
| 234 | 234 | && let ExprKind::MethodCall(..) = parent_expr.kind |
| 235 | && literal_str.starts_with('-') | |
| 235 | && literal_str.starts_with(['-', '!']) | |
| 236 | 236 | { |
| 237 | 237 | format!("({literal_str}_{cast_to})") |
| 238 | 238 | } else { |
| ... | ... | @@ -253,7 +253,7 @@ fn lint_unnecessary_cast( |
| 253 | 253 | fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<Lit> { |
| 254 | 254 | match expr.kind { |
| 255 | 255 | ExprKind::Lit(lit) => Some(lit), |
| 256 | ExprKind::Unary(UnOp::Neg, e) => { | |
| 256 | ExprKind::Unary(UnOp::Neg | UnOp::Not, e) => { | |
| 257 | 257 | if let ExprKind::Lit(lit) = e.kind { |
| 258 | 258 | Some(lit) |
| 259 | 259 | } else { |
src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::msrvs::{self, Msrv}; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core}; |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::{Expr, Mutability, Ty, TyKind}; |
| ... | ... | @@ -21,7 +21,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_> |
| 21 | 21 | |
| 22 | 22 | let sugg = if let TyKind::Infer(()) = mut_ty.ty.kind { |
| 23 | 23 | format!("{std_or_core}::{sugg_fn}()") |
| 24 | } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_source_text(cx) { | |
| 24 | } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_text(cx) { | |
| 25 | 25 | format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") |
| 26 | 26 | } else { |
| 27 | 27 | return; |
src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs+11-10| ... | ... | @@ -64,15 +64,8 @@ impl<'a> ClonedRefToSliceRefs<'a> { |
| 64 | 64 | |
| 65 | 65 | impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> { |
| 66 | 66 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { |
| 67 | if self.msrv.meets(cx, { | |
| 68 | if is_in_const_context(cx) { | |
| 69 | msrvs::CONST_SLICE_FROM_REF | |
| 70 | } else { | |
| 71 | msrvs::SLICE_FROM_REF | |
| 72 | } | |
| 73 | }) | |
| 74 | // `&[foo.clone()]` expressions | |
| 75 | && let ExprKind::AddrOf(_, mutability, arr) = &expr.kind | |
| 67 | // `&[foo.clone()]` expressions | |
| 68 | if let ExprKind::AddrOf(_, mutability, arr) = &expr.kind | |
| 76 | 69 | // mutable references would have a different meaning |
| 77 | 70 | && mutability.is_not() |
| 78 | 71 | |
| ... | ... | @@ -81,10 +74,18 @@ impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> { |
| 81 | 74 | |
| 82 | 75 | // check for clones |
| 83 | 76 | && let ExprKind::MethodCall(path, recv, _, _) = item.kind |
| 77 | ||
| 78 | && self.msrv.meets(cx, { | |
| 79 | if is_in_const_context(cx) { | |
| 80 | msrvs::CONST_SLICE_FROM_REF | |
| 81 | } else { | |
| 82 | msrvs::SLICE_FROM_REF | |
| 83 | } | |
| 84 | }) | |
| 84 | 85 | && let Some(adjustment) = is_needless_clone_or_equivalent(cx, recv, path.ident.name, item.hir_id) |
| 85 | 86 | |
| 86 | 87 | // check for immutability or purity |
| 87 | && (!is_mutable(cx, recv) || is_const_evaluatable(cx, recv)) | |
| 88 | && (!is_mutable(cx, recv) || is_const_evaluatable(cx.tcx, cx.typeck_results(), recv)) | |
| 88 | 89 | |
| 89 | 90 | // get appropriate crate for `slice::from_ref` |
| 90 | 91 | && let Some(builtin_crate) = clippy_utils::std_or_core(cx) |
src/tools/clippy/clippy_lints/src/cognitive_complexity.rs+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_help; |
| 3 | 3 | use clippy_utils::res::MaybeDef; |
| 4 | use clippy_utils::source::{IntoSpan, SpanRangeExt}; | |
| 4 | use clippy_utils::source::{IntoSpan, SpanExt}; | |
| 5 | 5 | use clippy_utils::visitors::for_each_expr_without_closures; |
| 6 | 6 | use clippy_utils::{LimitStack, get_async_fn_body, sym}; |
| 7 | 7 | use core::ops::ControlFlow; |
src/tools/clippy/clippy_lints/src/collapsible_if.rs+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_hir_and_then; |
| 3 | 3 | use clippy_utils::msrvs::Msrv; |
| 4 | use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; | |
| 4 | use clippy_utils::source::{IntoSpan as _, SpanExt, snippet, snippet_block_with_applicability}; | |
| 5 | 5 | use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text}; |
| 6 | 6 | use rustc_ast::{BinOpKind, MetaItemInner}; |
| 7 | 7 | use rustc_errors::Applicability; |
| ... | ... | @@ -319,7 +319,7 @@ pub(super) fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> { |
| 319 | 319 | } |
| 320 | 320 | } |
| 321 | 321 | |
| 322 | fn span_extract_keyword(cx: &impl HasSession, span: Span, keyword: &str) -> Option<Span> { | |
| 322 | fn span_extract_keyword(cx: &LateContext<'_>, span: Span, keyword: &str) -> Option<Span> { | |
| 323 | 323 | span.with_source_text(cx, |snippet| { |
| 324 | 324 | tokenize_with_text(snippet) |
| 325 | 325 | .filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword)) |
| ... | ... | @@ -335,7 +335,7 @@ fn span_extract_keyword(cx: &impl HasSession, span: Span, keyword: &str) -> Opti |
| 335 | 335 | } |
| 336 | 336 | |
| 337 | 337 | /// Peel the parentheses from an `if` expression, e.g. `((if true {} else {}))`. |
| 338 | pub(super) fn peel_parens(cx: &impl HasSession, mut span: Span) -> (Span, Span, Span) { | |
| 338 | pub(super) fn peel_parens(cx: &LateContext<'_>, mut span: Span) -> (Span, Span, Span) { | |
| 339 | 339 | use crate::rustc_span::Pos; |
| 340 | 340 | |
| 341 | 341 | let start = span.shrink_to_lo(); |
src/tools/clippy/clippy_lints/src/collection_is_never_read.rs+1-1| ... | ... | @@ -79,7 +79,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI |
| 79 | 79 | let mut has_read_access = false; |
| 80 | 80 | |
| 81 | 81 | // Inspect all expressions and sub-expressions in the block. |
| 82 | for_each_expr(cx, block, |expr| { | |
| 82 | for_each_expr(cx.tcx, block, |expr| { | |
| 83 | 83 | // Ignore expressions that are not simply `id`. |
| 84 | 84 | if expr.res_local_id() != Some(id) { |
| 85 | 85 | return ControlFlow::Continue(()); |
src/tools/clippy/clippy_lints/src/declared_lints.rs+3| ... | ... | @@ -361,11 +361,13 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ |
| 361 | 361 | crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO, |
| 362 | 362 | crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO, |
| 363 | 363 | crate::methods::BIND_INSTEAD_OF_MAP_INFO, |
| 364 | crate::methods::BY_REF_PEEKABLE_PEEK_INFO, | |
| 364 | 365 | crate::methods::BYTES_COUNT_TO_LEN_INFO, |
| 365 | 366 | crate::methods::BYTES_NTH_INFO, |
| 366 | 367 | crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO, |
| 367 | 368 | crate::methods::CHARS_LAST_CMP_INFO, |
| 368 | 369 | crate::methods::CHARS_NEXT_CMP_INFO, |
| 370 | crate::methods::CHUNKS_EXACT_TO_AS_CHUNKS_INFO, | |
| 369 | 371 | crate::methods::CLEAR_WITH_DRAIN_INFO, |
| 370 | 372 | crate::methods::CLONE_ON_COPY_INFO, |
| 371 | 373 | crate::methods::CLONE_ON_REF_PTR_INFO, |
| ... | ... | @@ -507,6 +509,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ |
| 507 | 509 | crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO, |
| 508 | 510 | crate::methods::UNNECESSARY_SORT_BY_INFO, |
| 509 | 511 | crate::methods::UNNECESSARY_TO_OWNED_INFO, |
| 512 | crate::methods::UNNECESSARY_UNWRAP_UNCHECKED_INFO, | |
| 510 | 513 | crate::methods::UNWRAP_OR_DEFAULT_INFO, |
| 511 | 514 | crate::methods::UNWRAP_USED_INFO, |
| 512 | 515 | crate::methods::USELESS_ASREF_INFO, |
src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::is_ty_alias; |
| 3 | use clippy_utils::source::SpanRangeExt as _; | |
| 3 | use clippy_utils::source::SpanExt as _; | |
| 4 | 4 | use hir::ExprKind; |
| 5 | 5 | use hir::def::Res; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -78,7 +78,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { |
| 78 | 78 | && !base.is_suggestable_infer_ty() |
| 79 | 79 | { |
| 80 | 80 | let mut removals = vec![(expr.span.with_lo(qpath.qself_span().hi()), String::new())]; |
| 81 | if expr.span.check_source_text(cx, |s| s.starts_with('<')) { | |
| 81 | if expr.span.check_text(cx, |s| s.starts_with('<')) { | |
| 82 | 82 | // Remove `<`, '>` has already been removed by the existing removal expression. |
| 83 | 83 | removals.push((expr.span.with_hi(qpath.qself_span().lo()), String::new())); |
| 84 | 84 | } |
src/tools/clippy/clippy_lints/src/disallowed_methods.rs+6-119| ... | ... | @@ -1,18 +1,13 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_config::types::{DisallowedPath, create_disallowed_map}; |
| 3 | use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; | |
| 4 | use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver}; | |
| 3 | use clippy_utils::diagnostics::span_lint_and_then; | |
| 5 | 4 | use clippy_utils::paths::PathNS; |
| 6 | use clippy_utils::sym; | |
| 7 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | |
| 8 | use rustc_data_structures::smallvec::SmallVec; | |
| 9 | 5 | use rustc_hir::def::{CtorKind, DefKind, Res}; |
| 10 | 6 | use rustc_hir::def_id::DefIdMap; |
| 11 | 7 | use rustc_hir::{Expr, ExprKind}; |
| 12 | 8 | use rustc_lint::{LateContext, LateLintPass}; |
| 13 | 9 | use rustc_middle::ty::TyCtxt; |
| 14 | 10 | use rustc_session::impl_lint_pass; |
| 15 | use rustc_span::{Span, Symbol}; | |
| 16 | 11 | |
| 17 | 12 | declare_clippy_lint! { |
| 18 | 13 | /// ### What it does |
| ... | ... | @@ -60,19 +55,6 @@ declare_clippy_lint! { |
| 60 | 55 | /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. |
| 61 | 56 | /// xs.push(123); // Vec::push is _not_ disallowed in the config. |
| 62 | 57 | /// ``` |
| 63 | /// | |
| 64 | /// Disallowed profiles allow scoping different disallow lists: | |
| 65 | /// ```toml | |
| 66 | /// [profiles.forward_pass] | |
| 67 | /// disallowed-methods = [{ path = "crate::devices::Buffer::copy_to_host", reason = "Forward code must not touch host buffers" }] | |
| 68 | /// ``` | |
| 69 | /// | |
| 70 | /// ```rust,ignore | |
| 71 | /// #[clippy::disallowed_profile("forward_pass")] | |
| 72 | /// fn evaluate() { | |
| 73 | /// // Method calls in this function use the `forward_pass` profile. | |
| 74 | /// } | |
| 75 | /// ``` | |
| 76 | 58 | #[clippy::version = "1.49.0"] |
| 77 | 59 | pub DISALLOWED_METHODS, |
| 78 | 60 | style, |
| ... | ... | @@ -82,22 +64,12 @@ declare_clippy_lint! { |
| 82 | 64 | impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); |
| 83 | 65 | |
| 84 | 66 | pub struct DisallowedMethods { |
| 85 | default: DefIdMap<(&'static str, &'static DisallowedPath)>, | |
| 86 | /// Lookup per profile that declares a non-empty `disallowed_methods` list. Profiles | |
| 87 | /// declared in `[profiles.*]` but without `disallowed_methods` entries are absent here. | |
| 88 | profiles: FxHashMap<Symbol, DefIdMap<(&'static str, &'static DisallowedPath)>>, | |
| 89 | /// Every profile name declared in `[profiles.*]`, regardless of whether it contributes | |
| 90 | /// to this lint. Used to suppress the "unknown profile" warning for profiles that exist | |
| 91 | /// in config but only define entries for other lints (e.g. `disallowed_types`). | |
| 92 | known_profiles: FxHashSet<Symbol>, | |
| 93 | profile_cache: ProfileResolver, | |
| 94 | warned_unknown_profiles: FxHashSet<Span>, | |
| 67 | disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, | |
| 95 | 68 | } |
| 96 | 69 | |
| 97 | 70 | impl DisallowedMethods { |
| 98 | #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration. | |
| 99 | 71 | pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { |
| 100 | let (default, _) = create_disallowed_map( | |
| 72 | let (disallowed, _) = create_disallowed_map( | |
| 101 | 73 | tcx, |
| 102 | 74 | &conf.disallowed_methods, |
| 103 | 75 | PathNS::Value, |
| ... | ... | @@ -110,62 +82,7 @@ impl DisallowedMethods { |
| 110 | 82 | "function", |
| 111 | 83 | false, |
| 112 | 84 | ); |
| 113 | ||
| 114 | let mut profiles = FxHashMap::default(); | |
| 115 | let mut known_profiles = FxHashSet::default(); | |
| 116 | let mut profile_entries: Vec<_> = conf.profiles.iter().collect(); | |
| 117 | profile_entries.sort_by_key(|(a, _)| *a); | |
| 118 | for (name, profile) in profile_entries { | |
| 119 | let symbol = Symbol::intern(name.as_str()); | |
| 120 | known_profiles.insert(symbol); | |
| 121 | ||
| 122 | let paths = profile.disallowed_methods.as_slice(); | |
| 123 | if paths.is_empty() { | |
| 124 | continue; | |
| 125 | } | |
| 126 | ||
| 127 | let (map, _) = create_disallowed_map( | |
| 128 | tcx, | |
| 129 | paths, | |
| 130 | PathNS::Value, | |
| 131 | |def_kind| { | |
| 132 | matches!( | |
| 133 | def_kind, | |
| 134 | DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn | |
| 135 | ) | |
| 136 | }, | |
| 137 | "function", | |
| 138 | false, | |
| 139 | ); | |
| 140 | profiles.insert(symbol, map); | |
| 141 | } | |
| 142 | ||
| 143 | Self { | |
| 144 | default, | |
| 145 | profiles, | |
| 146 | known_profiles, | |
| 147 | profile_cache: ProfileResolver::default(), | |
| 148 | warned_unknown_profiles: FxHashSet::default(), | |
| 149 | } | |
| 150 | } | |
| 151 | ||
| 152 | fn warn_unknown_profile(&mut self, cx: &LateContext<'_>, entry: &ProfileEntry) { | |
| 153 | if self.warned_unknown_profiles.insert(entry.span) { | |
| 154 | let attr_name = if entry.attr_name == sym::disallowed_profiles { | |
| 155 | "clippy::disallowed_profiles" | |
| 156 | } else { | |
| 157 | "clippy::disallowed_profile" | |
| 158 | }; | |
| 159 | span_lint( | |
| 160 | cx, | |
| 161 | DISALLOWED_METHODS, | |
| 162 | entry.span, | |
| 163 | format!( | |
| 164 | "`{attr_name}` references unknown profile `{}` for `clippy::disallowed_methods`", | |
| 165 | entry.name | |
| 166 | ), | |
| 167 | ); | |
| 168 | } | |
| 85 | Self { disallowed } | |
| 169 | 86 | } |
| 170 | 87 | } |
| 171 | 88 | |
| ... | ... | @@ -181,43 +98,13 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { |
| 181 | 98 | }, |
| 182 | 99 | _ => return, |
| 183 | 100 | }; |
| 184 | let mut active_profiles = SmallVec::<[Symbol; 2]>::new(); | |
| 185 | // Copy entries out of the cache before iterating: `warn_unknown_profile` takes | |
| 186 | // `&mut self`, which conflicts with the borrow held by `active_profiles(...)`. | |
| 187 | let entries: SmallVec<[ProfileEntry; 2]> = self | |
| 188 | .profile_cache | |
| 189 | .active_profiles(cx, expr.hir_id) | |
| 190 | .map(|selection| selection.iter().copied().collect()) | |
| 191 | .unwrap_or_default(); | |
| 192 | for entry in &entries { | |
| 193 | if self.profiles.contains_key(&entry.name) { | |
| 194 | active_profiles.push(entry.name); | |
| 195 | } else if !self.known_profiles.contains(&entry.name) { | |
| 196 | self.warn_unknown_profile(cx, entry); | |
| 197 | } | |
| 198 | } | |
| 199 | ||
| 200 | if let Some((profile, &(path, disallowed_path))) = active_profiles.iter().find_map(|symbol| { | |
| 201 | self.profiles | |
| 202 | .get(symbol) | |
| 203 | .and_then(|map| map.get(&id).map(|info| (*symbol, info))) | |
| 204 | }) { | |
| 205 | let diag_amendment = disallowed_path.diag_amendment(span); | |
| 206 | span_lint_and_then( | |
| 207 | cx, | |
| 208 | DISALLOWED_METHODS, | |
| 209 | span, | |
| 210 | format!("use of a disallowed method `{path}` (profile: {profile})"), | |
| 211 | |diag| diag_amendment(diag), | |
| 212 | ); | |
| 213 | } else if let Some(&(path, disallowed_path)) = self.default.get(&id) { | |
| 214 | let diag_amendment = disallowed_path.diag_amendment(span); | |
| 101 | if let Some(&(path, disallowed_path)) = self.disallowed.get(&id) { | |
| 215 | 102 | span_lint_and_then( |
| 216 | 103 | cx, |
| 217 | 104 | DISALLOWED_METHODS, |
| 218 | 105 | span, |
| 219 | 106 | format!("use of a disallowed method `{path}`"), |
| 220 | |diag| diag_amendment(diag), | |
| 107 | disallowed_path.diag_amendment(span), | |
| 221 | 108 | ); |
| 222 | 109 | } |
| 223 | 110 | } |
src/tools/clippy/clippy_lints/src/disallowed_types.rs+29-138| ... | ... | @@ -1,18 +1,15 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_config::types::{DisallowedPath, create_disallowed_map}; |
| 3 | use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; | |
| 4 | use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver}; | |
| 3 | use clippy_utils::diagnostics::span_lint_and_then; | |
| 5 | 4 | use clippy_utils::paths::PathNS; |
| 6 | use clippy_utils::sym; | |
| 7 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | |
| 8 | use rustc_data_structures::smallvec::SmallVec; | |
| 5 | use rustc_data_structures::fx::FxHashMap; | |
| 9 | 6 | use rustc_hir::def::{DefKind, Res}; |
| 10 | 7 | use rustc_hir::def_id::DefIdMap; |
| 11 | 8 | use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; |
| 12 | 9 | use rustc_lint::{LateContext, LateLintPass}; |
| 13 | 10 | use rustc_middle::ty::TyCtxt; |
| 14 | 11 | use rustc_session::impl_lint_pass; |
| 15 | use rustc_span::{Span, Symbol}; | |
| 12 | use rustc_span::Span; | |
| 16 | 13 | |
| 17 | 14 | declare_clippy_lint! { |
| 18 | 15 | /// ### What it does |
| ... | ... | @@ -54,17 +51,6 @@ declare_clippy_lint! { |
| 54 | 51 | /// // A similar type that is allowed by the config |
| 55 | 52 | /// use std::collections::HashMap; |
| 56 | 53 | /// ``` |
| 57 | /// | |
| 58 | /// Disallowed profiles can scope lists to specific modules: | |
| 59 | /// ```toml | |
| 60 | /// [profiles.forward_pass] | |
| 61 | /// disallowed-types = [{ path = "crate::buffers::HostBuffer", reason = "Prefer device buffers in forward computations" }] | |
| 62 | /// ``` | |
| 63 | /// | |
| 64 | /// ```rust,ignore | |
| 65 | /// #[clippy::disallowed_profile("forward_pass")] | |
| 66 | /// fn forward_step(buffer: crate::buffers::DeviceBuffer) { /* ... */ } | |
| 67 | /// ``` | |
| 68 | 54 | #[clippy::version = "1.55.0"] |
| 69 | 55 | pub DISALLOWED_TYPES, |
| 70 | 56 | style, |
| ... | ... | @@ -73,127 +59,37 @@ declare_clippy_lint! { |
| 73 | 59 | |
| 74 | 60 | impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]); |
| 75 | 61 | |
| 76 | struct TypeLookup { | |
| 62 | pub struct DisallowedTypes { | |
| 77 | 63 | def_ids: DefIdMap<(&'static str, &'static DisallowedPath)>, |
| 78 | 64 | prim_tys: FxHashMap<PrimTy, (&'static str, &'static DisallowedPath)>, |
| 79 | 65 | } |
| 80 | 66 | |
| 81 | impl TypeLookup { | |
| 82 | fn from_config(tcx: TyCtxt<'_>, paths: &'static [DisallowedPath]) -> Self { | |
| 83 | let (def_ids, prim_tys) = create_disallowed_map(tcx, paths, PathNS::Type, def_kind_predicate, "type", true); | |
| 84 | Self { def_ids, prim_tys } | |
| 85 | } | |
| 86 | ||
| 87 | fn find(&self, res: &Res) -> Option<(&'static str, &'static DisallowedPath)> { | |
| 88 | match res { | |
| 89 | Res::Def(_, did) => self.def_ids.get(did).copied(), | |
| 90 | Res::PrimTy(prim) => self.prim_tys.get(prim).copied(), | |
| 91 | _ => None, | |
| 92 | } | |
| 93 | } | |
| 94 | } | |
| 95 | ||
| 96 | pub struct DisallowedTypes { | |
| 97 | default: TypeLookup, | |
| 98 | /// Lookup per profile that declares a non-empty `disallowed_types` list. Profiles | |
| 99 | /// declared in `[profiles.*]` but without `disallowed_types` entries are absent here. | |
| 100 | profiles: FxHashMap<Symbol, TypeLookup>, | |
| 101 | /// Every profile name declared in `[profiles.*]`, regardless of whether it contributes | |
| 102 | /// to this lint. Used to suppress the "unknown profile" warning for profiles that exist | |
| 103 | /// in config but only define entries for other lints (e.g. `disallowed_methods`). | |
| 104 | known_profiles: FxHashSet<Symbol>, | |
| 105 | profile_cache: ProfileResolver, | |
| 106 | warned_unknown_profiles: FxHashSet<Span>, | |
| 107 | } | |
| 108 | ||
| 109 | 67 | impl DisallowedTypes { |
| 110 | #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration. | |
| 111 | 68 | pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { |
| 112 | let default = TypeLookup::from_config(tcx, &conf.disallowed_types); | |
| 113 | ||
| 114 | let mut profiles = FxHashMap::default(); | |
| 115 | let mut known_profiles = FxHashSet::default(); | |
| 116 | let mut profile_entries: Vec<_> = conf.profiles.iter().collect(); | |
| 117 | profile_entries.sort_by_key(|(a, _)| *a); | |
| 118 | for (name, profile) in profile_entries { | |
| 119 | let symbol = Symbol::intern(name.as_str()); | |
| 120 | known_profiles.insert(symbol); | |
| 121 | ||
| 122 | let paths = profile.disallowed_types.as_slice(); | |
| 123 | if paths.is_empty() { | |
| 124 | continue; | |
| 125 | } | |
| 126 | profiles.insert(symbol, TypeLookup::from_config(tcx, paths)); | |
| 127 | } | |
| 128 | ||
| 129 | Self { | |
| 130 | default, | |
| 131 | profiles, | |
| 132 | known_profiles, | |
| 133 | profile_cache: ProfileResolver::default(), | |
| 134 | warned_unknown_profiles: FxHashSet::default(), | |
| 135 | } | |
| 136 | } | |
| 137 | ||
| 138 | fn warn_unknown_profile(&mut self, cx: &LateContext<'_>, entry: &ProfileEntry) { | |
| 139 | if self.warned_unknown_profiles.insert(entry.span) { | |
| 140 | let attr_name = if entry.attr_name == sym::disallowed_profiles { | |
| 141 | "clippy::disallowed_profiles" | |
| 142 | } else { | |
| 143 | "clippy::disallowed_profile" | |
| 144 | }; | |
| 145 | span_lint( | |
| 146 | cx, | |
| 147 | DISALLOWED_TYPES, | |
| 148 | entry.span, | |
| 149 | format!( | |
| 150 | "`{attr_name}` references unknown profile `{}` for `clippy::disallowed_types`", | |
| 151 | entry.name | |
| 152 | ), | |
| 153 | ); | |
| 154 | } | |
| 69 | let (def_ids, prim_tys) = create_disallowed_map( | |
| 70 | tcx, | |
| 71 | &conf.disallowed_types, | |
| 72 | PathNS::Type, | |
| 73 | def_kind_predicate, | |
| 74 | "type", | |
| 75 | true, | |
| 76 | ); | |
| 77 | Self { def_ids, prim_tys } | |
| 155 | 78 | } |
| 156 | 79 | |
| 157 | fn check_res_emit(&mut self, cx: &LateContext<'_>, hir_id: rustc_hir::HirId, res: &Res, span: Span) { | |
| 158 | let mut active_profiles = SmallVec::<[Symbol; 2]>::new(); | |
| 159 | // Copy entries out of the cache before iterating: `warn_unknown_profile` takes | |
| 160 | // `&mut self`, which conflicts with the borrow held by `active_profiles(...)`. | |
| 161 | let entries: SmallVec<[ProfileEntry; 2]> = self | |
| 162 | .profile_cache | |
| 163 | .active_profiles(cx, hir_id) | |
| 164 | .map(|selection| selection.iter().copied().collect()) | |
| 165 | .unwrap_or_default(); | |
| 166 | for entry in &entries { | |
| 167 | if self.profiles.contains_key(&entry.name) { | |
| 168 | active_profiles.push(entry.name); | |
| 169 | } else if !self.known_profiles.contains(&entry.name) { | |
| 170 | self.warn_unknown_profile(cx, entry); | |
| 171 | } | |
| 172 | } | |
| 173 | ||
| 174 | if let Some((profile, (path, disallowed_path))) = active_profiles.iter().find_map(|symbol| { | |
| 175 | self.profiles | |
| 176 | .get(symbol) | |
| 177 | .and_then(|lookup| lookup.find(res).map(|info| (*symbol, info))) | |
| 178 | }) { | |
| 179 | let diag_amendment = disallowed_path.diag_amendment(span); | |
| 180 | span_lint_and_then( | |
| 181 | cx, | |
| 182 | DISALLOWED_TYPES, | |
| 183 | span, | |
| 184 | format!("use of a disallowed type `{path}` (profile: {profile})"), | |
| 185 | |diag| diag_amendment(diag), | |
| 186 | ); | |
| 187 | } else if let Some((path, disallowed_path)) = self.default.find(res) { | |
| 188 | let diag_amendment = disallowed_path.diag_amendment(span); | |
| 189 | span_lint_and_then( | |
| 190 | cx, | |
| 191 | DISALLOWED_TYPES, | |
| 192 | span, | |
| 193 | format!("use of a disallowed type `{path}`"), | |
| 194 | |diag| diag_amendment(diag), | |
| 195 | ); | |
| 196 | } | |
| 80 | fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) { | |
| 81 | let (path, disallowed_path) = match res { | |
| 82 | Res::Def(_, did) if let Some(&x) = self.def_ids.get(did) => x, | |
| 83 | Res::PrimTy(prim) if let Some(&x) = self.prim_tys.get(prim) => x, | |
| 84 | _ => return, | |
| 85 | }; | |
| 86 | span_lint_and_then( | |
| 87 | cx, | |
| 88 | DISALLOWED_TYPES, | |
| 89 | span, | |
| 90 | format!("use of a disallowed type `{path}`"), | |
| 91 | disallowed_path.diag_amendment(span), | |
| 92 | ); | |
| 197 | 93 | } |
| 198 | 94 | } |
| 199 | 95 | |
| ... | ... | @@ -215,22 +111,17 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { |
| 215 | 111 | if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind |
| 216 | 112 | && let Some(res) = path.res.type_ns |
| 217 | 113 | { |
| 218 | self.check_res_emit(cx, item.hir_id(), &res, item.span); | |
| 114 | self.check_res_emit(cx, &res, item.span); | |
| 219 | 115 | } |
| 220 | 116 | } |
| 221 | 117 | |
| 222 | 118 | fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) { |
| 223 | 119 | if let TyKind::Path(path) = &ty.kind { |
| 224 | self.check_res_emit(cx, ty.hir_id, &cx.qpath_res(path, ty.hir_id), ty.span); | |
| 120 | self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span); | |
| 225 | 121 | } |
| 226 | 122 | } |
| 227 | 123 | |
| 228 | 124 | fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { |
| 229 | self.check_res_emit( | |
| 230 | cx, | |
| 231 | poly.trait_ref.hir_ref_id, | |
| 232 | &poly.trait_ref.path.res, | |
| 233 | poly.trait_ref.path.span, | |
| 234 | ); | |
| 125 | self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span); | |
| 235 | 126 | } |
| 236 | 127 | } |
src/tools/clippy/clippy_lints/src/doc/missing_headers.rs+1-1| ... | ... | @@ -99,7 +99,7 @@ pub fn check( |
| 99 | 99 | fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> { |
| 100 | 100 | let mut panic_span = None; |
| 101 | 101 | let typeck = cx.tcx.typeck_body(body_id); |
| 102 | for_each_expr(cx, cx.tcx.hir_body(body_id), |expr| { | |
| 102 | for_each_expr(cx.tcx, cx.tcx.hir_body(body_id), |expr| { | |
| 103 | 103 | if is_inside_always_const_context(cx.tcx, expr.hir_id) { |
| 104 | 104 | return ControlFlow::<!>::Continue(()); |
| 105 | 105 | } |
src/tools/clippy/clippy_lints/src/doc/mod.rs+29-14| ... | ... | @@ -1124,6 +1124,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize |
| 1124 | 1124 | |
| 1125 | 1125 | let mut containers = Vec::new(); |
| 1126 | 1126 | |
| 1127 | // Skip collecting text and the per-word scan when `DOC_MARKDOWN` (pedantic) is allowed. | |
| 1128 | let check_doc_markdown = !clippy_utils::is_lint_allowed(cx, DOC_MARKDOWN, cx.last_node_with_lint_attrs); | |
| 1129 | ||
| 1127 | 1130 | let mut events = events.peekable(); |
| 1128 | 1131 | |
| 1129 | 1132 | while let Some((event, range)) = events.next() { |
| ... | ... | @@ -1238,19 +1241,29 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize |
| 1238 | 1241 | if let End(TagEnd::Item) = event { |
| 1239 | 1242 | containers.pop(); |
| 1240 | 1243 | } |
| 1241 | if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) { | |
| 1242 | span_lint_and_help( | |
| 1243 | cx, | |
| 1244 | DOC_MARKDOWN, | |
| 1245 | span, | |
| 1246 | "backticks are unbalanced", | |
| 1247 | None, | |
| 1248 | "a backtick may be missing a pair", | |
| 1249 | ); | |
| 1250 | text_to_check.clear(); | |
| 1251 | } else { | |
| 1252 | for (text, range, assoc_code_level) in text_to_check.drain(..) { | |
| 1253 | markdown::check(cx, valid_idents, &text, &fragments, range, assoc_code_level, blockquote_level); | |
| 1244 | if check_doc_markdown { | |
| 1245 | if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) { | |
| 1246 | span_lint_and_help( | |
| 1247 | cx, | |
| 1248 | DOC_MARKDOWN, | |
| 1249 | span, | |
| 1250 | "backticks are unbalanced", | |
| 1251 | None, | |
| 1252 | "a backtick may be missing a pair", | |
| 1253 | ); | |
| 1254 | text_to_check.clear(); | |
| 1255 | } else { | |
| 1256 | for (text, range, assoc_code_level) in text_to_check.drain(..) { | |
| 1257 | markdown::check( | |
| 1258 | cx, | |
| 1259 | valid_idents, | |
| 1260 | &text, | |
| 1261 | &fragments, | |
| 1262 | range, | |
| 1263 | assoc_code_level, | |
| 1264 | blockquote_level, | |
| 1265 | ); | |
| 1266 | } | |
| 1254 | 1267 | } |
| 1255 | 1268 | } |
| 1256 | 1269 | }, |
| ... | ... | @@ -1331,7 +1344,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize |
| 1331 | 1344 | // Don't check the text associated with external URLs |
| 1332 | 1345 | continue; |
| 1333 | 1346 | } |
| 1334 | text_to_check.push((text, range.clone(), code_level)); | |
| 1347 | if check_doc_markdown { | |
| 1348 | text_to_check.push((text, range.clone(), code_level)); | |
| 1349 | } | |
| 1335 | 1350 | doc_suspicious_footnotes::check(cx, doc, range, &fragments, attrs); |
| 1336 | 1351 | } |
| 1337 | 1352 | } |
src/tools/clippy/clippy_lints/src/double_parens.rs+2-2| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::source::{HasSession, SpanRangeExt, snippet_with_applicability, snippet_with_context}; | |
| 2 | use clippy_utils::source::{SpanExt, snippet_with_applicability, snippet_with_context}; | |
| 3 | 3 | use rustc_ast::ast::{Expr, ExprKind, MethodCall}; |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | use rustc_lint::{EarlyContext, EarlyLintPass}; | |
| 5 | use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; | |
| 6 | 6 | use rustc_session::declare_lint_pass; |
| 7 | 7 | |
| 8 | 8 | declare_clippy_lint! { |
src/tools/clippy/clippy_lints/src/empty_enums.rs+1-1| ... | ... | @@ -51,7 +51,7 @@ declare_clippy_lint! { |
| 51 | 51 | /// [visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html |
| 52 | 52 | #[clippy::version = "pre 1.29.0"] |
| 53 | 53 | pub EMPTY_ENUMS, |
| 54 | pedantic, | |
| 54 | nursery, | |
| 55 | 55 | "enum with no variants" |
| 56 | 56 | } |
| 57 | 57 |
src/tools/clippy/clippy_lints/src/empty_line_after.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use std::borrow::Cow; |
| 2 | 2 | |
| 3 | 3 | use clippy_utils::diagnostics::span_lint_and_then; |
| 4 | use clippy_utils::source::{SpanRangeExt, snippet_indent}; | |
| 4 | use clippy_utils::source::{SpanExt, snippet_indent}; | |
| 5 | 5 | use clippy_utils::tokenize_with_text; |
| 6 | 6 | use itertools::Itertools; |
| 7 | 7 | use rustc_ast::token::CommentKind; |
| ... | ... | @@ -288,7 +288,7 @@ impl<'a> Gap<'a> { |
| 288 | 288 | let prev_stop = prev_chunk.last()?; |
| 289 | 289 | let next_stop = next_chunk.first()?; |
| 290 | 290 | let gap_span = prev_stop.span.between(next_stop.span); |
| 291 | let gap_snippet = gap_span.get_source_text(cx)?; | |
| 291 | let gap_snippet = gap_span.get_text(cx)?; | |
| 292 | 292 | |
| 293 | 293 | let mut has_comment = false; |
| 294 | 294 | let mut empty_lines = Vec::new(); |
src/tools/clippy/clippy_lints/src/empty_with_brackets.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::attrs::span_contains_cfg; |
| 2 | 2 | use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::span_contains_non_whitespace; |
| 5 | 5 | use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -192,7 +192,7 @@ impl LateLintPass<'_> for EmptyWithBrackets { |
| 192 | 192 | // Span of the parentheses in variant definition |
| 193 | 193 | let span = variant.span.with_lo(variant.ident.span.hi()); |
| 194 | 194 | let span_inner = span |
| 195 | .with_lo(SpanRangeExt::trim_start(span, cx).start + BytePos(1)) | |
| 195 | .with_lo(SpanExt::trim_start(span, cx).start + BytePos(1)) | |
| 196 | 196 | .with_hi(span.hi() - BytePos(1)); |
| 197 | 197 | if span_contains_non_whitespace(cx, span_inner, false) { |
| 198 | 198 | continue; |
src/tools/clippy/clippy_lints/src/entry.rs+1-1| ... | ... | @@ -604,7 +604,7 @@ fn is_any_expr_in_map_used<'tcx>( |
| 604 | 604 | map: &'tcx Expr<'tcx>, |
| 605 | 605 | expr: &'tcx Expr<'tcx>, |
| 606 | 606 | ) -> bool { |
| 607 | for_each_expr(cx, map, |e| { | |
| 607 | for_each_expr(cx.tcx, map, |e| { | |
| 608 | 608 | if spanless_eq.eq_expr(ctxt, e, expr) { |
| 609 | 609 | return ControlFlow::Break(()); |
| 610 | 610 | } |
src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs+1-1| ... | ... | @@ -102,7 +102,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { |
| 102 | 102 | fn emit_sugg(&self, spans: Vec<Span>, msg: String, help: &'static str) { |
| 103 | 103 | let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect(); |
| 104 | 104 | span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| { |
| 105 | diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable); | |
| 105 | diag.multipart_suggestion(help, suggestions, Applicability::MaybeIncorrect); | |
| 106 | 106 | }); |
| 107 | 107 | } |
| 108 | 108 |
src/tools/clippy/clippy_lints/src/floating_point_arithmetic/mul_add.rs+2-1| ... | ... | @@ -91,7 +91,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { |
| 91 | 91 | cx, |
| 92 | 92 | SUBOPTIMAL_FLOPS, |
| 93 | 93 | expr.span, |
| 94 | "multiply and add expressions can be calculated more efficiently and accurately", | |
| 94 | "multiply and add expressions may be calculated more efficiently and accurately", | |
| 95 | 95 | |diag| { |
| 96 | 96 | let maybe_neg_sugg = |expr, app: &mut _| { |
| 97 | 97 | let sugg = Sugg::hir_with_applicability(cx, expr, "_", app); |
| ... | ... | @@ -120,6 +120,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { |
| 120 | 120 | }, |
| 121 | 121 | app, |
| 122 | 122 | ); |
| 123 | diag.note_once("the performance gain from `mul_add` may vary depending on the target architecture"); | |
| 123 | 124 | }, |
| 124 | 125 | ); |
| 125 | 126 | } |
src/tools/clippy/clippy_lints/src/format.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, first_node_in_macro, matching_root_macro_call}; |
| 3 | use clippy_utils::source::{SpanRangeExt, snippet_with_context}; | |
| 3 | use clippy_utils::source::{SpanExt, snippet_with_context}; | |
| 4 | 4 | use clippy_utils::sugg::Sugg; |
| 5 | 5 | use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { |
| 69 | 69 | ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), |
| 70 | 70 | ([], [_]) => { |
| 71 | 71 | // Simulate macro expansion, converting {{ and }} to { and }. |
| 72 | let Some(snippet) = format_args.span.get_source_text(cx) else { | |
| 72 | let Some(snippet) = format_args.span.get_text(cx) else { | |
| 73 | 73 | return; |
| 74 | 74 | }; |
| 75 | 75 | let s_expand = snippet.replace("{{", "{").replace("}}", "}"); |
src/tools/clippy/clippy_lints/src/format_args.rs+3-3| ... | ... | @@ -10,7 +10,7 @@ use clippy_utils::macros::{ |
| 10 | 10 | }; |
| 11 | 11 | use clippy_utils::msrvs::{self, Msrv}; |
| 12 | 12 | use clippy_utils::res::MaybeDef; |
| 13 | use clippy_utils::source::{SpanRangeExt, snippet, snippet_opt}; | |
| 13 | use clippy_utils::source::{SpanExt, snippet, snippet_opt}; | |
| 14 | 14 | use clippy_utils::ty::implements_trait; |
| 15 | 15 | use clippy_utils::{is_from_proc_macro, is_in_test, peel_hir_expr_while, sym, trait_ref_of_method}; |
| 16 | 16 | use itertools::Itertools; |
| ... | ... | @@ -380,7 +380,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { |
| 380 | 380 | /// Check if there is a comma after the last format macro arg. |
| 381 | 381 | fn check_trailing_comma(&self) { |
| 382 | 382 | let span = self.macro_call.span; |
| 383 | if let Some(src) = span.get_source_text(self.cx) | |
| 383 | if let Some(src) = span.get_text(self.cx) | |
| 384 | 384 | && let Some(src) = src.strip_suffix([')', ']', '}']) |
| 385 | 385 | && let src = src.trim_end_matches(|c: char| c.is_whitespace() && c != '\n') |
| 386 | 386 | && let Some(src) = src.strip_suffix(',') |
| ... | ... | @@ -694,7 +694,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { |
| 694 | 694 | count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) |
| 695 | 695 | && implements_trait(cx, target, display_trait_id, &[]) |
| 696 | 696 | && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() |
| 697 | && let Some(receiver_snippet) = receiver.span.source_callsite().get_source_text(cx) | |
| 697 | && let Some(receiver_snippet) = receiver.span.source_callsite().get_text(cx) | |
| 698 | 698 | { |
| 699 | 699 | let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); |
| 700 | 700 | if n_needed_derefs == 0 && !needs_ref { |
src/tools/clippy/clippy_lints/src/four_forward_slashes.rs+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::SpanRangeExt as _; | |
| 2 | use clippy_utils::source::SpanExt as _; | |
| 3 | 3 | use itertools::Itertools; |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_hir::Item; |
| ... | ... | @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes { |
| 86 | 86 | |
| 87 | 87 | // If the comment contains a bare CR (not followed by a LF), do not propose an auto-fix |
| 88 | 88 | // as bare CR are not allowed in doc comments. |
| 89 | if span.check_source_text(cx, contains_bare_cr) { | |
| 89 | if span.check_text(cx, contains_bare_cr) { | |
| 90 | 90 | diag.help(msg) |
| 91 | 91 | .note("bare CR characters are not allowed in doc comments"); |
| 92 | 92 | return; |
src/tools/clippy/clippy_lints/src/from_over_into.rs+3-3| ... | ... | @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then; |
| 5 | 5 | use clippy_utils::macros::span_is_local; |
| 6 | 6 | use clippy_utils::msrvs::{self, Msrv}; |
| 7 | 7 | use clippy_utils::res::MaybeResPath; |
| 8 | use clippy_utils::source::SpanRangeExt; | |
| 8 | use clippy_utils::source::SpanExt; | |
| 9 | 9 | use rustc_errors::Applicability; |
| 10 | 10 | use rustc_hir::intravisit::{Visitor, walk_path}; |
| 11 | 11 | use rustc_hir::{ |
| ... | ... | @@ -197,8 +197,8 @@ fn convert_to_from( |
| 197 | 197 | return None; |
| 198 | 198 | }; |
| 199 | 199 | |
| 200 | let from = self_ty.span.get_source_text(cx)?; | |
| 201 | let into = target_ty.span.get_source_text(cx)?; | |
| 200 | let from = self_ty.span.get_text(cx)?; | |
| 201 | let into = target_ty.span.get_text(cx)?; | |
| 202 | 202 | |
| 203 | 203 | let mut suggestions = vec![ |
| 204 | 204 | // impl Into<T> for U -> impl From<T> for U |
src/tools/clippy/clippy_lints/src/functions/must_use.rs+5-6| ... | ... | @@ -163,12 +163,11 @@ fn check_needless_must_use( |
| 163 | 163 | ); |
| 164 | 164 | } else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { |
| 165 | 165 | // Ignore async functions unless Future::Output type is a must_use type |
| 166 | if sig.header.is_async() { | |
| 167 | if let Some(future_ty) = cx.tcx.get_impl_future_output_ty(return_ty(cx, item_id)) | |
| 168 | && !is_must_use_ty(cx, future_ty) | |
| 169 | { | |
| 170 | return; | |
| 171 | } | |
| 166 | if sig.header.is_async() | |
| 167 | && let Some(future_ty) = cx.tcx.get_impl_future_output_ty(return_ty(cx, item_id)) | |
| 168 | && !is_must_use_ty(cx, future_ty) | |
| 169 | { | |
| 170 | return; | |
| 172 | 171 | } |
| 173 | 172 | |
| 174 | 173 | span_lint_and_then( |
src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs+1-1| ... | ... | @@ -50,7 +50,7 @@ fn check_raw_ptr<'tcx>( |
| 50 | 50 | |
| 51 | 51 | if !raw_ptrs.is_empty() { |
| 52 | 52 | let typeck = cx.tcx.typeck_body(body.id()); |
| 53 | let _: Option<!> = for_each_expr(cx, body.value, |e| { | |
| 53 | let _: Option<!> = for_each_expr(cx.tcx, body.value, |e| { | |
| 54 | 54 | match e.kind { |
| 55 | 55 | hir::ExprKind::Call(f, args) if is_unsafe_fn(cx, typeck.expr_ty(f)) => { |
| 56 | 56 | for arg in args { |
src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use rustc_hir as hir; |
| 4 | 4 | use rustc_hir::def_id::LocalDefId; |
| 5 | 5 | use rustc_hir::intravisit::FnKind; |
| ... | ... | @@ -23,7 +23,7 @@ pub(super) fn check_fn( |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | let mut line_count: u64 = 0; |
| 26 | let too_many = body.value.span.check_source_text(cx, |src| { | |
| 26 | let too_many = body.value.span.check_text(cx, |src| { | |
| 27 | 27 | let mut in_comment = false; |
| 28 | 28 | let mut code_in_line; |
| 29 | 29 |
src/tools/clippy/clippy_lints/src/if_not_else.rs+11-12| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 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 | use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_context}; | |
| 4 | use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_context}; | |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; |
| 7 | 7 | use rustc_lint::{LateContext, LateLintPass}; |
| ... | ... | @@ -104,28 +104,27 @@ impl LateLintPass<'_> for IfNotElse { |
| 104 | 104 | } |
| 105 | 105 | } |
| 106 | 106 | |
| 107 | fn make_sugg<'a>( | |
| 108 | sess: &impl HasSession, | |
| 107 | fn make_sugg( | |
| 108 | cx: &LateContext<'_>, | |
| 109 | 109 | expr_span: Span, |
| 110 | cond_kind: &'a ExprKind<'a>, | |
| 110 | cond_kind: &ExprKind<'_>, | |
| 111 | 111 | cond_inner: Span, |
| 112 | 112 | els_span: Span, |
| 113 | default: &'a str, | |
| 113 | default: &str, | |
| 114 | 114 | applicability: &mut Applicability, |
| 115 | 115 | ) -> String { |
| 116 | let (cond_inner_snip, _) = snippet_with_context(sess, cond_inner, expr_span.ctxt(), default, applicability); | |
| 117 | let (els_snip, _) = snippet_with_context(sess, els_span, expr_span.ctxt(), default, applicability); | |
| 118 | let indent = indent_of(sess, expr_span); | |
| 119 | ||
| 116 | let (cond_inner_snip, _) = snippet_with_context(cx, cond_inner, expr_span.ctxt(), default, applicability); | |
| 117 | let (els_snip, _) = snippet_with_context(cx, els_span, expr_span.ctxt(), default, applicability); | |
| 118 | let indent = indent_of(cx, expr_span); | |
| 120 | 119 | let suggestion = match cond_kind { |
| 121 | 120 | ExprKind::Unary(UnOp::Not, cond_rest) => { |
| 122 | 121 | let (cond_rest_snip, _) = |
| 123 | snippet_with_context(sess, cond_rest.span, expr_span.ctxt(), default, applicability); | |
| 122 | snippet_with_context(cx, cond_rest.span, expr_span.ctxt(), default, applicability); | |
| 124 | 123 | format!("if {cond_rest_snip} {els_snip} else {cond_inner_snip}") |
| 125 | 124 | }, |
| 126 | 125 | ExprKind::Binary(_, lhs, rhs) => { |
| 127 | let (lhs_snip, _) = snippet_with_context(sess, lhs.span, expr_span.ctxt(), default, applicability); | |
| 128 | let (rhs_snip, _) = snippet_with_context(sess, rhs.span, expr_span.ctxt(), default, applicability); | |
| 126 | let (lhs_snip, _) = snippet_with_context(cx, lhs.span, expr_span.ctxt(), default, applicability); | |
| 127 | let (rhs_snip, _) = snippet_with_context(cx, rhs.span, expr_span.ctxt(), default, applicability); | |
| 129 | 128 | |
| 130 | 129 | format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}") |
| 131 | 130 | }, |
src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::res::MaybeResPath; |
| 3 | use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; | |
| 3 | use clippy_utils::source::{IntoSpan, SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet}; | |
| 4 | 4 | use clippy_utils::ty::needs_ordered_drop; |
| 5 | 5 | use clippy_utils::visitors::for_each_expr_without_closures; |
| 6 | 6 | use clippy_utils::{ |
src/tools/clippy/clippy_lints/src/implicit_hasher.rs+1-1| ... | ... | @@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass; |
| 13 | 13 | use rustc_span::Span; |
| 14 | 14 | |
| 15 | 15 | use clippy_utils::diagnostics::span_lint_and_then; |
| 16 | use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet, snippet_with_context}; | |
| 16 | use clippy_utils::source::{IntoSpan, SpanExt, snippet, snippet_with_context}; | |
| 17 | 17 | use clippy_utils::sym; |
| 18 | 18 | |
| 19 | 19 | declare_clippy_lint! { |
src/tools/clippy/clippy_lints/src/incompatible_msrv.rs+3-2| ... | ... | @@ -193,10 +193,11 @@ impl IncompatibleMsrv { |
| 193 | 193 | } |
| 194 | 194 | } |
| 195 | 195 | |
| 196 | if (self.check_in_tests || !is_in_test(cx.tcx, node)) | |
| 197 | && let Some(current) = self.msrv.current(cx) | |
| 196 | // Check `is_in_test` last as it walks the HIR parent chain. | |
| 197 | if let Some(current) = self.msrv.current(cx) | |
| 198 | 198 | && let Availability::Since(version) = self.get_def_id_availability(cx.tcx, def_id, needs_const) |
| 199 | 199 | && version > current |
| 200 | && (self.check_in_tests || !is_in_test(cx.tcx, node)) | |
| 200 | 201 | { |
| 201 | 202 | span_lint_and_then( |
| 202 | 203 | cx, |
src/tools/clippy/clippy_lints/src/ineffective_open_options.rs+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::res::MaybeDef; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::{peel_blocks, peel_hir_expr_while, sym}; |
| 5 | 5 | use rustc_ast::LitKind; |
| 6 | 6 | use rustc_errors::Applicability; |
src/tools/clippy/clippy_lints/src/inline_trait_bounds.rs+2-2| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::{HasSession, snippet}; | |
| 2 | use clippy_utils::source::snippet; | |
| 3 | 3 | use clippy_utils::sym; |
| 4 | 4 | use rustc_ast::ast::{Fn, FnRetTy, GenericParam, GenericParamKind}; |
| 5 | 5 | use rustc_ast::visit::{FnCtxt, FnKind}; |
| 6 | 6 | use rustc_ast::{HasAttrs as _, NodeId}; |
| 7 | 7 | use rustc_errors::Applicability; |
| 8 | use rustc_lint::{EarlyContext, EarlyLintPass}; | |
| 8 | use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; | |
| 9 | 9 | use rustc_session::impl_lint_pass; |
| 10 | 10 | use rustc_span::Span; |
| 11 | 11 |
src/tools/clippy/clippy_lints/src/items_after_test_module.rs+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_hir_and_then; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; |
| 4 | 4 | use rustc_errors::{Applicability, SuggestionStyle}; |
| 5 | 5 | use rustc_hir::{HirId, Item, ItemKind, Mod}; |
| ... | ... | @@ -99,7 +99,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule { |
| 99 | 99 | if let Some(prev) = mod_pos.checked_sub(1) |
| 100 | 100 | && let prev = cx.tcx.hir_item(module.item_ids[prev]) |
| 101 | 101 | && let items_span = last.span.with_lo(test_mod.span.hi()) |
| 102 | && let Some(items) = items_span.get_source_text(cx) | |
| 102 | && let Some(items) = items_span.get_text(cx) | |
| 103 | 103 | { |
| 104 | 104 | diag.multipart_suggestion_with_style( |
| 105 | 105 | "move the items to before the test module was defined", |
src/tools/clippy/clippy_lints/src/large_stack_frames.rs+4-4| ... | ... | @@ -2,7 +2,7 @@ use std::{fmt, ops}; |
| 2 | 2 | |
| 3 | 3 | use clippy_config::Conf; |
| 4 | 4 | use clippy_utils::diagnostics::span_lint_and_then; |
| 5 | use clippy_utils::source::{HasSession, SpanRangeExt}; | |
| 5 | use clippy_utils::source::SpanExt; | |
| 6 | 6 | use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_in_test}; |
| 7 | 7 | use rustc_errors::Diag; |
| 8 | 8 | use rustc_hir::def_id::LocalDefId; |
| ... | ... | @@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { |
| 197 | 197 | // TODO: Is there a cleaner, robust way to ask this question? |
| 198 | 198 | // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", |
| 199 | 199 | // and that doesn't get us the true name in scope rather than the span text either. |
| 200 | if let Some(name) = local_span.get_source_text(cx) | |
| 200 | if let Some(name) = local_span.get_text(cx) | |
| 201 | 201 | && is_ident(&name) |
| 202 | 202 | { |
| 203 | 203 | // If the local is an ordinary named variable, |
| ... | ... | @@ -228,11 +228,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { |
| 228 | 228 | |
| 229 | 229 | if fn_span.from_expansion() { |
| 230 | 230 | // Don't lint on the main function generated by `--test` target |
| 231 | if cx.sess().is_test_crate() && is_entrypoint_fn(cx, local_def_id.to_def_id()) { | |
| 231 | if cx.tcx.sess.is_test_crate() && is_entrypoint_fn(cx, local_def_id.to_def_id()) { | |
| 232 | 232 | return; |
| 233 | 233 | } |
| 234 | 234 | |
| 235 | let is_from_external_macro = fn_span.in_external_macro(cx.sess().source_map()); | |
| 235 | let is_from_external_macro = fn_span.in_external_macro(cx.tcx.sess.source_map()); | |
| 236 | 236 | span_lint_and_then( |
| 237 | 237 | cx, |
| 238 | 238 | LARGE_STACK_FRAMES, |
src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | 3 | use clippy_utils::msrvs::{self, Msrv}; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use clippy_utils::{is_from_proc_macro, sym}; |
| 6 | 6 | use hir::def_id::DefId; |
| 7 | 7 | use rustc_errors::Applicability; |
| ... | ... | @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { |
| 121 | 121 | && let QPath::TypeRelative(ty, last_segment) = qpath |
| 122 | 122 | && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() |
| 123 | 123 | && is_integer_method(cx, def_id) |
| 124 | && let Some(mod_name) = ty.span.get_source_text(cx) | |
| 124 | && let Some(mod_name) = ty.span.get_text(cx) | |
| 125 | 125 | && ty.span.eq_ctxt(last_segment.ident.span) |
| 126 | 126 | { |
| 127 | 127 | let name = last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(); |
src/tools/clippy/clippy_lints/src/len_zero.rs+2-2| ... | ... | @@ -2,7 +2,7 @@ use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 3 | 3 | use clippy_utils::msrvs::Msrv; |
| 4 | 4 | use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; |
| 5 | use clippy_utils::source::{SpanRangeExt, snippet_with_context}; | |
| 5 | use clippy_utils::source::{SpanExt, snippet_with_context}; | |
| 6 | 6 | use clippy_utils::sugg::{Sugg, has_enclosing_paren}; |
| 7 | 7 | use clippy_utils::ty::implements_trait; |
| 8 | 8 | use clippy_utils::{parent_item_name, peel_ref_operators, sym}; |
| ... | ... | @@ -261,7 +261,7 @@ impl LenZero { |
| 261 | 261 | } |
| 262 | 262 | |
| 263 | 263 | fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { |
| 264 | let Some(snippet) = span.get_source_text(cx) else { | |
| 264 | let Some(snippet) = span.get_text(cx) else { | |
| 265 | 265 | return span; |
| 266 | 266 | }; |
| 267 | 267 | if has_enclosing_paren(snippet) { |
src/tools/clippy/clippy_lints/src/let_underscore.rs+2-1| ... | ... | @@ -162,7 +162,8 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { |
| 162 | 162 | ); |
| 163 | 163 | }, |
| 164 | 164 | ); |
| 165 | } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() | |
| 165 | } else if local.ty.is_none() | |
| 166 | && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() | |
| 166 | 167 | && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) |
| 167 | 168 | { |
| 168 | 169 | #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] |
src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::is_from_proc_macro; |
| 3 | use clippy_utils::source::{IntoSpan, SpanRangeExt}; | |
| 3 | use clippy_utils::source::{IntoSpan, SpanExt}; | |
| 4 | 4 | use rustc_ast::{Local, TyKind}; |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; |
src/tools/clippy/clippy_lints/src/lib.rs+3-5| ... | ... | @@ -454,9 +454,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co |
| 454 | 454 | // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. |
| 455 | 455 | // Due to the architecture of the compiler, currently `cfg_attr` attributes on crate |
| 456 | 456 | // level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. |
| 457 | store.register_pre_expansion_pass( | |
| 458 | Box::new(move || Box::new(attrs::EarlyAttributes::new(conf))) | |
| 459 | ); | |
| 457 | store.register_pre_expansion_pass(Box::new(move || Box::new(attrs::EarlyAttributes::new(conf)))); | |
| 460 | 458 | |
| 461 | 459 | let format_args_storage = FormatArgsStorage::default(); |
| 462 | 460 | let attr_storage = AttrStorage::default(); |
| ... | ... | @@ -531,7 +529,6 @@ rustc_lint::early_lint_methods!( |
| 531 | 529 | PartialPubFields: partial_pub_fields::PartialPubFields = partial_pub_fields::PartialPubFields, |
| 532 | 530 | UnderscoreTyped: let_with_type_underscore::UnderscoreTyped = let_with_type_underscore::UnderscoreTyped, |
| 533 | 531 | ExcessiveNesting: excessive_nesting::ExcessiveNesting = excessive_nesting::ExcessiveNesting::new(conf), |
| 534 | RefPatterns: ref_patterns::RefPatterns = ref_patterns::RefPatterns, | |
| 535 | 532 | NeedlessElse: needless_else::NeedlessElse = needless_else::NeedlessElse, |
| 536 | 533 | RawStrings: raw_strings::RawStrings = raw_strings::RawStrings::new(conf), |
| 537 | 534 | Visibility: visibility::Visibility = visibility::Visibility, |
| ... | ... | @@ -729,7 +726,7 @@ rustc_lint::late_lint_methods!( |
| 729 | 726 | UndocumentedUnsafeBlocks: undocumented_unsafe_blocks::UndocumentedUnsafeBlocks = undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(conf), |
| 730 | 727 | FormatArgs: format_args::FormatArgs<'tcx> = format_args::FormatArgs::new(tcx, conf, format_args.clone()), |
| 731 | 728 | TrailingEmptyArray: trailing_empty_array::TrailingEmptyArray = trailing_empty_array::TrailingEmptyArray, |
| 732 | NeedlessLateInit: needless_late_init::NeedlessLateInit = needless_late_init::NeedlessLateInit, | |
| 729 | NeedlessLateInit: needless_late_init::NeedlessLateInit<'tcx> = needless_late_init::NeedlessLateInit::new(conf), | |
| 733 | 730 | ReturnSelfNotMustUse: return_self_not_must_use::ReturnSelfNotMustUse = return_self_not_must_use::ReturnSelfNotMustUse, |
| 734 | 731 | NumberedFields: init_numbered_fields::NumberedFields = init_numbered_fields::NumberedFields, |
| 735 | 732 | ManualBits: manual_bits::ManualBits = manual_bits::ManualBits::new(conf), |
| ... | ... | @@ -859,6 +856,7 @@ rustc_lint::late_lint_methods!( |
| 859 | 856 | ByteCharSlice: byte_char_slices::ByteCharSlice = byte_char_slices::ByteCharSlice, |
| 860 | 857 | ManualAssertEq: manual_assert_eq::ManualAssertEq = manual_assert_eq::ManualAssertEq, |
| 861 | 858 | WithCapacityZero: with_capacity_zero::WithCapacityZero = with_capacity_zero::WithCapacityZero, |
| 859 | RefPatterns: ref_patterns::RefPatterns = ref_patterns::RefPatterns, | |
| 862 | 860 | // add late passes here, used by `cargo dev new_lint` |
| 863 | 861 | ]] |
| 864 | 862 | ); |
src/tools/clippy/clippy_lints/src/lifetimes.rs+3-1| ... | ... | @@ -161,7 +161,9 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly_trait_ref: &'tcx PolyTraitRef<'tcx>) { |
| 164 | report_extra_trait_object_lifetimes(cx, poly_trait_ref.bound_generic_params, &poly_trait_ref.trait_ref); | |
| 164 | if !poly_trait_ref.span.from_expansion() { | |
| 165 | report_extra_trait_object_lifetimes(cx, poly_trait_ref.bound_generic_params, &poly_trait_ref.trait_ref); | |
| 166 | } | |
| 165 | 167 | } |
| 166 | 168 | |
| 167 | 169 | fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { |
src/tools/clippy/clippy_lints/src/literal_representation.rs+8-4| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | 3 | use clippy_utils::numeric_literal::{NumericLiteral, Radix}; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use rustc_ast::ast::{Expr, ExprKind, LitKind}; |
| 6 | 6 | use rustc_ast::token; |
| 7 | 7 | use rustc_errors::Applicability; |
| ... | ... | @@ -207,7 +207,9 @@ pub struct LiteralDigitGrouping { |
| 207 | 207 | |
| 208 | 208 | impl EarlyLintPass for LiteralDigitGrouping { |
| 209 | 209 | fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { |
| 210 | // `NumericLiteral::from_lit_kind` only accepts integer and float literals. | |
| 210 | 211 | if let ExprKind::Lit(lit) = expr.kind |
| 212 | && matches!(lit.kind, token::LitKind::Integer | token::LitKind::Float) | |
| 211 | 213 | && !expr.span.in_external_macro(cx.sess().source_map()) |
| 212 | 214 | { |
| 213 | 215 | self.check_lit(cx, lit, expr.span); |
| ... | ... | @@ -226,7 +228,7 @@ impl LiteralDigitGrouping { |
| 226 | 228 | } |
| 227 | 229 | |
| 228 | 230 | fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { |
| 229 | if let Some(src) = span.get_source_text(cx) | |
| 231 | if let Some(src) = span.get_text(cx) | |
| 230 | 232 | && let Ok(lit_kind) = LitKind::from_token_lit(lit) |
| 231 | 233 | && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) |
| 232 | 234 | { |
| ... | ... | @@ -418,7 +420,9 @@ pub struct DecimalLiteralRepresentation { |
| 418 | 420 | |
| 419 | 421 | impl EarlyLintPass for DecimalLiteralRepresentation { |
| 420 | 422 | fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { |
| 423 | // Only integer tokens can produce `LitKind::Int`. | |
| 421 | 424 | if let ExprKind::Lit(lit) = expr.kind |
| 425 | && lit.kind == token::LitKind::Integer | |
| 422 | 426 | && !expr.span.in_external_macro(cx.sess().source_map()) |
| 423 | 427 | { |
| 424 | 428 | self.check_lit(cx, lit, expr.span); |
| ... | ... | @@ -436,10 +440,10 @@ impl DecimalLiteralRepresentation { |
| 436 | 440 | // Lint integral literals. |
| 437 | 441 | if let Ok(lit_kind) = LitKind::from_token_lit(lit) |
| 438 | 442 | && let LitKind::Int(val, _) = lit_kind |
| 439 | && let Some(src) = span.get_source_text(cx) | |
| 443 | && val >= u128::from(self.threshold) | |
| 444 | && let Some(src) = span.get_text(cx) | |
| 440 | 445 | && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) |
| 441 | 446 | && num_lit.radix == Radix::Decimal |
| 442 | && val >= u128::from(self.threshold) | |
| 443 | 447 | { |
| 444 | 448 | let hex = format!("{val:#X}"); |
| 445 | 449 | let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); |
src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs+2-2| ... | ... | @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr |
| 48 | 48 | && let PatKind::Binding(_, binding_id, ..) = pat.kind |
| 49 | 49 | { |
| 50 | 50 | // Destructured iterator element `(idx, _)`, look for uses of the binding |
| 51 | for_each_expr(cx, body, |expr| { | |
| 51 | for_each_expr(cx.tcx, body, |expr| { | |
| 52 | 52 | if expr.res_local_id() == Some(binding_id) { |
| 53 | 53 | check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv); |
| 54 | 54 | } |
| ... | ... | @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr |
| 56 | 56 | }); |
| 57 | 57 | } else if let PatKind::Binding(_, binding_id, ..) = pat.kind { |
| 58 | 58 | // Bound as a tuple, look for `tup.0` |
| 59 | for_each_expr(cx, body, |expr| { | |
| 59 | for_each_expr(cx.tcx, body, |expr| { | |
| 60 | 60 | if let ExprKind::Field(e, field) = expr.kind |
| 61 | 61 | && e.res_local_id() == Some(binding_id) |
| 62 | 62 | && field.name == sym::integer(0) |
src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs+19| ... | ... | @@ -13,6 +13,7 @@ use rustc_hir::QPath::Resolved; |
| 13 | 13 | use rustc_hir::def::Res; |
| 14 | 14 | use rustc_hir::{Expr, ExprKind, Pat}; |
| 15 | 15 | use rustc_lint::LateContext; |
| 16 | use rustc_middle::ty; | |
| 16 | 17 | use rustc_span::{Spanned, sym}; |
| 17 | 18 | |
| 18 | 19 | use super::MANUAL_SLICE_FILL; |
| ... | ... | @@ -84,6 +85,24 @@ pub(super) fn check<'tcx>( |
| 84 | 85 | { |
| 85 | 86 | sugg(cx, body, expr, recv_path.span, assignval.span); |
| 86 | 87 | } |
| 88 | // `for slot in s { *slot = value; }` where `s` is already `&mut [T; N]` | |
| 89 | else if let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind | |
| 90 | && let ExprKind::Unary(UnOp::Deref, slice_iter) = assignee.kind | |
| 91 | && let ExprKind::Path(Resolved(_, slice_path)) = slice_iter.kind | |
| 92 | && let Res::Local(local) = slice_path.res | |
| 93 | && local == pat.hir_id | |
| 94 | && !assignval.span.from_expansion() | |
| 95 | && switch_to_eager_eval(cx, assignval) | |
| 96 | && !is_local_used(cx, assignval, local) | |
| 97 | && let arg_ty = cx.typeck_results().expr_ty(arg) | |
| 98 | && let ty::Ref(_, inner_ty, rustc_ast::Mutability::Mut) = arg_ty.kind() | |
| 99 | && is_slice_like(cx, *inner_ty) | |
| 100 | && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() | |
| 101 | && implements_trait(cx, *inner_ty, clone_trait, &[]) | |
| 102 | && msrv.meets(cx, msrvs::SLICE_FILL) | |
| 103 | { | |
| 104 | sugg(cx, body, expr, arg.span, assignval.span); | |
| 105 | } | |
| 87 | 106 | } |
| 88 | 107 | |
| 89 | 108 | fn sugg<'tcx>( |
src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use super::UNUSED_ENUMERATE_INDEX; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_hir_and_then; |
| 3 | 3 | use clippy_utils::res::MaybeDef; |
| 4 | use clippy_utils::source::{SpanRangeExt, walk_span_to_context}; | |
| 4 | use clippy_utils::source::{SpanExt, walk_span_to_context}; | |
| 5 | 5 | use clippy_utils::{expr_or_init, pat_is_wild, sym}; |
| 6 | 6 | use rustc_errors::Applicability; |
| 7 | 7 | use rustc_hir::{Closure, Expr, ExprKind, Pat, PatKind, TyKind}; |
src/tools/clippy/clippy_lints/src/manual_async_fn.rs+4-4| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block}; | |
| 2 | use clippy_utils::source::{SpanExt, position_before_rarrow, snippet_block}; | |
| 3 | 3 | use rustc_errors::Applicability; |
| 4 | 4 | use rustc_hir::intravisit::FnKind; |
| 5 | 5 | use rustc_hir::{ |
| ... | ... | @@ -76,8 +76,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { |
| 76 | 76 | "this function can be simplified using the `async fn` syntax", |
| 77 | 77 | |diag| { |
| 78 | 78 | if let Some(vis_span) = vis_span_opt |
| 79 | && let Some(vis_snip) = vis_span.get_source_text(cx) | |
| 80 | && let Some(header_snip) = header_span.get_source_text(cx) | |
| 79 | && let Some(vis_snip) = vis_span.get_text(cx) | |
| 80 | && let Some(header_snip) = header_span.get_text(cx) | |
| 81 | 81 | && let Some(ret_pos) = position_before_rarrow(&header_snip) |
| 82 | 82 | && let Some((_, ret_snip)) = suggested_ret(cx, output) |
| 83 | 83 | { |
| ... | ... | @@ -185,6 +185,6 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, |
| 185 | 185 | Some((sugg, String::new())) |
| 186 | 186 | } else { |
| 187 | 187 | let sugg = "return the output of the future directly"; |
| 188 | output.span.get_source_text(cx).map(|src| (sugg, format!(" -> {src}"))) | |
| 188 | output.span.get_text(cx).map(|src| (sugg, format!(" -> {src}"))) | |
| 189 | 189 | } |
| 190 | 190 | } |
src/tools/clippy/clippy_lints/src/manual_clamp.rs+29-9| ... | ... | @@ -140,7 +140,13 @@ struct InputMinMax<'tcx> { |
| 140 | 140 | |
| 141 | 141 | impl<'tcx> LateLintPass<'tcx> for ManualClamp { |
| 142 | 142 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { |
| 143 | if !expr.span.from_expansion() && !is_in_const_context(cx) { | |
| 143 | // Cheap kind check before the costlier const context query. | |
| 144 | if matches!( | |
| 145 | expr.kind, | |
| 146 | ExprKind::If(..) | ExprKind::Match(..) | ExprKind::MethodCall(..) | ExprKind::Call(..) | |
| 147 | ) && !expr.span.from_expansion() | |
| 148 | && !is_in_const_context(cx) | |
| 149 | { | |
| 144 | 150 | let suggestion = is_if_elseif_else_pattern(cx, expr) |
| 145 | 151 | .or_else(|| is_max_min_pattern(cx, expr)) |
| 146 | 152 | .or_else(|| is_call_max_min_pattern(cx, expr)) |
| ... | ... | @@ -155,6 +161,15 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { |
| 155 | 161 | } |
| 156 | 162 | |
| 157 | 163 | fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { |
| 164 | // Cheap `if`-statement check before the costlier const context query. | |
| 165 | if !block | |
| 166 | .stmts | |
| 167 | .iter() | |
| 168 | .any(|stmt| matches!(stmt.kind, StmtKind::Expr(e) if matches!(e.kind, ExprKind::If(..)))) | |
| 169 | { | |
| 170 | return; | |
| 171 | } | |
| 172 | ||
| 158 | 173 | if is_in_const_context(cx) || !self.msrv.meets(cx, msrvs::CLAMP) { |
| 159 | 174 | return; |
| 160 | 175 | } |
| ... | ... | @@ -293,18 +308,19 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx |
| 293 | 308 | /// ``` |
| 294 | 309 | fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> { |
| 295 | 310 | if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = expr.kind |
| 311 | && let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind | |
| 312 | // Match method names before the costlier type queries. | |
| 313 | && let Some((min, max)) = match (seg_first.ident.name, seg_second.ident.name) { | |
| 314 | (sym::min, sym::max) => Some((arg_second, arg_first)), | |
| 315 | (sym::max, sym::min) => Some((arg_first, arg_second)), | |
| 316 | _ => None, | |
| 317 | } | |
| 296 | 318 | && (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point() |
| 297 | 319 | || cx.ty_based_def(expr).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord)) |
| 298 | && let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind | |
| 299 | 320 | && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() |
| 300 | 321 | || cx.ty_based_def(receiver).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord)) |
| 301 | 322 | { |
| 302 | 323 | let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point(); |
| 303 | let (min, max) = match (seg_first.ident.name, seg_second.ident.name) { | |
| 304 | (sym::min, sym::max) => (arg_second, arg_first), | |
| 305 | (sym::max, sym::min) => (arg_first, arg_second), | |
| 306 | _ => return None, | |
| 307 | }; | |
| 308 | 324 | Some(ClampSuggestion { |
| 309 | 325 | params: InputMinMax { |
| 310 | 326 | input, |
| ... | ... | @@ -367,12 +383,16 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) |
| 367 | 383 | && let Some(inner_seg) = segment(cx, inner_fn) |
| 368 | 384 | && let Some(outer_seg) = segment(cx, outer_fn) |
| 369 | 385 | { |
| 370 | let (input, inner_arg) = match (is_const_evaluatable(cx, first), is_const_evaluatable(cx, second)) { | |
| 386 | let typeck = cx.typeck_results(); | |
| 387 | let (input, inner_arg) = match ( | |
| 388 | is_const_evaluatable(cx.tcx, typeck, first), | |
| 389 | is_const_evaluatable(cx.tcx, typeck, second), | |
| 390 | ) { | |
| 371 | 391 | (true, false) => (second, first), |
| 372 | 392 | (false, true) => (first, second), |
| 373 | 393 | _ => return None, |
| 374 | 394 | }; |
| 375 | let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point(); | |
| 395 | let is_float = typeck.expr_ty_adjusted(input).is_floating_point(); | |
| 376 | 396 | let (min, max) = match (inner_seg, outer_seg) { |
| 377 | 397 | (FunctionType::CmpMin, FunctionType::CmpMax) => (outer_arg, inner_arg), |
| 378 | 398 | (FunctionType::CmpMax, FunctionType::CmpMin) => (inner_arg, outer_arg), |
src/tools/clippy/clippy_lints/src/manual_float_methods.rs+2-2| ... | ... | @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; |
| 4 | 4 | use clippy_utils::is_from_proc_macro; |
| 5 | 5 | use clippy_utils::msrvs::{self, Msrv}; |
| 6 | 6 | use clippy_utils::res::MaybeResPath; |
| 7 | use clippy_utils::source::SpanRangeExt; | |
| 7 | use clippy_utils::source::SpanExt; | |
| 8 | 8 | use rustc_errors::Applicability; |
| 9 | 9 | use rustc_hir::def::DefKind; |
| 10 | 10 | use rustc_hir::def_id::DefId; |
| ... | ... | @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { |
| 157 | 157 | // case somebody does that for some reason |
| 158 | 158 | && (const_1.is_pos_infinity() && const_2.is_neg_infinity() |
| 159 | 159 | || const_1.is_neg_infinity() && const_2.is_pos_infinity()) |
| 160 | && let Some(local_snippet) = first.span.get_source_text(cx) | |
| 160 | && let Some(local_snippet) = first.span.get_text(cx) | |
| 161 | 161 | { |
| 162 | 162 | let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { |
| 163 | 163 | (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, |
src/tools/clippy/clippy_lints/src/manual_hash_one.rs+3-3| ... | ... | @@ -2,7 +2,7 @@ use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_hir_and_then; |
| 3 | 3 | use clippy_utils::msrvs::{self, Msrv}; |
| 4 | 4 | use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes}; |
| 5 | use clippy_utils::source::SpanRangeExt; | |
| 5 | use clippy_utils::source::SpanExt; | |
| 6 | 6 | use clippy_utils::sym; |
| 7 | 7 | use clippy_utils::visitors::{is_local_used, local_used_once}; |
| 8 | 8 | use rustc_errors::Applicability; |
| ... | ... | @@ -105,8 +105,8 @@ impl LateLintPass<'_> for ManualHashOne { |
| 105 | 105 | finish_expr.span, |
| 106 | 106 | "manual implementation of `BuildHasher::hash_one`", |
| 107 | 107 | |diag| { |
| 108 | if let Some(build_hasher) = build_hasher.span.get_source_text(cx) | |
| 109 | && let Some(hashed_value) = hashed_value.span.get_source_text(cx) | |
| 108 | if let Some(build_hasher) = build_hasher.span.get_text(cx) | |
| 109 | && let Some(hashed_value) = hashed_value.span.get_text(cx) | |
| 110 | 110 | { |
| 111 | 111 | diag.multipart_suggestion( |
| 112 | 112 | "try", |
src/tools/clippy/clippy_lints/src/manual_range_patterns.rs+3-3| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use rustc_ast::LitKind; |
| 4 | 4 | use rustc_data_structures::fx::FxHashSet; |
| 5 | 5 | use rustc_errors::Applicability; |
| ... | ... | @@ -143,8 +143,8 @@ impl LateLintPass<'_> for ManualRangePatterns { |
| 143 | 143 | pat.span, |
| 144 | 144 | "this OR pattern can be rewritten using a range", |
| 145 | 145 | |diag| { |
| 146 | if let Some(min) = min.span.get_source_text(cx) | |
| 147 | && let Some(max) = max.span.get_source_text(cx) | |
| 146 | if let Some(min) = min.span.get_text(cx) | |
| 147 | && let Some(max) = max.span.get_text(cx) | |
| 148 | 148 | { |
| 149 | 149 | diag.span_suggestion( |
| 150 | 150 | pat.span, |
src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs+1-1| ... | ... | @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; |
| 2 | 2 | use clippy_utils::higher::{If, IfLetOrMatch}; |
| 3 | 3 | use clippy_utils::msrvs::Msrv; |
| 4 | 4 | use clippy_utils::res::{MaybeDef, MaybeResPath}; |
| 5 | use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; | |
| 5 | use clippy_utils::source::{IntoSpan, SpanExt, snippet}; | |
| 6 | 6 | use clippy_utils::usage::mutated_variables; |
| 7 | 7 | use clippy_utils::visitors::is_local_used; |
| 8 | 8 | use clippy_utils::{SpanlessEq, get_ref_operators, is_unit_expr, peel_blocks_with_stmt, peel_ref_operators}; |
src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::consts::ConstEvalCtxt; |
| 2 | 2 | use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; |
| 3 | use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline}; | |
| 3 | use clippy_utils::source::{SpanExt as _, indent_of, reindent_multiline}; | |
| 4 | 4 | use rustc_ast::{BindingMode, ByRef}; |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::def::Res; |
| ... | ... | @@ -160,7 +160,7 @@ fn handle( |
| 160 | 160 | ); |
| 161 | 161 | } else if let Some(ty_name) = find_type_name(cx, cx.typeck_results().expr_ty(condition)) |
| 162 | 162 | && cx.typeck_results().expr_adjustments(body_some).is_empty() |
| 163 | && let Some(or_body_snippet) = peel_blocks(body_none).span.get_source_text(cx) | |
| 163 | && let Some(or_body_snippet) = peel_blocks(body_none).span.get_text(cx) | |
| 164 | 164 | && let Some(indent) = indent_of(cx, expr.span) |
| 165 | 165 | && ConstEvalCtxt::new(cx).eval_local(body_none, expr.span.ctxt()).is_some() |
| 166 | 166 | { |
src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::res::MaybeResPath; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::{SpanlessEq, fulfill_or_allowed, hash_expr, is_lint_allowed, search_same}; |
| 5 | 5 | use core::cmp::Ordering; |
| 6 | 6 | use core::{iter, slice}; |
| ... | ... | @@ -152,7 +152,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { |
| 152 | 152 | if let Some(((_, dest), src)) = split |
| 153 | 153 | && let Some(pat_snippets) = group |
| 154 | 154 | .iter() |
| 155 | .map(|(_, arm)| arm.pat.span.get_source_text(cx)) | |
| 155 | .map(|(_, arm)| arm.pat.span.get_text(cx)) | |
| 156 | 156 | .collect::<Option<Vec<_>>>() |
| 157 | 157 | { |
| 158 | 158 | let suggs = src |
src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; |
| 2 | 2 | use clippy_utils::res::MaybeDef; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns}; |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::def::{CtorKind, DefKind, Res}; |
| ... | ... | @@ -119,7 +119,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { |
| 119 | 119 | wildcard_ident.map_or(String::new(), |ident| { |
| 120 | 120 | ident |
| 121 | 121 | .span |
| 122 | .get_source_text(cx) | |
| 122 | .get_text(cx) | |
| 123 | 123 | .map_or_else(|| format!("{} @ ", ident.name), |s| format!("{s} @ ")) |
| 124 | 124 | }), |
| 125 | 125 | if let CommonPrefixSearcher::Path(path_prefix) = path_prefix { |
src/tools/clippy/clippy_lints/src/matches/mod.rs+75-83| ... | ... | @@ -26,14 +26,15 @@ mod wild_in_or_pats; |
| 26 | 26 | |
| 27 | 27 | use clippy_config::Conf; |
| 28 | 28 | use clippy_utils::msrvs::{self, Msrv}; |
| 29 | use clippy_utils::source::walk_span_to_context; | |
| 29 | use clippy_utils::source::SpanExt; | |
| 30 | 30 | use clippy_utils::{ |
| 31 | higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, sym, | |
| 31 | higher, is_direct_expn_of, is_in_const_context, is_lint_allowed, is_span_match, sym, tokenize_with_text, | |
| 32 | 32 | }; |
| 33 | 33 | use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; |
| 34 | use rustc_lexer::{TokenKind, is_whitespace}; | |
| 34 | 35 | use rustc_lint::{LateContext, LateLintPass, LintContext}; |
| 35 | 36 | use rustc_session::impl_lint_pass; |
| 36 | use rustc_span::{SpanData, SyntaxContext}; | |
| 37 | use rustc_span::Span; | |
| 37 | 38 | |
| 38 | 39 | declare_clippy_lint! { |
| 39 | 40 | /// ### What it does |
| ... | ... | @@ -1084,34 +1085,38 @@ impl<'tcx> LateLintPass<'tcx> for Matches { |
| 1084 | 1085 | try_err::check(cx, expr, ex); |
| 1085 | 1086 | } |
| 1086 | 1087 | |
| 1087 | if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) { | |
| 1088 | if !from_expansion | |
| 1089 | && let mut has_cfg = false | |
| 1090 | && let mut has_comments = false | |
| 1091 | && walk_intra_arm_text(cx, expr.span, ex.span, arms, |s| { | |
| 1092 | let mut iter = tokenize_with_text(s).filter(|(t, ..)| match t { | |
| 1093 | TokenKind::Whitespace => false, | |
| 1094 | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } => { | |
| 1095 | has_comments = true; | |
| 1096 | false | |
| 1097 | }, | |
| 1098 | _ => true, | |
| 1099 | }); | |
| 1100 | while let Some((t, ..)) = iter.next() { | |
| 1101 | if matches!(t, TokenKind::Pound) | |
| 1102 | && matches!(iter.next(), Some((TokenKind::OpenBracket, ..))) | |
| 1103 | && matches!(iter.next(), Some((TokenKind::Ident, "cfg", _))) | |
| 1104 | { | |
| 1105 | has_cfg = true; | |
| 1106 | } | |
| 1107 | } | |
| 1108 | }) | |
| 1109 | && !has_cfg | |
| 1110 | { | |
| 1088 | 1111 | if source == MatchSource::Normal { |
| 1089 | if !(self.msrv.meets(cx, msrvs::MATCHES_MACRO) | |
| 1090 | && match_like_matches::check_match(cx, expr, ex, arms)) | |
| 1091 | { | |
| 1112 | let is_match_like_matches = self.msrv.meets(cx, msrvs::MATCHES_MACRO) | |
| 1113 | && match_like_matches::check_match(cx, expr, ex, arms); | |
| 1114 | if !(is_match_like_matches || is_lint_allowed(cx, MATCH_SAME_ARMS, expr.hir_id)) { | |
| 1092 | 1115 | match_same_arms::check(cx, arms); |
| 1093 | 1116 | } |
| 1094 | 1117 | |
| 1095 | 1118 | redundant_pattern_match::check_match(cx, expr, ex, arms); |
| 1096 | let mut match_comments = span_extract_comments(cx, expr.span); | |
| 1097 | // We remove comments from inside arms block. | |
| 1098 | if !match_comments.is_empty() { | |
| 1099 | for arm in arms { | |
| 1100 | for comment in span_extract_comments(cx, arm.body.span) { | |
| 1101 | if let Some(index) = match_comments | |
| 1102 | .iter() | |
| 1103 | .enumerate() | |
| 1104 | .find(|(_, cm)| **cm == comment) | |
| 1105 | .map(|(index, _)| index) | |
| 1106 | { | |
| 1107 | match_comments.remove(index); | |
| 1108 | } | |
| 1109 | } | |
| 1110 | } | |
| 1111 | } | |
| 1112 | // If there are still comments, it means they are outside of the arms. Tell the lint | |
| 1113 | // code about it. | |
| 1114 | single_match::check(cx, ex, arms, expr, !match_comments.is_empty()); | |
| 1119 | single_match::check(cx, ex, arms, expr, has_comments); | |
| 1115 | 1120 | match_bool::check(cx, ex, arms, expr); |
| 1116 | 1121 | overlapping_arms::check(cx, ex, arms); |
| 1117 | 1122 | match_wild_enum::check(cx, ex, arms); |
| ... | ... | @@ -1216,64 +1221,51 @@ impl<'tcx> LateLintPass<'tcx> for Matches { |
| 1216 | 1221 | } |
| 1217 | 1222 | } |
| 1218 | 1223 | |
| 1219 | /// Checks if there are any arms with a `#[cfg(..)]` attribute. | |
| 1220 | fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]) -> bool { | |
| 1221 | let Some(scrutinee_span) = walk_span_to_context(scrutinee.span, SyntaxContext::root()) else { | |
| 1222 | // Shouldn't happen, but treat this as though a `cfg` attribute were found | |
| 1223 | return true; | |
| 1224 | }; | |
| 1225 | ||
| 1226 | let start = scrutinee_span.hi(); | |
| 1227 | let mut arm_spans = arms.iter().map(|arm| { | |
| 1228 | let data = arm.span.data(); | |
| 1229 | (data.ctxt == SyntaxContext::root()).then_some((data.lo, data.hi)) | |
| 1230 | }); | |
| 1231 | let end = e.span.hi(); | |
| 1232 | ||
| 1233 | // Walk through all the non-code space before each match arm. The space trailing the final arm is | |
| 1234 | // handled after the `try_fold` e.g. | |
| 1235 | // | |
| 1236 | // match foo { | |
| 1237 | // _________^- everything between the scrutinee and arm1 | |
| 1238 | //| arm1 => (), | |
| 1239 | //|---^___________^ everything before arm2 | |
| 1240 | //| #[cfg(feature = "enabled")] | |
| 1241 | //| arm2 => some_code(), | |
| 1242 | //|---^____________________^ everything before arm3 | |
| 1243 | //| // some comment about arm3 | |
| 1244 | //| arm3 => some_code(), | |
| 1245 | //|---^____________________^ everything after arm3 | |
| 1246 | //| #[cfg(feature = "disabled")] | |
| 1247 | //| arm4 = some_code(), | |
| 1248 | //|}; | |
| 1249 | //|^ | |
| 1250 | let found = arm_spans.try_fold(start, |start, range| { | |
| 1251 | let Some((end, next_start)) = range else { | |
| 1252 | // Shouldn't happen as macros can't expand to match arms, but treat this as though a `cfg` attribute | |
| 1253 | // were found. | |
| 1254 | return Err(()); | |
| 1255 | }; | |
| 1256 | let span = SpanData { | |
| 1257 | lo: start, | |
| 1258 | hi: end, | |
| 1259 | ctxt: SyntaxContext::root(), | |
| 1260 | parent: None, | |
| 1261 | } | |
| 1262 | .span(); | |
| 1263 | (!span_contains_cfg(cx, span)).then_some(next_start).ok_or(()) | |
| 1264 | }); | |
| 1265 | match found { | |
| 1266 | Ok(start) => { | |
| 1267 | let span = SpanData { | |
| 1268 | lo: start, | |
| 1269 | hi: end, | |
| 1270 | ctxt: SyntaxContext::root(), | |
| 1271 | parent: None, | |
| 1224 | /// Calls the given function for each segment of the source text within the | |
| 1225 | /// match block which is not part of any arm. For the purposes of this function | |
| 1226 | /// attributes on an arm are not considered part of the arm. | |
| 1227 | /// | |
| 1228 | /// This will return whether all the relevant source text could be retrieved. If | |
| 1229 | /// all the source text cannot be retrieved it should be assumed that the match | |
| 1230 | /// originates from a macro. | |
| 1231 | #[must_use] | |
| 1232 | fn walk_intra_arm_text( | |
| 1233 | cx: &LateContext<'_>, | |
| 1234 | match_sp: Span, | |
| 1235 | scrutinee_sp: Span, | |
| 1236 | arms: &[Arm<'_>], | |
| 1237 | mut f: impl FnMut(&str), | |
| 1238 | ) -> bool { | |
| 1239 | if let Some(src) = match_sp.get_source_range(cx) | |
| 1240 | && let scrutinee_sp = scrutinee_sp.source_callsite().data() | |
| 1241 | && let block_start = (scrutinee_sp.hi.0 - src.sf.start_pos.0) as usize | |
| 1242 | && let Some(src_text) = src.sf.src.as_ref().map(|x| &***x) | |
| 1243 | && let Some(block_text) = src_text.get(block_start..src.range.end) | |
| 1244 | && let Some(stripped_text) = block_text.trim_start_matches(is_whitespace).strip_prefix('{') | |
| 1245 | && let arms_start = block_start + (block_text.len() - stripped_text.len()) | |
| 1246 | && let Some(arms_end) = stripped_text | |
| 1247 | .trim_end_matches(|c| is_whitespace(c) || c == ')') | |
| 1248 | .strip_suffix('}') | |
| 1249 | .map(|s| src.range.end - (stripped_text.len() - s.len())) | |
| 1250 | && let Some(range) = arms.iter().try_fold(arms_start..arms_end, |range, arm| { | |
| 1251 | let arm_sp: rustc_span::SpanData = arm.span.source_callsite().data(); | |
| 1252 | let arm_range = (arm_sp.lo.0 - src.sf.start_pos.0) as usize..(arm_sp.hi.0 - src.sf.start_pos.0) as usize; | |
| 1253 | if range.start <= arm_range.start | |
| 1254 | && arm_range.end <= range.end | |
| 1255 | && let Some(src) = src_text.get(range.start..arm_range.start) | |
| 1256 | { | |
| 1257 | f(src); | |
| 1258 | Some(arm_range.end..range.end) | |
| 1259 | } else { | |
| 1260 | None | |
| 1272 | 1261 | } |
| 1273 | .span(); | |
| 1274 | span_contains_cfg(cx, span) | |
| 1275 | }, | |
| 1276 | Err(()) => true, | |
| 1262 | }) | |
| 1263 | && let Some(src) = src_text.get(range) | |
| 1264 | { | |
| 1265 | f(src); | |
| 1266 | true | |
| 1267 | } else { | |
| 1268 | false | |
| 1277 | 1269 | } |
| 1278 | 1270 | } |
| 1279 | 1271 |
src/tools/clippy/clippy_lints/src/matches/single_match.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::source::{ |
| 3 | SpanRangeExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, | |
| 3 | SpanExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, | |
| 4 | 4 | }; |
| 5 | 5 | use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs}; |
| 6 | 6 | use clippy_utils::{is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, sym}; |
| ... | ... | @@ -22,7 +22,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; |
| 22 | 22 | /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty |
| 23 | 23 | /// match arms. |
| 24 | 24 | fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { |
| 25 | span.check_source_text(cx, |text| text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")) | |
| 25 | span.check_text(cx, |text| text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")) | |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | pub(crate) fn check<'tcx>( |
src/tools/clippy/clippy_lints/src/methods/by_ref_peekable_peek.rs created+84| ... | ... | @@ -0,0 +1,84 @@ |
| 1 | use crate::clippy_utils::res::MaybeTypeckRes; | |
| 2 | use clippy_utils::diagnostics::span_lint_and_then; | |
| 3 | use clippy_utils::res::{MaybeDef, MaybeResPath as _}; | |
| 4 | use clippy_utils::sugg::Sugg; | |
| 5 | use clippy_utils::sym; | |
| 6 | use clippy_utils::ty::implements_trait; | |
| 7 | use rustc_ast::BindingMode; | |
| 8 | use rustc_errors::Applicability; | |
| 9 | use rustc_hir::{Expr, ExprKind, LetStmt, Node, PatKind}; | |
| 10 | use rustc_lint::LateContext; | |
| 11 | use rustc_middle::ty; | |
| 12 | ||
| 13 | use super::BY_REF_PEEKABLE_PEEK; | |
| 14 | ||
| 15 | pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>) { | |
| 16 | if let ExprKind::MethodCall(maybe_peekable, peekable_recv, [], _) = recv.kind | |
| 17 | && maybe_peekable.ident.name == sym::peekable | |
| 18 | && !peekable_recv.span.from_expansion() | |
| 19 | && let ExprKind::MethodCall(maybe_by_ref, by_ref_recv, [], _) = peekable_recv.kind | |
| 20 | && maybe_by_ref.ident.name == sym::by_ref | |
| 21 | && !by_ref_recv.span.from_expansion() | |
| 22 | && [peekable_recv, recv] | |
| 23 | .into_iter() | |
| 24 | .all(|e| cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Iterator)) | |
| 25 | { | |
| 26 | span_lint_and_then( | |
| 27 | cx, | |
| 28 | BY_REF_PEEKABLE_PEEK, | |
| 29 | expr.span, | |
| 30 | "calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output", | |
| 31 | |diag| { | |
| 32 | let span = by_ref_recv.span.shrink_to_hi().with_hi(expr.span.hi()); | |
| 33 | if let ty::Ref(_, iter_ty, _) = cx.typeck_results().expr_ty_adjusted(by_ref_recv).kind() | |
| 34 | && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() | |
| 35 | && implements_trait(cx, *iter_ty, clone_trait, &[]) | |
| 36 | { | |
| 37 | diag.span_suggestion_verbose( | |
| 38 | span, | |
| 39 | "to peek the first item without advancing the underlying iterator, use", | |
| 40 | ".clone().next().as_ref()", | |
| 41 | Applicability::MaybeIncorrect, | |
| 42 | ); | |
| 43 | } | |
| 44 | diag.span_suggestion_verbose( | |
| 45 | span, | |
| 46 | "to advance the underlying iterator, use", | |
| 47 | ".next().as_ref()", | |
| 48 | Applicability::MaybeIncorrect, | |
| 49 | ); | |
| 50 | // If the iterator is a local variable, initialized through a simple binding with an inferred | |
| 51 | // initialization expression, suggest making the initialization expression peekable. | |
| 52 | if let Some(iter_local_id) = by_ref_recv.res_local_id() | |
| 53 | && let Node::LetStmt(LetStmt { | |
| 54 | pat: let_pat, | |
| 55 | ty: None, | |
| 56 | init: Some(init_expr), | |
| 57 | els: None, | |
| 58 | span: let_stmt_span, | |
| 59 | .. | |
| 60 | }) = cx.tcx.parent_hir_node(iter_local_id) | |
| 61 | && let PatKind::Binding(BindingMode::MUT, _, _, None) = let_pat.kind | |
| 62 | && !let_stmt_span.from_expansion() | |
| 63 | // Changing the type of the iterator may prevent the code from compiling | |
| 64 | && let mut app = Applicability::MaybeIncorrect | |
| 65 | && let sugg = | |
| 66 | Sugg::hir_with_context(cx, init_expr, let_stmt_span.ctxt(), "_", &mut app).maybe_paren() | |
| 67 | { | |
| 68 | diag.multipart_suggestion( | |
| 69 | "to make the iterator peekable, use", | |
| 70 | vec![ | |
| 71 | (init_expr.span.source_callsite(), format!("{sugg}.peekable()")), | |
| 72 | (recv.span.with_lo(by_ref_recv.span.hi()), String::new()), | |
| 73 | ], | |
| 74 | app, | |
| 75 | ); | |
| 76 | } else { | |
| 77 | diag.help( | |
| 78 | "you might want to transform the iterator itself using `.peekable()` without using `.by_ref()`", | |
| 79 | ); | |
| 80 | } | |
| 81 | }, | |
| 82 | ); | |
| 83 | } | |
| 84 | } |
src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::msrvs::{self, Msrv}; |
| 3 | 3 | use clippy_utils::res::MaybeDef; |
| 4 | use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; | |
| 4 | use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; | |
| 5 | 5 | use clippy_utils::sym; |
| 6 | 6 | use rustc_ast::ast::LitKind; |
| 7 | 7 | use rustc_errors::Applicability; |
| ... | ... | @@ -51,7 +51,7 @@ pub(super) fn check<'tcx>( |
| 51 | 51 | "case-sensitive file extension comparison", |
| 52 | 52 | |diag| { |
| 53 | 53 | diag.help("consider using a case-insensitive comparison instead"); |
| 54 | if let Some(recv_source) = recv.span.get_source_text(cx) { | |
| 54 | if let Some(recv_source) = recv.span.get_text(cx) { | |
| 55 | 55 | let recv_source = if cx.typeck_results().expr_ty(recv).is_ref() { |
| 56 | 56 | recv_source.to_owned() |
| 57 | 57 | } else { |
src/tools/clippy/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs created+104| ... | ... | @@ -0,0 +1,104 @@ |
| 1 | use super::CHUNKS_EXACT_TO_AS_CHUNKS; | |
| 2 | use clippy_utils::diagnostics::span_lint_and_then; | |
| 3 | use clippy_utils::msrvs::{self, Msrv}; | |
| 4 | use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; | |
| 5 | use clippy_utils::source::snippet_with_context; | |
| 6 | use clippy_utils::visitors::is_const_evaluatable; | |
| 7 | use clippy_utils::{get_expr_use_site, sym}; | |
| 8 | use rustc_errors::Applicability; | |
| 9 | use rustc_hir::{Expr, ExprKind, Node, PatKind}; | |
| 10 | use rustc_lint::LateContext; | |
| 11 | use rustc_middle::ty; | |
| 12 | use rustc_span::{DesugaringKind, ExpnKind, Span, Symbol}; | |
| 13 | ||
| 14 | pub(super) fn check<'tcx>( | |
| 15 | cx: &LateContext<'tcx>, | |
| 16 | recv: &'tcx Expr<'tcx>, | |
| 17 | arg: &'tcx Expr<'tcx>, | |
| 18 | expr: &'tcx Expr<'tcx>, | |
| 19 | call_span: Span, | |
| 20 | method_name: Symbol, | |
| 21 | msrv: Msrv, | |
| 22 | ) { | |
| 23 | let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); | |
| 24 | if !matches!(recv_ty.kind(), ty::Ref(_, inner, _) if inner.is_slice()) { | |
| 25 | return; | |
| 26 | } | |
| 27 | ||
| 28 | if is_const_evaluatable(cx.tcx, cx.typeck_results(), arg) { | |
| 29 | if !msrv.meets(cx, msrvs::AS_CHUNKS) { | |
| 30 | return; | |
| 31 | } | |
| 32 | ||
| 33 | let use_ctxt = get_expr_use_site(cx.tcx, cx.typeck_results(), expr.span.ctxt(), expr); | |
| 34 | ||
| 35 | if use_ctxt.is_ty_unified { | |
| 36 | return; | |
| 37 | } | |
| 38 | ||
| 39 | let suggestion_method = if method_name == sym::chunks_exact_mut { | |
| 40 | "as_chunks_mut" | |
| 41 | } else { | |
| 42 | "as_chunks" | |
| 43 | }; | |
| 44 | ||
| 45 | let mut applicability = Applicability::MachineApplicable; | |
| 46 | let arg_str = snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut applicability).0; | |
| 47 | ||
| 48 | let as_chunks = format_args!("{suggestion_method}::<{arg_str}>()"); | |
| 49 | ||
| 50 | span_lint_and_then( | |
| 51 | cx, | |
| 52 | CHUNKS_EXACT_TO_AS_CHUNKS, | |
| 53 | call_span, | |
| 54 | format!("using `{method_name}` with a constant chunk size"), | |
| 55 | |diag| { | |
| 56 | if let Node::Expr(use_expr) = use_ctxt.node { | |
| 57 | match use_expr.kind { | |
| 58 | ExprKind::Call(_, [recv]) | ExprKind::MethodCall(_, recv, [], _) | |
| 59 | if recv.hir_id == use_ctxt.child_id | |
| 60 | && matches!( | |
| 61 | use_expr.span.ctxt().outer_expn_data().kind, | |
| 62 | ExpnKind::Desugaring(DesugaringKind::ForLoop), | |
| 63 | ) => | |
| 64 | { | |
| 65 | diag.span_suggestion( | |
| 66 | call_span, | |
| 67 | "consider using `as_chunks` instead", | |
| 68 | format!("{as_chunks}.0"), | |
| 69 | applicability, | |
| 70 | ); | |
| 71 | return; | |
| 72 | }, | |
| 73 | ExprKind::MethodCall(_, recv, ..) | |
| 74 | if recv.hir_id == use_ctxt.child_id | |
| 75 | && cx | |
| 76 | .ty_based_def(use_expr) | |
| 77 | .assoc_fn_parent(cx) | |
| 78 | .is_diag_item(cx, sym::Iterator) => | |
| 79 | { | |
| 80 | diag.span_suggestion( | |
| 81 | call_span, | |
| 82 | "consider using `as_chunks` instead", | |
| 83 | format!("{as_chunks}.0.iter()"), | |
| 84 | applicability, | |
| 85 | ); | |
| 86 | return; | |
| 87 | }, | |
| 88 | _ => {}, | |
| 89 | } | |
| 90 | } | |
| 91 | ||
| 92 | diag.span_help(call_span, format!("consider using `{as_chunks}` instead")); | |
| 93 | ||
| 94 | if let Node::LetStmt(let_stmt) = use_ctxt.node | |
| 95 | && let PatKind::Binding(_, _, ident, _) = let_stmt.pat.kind | |
| 96 | { | |
| 97 | diag.note(format!( | |
| 98 | "you can access the chunks using `{ident}.0.iter()`, and the remainder using `{ident}.1`" | |
| 99 | )); | |
| 100 | } | |
| 101 | }, | |
| 102 | ); | |
| 103 | } | |
| 104 | } |
src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs+4-5| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::res::MaybeDef; | |
| 3 | use clippy_utils::{is_range_full, sym}; | |
| 2 | use clippy_utils::res::{MaybeDef, MaybeResPath}; | |
| 3 | use clippy_utils::{is_full_collection_range, sym}; | |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | use rustc_hir::{Expr, ExprKind, LangItem, QPath}; | |
| 5 | use rustc_hir::{Expr, LangItem}; | |
| 6 | 6 | use rustc_lint::LateContext; |
| 7 | 7 | use rustc_span::Span; |
| 8 | 8 | |
| ... | ... | @@ -16,8 +16,7 @@ const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap, |
| 16 | 16 | pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: Option<&Expr<'_>>) { |
| 17 | 17 | if let Some(arg) = arg { |
| 18 | 18 | if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITH_ARG) |
| 19 | && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind | |
| 20 | && is_range_full(cx, arg, Some(container_path)) | |
| 19 | && is_full_collection_range(cx, recv.res_local_id(), arg) | |
| 21 | 20 | { |
| 22 | 21 | suggest(cx, expr, recv, span); |
| 23 | 22 | } |
src/tools/clippy/clippy_lints/src/methods/drain_collect.rs+20-56| ... | ... | @@ -1,67 +1,31 @@ |
| 1 | 1 | use crate::methods::DRAIN_COLLECT; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 3 | use clippy_utils::res::MaybeDef; | |
| 3 | use clippy_utils::res::{MaybeDef, MaybeResPath}; | |
| 4 | 4 | use clippy_utils::source::snippet; |
| 5 | use clippy_utils::{is_range_full, std_or_core, sym}; | |
| 5 | use clippy_utils::{is_full_collection_range, std_or_core, sym}; | |
| 6 | 6 | use rustc_errors::Applicability; |
| 7 | use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath}; | |
| 7 | use rustc_hir::Expr; | |
| 8 | 8 | use rustc_lint::LateContext; |
| 9 | 9 | use rustc_middle::ty; |
| 10 | use rustc_middle::ty::Ty; | |
| 11 | use rustc_span::Symbol; | |
| 12 | 10 | |
| 13 | /// Checks if both types match the given diagnostic item, e.g.: | |
| 14 | /// | |
| 15 | /// `vec![1,2].drain(..).collect::<Vec<_>>()` | |
| 16 | /// ^^^^^^^^^ ^^^^^^ true | |
| 17 | /// `vec![1,2].drain(..).collect::<HashSet<_>>()` | |
| 18 | /// ^^^^^^^^^ ^^^^^^^^^^ false | |
| 19 | fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool { | |
| 20 | if let Some(expr_adt) = expr.ty_adt_def() | |
| 21 | && let Some(recv_adt) = recv.ty_adt_def() | |
| 22 | { | |
| 23 | cx.tcx.is_diagnostic_item(sym, expr_adt.did()) && cx.tcx.is_diagnostic_item(sym, recv_adt.did()) | |
| 24 | } else { | |
| 25 | false | |
| 26 | } | |
| 27 | } | |
| 28 | ||
| 29 | /// Checks `std::{vec::Vec, collections::VecDeque}`. | |
| 30 | fn check_vec(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { | |
| 31 | (types_match_diagnostic_item(cx, expr, recv, sym::Vec) | |
| 32 | || types_match_diagnostic_item(cx, expr, recv, sym::VecDeque)) | |
| 33 | && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) | |
| 34 | } | |
| 35 | ||
| 36 | /// Checks `std::string::String` | |
| 37 | fn check_string(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { | |
| 38 | expr.is_lang_item(cx, LangItem::String) | |
| 39 | && recv.is_lang_item(cx, LangItem::String) | |
| 40 | && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) | |
| 41 | } | |
| 42 | ||
| 43 | /// Checks `std::collections::{HashSet, HashMap, BinaryHeap}`. | |
| 44 | fn check_collections(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>) -> Option<&'static str> { | |
| 45 | types_match_diagnostic_item(cx, expr, recv, sym::HashSet) | |
| 46 | .then_some("HashSet") | |
| 47 | .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::HashMap).then_some("HashMap")) | |
| 48 | .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::BinaryHeap).then_some("BinaryHeap")) | |
| 49 | } | |
| 50 | ||
| 51 | pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, recv: &Expr<'_>) { | |
| 52 | let expr_ty = cx.typeck_results().expr_ty(expr); | |
| 53 | let recv_ty = cx.typeck_results().expr_ty(recv); | |
| 54 | let recv_ty_no_refs = recv_ty.peel_refs(); | |
| 55 | ||
| 56 | if let ExprKind::Path(QPath::Resolved(_, recv_path)) = recv.kind | |
| 57 | && let Some(typename) = check_vec(cx, args, expr_ty, recv_ty_no_refs, recv_path) | |
| 58 | .then_some("Vec") | |
| 59 | .or_else(|| check_string(cx, args, expr_ty, recv_ty_no_refs, recv_path).then_some("String")) | |
| 60 | .or_else(|| check_collections(cx, expr_ty, recv_ty_no_refs)) | |
| 11 | pub(super) fn check(cx: &LateContext<'_>, arg: Option<&Expr<'_>>, expr: &Expr<'_>, recv: &Expr<'_>) { | |
| 12 | let ty = cx.typeck_results().expr_ty(recv); | |
| 13 | let (is_ref, ty) = match *ty.kind() { | |
| 14 | ty::Ref(_, ty, _) => (true, ty), | |
| 15 | _ => (false, ty), | |
| 16 | }; | |
| 17 | if cx.typeck_results().expr_ty(expr) == ty | |
| 18 | && let Some(did) = ty.opt_def_id() | |
| 19 | && (cx.tcx.lang_items().string() == Some(did) | |
| 20 | || matches!( | |
| 21 | ty.opt_diag_name(cx), | |
| 22 | Some(sym::HashMap | sym::HashSet | sym::BinaryHeap | sym::Vec | sym::VecDeque) | |
| 23 | )) | |
| 24 | && arg.is_none_or(|arg| is_full_collection_range(cx, recv.res_local_id(), arg)) | |
| 61 | 25 | && let Some(exec_context) = std_or_core(cx) |
| 62 | 26 | { |
| 63 | 27 | let recv = snippet(cx, recv.span, "<expr>"); |
| 64 | let sugg = if let ty::Ref(..) = recv_ty.kind() { | |
| 28 | let sugg = if is_ref { | |
| 65 | 29 | format!("{exec_context}::mem::take({recv})") |
| 66 | 30 | } else { |
| 67 | 31 | format!("{exec_context}::mem::take(&mut {recv})") |
| ... | ... | @@ -71,8 +35,8 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re |
| 71 | 35 | cx, |
| 72 | 36 | DRAIN_COLLECT, |
| 73 | 37 | expr.span, |
| 74 | format!("you seem to be trying to move all elements into a new `{typename}`"), | |
| 75 | "consider using `mem::take`", | |
| 38 | "draining all elements of a collection into a new collection of the same type", | |
| 39 | "use `mem::take` to avoid creating a new allocation", | |
| 76 | 40 | sugg, |
| 77 | 41 | Applicability::MachineApplicable, |
| 78 | 42 | ); |
src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs+1-1| ... | ... | @@ -100,7 +100,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Ex |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | 102 | fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool { |
| 103 | for_each_expr(cx, arg, |expr| { | |
| 103 | for_each_expr(cx.tcx, arg, |expr| { | |
| 104 | 104 | if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. }) |
| 105 | 105 | && !is_inside_always_const_context(cx.tcx, expr.hir_id) |
| 106 | 106 | { |
src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use super::FILTER_MAP_BOOL_THEN; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | 3 | use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; |
| 4 | use clippy_utils::source::{SpanRangeExt, snippet_with_context}; | |
| 4 | use clippy_utils::source::{SpanExt, snippet_with_context}; | |
| 5 | 5 | use clippy_utils::ty::is_copy; |
| 6 | 6 | use clippy_utils::{CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, peel_blocks, sym}; |
| 7 | 7 | use rustc_ast::Mutability; |
| ... | ... | @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & |
| 43 | 43 | .iter() |
| 44 | 44 | .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) |
| 45 | 45 | .count() |
| 46 | && let Some(param_snippet) = param.span.get_source_text(cx) | |
| 46 | && let Some(param_snippet) = param.span.get_text(cx) | |
| 47 | 47 | { |
| 48 | 48 | let mut applicability = Applicability::MachineApplicable; |
| 49 | 49 | let (filter, _) = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut applicability); |
src/tools/clippy/clippy_lints/src/methods/filter_next.rs+30-33| ... | ... | @@ -1,15 +1,15 @@ |
| 1 | use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; | |
| 2 | use clippy_utils::source::snippet; | |
| 1 | use clippy_utils::diagnostics::span_lint_and_then; | |
| 2 | use clippy_utils::source::snippet_with_applicability; | |
| 3 | 3 | use clippy_utils::ty::implements_trait; |
| 4 | 4 | use clippy_utils::{path_to_local_with_projections, sym}; |
| 5 | 5 | use rustc_ast::{BindingMode, Mutability}; |
| 6 | 6 | use rustc_errors::Applicability; |
| 7 | use rustc_hir as hir; | |
| 7 | use rustc_hir::{Expr, Node, PatKind}; | |
| 8 | 8 | use rustc_lint::LateContext; |
| 9 | 9 | |
| 10 | 10 | use super::FILTER_NEXT; |
| 11 | 11 | |
| 12 | #[derive(Copy, Clone)] | |
| 12 | #[derive(Clone, Copy)] | |
| 13 | 13 | pub(super) enum Direction { |
| 14 | 14 | Forward, |
| 15 | 15 | Backward, |
| ... | ... | @@ -17,15 +17,13 @@ pub(super) enum Direction { |
| 17 | 17 | |
| 18 | 18 | /// lint use of `filter().next()` for `Iterator` and `filter().next_back()` for |
| 19 | 19 | /// `DoubleEndedIterator` |
| 20 | pub(super) fn check<'tcx>( | |
| 21 | cx: &LateContext<'tcx>, | |
| 22 | expr: &'tcx hir::Expr<'_>, | |
| 23 | recv: &'tcx hir::Expr<'_>, | |
| 24 | filter_arg: &'tcx hir::Expr<'_>, | |
| 20 | pub(super) fn check( | |
| 21 | cx: &LateContext<'_>, | |
| 22 | expr: &Expr<'_>, | |
| 23 | recv: &Expr<'_>, | |
| 24 | filter_arg: &Expr<'_>, | |
| 25 | 25 | direction: Direction, |
| 26 | 26 | ) { |
| 27 | // lint if caller of `.filter().next()` is an Iterator or `.filter().next_back()` is a | |
| 28 | // DoubleEndedIterator | |
| 29 | 27 | let (required_trait, next_method, find_method) = match direction { |
| 30 | 28 | Direction::Forward => (sym::Iterator, "next", "find"), |
| 31 | 29 | Direction::Backward => (sym::DoubleEndedIterator, "next_back", "rfind"), |
| ... | ... | @@ -37,30 +35,31 @@ pub(super) fn check<'tcx>( |
| 37 | 35 | { |
| 38 | 36 | return; |
| 39 | 37 | } |
| 40 | let msg = format!( | |
| 41 | "called `filter(..).{next_method}()` on an `{}`. This is more succinctly expressed by calling \ | |
| 42 | `.{find_method}(..)` instead", | |
| 43 | required_trait.as_str() | |
| 44 | ); | |
| 45 | let filter_snippet = snippet(cx, filter_arg.span, ".."); | |
| 46 | if filter_snippet.lines().count() <= 1 { | |
| 47 | let iter_snippet = snippet(cx, recv.span, ".."); | |
| 48 | // add note if not multi-line | |
| 49 | span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { | |
| 50 | let (applicability, pat) = if let Some(id) = path_to_local_with_projections(recv) | |
| 51 | && let hir::Node::Pat(pat) = cx.tcx.hir_node(id) | |
| 52 | && let hir::PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind | |
| 38 | span_lint_and_then( | |
| 39 | cx, | |
| 40 | FILTER_NEXT, | |
| 41 | expr.span, | |
| 42 | format!("called `filter(..).{next_method}()` on an `{required_trait}`"), | |
| 43 | |diag| { | |
| 44 | let mut app = Applicability::MachineApplicable; | |
| 45 | let filter_snippet = snippet_with_applicability(cx, filter_arg.span, "..", &mut app); | |
| 46 | let iter_snippet = snippet_with_applicability(cx, recv.span, "..", &mut app); | |
| 47 | ||
| 48 | let pat = if let Some(id) = path_to_local_with_projections(recv) | |
| 49 | && let Node::Pat(pat) = cx.tcx.hir_node(id) | |
| 50 | && let PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind | |
| 53 | 51 | { |
| 54 | (Applicability::Unspecified, Some((pat.span, ident))) | |
| 52 | app = Applicability::Unspecified; | |
| 53 | Some((pat.span, ident)) | |
| 55 | 54 | } else { |
| 56 | (Applicability::MachineApplicable, None) | |
| 55 | None | |
| 57 | 56 | }; |
| 58 | 57 | |
| 59 | diag.span_suggestion( | |
| 58 | diag.span_suggestion_verbose( | |
| 60 | 59 | expr.span, |
| 61 | "try", | |
| 60 | format!("use `.{find_method}(..)` instead"), | |
| 62 | 61 | format!("{iter_snippet}.{find_method}({filter_snippet})"), |
| 63 | applicability, | |
| 62 | app, | |
| 64 | 63 | ); |
| 65 | 64 | |
| 66 | 65 | if let Some((pat_span, ident)) = pat { |
| ... | ... | @@ -69,8 +68,6 @@ pub(super) fn check<'tcx>( |
| 69 | 68 | format!("you will also need to make `{ident}` mutable, because `{find_method}` takes `&mut self`"), |
| 70 | 69 | ); |
| 71 | 70 | } |
| 72 | }); | |
| 73 | } else { | |
| 74 | span_lint(cx, FILTER_NEXT, expr.span, msg); | |
| 75 | } | |
| 71 | }, | |
| 72 | ); | |
| 76 | 73 | } |
src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs+4-4| ... | ... | @@ -1,7 +1,8 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::{is_range_full, sym}; | |
| 2 | use clippy_utils::res::MaybeResPath; | |
| 3 | use clippy_utils::{is_full_collection_range, sym}; | |
| 3 | 4 | use rustc_errors::Applicability; |
| 4 | use rustc_hir::{Expr, ExprKind, QPath}; | |
| 5 | use rustc_hir::{Expr, ExprKind}; | |
| 5 | 6 | use rustc_lint::LateContext; |
| 6 | 7 | use rustc_span::Span; |
| 7 | 8 | |
| ... | ... | @@ -12,8 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span |
| 12 | 13 | && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() |
| 13 | 14 | && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) |
| 14 | 15 | && matches!(ty_name, sym::Vec | sym::VecDeque) |
| 15 | && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind | |
| 16 | && is_range_full(cx, arg, Some(container_path)) | |
| 16 | && is_full_collection_range(cx, recv.res_local_id(), arg) | |
| 17 | 17 | { |
| 18 | 18 | span_lint_and_sugg( |
| 19 | 19 | cx, |
src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::msrvs::{self, Msrv}; |
| 3 | 3 | use clippy_utils::res::{MaybeDef, MaybeResPath}; |
| 4 | use clippy_utils::source::{IntoSpan, SpanRangeExt}; | |
| 4 | use clippy_utils::source::{IntoSpan, SpanExt}; | |
| 5 | 5 | use clippy_utils::ty::get_field_by_name; |
| 6 | 6 | use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; |
| 7 | 7 | use clippy_utils::{ExprUseNode, get_expr_use_site, sym}; |
| ... | ... | @@ -47,7 +47,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: |
| 47 | 47 | let can_lint = for_each_expr_without_closures(block.stmts, |e| { |
| 48 | 48 | if let ExprKind::Closure(c) = e.kind { |
| 49 | 49 | // Nested closures don't need to treat returns specially. |
| 50 | let _: Option<!> = for_each_expr(cx, cx.tcx.hir_body(c.body).value, |e| { | |
| 50 | let _: Option<!> = for_each_expr(cx.tcx, cx.tcx.hir_body(c.body).value, |e| { | |
| 51 | 51 | if e.res_local_id() == Some(arg_id) { |
| 52 | 52 | let (kind, same_ctxt) = check_use(cx, ctxt, e); |
| 53 | 53 | match (kind, same_ctxt && e.span.ctxt() == ctxt) { |
src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; |
| 3 | use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; | |
| 3 | use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; | |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_hir::LangItem::{ResultErr, ResultOk}; |
| 6 | 6 | use rustc_hir::{Expr, ExprKind, PatKind}; |
| ... | ... | @@ -27,8 +27,8 @@ pub(super) fn check<'tcx>( |
| 27 | 27 | && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind |
| 28 | 28 | && err_path.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr) |
| 29 | 29 | && is_ok_wrapping(cx, map_expr) |
| 30 | && let Some(recv_snippet) = recv.span.get_source_text(cx) | |
| 31 | && let Some(err_arg_snippet) = err_arg.span.get_source_text(cx) | |
| 30 | && let Some(recv_snippet) = recv.span.get_text(cx) | |
| 31 | && let Some(err_arg_snippet) = err_arg.span.get_text(cx) | |
| 32 | 32 | && let Some(indent) = indent_of(cx, expr.span) |
| 33 | 33 | { |
| 34 | 34 | let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str(), true, Some(indent + 4)); |
src/tools/clippy/clippy_lints/src/methods/manual_option_zip.rs+3| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::eager_or_lazy::switch_to_eager_eval; | |
| 2 | 3 | use clippy_utils::msrvs::{self, Msrv}; |
| 3 | 4 | use clippy_utils::peel_blocks; |
| 4 | 5 | use clippy_utils::res::{MaybeDef, MaybeResPath}; |
| ... | ... | @@ -29,6 +30,8 @@ pub(super) fn check<'tcx>( |
| 29 | 30 | && let ExprKind::MethodCall(method_path, map_recv, [map_arg], _) = peel_blocks(outer_value).kind |
| 30 | 31 | && method_path.ident.name == sym::map |
| 31 | 32 | && cx.typeck_results().expr_ty(map_recv).is_diag_item(cx, sym::Option) |
| 33 | // `b` is not lazy evaluated | |
| 34 | && switch_to_eager_eval(cx, map_recv) | |
| 32 | 35 | // `b` does not reference the outer closure parameter `a`. |
| 33 | 36 | && !local_used_in(cx, outer_param_id, map_recv) |
| 34 | 37 | // `|b| (a, b)` |
src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs+3-5| ... | ... | @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::is_from_proc_macro; |
| 3 | 3 | use clippy_utils::msrvs::{self, Msrv}; |
| 4 | 4 | use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; |
| 5 | use clippy_utils::source::SpanRangeExt; | |
| 5 | use clippy_utils::source::SpanExt; | |
| 6 | 6 | use clippy_utils::ty::implements_trait; |
| 7 | 7 | use rustc_errors::Applicability; |
| 8 | 8 | use rustc_hir::def::{DefKind, Res}; |
| ... | ... | @@ -31,14 +31,12 @@ pub(super) fn check<'tcx>( |
| 31 | 31 | && let ExprKind::Closure(closure) = acc.kind |
| 32 | 32 | && msrv.meets(cx, msrvs::ITERATOR_TRY_FOLD) |
| 33 | 33 | && !is_from_proc_macro(cx, expr) |
| 34 | && let Some(args_snip) = closure | |
| 35 | .fn_arg_span | |
| 36 | .and_then(|fn_arg_span| fn_arg_span.get_source_text(cx)) | |
| 34 | && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| fn_arg_span.get_text(cx)) | |
| 37 | 35 | { |
| 38 | 36 | let init_snip = rest |
| 39 | 37 | .is_empty() |
| 40 | 38 | .then_some(first.span) |
| 41 | .and_then(|span| span.get_source_text(cx)) | |
| 39 | .and_then(|span| span.get_text(cx)) | |
| 42 | 40 | .map_or_else(|| "...".to_owned(), |src| src.to_owned()); |
| 43 | 41 | |
| 44 | 42 | span_lint_and_sugg( |
src/tools/clippy/clippy_lints/src/methods/map_all_any_identity.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::is_expr_identity_function; |
| 3 | 3 | use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::Expr; |
| 7 | 7 | use rustc_lint::LateContext; |
| ... | ... | @@ -24,7 +24,7 @@ pub(super) fn check( |
| 24 | 24 | && cx.ty_based_def(recv).opt_parent(cx).is_diag_item(cx, sym::Iterator) |
| 25 | 25 | && is_expr_identity_function(cx, any_arg) |
| 26 | 26 | && let map_any_call_span = map_call_span.with_hi(any_call_span.hi()) |
| 27 | && let Some(map_arg) = map_arg.span.get_source_text(cx) | |
| 27 | && let Some(map_arg) = map_arg.span.get_text(cx) | |
| 28 | 28 | { |
| 29 | 29 | span_lint_and_then( |
| 30 | 30 | cx, |
src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs+4-4| ... | ... | @@ -128,10 +128,10 @@ pub(super) fn check<'tcx>( |
| 128 | 128 | (SuggestedKind::AndThen, _) => "and_then", |
| 129 | 129 | (SuggestedKind::IsVariantAnd, sym::Result) => "is_ok_and", |
| 130 | 130 | (SuggestedKind::IsVariantAnd, sym::Option) => "is_some_and", |
| 131 | (SuggestedKind::Other, _) | |
| 132 | if unwrap_arg_ty.peel_refs().is_array() | |
| 133 | && cx.typeck_results().expr_ty_adjusted(unwrap_arg).peel_refs().is_slice() => | |
| 134 | { | |
| 131 | (SuggestedKind::Other, _) if unwrap_arg_ty != cx.typeck_results().expr_ty_adjusted(unwrap_arg) => { | |
| 132 | // If the `unwrap_or` argument needs an adjustment, moving it into `map_or`'s | |
| 133 | // first argument can make type inference pick the unadjusted type and reject | |
| 134 | // the closure return type. Keep the lint, but don't emit a rustfix. | |
| 135 | 135 | return; |
| 136 | 136 | }, |
| 137 | 137 | _ => "map_or", |
src/tools/clippy/clippy_lints/src/methods/mod.rs+114-9| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | mod bind_instead_of_map; |
| 2 | mod by_ref_peekable_peek; | |
| 2 | 3 | mod bytecount; |
| 3 | 4 | mod bytes_count_to_len; |
| 4 | 5 | mod bytes_nth; |
| ... | ... | @@ -9,6 +10,7 @@ mod chars_last_cmp; |
| 9 | 10 | mod chars_last_cmp_with_unwrap; |
| 10 | 11 | mod chars_next_cmp; |
| 11 | 12 | mod chars_next_cmp_with_unwrap; |
| 13 | mod chunks_exact_to_as_chunks; | |
| 12 | 14 | mod clear_with_drain; |
| 13 | 15 | mod clone_on_copy; |
| 14 | 16 | mod clone_on_ref_ptr; |
| ... | ... | @@ -141,6 +143,7 @@ mod unnecessary_map_or_else; |
| 141 | 143 | mod unnecessary_min_or_max; |
| 142 | 144 | mod unnecessary_sort_by; |
| 143 | 145 | mod unnecessary_to_owned; |
| 146 | mod unnecessary_unwrap_unchecked; | |
| 144 | 147 | mod unwrap_expect_used; |
| 145 | 148 | mod useless_asref; |
| 146 | 149 | mod useless_nonzero_new_unchecked; |
| ... | ... | @@ -201,6 +204,39 @@ declare_clippy_lint! { |
| 201 | 204 | "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`" |
| 202 | 205 | } |
| 203 | 206 | |
| 207 | declare_clippy_lint! { | |
| 208 | /// ### What it does | |
| 209 | /// Checks for usages of `Iterator::by_ref().peekable().peek()`. | |
| 210 | /// | |
| 211 | /// ### Why is this bad? | |
| 212 | /// While it might look like this will allow peeking on the first | |
| 213 | /// element of an iterator without consuming it and without consuming | |
| 214 | /// the iterator itself, it will in practice consume the first element. | |
| 215 | /// | |
| 216 | /// The implementation of `Peekable::peek()` produces the first element | |
| 217 | /// of the underlying iterator, and stores it internally so that it can | |
| 218 | /// be later produced. As a consequence, it advances the underlying | |
| 219 | /// iterator, whose `.next()` method will now produce its second element. | |
| 220 | /// | |
| 221 | /// ### Example | |
| 222 | /// ```no_run | |
| 223 | /// let mut iter = [1, 2, 3].into_iter(); | |
| 224 | /// let x = iter.by_ref().peekable().peek(); // 1 | |
| 225 | /// let y = iter.by_ref().peekable().peek(); // 2 | |
| 226 | /// ``` | |
| 227 | /// If this does what you intended, use the following instead, which is | |
| 228 | /// shorter and clearer: | |
| 229 | /// ```no_run | |
| 230 | /// let mut iter = [1, 2, 3].into_iter(); | |
| 231 | /// let x = iter.next().as_ref(); // 1 | |
| 232 | /// let y = iter.next().as_ref(); // 2 | |
| 233 | /// ``` | |
| 234 | #[clippy::version = "1.98.0"] | |
| 235 | pub BY_REF_PEEKABLE_PEEK, | |
| 236 | suspicious, | |
| 237 | "Using `.by_ref().peekable().peek()` on an iterator" | |
| 238 | } | |
| 239 | ||
| 204 | 240 | declare_clippy_lint! { |
| 205 | 241 | /// ### What it does |
| 206 | 242 | /// It checks for `str::bytes().count()` and suggests replacing it with |
| ... | ... | @@ -329,6 +365,32 @@ declare_clippy_lint! { |
| 329 | 365 | "using `.chars().next()` to check if a string starts with a char" |
| 330 | 366 | } |
| 331 | 367 | |
| 368 | declare_clippy_lint! { | |
| 369 | /// ### What it does | |
| 370 | /// Checks for usage of `chunks_exact` or `chunks_exact_mut` with a constant chunk size. | |
| 371 | /// | |
| 372 | /// ### Why is this bad? | |
| 373 | /// `as_chunks` provides better ergonomics and type safety by returning arrays instead of slices. | |
| 374 | /// It was stabilized in Rust 1.88. | |
| 375 | /// | |
| 376 | /// ### Example | |
| 377 | /// ```no_run | |
| 378 | /// let slice = [1, 2, 3, 4, 5, 6]; | |
| 379 | /// let mut it = slice.chunks_exact(2); | |
| 380 | /// for chunk in it {} | |
| 381 | /// ``` | |
| 382 | /// Use instead: | |
| 383 | /// ```no_run | |
| 384 | /// let slice = [1, 2, 3, 4, 5, 6]; | |
| 385 | /// let (chunks, remainder) = slice.as_chunks::<2>(); | |
| 386 | /// for chunk in chunks {} | |
| 387 | /// ``` | |
| 388 | #[clippy::version = "1.93.0"] | |
| 389 | pub CHUNKS_EXACT_TO_AS_CHUNKS, | |
| 390 | style, | |
| 391 | "using `chunks_exact` with constant when `as_chunks` is more ergonomic" | |
| 392 | } | |
| 393 | ||
| 332 | 394 | declare_clippy_lint! { |
| 333 | 395 | /// ### What it does |
| 334 | 396 | /// Checks for usage of `.drain(..)` for the sole purpose of clearing a container. |
| ... | ... | @@ -4541,6 +4603,34 @@ declare_clippy_lint! { |
| 4541 | 4603 | "unnecessary calls to `to_owned`-like functions" |
| 4542 | 4604 | } |
| 4543 | 4605 | |
| 4606 | declare_clippy_lint! { | |
| 4607 | /// ### What it does | |
| 4608 | /// Checks for calls to `unwrap_unchecked` when an `_unchecked` variant of the function exists. | |
| 4609 | /// | |
| 4610 | /// ### Why is this bad? | |
| 4611 | /// Calling the non-unchecked variant may result in checking that is then discarded | |
| 4612 | /// if `unwrap_unchecked` is called directly afterwards, whereas the unchecked | |
| 4613 | /// variant most likely avoids performing the check completely. | |
| 4614 | /// | |
| 4615 | /// ### Known problems | |
| 4616 | /// | |
| 4617 | /// The unchecked variant is only suggested if it's defined in the same `impl` block | |
| 4618 | /// as the non-unchecked one | |
| 4619 | /// | |
| 4620 | /// ### Example | |
| 4621 | /// ```rust | |
| 4622 | /// let s = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 4623 | /// ``` | |
| 4624 | /// Use instead: | |
| 4625 | /// ```rust | |
| 4626 | /// let s = unsafe { std::str::from_utf8_unchecked(&[]) }; | |
| 4627 | /// ``` | |
| 4628 | #[clippy::version = "1.98.0"] | |
| 4629 | pub UNNECESSARY_UNWRAP_UNCHECKED, | |
| 4630 | complexity, | |
| 4631 | "calling `unwrap_unchecked` on a function which has an `_unchecked` variant" | |
| 4632 | } | |
| 4633 | ||
| 4544 | 4634 | declare_clippy_lint! { |
| 4545 | 4635 | /// ### What it does |
| 4546 | 4636 | /// Checks for usages of the following functions with an argument that constructs a default value |
| ... | ... | @@ -4835,9 +4925,11 @@ impl_lint_pass!(Methods => [ |
| 4835 | 4925 | BIND_INSTEAD_OF_MAP, |
| 4836 | 4926 | BYTES_COUNT_TO_LEN, |
| 4837 | 4927 | BYTES_NTH, |
| 4928 | BY_REF_PEEKABLE_PEEK, | |
| 4838 | 4929 | CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, |
| 4839 | 4930 | CHARS_LAST_CMP, |
| 4840 | 4931 | CHARS_NEXT_CMP, |
| 4932 | CHUNKS_EXACT_TO_AS_CHUNKS, | |
| 4841 | 4933 | CLEAR_WITH_DRAIN, |
| 4842 | 4934 | CLONED_INSTEAD_OF_COPIED, |
| 4843 | 4935 | CLONE_ON_COPY, |
| ... | ... | @@ -4979,6 +5071,7 @@ impl_lint_pass!(Methods => [ |
| 4979 | 5071 | UNNECESSARY_RESULT_MAP_OR_ELSE, |
| 4980 | 5072 | UNNECESSARY_SORT_BY, |
| 4981 | 5073 | UNNECESSARY_TO_OWNED, |
| 5074 | UNNECESSARY_UNWRAP_UNCHECKED, | |
| 4982 | 5075 | UNWRAP_OR_DEFAULT, |
| 4983 | 5076 | UNWRAP_USED, |
| 4984 | 5077 | USELESS_ASREF, |
| ... | ... | @@ -5198,12 +5291,15 @@ impl Methods { |
| 5198 | 5291 | _ => {}, |
| 5199 | 5292 | } |
| 5200 | 5293 | }, |
| 5294 | (name @ (sym::chunks_exact | sym::chunks_exact_mut), [arg]) => { | |
| 5295 | chunks_exact_to_as_chunks::check(cx, recv, arg, expr, call_span, name, self.msrv); | |
| 5296 | }, | |
| 5201 | 5297 | (sym::and_then, [arg]) => { |
| 5202 | 5298 | manual_option_zip::check(cx, expr, recv, arg, self.msrv); |
| 5203 | 5299 | let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg); |
| 5204 | 5300 | let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg); |
| 5205 | 5301 | if !biom_option_linted && !biom_result_linted { |
| 5206 | let ule_and_linted = unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); | |
| 5302 | let ule_and_linted = unnecessary_lazy_eval::check(cx, expr, recv, arg, "and", true); | |
| 5207 | 5303 | if !ule_and_linted { |
| 5208 | 5304 | return_and_then::check(cx, expr, recv, arg); |
| 5209 | 5305 | } |
| ... | ... | @@ -5277,8 +5373,10 @@ impl Methods { |
| 5277 | 5373 | manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); |
| 5278 | 5374 | } |
| 5279 | 5375 | }, |
| 5280 | Some((sym::drain, recv, args, ..)) => { | |
| 5281 | drain_collect::check(cx, args, expr, recv); | |
| 5376 | Some((sym::drain, recv, args, ..)) => match args { | |
| 5377 | [arg] => drain_collect::check(cx, Some(arg), expr, recv), | |
| 5378 | [] => drain_collect::check(cx, None, expr, recv), | |
| 5379 | _ => {}, | |
| 5282 | 5380 | }, |
| 5283 | 5381 | _ => {}, |
| 5284 | 5382 | } |
| ... | ... | @@ -5333,7 +5431,11 @@ impl Methods { |
| 5333 | 5431 | } |
| 5334 | 5432 | unnecessary_literal_unwrap::check(cx, expr, recv, name, args); |
| 5335 | 5433 | }, |
| 5336 | (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_unchecked | sym::unwrap_err_unchecked, []) => { | |
| 5434 | (sym::unwrap_unchecked, []) => { | |
| 5435 | unnecessary_unwrap_unchecked::check(cx, expr, recv, call_span); | |
| 5436 | unnecessary_literal_unwrap::check(cx, expr, recv, name, args); | |
| 5437 | }, | |
| 5438 | (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_err_unchecked, []) => { | |
| 5337 | 5439 | unnecessary_literal_unwrap::check(cx, expr, recv, name, args); |
| 5338 | 5440 | }, |
| 5339 | 5441 | (sym::extend, [arg]) => { |
| ... | ... | @@ -5439,7 +5541,7 @@ impl Methods { |
| 5439 | 5541 | get_last_with_len::check(cx, expr, recv, arg); |
| 5440 | 5542 | }, |
| 5441 | 5543 | (sym::get_or_insert_with, [arg]) => { |
| 5442 | unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"); | |
| 5544 | unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert", false); | |
| 5443 | 5545 | }, |
| 5444 | 5546 | (sym::hash, [arg]) => { |
| 5445 | 5547 | unit_hash::check(cx, expr, recv, arg); |
| ... | ... | @@ -5594,16 +5696,19 @@ impl Methods { |
| 5594 | 5696 | ptr_offset_by_literal::check(cx, expr, self.msrv); |
| 5595 | 5697 | }, |
| 5596 | 5698 | (sym::ok_or_else, [arg]) => { |
| 5597 | unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"); | |
| 5699 | unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or", true); | |
| 5598 | 5700 | }, |
| 5599 | 5701 | (sym::open, [_]) => { |
| 5600 | 5702 | open_options::check(cx, expr, recv); |
| 5601 | 5703 | }, |
| 5602 | 5704 | (sym::or_else, [arg]) => { |
| 5603 | 5705 | if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) { |
| 5604 | unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); | |
| 5706 | unnecessary_lazy_eval::check(cx, expr, recv, arg, "or", false); | |
| 5605 | 5707 | } |
| 5606 | 5708 | }, |
| 5709 | (sym::peek, []) => { | |
| 5710 | by_ref_peekable_peek::check(cx, expr, recv); | |
| 5711 | }, | |
| 5607 | 5712 | (sym::push, [arg]) => { |
| 5608 | 5713 | path_buf_push_overwrite::check(cx, expr, arg); |
| 5609 | 5714 | }, |
| ... | ... | @@ -5699,7 +5804,7 @@ impl Methods { |
| 5699 | 5804 | if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { |
| 5700 | 5805 | return; |
| 5701 | 5806 | } |
| 5702 | unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); | |
| 5807 | unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some", true); | |
| 5703 | 5808 | }, |
| 5704 | 5809 | (sym::try_into, []) if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::TryInto) => { |
| 5705 | 5810 | unnecessary_fallible_conversions::check_method(cx, expr); |
| ... | ... | @@ -5789,7 +5894,7 @@ impl Methods { |
| 5789 | 5894 | ); |
| 5790 | 5895 | }, |
| 5791 | 5896 | _ => { |
| 5792 | unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); | |
| 5897 | unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or", false); | |
| 5793 | 5898 | }, |
| 5794 | 5899 | } |
| 5795 | 5900 | unnecessary_literal_unwrap::check(cx, expr, recv, name, args); |
src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs+3-3| ... | ... | @@ -8,7 +8,7 @@ use rustc_span::Span; |
| 8 | 8 | use super::NEEDLESS_CHARACTER_ITERATION; |
| 9 | 9 | use super::utils::get_last_chain_binding_hir_id; |
| 10 | 10 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 11 | use clippy_utils::source::SpanRangeExt; | |
| 11 | use clippy_utils::source::SpanExt; | |
| 12 | 12 | use clippy_utils::{peel_blocks, sym}; |
| 13 | 13 | |
| 14 | 14 | fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { |
| ... | ... | @@ -36,7 +36,7 @@ fn handle_expr( |
| 36 | 36 | && receiver.res_local_id() == Some(first_param) |
| 37 | 37 | && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() |
| 38 | 38 | && *char_arg_ty.kind() == ty::Char |
| 39 | && let Some(snippet) = before_chars.get_source_text(cx) | |
| 39 | && let Some(snippet) = before_chars.get_text(cx) | |
| 40 | 40 | { |
| 41 | 41 | span_lint_and_sugg( |
| 42 | 42 | cx, |
| ... | ... | @@ -78,7 +78,7 @@ fn handle_expr( |
| 78 | 78 | if revert != is_all |
| 79 | 79 | && fn_path.ty_rel_def(cx).is_diag_item(cx, sym::char_is_ascii) |
| 80 | 80 | && peels_expr_ref(arg).res_local_id() == Some(first_param) |
| 81 | && let Some(snippet) = before_chars.get_source_text(cx) | |
| 81 | && let Some(snippet) = before_chars.get_text(cx) | |
| 82 | 82 | { |
| 83 | 83 | span_lint_and_sugg( |
| 84 | 84 | cx, |
src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::res::{MaybeDef, MaybeResPath}; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::sym; |
| 5 | 5 | use clippy_utils::usage::local_used_after_expr; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name |
| 32 | 32 | expr.span, |
| 33 | 33 | "derefed type is same as origin", |
| 34 | 34 | "try", |
| 35 | recv.span.get_source_text(cx).unwrap().to_owned(), | |
| 35 | recv.span.get_text(cx).unwrap().to_owned(), | |
| 36 | 36 | Applicability::MachineApplicable, |
| 37 | 37 | ); |
| 38 | 38 | } |
src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs+25-8| ... | ... | @@ -30,9 +30,26 @@ pub(super) fn check<'tcx>( |
| 30 | 30 | args: &'tcx [hir::Expr<'_>], |
| 31 | 31 | msrv: Msrv, |
| 32 | 32 | ) { |
| 33 | // Bail out early unless the method is one that `check_unwrap_or_default` or | |
| 34 | // `check_or_fn_call` can lint, to avoid walking the argument of every method call. | |
| 35 | if !matches!( | |
| 36 | name, | |
| 37 | sym::unwrap_or | |
| 38 | | sym::unwrap_or_else | |
| 39 | | sym::or_insert | |
| 40 | | sym::or_insert_with | |
| 41 | | sym::get_or_insert | |
| 42 | | sym::map_or | |
| 43 | | sym::ok_or | |
| 44 | | sym::or | |
| 45 | | sym::and | |
| 46 | ) { | |
| 47 | return; | |
| 48 | } | |
| 49 | ||
| 33 | 50 | if let [arg] = args { |
| 34 | 51 | let inner_arg = peel_blocks(arg); |
| 35 | for_each_expr(cx, inner_arg, |ex| { | |
| 52 | for_each_expr(cx.tcx, inner_arg, |ex| { | |
| 36 | 53 | // `or_fun_call` lint needs to take nested expr into account, |
| 37 | 54 | // but `unwrap_or_default` lint doesn't, we don't want something like: |
| 38 | 55 | // `opt.unwrap_or(Foo { inner: String::default(), other: 1 })` to get replaced by |
| ... | ... | @@ -72,7 +89,7 @@ pub(super) fn check<'tcx>( |
| 72 | 89 | // `map_or` takes two arguments |
| 73 | 90 | if let [arg, lambda] = args { |
| 74 | 91 | let inner_arg = peel_blocks(arg); |
| 75 | for_each_expr(cx, inner_arg, |ex| { | |
| 92 | for_each_expr(cx.tcx, inner_arg, |ex| { | |
| 76 | 93 | let is_top_most_expr = ex.hir_id == inner_arg.hir_id; |
| 77 | 94 | match ex.kind { |
| 78 | 95 | hir::ExprKind::Call(fun, fun_args) => { |
| ... | ... | @@ -112,6 +129,12 @@ fn check_unwrap_or_default( |
| 112 | 129 | method_span: Span, |
| 113 | 130 | msrv: Msrv, |
| 114 | 131 | ) -> bool { |
| 132 | let sugg = match (name, call_expr.is_some()) { | |
| 133 | (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default, | |
| 134 | (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default, | |
| 135 | _ => return false, | |
| 136 | }; | |
| 137 | ||
| 115 | 138 | let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs(); |
| 116 | 139 | |
| 117 | 140 | // Check MSRV, but only for `Result::unwrap_or_default` |
| ... | ... | @@ -150,12 +173,6 @@ fn check_unwrap_or_default( |
| 150 | 173 | } |
| 151 | 174 | }; |
| 152 | 175 | |
| 153 | let sugg = match (name, call_expr.is_some()) { | |
| 154 | (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default, | |
| 155 | (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default, | |
| 156 | _ => return false, | |
| 157 | }; | |
| 158 | ||
| 159 | 176 | let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| { |
| 160 | 177 | cx.tcx |
| 161 | 178 | .inherent_impls(adt_def.did()) |
src/tools/clippy/clippy_lints/src/methods/ptr_offset_by_literal.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::msrvs::{self, Msrv}; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::sym; |
| 5 | 5 | use rustc_ast::LitKind; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -92,7 +92,7 @@ fn expr_as_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti |
| 92 | 92 | } |
| 93 | 93 | |
| 94 | 94 | fn format_isize_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<String> { |
| 95 | let text = expr.span.get_source_text(cx)?; | |
| 95 | let text = expr.span.get_text(cx)?; | |
| 96 | 96 | let text = peel_parens_str(&text); |
| 97 | 97 | Some(text.trim_end_matches("isize").trim_end_matches('_').to_string()) |
| 98 | 98 | } |
src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; |
| 3 | use clippy_utils::source::{SpanRangeExt as _, snippet_with_applicability}; | |
| 3 | use clippy_utils::source::{SpanExt as _, snippet_with_applicability}; | |
| 4 | 4 | use clippy_utils::{SpanlessEq, get_parent_expr, higher, is_integer_literal, sym}; |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::{Expr, ExprKind, Node, Pat, PatKind, QPath}; |
| ... | ... | @@ -49,8 +49,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' |
| 49 | 49 | ), |
| 50 | 50 | )]; |
| 51 | 51 | if let Some((left, right)) = invert_bindings |
| 52 | && let Some(snip_left) = left.get_source_text(cx) | |
| 53 | && let Some(snip_right) = right.get_source_text(cx) | |
| 52 | && let Some(snip_left) = left.get_text(cx) | |
| 53 | && let Some(snip_right) = right.get_text(cx) | |
| 54 | 54 | { |
| 55 | 55 | suggestions.extend([(left, snip_right.to_string()), (right, snip_left.to_string())]); |
| 56 | 56 | } else { |
src/tools/clippy/clippy_lints/src/methods/str_split.rs+3-2| ... | ... | @@ -22,8 +22,9 @@ pub(super) fn check<'a>( |
| 22 | 22 | // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`. |
| 23 | 23 | if let ExprKind::MethodCall(trim_method_name, trim_recv, [], trim_span) = split_recv.kind |
| 24 | 24 | && trim_method_name.ident.name == sym::trim |
| 25 | && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str() | |
| 26 | && !is_const_evaluatable(cx, trim_recv) | |
| 25 | && let typeck = cx.typeck_results() | |
| 26 | && typeck.expr_ty_adjusted(trim_recv).peel_refs().is_str() | |
| 27 | && !is_const_evaluatable(cx.tcx, typeck, trim_recv) | |
| 27 | 28 | && let ExprKind::Lit(split_lit) = split_arg.kind |
| 28 | 29 | && matches!( |
| 29 | 30 | split_lit.node, |
src/tools/clippy/clippy_lints/src/methods/str_splitn.rs+1-1| ... | ... | @@ -214,7 +214,7 @@ fn indirect_usage<'tcx>( |
| 214 | 214 | }) = stmt.kind |
| 215 | 215 | { |
| 216 | 216 | let mut path_to_binding = None; |
| 217 | let _: Option<!> = for_each_expr(cx, init_expr, |e| { | |
| 217 | let _: Option<!> = for_each_expr(cx.tcx, init_expr, |e| { | |
| 218 | 218 | if e.res_local_id() == Some(binding) { |
| 219 | 219 | path_to_binding = Some(e); |
| 220 | 220 | } |
src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs+2-2| ... | ... | @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::is_from_proc_macro; |
| 3 | 3 | use clippy_utils::msrvs::{self, Msrv}; |
| 4 | 4 | use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes}; |
| 5 | use clippy_utils::source::SpanRangeExt; | |
| 5 | use clippy_utils::source::SpanExt; | |
| 6 | 6 | use itertools::Itertools; |
| 7 | 7 | use rustc_ast::LitKind; |
| 8 | 8 | use rustc_errors::Applicability; |
| ... | ... | @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( |
| 35 | 35 | } |
| 36 | 36 | && msrv.meets(cx, msrvs::MATCHES_MACRO) |
| 37 | 37 | && !is_from_proc_macro(cx, expr) |
| 38 | && let Some(scrutinee_snip) = scrutinee.span.get_source_text(cx) | |
| 38 | && let Some(scrutinee_snip) = scrutinee.span.get_text(cx) | |
| 39 | 39 | { |
| 40 | 40 | // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then |
| 41 | 41 | // something like `r"\"` will become `'\'`, which is of course invalid |
src/tools/clippy/clippy_lints/src/methods/unnecessary_first_then_check.rs+3-3| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_hir::{Expr, ExprKind}; |
| ... | ... | @@ -29,8 +29,8 @@ pub(super) fn check( |
| 29 | 29 | }; |
| 30 | 30 | |
| 31 | 31 | let both_calls_span = first_call_span.with_hi(call_span.hi()); |
| 32 | if let Some(both_calls_snippet) = both_calls_span.get_source_text(cx) | |
| 33 | && let Some(first_caller_snippet) = first_caller.span.get_source_text(cx) | |
| 32 | if let Some(both_calls_snippet) = both_calls_span.get_text(cx) | |
| 33 | && let Some(first_caller_snippet) = first_caller.span.get_text(cx) | |
| 34 | 34 | { |
| 35 | 35 | let (sugg_span, suggestion) = if is_some { |
| 36 | 36 | ( |
src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs+5-5| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; |
| 2 | 2 | use clippy_utils::res::MaybeDef; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::sym; |
| 5 | 5 | |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -39,11 +39,11 @@ pub(super) fn check( |
| 39 | 39 | return; |
| 40 | 40 | }; |
| 41 | 41 | let both_calls_span = get_call_span.with_hi(call_span.hi()); |
| 42 | if let Some(snippet) = both_calls_span.get_source_text(cx) | |
| 43 | && let Some(arg_snippet) = arg.span.get_source_text(cx) | |
| 42 | if let Some(snippet) = both_calls_span.get_text(cx) | |
| 43 | && let Some(arg_snippet) = arg.span.get_text(cx) | |
| 44 | 44 | { |
| 45 | 45 | let generics_snippet = if let Some(generics) = path.args |
| 46 | && let Some(generics_snippet) = generics.span_ext.get_source_text(cx) | |
| 46 | && let Some(generics_snippet) = generics.span_ext.get_text(cx) | |
| 47 | 47 | { |
| 48 | 48 | format!("::{generics_snippet}") |
| 49 | 49 | } else { |
| ... | ... | @@ -64,7 +64,7 @@ pub(super) fn check( |
| 64 | 64 | suggestion, |
| 65 | 65 | Applicability::MaybeIncorrect, |
| 66 | 66 | ); |
| 67 | } else if let Some(caller_snippet) = get_caller.span.get_source_text(cx) { | |
| 67 | } else if let Some(caller_snippet) = get_caller.span.get_text(cx) { | |
| 68 | 68 | let full_span = get_caller.span.with_hi(call_span.hi()); |
| 69 | 69 | |
| 70 | 70 | span_lint_and_then( |
src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs+3-3| ... | ... | @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | 3 | use clippy_utils::higher::ForLoop; |
| 4 | 4 | use clippy_utils::res::MaybeResPath; |
| 5 | use clippy_utils::source::SpanRangeExt; | |
| 5 | use clippy_utils::source::SpanExt; | |
| 6 | 6 | use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; |
| 7 | 7 | use clippy_utils::visitors::for_each_expr_without_closures; |
| 8 | 8 | use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr}; |
| ... | ... | @@ -42,7 +42,7 @@ pub fn check_for_loop_iter( |
| 42 | 42 | && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) |
| 43 | 43 | && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body) |
| 44 | 44 | && !clone_or_copy_needed |
| 45 | && let Some(receiver_snippet) = receiver.span.get_source_text(cx) | |
| 45 | && let Some(receiver_snippet) = receiver.span.get_text(cx) | |
| 46 | 46 | { |
| 47 | 47 | // Issue 12098 |
| 48 | 48 | // https://github.com/rust-lang/rust-clippy/issues/12098 |
| ... | ... | @@ -102,7 +102,7 @@ pub fn check_for_loop_iter( |
| 102 | 102 | && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) |
| 103 | 103 | && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item) |
| 104 | 104 | && iter_item_ty == into_iter_item_ty |
| 105 | && let Some(collection_snippet) = collection.span.get_source_text(cx) | |
| 105 | && let Some(collection_snippet) = collection.span.get_text(cx) | |
| 106 | 106 | { |
| 107 | 107 | collection_snippet |
| 108 | 108 | } else { |
src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs+40-16| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::res::MaybeDef; |
| 3 | use clippy_utils::source::snippet; | |
| 3 | use clippy_utils::source::{snippet, snippet_with_applicability}; | |
| 4 | 4 | use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage}; |
| 5 | 5 | use hir::FnRetTy; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -18,6 +18,7 @@ pub(super) fn check<'tcx>( |
| 18 | 18 | recv: &'tcx hir::Expr<'_>, |
| 19 | 19 | arg: &'tcx hir::Expr<'_>, |
| 20 | 20 | simplify_using: &str, |
| 21 | use_turbofish: bool, | |
| 21 | 22 | ) -> bool { |
| 22 | 23 | let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option); |
| 23 | 24 | let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result); |
| ... | ... | @@ -46,23 +47,43 @@ pub(super) fn check<'tcx>( |
| 46 | 47 | } else { |
| 47 | 48 | "unnecessary closure used with `bool::then`" |
| 48 | 49 | }; |
| 49 | let applicability = if body | |
| 50 | ||
| 51 | let mut applicability = Applicability::MachineApplicable; | |
| 52 | if body | |
| 50 | 53 | .params |
| 51 | 54 | .iter() |
| 52 | 55 | // bindings are checked to be unused above |
| 53 | .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) | |
| 54 | && matches!( | |
| 55 | fn_decl.output, | |
| 56 | FnRetTy::DefaultReturn(_) | |
| 57 | | FnRetTy::Return(hir::Ty { | |
| 58 | kind: hir::TyKind::Infer(()), | |
| 59 | .. | |
| 60 | }) | |
| 61 | ) { | |
| 62 | Applicability::MachineApplicable | |
| 63 | } else { | |
| 64 | // replacing the lambda may break type inference | |
| 65 | Applicability::MaybeIncorrect | |
| 56 | .any(|param| !matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) | |
| 57 | { | |
| 58 | // If the closure parameters have a pattern, | |
| 59 | // it might be required for type inferrence. | |
| 60 | applicability = Applicability::MaybeIncorrect; | |
| 61 | } | |
| 62 | let (ascription, turbofish) = match fn_decl.output { | |
| 63 | FnRetTy::DefaultReturn(_) | |
| 64 | | FnRetTy::Return(hir::Ty { | |
| 65 | kind: hir::TyKind::Infer(()), | |
| 66 | .. | |
| 67 | }) => { | |
| 68 | // if the closure has no explicit return type, | |
| 69 | // then there's nothing to preserve | |
| 70 | (String::new(), String::new()) | |
| 71 | }, | |
| 72 | FnRetTy::Return(ty) => { | |
| 73 | // explicit return type was given on the closure | |
| 74 | // | |
| 75 | // we can preserve this information using `as`, but `as` is | |
| 76 | // a somewhat dangerous feature, because it can be used to | |
| 77 | // truncate integers | |
| 78 | // | |
| 79 | // if possible, use turbofish to preserve the type information | |
| 80 | let ty = snippet_with_applicability(cx, ty.span, "_", &mut applicability); | |
| 81 | if use_turbofish { | |
| 82 | (String::new(), format!("::<{ty}>")) | |
| 83 | } else { | |
| 84 | (format!(" as {ty}"), String::new()) | |
| 85 | } | |
| 86 | }, | |
| 66 | 87 | }; |
| 67 | 88 | |
| 68 | 89 | // This is a duplicate of what's happening in clippy_lints::methods::method_call, |
| ... | ... | @@ -73,7 +94,10 @@ pub(super) fn check<'tcx>( |
| 73 | 94 | diag.span_suggestion_verbose( |
| 74 | 95 | span, |
| 75 | 96 | format!("use `{simplify_using}` instead"), |
| 76 | format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), | |
| 97 | format!( | |
| 98 | "{simplify_using}{turbofish}({}{ascription})", | |
| 99 | snippet(cx, body_expr.span, "..") | |
| 100 | ), | |
| 77 | 101 | applicability, |
| 78 | 102 | ); |
| 79 | 103 | }); |
src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs+9-1| ... | ... | @@ -262,7 +262,15 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) -> Option< |
| 262 | 262 | if mirrored_exprs(left_expr, right_expr, &binding_map, BindingSource::Left) { |
| 263 | 263 | (left_expr, l_pat.span, false) |
| 264 | 264 | } else if mirrored_exprs(left_expr, right_expr, &binding_map, BindingSource::Right) { |
| 265 | (left_expr, r_pat.span, true) | |
| 265 | // Use the right-hand expr (the `a` side) as the key body, peeling any `&` | |
| 266 | // introduced by the `.cmp(&rhs)` call so the suggestion doesn't contain a | |
| 267 | // spurious borrow. | |
| 268 | let right_body = if let ExprKind::AddrOf(_, _, inner) = right_expr.kind { | |
| 269 | inner | |
| 270 | } else { | |
| 271 | right_expr | |
| 272 | }; | |
| 273 | (right_body, l_pat.span, true) | |
| 266 | 274 | } else { |
| 267 | 275 | return None; |
| 268 | 276 | }; |
src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs+5-5| ... | ... | @@ -3,7 +3,7 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; |
| 3 | 3 | use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; |
| 4 | 4 | use clippy_utils::msrvs::{self, Msrv}; |
| 5 | 5 | use clippy_utils::res::MaybeDef; |
| 6 | use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_context}; | |
| 6 | use clippy_utils::source::{SpanExt, snippet, snippet_with_context}; | |
| 7 | 7 | use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_and_count_ty_refs}; |
| 8 | 8 | use clippy_utils::visitors::find_all_ret_expressions; |
| 9 | 9 | use clippy_utils::{fn_def_id, get_parent_expr, is_expr_temporary_value, return_ty, sym}; |
| ... | ... | @@ -217,7 +217,7 @@ fn check_into_iter_call_arg( |
| 217 | 217 | && let parent_ty = cx.typeck_results().expr_ty(parent) |
| 218 | 218 | && implements_trait(cx, parent_ty, iterator_trait_id, &[]) |
| 219 | 219 | && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty) |
| 220 | && let Some(receiver_snippet) = receiver.span.get_source_text(cx) | |
| 220 | && let Some(receiver_snippet) = receiver.span.get_text(cx) | |
| 221 | 221 | // If the receiver is a `Cow`, we can't remove the `into_owned` generally, see https://github.com/rust-lang/rust-clippy/issues/13624. |
| 222 | 222 | && !cx.typeck_results().expr_ty(receiver).is_diag_item(cx, sym::Cow) |
| 223 | 223 | // Calling `iter()` on a temporary object can lead to false positives. #14242 |
| ... | ... | @@ -313,8 +313,8 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, |
| 313 | 313 | fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { |
| 314 | 314 | if let Some(parent) = get_parent_expr(cx, expr) |
| 315 | 315 | && let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent) |
| 316 | && let Some(receiver_snippet) = receiver.span.get_source_text(cx) | |
| 317 | && let Some(arg_snippet) = argument_expr.span.get_source_text(cx) | |
| 316 | && let Some(receiver_snippet) = receiver.span.get_text(cx) | |
| 317 | && let Some(arg_snippet) = argument_expr.span.get_text(cx) | |
| 318 | 318 | { |
| 319 | 319 | // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x` |
| 320 | 320 | // implements `AsRef<str>` but does not implement `Deref<Target = str>`. In this case, we have to |
| ... | ... | @@ -712,7 +712,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx |
| 712 | 712 | && let arg_ty = arg_ty.peel_refs() |
| 713 | 713 | // For now we limit this lint to `String` and `Vec`. |
| 714 | 714 | && (is_str_and_string(cx, arg_ty, original_arg_ty) || is_slice_and_vec(cx, arg_ty, original_arg_ty)) |
| 715 | && let Some(snippet) = caller.span.get_source_text(cx) | |
| 715 | && let Some(snippet) = caller.span.get_text(cx) | |
| 716 | 716 | { |
| 717 | 717 | span_lint_and_sugg( |
| 718 | 718 | cx, |
src/tools/clippy/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs created+276| ... | ... | @@ -0,0 +1,276 @@ |
| 1 | use clippy_utils::diagnostics::span_lint_and_then; | |
| 2 | use clippy_utils::res::MaybeQPath; | |
| 3 | use clippy_utils::ty::{option_or_result_arg_ty, same_type_modulo_regions}; | |
| 4 | use clippy_utils::{is_from_proc_macro, last_path_segment, over}; | |
| 5 | use rustc_errors::Applicability; | |
| 6 | use rustc_hir::def::{DefKind, Namespace, Res}; | |
| 7 | use rustc_hir::def_id::DefId; | |
| 8 | use rustc_hir::{Body, Expr, ExprKind, PatKind, Safety}; | |
| 9 | use rustc_lint::LateContext; | |
| 10 | use rustc_middle::ty::{self, Ty}; | |
| 11 | use rustc_span::Span; | |
| 12 | use rustc_span::symbol::Ident; | |
| 13 | ||
| 14 | use super::UNNECESSARY_UNWRAP_UNCHECKED; | |
| 15 | ||
| 16 | #[derive(Clone, Copy, Debug)] | |
| 17 | enum Variant { | |
| 18 | /// Free `fn` in a module | |
| 19 | Fn, | |
| 20 | /// Associated item from an `impl` | |
| 21 | Assoc(AssocKind), | |
| 22 | } | |
| 23 | ||
| 24 | impl Variant { | |
| 25 | fn msg(self) -> &'static str { | |
| 26 | // Don't use `format!` instead -- it won't be optimized out. | |
| 27 | match self { | |
| 28 | Variant::Fn => "usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists", | |
| 29 | Variant::Assoc(AssocKind::Fn) => { | |
| 30 | "usage of `unwrap_unchecked` when an `_unchecked` variant of the associated function exists" | |
| 31 | }, | |
| 32 | Variant::Assoc(AssocKind::Method) => { | |
| 33 | "usage of `unwrap_unchecked` when an `_unchecked` variant of the method exists" | |
| 34 | }, | |
| 35 | } | |
| 36 | } | |
| 37 | } | |
| 38 | ||
| 39 | /// This only exists so the help message shows `associated function` or `method`, depending on | |
| 40 | /// whether it has a `self` parameter. | |
| 41 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | |
| 42 | enum AssocKind { | |
| 43 | /// No `self`: `fn new() -> Self` | |
| 44 | Fn, | |
| 45 | /// Has `self`: `fn ty<'tcx>(&self) -> Ty<'tcx>` | |
| 46 | Method, | |
| 47 | } | |
| 48 | ||
| 49 | impl AssocKind { | |
| 50 | fn new(fn_has_self_parameter: bool) -> Self { | |
| 51 | if fn_has_self_parameter { Self::Method } else { Self::Fn } | |
| 52 | } | |
| 53 | } | |
| 54 | ||
| 55 | fn unchecked_ident(checked_ident: Ident) -> Option<Ident> { | |
| 56 | let checked_ident = checked_ident.to_string(); | |
| 57 | // Only add `_unchecked` if it doesn't already end with `_` | |
| 58 | (!checked_ident.ends_with('_')).then(|| Ident::from_str(&(checked_ident + "_unchecked"))) | |
| 59 | } | |
| 60 | ||
| 61 | /// Find a function called the same as `checked`, but with added `_unchecked`. | |
| 62 | /// | |
| 63 | /// This doesn't check if the methods are actually "similar" -- for that, see | |
| 64 | /// [`same_functions_modulo_safety`] | |
| 65 | fn find_unchecked_sibling_fn( | |
| 66 | cx: &LateContext<'_>, | |
| 67 | checked_def_id: DefId, | |
| 68 | checked_ident: Ident, | |
| 69 | ) -> Option<(DefId, Ident)> { | |
| 70 | // Don't use `parent_module`. We only want to lint if its first parent is a `Mod`, | |
| 71 | // i.e. if this is a free-standing function | |
| 72 | let parent = cx.tcx.parent(checked_def_id); | |
| 73 | if cx.tcx.def_kind(parent) == DefKind::Mod | |
| 74 | && let children = parent.as_local().map_or_else( | |
| 75 | || cx.tcx.module_children(parent), | |
| 76 | // We must use a !query for local modules to prevent an ICE. | |
| 77 | |parent| cx.tcx.module_children_local(parent), | |
| 78 | ) | |
| 79 | // Make sure that there are other functions in this module | |
| 80 | // (otherwise there couldn't be an unchecked version) | |
| 81 | && children.len() > 1 | |
| 82 | && let Some(unchecked_ident) = unchecked_ident(checked_ident) | |
| 83 | && let Some(unchecked_def_id) = children.iter().find_map(|child| { | |
| 84 | if child.ident == unchecked_ident | |
| 85 | && let Res::Def(DefKind::Fn, def_id) = child.res | |
| 86 | { | |
| 87 | Some(def_id) | |
| 88 | } else { | |
| 89 | None | |
| 90 | } | |
| 91 | }) | |
| 92 | { | |
| 93 | Some((unchecked_def_id, unchecked_ident)) | |
| 94 | } else { | |
| 95 | None | |
| 96 | } | |
| 97 | } | |
| 98 | ||
| 99 | /// Find a method called the same as `checked`, but with added `_unchecked`. | |
| 100 | /// | |
| 101 | /// This doesn't check if the methods are actually "similar" -- for that, see | |
| 102 | /// [`same_functions_modulo_safety`] | |
| 103 | fn find_unchecked_sibling_method<'tcx>( | |
| 104 | cx: &LateContext<'tcx>, | |
| 105 | checked_def_id: DefId, | |
| 106 | checked_ident: Ident, | |
| 107 | ) -> Option<(&'tcx ty::AssocItem, Ident)> { | |
| 108 | // Don't use `parent_impl`. We only want to lint if its first parent is an `Impl` | |
| 109 | let parent = cx.tcx.parent(checked_def_id); | |
| 110 | if matches!(cx.tcx.def_kind(parent), DefKind::Impl { .. }) | |
| 111 | && let Some(unchecked_ident) = unchecked_ident(checked_ident) | |
| 112 | // Only look in the same impl (to avoid dealing with generics etc.) | |
| 113 | && let Some(unchecked) = cx.tcx.associated_items(parent).find_by_ident_and_namespace( | |
| 114 | cx.tcx, | |
| 115 | unchecked_ident, | |
| 116 | Namespace::ValueNS, | |
| 117 | parent, | |
| 118 | ) | |
| 119 | { | |
| 120 | Some((unchecked, unchecked_ident)) | |
| 121 | } else { | |
| 122 | None | |
| 123 | } | |
| 124 | } | |
| 125 | ||
| 126 | /// Checks that `checked_def_id` and `unchecked_def_id` refer to functions with: | |
| 127 | /// - same visibility | |
| 128 | /// - identical signatures, apart from unsafety | |
| 129 | /// - "matching" return types: the checked version returns `Option<T>`/`Result<T, E>`, while the | |
| 130 | /// unchecked one returns `T` | |
| 131 | fn same_functions_modulo_safety<'tcx>( | |
| 132 | cx: &LateContext<'tcx>, | |
| 133 | checked_def_id: DefId, | |
| 134 | unchecked_def_id: DefId, | |
| 135 | unwrapped_ret_ty: Ty<'tcx>, | |
| 136 | ) -> bool { | |
| 137 | let hir_body = |def_id: DefId| -> Option<&'tcx Body<'tcx>> { cx.tcx.hir_maybe_body_owned_by(def_id.as_local()?) }; | |
| 138 | let fn_sig = |def_id| cx.tcx.fn_sig(def_id).skip_binder().skip_binder(); | |
| 139 | ||
| 140 | if match (hir_body(checked_def_id), hir_body(unchecked_def_id)) { | |
| 141 | // For local functions, we can get the parameter names. In that case, we want to make sure | |
| 142 | // that the latter are equal between the checked and unchecked versions. | |
| 143 | (Some(checked_body), Some(unchecked_body)) => { | |
| 144 | over(checked_body.params, unchecked_body.params, |p1, p2| { | |
| 145 | // We only allow simple params (plain bindings) for now, to stay on the safer side. | |
| 146 | if let PatKind::Binding(bm1, _, ident1, None) = p1.pat.kind | |
| 147 | && let PatKind::Binding(bm2, _, ident2, None) = p2.pat.kind | |
| 148 | { | |
| 149 | bm1 == bm2 && ident1 == ident2 | |
| 150 | } else { | |
| 151 | false | |
| 152 | } | |
| 153 | }) | |
| 154 | }, | |
| 155 | // For non-local functions, parameter names are not accessible. Oh well, we'll let it slip | |
| 156 | (None, None) => true, | |
| 157 | // If only one of the versions is non-local, then something weird happened. Bail just in case | |
| 158 | _ => false, | |
| 159 | } { | |
| 160 | // Check that the functions have identical signatures, apart from safety, and return type (see | |
| 161 | // below) | |
| 162 | let checked_fn_sig = fn_sig(checked_def_id); | |
| 163 | let unchecked_fn_sig = fn_sig(unchecked_def_id); | |
| 164 | ||
| 165 | (checked_fn_sig.safety() == Safety::Safe && unchecked_fn_sig.safety() == Safety::Unsafe) | |
| 166 | && checked_fn_sig.c_variadic() == unchecked_fn_sig.c_variadic() | |
| 167 | && checked_fn_sig.abi() == unchecked_fn_sig.abi() | |
| 168 | // NOTE: the reason we use `same_type_modulo_regions` all over the place here is that | |
| 169 | // the regions of different functions will be distinct, even if they are called the same | |
| 170 | && over(checked_fn_sig.inputs(), unchecked_fn_sig.inputs(), |ty1, ty2| { | |
| 171 | same_type_modulo_regions(*ty1, *ty2) | |
| 172 | }) | |
| 173 | // The checked version should return `Option<T>` or `Result<T, E>`, | |
| 174 | // and the unchecked version should return just `T` | |
| 175 | && same_type_modulo_regions(unchecked_fn_sig.output(), unwrapped_ret_ty) | |
| 176 | && option_or_result_arg_ty(cx, checked_fn_sig.output()) | |
| 177 | .is_some_and(|wrapped_ty| same_type_modulo_regions(wrapped_ty, unwrapped_ret_ty)) | |
| 178 | // Check that the visibilities are the same (for the purposes of replacing, it would be enough to have | |
| 179 | // the former _at least as_ visible as the latter, but we don't bother) | |
| 180 | && cx.tcx.visibility(unchecked_def_id) == cx.tcx.visibility(checked_def_id) | |
| 181 | } else { | |
| 182 | false | |
| 183 | } | |
| 184 | } | |
| 185 | ||
| 186 | pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, recv: &Expr<'_>, call_span: Span) { | |
| 187 | if expr.span.from_expansion() { | |
| 188 | return; | |
| 189 | } | |
| 190 | let expected_ret_ty = cx.typeck_results().expr_ty(expr); | |
| 191 | let (variant, checked_span, unchecked_sugg, unchecked_full_path) = match recv.kind { | |
| 192 | // Construct `Variant::Fn(_)`, if applicable. This is necessary for us to handle | |
| 193 | // functions like `std::str::from_utf8_unchecked`. | |
| 194 | ExprKind::Call(path, _) | |
| 195 | if let ExprKind::Path(qpath) = path.kind | |
| 196 | && let checked_ident = last_path_segment(&qpath).ident | |
| 197 | && let checked_def_id = path.res(cx).def_id() | |
| 198 | && let Some((unchecked_def_id, unchecked_ident)) = | |
| 199 | find_unchecked_sibling_fn(cx, checked_def_id, checked_ident) | |
| 200 | && same_functions_modulo_safety(cx, checked_def_id, unchecked_def_id, expected_ret_ty) => | |
| 201 | { | |
| 202 | let unchecked_full_path = cx.tcx.def_path_str(unchecked_def_id); | |
| 203 | ( | |
| 204 | Variant::Fn, | |
| 205 | checked_ident.span, | |
| 206 | if checked_ident.span == path.span { | |
| 207 | // replacing `bar(x)` with `bar_unchecked(x)` | |
| 208 | // `bar_unchecked` might not be in scope, so suggest the full path | |
| 209 | unchecked_full_path.clone() | |
| 210 | } else { | |
| 211 | // replacing `foo::bar(x)` with `foo::bar_unchecked(x)` | |
| 212 | // since the path is qualified, we can just replace the final segment | |
| 213 | unchecked_ident.to_string() | |
| 214 | }, | |
| 215 | unchecked_full_path, | |
| 216 | ) | |
| 217 | }, | |
| 218 | // We unfortunately must handle `A::a(&a)` and `a.a()` separately, this handles the | |
| 219 | // former | |
| 220 | ExprKind::Call(path, _) | |
| 221 | if let ExprKind::Path(qpath) = path.kind | |
| 222 | && let checked_ident = last_path_segment(&qpath).ident | |
| 223 | && let checked_def_id = path.res(cx).def_id() | |
| 224 | && let Some((unchecked, unchecked_ident)) = | |
| 225 | find_unchecked_sibling_method(cx, checked_def_id, checked_ident) | |
| 226 | && let ty::AssocKind::Fn { has_self, .. } = unchecked.kind | |
| 227 | && same_functions_modulo_safety(cx, checked_def_id, unchecked.def_id, expected_ret_ty) => | |
| 228 | { | |
| 229 | let unchecked_full_path = cx.tcx.def_path_str(unchecked.def_id); | |
| 230 | ( | |
| 231 | Variant::Assoc(AssocKind::new(has_self)), | |
| 232 | // since this is basically a method call, we only need to replace the method ident | |
| 233 | checked_ident.span, | |
| 234 | unchecked_ident.to_string(), | |
| 235 | unchecked_full_path, | |
| 236 | ) | |
| 237 | }, | |
| 238 | // ... And now the latter ^^ | |
| 239 | ExprKind::MethodCall(segment, _, _, _) | |
| 240 | if let checked_ident = segment.ident | |
| 241 | && let Some(checked_def_id) = cx.typeck_results().type_dependent_def_id(recv.hir_id) | |
| 242 | && let Some((unchecked, unchecked_ident)) = | |
| 243 | find_unchecked_sibling_method(cx, checked_def_id, checked_ident) | |
| 244 | && same_functions_modulo_safety(cx, checked_def_id, unchecked.def_id, expected_ret_ty) => | |
| 245 | { | |
| 246 | let unchecked_full_path = cx.tcx.def_path_str(unchecked.def_id); | |
| 247 | ( | |
| 248 | Variant::Assoc(AssocKind::Method), | |
| 249 | // since this is a method call, we only need to replace the method ident | |
| 250 | checked_ident.span, | |
| 251 | unchecked_ident.to_string(), | |
| 252 | unchecked_full_path, | |
| 253 | ) | |
| 254 | }, | |
| 255 | _ => return, | |
| 256 | }; | |
| 257 | ||
| 258 | if !is_from_proc_macro(cx, expr) { | |
| 259 | span_lint_and_then(cx, UNNECESSARY_UNWRAP_UNCHECKED, expr.span, variant.msg(), |diag| { | |
| 260 | let sugg = vec![ | |
| 261 | // replace the function with the unchecked version | |
| 262 | (checked_span, unchecked_sugg), | |
| 263 | // remove the call to `.unwrap_unchecked()` | |
| 264 | (call_span.with_lo(recv.span.hi()), String::new()), | |
| 265 | ]; | |
| 266 | diag.multipart_suggestion( | |
| 267 | format!("use `{unchecked_full_path}` instead, and remove the call to `.unwrap_unchecked()`"), | |
| 268 | sugg, | |
| 269 | // TODO: make this `MachineApplicable` when the function comes from std/alloc/core | |
| 270 | // The reasoning is that, if the function comes from std/alloc/core, its checked and unchecked are | |
| 271 | // pretty likely to have their semantics match. | |
| 272 | Applicability::MaybeIncorrect, | |
| 273 | ); | |
| 274 | }); | |
| 275 | } | |
| 276 | } |
src/tools/clippy/clippy_lints/src/minmax.rs+6-5| ... | ... | @@ -79,14 +79,15 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons |
| 79 | 79 | } |
| 80 | 80 | }, |
| 81 | 81 | ExprKind::MethodCall(path, receiver, args @ [_], _) => { |
| 82 | let m = match path.ident.name { | |
| 83 | sym::max => MinMax::Max, | |
| 84 | sym::min => MinMax::Min, | |
| 85 | _ => return None, | |
| 86 | }; | |
| 82 | 87 | if cx.typeck_results().expr_ty(receiver).is_floating_point() |
| 83 | 88 | || cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Ord) |
| 84 | 89 | { |
| 85 | match path.ident.name { | |
| 86 | sym::max => fetch_const(cx, expr.span.ctxt(), Some(receiver), args, MinMax::Max), | |
| 87 | sym::min => fetch_const(cx, expr.span.ctxt(), Some(receiver), args, MinMax::Min), | |
| 88 | _ => None, | |
| 89 | } | |
| 90 | fetch_const(cx, expr.span.ctxt(), Some(receiver), args, m) | |
| 90 | 91 | } else { |
| 91 | 92 | None |
| 92 | 93 | } |
src/tools/clippy/clippy_lints/src/misc_early/mod.rs+9-5| ... | ... | @@ -333,11 +333,15 @@ impl EarlyLintPass for MiscEarlyLints { |
| 333 | 333 | } |
| 334 | 334 | |
| 335 | 335 | fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { |
| 336 | if expr.span.in_external_macro(cx.sess().source_map()) { | |
| 337 | return; | |
| 338 | } | |
| 339 | ||
| 340 | if let ExprKind::Lit(lit) = expr.kind { | |
| 336 | // `check_lit` only lints integer literals and suffixed float literals. | |
| 337 | if let ExprKind::Lit(lit) = expr.kind | |
| 338 | && match lit.kind { | |
| 339 | token::LitKind::Integer => true, | |
| 340 | token::LitKind::Float => lit.suffix.is_some(), | |
| 341 | _ => false, | |
| 342 | } | |
| 343 | && !expr.span.in_external_macro(cx.sess().source_map()) | |
| 344 | { | |
| 341 | 345 | MiscEarlyLints::check_lit(cx, lit, expr.span); |
| 342 | 346 | } |
| 343 | 347 | } |
src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use itertools::Itertools; |
| 4 | 4 | use rustc_ast::ast::{Pat, PatKind}; |
| 5 | 5 | use rustc_lint::EarlyContext; |
| ... | ... | @@ -59,7 +59,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { |
| 59 | 59 | .iter() |
| 60 | 60 | .filter_map(|f| match f.pat.kind { |
| 61 | 61 | PatKind::Wild => None, |
| 62 | _ => f.span.get_source_text(cx), | |
| 62 | _ => f.span.get_text(cx), | |
| 63 | 63 | }) |
| 64 | 64 | .format(", "), |
| 65 | 65 | )); |
src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 3 | 3 | use clippy_utils::paths::{PathNS, lookup_path_str}; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::def::Res; |
| 7 | 7 | use rustc_hir::def_id::DefIdMap; |
| ... | ... | @@ -78,7 +78,7 @@ impl LateLintPass<'_> for ImportRename { |
| 78 | 78 | && let Some(name) = self.renames.get(&id) |
| 79 | 79 | // Remove semicolon since it is not present for nested imports |
| 80 | 80 | && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';') |
| 81 | && let Some(snip) = span_without_semi.get_source_text(cx) | |
| 81 | && let Some(snip) = span_without_semi.get_text(cx) | |
| 82 | 82 | && let Some(import) = match snip.split_once(" as ") { |
| 83 | 83 | None => Some(snip.as_str()), |
| 84 | 84 | Some((import, rename)) => { |
src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs+2-2| ... | ... | @@ -109,7 +109,7 @@ fn should_lint<'tcx>( |
| 109 | 109 | // Is there a call to `DebugStruct::debug_struct`? Do lint if there is. |
| 110 | 110 | let mut has_debug_struct = false; |
| 111 | 111 | |
| 112 | for_each_expr(cx, block, |expr| { | |
| 112 | for_each_expr(cx.tcx, block, |expr| { | |
| 113 | 113 | if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { |
| 114 | 114 | let recv_ty = typeck_results.expr_ty(recv).peel_refs(); |
| 115 | 115 | |
| ... | ... | @@ -166,7 +166,7 @@ fn check_struct<'tcx>( |
| 166 | 166 | let mut has_direct_field_access = false; |
| 167 | 167 | let mut field_accesses = FxHashSet::default(); |
| 168 | 168 | |
| 169 | for_each_expr(cx, block, |expr| { | |
| 169 | for_each_expr(cx.tcx, block, |expr| { | |
| 170 | 170 | if let ExprKind::Field(target, ident) = expr.kind |
| 171 | 171 | && let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs() |
| 172 | 172 | && target_ty == self_ty |
src/tools/clippy/clippy_lints/src/missing_inline.rs+28-123| ... | ... | @@ -1,8 +1,6 @@ |
| 1 | use clippy_utils::diagnostics::{span_lint, span_lint_hir}; | |
| 2 | use rustc_hir::def_id::DefId; | |
| 3 | use rustc_hir::{self as hir, Attribute, find_attr}; | |
| 4 | use rustc_lint::{LateContext, LateLintPass, LintContext}; | |
| 5 | use rustc_middle::ty::AssocContainer; | |
| 1 | use clippy_utils::diagnostics::span_lint; | |
| 2 | use rustc_hir::{ImplItem, ImplItemKind, Item, ItemKind, OwnerId, TraitFn, TraitItem, TraitItemKind, find_attr}; | |
| 3 | use rustc_lint::{LateContext, LateLintPass}; | |
| 6 | 4 | use rustc_session::config::CrateType; |
| 7 | 5 | use rustc_session::declare_lint_pass; |
| 8 | 6 | use rustc_span::Span; |
| ... | ... | @@ -66,134 +64,41 @@ declare_clippy_lint! { |
| 66 | 64 | |
| 67 | 65 | declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]); |
| 68 | 66 | |
| 69 | fn check_missing_inline_attrs( | |
| 70 | cx: &LateContext<'_>, | |
| 71 | attrs: &[Attribute], | |
| 72 | sp: Span, | |
| 73 | desc: &'static str, | |
| 74 | hir_id: Option<hir::HirId>, | |
| 75 | ) { | |
| 76 | if !find_attr!(attrs, Inline(..)) { | |
| 77 | let msg = format!("missing `#[inline]` for {desc}"); | |
| 78 | if let Some(hir_id) = hir_id { | |
| 79 | span_lint_hir(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, hir_id, sp, msg); | |
| 80 | } else { | |
| 81 | span_lint(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, msg); | |
| 82 | } | |
| 67 | fn check(cx: &LateContext<'_>, item: OwnerId, sp: Span) { | |
| 68 | if cx.effective_visibilities.is_exported(item.def_id) | |
| 69 | && !find_attr!(cx.tcx.hir_attrs(item.into()), Inline(..)) | |
| 70 | // Rust `inline` doesn't mean anything with external linkage. | |
| 71 | && !cx.tcx.codegen_fn_attrs(item.def_id).contains_extern_indicator() | |
| 72 | && !cx.tcx.crate_types().iter().any(|&t| matches!(t, CrateType::ProcMacro)) | |
| 73 | && !sp.in_external_macro(cx.tcx.sess.source_map()) | |
| 74 | { | |
| 75 | span_lint( | |
| 76 | cx, | |
| 77 | MISSING_INLINE_IN_PUBLIC_ITEMS, | |
| 78 | sp, | |
| 79 | "missing `#[inline]` on a publicly callable function", | |
| 80 | ); | |
| 83 | 81 | } |
| 84 | 82 | } |
| 85 | 83 | |
| 86 | 84 | impl<'tcx> LateLintPass<'tcx> for MissingInline { |
| 87 | fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { | |
| 88 | if it.span.in_external_macro(cx.sess().source_map()) { | |
| 89 | return; | |
| 90 | } | |
| 91 | ||
| 92 | if cx | |
| 93 | .tcx | |
| 94 | .crate_types() | |
| 95 | .iter() | |
| 96 | .any(|t: &CrateType| matches!(t, CrateType::ProcMacro)) | |
| 97 | { | |
| 98 | return; | |
| 99 | } | |
| 100 | ||
| 101 | if !cx.effective_visibilities.is_exported(it.owner_id.def_id) { | |
| 102 | return; | |
| 103 | } | |
| 104 | match it.kind { | |
| 105 | hir::ItemKind::Fn { .. } => { | |
| 106 | if fn_is_externally_exported(cx, it.owner_id.to_def_id()) { | |
| 107 | return; | |
| 108 | } | |
| 109 | ||
| 110 | let desc = "a function"; | |
| 111 | let attrs = cx.tcx.hir_attrs(it.hir_id()); | |
| 112 | check_missing_inline_attrs(cx, attrs, it.span, desc, None); | |
| 113 | }, | |
| 114 | hir::ItemKind::Trait { items: trait_items, .. } => { | |
| 115 | // note: we need to check if the trait is exported so we can't use | |
| 116 | // `LateLintPass::check_trait_item` here. | |
| 117 | for &tit in trait_items { | |
| 118 | let tit_ = cx.tcx.hir_trait_item(tit); | |
| 119 | match tit_.kind { | |
| 120 | hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {}, | |
| 121 | hir::TraitItemKind::Fn(..) => { | |
| 122 | if cx.tcx.defaultness(tit.owner_id).has_value() { | |
| 123 | // trait method with default body needs inline in case | |
| 124 | // an impl is not provided | |
| 125 | let desc = "a default trait method"; | |
| 126 | let item = cx.tcx.hir_trait_item(tit); | |
| 127 | let attrs = cx.tcx.hir_attrs(item.hir_id()); | |
| 128 | check_missing_inline_attrs(cx, attrs, item.span, desc, Some(tit.hir_id())); | |
| 129 | } | |
| 130 | }, | |
| 131 | } | |
| 132 | } | |
| 133 | }, | |
| 134 | hir::ItemKind::Const(..) | |
| 135 | | hir::ItemKind::Enum(..) | |
| 136 | | hir::ItemKind::Macro(..) | |
| 137 | | hir::ItemKind::Mod(..) | |
| 138 | | hir::ItemKind::Static(..) | |
| 139 | | hir::ItemKind::Struct(..) | |
| 140 | | hir::ItemKind::TraitAlias(..) | |
| 141 | | hir::ItemKind::GlobalAsm { .. } | |
| 142 | | hir::ItemKind::TyAlias(..) | |
| 143 | | hir::ItemKind::Union(..) | |
| 144 | | hir::ItemKind::ExternCrate(..) | |
| 145 | | hir::ItemKind::ForeignMod { .. } | |
| 146 | | hir::ItemKind::Impl { .. } | |
| 147 | | hir::ItemKind::Use(..) => {}, | |
| 85 | fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { | |
| 86 | if let ItemKind::Fn { .. } = it.kind { | |
| 87 | check(cx, it.owner_id, it.span); | |
| 148 | 88 | } |
| 149 | 89 | } |
| 150 | 90 | |
| 151 | fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { | |
| 152 | if impl_item.span.in_external_macro(cx.sess().source_map()) | |
| 153 | || cx | |
| 154 | .tcx | |
| 155 | .crate_types() | |
| 156 | .iter() | |
| 157 | .any(|t: &CrateType| matches!(t, CrateType::ProcMacro)) | |
| 91 | fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { | |
| 92 | if let TraitItemKind::Fn(_, f) = item.kind | |
| 93 | && let TraitFn::Provided(_) = f | |
| 158 | 94 | { |
| 159 | return; | |
| 95 | check(cx, item.owner_id, item.span); | |
| 160 | 96 | } |
| 97 | } | |
| 161 | 98 | |
| 162 | // If the item being implemented is not exported, then we don't need #[inline] | |
| 163 | if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) { | |
| 164 | return; | |
| 165 | } | |
| 166 | ||
| 167 | let desc = match impl_item.kind { | |
| 168 | hir::ImplItemKind::Fn(..) => "a method", | |
| 169 | hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => return, | |
| 170 | }; | |
| 171 | ||
| 172 | let assoc_item = cx.tcx.associated_item(impl_item.owner_id); | |
| 173 | let container_id = assoc_item.container_id(cx.tcx); | |
| 174 | let trait_def_id = match assoc_item.container { | |
| 175 | AssocContainer::Trait => Some(container_id), | |
| 176 | AssocContainer::TraitImpl(_) => Some(cx.tcx.impl_trait_id(container_id)), | |
| 177 | AssocContainer::InherentImpl => None, | |
| 178 | }; | |
| 179 | ||
| 180 | if let Some(trait_def_id) = trait_def_id | |
| 181 | && trait_def_id.is_local() | |
| 182 | && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) | |
| 183 | { | |
| 184 | // If a trait is being implemented for an item, and the | |
| 185 | // trait is not exported, we don't need #[inline] | |
| 186 | return; | |
| 99 | fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { | |
| 100 | if let ImplItemKind::Fn(..) = item.kind { | |
| 101 | check(cx, item.owner_id, item.span); | |
| 187 | 102 | } |
| 188 | ||
| 189 | let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); | |
| 190 | check_missing_inline_attrs(cx, attrs, impl_item.span, desc, None); | |
| 191 | 103 | } |
| 192 | 104 | } |
| 193 | ||
| 194 | /// Checks if this function is externally exported, where #[inline] wouldn't have the desired effect | |
| 195 | /// and a rustc warning would be triggered, see #15301 | |
| 196 | fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool { | |
| 197 | let attrs = cx.tcx.codegen_fn_attrs(def_id); | |
| 198 | attrs.contains_extern_indicator() | |
| 199 | } |
src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs+1-1| ... | ... | @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; |
| 6 | 6 | use rustc_span::Span; |
| 7 | 7 | |
| 8 | 8 | use clippy_utils::diagnostics::span_lint; |
| 9 | use clippy_utils::source::SpanRangeExt; | |
| 9 | use clippy_utils::source::SpanExt; | |
| 10 | 10 | |
| 11 | 11 | declare_clippy_lint! { |
| 12 | 12 | /// ### What it does |
src/tools/clippy/clippy_lints/src/mutex_atomic.rs+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::res::MaybeDef; |
| 3 | use clippy_utils::source::{IntoSpan, SpanRangeExt}; | |
| 3 | use clippy_utils::source::{IntoSpan, SpanExt}; | |
| 4 | 4 | use clippy_utils::sugg::Sugg; |
| 5 | 5 | use clippy_utils::ty::ty_from_hir_ty; |
| 6 | 6 | use rustc_errors::{Applicability, Diag}; |
src/tools/clippy/clippy_lints/src/needless_else.rs+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::source::{IntoSpan, SpanRangeExt}; | |
| 2 | use clippy_utils::source::{IntoSpan, SpanExt}; | |
| 3 | 3 | use rustc_ast::ast::{Expr, ExprKind}; |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_lint::{EarlyContext, EarlyLintPass}; |
| ... | ... | @@ -43,7 +43,7 @@ impl EarlyLintPass for NeedlessElse { |
| 43 | 43 | && !else_clause.span.from_expansion() |
| 44 | 44 | && block.stmts.is_empty() |
| 45 | 45 | && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx) |
| 46 | && range.clone().check_source_text(cx, |src| { | |
| 46 | && range.clone().check_text(cx, |src| { | |
| 47 | 47 | // Ignore else blocks that contain comments or #[cfg]s |
| 48 | 48 | !src.contains(['/', '#']) |
| 49 | 49 | }) |
src/tools/clippy/clippy_lints/src/needless_ifs.rs+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::higher::If; |
| 3 | 3 | use clippy_utils::is_from_proc_macro; |
| 4 | use clippy_utils::source::{SpanRangeExt, walk_span_to_context}; | |
| 4 | use clippy_utils::source::{SpanExt, walk_span_to_context}; | |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::{ExprKind, Stmt, StmtKind}; |
| 7 | 7 | use rustc_lint::{LateContext, LateLintPass, LintContext}; |
| ... | ... | @@ -48,7 +48,7 @@ impl LateLintPass<'_> for NeedlessIfs { |
| 48 | 48 | && block.stmts.is_empty() |
| 49 | 49 | && block.expr.is_none() |
| 50 | 50 | && !expr.span.in_external_macro(cx.sess().source_map()) |
| 51 | && then.span.check_source_text(cx, |src| { | |
| 51 | && then.span.check_text(cx, |src| { | |
| 52 | 52 | // Ignore |
| 53 | 53 | // - empty macro expansions |
| 54 | 54 | // - empty reptitions in macro expansions |
| ... | ... | @@ -58,7 +58,7 @@ impl LateLintPass<'_> for NeedlessIfs { |
| 58 | 58 | .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace() || ch == b'\x0b') |
| 59 | 59 | }) |
| 60 | 60 | && let Some(cond_span) = walk_span_to_context(cond.span, expr.span.ctxt()) |
| 61 | && let Some(cond_snippet) = cond_span.get_source_text(cx) | |
| 61 | && let Some(cond_snippet) = cond_span.get_text(cx) | |
| 62 | 62 | && !is_from_proc_macro(cx, expr) |
| 63 | 63 | { |
| 64 | 64 | span_lint_and_sugg( |
src/tools/clippy/clippy_lints/src/needless_late_init.rs+349-196| ... | ... | @@ -1,16 +1,19 @@ |
| 1 | use clippy_config::Conf; | |
| 1 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 3 | use clippy_utils::res::MaybeResPath; |
| 3 | use clippy_utils::source::{SourceText, SpanRangeExt, snippet}; | |
| 4 | use clippy_utils::source::snippet_with_applicability; | |
| 4 | 5 | use clippy_utils::ty::needs_ordered_drop; |
| 5 | 6 | use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; |
| 6 | 7 | use core::ops::ControlFlow; |
| 7 | 8 | use rustc_errors::{Applicability, MultiSpan}; |
| 8 | 9 | use rustc_hir::{ |
| 9 | BindingMode, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind, | |
| 10 | BindingMode, Block, Expr, ExprKind, HirId, HirIdMap, HirIdSet, LetStmt, LocalSource, MatchSource, Node, Pat, | |
| 11 | PatKind, Stmt, StmtKind, | |
| 10 | 12 | }; |
| 11 | 13 | use rustc_lint::{LateContext, LateLintPass}; |
| 12 | use rustc_session::declare_lint_pass; | |
| 14 | use rustc_session::impl_lint_pass; | |
| 13 | 15 | use rustc_span::Span; |
| 16 | use std::borrow::Cow; | |
| 14 | 17 | |
| 15 | 18 | declare_clippy_lint! { |
| 16 | 19 | /// ### What it does |
| ... | ... | @@ -61,17 +64,126 @@ declare_clippy_lint! { |
| 61 | 64 | "late initializations that can be replaced by a `let` statement with an initializer" |
| 62 | 65 | } |
| 63 | 66 | |
| 64 | declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]); | |
| 67 | impl_lint_pass!(NeedlessLateInit<'_> => [NEEDLESS_LATE_INIT]); | |
| 65 | 68 | |
| 66 | fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool { | |
| 67 | for_each_expr(cx, stmt, |e| { | |
| 68 | if matches!(e.kind, ExprKind::Assign(..)) { | |
| 69 | ControlFlow::Break(()) | |
| 70 | } else { | |
| 71 | ControlFlow::Continue(()) | |
| 69 | pub struct NeedlessLateInit<'tcx> { | |
| 70 | check_grouped_late_init: bool, | |
| 71 | grouped_late_inits: Vec<(HirId, HirIdMap<GroupedLateInit<'tcx>>)>, | |
| 72 | } | |
| 73 | ||
| 74 | impl<'tcx> NeedlessLateInit<'tcx> { | |
| 75 | pub fn new(conf: &'static Conf) -> Self { | |
| 76 | Self { | |
| 77 | check_grouped_late_init: conf.check_grouped_late_init, | |
| 78 | grouped_late_inits: Vec::default(), | |
| 72 | 79 | } |
| 73 | }) | |
| 74 | .is_some() | |
| 80 | } | |
| 81 | ||
| 82 | fn check_if_or_match( | |
| 83 | &mut self, | |
| 84 | cx: &LateContext<'tcx>, | |
| 85 | local_stmt: &'tcx LetStmt<'tcx>, | |
| 86 | block: &'tcx Block<'tcx>, | |
| 87 | binding_id: HirId, | |
| 88 | usage: Usage<'tcx>, | |
| 89 | exprs: impl IntoIterator<Item = &'tcx Expr<'tcx>>, | |
| 90 | ) { | |
| 91 | let mut assigns: Vec<LocalAssignGroup<'tcx>> = Vec::new(); | |
| 92 | for expr in exprs { | |
| 93 | let ty = cx.typeck_results().expr_ty(expr); | |
| 94 | if ty.is_never() { | |
| 95 | continue; | |
| 96 | } | |
| 97 | if !ty.is_unit() { | |
| 98 | return; | |
| 99 | } | |
| 100 | ||
| 101 | let Some(assign_group) = LocalAssignGroup::new(cx, expr) else { | |
| 102 | return; | |
| 103 | }; | |
| 104 | ||
| 105 | if let Some(last_group) = assigns.last() | |
| 106 | && !assign_group.is_parallel(last_group) | |
| 107 | { | |
| 108 | return; | |
| 109 | } | |
| 110 | ||
| 111 | assigns.push(assign_group); | |
| 112 | } | |
| 113 | ||
| 114 | let Some(first_group) = assigns.first() else { | |
| 115 | return; | |
| 116 | }; | |
| 117 | // If there are multiple assignments grouped together, lazyly check them after processing the block. | |
| 118 | if first_group.0.len() > 1 { | |
| 119 | if self.check_grouped_late_init { | |
| 120 | let late_inits = if let Some((hir_id, late_inits)) = self.grouped_late_inits.last_mut() | |
| 121 | && *hir_id == block.hir_id | |
| 122 | { | |
| 123 | late_inits | |
| 124 | } else { | |
| 125 | &mut self.grouped_late_inits.push_mut((block.hir_id, HirIdMap::default())).1 | |
| 126 | }; | |
| 127 | ||
| 128 | let mut decls = HirIdMap::default(); | |
| 129 | decls.insert(binding_id, local_stmt); | |
| 130 | late_inits.insert(usage.expr.hir_id, GroupedLateInit { usage, assigns, decls }); | |
| 131 | } | |
| 132 | ||
| 133 | return; | |
| 134 | } | |
| 135 | ||
| 136 | if first_group.0[0].lhs_id == binding_id { | |
| 137 | span_lint_and_then( | |
| 138 | cx, | |
| 139 | NEEDLESS_LATE_INIT, | |
| 140 | local_stmt.span, | |
| 141 | "unneeded late initialization", | |
| 142 | |diag| { | |
| 143 | let mut suggestions = vec![]; | |
| 144 | for group in assigns { | |
| 145 | suggestions.extend( | |
| 146 | group | |
| 147 | .0 | |
| 148 | .iter() | |
| 149 | .flat_map(|assign| { | |
| 150 | let rhs_span = assign.rhs.span.source_callsite(); | |
| 151 | let mut spans = vec![assign.span.until(rhs_span)]; | |
| 152 | ||
| 153 | if rhs_span.hi() != assign.span.hi() { | |
| 154 | spans.push(rhs_span.shrink_to_hi().with_hi(assign.span.hi())); | |
| 155 | } | |
| 156 | ||
| 157 | spans | |
| 158 | }) | |
| 159 | .map(|span| (span, String::new())), | |
| 160 | ); | |
| 161 | } | |
| 162 | ||
| 163 | suggestions.push((local_stmt.span, String::new())); | |
| 164 | let mut applicability = Applicability::MachineApplicable; | |
| 165 | let let_snippet = local_snippet_without_semicolon(cx, local_stmt, &mut applicability); | |
| 166 | suggestions.push((usage.span.shrink_to_lo(), format!("{let_snippet} = "))); | |
| 167 | if usage.needs_semi { | |
| 168 | suggestions.push((usage.span.shrink_to_hi(), ";".to_owned())); | |
| 169 | } | |
| 170 | let binding_name = cx.tcx.hir_name(binding_id); | |
| 171 | let descriptor = if matches!(usage.expr.kind, ExprKind::If(..)) { | |
| 172 | "branches" | |
| 173 | } else { | |
| 174 | "`match` arms" | |
| 175 | }; | |
| 176 | diag.multipart_suggestion( | |
| 177 | format!( | |
| 178 | "move the declaration `{binding_name}` here and remove the assignments from the {descriptor}", | |
| 179 | ), | |
| 180 | suggestions, | |
| 181 | applicability, | |
| 182 | ); | |
| 183 | }, | |
| 184 | ); | |
| 185 | } | |
| 186 | } | |
| 75 | 187 | } |
| 76 | 188 | |
| 77 | 189 | fn contains_let(cond: &Expr<'_>) -> bool { |
| ... | ... | @@ -99,112 +211,35 @@ fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { |
| 99 | 211 | } |
| 100 | 212 | |
| 101 | 213 | #[derive(Debug)] |
| 102 | struct LocalAssign { | |
| 214 | struct LocalAssign<'tcx> { | |
| 103 | 215 | lhs_id: HirId, |
| 104 | rhs_span: Span, | |
| 216 | rhs: &'tcx Expr<'tcx>, | |
| 105 | 217 | span: Span, |
| 106 | 218 | } |
| 107 | 219 | |
| 108 | impl LocalAssign { | |
| 109 | fn from_expr(expr: &Expr<'_>, span: Span) -> Option<Self> { | |
| 220 | impl<'tcx> LocalAssign<'tcx> { | |
| 221 | fn new(expr: &'tcx Expr<'tcx>, span: Span) -> Option<Self> { | |
| 110 | 222 | if expr.span.from_expansion() { |
| 111 | 223 | return None; |
| 112 | 224 | } |
| 113 | 225 | |
| 114 | if let ExprKind::Assign(lhs, rhs, _) = expr.kind { | |
| 115 | if lhs.span.from_expansion() { | |
| 116 | return None; | |
| 117 | } | |
| 118 | ||
| 119 | Some(Self { | |
| 226 | if let ExprKind::Assign(lhs, rhs, _) = expr.kind | |
| 227 | && !lhs.span.from_expansion() | |
| 228 | { | |
| 229 | return Some(Self { | |
| 120 | 230 | lhs_id: lhs.res_local_id()?, |
| 121 | rhs_span: rhs.span.source_callsite(), | |
| 231 | rhs, | |
| 122 | 232 | span, |
| 123 | }) | |
| 124 | } else { | |
| 125 | None | |
| 126 | } | |
| 127 | } | |
| 128 | ||
| 129 | fn new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, binding_id: HirId) -> Option<LocalAssign> { | |
| 130 | let assign = match expr.kind { | |
| 131 | ExprKind::Block(Block { expr: Some(expr), .. }, _) => Self::from_expr(expr, expr.span), | |
| 132 | ExprKind::Block(block, _) => { | |
| 133 | if let Some((last, other_stmts)) = block.stmts.split_last() | |
| 134 | && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind | |
| 135 | ||
| 136 | && let assign = Self::from_expr(expr, last.span)? | |
| 137 | ||
| 138 | // avoid visiting if not needed | |
| 139 | && assign.lhs_id == binding_id | |
| 140 | && other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt)) | |
| 141 | { | |
| 142 | Some(assign) | |
| 143 | } else { | |
| 144 | None | |
| 145 | } | |
| 146 | }, | |
| 147 | ExprKind::Assign(..) => Self::from_expr(expr, expr.span), | |
| 148 | _ => None, | |
| 149 | }?; | |
| 150 | ||
| 151 | if assign.lhs_id == binding_id { | |
| 152 | Some(assign) | |
| 153 | } else { | |
| 154 | None | |
| 155 | } | |
| 156 | } | |
| 157 | } | |
| 158 | ||
| 159 | fn assignment_suggestions<'tcx>( | |
| 160 | cx: &LateContext<'tcx>, | |
| 161 | binding_id: HirId, | |
| 162 | exprs: impl IntoIterator<Item = &'tcx Expr<'tcx>>, | |
| 163 | ) -> Option<(Applicability, Vec<(Span, String)>)> { | |
| 164 | let mut assignments = Vec::new(); | |
| 165 | ||
| 166 | for expr in exprs { | |
| 167 | let ty = cx.typeck_results().expr_ty(expr); | |
| 168 | ||
| 169 | if ty.is_never() { | |
| 170 | continue; | |
| 171 | } | |
| 172 | if !ty.is_unit() { | |
| 173 | return None; | |
| 233 | }); | |
| 174 | 234 | } |
| 175 | 235 | |
| 176 | let assign = LocalAssign::new(cx, expr, binding_id)?; | |
| 177 | ||
| 178 | assignments.push(assign); | |
| 179 | } | |
| 180 | ||
| 181 | let suggestions = assignments | |
| 182 | .iter() | |
| 183 | .flat_map(|assignment| { | |
| 184 | let mut spans = vec![assignment.span.until(assignment.rhs_span)]; | |
| 185 | ||
| 186 | if assignment.rhs_span.hi() != assignment.span.hi() { | |
| 187 | spans.push(assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi())); | |
| 188 | } | |
| 189 | ||
| 190 | spans | |
| 191 | }) | |
| 192 | .map(|span| (span, String::new())) | |
| 193 | .collect::<Vec<(Span, String)>>(); | |
| 194 | ||
| 195 | match suggestions.len() { | |
| 196 | // All of `exprs` are never types | |
| 197 | // https://github.com/rust-lang/rust-clippy/issues/8911 | |
| 198 | 0 => None, | |
| 199 | 1 => Some((Applicability::MachineApplicable, suggestions)), | |
| 200 | // multiple suggestions don't work with rustfix in multipart_suggest | |
| 201 | // https://github.com/rust-lang/rustfix/issues/141 | |
| 202 | _ => Some((Applicability::Unspecified, suggestions)), | |
| 236 | None | |
| 203 | 237 | } |
| 204 | 238 | } |
| 205 | 239 | |
| 240 | #[derive(Debug)] | |
| 206 | 241 | struct Usage<'tcx> { |
| 207 | stmt: &'tcx Stmt<'tcx>, | |
| 242 | span: Span, | |
| 208 | 243 | expr: &'tcx Expr<'tcx>, |
| 209 | 244 | needs_semi: bool, |
| 210 | 245 | } |
| ... | ... | @@ -226,20 +261,34 @@ fn first_usage<'tcx>( |
| 226 | 261 | .find(|&stmt| is_local_used(cx, stmt, binding_id)) |
| 227 | 262 | .and_then(|stmt| match stmt.kind { |
| 228 | 263 | StmtKind::Expr(expr) => Some(Usage { |
| 229 | stmt, | |
| 264 | span: stmt.span, | |
| 230 | 265 | expr, |
| 231 | 266 | needs_semi: true, |
| 232 | 267 | }), |
| 233 | 268 | StmtKind::Semi(expr) => Some(Usage { |
| 234 | stmt, | |
| 269 | span: stmt.span, | |
| 235 | 270 | expr, |
| 236 | 271 | needs_semi: false, |
| 237 | 272 | }), |
| 238 | 273 | _ => None, |
| 239 | 274 | }) |
| 275 | .or_else(|| { | |
| 276 | block | |
| 277 | .expr | |
| 278 | .filter(|expr| is_local_used(cx, *expr, binding_id)) | |
| 279 | .map(|expr| Usage { | |
| 280 | span: expr.span, | |
| 281 | expr, | |
| 282 | needs_semi: true, | |
| 283 | }) | |
| 284 | }) | |
| 240 | 285 | } |
| 241 | 286 | |
| 242 | fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option<SourceText> { | |
| 287 | fn local_snippet_without_semicolon<'a>( | |
| 288 | cx: &LateContext<'_>, | |
| 289 | local: &LetStmt<'_>, | |
| 290 | applicability: &mut Applicability, | |
| 291 | ) -> Cow<'a, str> { | |
| 243 | 292 | let span = local.span.with_hi(match local.ty { |
| 244 | 293 | // let <pat>: <ty>; |
| 245 | 294 | // ~~~~~~~~~~~~~~~ |
| ... | ... | @@ -249,105 +298,70 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> |
| 249 | 298 | None => local.pat.span.hi(), |
| 250 | 299 | }); |
| 251 | 300 | |
| 252 | span.get_source_text(cx) | |
| 301 | snippet_with_applicability(cx, span, "..", applicability) | |
| 253 | 302 | } |
| 254 | 303 | |
| 255 | fn check<'tcx>( | |
| 256 | cx: &LateContext<'tcx>, | |
| 257 | local: &'tcx LetStmt<'tcx>, | |
| 258 | local_stmt: &'tcx Stmt<'tcx>, | |
| 259 | block: &'tcx Block<'tcx>, | |
| 260 | binding_id: HirId, | |
| 261 | ) -> Option<()> { | |
| 262 | let usage = first_usage(cx, binding_id, local_stmt.hir_id, block)?; | |
| 263 | let binding_name = cx.tcx.hir_opt_name(binding_id)?; | |
| 264 | let let_snippet = local_snippet_without_semicolon(cx, local)?; | |
| 265 | ||
| 266 | match usage.expr.kind { | |
| 267 | ExprKind::Assign(..) => { | |
| 268 | let assign = LocalAssign::new(cx, usage.expr, binding_id)?; | |
| 269 | let mut msg_span = MultiSpan::from_spans(vec![local_stmt.span, assign.span]); | |
| 270 | msg_span.push_span_label(local_stmt.span, "created here"); | |
| 271 | msg_span.push_span_label(assign.span, "initialised here"); | |
| 272 | ||
| 273 | span_lint_and_then( | |
| 274 | cx, | |
| 275 | NEEDLESS_LATE_INIT, | |
| 276 | msg_span, | |
| 277 | "unneeded late initialization", | |
| 278 | |diag| { | |
| 279 | diag.multipart_suggestion( | |
| 280 | format!("move the declaration `{binding_name}` here"), | |
| 281 | vec![ | |
| 282 | (local_stmt.span, String::new()), | |
| 283 | ( | |
| 284 | assign.span, | |
| 285 | let_snippet.to_owned() + " = " + &snippet(cx, assign.rhs_span, ".."), | |
| 286 | ), | |
| 287 | ], | |
| 288 | Applicability::MachineApplicable, | |
| 289 | ); | |
| 290 | }, | |
| 291 | ); | |
| 292 | }, | |
| 293 | ExprKind::If(cond, then_expr, Some(else_expr)) if !contains_let(cond) => { | |
| 294 | let (applicability, mut suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?; | |
| 295 | ||
| 296 | span_lint_and_then( | |
| 297 | cx, | |
| 298 | NEEDLESS_LATE_INIT, | |
| 299 | local_stmt.span, | |
| 300 | "unneeded late initialization", | |
| 301 | |diag| { | |
| 302 | suggestions.push((local_stmt.span, String::new())); | |
| 303 | suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = "))); | |
| 304 | ||
| 305 | if usage.needs_semi { | |
| 306 | suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned())); | |
| 304 | #[derive(Debug)] | |
| 305 | struct LocalAssignGroup<'tcx>(Vec<LocalAssign<'tcx>>); | |
| 306 | ||
| 307 | impl<'tcx> LocalAssignGroup<'tcx> { | |
| 308 | fn new(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<Self> { | |
| 309 | match expr.kind { | |
| 310 | ExprKind::Block(Block { expr: Some(expr), .. }, _) | |
| 311 | if let Some(assign) = LocalAssign::new(expr, expr.span) => | |
| 312 | { | |
| 313 | Some(LocalAssignGroup(vec![assign])) | |
| 314 | }, | |
| 315 | ExprKind::Block(Block { expr: None, stmts, .. }, _) => { | |
| 316 | let mut assign_group = Vec::new(); | |
| 317 | // Avoid cases when the assignee is used or reassigned in the subsequent assignments | |
| 318 | let mut used_locals = HirIdSet::default(); | |
| 319 | for stmt in stmts.iter().rev() { | |
| 320 | if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind | |
| 321 | && let Some(assign) = LocalAssign::new(expr, stmt.span) | |
| 322 | && !used_locals.contains(&assign.lhs_id) | |
| 323 | { | |
| 324 | used_locals.insert(assign.lhs_id); | |
| 325 | for_each_expr(cx.tcx, assign.rhs, |e| { | |
| 326 | if let Some(id) = e.res_local_id() { | |
| 327 | used_locals.insert(id); | |
| 328 | } | |
| 329 | ControlFlow::<()>::Continue(()) | |
| 330 | }); | |
| 331 | assign_group.push(assign); | |
| 332 | continue; | |
| 307 | 333 | } |
| 308 | 334 | |
| 309 | diag.multipart_suggestion( | |
| 310 | format!( | |
| 311 | "move the declaration `{binding_name}` here and remove the assignments from the branches" | |
| 312 | ), | |
| 313 | suggestions, | |
| 314 | applicability, | |
| 315 | ); | |
| 316 | }, | |
| 317 | ); | |
| 318 | }, | |
| 319 | ExprKind::Match(_, arms, MatchSource::Normal) => { | |
| 320 | let (applicability, mut suggestions) = | |
| 321 | assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?; | |
| 322 | ||
| 323 | span_lint_and_then( | |
| 324 | cx, | |
| 325 | NEEDLESS_LATE_INIT, | |
| 326 | local_stmt.span, | |
| 327 | "unneeded late initialization", | |
| 328 | |diag| { | |
| 329 | suggestions.push((local_stmt.span, String::new())); | |
| 330 | suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = "))); | |
| 331 | ||
| 332 | if usage.needs_semi { | |
| 333 | suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned())); | |
| 334 | } | |
| 335 | break; | |
| 336 | } | |
| 337 | if assign_group.is_empty() { | |
| 338 | None | |
| 339 | } else { | |
| 340 | Some(LocalAssignGroup(assign_group)) | |
| 341 | } | |
| 342 | }, | |
| 343 | ExprKind::Assign(..) if let Some(assign) = LocalAssign::new(expr, expr.span) => { | |
| 344 | Some(LocalAssignGroup(vec![assign])) | |
| 345 | }, | |
| 346 | _ => None, | |
| 347 | } | |
| 348 | } | |
| 335 | 349 | |
| 336 | diag.multipart_suggestion( | |
| 337 | format!("move the declaration `{binding_name}` here and remove the assignments from the `match` arms"), | |
| 338 | suggestions, | |
| 339 | applicability, | |
| 340 | ); | |
| 341 | }, | |
| 342 | ); | |
| 343 | }, | |
| 344 | _ => {}, | |
| 350 | /// Checks if the assignments in `self` and `other` are parallel, i.e. they have the same number | |
| 351 | /// of assignments and the same assignees in the same order. | |
| 352 | fn is_parallel(&self, other: &Self) -> bool { | |
| 353 | self.0.len() == other.0.len() && self.0.iter().zip(other.0.iter()).all(|(a, b)| a.lhs_id == b.lhs_id) | |
| 345 | 354 | } |
| 355 | } | |
| 346 | 356 | |
| 347 | Some(()) | |
| 357 | #[derive(Debug)] | |
| 358 | struct GroupedLateInit<'tcx> { | |
| 359 | usage: Usage<'tcx>, | |
| 360 | assigns: Vec<LocalAssignGroup<'tcx>>, | |
| 361 | decls: HirIdMap<&'tcx LetStmt<'tcx>>, | |
| 348 | 362 | } |
| 349 | 363 | |
| 350 | impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { | |
| 364 | impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit<'tcx> { | |
| 351 | 365 | fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { |
| 352 | 366 | let mut parents = cx.tcx.hir_parent_iter(local.hir_id); |
| 353 | 367 | if let LetStmt { |
| ... | ... | @@ -362,8 +376,147 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { |
| 362 | 376 | } = local |
| 363 | 377 | && let Some((_, Node::Stmt(local_stmt))) = parents.next() |
| 364 | 378 | && let Some((_, Node::Block(block))) = parents.next() |
| 379 | && let Some(usage) = first_usage(cx, *binding_id, local_stmt.hir_id, block) | |
| 365 | 380 | { |
| 366 | check(cx, local, local_stmt, block, *binding_id); | |
| 381 | if self.check_grouped_late_init | |
| 382 | && let Some((hir_id, late_inits)) = self.grouped_late_inits.last_mut() | |
| 383 | && *hir_id == block.hir_id | |
| 384 | && let Some(late_init) = late_inits.get_mut(&usage.expr.hir_id) | |
| 385 | { | |
| 386 | late_init.decls.insert(*binding_id, local); | |
| 387 | return; | |
| 388 | } | |
| 389 | ||
| 390 | match usage.expr.kind { | |
| 391 | ExprKind::Assign(..) | |
| 392 | if let Some(assign) = LocalAssign::new(usage.expr, usage.expr.span) | |
| 393 | && assign.lhs_id == *binding_id => | |
| 394 | { | |
| 395 | let mut applicability = Applicability::MachineApplicable; | |
| 396 | let let_snippet = local_snippet_without_semicolon(cx, local, &mut applicability); | |
| 397 | let binding_name = cx.tcx.hir_name(*binding_id); | |
| 398 | let mut msg_span = MultiSpan::from_spans(vec![local_stmt.span, assign.span]); | |
| 399 | msg_span.push_span_label(local_stmt.span, "created here"); | |
| 400 | msg_span.push_span_label(assign.span, "initialised here"); | |
| 401 | ||
| 402 | span_lint_and_then( | |
| 403 | cx, | |
| 404 | NEEDLESS_LATE_INIT, | |
| 405 | msg_span, | |
| 406 | "unneeded late initialization", | |
| 407 | |diag| { | |
| 408 | let mut applicability = Applicability::MachineApplicable; | |
| 409 | let rhs_snippet = snippet_with_applicability( | |
| 410 | cx, | |
| 411 | assign.rhs.span.source_callsite(), | |
| 412 | "..", | |
| 413 | &mut applicability, | |
| 414 | ); | |
| 415 | diag.multipart_suggestion( | |
| 416 | format!("move the declaration `{binding_name}` here"), | |
| 417 | vec![ | |
| 418 | (local_stmt.span, String::new()), | |
| 419 | (assign.span, format!("{let_snippet} = {rhs_snippet}")), | |
| 420 | ], | |
| 421 | applicability, | |
| 422 | ); | |
| 423 | }, | |
| 424 | ); | |
| 425 | }, | |
| 426 | ExprKind::If(cond, then_expr, Some(mut else_expr)) if !contains_let(cond) => { | |
| 427 | // Flatten multiple if branches | |
| 428 | let mut exprs = vec![then_expr]; | |
| 429 | while let ExprKind::If(cond, then, Some(else_)) = else_expr.kind { | |
| 430 | if contains_let(cond) { | |
| 431 | return; | |
| 432 | } | |
| 433 | exprs.push(then); | |
| 434 | else_expr = else_; | |
| 435 | } | |
| 436 | exprs.push(else_expr); | |
| 437 | self.check_if_or_match(cx, local, block, *binding_id, usage, exprs); | |
| 438 | }, | |
| 439 | ExprKind::Match(_, arms, MatchSource::Normal) => { | |
| 440 | self.check_if_or_match(cx, local, block, *binding_id, usage, arms.iter().map(|arm| arm.body)); | |
| 441 | }, | |
| 442 | _ => {}, | |
| 443 | } | |
| 444 | } | |
| 445 | } | |
| 446 | ||
| 447 | fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { | |
| 448 | if self.check_grouped_late_init | |
| 449 | && let Some((_, late_inits)) = self.grouped_late_inits.pop_if(|(hir_id, _)| *hir_id == block.hir_id) | |
| 450 | { | |
| 451 | 'outer: for (_, late_init) in late_inits { | |
| 452 | if late_init.decls.len() < late_init.assigns[0].0.len() { | |
| 453 | continue; | |
| 454 | } | |
| 455 | ||
| 456 | let mut suggestions = vec![]; | |
| 457 | for assign in &late_init.assigns[0].0 { | |
| 458 | if let Some(local) = late_init.decls.get(&assign.lhs_id) | |
| 459 | // If the local has a type annotation, skip it since removing the annotation might cause type | |
| 460 | // inference issues while annotating the tuple makes the suggestion harder to read. | |
| 461 | && local.ty.is_none() | |
| 462 | { | |
| 463 | suggestions.push((local.span, String::new())); | |
| 464 | } else { | |
| 465 | continue 'outer; | |
| 466 | } | |
| 467 | } | |
| 468 | ||
| 469 | span_lint_and_then( | |
| 470 | cx, | |
| 471 | NEEDLESS_LATE_INIT, | |
| 472 | late_init.usage.span, | |
| 473 | "unneeded late initialization", | |
| 474 | |diag| { | |
| 475 | let mut applicability = Applicability::MachineApplicable; | |
| 476 | for group in &late_init.assigns { | |
| 477 | let rhs_snippet = group | |
| 478 | .0 | |
| 479 | .iter() | |
| 480 | .rev() | |
| 481 | .map(|assign| { | |
| 482 | snippet_with_applicability( | |
| 483 | cx, | |
| 484 | assign.rhs.span.source_callsite(), | |
| 485 | "..", | |
| 486 | &mut applicability, | |
| 487 | ) | |
| 488 | }) | |
| 489 | .intersperse(", ".into()) | |
| 490 | .collect::<String>(); | |
| 491 | suggestions.push(( | |
| 492 | group.0.last().unwrap().span.to(group.0[0].span), | |
| 493 | format!("({rhs_snippet})"), | |
| 494 | )); | |
| 495 | } | |
| 496 | let let_snippet = late_init.assigns[0] | |
| 497 | .0 | |
| 498 | .iter() | |
| 499 | .rev() | |
| 500 | .map(|assign| cx.tcx.hir_name(assign.lhs_id).to_string()) | |
| 501 | .intersperse(", ".to_owned()) | |
| 502 | .collect::<String>(); | |
| 503 | suggestions.push((late_init.usage.span.shrink_to_lo(), format!("let ({let_snippet}) = "))); | |
| 504 | if late_init.usage.needs_semi { | |
| 505 | suggestions.push((late_init.usage.span.shrink_to_hi(), ";".to_owned())); | |
| 506 | } | |
| 507 | let descriptor = if matches!(late_init.usage.expr.kind, ExprKind::If(..)) { | |
| 508 | "branches" | |
| 509 | } else { | |
| 510 | "`match` arms" | |
| 511 | }; | |
| 512 | diag.multipart_suggestion( | |
| 513 | format!("move the declarations here and remove the assignments from the {descriptor}"), | |
| 514 | suggestions, | |
| 515 | applicability, | |
| 516 | ); | |
| 517 | }, | |
| 518 | ); | |
| 519 | } | |
| 367 | 520 | } |
| 368 | 521 | } |
| 369 | 522 | } |
src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs+2-3| ... | ... | @@ -1,7 +1,6 @@ |
| 1 | 1 | use super::needless_pass_by_value::requires_exact_signature; |
| 2 | 2 | use clippy_config::Conf; |
| 3 | 3 | use clippy_utils::diagnostics::span_lint_hir_and_then; |
| 4 | use clippy_utils::source::HasSession as _; | |
| 5 | 4 | use clippy_utils::visitors::for_each_expr; |
| 6 | 5 | use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; |
| 7 | 6 | use core::ops::ControlFlow; |
| ... | ... | @@ -207,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { |
| 207 | 206 | // We retrieve all the closures declared in the function because they will not be found |
| 208 | 207 | // by `euv::Delegate`. |
| 209 | 208 | let mut closures: FxIndexSet<LocalDefId> = FxIndexSet::default(); |
| 210 | for_each_expr(cx, body, |expr| { | |
| 209 | for_each_expr(cx.tcx, body, |expr| { | |
| 211 | 210 | if let ExprKind::Closure(closure) = expr.kind { |
| 212 | 211 | closures.insert(closure.def_id); |
| 213 | 212 | } |
| ... | ... | @@ -269,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { |
| 269 | 268 | // If the argument is never used mutably, we emit the warning. |
| 270 | 269 | let sp = input.span; |
| 271 | 270 | if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind { |
| 272 | let Some(after_mut_span) = cx.sess().source_map().span_extend_to_prev_str( | |
| 271 | let Some(after_mut_span) = cx.tcx.sess.source_map().span_extend_to_prev_str( | |
| 273 | 272 | inner_ty.ty.span.shrink_to_lo(), |
| 274 | 273 | "mut", |
| 275 | 274 | true, |
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::res::{MaybeDef, MaybeResPath}; |
| 3 | use clippy_utils::source::{SpanRangeExt, snippet}; | |
| 3 | use clippy_utils::source::{SpanExt, snippet}; | |
| 4 | 4 | use clippy_utils::ty::{implements_trait, implements_trait_with_env_from_iter, is_copy}; |
| 5 | 5 | use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; |
| 6 | 6 | use clippy_utils::{is_self, peel_hir_ty_options, strip_pat_refs, sym}; |
| ... | ... | @@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { |
| 248 | 248 | for (span, suggestion) in clone_spans { |
| 249 | 249 | diag.span_suggestion( |
| 250 | 250 | span, |
| 251 | span.get_source_text(cx).map_or_else( | |
| 251 | span.get_text(cx).map_or_else( | |
| 252 | 252 | || "change the call to".to_owned(), |
| 253 | 253 | |src| format!("change `{src}` to"), |
| 254 | 254 | ), |
| ... | ... | @@ -275,7 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { |
| 275 | 275 | for (span, suggestion) in clone_spans { |
| 276 | 276 | diag.span_suggestion( |
| 277 | 277 | span, |
| 278 | span.get_source_text(cx).map_or_else( | |
| 278 | span.get_text(cx).map_or_else( | |
| 279 | 279 | || "change the call to".to_owned(), |
| 280 | 280 | |src| format!("change `{src}` to"), |
| 281 | 281 | ), |
src/tools/clippy/clippy_lints/src/no_effect.rs+4-4| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; |
| 2 | 2 | use clippy_utils::res::MaybeResPath; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::ty::{expr_type_is_certain, has_drop}; |
| 5 | 5 | use clippy_utils::{in_automatically_derived, is_inside_always_const_context, is_lint_allowed, peel_blocks}; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -278,8 +278,8 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { |
| 278 | 278 | if let ExprKind::Index(..) = &expr.kind { |
| 279 | 279 | if !is_inside_always_const_context(cx.tcx, expr.hir_id) |
| 280 | 280 | && let [arr, func] = &*reduced |
| 281 | && let Some(arr) = arr.span.get_source_text(cx) | |
| 282 | && let Some(func) = func.span.get_source_text(cx) | |
| 281 | && let Some(arr) = arr.span.get_text(cx) | |
| 282 | && let Some(func) = func.span.get_text(cx) | |
| 283 | 283 | { |
| 284 | 284 | span_lint_hir_and_then( |
| 285 | 285 | cx, |
| ... | ... | @@ -300,7 +300,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { |
| 300 | 300 | } else { |
| 301 | 301 | let mut snippet = String::new(); |
| 302 | 302 | for e in reduced { |
| 303 | if let Some(snip) = e.span.get_source_text(cx) { | |
| 303 | if let Some(snip) = e.span.get_text(cx) { | |
| 304 | 304 | snippet.push_str(&snip); |
| 305 | 305 | snippet.push_str("; "); |
| 306 | 306 | } else { |
src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs+3-3| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; | |
| 2 | use clippy_utils::source::{SpanExt, snippet_with_applicability}; | |
| 3 | 3 | use clippy_utils::sym; |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_hir::{Expr, ExprKind}; |
| ... | ... | @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { |
| 52 | 52 | && param.span.eq_ctxt(expr.span) |
| 53 | 53 | && param |
| 54 | 54 | .span |
| 55 | .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) | |
| 55 | .check_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) | |
| 56 | 56 | { |
| 57 | 57 | show_error(cx, param); |
| 58 | 58 | } |
| ... | ... | @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { |
| 65 | 65 | && param.span.eq_ctxt(expr.span) |
| 66 | 66 | && param |
| 67 | 67 | .span |
| 68 | .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) | |
| 68 | .check_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) | |
| 69 | 69 | { |
| 70 | 70 | show_error(cx, param); |
| 71 | 71 | } |
src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs+1-1| ... | ... | @@ -198,7 +198,7 @@ impl LazyInfo { |
| 198 | 198 | |
| 199 | 199 | // visit body to collect `Lazy::new` calls |
| 200 | 200 | let mut new_fn_calls = FxIndexMap::default(); |
| 201 | for_each_expr::<(), ()>(cx, body, |ex| { | |
| 201 | for_each_expr::<(), ()>(cx.tcx, body, |ex| { | |
| 202 | 202 | if let Some((fn_did, call_span)) = fn_def_id_and_span_from_body(cx, ex, body_id) |
| 203 | 203 | && paths::ONCE_CELL_SYNC_LAZY_NEW.matches(cx, fn_did) |
| 204 | 204 | { |
src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_config::types::MacroMatcher; |
| 3 | 3 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 4 | use clippy_utils::source::{SourceText, SpanRangeExt}; | |
| 4 | use clippy_utils::source::{SourceText, SpanExt}; | |
| 5 | 5 | use rustc_ast::ast; |
| 6 | 6 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
| 7 | 7 | use rustc_errors::Applicability; |
| ... | ... | @@ -129,7 +129,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace |
| 129 | 129 | if let ExpnKind::Macro(MacroKind::Bang, mac_name) = expn_data.kind |
| 130 | 130 | && let name = mac_name.as_str() |
| 131 | 131 | && let Some(&braces) = mac_braces.macro_braces.get(name) |
| 132 | && let Some(snip) = expn_data.call_site.get_source_text(cx) | |
| 132 | && let Some(snip) = expn_data.call_site.get_text(cx) | |
| 133 | 133 | // we must check only invocation sites |
| 134 | 134 | // https://github.com/rust-lang/rust-clippy/issues/7422 |
| 135 | 135 | && let Some(macro_args_str) = snip.strip_prefix(name).and_then(|snip| snip.strip_prefix('!')) |
src/tools/clippy/clippy_lints/src/octal_escapes.rs+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use rustc_ast::token::LitKind; |
| 4 | 4 | use rustc_ast::{Expr, ExprKind}; |
| 5 | 5 | use rustc_errors::Applicability; |
| ... | ... | @@ -86,7 +86,7 @@ impl EarlyLintPass for OctalEscapes { |
| 86 | 86 | |
| 87 | 87 | // Last check to make sure the source text matches what we read from the string. |
| 88 | 88 | // Macros are involved somehow if this doesn't match. |
| 89 | if span.check_source_text(cx, |src| match *src.as_bytes() { | |
| 89 | if span.check_text(cx, |src| match *src.as_bytes() { | |
| 90 | 90 | [b'\\', b'0', lo] => lo == c_lo, |
| 91 | 91 | [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo, |
| 92 | 92 | _ => false, |
src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::msrvs::Msrv; |
| 3 | 3 | use clippy_utils::qualify_min_const_fn::is_stable_const_fn; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use clippy_utils::ty::implements_trait; |
| 6 | 6 | use clippy_utils::visitors::for_each_expr_without_closures; |
| 7 | 7 | use clippy_utils::{binop_traits, eq_expr_value, is_in_const_context, trait_ref_of_method}; |
| ... | ... | @@ -74,8 +74,8 @@ pub(super) fn check<'tcx>( |
| 74 | 74 | expr.span, |
| 75 | 75 | "manual implementation of an assign operation", |
| 76 | 76 | |diag| { |
| 77 | if let Some(snip_a) = assignee.span.get_source_text(cx) | |
| 78 | && let Some(snip_r) = rhs.span.get_source_text(cx) | |
| 77 | if let Some(snip_a) = assignee.span.get_text(cx) | |
| 78 | && let Some(snip_r) = rhs.span.get_text(cx) | |
| 79 | 79 | { |
| 80 | 80 | diag.span_suggestion( |
| 81 | 81 | expr.span, |
src/tools/clippy/clippy_lints/src/operators/decimal_bitwise_operands.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_help; |
| 2 | 2 | use clippy_utils::numeric_literal; |
| 3 | 3 | use clippy_utils::numeric_literal::NumericLiteral; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use rustc_ast::LitKind; |
| 6 | 6 | use rustc_data_structures::packed::Pu128; |
| 7 | 7 | use rustc_hir::{BinOpKind, Expr, ExprKind}; |
| ... | ... | @@ -40,7 +40,7 @@ fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { |
| 40 | 40 | if let LitKind::Int(Pu128(val), _) = lit.node |
| 41 | 41 | && !is_single_digit(val) |
| 42 | 42 | && !is_power_of_twoish(val) |
| 43 | && let Some(src) = lit.span.get_source_text(cx) | |
| 43 | && let Some(src) = lit.span.get_text(cx) | |
| 44 | 44 | && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) |
| 45 | 45 | && num_lit.is_decimal() |
| 46 | 46 | { |
src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs+3-3| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use clippy_utils::{eq_expr_value, sugg}; |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_hir as hir; |
| ... | ... | @@ -43,8 +43,8 @@ fn lint_misrefactored_assign_op( |
| 43 | 43 | expr.span, |
| 44 | 44 | "variable appears on both sides of an assignment operation", |
| 45 | 45 | |diag| { |
| 46 | if let Some(snip_a) = assignee.span.get_source_text(cx) | |
| 47 | && let Some(snip_r) = rhs_other.span.get_source_text(cx) | |
| 46 | if let Some(snip_a) = assignee.span.get_text(cx) | |
| 47 | && let Some(snip_r) = rhs_other.span.get_text(cx) | |
| 48 | 48 | { |
| 49 | 49 | let a = &sugg::Sugg::hir(cx, assignee, ".."); |
| 50 | 50 | let r = &sugg::Sugg::hir(cx, rhs, ".."); |
src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs+1-1| ... | ... | @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { |
| 64 | 64 | |
| 65 | 65 | fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { |
| 66 | 66 | let mut panics = Vec::new(); |
| 67 | let _: Option<!> = for_each_expr(cx, body.value, |e| { | |
| 67 | let _: Option<!> = for_each_expr(cx.tcx, body.value, |e| { | |
| 68 | 68 | let Some(macro_call) = root_macro_call_first_node(cx, e) else { |
| 69 | 69 | return ControlFlow::Continue(Descend::Yes); |
| 70 | 70 | }; |
src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs+4-4| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | 2 | use clippy_utils::res::{MaybeDef, MaybeResPath}; |
| 3 | use clippy_utils::source::{SpanRangeExt, snippet}; | |
| 3 | use clippy_utils::source::{SpanExt, snippet}; | |
| 4 | 4 | use clippy_utils::sym; |
| 5 | 5 | use rustc_ast::{LitKind, StrStyle}; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -73,7 +73,7 @@ impl PathbufPushSearcher<'_> { |
| 73 | 73 | && let Some(arg) = self.arg |
| 74 | 74 | && let ExprKind::Lit(x) = arg.kind |
| 75 | 75 | && let LitKind::Str(_, StrStyle::Cooked) = x.node |
| 76 | && let Some(s) = arg.span.get_source_text(cx) | |
| 76 | && let Some(s) = arg.span.get_text(cx) | |
| 77 | 77 | { |
| 78 | 78 | Some(format!(" = PathBuf::from({s});")) |
| 79 | 79 | } else { |
| ... | ... | @@ -83,8 +83,8 @@ impl PathbufPushSearcher<'_> { |
| 83 | 83 | |
| 84 | 84 | fn gen_pathbuf_join(&self, cx: &LateContext<'_>) -> Option<String> { |
| 85 | 85 | let arg = self.arg?; |
| 86 | let arg_str = arg.span.get_source_text(cx)?; | |
| 87 | let init_val = self.init_val.span.get_source_text(cx)?; | |
| 86 | let arg_str = arg.span.get_text(cx)?; | |
| 87 | let init_val = self.init_val.span.get_text(cx)?; | |
| 88 | 88 | Some(format!(" = {init_val}.join({arg_str});")) |
| 89 | 89 | } |
| 90 | 90 |
src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs+4-4| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use super::PTR_ARG; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_hir_and_then; |
| 3 | 3 | use clippy_utils::res::MaybeResPath; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_expr_use_or_unification_node, is_lint_allowed, sym}; |
| 6 | 6 | use hir::LifetimeKind; |
| 7 | 7 | use rustc_abi::ExternAbi; |
| ... | ... | @@ -55,7 +55,7 @@ pub(super) fn check_body<'tcx>( |
| 55 | 55 | .chain(result.replacements.iter().map(|r| { |
| 56 | 56 | ( |
| 57 | 57 | r.expr_span, |
| 58 | format!("{}{}", r.self_span.get_source_text(cx).unwrap(), r.replacement), | |
| 58 | format!("{}{}", r.self_span.get_text(cx).unwrap(), r.replacement), | |
| 59 | 59 | ) |
| 60 | 60 | })) |
| 61 | 61 | .collect(), |
| ... | ... | @@ -156,7 +156,7 @@ impl fmt::Display for DerefTyDisplay<'_, '_> { |
| 156 | 156 | DerefTy::Path => f.write_str("Path"), |
| 157 | 157 | DerefTy::Slice(hir_ty, ty) => { |
| 158 | 158 | f.write_char('[')?; |
| 159 | match hir_ty.and_then(|s| s.get_source_text(self.0)) { | |
| 159 | match hir_ty.and_then(|s| s.get_text(self.0)) { | |
| 160 | 160 | Some(s) => f.write_str(&s)?, |
| 161 | 161 | None => ty.fmt(f)?, |
| 162 | 162 | } |
| ... | ... | @@ -279,7 +279,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( |
| 279 | 279 | diag.span_suggestion( |
| 280 | 280 | hir_ty.span, |
| 281 | 281 | "change this to", |
| 282 | match ty.span().get_source_text(cx) { | |
| 282 | match ty.span().get_text(cx) { | |
| 283 | 283 | Some(s) => format!("&{}{s}", mutability.prefix_str()), |
| 284 | 284 | None => format!("&{}{}", mutability.prefix_str(), args.type_at(1)), |
| 285 | 285 | }, |
src/tools/clippy/clippy_lints/src/question_mark.rs+8-1| ... | ... | @@ -629,6 +629,11 @@ fn is_inferred_ret_closure(expr: &Expr<'_>) -> bool { |
| 629 | 629 | |
| 630 | 630 | impl<'tcx> LateLintPass<'tcx> for QuestionMark { |
| 631 | 631 | fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { |
| 632 | // Cheap `let` check before the costlier lint level and const context queries. | |
| 633 | if !matches!(stmt.kind, StmtKind::Let(..)) { | |
| 634 | return; | |
| 635 | } | |
| 636 | ||
| 632 | 637 | if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) || !self.msrv.meets(cx, msrvs::QUESTION_MARK_OPERATOR) |
| 633 | 638 | { |
| 634 | 639 | return; |
| ... | ... | @@ -646,7 +651,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { |
| 646 | 651 | return; |
| 647 | 652 | } |
| 648 | 653 | |
| 649 | if !self.inside_try_block() | |
| 654 | // Cheap `if`/`match` check before the costlier lint level and const context queries. | |
| 655 | if matches!(expr.kind, ExprKind::If(..) | ExprKind::Match(..)) | |
| 656 | && !self.inside_try_block() | |
| 650 | 657 | && !is_in_const_context(cx) |
| 651 | 658 | && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) |
| 652 | 659 | && self.msrv.meets(cx, msrvs::QUESTION_MARK_OPERATOR) |
src/tools/clippy/clippy_lints/src/ranges.rs+32-25| ... | ... | @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; |
| 3 | 3 | use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; |
| 4 | 4 | use clippy_utils::msrvs::{self, Msrv}; |
| 5 | 5 | use clippy_utils::res::MaybeResPath; |
| 6 | use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; | |
| 6 | use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; | |
| 7 | 7 | use clippy_utils::sugg::Sugg; |
| 8 | 8 | use clippy_utils::ty::implements_trait; |
| 9 | 9 | use clippy_utils::{ |
| ... | ... | @@ -191,14 +191,21 @@ impl Ranges { |
| 191 | 191 | impl<'tcx> LateLintPass<'tcx> for Ranges { |
| 192 | 192 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { |
| 193 | 193 | if let ExprKind::Binary(ref op, l, r) = expr.kind |
| 194 | && matches!( | |
| 195 | op.node, | |
| 196 | BinOpKind::And | BinOpKind::BitAnd | BinOpKind::Or | BinOpKind::BitOr | |
| 197 | ) | |
| 194 | 198 | && self.msrv.meets(cx, msrvs::RANGE_CONTAINS) |
| 199 | && !is_in_const_context(cx) | |
| 195 | 200 | { |
| 196 | 201 | check_possible_range_contains(cx, op.node, l, r, expr, expr.span); |
| 197 | 202 | } |
| 198 | 203 | |
| 199 | check_exclusive_range_plus_one(cx, expr); | |
| 200 | check_inclusive_range_minus_one(cx, expr); | |
| 201 | check_reversed_empty_range(cx, expr); | |
| 204 | if let Some(range) = higher::Range::hir(cx, expr) { | |
| 205 | check_exclusive_range_plus_one(cx, expr, &range); | |
| 206 | check_inclusive_range_minus_one(cx, expr, &range); | |
| 207 | check_reversed_empty_range(cx, expr, &range); | |
| 208 | } | |
| 202 | 209 | } |
| 203 | 210 | } |
| 204 | 211 | |
| ... | ... | @@ -210,10 +217,6 @@ fn check_possible_range_contains( |
| 210 | 217 | expr: &Expr<'_>, |
| 211 | 218 | span: Span, |
| 212 | 219 | ) { |
| 213 | if is_in_const_context(cx) { | |
| 214 | return; | |
| 215 | } | |
| 216 | ||
| 217 | 220 | let combine_and = match op { |
| 218 | 221 | BinOpKind::And | BinOpKind::BitAnd => true, |
| 219 | 222 | BinOpKind::Or | BinOpKind::BitOr => false, |
| ... | ... | @@ -300,7 +303,7 @@ fn check_possible_range_contains( |
| 300 | 303 | if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind |
| 301 | 304 | && op == lhs_op.node |
| 302 | 305 | && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) |
| 303 | && new_span.check_source_text(cx, |src| { | |
| 306 | && new_span.check_text(cx, |src| { | |
| 304 | 307 | // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong |
| 305 | 308 | src.matches('(').count() == src.matches(')').count() |
| 306 | 309 | }) |
| ... | ... | @@ -481,54 +484,58 @@ fn can_switch_ranges<'tcx>( |
| 481 | 484 | } |
| 482 | 485 | |
| 483 | 486 | // exclusive range plus one: `x..(y+1)` |
| 484 | fn check_exclusive_range_plus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | |
| 487 | fn check_exclusive_range_plus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, range: &higher::Range<'tcx>) { | |
| 485 | 488 | check_range_switch( |
| 486 | 489 | cx, |
| 487 | 490 | expr, |
| 491 | range, | |
| 488 | 492 | RangeLimits::HalfOpen, |
| 489 | 493 | y_plus_one, |
| 490 | 494 | RANGE_PLUS_ONE, |
| 491 | 495 | "an inclusive range would be more readable", |
| 492 | "..=", | |
| 493 | 496 | ); |
| 494 | 497 | } |
| 495 | 498 | |
| 496 | 499 | // inclusive range minus one: `x..=(y-1)` |
| 497 | fn check_inclusive_range_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | |
| 500 | fn check_inclusive_range_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, range: &higher::Range<'tcx>) { | |
| 498 | 501 | check_range_switch( |
| 499 | 502 | cx, |
| 500 | 503 | expr, |
| 504 | range, | |
| 501 | 505 | RangeLimits::Closed, |
| 502 | 506 | y_minus_one, |
| 503 | 507 | RANGE_MINUS_ONE, |
| 504 | 508 | "an exclusive range would be more readable", |
| 505 | "..", | |
| 506 | 509 | ); |
| 507 | 510 | } |
| 508 | 511 | |
| 509 | 512 | /// Check for a `kind` of range in `expr`, check for `predicate` on the end, |
| 510 | /// and emit the `lint` with `msg` and the `operator`. | |
| 513 | /// and emit the `lint` with `msg`, suggesting the opposite range limits. | |
| 511 | 514 | fn check_range_switch<'tcx>( |
| 512 | 515 | cx: &LateContext<'tcx>, |
| 513 | 516 | expr: &'tcx Expr<'_>, |
| 517 | range: &higher::Range<'tcx>, | |
| 514 | 518 | kind: RangeLimits, |
| 515 | 519 | predicate: impl for<'hir> FnOnce(&Expr<'hir>) -> Option<&'hir Expr<'hir>>, |
| 516 | 520 | lint: &'static Lint, |
| 517 | 521 | msg: &'static str, |
| 518 | operator: &str, | |
| 519 | 522 | ) { |
| 520 | if let Some(range) = higher::Range::hir(cx, expr) | |
| 521 | && let higher::Range { | |
| 522 | start, | |
| 523 | end: Some(end), | |
| 524 | limits, | |
| 525 | span, | |
| 526 | } = range | |
| 523 | if let higher::Range { | |
| 524 | start, | |
| 525 | end: Some(end), | |
| 526 | limits, | |
| 527 | span, | |
| 528 | } = *range | |
| 527 | 529 | && span.can_be_used_for_suggestions() |
| 528 | 530 | && limits == kind |
| 529 | 531 | && let Some(y) = predicate(end) |
| 530 | 532 | && can_switch_ranges(cx, span.ctxt(), expr, kind, cx.typeck_results().expr_ty(y)) |
| 531 | 533 | { |
| 534 | // Suggest the opposite range limits to the ones being checked. | |
| 535 | let operator = match kind { | |
| 536 | RangeLimits::HalfOpen => "..=", | |
| 537 | RangeLimits::Closed => "..", | |
| 538 | }; | |
| 532 | 539 | span_lint_and_then(cx, lint, span, msg, |diag| { |
| 533 | 540 | let mut app = Applicability::MachineApplicable; |
| 534 | 541 | let start = start.map_or(String::new(), |x| { |
| ... | ... | @@ -550,7 +557,7 @@ fn check_range_switch<'tcx>( |
| 550 | 557 | } |
| 551 | 558 | } |
| 552 | 559 | |
| 553 | fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { | |
| 560 | fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>, range: &higher::Range<'_>) { | |
| 554 | 561 | fn inside_indexing_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { |
| 555 | 562 | matches!( |
| 556 | 563 | get_parent_expr(cx, expr), |
| ... | ... | @@ -580,12 +587,12 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { |
| 580 | 587 | } |
| 581 | 588 | } |
| 582 | 589 | |
| 583 | if let Some(higher::Range { | |
| 590 | if let higher::Range { | |
| 584 | 591 | start: Some(start), |
| 585 | 592 | end: Some(end), |
| 586 | 593 | limits, |
| 587 | 594 | span, |
| 588 | }) = higher::Range::hir(cx, expr) | |
| 595 | } = *range | |
| 589 | 596 | && let ty = cx.typeck_results().expr_ty(start) |
| 590 | 597 | && let ty::Int(_) | ty::Uint(_) = ty.kind() |
| 591 | 598 | && let ecx = ConstEvalCtxt::new(cx) |
src/tools/clippy/clippy_lints/src/raw_strings.rs+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | use clippy_utils::source::{SpanRangeExt, snippet_opt}; | |
| 3 | use clippy_utils::source::{SpanExt, snippet_opt}; | |
| 4 | 4 | use rustc_ast::ast::{Expr, ExprKind}; |
| 5 | 5 | use rustc_ast::token::LitKind; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -74,7 +74,7 @@ impl EarlyLintPass for RawStrings { |
| 74 | 74 | fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { |
| 75 | 75 | if let ExprKind::FormatArgs(format_args) = &expr.kind |
| 76 | 76 | && !format_args.span.in_external_macro(cx.sess().source_map()) |
| 77 | && format_args.span.check_source_text(cx, |src| src.starts_with('r')) | |
| 77 | && format_args.span.check_text(cx, |src| src.starts_with('r')) | |
| 78 | 78 | && let Some(str) = snippet_opt(cx.sess(), format_args.span) |
| 79 | 79 | && let count_hash = str.bytes().skip(1).take_while(|b| *b == b'#').count() |
| 80 | 80 | && let Some(str) = str.get(count_hash + 2..str.len() - count_hash - 1) |
| ... | ... | @@ -97,7 +97,7 @@ impl EarlyLintPass for RawStrings { |
| 97 | 97 | _ => return, |
| 98 | 98 | } |
| 99 | 99 | && !expr.span.in_external_macro(cx.sess().source_map()) |
| 100 | && expr.span.check_source_text(cx, |src| src.starts_with(prefix)) | |
| 100 | && expr.span.check_text(cx, |src| src.starts_with(prefix)) | |
| 101 | 101 | { |
| 102 | 102 | self.check_raw_string(cx, lit.symbol.as_str(), expr.span, prefix, max, lit.kind.descr()); |
| 103 | 103 | } |
src/tools/clippy/clippy_lints/src/redundant_clone.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; |
| 2 | 2 | use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage}; |
| 3 | 3 | use clippy_utils::res::MaybeDef; |
| 4 | use clippy_utils::source::SpanRangeExt; | |
| 4 | use clippy_utils::source::SpanExt; | |
| 5 | 5 | use clippy_utils::ty::{has_drop, is_copy, peel_and_count_ty_refs}; |
| 6 | 6 | use clippy_utils::{fn_has_unsatisfiable_preds, sym}; |
| 7 | 7 | use rustc_errors::Applicability; |
| ... | ... | @@ -214,7 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { |
| 214 | 214 | .unwrap_crate_local() |
| 215 | 215 | .lint_root; |
| 216 | 216 | |
| 217 | if let Some(snip) = span.get_source_text(cx) | |
| 217 | if let Some(snip) = span.get_text(cx) | |
| 218 | 218 | && let Some(dot) = snip.rfind('.') |
| 219 | 219 | { |
| 220 | 220 | let sugg_span = span.with_lo(span.lo() + BytePos(u32::try_from(dot).unwrap())); |
src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs+1-2| ... | ... | @@ -1,5 +1,4 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::HasSession; | |
| 3 | 2 | use rustc_errors::Applicability; |
| 4 | 3 | use rustc_hir::def::{DefKind, Res}; |
| 5 | 4 | use rustc_hir::{Item, ItemKind, UseKind}; |
| ... | ... | @@ -49,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { |
| 49 | 48 | && !cx.effective_visibilities.is_exported(item.owner_id.def_id) |
| 50 | 49 | && self.is_exported.last() == Some(&false) |
| 51 | 50 | && !is_ignorable_export(item) |
| 52 | && !item.span.in_external_macro(cx.sess().source_map()) | |
| 51 | && !item.span.in_external_macro(cx.tcx.sess.source_map()) | |
| 53 | 52 | { |
| 54 | 53 | let span = item |
| 55 | 54 | .kind |
src/tools/clippy/clippy_lints/src/redundant_test_prefix.rs+1-1| ... | ... | @@ -144,7 +144,7 @@ fn name_conflicts<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, fn_name: S |
| 144 | 144 | |
| 145 | 145 | // Also check that within the body of the function there is also no function call |
| 146 | 146 | // with the same name (since it will result in recursion) |
| 147 | for_each_expr(cx, body, |expr| { | |
| 147 | for_each_expr(cx.tcx, body, |expr| { | |
| 148 | 148 | if let ExprKind::Path(qpath) = &expr.kind |
| 149 | 149 | && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id() |
| 150 | 150 | && let Some(name) = tcx.opt_item_name(def_id) |
src/tools/clippy/clippy_lints/src/ref_patterns.rs+7-5| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use rustc_ast::ast::{BindingMode, Pat, PatKind}; | |
| 3 | use rustc_lint::{EarlyContext, EarlyLintPass}; | |
| 2 | use clippy_utils::in_automatically_derived; | |
| 3 | use rustc_hir::{BindingMode, Pat, PatKind}; | |
| 4 | use rustc_lint::{LateContext, LateLintPass}; | |
| 4 | 5 | use rustc_session::declare_lint_pass; |
| 5 | 6 | |
| 6 | 7 | declare_clippy_lint! { |
| ... | ... | @@ -29,10 +30,11 @@ declare_clippy_lint! { |
| 29 | 30 | |
| 30 | 31 | declare_lint_pass!(RefPatterns => [REF_PATTERNS]); |
| 31 | 32 | |
| 32 | impl EarlyLintPass for RefPatterns { | |
| 33 | fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { | |
| 34 | if let PatKind::Ident(BindingMode::REF, _, _) = pat.kind | |
| 33 | impl<'tcx> LateLintPass<'tcx> for RefPatterns { | |
| 34 | fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'tcx>) { | |
| 35 | if let PatKind::Binding(BindingMode::REF, _, _, _) = pat.kind | |
| 35 | 36 | && !pat.span.from_expansion() |
| 37 | && !in_automatically_derived(cx.tcx, pat.hir_id) | |
| 36 | 38 | { |
| 37 | 39 | #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] |
| 38 | 40 | span_lint_and_then(cx, REF_PATTERNS, pat.span, "usage of ref pattern", |diag| { |
src/tools/clippy/clippy_lints/src/regex.rs+2-2| ... | ... | @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; |
| 5 | 5 | use clippy_utils::paths; |
| 6 | 6 | use clippy_utils::paths::PathLookup; |
| 7 | 7 | use clippy_utils::res::MaybeQPath; |
| 8 | use clippy_utils::source::SpanRangeExt; | |
| 8 | use clippy_utils::source::SpanExt; | |
| 9 | 9 | use rustc_ast::ast::{LitKind, StrStyle}; |
| 10 | 10 | use rustc_hir::def_id::DefIdMap; |
| 11 | 11 | use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId}; |
| ... | ... | @@ -190,7 +190,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescape |
| 190 | 190 | }; |
| 191 | 191 | |
| 192 | 192 | if let Some((primary, auxiliary, kind)) = parts |
| 193 | && let Some(literal_snippet) = base.get_source_text(cx) | |
| 193 | && let Some(literal_snippet) = base.get_text(cx) | |
| 194 | 194 | && let Some(inner) = literal_snippet.get(offset as usize..) |
| 195 | 195 | // Only convert to native rustc spans if the parsed regex matches the |
| 196 | 196 | // source snippet exactly, to ensure the span offsets are correct |
src/tools/clippy/clippy_lints/src/returns/let_and_return.rs+1-1| ... | ... | @@ -67,7 +67,7 @@ pub(super) fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>) |
| 67 | 67 | } |
| 68 | 68 | } |
| 69 | 69 | fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { |
| 70 | for_each_expr(cx, expr, |e| { | |
| 70 | for_each_expr(cx.tcx, expr, |e| { | |
| 71 | 71 | if let Some(def_id) = fn_def_id(cx, e) |
| 72 | 72 | && cx |
| 73 | 73 | .tcx |
src/tools/clippy/clippy_lints/src/semicolon_block.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; |
| 6 | 6 | use rustc_lint::{LateContext, LateLintPass, LintContext}; |
| ... | ... | @@ -94,7 +94,7 @@ impl SemicolonBlock { |
| 94 | 94 | // ({ 0 }); // if we remove this `;`, this will parse as a `({ 0 })(5);` function call |
| 95 | 95 | // (5); |
| 96 | 96 | // } |
| 97 | if remove_span.check_source_text(cx, |src| src.contains(')')) { | |
| 97 | if remove_span.check_text(cx, |src| src.contains(')')) { | |
| 98 | 98 | return; |
| 99 | 99 | } |
| 100 | 100 |
src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs+1-1| ... | ... | @@ -127,7 +127,7 @@ fn find_insert_calls<'tcx>( |
| 127 | 127 | contains_expr: &OpExpr<'tcx>, |
| 128 | 128 | expr: &'tcx Expr<'_>, |
| 129 | 129 | ) -> Option<OpExpr<'tcx>> { |
| 130 | for_each_expr(cx, expr, |e| { | |
| 130 | for_each_expr(cx.tcx, expr, |e| { | |
| 131 | 131 | if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym::insert) |
| 132 | 132 | && SpanlessEq::new(cx).eq_expr(SyntaxContext::root(), contains_expr.receiver, insert_expr.receiver) |
| 133 | 133 | && SpanlessEq::new(cx).eq_expr(SyntaxContext::root(), contains_expr.value, insert_expr.value) |
src/tools/clippy/clippy_lints/src/shadow.rs+1-1| ... | ... | @@ -199,7 +199,7 @@ pub fn is_local_used_except<'tcx>( |
| 199 | 199 | id: HirId, |
| 200 | 200 | except: Option<HirId>, |
| 201 | 201 | ) -> bool { |
| 202 | for_each_expr(cx, visitable, |e| { | |
| 202 | for_each_expr(cx.tcx, visitable, |e| { | |
| 203 | 203 | if except.is_some_and(|it| it == e.hir_id) { |
| 204 | 204 | ControlFlow::Continue(Descend::No) |
| 205 | 205 | } else if e.res_local_id() == Some(id) { |
src/tools/clippy/clippy_lints/src/single_component_path_imports.rs+12-4| ... | ... | @@ -146,16 +146,24 @@ impl SingleComponentPathImports { |
| 146 | 146 | // ``` |
| 147 | 147 | let mut macros = Vec::new(); |
| 148 | 148 | |
| 149 | let mut import_usage_visitor = ImportUsageVisitor::default(); | |
| 150 | 149 | for item in items { |
| 151 | 150 | self.track_uses(item, &mut imports_reused_with_self, &mut single_use_usages, &mut macros); |
| 151 | } | |
| 152 | ||
| 153 | // Only walk the module's AST in search of `self::xxx` paths when there are single | |
| 154 | // component imports left to lint, as the visitor recurses into every nested item. | |
| 155 | single_use_usages.retain(|usage| !imports_reused_with_self.contains(&usage.name)); | |
| 156 | if single_use_usages.is_empty() { | |
| 157 | return; | |
| 158 | } | |
| 159 | ||
| 160 | let mut import_usage_visitor = ImportUsageVisitor::default(); | |
| 161 | for item in items { | |
| 152 | 162 | import_usage_visitor.visit_item(item); |
| 153 | 163 | } |
| 154 | 164 | |
| 155 | 165 | for usage in single_use_usages { |
| 156 | if !imports_reused_with_self.contains(&usage.name) | |
| 157 | && !import_usage_visitor.imports_referenced_with_self.contains(&usage.name) | |
| 158 | { | |
| 166 | if !import_usage_visitor.imports_referenced_with_self.contains(&usage.name) { | |
| 159 | 167 | self.found.entry(usage.item_id).or_default().push(usage); |
| 160 | 168 | } |
| 161 | 169 | } |
src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::higher::{Range, VecArgs}; |
| 3 | 3 | use clippy_utils::macros::root_macro_call_first_node; |
| 4 | use clippy_utils::source::{SpanRangeExt, snippet_with_context}; | |
| 4 | use clippy_utils::source::{SpanExt, snippet_with_context}; | |
| 5 | 5 | use clippy_utils::ty::implements_trait; |
| 6 | 6 | use clippy_utils::{is_no_std_crate, sym}; |
| 7 | 7 | use rustc_ast::{LitIntType, LitKind, RangeLimits, UintTy}; |
| ... | ... | @@ -91,7 +91,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { |
| 91 | 91 | return; |
| 92 | 92 | }; |
| 93 | 93 | |
| 94 | let Some(snippet) = span.get_source_text(cx) else { | |
| 94 | let Some(snippet) = span.get_text(cx) else { | |
| 95 | 95 | return; |
| 96 | 96 | }; |
| 97 | 97 | // `is_from_proc_macro` will skip any `vec![]`. Let's not! |
src/tools/clippy/clippy_lints/src/std_instead_of_core.rs+15-14| ... | ... | @@ -238,20 +238,21 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> |
| 238 | 238 | /// Does not catch individually moved items |
| 239 | 239 | fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: Msrv) -> bool { |
| 240 | 240 | loop { |
| 241 | if let Some(stability) = cx.tcx.lookup_stability(def_id) | |
| 242 | && let StabilityLevel::Stable { | |
| 243 | since, | |
| 244 | allowed_through_unstable_modules: None, | |
| 245 | } = stability.level | |
| 246 | { | |
| 247 | let stable = match since { | |
| 248 | StableSince::Version(v) => msrv.meets(cx, v), | |
| 249 | StableSince::Current => msrv.current(cx).is_none(), | |
| 250 | StableSince::Err(_) => false, | |
| 251 | }; | |
| 252 | ||
| 253 | if !stable { | |
| 254 | return false; | |
| 241 | if let Some(stability) = cx.tcx.lookup_stability(def_id) { | |
| 242 | match stability.level { | |
| 243 | // Workaround for items from `core::intrinsics` with a stable export in a different module. | |
| 244 | // Not that we ignore the `since` field as we are already accessing the item in question. | |
| 245 | StabilityLevel::Stable { | |
| 246 | allowed_through_unstable_modules: Some(_), | |
| 247 | .. | |
| 248 | } => return true, | |
| 249 | StabilityLevel::Stable { since, .. } => match since { | |
| 250 | StableSince::Version(v) if !msrv.meets(cx, v) => return false, | |
| 251 | StableSince::Current if msrv.current(cx).is_none() => return false, | |
| 252 | StableSince::Err(_) => return false, | |
| 253 | StableSince::Version(_) | StableSince::Current => {}, | |
| 254 | }, | |
| 255 | StabilityLevel::Unstable { .. } => return false, | |
| 255 | 256 | } |
| 256 | 257 | } |
| 257 | 258 |
src/tools/clippy/clippy_lints/src/string_patterns.rs+3-3| ... | ... | @@ -147,7 +147,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr< |
| 147 | 147 | |
| 148 | 148 | // We want to retrieve all the comparisons done. |
| 149 | 149 | // They are ordered in a nested way and so we need to traverse the AST to collect them all. |
| 150 | if for_each_expr(cx, body.value, |sub_expr| -> ControlFlow<(), Descend> { | |
| 150 | if for_each_expr(cx.tcx, body.value, |sub_expr| -> ControlFlow<(), Descend> { | |
| 151 | 151 | match sub_expr.kind { |
| 152 | 152 | ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => { |
| 153 | 153 | if left.res_local_id() == Some(binding) |
| ... | ... | @@ -230,13 +230,13 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns { |
| 230 | 230 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { |
| 231 | 231 | if !expr.span.from_expansion() |
| 232 | 232 | && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind |
| 233 | && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() | |
| 234 | && ty.is_str() | |
| 235 | 233 | && let method_name = method.ident.name |
| 236 | 234 | && let Some(&(_, pos)) = PATTERN_METHODS |
| 237 | 235 | .iter() |
| 238 | 236 | .find(|(array_method_name, _)| *array_method_name == method_name) |
| 239 | 237 | && let Some(arg) = args.get(pos) |
| 238 | && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() | |
| 239 | && ty.is_str() | |
| 240 | 240 | { |
| 241 | 241 | check_single_char_pattern_lint(cx, arg); |
| 242 | 242 |
src/tools/clippy/clippy_lints/src/trait_bounds.rs+3-6| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; |
| 3 | 3 | use clippy_utils::msrvs::{self, Msrv}; |
| 4 | use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; | |
| 4 | use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; | |
| 5 | 5 | use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; |
| 6 | 6 | use core::hash::{Hash, Hasher}; |
| 7 | 7 | use itertools::Itertools; |
| ... | ... | @@ -212,10 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { |
| 212 | 212 | bounds_span = bounds_span.to(bound.span); |
| 213 | 213 | } |
| 214 | 214 | |
| 215 | let fixed_trait_snippet = unique_traits | |
| 216 | .iter() | |
| 217 | .filter_map(|b| b.span.get_source_text(cx)) | |
| 218 | .join(" + "); | |
| 215 | let fixed_trait_snippet = unique_traits.iter().filter_map(|b| b.span.get_text(cx)).join(" + "); | |
| 219 | 216 | |
| 220 | 217 | span_lint_and_sugg( |
| 221 | 218 | cx, |
| ... | ... | @@ -451,7 +448,7 @@ fn rollup_traits<'cx, 'tcx>( |
| 451 | 448 | |
| 452 | 449 | let traits = comparable_bounds |
| 453 | 450 | .iter() |
| 454 | .filter_map(|&(_, span)| span.get_source_text(cx)) | |
| 451 | .filter_map(|&(_, span)| span.get_text(cx)) | |
| 455 | 452 | .join(" + "); |
| 456 | 453 | |
| 457 | 454 | span_lint_and_sugg( |
src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use std::borrow::Cow; |
| 2 | 2 | |
| 3 | 3 | use clippy_utils::diagnostics::span_lint_and_then; |
| 4 | use clippy_utils::source::{HasSession, SpanRangeExt as _}; | |
| 4 | use clippy_utils::source::SpanExt as _; | |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; |
| 7 | 7 | use rustc_lint::LateContext; |
| ... | ... | @@ -114,8 +114,8 @@ fn ty_cannot_be_named(ty: Ty<'_>) -> bool { |
| 114 | 114 | ) |
| 115 | 115 | } |
| 116 | 116 | |
| 117 | fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { | |
| 118 | span.with_source_text(sess, |name| { | |
| 117 | fn maybe_name_by_expr<'a>(cx: &LateContext<'_>, span: Span, default: &'a str) -> Cow<'a, str> { | |
| 118 | span.with_source_text(cx, |name| { | |
| 119 | 119 | (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into()) |
| 120 | 120 | }) |
| 121 | 121 | .flatten() |
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs+1-1| ... | ... | @@ -393,7 +393,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>( |
| 393 | 393 | } |
| 394 | 394 | |
| 395 | 395 | // this should roughly be the reverse of `block_parents_have_safety_comment` |
| 396 | if for_each_expr(cx, expr, |expr| match expr.kind { | |
| 396 | if for_each_expr(cx.tcx, expr, |expr| match expr.kind { | |
| 397 | 397 | hir::ExprKind::Block( |
| 398 | 398 | Block { |
| 399 | 399 | rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), |
src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs+15-26| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; | |
| 1 | use clippy_utils::diagnostics::span_lint_and_then; | |
| 2 | 2 | use rustc_hir::def_id::DefId; |
| 3 | 3 | use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; |
| 4 | 4 | use rustc_lint::{LateContext, LateLintPass}; |
| ... | ... | @@ -180,32 +180,21 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { |
| 180 | 180 | let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>(); |
| 181 | 181 | let arg_indices = get_args_to_check(cx, expr, args.len(), fn_mut_trait, ord_trait, partial_ord_trait); |
| 182 | 182 | for (i, trait_name) in arg_indices { |
| 183 | match check_arg(cx, args[i]) { | |
| 184 | Some((span, None)) => { | |
| 185 | span_lint( | |
| 186 | cx, | |
| 187 | UNIT_RETURN_EXPECTING_ORD, | |
| 188 | span, | |
| 189 | format!( | |
| 190 | "this closure returns \ | |
| 183 | if let Some((span, last_semi)) = check_arg(cx, args[i]) { | |
| 184 | span_lint_and_then( | |
| 185 | cx, | |
| 186 | UNIT_RETURN_EXPECTING_ORD, | |
| 187 | span, | |
| 188 | format!( | |
| 189 | "this closure returns \ | |
| 191 | 190 | the unit type which also implements {trait_name}" |
| 192 | ), | |
| 193 | ); | |
| 194 | }, | |
| 195 | Some((span, Some(last_semi))) => { | |
| 196 | span_lint_and_help( | |
| 197 | cx, | |
| 198 | UNIT_RETURN_EXPECTING_ORD, | |
| 199 | span, | |
| 200 | format!( | |
| 201 | "this closure returns \ | |
| 202 | the unit type which also implements {trait_name}" | |
| 203 | ), | |
| 204 | Some(last_semi), | |
| 205 | "probably caused by this trailing semicolon", | |
| 206 | ); | |
| 207 | }, | |
| 208 | None => {}, | |
| 191 | ), | |
| 192 | |diag| { | |
| 193 | if let Some(last_semi) = last_semi { | |
| 194 | diag.span_help(last_semi, "probably caused by this trailing semicolon"); | |
| 195 | } | |
| 196 | }, | |
| 197 | ); | |
| 209 | 198 | } |
| 210 | 199 | } |
| 211 | 200 | } |
src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use std::iter; |
| 2 | 2 | |
| 3 | 3 | use clippy_utils::diagnostics::span_lint_and_then; |
| 4 | use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; | |
| 4 | use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; | |
| 5 | 5 | use clippy_utils::sugg::Sugg; |
| 6 | 6 | use clippy_utils::ty::expr_type_is_certain; |
| 7 | 7 | use clippy_utils::{is_empty_block, is_expr_default, is_from_proc_macro}; |
| ... | ... | @@ -85,7 +85,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ |
| 85 | 85 | && block.expr.is_none() |
| 86 | 86 | && let Some(last_stmt) = block.stmts.iter().last() |
| 87 | 87 | && let StmtKind::Semi(last_expr) = last_stmt.kind |
| 88 | && let Some(snip) = last_expr.span.get_source_text(cx) | |
| 88 | && let Some(snip) = last_expr.span.get_text(cx) | |
| 89 | 89 | { |
| 90 | 90 | Some((last_stmt.span, snip)) |
| 91 | 91 | } else { |
| ... | ... | @@ -117,7 +117,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ |
| 117 | 117 | .filter_map(|arg| get_expr_snippet_with_type_certainty(cx, arg)) |
| 118 | 118 | .collect(); |
| 119 | 119 | |
| 120 | if let Some(call_snippet) = expr.span.get_source_text(cx) { | |
| 120 | if let Some(call_snippet) = expr.span.get_text(cx) { | |
| 121 | 121 | if arg_snippets_without_redundant_exprs.is_empty() |
| 122 | 122 | && let suggestions = args_to_recover |
| 123 | 123 | .iter() |
src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs+8-3| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | use clippy_config::Conf; |
| 2 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | use clippy_utils::ty::approx_ty_size; | |
| 4 | 3 | use rustc_errors::Applicability; |
| 5 | 4 | use rustc_hir::def_id::LocalDefId; |
| 6 | 5 | use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; |
| 7 | 6 | use rustc_lint::{LateContext, LateLintPass}; |
| 7 | use rustc_middle::ty::layout::LayoutOf; | |
| 8 | 8 | use rustc_session::impl_lint_pass; |
| 9 | 9 | use rustc_span::Symbol; |
| 10 | 10 | |
| ... | ... | @@ -81,8 +81,13 @@ impl UnnecessaryBoxReturns { |
| 81 | 81 | |
| 82 | 82 | // It's sometimes useful to return Box<T> if T is unsized, so don't lint those. |
| 83 | 83 | // Also, don't lint if we know that T is very large, in which case returning |
| 84 | // a Box<T> may be beneficial. | |
| 85 | if boxed_ty.is_sized(cx.tcx, cx.typing_env()) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { | |
| 84 | // a Box<T> may be beneficial. When the size depends on generic parameters | |
| 85 | // (e.g. `[T; N]`) it cannot be determined here, so don't lint that either, as | |
| 86 | // the `Box` may be a deliberate choice to avoid copying a large value. | |
| 87 | if boxed_ty.is_sized(cx.tcx, cx.typing_env()) | |
| 88 | && let Ok(layout) = cx.layout_of(boxed_ty) | |
| 89 | && layout.size.bytes() <= self.maximum_size | |
| 90 | { | |
| 86 | 91 | span_lint_and_then( |
| 87 | 92 | cx, |
| 88 | 93 | UNNECESSARY_BOX_RETURNS, |
src/tools/clippy/clippy_lints/src/unnecessary_mut_passed.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use rustc_errors::Applicability; |
| 4 | 4 | use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; |
| 5 | 5 | use rustc_lint::{LateContext, LateLintPass}; |
src/tools/clippy/clippy_lints/src/unused_async.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; |
| 2 | 2 | use clippy_utils::is_def_id_trait_method; |
| 3 | use clippy_utils::source::{HasSession, snippet_with_applicability, walk_span_to_context}; | |
| 3 | use clippy_utils::source::{snippet_with_applicability, walk_span_to_context}; | |
| 4 | 4 | use clippy_utils::usage::is_todo_unimplemented_stub; |
| 5 | 5 | use rustc_errors::Applicability; |
| 6 | 6 | use rustc_hir::def::DefKind; |
| ... | ... | @@ -303,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { |
| 303 | 303 | // evaluate the expression, to immediately evaluate the expression. |
| 304 | 304 | let mut app = Applicability::MaybeIncorrect; |
| 305 | 305 | |
| 306 | let async_span = cx.sess().source_map().span_extend_while_whitespace(async_span); | |
| 306 | let async_span = cx.tcx.sess.source_map().span_extend_while_whitespace(async_span); | |
| 307 | 307 | |
| 308 | 308 | let signature_snippet = snippet_with_applicability(cx, signature_span, "_", &mut app); |
| 309 | 309 | let tail_snippet = snippet_with_applicability(cx, tail_span, "_", &mut app).to_string(); |
src/tools/clippy/clippy_lints/src/unused_unit.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; | |
| 2 | use clippy_utils::source::{SpanExt, position_before_rarrow}; | |
| 3 | 3 | use clippy_utils::{is_never_expr, is_unit_expr}; |
| 4 | 4 | use rustc_ast::{Block, StmtKind}; |
| 5 | 5 | use rustc_errors::Applicability; |
src/tools/clippy/clippy_lints/src/useless_conversion.rs+4-4| ... | ... | @@ -132,8 +132,8 @@ fn into_iter_bound<'tcx>( |
| 132 | 132 | /// Extracts the receiver of a `.into_iter()` method call. |
| 133 | 133 | fn into_iter_call<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Option<&'hir Expr<'hir>> { |
| 134 | 134 | if let ExprKind::MethodCall(name, recv, [], _) = expr.kind |
| 135 | && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IntoIterator) | |
| 136 | 135 | && name.ident.name == sym::into_iter |
| 136 | && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IntoIterator) | |
| 137 | 137 | { |
| 138 | 138 | Some(recv) |
| 139 | 139 | } else { |
| ... | ... | @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { |
| 208 | 208 | }, |
| 209 | 209 | |
| 210 | 210 | ExprKind::MethodCall(name, recv, [], _) => { |
| 211 | if cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Into) && name.ident.name == sym::into { | |
| 211 | if name.ident.name == sym::into && cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Into) { | |
| 212 | 212 | let a = cx.typeck_results().expr_ty(e); |
| 213 | 213 | let b = cx.typeck_results().expr_ty(recv); |
| 214 | 214 | if same_type_modulo_regions(a, b) { |
| ... | ... | @@ -393,8 +393,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { |
| 393 | 393 | ); |
| 394 | 394 | } |
| 395 | 395 | } |
| 396 | if cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::TryInto) | |
| 397 | && name.ident.name == sym::try_into | |
| 396 | if name.ident.name == sym::try_into | |
| 397 | && cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::TryInto) | |
| 398 | 398 | && let a = cx.typeck_results().expr_ty(e) |
| 399 | 399 | && let b = cx.typeck_results().expr_ty(recv) |
| 400 | 400 | && a.is_diag_item(cx, sym::Result) |
src/tools/clippy/clippy_lints/src/useless_vec.rs+3-3| ... | ... | @@ -7,7 +7,7 @@ use clippy_config::Conf; |
| 7 | 7 | use clippy_utils::consts::{ConstEvalCtxt, Constant}; |
| 8 | 8 | use clippy_utils::diagnostics::span_lint_hir_and_then; |
| 9 | 9 | use clippy_utils::msrvs::{self, Msrv}; |
| 10 | use clippy_utils::source::SpanRangeExt; | |
| 10 | use clippy_utils::source::SpanExt; | |
| 11 | 11 | use clippy_utils::ty::is_copy; |
| 12 | 12 | use clippy_utils::visitors::for_each_local_use_after_expr; |
| 13 | 13 | use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_parent_expr, higher, is_in_test, span_contains_comment}; |
| ... | ... | @@ -285,10 +285,10 @@ impl SuggestedType { |
| 285 | 285 | assert!(args_span.is_none_or(|s| !s.from_expansion())); |
| 286 | 286 | assert!(len_span.is_none_or(|s| !s.from_expansion())); |
| 287 | 287 | |
| 288 | let maybe_args = args_span.map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")); | |
| 288 | let maybe_args = args_span.map(|sp| sp.get_text(cx).expect("spans are always crate-local")); | |
| 289 | 289 | let maybe_args = maybe_args.as_deref().unwrap_or_default(); |
| 290 | 290 | let maybe_len = len_span |
| 291 | .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) | |
| 291 | .map(|sp| sp.get_text(cx).expect("spans are always crate-local")) | |
| 292 | 292 | .map(|st| format!("; {st}")) |
| 293 | 293 | .unwrap_or_default(); |
| 294 | 294 |
src/tools/clippy/clippy_lints/src/utils/author.rs+26-8| ... | ... | @@ -6,11 +6,11 @@ use rustc_ast::ast::{LitFloatType, LitKind}; |
| 6 | 6 | use rustc_data_structures::fx::FxHashMap; |
| 7 | 7 | use rustc_hir::def_id::DefId; |
| 8 | 8 | use rustc_hir::{ |
| 9 | self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, | |
| 9 | self as hir, BindingMode, Body, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, | |
| 10 | 10 | FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, |
| 11 | 11 | }; |
| 12 | 12 | use rustc_lint::{LateContext, LateLintPass}; |
| 13 | use rustc_middle::ty::{FloatTy, IntTy, UintTy}; | |
| 13 | use rustc_middle::ty::{FloatTy, IntTy, TypeckResults, UintTy}; | |
| 14 | 14 | use rustc_session::declare_lint_pass; |
| 15 | 15 | use rustc_span::symbol::{Ident, Symbol}; |
| 16 | 16 | use std::cell::Cell; |
| ... | ... | @@ -137,15 +137,31 @@ impl<'tcx> LateLintPass<'tcx> for Author { |
| 137 | 137 | |
| 138 | 138 | fn check_item(cx: &LateContext<'_>, hir_id: HirId) { |
| 139 | 139 | if let Some(body) = cx.tcx.hir_maybe_body_owned_by(hir_id.expect_owner().def_id) { |
| 140 | check_node(cx, hir_id, |v| { | |
| 141 | v.expr(&v.bind("expr", body.value)); | |
| 142 | }); | |
| 140 | check_node_with_body( | |
| 141 | cx, | |
| 142 | hir_id, | |
| 143 | |v| { | |
| 144 | v.expr(&v.bind("expr", body.value)); | |
| 145 | }, | |
| 146 | Some(body), | |
| 147 | ); | |
| 143 | 148 | } |
| 144 | 149 | } |
| 145 | 150 | |
| 146 | 151 | fn check_node(cx: &LateContext<'_>, hir_id: HirId, f: impl Fn(&PrintVisitor<'_, '_>)) { |
| 152 | check_node_with_body(cx, hir_id, f, None); | |
| 153 | } | |
| 154 | ||
| 155 | /// Check the node at `hir_id`, in the context of `body` or the default from `cx` if none is given. | |
| 156 | fn check_node_with_body( | |
| 157 | cx: &LateContext<'_>, | |
| 158 | hir_id: HirId, | |
| 159 | f: impl Fn(&PrintVisitor<'_, '_>), | |
| 160 | body: Option<&Body<'_>>, | |
| 161 | ) { | |
| 147 | 162 | if has_attr(cx, hir_id) { |
| 148 | f(&PrintVisitor::new(cx)); | |
| 163 | let typeck_results = body.map_or_else(|| cx.typeck_results(), |body| cx.tcx.typeck_body(body.id())); | |
| 164 | f(&PrintVisitor::new(cx, typeck_results)); | |
| 149 | 165 | println!("{{"); |
| 150 | 166 | println!(" // report your lint here"); |
| 151 | 167 | println!("}}"); |
| ... | ... | @@ -199,6 +215,7 @@ impl<T: Display> Display for OptionPat<T> { |
| 199 | 215 | |
| 200 | 216 | struct PrintVisitor<'a, 'tcx> { |
| 201 | 217 | cx: &'a LateContext<'tcx>, |
| 218 | typeck_results: &'tcx TypeckResults<'tcx>, | |
| 202 | 219 | /// Fields are the current index that needs to be appended to pattern |
| 203 | 220 | /// binding names |
| 204 | 221 | ids: Cell<FxHashMap<&'static str, u32>>, |
| ... | ... | @@ -207,9 +224,10 @@ struct PrintVisitor<'a, 'tcx> { |
| 207 | 224 | } |
| 208 | 225 | |
| 209 | 226 | impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { |
| 210 | fn new(cx: &'a LateContext<'tcx>) -> Self { | |
| 227 | fn new(cx: &'a LateContext<'tcx>, typeck_results: &'tcx TypeckResults<'tcx>) -> Self { | |
| 211 | 228 | Self { |
| 212 | 229 | cx, |
| 230 | typeck_results, | |
| 213 | 231 | ids: Cell::default(), |
| 214 | 232 | first: Cell::new(true), |
| 215 | 233 | } |
| ... | ... | @@ -291,7 +309,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { |
| 291 | 309 | } |
| 292 | 310 | |
| 293 | 311 | fn maybe_path<'p>(&self, path: &Binding<impl MaybeQPath<'p>>) { |
| 294 | if let Some(id) = path.value.res(self.cx).opt_def_id() | |
| 312 | if let Some(id) = path.value.res(self.typeck_results).opt_def_id() | |
| 295 | 313 | && !id.is_local() |
| 296 | 314 | { |
| 297 | 315 | if let Some(lang) = self.cx.tcx.lang_items().from_def_id(id) { |
src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs+99-52| ... | ... | @@ -1,18 +1,18 @@ |
| 1 | 1 | use clippy_utils::macros::FormatArgsStorage; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use itertools::Itertools; | |
| 2 | use clippy_utils::source::{SpanExt, walk_span_to_context}; | |
| 4 | 3 | use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; |
| 5 | 4 | use rustc_data_structures::fx::FxHashMap; |
| 6 | 5 | use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; |
| 7 | use rustc_lint::{EarlyContext, EarlyLintPass}; | |
| 6 | use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; | |
| 8 | 7 | use rustc_session::impl_lint_pass; |
| 9 | use rustc_span::{Span, hygiene}; | |
| 10 | use std::iter::once; | |
| 8 | use rustc_span::source_map::SourceMap; | |
| 9 | use rustc_span::{Span, SpanData}; | |
| 11 | 10 | use std::mem; |
| 12 | 11 | |
| 13 | 12 | /// Populates [`FormatArgsStorage`] with AST [`FormatArgs`] nodes |
| 14 | 13 | pub struct FormatArgsCollector { |
| 15 | 14 | format_args: FxHashMap<Span, FormatArgs>, |
| 15 | parent_spans: Vec<SpanData>, | |
| 16 | 16 | storage: FormatArgsStorage, |
| 17 | 17 | } |
| 18 | 18 | |
| ... | ... | @@ -20,6 +20,7 @@ impl FormatArgsCollector { |
| 20 | 20 | pub fn new(storage: FormatArgsStorage) -> Self { |
| 21 | 21 | Self { |
| 22 | 22 | format_args: FxHashMap::default(), |
| 23 | parent_spans: Vec::new(), | |
| 23 | 24 | storage, |
| 24 | 25 | } |
| 25 | 26 | } |
| ... | ... | @@ -30,7 +31,7 @@ impl_lint_pass!(FormatArgsCollector => []); |
| 30 | 31 | impl EarlyLintPass for FormatArgsCollector { |
| 31 | 32 | fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { |
| 32 | 33 | if let ExprKind::FormatArgs(args) = &expr.kind { |
| 33 | if has_span_from_proc_macro(cx, args) { | |
| 34 | if self.has_span_from_external_macro(cx.sess().source_map(), expr.span, args) { | |
| 34 | 35 | return; |
| 35 | 36 | } |
| 36 | 37 | |
| ... | ... | @@ -43,53 +44,99 @@ impl EarlyLintPass for FormatArgsCollector { |
| 43 | 44 | } |
| 44 | 45 | } |
| 45 | 46 | |
| 46 | /// Detects if the format string or an argument has its span set by a proc macro to something inside | |
| 47 | /// a macro callsite, e.g. | |
| 48 | /// | |
| 49 | /// ```ignore | |
| 50 | /// println!(some_proc_macro!("input {}"), a); | |
| 51 | /// ``` | |
| 52 | /// | |
| 53 | /// Where `some_proc_macro` expands to | |
| 54 | /// | |
| 55 | /// ```ignore | |
| 56 | /// println!("output {}", a); | |
| 57 | /// ``` | |
| 58 | /// | |
| 59 | /// But with the span of `"output {}"` set to the macro input | |
| 60 | /// | |
| 61 | /// ```ignore | |
| 62 | /// println!(some_proc_macro!("input {}"), a); | |
| 63 | /// // ^^^^^^^^^^ | |
| 64 | /// ``` | |
| 65 | fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { | |
| 66 | let ctxt = args.span.ctxt(); | |
| 47 | impl FormatArgsCollector { | |
| 48 | /// Detects if the format string or an argument has its span set by a proc macro to something | |
| 49 | /// inside a macro callsite, e.g. | |
| 50 | /// | |
| 51 | /// ```ignore | |
| 52 | /// println!(some_proc_macro!("input {}"), a); | |
| 53 | /// ``` | |
| 54 | /// | |
| 55 | /// Where `some_proc_macro` expands to | |
| 56 | /// | |
| 57 | /// ```ignore | |
| 58 | /// println!("output {}", a); | |
| 59 | /// ``` | |
| 60 | /// | |
| 61 | /// But with the span of `"output {}"` set to the macro input | |
| 62 | /// | |
| 63 | /// ```ignore | |
| 64 | /// println!(some_proc_macro!("input {}"), a); | |
| 65 | /// // ^^^^^^^^^^ | |
| 66 | /// ``` | |
| 67 | fn has_span_from_external_macro(&mut self, sm: &SourceMap, fmt_sp: Span, args: &FormatArgs) -> bool { | |
| 68 | let mut fmt_sp = fmt_sp.data(); | |
| 69 | ||
| 70 | // Find the first macro call that contains the format string. | |
| 71 | let arg_sp = if let Some(arg_sp) = walk_span_to_context(args.span, fmt_sp.ctxt) { | |
| 72 | arg_sp.data() | |
| 73 | } else { | |
| 74 | // Try to find a common parent for the format call and the format string. | |
| 75 | self.parent_spans.clear(); | |
| 76 | // `fmt_sp.ctxt` isn't a parent of the format string so don't add it to the | |
| 77 | // search. The first iteration will always run since it can't be the root. | |
| 78 | while !fmt_sp.ctxt.is_root() { | |
| 79 | fmt_sp = fmt_sp.ctxt.outer_expn_data().call_site.data(); | |
| 80 | self.parent_spans.push(fmt_sp); | |
| 81 | } | |
| 82 | let mut arg_sp = args.span.data(); | |
| 83 | // Note: A parent span will always eventually be found since the root context | |
| 84 | // is an ancestor of all contexts. | |
| 85 | loop { | |
| 86 | match self.parent_spans.iter().find(|s| s.ctxt == arg_sp.ctxt) { | |
| 87 | Some(call_sp) if call_sp.lo <= arg_sp.lo && arg_sp.hi <= call_sp.hi => { | |
| 88 | fmt_sp = *call_sp; | |
| 89 | break arg_sp; | |
| 90 | }, | |
| 91 | // If the string isn't within the call span we some macro stuff we can't | |
| 92 | // easily interpret. | |
| 93 | Some(_) => return true, | |
| 94 | None => arg_sp = arg_sp.ctxt.outer_expn_data().call_site.data(), | |
| 95 | } | |
| 96 | } | |
| 97 | }; | |
| 98 | if fmt_sp.ctxt.in_external_macro(sm) { | |
| 99 | return true; | |
| 100 | } | |
| 101 | let Some(src) = arg_sp.get_source_range(sm) else { | |
| 102 | return true; | |
| 103 | }; | |
| 104 | let Some(src_text) = src.sf.src.as_ref().map(|x| &***x) else { | |
| 105 | return true; | |
| 106 | }; | |
| 67 | 107 | |
| 68 | // `format!("{} {} {c}", "one", "two", c = "three")` | |
| 69 | // ^^^^^ ^^^^^ ^^^^^^^ | |
| 70 | let argument_span = args | |
| 71 | .arguments | |
| 72 | .explicit_args() | |
| 73 | .iter() | |
| 74 | .map(|argument| hygiene::walk_chain(argument.expr.span, ctxt)); | |
| 108 | // Check the spans between the format string and the arguments and between each argument. | |
| 109 | args.arguments | |
| 110 | .explicit_args() | |
| 111 | .iter() | |
| 112 | .try_fold(src.range.end, |start, arg| { | |
| 113 | let expr_sp = walk_span_to_context(arg.expr.span, fmt_sp.ctxt)?.data(); | |
| 114 | let expr_start = (expr_sp.lo.0 - src.sf.start_pos.0) as usize; | |
| 115 | let expr_end = (expr_sp.hi.0 - src.sf.start_pos.0) as usize; | |
| 116 | let mut tks = tokenize(src_text.get(start..expr_start)?, FrontmatterAllowed::No) | |
| 117 | .map(|x| x.kind) | |
| 118 | .filter(|x| { | |
| 119 | !matches!( | |
| 120 | x, | |
| 121 | TokenKind::LineComment { doc_style: None } | |
| 122 | | TokenKind::BlockComment { | |
| 123 | doc_style: None, | |
| 124 | terminated: true | |
| 125 | } | |
| 126 | | TokenKind::Whitespace | |
| 127 | ) | |
| 128 | }); | |
| 75 | 129 | |
| 76 | // `format!("{} {} {c}", "one", "two", c = "three")` | |
| 77 | // ^^ ^^ ^^^^^^ | |
| 78 | !once(args.span) | |
| 79 | .chain(argument_span) | |
| 80 | .tuple_windows() | |
| 81 | .map(|(start, end)| start.between(end)) | |
| 82 | .all(|sp| { | |
| 83 | sp.check_source_text(cx, |src| { | |
| 84 | // text should be either `, name` or `, name =` | |
| 85 | let mut iter = tokenize(src, FrontmatterAllowed::No).filter(|t| { | |
| 86 | !matches!( | |
| 87 | t.kind, | |
| 88 | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace | |
| 89 | ) | |
| 90 | }); | |
| 91 | iter.next().is_some_and(|t| matches!(t.kind, TokenKind::Comma)) | |
| 92 | && iter.all(|t| matches!(t.kind, TokenKind::Ident | TokenKind::Eq)) | |
| 130 | // `,` or `, ident =` | |
| 131 | let matches = matches!(tks.next(), Some(TokenKind::Comma)) | |
| 132 | && match tks.next() { | |
| 133 | Some(TokenKind::Ident) => matches!(tks.next(), Some(TokenKind::Eq)), | |
| 134 | Some(_) => false, | |
| 135 | None => true, | |
| 136 | } | |
| 137 | && tks.next().is_none(); | |
| 138 | matches.then_some(expr_end) | |
| 93 | 139 | }) |
| 94 | }) | |
| 140 | .is_none() | |
| 141 | } | |
| 95 | 142 | } |
src/tools/clippy/clippy_lints/src/visibility.rs+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | use clippy_utils::source::SpanRangeExt; | |
| 2 | use clippy_utils::source::SpanExt; | |
| 3 | 3 | use rustc_ast::ast::{Item, VisibilityKind}; |
| 4 | 4 | use rustc_errors::Applicability; |
| 5 | 5 | use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; |
| ... | ... | @@ -152,5 +152,5 @@ impl EarlyLintPass for Visibility { |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | 154 | fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> bool { |
| 155 | !span.check_source_text(cx, |src| src.starts_with("pub")) | |
| 155 | !span.check_text(cx, |src| src.starts_with("pub")) | |
| 156 | 156 | } |
src/tools/clippy/clippy_lints/src/write/literal.rs+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::macros::format_arg_removal_span; |
| 3 | use clippy_utils::source::SpanRangeExt; | |
| 3 | use clippy_utils::source::SpanExt; | |
| 4 | 4 | use clippy_utils::sym; |
| 5 | 5 | use rustc_ast::token::LitKind; |
| 6 | 6 | use rustc_ast::{ |
| ... | ... | @@ -48,7 +48,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) |
| 48 | 48 | && let Some(arg) = format_args.arguments.by_index(index) |
| 49 | 49 | && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind |
| 50 | 50 | && !arg.expr.span.from_expansion() |
| 51 | && let Some(value_string) = arg.expr.span.get_source_text(cx) | |
| 51 | && let Some(value_string) = arg.expr.span.get_text(cx) | |
| 52 | 52 | { |
| 53 | 53 | let (replacement, replace_raw) = match lit.kind { |
| 54 | 54 | LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { |
| ... | ... | @@ -71,7 +71,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) |
| 71 | 71 | _ => continue, |
| 72 | 72 | }; |
| 73 | 73 | |
| 74 | let Some(format_string_snippet) = format_args.span.get_source_text(cx) else { | |
| 74 | let Some(format_string_snippet) = format_args.span.get_text(cx) else { | |
| 75 | 75 | continue; |
| 76 | 76 | }; |
| 77 | 77 | let format_string_is_raw = format_string_snippet.starts_with('r'); |
src/tools/clippy/clippy_lints/src/write/with_newline.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
| 2 | 2 | use clippy_utils::macros::MacroCall; |
| 3 | use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; | |
| 3 | use clippy_utils::source::{SpanExt, expand_past_previous_comma}; | |
| 4 | 4 | use clippy_utils::sym; |
| 5 | 5 | use rustc_ast::{FormatArgs, FormatArgsPiece}; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -48,7 +48,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: |
| 48 | 48 | format!("using `{name}!()` with a format string that ends in a single newline"), |
| 49 | 49 | |diag| { |
| 50 | 50 | let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); |
| 51 | let Some(format_snippet) = format_string_span.get_source_text(cx) else { | |
| 51 | let Some(format_snippet) = format_string_span.get_text(cx) else { | |
| 52 | 52 | return; |
| 53 | 53 | }; |
| 54 | 54 |
src/tools/clippy/clippy_lints_internal/src/lib.rs+19-11| ... | ... | @@ -63,15 +63,23 @@ static LINTS: &[&Lint] = &[ |
| 63 | 63 | pub fn register_lints(store: &mut LintStore) { |
| 64 | 64 | store.register_lints(LINTS); |
| 65 | 65 | |
| 66 | store.register_early_pass(|| Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths)); | |
| 67 | store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); | |
| 68 | store.register_late_pass(|_| Box::new(collapsible_span_lint_calls::CollapsibleCalls)); | |
| 69 | store.register_late_pass(|_| Box::<symbols::Symbols>::default()); | |
| 70 | store.register_late_pass(|_| Box::<lint_without_lint_pass::LintWithoutLintPass>::default()); | |
| 71 | store.register_late_pass(|_| Box::new(unnecessary_def_path::UnnecessaryDefPath)); | |
| 72 | store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass)); | |
| 73 | store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl)); | |
| 74 | store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new())); | |
| 75 | store.register_late_pass(|_| Box::new(unusual_names::UnusualNames)); | |
| 76 | store.register_late_pass(|_| Box::new(repeated_is_diagnostic_item::RepeatedIsDiagnosticItem)); | |
| 66 | store.register_early_pass(Box::new(|| { | |
| 67 | Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths) | |
| 68 | })); | |
| 69 | store.register_early_pass(Box::new(|| Box::new(produce_ice::ProduceIce))); | |
| 70 | store.register_late_pass(Box::new(|_| Box::new(collapsible_span_lint_calls::CollapsibleCalls))); | |
| 71 | store.register_late_pass(Box::new(|_| Box::<symbols::Symbols>::default())); | |
| 72 | store.register_late_pass(Box::new(|_| { | |
| 73 | Box::<lint_without_lint_pass::LintWithoutLintPass>::default() | |
| 74 | })); | |
| 75 | store.register_late_pass(Box::new(|_| Box::new(unnecessary_def_path::UnnecessaryDefPath))); | |
| 76 | store.register_late_pass(Box::new(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass))); | |
| 77 | store.register_late_pass(Box::new(|_| Box::new(msrv_attr_impl::MsrvAttrImpl))); | |
| 78 | store.register_late_pass(Box::new(|_| { | |
| 79 | Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new()) | |
| 80 | })); | |
| 81 | store.register_late_pass(Box::new(|_| Box::new(unusual_names::UnusualNames))); | |
| 82 | store.register_late_pass(Box::new(|_| { | |
| 83 | Box::new(repeated_is_diagnostic_item::RepeatedIsDiagnosticItem) | |
| 84 | })); | |
| 77 | 85 | } |
src/tools/clippy/clippy_lints_internal/src/repeated_is_diagnostic_item.rs+2-2| ... | ... | @@ -541,7 +541,7 @@ fn extract_nested_is_diag_item<'tcx>( |
| 541 | 541 | cx: &LateContext<'tcx>, |
| 542 | 542 | cond: &'tcx Expr<'_>, |
| 543 | 543 | ) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> { |
| 544 | for_each_expr(cx, cond, |cond_part| { | |
| 544 | for_each_expr(cx.tcx, cond, |cond_part| { | |
| 545 | 545 | if let Some(res) = extract_is_diag_item(cx, cond_part) { |
| 546 | 546 | ControlFlow::Break((cond_part.span, res)) |
| 547 | 547 | } else { |
| ... | ... | @@ -554,7 +554,7 @@ fn extract_nested_is_diagnostic_item<'tcx>( |
| 554 | 554 | cx: &LateContext<'tcx>, |
| 555 | 555 | cond: &'tcx Expr<'_>, |
| 556 | 556 | ) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> { |
| 557 | for_each_expr(cx, cond, |cond_part| { | |
| 557 | for_each_expr(cx.tcx, cond, |cond_part| { | |
| 558 | 558 | if let Some(res) = extract_is_diagnostic_item(cx, cond_part) { |
| 559 | 559 | ControlFlow::Break((cond_part.span, res)) |
| 560 | 560 | } else { |
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-2026-06-11 | |
| 11 | nightly-2026-06-25 | |
| 12 | 12 | ``` |
| 13 | 13 | <!-- end autogenerated nightly --> |
| 14 | 14 |
src/tools/clippy/clippy_utils/src/attrs.rs+7-4| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | //! Utility functions for attributes, including Clippy's built-in ones |
| 2 | 2 | |
| 3 | use crate::source::SpanRangeExt; | |
| 3 | use crate::source::SpanExt; | |
| 4 | 4 | use crate::{sym, tokenize_with_text}; |
| 5 | 5 | use rustc_ast::attr::AttributeExt; |
| 6 | 6 | use rustc_errors::Applicability; |
| ... | ... | @@ -37,8 +37,6 @@ pub fn check_clippy_attr<A: AttributeExt>(sess: &Session, attr: &A) { |
| 37 | 37 | | sym::version |
| 38 | 38 | | sym::cognitive_complexity |
| 39 | 39 | | sym::dump |
| 40 | | sym::disallowed_profile | |
| 41 | | sym::disallowed_profiles | |
| 42 | 40 | | sym::msrv |
| 43 | 41 | | sym::has_significant_drop |
| 44 | 42 | | sym::format_args => {}, |
| ... | ... | @@ -107,7 +105,12 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { |
| 107 | 105 | |
| 108 | 106 | /// Checks whether the given span contains a `#[cfg(..)]` attribute |
| 109 | 107 | pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { |
| 110 | s.check_source_text(cx, |src| { | |
| 108 | s.check_text(cx, |src| { | |
| 109 | // PERF: A `#[cfg]` needs a literal `#`, so skip the lexer when the source has none. | |
| 110 | if !src.contains('#') { | |
| 111 | return false; | |
| 112 | } | |
| 113 | ||
| 111 | 114 | let mut iter = tokenize_with_text(src); |
| 112 | 115 | |
| 113 | 116 | // Search for the token sequence [`#`, `[`, `cfg`] |
src/tools/clippy/clippy_utils/src/consts.rs+20-10| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | #![expect(clippy::float_cmp)] |
| 6 | 6 | |
| 7 | 7 | use crate::res::MaybeDef; |
| 8 | use crate::source::{SpanRangeExt, walk_span_to_context}; | |
| 8 | use crate::source::{SpanExt, walk_span_to_context}; | |
| 9 | 9 | use crate::{clip, is_direct_expn_of, sext, sym, unsext}; |
| 10 | 10 | |
| 11 | 11 | use rustc_abi::Size; |
| ... | ... | @@ -522,9 +522,9 @@ pub fn eval_int(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<FullInt> { |
| 522 | 522 | /// |
| 523 | 523 | /// See the module level documentation for some context. |
| 524 | 524 | pub struct ConstEvalCtxt<'tcx> { |
| 525 | tcx: TyCtxt<'tcx>, | |
| 526 | typing_env: ty::TypingEnv<'tcx>, | |
| 527 | typeck: &'tcx TypeckResults<'tcx>, | |
| 525 | pub tcx: TyCtxt<'tcx>, | |
| 526 | pub typing_env: ty::TypingEnv<'tcx>, | |
| 527 | pub typeck: &'tcx TypeckResults<'tcx>, | |
| 528 | 528 | source: Cell<ConstantSource>, |
| 529 | 529 | ctxt: Cell<SyntaxContext>, |
| 530 | 530 | } |
| ... | ... | @@ -885,12 +885,22 @@ impl<'tcx> ConstEvalCtxt<'tcx> { |
| 885 | 885 | _ => return None, |
| 886 | 886 | }; |
| 887 | 887 | |
| 888 | let args = self.typeck.node_args(id); | |
| 889 | ||
| 890 | if !args.is_empty() { | |
| 891 | let owner_def_id = self.typeck.hir_owner.def_id.to_def_id(); | |
| 892 | let identity_args = ty::GenericArgs::identity_for_item(self.tcx, owner_def_id); | |
| 893 | // Don't try to fully evaluate consts inside code whose bounds can't be satisfied. | |
| 894 | if self | |
| 895 | .tcx | |
| 896 | .instantiate_and_check_impossible_predicates((owner_def_id, identity_args)) | |
| 897 | { | |
| 898 | return None; | |
| 899 | } | |
| 900 | } | |
| 901 | ||
| 888 | 902 | self.tcx |
| 889 | .const_eval_resolve( | |
| 890 | self.typing_env, | |
| 891 | mir::UnevaluatedConst::new(did, self.typeck.node_args(id)), | |
| 892 | qpath.span(), | |
| 893 | ) | |
| 903 | .const_eval_resolve(self.typing_env, mir::UnevaluatedConst::new(did, args), qpath.span()) | |
| 894 | 904 | .ok() |
| 895 | 905 | } |
| 896 | 906 | |
| ... | ... | @@ -934,7 +944,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { |
| 934 | 944 | if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) |
| 935 | 945 | && let expr_lo = expr_span.lo() |
| 936 | 946 | && expr_lo >= span.lo |
| 937 | && let Some(src) = (span.lo..expr_lo).get_source_range(&self.tcx) | |
| 947 | && let Some(src) = (span.lo..expr_lo).get_source_range(self.tcx) | |
| 938 | 948 | && let Some(src) = src.as_str() |
| 939 | 949 | { |
| 940 | 950 | use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; |
src/tools/clippy/clippy_utils/src/disallowed_profiles.rs deleted-180| ... | ... | @@ -1,180 +0,0 @@ |
| 1 | use crate::sym; | |
| 2 | use rustc_ast::ast::{LitKind, MetaItemInner}; | |
| 3 | use rustc_data_structures::fx::FxHashMap; | |
| 4 | use rustc_data_structures::smallvec::SmallVec; | |
| 5 | use rustc_hir::{Attribute, HirId}; | |
| 6 | use rustc_lint::LateContext; | |
| 7 | use rustc_span::{Span, Symbol}; | |
| 8 | ||
| 9 | /// One profile name referenced by a `#[clippy::disallowed_profile(...)]` or | |
| 10 | /// `#[clippy::disallowed_profiles(...)]` attribute on an item. | |
| 11 | /// | |
| 12 | /// A single attribute produces one `ProfileEntry` per string argument. The entry records which | |
| 13 | /// attribute variant introduced it, the profile name, and the span of that string literal so | |
| 14 | /// diagnostics (e.g. "unknown profile") can point at the exact argument. | |
| 15 | #[derive(Copy, Clone)] | |
| 16 | pub struct ProfileEntry { | |
| 17 | pub attr_name: Symbol, | |
| 18 | pub name: Symbol, | |
| 19 | pub span: Span, | |
| 20 | } | |
| 21 | ||
| 22 | /// The set of profiles active at some `HirId`, obtained by walking up the HIR from that id and | |
| 23 | /// collecting the first ancestor that carries a `#[clippy::disallowed_profile(s)]` attribute. | |
| 24 | /// | |
| 25 | /// An empty selection is represented by `None` at the call site; a `ProfileSelection` is always | |
| 26 | /// non-empty. | |
| 27 | #[derive(Clone)] | |
| 28 | pub struct ProfileSelection { | |
| 29 | entries: SmallVec<[ProfileEntry; 2]>, | |
| 30 | } | |
| 31 | ||
| 32 | impl ProfileSelection { | |
| 33 | pub fn new(entries: SmallVec<[ProfileEntry; 2]>) -> Self { | |
| 34 | Self { entries } | |
| 35 | } | |
| 36 | ||
| 37 | pub fn is_empty(&self) -> bool { | |
| 38 | self.entries.is_empty() | |
| 39 | } | |
| 40 | ||
| 41 | pub fn iter(&self) -> impl Iterator<Item = &ProfileEntry> { | |
| 42 | self.entries.iter() | |
| 43 | } | |
| 44 | } | |
| 45 | ||
| 46 | #[derive(Default)] | |
| 47 | pub struct ProfileResolver { | |
| 48 | cache: FxHashMap<HirId, Option<ProfileSelection>>, | |
| 49 | } | |
| 50 | ||
| 51 | impl ProfileResolver { | |
| 52 | pub fn active_profiles(&mut self, cx: &LateContext<'_>, hir_id: HirId) -> Option<&ProfileSelection> { | |
| 53 | // NOTE: The `contains_key`+`get` dance is intentional: using only `get` here triggers borrowck | |
| 54 | // errors because we need to mutate `self.cache` on cache misses. | |
| 55 | if self.cache.contains_key(&hir_id) { | |
| 56 | return self.cache.get(&hir_id).and_then(|selection| selection.as_ref()); | |
| 57 | } | |
| 58 | ||
| 59 | let (resolved, visited) = self.resolve(cx, hir_id); | |
| 60 | ||
| 61 | for id in visited { | |
| 62 | self.cache.entry(id).or_insert_with(|| resolved.clone()); | |
| 63 | } | |
| 64 | self.cache.insert(hir_id, resolved); | |
| 65 | ||
| 66 | self.cache.get(&hir_id).and_then(|selection| selection.as_ref()) | |
| 67 | } | |
| 68 | ||
| 69 | fn resolve(&self, cx: &LateContext<'_>, start: HirId) -> (Option<ProfileSelection>, SmallVec<[HirId; 8]>) { | |
| 70 | let mut visited = SmallVec::<[HirId; 8]>::new(); | |
| 71 | let mut current = Some(start); | |
| 72 | ||
| 73 | while let Some(id) = current { | |
| 74 | if let Some(cached) = self.cache.get(&id) { | |
| 75 | return (cached.clone(), visited); | |
| 76 | } | |
| 77 | ||
| 78 | visited.push(id); | |
| 79 | ||
| 80 | if let Some(selection) = profiles_from_attrs(cx, cx.tcx.hir_attrs(id)) { | |
| 81 | return (Some(selection), visited); | |
| 82 | } | |
| 83 | ||
| 84 | if id == rustc_hir::CRATE_HIR_ID { | |
| 85 | current = None; | |
| 86 | } else { | |
| 87 | current = Some(cx.tcx.parent_hir_id(id)); | |
| 88 | } | |
| 89 | } | |
| 90 | ||
| 91 | (None, visited) | |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | fn profiles_from_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) -> Option<ProfileSelection> { | |
| 96 | let mut entries = SmallVec::<[ProfileEntry; 2]>::new(); | |
| 97 | ||
| 98 | for attr in attrs { | |
| 99 | let path = attr.path(); | |
| 100 | if path.len() != 2 || path[0] != sym::clippy { | |
| 101 | continue; | |
| 102 | } | |
| 103 | ||
| 104 | let name = path[1]; | |
| 105 | if name != sym::disallowed_profile && name != sym::disallowed_profiles { | |
| 106 | continue; | |
| 107 | } | |
| 108 | ||
| 109 | let attr_label = if name == sym::disallowed_profiles { | |
| 110 | "`clippy::disallowed_profiles`" | |
| 111 | } else { | |
| 112 | "`clippy::disallowed_profile`" | |
| 113 | }; | |
| 114 | ||
| 115 | let Some(items) = attr.meta_item_list() else { | |
| 116 | cx.tcx | |
| 117 | .sess | |
| 118 | .dcx() | |
| 119 | .struct_span_err(attr.span(), format!("{attr_label} expects string arguments")) | |
| 120 | .emit(); | |
| 121 | continue; | |
| 122 | }; | |
| 123 | ||
| 124 | if items.is_empty() { | |
| 125 | cx.tcx | |
| 126 | .sess | |
| 127 | .dcx() | |
| 128 | .struct_span_err(attr.span(), format!("{attr_label} expects at least one profile name")) | |
| 129 | .emit(); | |
| 130 | continue; | |
| 131 | } | |
| 132 | ||
| 133 | if name == sym::disallowed_profile && items.len() != 1 { | |
| 134 | cx.tcx | |
| 135 | .sess | |
| 136 | .dcx() | |
| 137 | .struct_span_err(attr.span(), "use `clippy::disallowed_profiles` for multiple profiles") | |
| 138 | .emit(); | |
| 139 | } | |
| 140 | ||
| 141 | for item in items { | |
| 142 | match literal_symbol(&item) { | |
| 143 | Some((symbol, span)) => entries.push(ProfileEntry { | |
| 144 | attr_name: name, | |
| 145 | name: symbol, | |
| 146 | span, | |
| 147 | }), | |
| 148 | None => emit_string_error(cx, &item), | |
| 149 | } | |
| 150 | } | |
| 151 | } | |
| 152 | ||
| 153 | if entries.is_empty() { | |
| 154 | None | |
| 155 | } else { | |
| 156 | Some(ProfileSelection::new(entries)) | |
| 157 | } | |
| 158 | } | |
| 159 | ||
| 160 | fn literal_symbol(item: &MetaItemInner) -> Option<(Symbol, Span)> { | |
| 161 | match item { | |
| 162 | MetaItemInner::Lit(lit) => { | |
| 163 | let LitKind::Str(symbol, _) = lit.kind else { return None }; | |
| 164 | Some((symbol, lit.span)) | |
| 165 | }, | |
| 166 | MetaItemInner::MetaItem(_) => None, | |
| 167 | } | |
| 168 | } | |
| 169 | ||
| 170 | fn emit_string_error(cx: &LateContext<'_>, item: &MetaItemInner) { | |
| 171 | let span = match item { | |
| 172 | MetaItemInner::Lit(lit) => lit.span, | |
| 173 | MetaItemInner::MetaItem(meta) => meta.span, | |
| 174 | }; | |
| 175 | cx.tcx | |
| 176 | .sess | |
| 177 | .dcx() | |
| 178 | .struct_span_err(span, "expected string literal profile name") | |
| 179 | .emit(); | |
| 180 | } |
src/tools/clippy/clippy_utils/src/eager_or_lazy.rs+48-57| ... | ... | @@ -11,15 +11,15 @@ |
| 11 | 11 | |
| 12 | 12 | use crate::consts::{ConstEvalCtxt, FullInt}; |
| 13 | 13 | use crate::sym; |
| 14 | use crate::ty::{all_predicates_of, is_copy}; | |
| 14 | use crate::ty::all_predicates_of; | |
| 15 | 15 | use crate::visitors::is_const_evaluatable; |
| 16 | 16 | use rustc_hir::def::{DefKind, Res}; |
| 17 | 17 | use rustc_hir::def_id::DefId; |
| 18 | 18 | use rustc_hir::intravisit::{Visitor, walk_expr}; |
| 19 | 19 | use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; |
| 20 | 20 | use rustc_lint::LateContext; |
| 21 | use rustc_middle::ty; | |
| 22 | 21 | use rustc_middle::ty::adjustment::{Adjust, DerefAdjustKind}; |
| 22 | use rustc_middle::ty::{self, TyCtxt}; | |
| 23 | 23 | use rustc_span::Symbol; |
| 24 | 24 | use std::{cmp, ops}; |
| 25 | 25 | |
| ... | ... | @@ -48,17 +48,17 @@ impl ops::BitOrAssign for EagernessSuggestion { |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | /// Determine the eagerness of the given function call. |
| 51 | fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { | |
| 51 | fn fn_eagerness(tcx: TyCtxt<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { | |
| 52 | 52 | use EagernessSuggestion::{Eager, Lazy, NoChange}; |
| 53 | 53 | |
| 54 | let ty = match cx.tcx.impl_of_assoc(fn_id) { | |
| 55 | Some(id) => cx.tcx.type_of(id).instantiate_identity().skip_norm_wip(), | |
| 54 | let ty = match tcx.impl_of_assoc(fn_id) { | |
| 55 | Some(id) => tcx.type_of(id).instantiate_identity().skip_norm_wip(), | |
| 56 | 56 | None => return Lazy, |
| 57 | 57 | }; |
| 58 | 58 | |
| 59 | 59 | if (matches!(name, sym::is_empty | sym::len) || name.as_str().starts_with("as_")) && have_one_arg { |
| 60 | 60 | if matches!( |
| 61 | cx.tcx.crate_name(fn_id.krate), | |
| 61 | tcx.crate_name(fn_id.krate), | |
| 62 | 62 | sym::std | sym::core | sym::alloc | sym::proc_macro |
| 63 | 63 | ) { |
| 64 | 64 | Eager |
| ... | ... | @@ -71,22 +71,20 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: |
| 71 | 71 | // Due to the limited operations on these types functions should be fairly cheap. |
| 72 | 72 | if def.variants().iter().flat_map(|v| v.fields.iter()).any(|x| { |
| 73 | 73 | matches!( |
| 74 | cx.tcx | |
| 75 | .type_of(x.did) | |
| 74 | tcx.type_of(x.did) | |
| 76 | 75 | .instantiate_identity() |
| 77 | 76 | .skip_norm_wip() |
| 78 | 77 | .peel_refs() |
| 79 | 78 | .kind(), |
| 80 | 79 | ty::Param(_) |
| 81 | 80 | ) |
| 82 | }) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { | |
| 83 | ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, | |
| 81 | }) && all_predicates_of(tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { | |
| 82 | ty::ClauseKind::Trait(pred) => tcx.trait_def(pred.trait_ref.def_id).is_marker, | |
| 84 | 83 | _ => true, |
| 85 | 84 | }) && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_))) |
| 86 | 85 | { |
| 87 | 86 | // Limit the function to either `(self) -> bool` or `(&self) -> bool` |
| 88 | match &**cx | |
| 89 | .tcx | |
| 87 | match &**tcx | |
| 90 | 88 | .fn_sig(fn_id) |
| 91 | 89 | .instantiate_identity() |
| 92 | 90 | .skip_norm_wip() |
| ... | ... | @@ -104,14 +102,12 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: |
| 104 | 102 | } |
| 105 | 103 | } |
| 106 | 104 | |
| 107 | fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> bool { | |
| 105 | fn res_has_significant_drop(res: Res, ecx: &ConstEvalCtxt<'_>, e: &Expr<'_>) -> bool { | |
| 108 | 106 | if let Res::Def(DefKind::Ctor(..) | DefKind::Variant | DefKind::Enum | DefKind::Struct, _) |
| 109 | 107 | | Res::SelfCtor(_) |
| 110 | 108 | | Res::SelfTyAlias { .. } = res |
| 111 | 109 | { |
| 112 | cx.typeck_results() | |
| 113 | .expr_ty(e) | |
| 114 | .has_significant_drop(cx.tcx, cx.typing_env()) | |
| 110 | ecx.typeck.expr_ty(e).has_significant_drop(ecx.tcx, ecx.typing_env) | |
| 115 | 111 | } else { |
| 116 | 112 | false |
| 117 | 113 | } |
| ... | ... | @@ -119,12 +115,12 @@ fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> boo |
| 119 | 115 | |
| 120 | 116 | #[expect(clippy::too_many_lines)] |
| 121 | 117 | fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion { |
| 122 | struct V<'cx, 'tcx> { | |
| 123 | cx: &'cx LateContext<'tcx>, | |
| 118 | struct V<'tcx> { | |
| 119 | ecx: ConstEvalCtxt<'tcx>, | |
| 124 | 120 | eagerness: EagernessSuggestion, |
| 125 | 121 | } |
| 126 | 122 | |
| 127 | impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { | |
| 123 | impl<'tcx> Visitor<'tcx> for V<'tcx> { | |
| 128 | 124 | fn visit_expr(&mut self, e: &'tcx Expr<'_>) { |
| 129 | 125 | use EagernessSuggestion::{ForceNoChange, Lazy, NoChange}; |
| 130 | 126 | if self.eagerness == ForceNoChange { |
| ... | ... | @@ -134,8 +130,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS |
| 134 | 130 | // Autoderef through a user-defined `Deref` impl can have side-effects, |
| 135 | 131 | // so don't suggest changing it. |
| 136 | 132 | if self |
| 137 | .cx | |
| 138 | .typeck_results() | |
| 133 | .ecx | |
| 134 | .typeck | |
| 139 | 135 | .expr_adjustments(e) |
| 140 | 136 | .iter() |
| 141 | 137 | .any(|adj| matches!(adj.kind, Adjust::Deref(DerefAdjustKind::Overloaded(_)))) |
| ... | ... | @@ -152,58 +148,62 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS |
| 152 | 148 | .. |
| 153 | 149 | }, |
| 154 | 150 | args, |
| 155 | ) => match self.cx.qpath_res(path, hir_id) { | |
| 151 | ) => match self.ecx.typeck.qpath_res(path, hir_id) { | |
| 156 | 152 | res @ (Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_)) => { |
| 157 | if res_has_significant_drop(res, self.cx, e) { | |
| 153 | if res_has_significant_drop(res, &self.ecx, e) { | |
| 158 | 154 | self.eagerness = ForceNoChange; |
| 159 | 155 | return; |
| 160 | 156 | } |
| 161 | 157 | }, |
| 162 | Res::Def(_, id) if self.cx.tcx.is_promotable_const_fn(id) => (), | |
| 158 | Res::Def(_, id) if self.ecx.tcx.is_promotable_const_fn(id) => (), | |
| 163 | 159 | // No need to walk the arguments here, `is_const_evaluatable` already did |
| 164 | Res::Def(..) if is_const_evaluatable(self.cx, e) => { | |
| 160 | Res::Def(..) if is_const_evaluatable(self.ecx.tcx, self.ecx.typeck, e) => { | |
| 165 | 161 | self.eagerness |= NoChange; |
| 166 | 162 | return; |
| 167 | 163 | }, |
| 168 | 164 | Res::Def(_, id) => match path { |
| 169 | 165 | QPath::Resolved(_, p) => { |
| 170 | self.eagerness |= | |
| 171 | fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty()); | |
| 166 | self.eagerness |= fn_eagerness( | |
| 167 | self.ecx.tcx, | |
| 168 | id, | |
| 169 | p.segments.last().unwrap().ident.name, | |
| 170 | !args.is_empty(), | |
| 171 | ); | |
| 172 | 172 | }, |
| 173 | 173 | QPath::TypeRelative(_, name) => { |
| 174 | self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty()); | |
| 174 | self.eagerness |= fn_eagerness(self.ecx.tcx, id, name.ident.name, !args.is_empty()); | |
| 175 | 175 | }, |
| 176 | 176 | }, |
| 177 | 177 | _ => self.eagerness = Lazy, |
| 178 | 178 | }, |
| 179 | 179 | // No need to walk the arguments here, `is_const_evaluatable` already did |
| 180 | ExprKind::MethodCall(..) if is_const_evaluatable(self.cx, e) => { | |
| 180 | ExprKind::MethodCall(..) if is_const_evaluatable(self.ecx.tcx, self.ecx.typeck, e) => { | |
| 181 | 181 | self.eagerness |= NoChange; |
| 182 | 182 | return; |
| 183 | 183 | }, |
| 184 | 184 | #[expect(clippy::match_same_arms)] // arm pattern can't be merged due to `ref`, see rust#105778 |
| 185 | 185 | ExprKind::Struct(path, ..) => { |
| 186 | if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) { | |
| 186 | if res_has_significant_drop(self.ecx.typeck.qpath_res(path, e.hir_id), &self.ecx, e) { | |
| 187 | 187 | self.eagerness = ForceNoChange; |
| 188 | 188 | return; |
| 189 | 189 | } |
| 190 | 190 | }, |
| 191 | 191 | ExprKind::Path(ref path) => { |
| 192 | if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) { | |
| 192 | if res_has_significant_drop(self.ecx.typeck.qpath_res(path, e.hir_id), &self.ecx, e) { | |
| 193 | 193 | self.eagerness = ForceNoChange; |
| 194 | 194 | return; |
| 195 | 195 | } |
| 196 | 196 | }, |
| 197 | 197 | ExprKind::MethodCall(name, ..) => { |
| 198 | 198 | self.eagerness |= self |
| 199 | .cx | |
| 200 | .typeck_results() | |
| 199 | .ecx | |
| 200 | .typeck | |
| 201 | 201 | .type_dependent_def_id(e.hir_id) |
| 202 | .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true)); | |
| 202 | .map_or(Lazy, |id| fn_eagerness(self.ecx.tcx, id, name.ident.name, true)); | |
| 203 | 203 | }, |
| 204 | 204 | ExprKind::Index(_, e, _) => { |
| 205 | let ty = self.cx.typeck_results().expr_ty_adjusted(e); | |
| 206 | if is_copy(self.cx, ty) && !ty.is_ref() { | |
| 205 | let ty = self.ecx.typeck.expr_ty_adjusted(e); | |
| 206 | if self.ecx.tcx.type_is_copy_modulo_regions(self.ecx.typing_env, ty) && !ty.is_ref() { | |
| 207 | 207 | self.eagerness |= NoChange; |
| 208 | 208 | } else { |
| 209 | 209 | self.eagerness = Lazy; |
| ... | ... | @@ -211,24 +211,19 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS |
| 211 | 211 | }, |
| 212 | 212 | |
| 213 | 213 | // `-i32::MIN` panics with overflow checks |
| 214 | ExprKind::Unary(UnOp::Neg, right) if ConstEvalCtxt::new(self.cx).eval(right).is_none() => { | |
| 214 | ExprKind::Unary(UnOp::Neg, right) if self.ecx.eval(right).is_none() => { | |
| 215 | 215 | self.eagerness |= NoChange; |
| 216 | 216 | }, |
| 217 | 217 | |
| 218 | 218 | // Custom `Deref` impl might have side effects |
| 219 | ExprKind::Unary(UnOp::Deref, e) | |
| 220 | if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() => | |
| 221 | { | |
| 219 | ExprKind::Unary(UnOp::Deref, e) if self.ecx.typeck.expr_ty(e).builtin_deref(true).is_none() => { | |
| 222 | 220 | self.eagerness |= NoChange; |
| 223 | 221 | }, |
| 224 | 222 | // Dereferences should be cheap, but dereferencing a raw pointer earlier may not be safe. |
| 225 | ExprKind::Unary(UnOp::Deref, e) if !self.cx.typeck_results().expr_ty(e).is_raw_ptr() => (), | |
| 223 | ExprKind::Unary(UnOp::Deref, e) if !self.ecx.typeck.expr_ty(e).is_raw_ptr() => (), | |
| 226 | 224 | ExprKind::Unary(UnOp::Deref, _) => self.eagerness |= NoChange, |
| 227 | 225 | ExprKind::Unary(_, e) |
| 228 | if matches!( | |
| 229 | self.cx.typeck_results().expr_ty(e).kind(), | |
| 230 | ty::Bool | ty::Int(_) | ty::Uint(_), | |
| 231 | ) => {}, | |
| 226 | if matches!(self.ecx.typeck.expr_ty(e).kind(), ty::Bool | ty::Int(_) | ty::Uint(_),) => {}, | |
| 232 | 227 | |
| 233 | 228 | // `>>` and `<<` panic when the right-hand side is greater than or equal to the number of bits in the |
| 234 | 229 | // type of the left-hand side, or is negative. |
| ... | ... | @@ -236,18 +231,16 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS |
| 236 | 231 | // overflow with constants, the compiler emits an error for it and the programmer will have to fix it. |
| 237 | 232 | // Thus, we would realistically only delay the lint. |
| 238 | 233 | ExprKind::Binary(op, _, right) |
| 239 | if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr) | |
| 240 | && ConstEvalCtxt::new(self.cx).eval(right).is_none() => | |
| 234 | if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr) && self.ecx.eval(right).is_none() => | |
| 241 | 235 | { |
| 242 | 236 | self.eagerness |= NoChange; |
| 243 | 237 | }, |
| 244 | 238 | |
| 245 | 239 | ExprKind::Binary(op, left, right) |
| 246 | 240 | if matches!(op.node, BinOpKind::Div | BinOpKind::Rem) |
| 247 | && let right_ty = self.cx.typeck_results().expr_ty(right) | |
| 248 | && let ecx = ConstEvalCtxt::new(self.cx) | |
| 249 | && let left = ecx.eval(left) | |
| 250 | && let right = ecx.eval(right).and_then(|c| c.int_value(self.cx.tcx, right_ty)) | |
| 241 | && let right_ty = self.ecx.typeck.expr_ty(right) | |
| 242 | && let left = self.ecx.eval(left) | |
| 243 | && let right = self.ecx.eval(right).and_then(|c| c.int_value(self.ecx.tcx, right_ty)) | |
| 251 | 244 | && matches!( |
| 252 | 245 | (left, right), |
| 253 | 246 | // `1 / x`: x might be zero |
| ... | ... | @@ -265,16 +258,14 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS |
| 265 | 258 | // error and it's good to have the eagerness warning up front when the user fixes the logic error. |
| 266 | 259 | ExprKind::Binary(op, left, right) |
| 267 | 260 | if matches!(op.node, BinOpKind::Add | BinOpKind::Sub | BinOpKind::Mul) |
| 268 | && !self.cx.typeck_results().expr_ty(e).is_floating_point() | |
| 269 | && let ecx = ConstEvalCtxt::new(self.cx) | |
| 270 | && (ecx.eval(left).is_none() || ecx.eval(right).is_none()) => | |
| 261 | && !self.ecx.typeck.expr_ty(e).is_floating_point() | |
| 262 | && (self.ecx.eval(left).is_none() || self.ecx.eval(right).is_none()) => | |
| 271 | 263 | { |
| 272 | 264 | self.eagerness |= NoChange; |
| 273 | 265 | }, |
| 274 | 266 | |
| 275 | 267 | ExprKind::Binary(_, lhs, rhs) |
| 276 | if self.cx.typeck_results().expr_ty(lhs).is_primitive() | |
| 277 | && self.cx.typeck_results().expr_ty(rhs).is_primitive() => {}, | |
| 268 | if self.ecx.typeck.expr_ty(lhs).is_primitive() && self.ecx.typeck.expr_ty(rhs).is_primitive() => {}, | |
| 278 | 269 | |
| 279 | 270 | // Can't be moved into a closure |
| 280 | 271 | ExprKind::Break(..) |
| ... | ... | @@ -322,7 +313,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS |
| 322 | 313 | } |
| 323 | 314 | |
| 324 | 315 | let mut v = V { |
| 325 | cx, | |
| 316 | ecx: ConstEvalCtxt::new(cx), | |
| 326 | 317 | eagerness: EagernessSuggestion::Eager, |
| 327 | 318 | }; |
| 328 | 319 | v.visit_expr(e); |
src/tools/clippy/clippy_utils/src/hir_utils.rs+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use crate::consts::ConstEvalCtxt; |
| 2 | 2 | use crate::macros::macro_backtrace; |
| 3 | use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; | |
| 3 | use crate::source::{SpanExt, SpanRange, walk_span_to_context}; | |
| 4 | 4 | use crate::{sym, tokenize_with_text}; |
| 5 | 5 | use core::mem; |
| 6 | 6 | use rustc_ast::ast; |
| ... | ... | @@ -1036,7 +1036,7 @@ fn reduce_exprkind<'hir>( |
| 1036 | 1036 | // `{}` => `()` |
| 1037 | 1037 | ([], None) |
| 1038 | 1038 | if block.span.ctxt() != eval_ctxt |
| 1039 | || block.span.check_source_text(cx, |src| { | |
| 1039 | || block.span.check_text(cx, |src| { | |
| 1040 | 1040 | tokenize(src, FrontmatterAllowed::No) |
| 1041 | 1041 | .map(|t| t.kind) |
| 1042 | 1042 | .filter(|t| { |
src/tools/clippy/clippy_utils/src/lib.rs+22-58| ... | ... | @@ -46,7 +46,6 @@ mod check_proc_macro; |
| 46 | 46 | pub mod comparisons; |
| 47 | 47 | pub mod consts; |
| 48 | 48 | pub mod diagnostics; |
| 49 | pub mod disallowed_profiles; | |
| 50 | 49 | pub mod eager_or_lazy; |
| 51 | 50 | pub mod higher; |
| 52 | 51 | mod hir_utils; |
| ... | ... | @@ -116,14 +115,14 @@ use rustc_span::hygiene::{ExpnKind, MacroKind}; |
| 116 | 115 | use rustc_span::source_map::SourceMap; |
| 117 | 116 | use rustc_span::symbol::{Ident, Symbol, kw}; |
| 118 | 117 | use rustc_span::{InnerSpan, Span, SyntaxContext}; |
| 119 | use source::{SpanRangeExt, walk_span_to_context}; | |
| 118 | use source::{SpanExt, walk_span_to_context}; | |
| 120 | 119 | use visitors::{Visitable, for_each_unconsumed_temporary}; |
| 121 | 120 | |
| 122 | 121 | use crate::ast_utils::unordered_over; |
| 123 | use crate::consts::ConstEvalCtxt; | |
| 124 | 122 | use crate::higher::Range; |
| 125 | 123 | use crate::msrvs::Msrv; |
| 126 | 124 | use crate::res::{MaybeDef, MaybeQPath, MaybeResPath}; |
| 125 | use crate::source::HasSourceMap; | |
| 127 | 126 | use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; |
| 128 | 127 | use crate::visitors::for_each_expr_without_closures; |
| 129 | 128 | |
| ... | ... | @@ -1329,59 +1328,23 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { |
| 1329 | 1328 | }) |
| 1330 | 1329 | } |
| 1331 | 1330 | |
| 1332 | /// Checks whether the given `Expr` is a range equivalent to a `RangeFull`. | |
| 1333 | /// | |
| 1334 | /// For the lower bound, this means that: | |
| 1335 | /// - either there is none | |
| 1336 | /// - or it is the smallest value that can be represented by the range's integer type | |
| 1337 | /// | |
| 1338 | /// For the upper bound, this means that: | |
| 1339 | /// - either there is none | |
| 1340 | /// - or it is the largest value that can be represented by the range's integer type and is | |
| 1341 | /// inclusive | |
| 1342 | /// - or it is a call to some container's `len` method and is exclusive, and the range is passed to | |
| 1343 | /// a method call on that same container (e.g. `v.drain(..v.len())`) | |
| 1344 | /// | |
| 1345 | /// If the given `Expr` is not some kind of range, the function returns `false`. | |
| 1346 | pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { | |
| 1347 | let ty = cx.typeck_results().expr_ty(expr); | |
| 1331 | /// Checks whether the given `Expr` is a range over the entire container. | |
| 1332 | pub fn is_full_collection_range(cx: &LateContext<'_>, container: Option<HirId>, expr: &Expr<'_>) -> bool { | |
| 1348 | 1333 | if let Some(Range { start, end, limits, .. }) = Range::hir(cx, expr) { |
| 1349 | let start_is_none_or_min = start.is_none_or(|start| { | |
| 1350 | if let rustc_ty::Adt(_, subst) = ty.kind() | |
| 1351 | && let bnd_ty = subst.type_at(0) | |
| 1352 | && let Some(start_const) = ConstEvalCtxt::new(cx).eval(start) | |
| 1353 | { | |
| 1354 | start_const.is_numeric_min(cx.tcx, bnd_ty) | |
| 1355 | } else { | |
| 1356 | false | |
| 1357 | } | |
| 1358 | }); | |
| 1359 | let end_is_none_or_max = end.is_none_or(|end| match limits { | |
| 1360 | RangeLimits::Closed => { | |
| 1361 | if let rustc_ty::Adt(_, subst) = ty.kind() | |
| 1362 | && let bnd_ty = subst.type_at(0) | |
| 1363 | && let Some(end_const) = ConstEvalCtxt::new(cx).eval(end) | |
| 1364 | { | |
| 1365 | end_const.is_numeric_max(cx.tcx, bnd_ty) | |
| 1366 | } else { | |
| 1367 | false | |
| 1368 | } | |
| 1369 | }, | |
| 1370 | RangeLimits::HalfOpen => { | |
| 1371 | if let Some(container_path) = container_path | |
| 1372 | && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind | |
| 1373 | && name.ident.name == sym::len | |
| 1374 | && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind | |
| 1334 | start.is_none_or(|start| is_integer_literal(start, 0)) | |
| 1335 | && end.is_none_or(|end| { | |
| 1336 | if limits == RangeLimits::HalfOpen | |
| 1337 | && let Some(container) = container | |
| 1338 | && let ExprKind::MethodCall(seg, recv, [], _) = end.kind | |
| 1375 | 1339 | { |
| 1376 | container_path.res == path.res | |
| 1340 | seg.ident.name == sym::len && recv.res_local_id() == Some(container) | |
| 1377 | 1341 | } else { |
| 1378 | 1342 | false |
| 1379 | 1343 | } |
| 1380 | }, | |
| 1381 | }); | |
| 1382 | return start_is_none_or_min && end_is_none_or_max; | |
| 1344 | }) | |
| 1345 | } else { | |
| 1346 | false | |
| 1383 | 1347 | } |
| 1384 | false | |
| 1385 | 1348 | } |
| 1386 | 1349 | |
| 1387 | 1350 | /// Checks whether the given expression is a constant literal of the given value. |
| ... | ... | @@ -2880,8 +2843,8 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str, Inn |
| 2880 | 2843 | |
| 2881 | 2844 | /// Checks whether a given span has any comment token |
| 2882 | 2845 | /// This checks for all types of comment: line "//", block "/**", doc "///" "//!" |
| 2883 | pub fn span_contains_comment(cx: &impl source::HasSession, span: Span) -> bool { | |
| 2884 | span.check_source_text(cx, |snippet| { | |
| 2846 | pub fn span_contains_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool { | |
| 2847 | span.check_text(sm, |snippet| { | |
| 2885 | 2848 | tokenize(snippet, FrontmatterAllowed::No).any(|token| { |
| 2886 | 2849 | matches!( |
| 2887 | 2850 | token.kind, |
| ... | ... | @@ -2895,8 +2858,8 @@ pub fn span_contains_comment(cx: &impl source::HasSession, span: Span) -> bool { |
| 2895 | 2858 | /// token, including comments unless `skip_comments` is set. |
| 2896 | 2859 | /// This is useful to determine if there are any actual code tokens in the span that are omitted in |
| 2897 | 2860 | /// the late pass, such as platform-specific code. |
| 2898 | pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool { | |
| 2899 | span.check_source_text(cx, |snippet| { | |
| 2861 | pub fn span_contains_non_whitespace<'sm>(sm: impl HasSourceMap<'sm>, span: Span, skip_comments: bool) -> bool { | |
| 2862 | span.check_text(sm, |snippet| { | |
| 2900 | 2863 | tokenize_with_text(snippet).any(|(token, _, _)| match token { |
| 2901 | 2864 | TokenKind::Whitespace => false, |
| 2902 | 2865 | TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments, |
| ... | ... | @@ -2904,18 +2867,19 @@ pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, sk |
| 2904 | 2867 | }) |
| 2905 | 2868 | }) |
| 2906 | 2869 | } |
| 2870 | ||
| 2907 | 2871 | /// Returns all the comments a given span contains |
| 2908 | 2872 | /// |
| 2909 | 2873 | /// Comments are returned wrapped with their relevant delimiters |
| 2910 | pub fn span_extract_comment(cx: &impl source::HasSession, span: Span) -> String { | |
| 2911 | span_extract_comments(cx, span).join("\n") | |
| 2874 | pub fn span_extract_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> String { | |
| 2875 | span_extract_comments(sm, span).join("\n") | |
| 2912 | 2876 | } |
| 2913 | 2877 | |
| 2914 | 2878 | /// Returns all the comments a given span contains. |
| 2915 | 2879 | /// |
| 2916 | 2880 | /// Comments are returned wrapped with their relevant delimiters. |
| 2917 | pub fn span_extract_comments(cx: &impl source::HasSession, span: Span) -> Vec<String> { | |
| 2918 | span.with_source_text(cx, |snippet| { | |
| 2881 | pub fn span_extract_comments<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Vec<String> { | |
| 2882 | span.with_source_text(sm, |snippet| { | |
| 2919 | 2883 | tokenize_with_text(snippet) |
| 2920 | 2884 | .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) |
| 2921 | 2885 | .map(|(_, s, _)| s.to_string()) |
src/tools/clippy/clippy_utils/src/msrvs.rs+32-10| ... | ... | @@ -3,8 +3,9 @@ use rustc_ast::Attribute; |
| 3 | 3 | use rustc_ast::attr::AttributeExt; |
| 4 | 4 | use rustc_attr_parsing::parse_version; |
| 5 | 5 | use rustc_data_structures::smallvec::SmallVec; |
| 6 | use rustc_hir::RustcVersion; | |
| 6 | use rustc_hir::{HirId, RustcVersion}; | |
| 7 | 7 | use rustc_lint::LateContext; |
| 8 | use rustc_middle::ty::TyCtxt; | |
| 8 | 9 | use rustc_session::Session; |
| 9 | 10 | use rustc_span::Symbol; |
| 10 | 11 | use serde::Deserialize; |
| ... | ... | @@ -26,7 +27,7 @@ msrv_aliases! { |
| 26 | 27 | 1,97,0 { ISOLATE_LOWEST_ONE } |
| 27 | 28 | 1,93,0 { VEC_DEQUE_POP_BACK_IF, VEC_DEQUE_POP_FRONT_IF } |
| 28 | 29 | 1,91,0 { DURATION_FROM_MINUTES_HOURS } |
| 29 | 1,88,0 { LET_CHAINS } | |
| 30 | 1,88,0 { LET_CHAINS, AS_CHUNKS } | |
| 30 | 31 | 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST } |
| 31 | 32 | 1,86,0 { VEC_POP_IF } |
| 32 | 33 | 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL, WAKER_NOOP } |
| ... | ... | @@ -118,16 +119,29 @@ impl Msrv { |
| 118 | 119 | /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations |
| 119 | 120 | pub fn current(self, cx: &LateContext<'_>) -> Option<RustcVersion> { |
| 120 | 121 | if SEEN_MSRV_ATTR.load(Ordering::Relaxed) { |
| 121 | let start = cx.last_node_with_lint_attrs; | |
| 122 | if let Some(msrv_attr) = once(start) | |
| 123 | .chain(cx.tcx.hir_parent_id_iter(start)) | |
| 124 | .find_map(|id| parse_attrs(cx.tcx.sess, cx.tcx.hir_attrs(id))) | |
| 125 | { | |
| 126 | return Some(msrv_attr); | |
| 127 | } | |
| 122 | self.for_attrs(cx.tcx, cx.last_node_with_lint_attrs) | |
| 123 | } else { | |
| 124 | self.0 | |
| 128 | 125 | } |
| 126 | } | |
| 129 | 127 | |
| 130 | self.0 | |
| 128 | /// Returns the MSRV at the specified node | |
| 129 | /// | |
| 130 | /// If the crate being linted uses an `#[clippy::msrv]` attribute this will search the parent | |
| 131 | /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations | |
| 132 | pub fn at(self, tcx: TyCtxt<'_>, node: HirId) -> Option<RustcVersion> { | |
| 133 | if SEEN_MSRV_ATTR.load(Ordering::Relaxed) { | |
| 134 | self.for_attrs(tcx, node) | |
| 135 | } else { | |
| 136 | self.0 | |
| 137 | } | |
| 138 | } | |
| 139 | ||
| 140 | fn for_attrs(self, tcx: TyCtxt<'_>, node: HirId) -> Option<RustcVersion> { | |
| 141 | once(node) | |
| 142 | .chain(tcx.hir_parent_id_iter(node)) | |
| 143 | .find_map(|id| parse_attrs(tcx.sess, tcx.hir_attrs(id))) | |
| 144 | .or(self.0) | |
| 131 | 145 | } |
| 132 | 146 | |
| 133 | 147 | /// Checks if a required version from [this module](self) is met at the current node |
| ... | ... | @@ -138,6 +152,14 @@ impl Msrv { |
| 138 | 152 | self.current(cx).is_none_or(|msrv| msrv >= required) |
| 139 | 153 | } |
| 140 | 154 | |
| 155 | /// Checks if a required version from [this module](self) is met at the specified node | |
| 156 | /// | |
| 157 | /// If the crate being linted uses an `#[clippy::msrv]` attribute this will search the parent | |
| 158 | /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations | |
| 159 | pub fn meets_at(self, tcx: TyCtxt<'_>, node: HirId, required: RustcVersion) -> bool { | |
| 160 | self.at(tcx, node).is_none_or(|msrv| msrv >= required) | |
| 161 | } | |
| 162 | ||
| 141 | 163 | pub fn read_cargo(&mut self, sess: &Session) { |
| 142 | 164 | let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") |
| 143 | 165 | .ok() |
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs+12-10| ... | ... | @@ -6,9 +6,8 @@ |
| 6 | 6 | use crate::msrvs::{self, Msrv}; |
| 7 | 7 | use hir::LangItem; |
| 8 | 8 | use rustc_const_eval::check_consts::ConstCx; |
| 9 | use rustc_hir as hir; | |
| 10 | 9 | use rustc_hir::def_id::DefId; |
| 11 | use rustc_hir::{RustcVersion, StableSince}; | |
| 10 | use rustc_hir::{self as hir, HirId, RustcVersion, StableSince}; | |
| 12 | 11 | use rustc_infer::infer::TyCtxtInferExt; |
| 13 | 12 | use rustc_infer::traits::Obligation; |
| 14 | 13 | use rustc_lint::LateContext; |
| ... | ... | @@ -420,14 +419,17 @@ fn check_terminator<'tcx>( |
| 420 | 419 | |
| 421 | 420 | /// Checks if the given `def_id` is a stable const fn, in respect to the given MSRV. |
| 422 | 421 | pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool { |
| 423 | cx.tcx.is_const_fn(def_id) | |
| 424 | && cx | |
| 425 | .tcx | |
| 422 | is_stable_const_fn_at(cx.tcx, cx.last_node_with_lint_attrs, def_id, msrv) | |
| 423 | } | |
| 424 | ||
| 425 | /// Checks if the given `def_id` is a stable const fn, in respect to the given MSRV. | |
| 426 | pub fn is_stable_const_fn_at(tcx: TyCtxt<'_>, node: HirId, def_id: DefId, msrv: Msrv) -> bool { | |
| 427 | tcx.is_const_fn(def_id) | |
| 428 | && tcx | |
| 426 | 429 | .lookup_const_stability(def_id) |
| 427 | 430 | .or_else(|| { |
| 428 | cx.tcx | |
| 429 | .trait_of_assoc(def_id) | |
| 430 | .and_then(|trait_def_id| cx.tcx.lookup_const_stability(trait_def_id)) | |
| 431 | tcx.trait_of_assoc(def_id) | |
| 432 | .and_then(|trait_def_id| tcx.lookup_const_stability(trait_def_id)) | |
| 431 | 433 | }) |
| 432 | 434 | .is_none_or(|const_stab| { |
| 433 | 435 | if let rustc_hir::StabilityLevel::Stable { since, .. } = const_stab.level { |
| ... | ... | @@ -441,10 +443,10 @@ pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bo |
| 441 | 443 | StableSince::Err(_) => return false, |
| 442 | 444 | }; |
| 443 | 445 | |
| 444 | msrv.meets(cx, const_stab_rust_version) | |
| 446 | msrv.meets_at(tcx, node, const_stab_rust_version) | |
| 445 | 447 | } else { |
| 446 | 448 | // Unstable const fn, check if the feature is enabled. |
| 447 | cx.tcx.features().enabled(const_stab.feature) && msrv.current(cx).is_none() | |
| 449 | tcx.features().enabled(const_stab.feature) && msrv.at(tcx, node).is_none() | |
| 448 | 450 | } |
| 449 | 451 | }) |
| 450 | 452 | } |
src/tools/clippy/clippy_utils/src/source.rs+98-85| ... | ... | @@ -20,27 +20,38 @@ use std::borrow::Cow; |
| 20 | 20 | use std::fmt; |
| 21 | 21 | use std::ops::{Deref, Index, Range}; |
| 22 | 22 | |
| 23 | pub trait HasSession { | |
| 24 | fn sess(&self) -> &Session; | |
| 23 | pub trait HasSourceMap<'sm>: Copy { | |
| 24 | #[must_use] | |
| 25 | fn source_map(self) -> &'sm SourceMap; | |
| 25 | 26 | } |
| 26 | impl HasSession for Session { | |
| 27 | fn sess(&self) -> &Session { | |
| 27 | impl<'sm> HasSourceMap<'sm> for &'sm SourceMap { | |
| 28 | #[inline] | |
| 29 | fn source_map(self) -> &'sm SourceMap { | |
| 28 | 30 | self |
| 29 | 31 | } |
| 30 | 32 | } |
| 31 | impl HasSession for TyCtxt<'_> { | |
| 32 | fn sess(&self) -> &Session { | |
| 33 | self.sess | |
| 33 | impl<'sm> HasSourceMap<'sm> for &'sm Session { | |
| 34 | #[inline] | |
| 35 | fn source_map(self) -> &'sm SourceMap { | |
| 36 | self.source_map() | |
| 34 | 37 | } |
| 35 | 38 | } |
| 36 | impl HasSession for EarlyContext<'_> { | |
| 37 | fn sess(&self) -> &Session { | |
| 38 | ::rustc_lint::LintContext::sess(self) | |
| 39 | impl<'sm> HasSourceMap<'sm> for TyCtxt<'sm> { | |
| 40 | #[inline] | |
| 41 | fn source_map(self) -> &'sm SourceMap { | |
| 42 | self.sess.source_map() | |
| 39 | 43 | } |
| 40 | 44 | } |
| 41 | impl HasSession for LateContext<'_> { | |
| 42 | fn sess(&self) -> &Session { | |
| 43 | self.tcx.sess() | |
| 45 | impl<'sm> HasSourceMap<'sm> for &'sm EarlyContext<'_> { | |
| 46 | #[inline] | |
| 47 | fn source_map(self) -> &'sm SourceMap { | |
| 48 | ::rustc_lint::LintContext::sess(self).source_map() | |
| 49 | } | |
| 50 | } | |
| 51 | impl<'sm> HasSourceMap<'sm> for &LateContext<'sm> { | |
| 52 | #[inline] | |
| 53 | fn source_map(self) -> &'sm SourceMap { | |
| 54 | self.tcx.sess.source_map() | |
| 44 | 55 | } |
| 45 | 56 | } |
| 46 | 57 | |
| ... | ... | @@ -95,39 +106,39 @@ impl IntoSpan for Range<BytePos> { |
| 95 | 106 | } |
| 96 | 107 | } |
| 97 | 108 | |
| 98 | pub trait SpanRangeExt: SpanRange { | |
| 109 | pub trait SpanExt: SpanRange { | |
| 99 | 110 | /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, |
| 100 | 111 | /// or the source text is not accessible. |
| 101 | fn get_source_text(self, cx: &impl HasSession) -> Option<SourceText> { | |
| 102 | get_source_range(cx.sess().source_map(), self.into_range()).and_then(SourceText::new) | |
| 112 | fn get_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option<SourceText> { | |
| 113 | get_source_range(sm.source_map(), self.into_range()).and_then(SourceText::new) | |
| 103 | 114 | } |
| 104 | 115 | |
| 105 | 116 | /// Gets the source file, and range in the file, of the given span. Returns `None` if the span |
| 106 | 117 | /// extends through multiple files, or is malformed. |
| 107 | fn get_source_range(self, cx: &impl HasSession) -> Option<SourceFileRange> { | |
| 108 | get_source_range(cx.sess().source_map(), self.into_range()) | |
| 118 | fn get_source_range<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option<SourceFileRange> { | |
| 119 | get_source_range(sm.source_map(), self.into_range()) | |
| 109 | 120 | } |
| 110 | 121 | |
| 111 | 122 | /// Calls the given function with the source text referenced and returns the value. Returns |
| 112 | 123 | /// `None` if the source text cannot be retrieved. |
| 113 | fn with_source_text<T>(self, cx: &impl HasSession, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> { | |
| 114 | with_source_text(cx.sess().source_map(), self.into_range(), f) | |
| 124 | fn with_source_text<'sm, T>(self, sm: impl HasSourceMap<'sm>, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> { | |
| 125 | with_source_text(sm.source_map(), self.into_range(), f) | |
| 115 | 126 | } |
| 116 | 127 | |
| 117 | 128 | /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the |
| 118 | 129 | /// source text cannot be retrieved. |
| 119 | fn check_source_text(self, cx: &impl HasSession, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { | |
| 120 | self.with_source_text(cx, pred).unwrap_or(false) | |
| 130 | fn check_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { | |
| 131 | self.with_source_text(sm, pred).unwrap_or(false) | |
| 121 | 132 | } |
| 122 | 133 | |
| 123 | 134 | /// Calls the given function with the both the text of the source file and the referenced range, |
| 124 | 135 | /// and returns the value. Returns `None` if the source text cannot be retrieved. |
| 125 | fn with_source_text_and_range<T>( | |
| 136 | fn with_source_text_and_range<'sm, T>( | |
| 126 | 137 | self, |
| 127 | cx: &impl HasSession, | |
| 138 | sm: impl HasSourceMap<'sm>, | |
| 128 | 139 | f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T, |
| 129 | 140 | ) -> Option<T> { |
| 130 | with_source_text_and_range(cx.sess().source_map(), self.into_range(), f) | |
| 141 | with_source_text_and_range(sm.source_map(), self.into_range(), f) | |
| 131 | 142 | } |
| 132 | 143 | |
| 133 | 144 | /// Calls the given function with the both the text of the source file and the referenced range, |
| ... | ... | @@ -135,12 +146,12 @@ pub trait SpanRangeExt: SpanRange { |
| 135 | 146 | /// retrieved, or no result is returned. |
| 136 | 147 | /// |
| 137 | 148 | /// The new range must reside within the same source file. |
| 138 | fn map_range( | |
| 149 | fn map_range<'sm>( | |
| 139 | 150 | self, |
| 140 | cx: &impl HasSession, | |
| 151 | sm: impl HasSourceMap<'sm>, | |
| 141 | 152 | f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range<usize>) -> Option<Range<usize>>, |
| 142 | 153 | ) -> Option<Range<BytePos>> { |
| 143 | map_range(cx.sess().source_map(), self.into_range(), f) | |
| 154 | map_range(sm.source_map(), self.into_range(), f) | |
| 144 | 155 | } |
| 145 | 156 | |
| 146 | 157 | /// Extends the range to include all preceding whitespace characters. |
| ... | ... | @@ -156,16 +167,16 @@ pub trait SpanRangeExt: SpanRange { |
| 156 | 167 | /// |
| 157 | 168 | /// When the range points to `foo`, suggesting to remove the range after it's been extended will |
| 158 | 169 | /// cause the `)` to be placed inside the line comment as `( // Some comment)`. |
| 159 | fn with_leading_whitespace(self, cx: &impl HasSession) -> Range<BytePos> { | |
| 160 | with_leading_whitespace(cx.sess().source_map(), self.into_range()) | |
| 170 | fn with_leading_whitespace<'sm>(self, sm: impl HasSourceMap<'sm>) -> Range<BytePos> { | |
| 171 | with_leading_whitespace(sm.source_map(), self.into_range()) | |
| 161 | 172 | } |
| 162 | 173 | |
| 163 | 174 | /// Trims the leading whitespace from the range. |
| 164 | fn trim_start(self, cx: &impl HasSession) -> Range<BytePos> { | |
| 165 | trim_start(cx.sess().source_map(), self.into_range()) | |
| 175 | fn trim_start<'sm>(self, sm: impl HasSourceMap<'sm>) -> Range<BytePos> { | |
| 176 | trim_start(sm.source_map(), self.into_range()) | |
| 166 | 177 | } |
| 167 | 178 | } |
| 168 | impl<T: SpanRange> SpanRangeExt for T {} | |
| 179 | impl<T: SpanRange> SpanExt for T {} | |
| 169 | 180 | |
| 170 | 181 | /// Handle to a range of text in a source file. |
| 171 | 182 | pub struct SourceText(SourceFileRange); |
| ... | ... | @@ -353,15 +364,15 @@ impl SourceFileRange { |
| 353 | 364 | } |
| 354 | 365 | |
| 355 | 366 | /// Like [`snippet_block`], but add braces if the expr is not an `ExprKind::Block` with no label. |
| 356 | pub fn expr_block( | |
| 357 | sess: &impl HasSession, | |
| 367 | pub fn expr_block<'sm>( | |
| 368 | sm: impl HasSourceMap<'sm>, | |
| 358 | 369 | expr: &Expr<'_>, |
| 359 | 370 | outer: SyntaxContext, |
| 360 | 371 | default: &str, |
| 361 | 372 | indent_relative_to: Option<Span>, |
| 362 | 373 | app: &mut Applicability, |
| 363 | 374 | ) -> String { |
| 364 | let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app); | |
| 375 | let (code, from_macro) = snippet_block_with_context(sm, expr.span, outer, default, indent_relative_to, app); | |
| 365 | 376 | if !from_macro |
| 366 | 377 | && let ExprKind::Block(block, None) = expr.kind |
| 367 | 378 | && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) |
| ... | ... | @@ -386,13 +397,13 @@ pub fn expr_block( |
| 386 | 397 | /// let x = (); |
| 387 | 398 | /// // ^^^^^^^^^^ |
| 388 | 399 | /// ``` |
| 389 | pub fn first_line_of_span(sess: &impl HasSession, span: Span) -> Span { | |
| 390 | first_char_in_first_line(sess, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) | |
| 400 | pub fn first_line_of_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { | |
| 401 | first_char_in_first_line(sm, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) | |
| 391 | 402 | } |
| 392 | 403 | |
| 393 | fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option<BytePos> { | |
| 394 | let line_span = line_span(sess, span); | |
| 395 | snippet_opt(sess, line_span).and_then(|snip| { | |
| 404 | fn first_char_in_first_line<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option<BytePos> { | |
| 405 | let line_span = line_span(sm, span); | |
| 406 | snippet_opt(sm, line_span).and_then(|snip| { | |
| 396 | 407 | snip.find(|c: char| !c.is_whitespace()) |
| 397 | 408 | .map(|pos| line_span.lo() + BytePos::from_usize(pos)) |
| 398 | 409 | }) |
| ... | ... | @@ -407,9 +418,9 @@ fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option<BytePo |
| 407 | 418 | /// let x = (); |
| 408 | 419 | /// // ^^^^^^^^^^^^^^ |
| 409 | 420 | /// ``` |
| 410 | fn line_span(sess: &impl HasSession, span: Span) -> Span { | |
| 421 | fn line_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { | |
| 411 | 422 | let span = original_sp(span, DUMMY_SP); |
| 412 | let SourceFileAndLine { sf, line } = sess.sess().source_map().lookup_line(span.lo()).unwrap(); | |
| 423 | let SourceFileAndLine { sf, line } = sm.source_map().lookup_line(span.lo()).unwrap(); | |
| 413 | 424 | let line_start = sf.lines()[line]; |
| 414 | 425 | let line_start = sf.absolute_position(line_start); |
| 415 | 426 | span.with_lo(line_start) |
| ... | ... | @@ -423,13 +434,13 @@ fn line_span(sess: &impl HasSession, span: Span) -> Span { |
| 423 | 434 | /// let x = (); |
| 424 | 435 | /// // ^^ -- will return 4 |
| 425 | 436 | /// ``` |
| 426 | pub fn indent_of(sess: &impl HasSession, span: Span) -> Option<usize> { | |
| 427 | snippet_opt(sess, line_span(sess, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) | |
| 437 | pub fn indent_of<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option<usize> { | |
| 438 | snippet_opt(sm, line_span(sm, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) | |
| 428 | 439 | } |
| 429 | 440 | |
| 430 | 441 | /// Gets a snippet of the indentation of the line of a span |
| 431 | pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> { | |
| 432 | snippet_opt(sess, line_span(sess, span)).map(|mut s| { | |
| 442 | pub fn snippet_indent<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option<String> { | |
| 443 | snippet_opt(sm, line_span(sm, span)).map(|mut s| { | |
| 433 | 444 | let len = s.len() - s.trim_start().len(); |
| 434 | 445 | s.truncate(len); |
| 435 | 446 | s |
| ... | ... | @@ -441,8 +452,8 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> { |
| 441 | 452 | // sources that the user has no control over. |
| 442 | 453 | // For some reason these attributes don't have any expansion info on them, so |
| 443 | 454 | // we have to check it this way until there is a better way. |
| 444 | pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool { | |
| 445 | if let Some(snippet) = snippet_opt(sess, span) | |
| 455 | pub fn is_present_in_source<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool { | |
| 456 | if let Some(snippet) = snippet_opt(sm, span) | |
| 446 | 457 | && snippet.is_empty() |
| 447 | 458 | { |
| 448 | 459 | return false; |
| ... | ... | @@ -534,8 +545,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, |
| 534 | 545 | /// snippet(cx, span1, "..") // -> "value" |
| 535 | 546 | /// snippet(cx, span2, "..") // -> "Vec::new()" |
| 536 | 547 | /// ``` |
| 537 | pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { | |
| 538 | snippet_opt(sess, span).map_or_else(|| Cow::Borrowed(default), From::from) | |
| 548 | pub fn snippet<'a, 'sm>(sm: impl HasSourceMap<'sm>, span: Span, default: &'a str) -> Cow<'a, str> { | |
| 549 | snippet_opt(sm, span).map_or_else(|| Cow::Borrowed(default), From::from) | |
| 539 | 550 | } |
| 540 | 551 | |
| 541 | 552 | /// Same as [`snippet`], but it adapts the applicability level by following rules: |
| ... | ... | @@ -547,17 +558,17 @@ pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow< |
| 547 | 558 | /// |
| 548 | 559 | /// If the span might realistically contain a macro call (e.g. `vec![]`), consider using |
| 549 | 560 | /// [`snippet_with_context`] instead. |
| 550 | pub fn snippet_with_applicability<'a>( | |
| 551 | sess: &impl HasSession, | |
| 561 | pub fn snippet_with_applicability<'a, 'sm>( | |
| 562 | sm: impl HasSourceMap<'sm>, | |
| 552 | 563 | span: Span, |
| 553 | 564 | default: &'a str, |
| 554 | 565 | applicability: &mut Applicability, |
| 555 | 566 | ) -> Cow<'a, str> { |
| 556 | snippet_with_applicability_sess(sess.sess(), span, default, applicability) | |
| 567 | snippet_with_applicability_sm(sm.source_map(), span, default, applicability) | |
| 557 | 568 | } |
| 558 | 569 | |
| 559 | fn snippet_with_applicability_sess<'a>( | |
| 560 | sess: &Session, | |
| 570 | fn snippet_with_applicability_sm<'a>( | |
| 571 | sm: &SourceMap, | |
| 561 | 572 | span: Span, |
| 562 | 573 | default: &'a str, |
| 563 | 574 | applicability: &mut Applicability, |
| ... | ... | @@ -565,7 +576,7 @@ fn snippet_with_applicability_sess<'a>( |
| 565 | 576 | if *applicability != Applicability::Unspecified && span.from_expansion() { |
| 566 | 577 | *applicability = Applicability::MaybeIncorrect; |
| 567 | 578 | } |
| 568 | if let Some(t) = snippet_opt(sess, span) { | |
| 579 | if let Some(t) = snippet_opt(sm, span) { | |
| 569 | 580 | Cow::Owned(t) |
| 570 | 581 | } else { |
| 571 | 582 | if *applicability == Applicability::MachineApplicable { |
| ... | ... | @@ -576,8 +587,8 @@ fn snippet_with_applicability_sess<'a>( |
| 576 | 587 | } |
| 577 | 588 | |
| 578 | 589 | /// Converts a span to a code snippet. Returns `None` if not available. |
| 579 | pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option<String> { | |
| 580 | sess.sess().source_map().span_to_snippet(span).ok() | |
| 590 | pub fn snippet_opt<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option<String> { | |
| 591 | sm.source_map().span_to_snippet(span).ok() | |
| 581 | 592 | } |
| 582 | 593 | |
| 583 | 594 | /// Converts a span (from a block) to a code snippet if available, otherwise use default. |
| ... | ... | @@ -614,37 +625,42 @@ pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option<String> { |
| 614 | 625 | /// } // aligned with `if` |
| 615 | 626 | /// ``` |
| 616 | 627 | /// Note that the first line of the snippet always has 0 indentation. |
| 617 | pub fn snippet_block(sess: &impl HasSession, span: Span, default: &str, indent_relative_to: Option<Span>) -> String { | |
| 618 | let snip = snippet(sess, span, default); | |
| 619 | let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); | |
| 628 | pub fn snippet_block<'sm>( | |
| 629 | sm: impl HasSourceMap<'sm>, | |
| 630 | span: Span, | |
| 631 | default: &str, | |
| 632 | indent_relative_to: Option<Span>, | |
| 633 | ) -> String { | |
| 634 | let snip = snippet(sm, span, default); | |
| 635 | let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); | |
| 620 | 636 | reindent_multiline(&snip, true, indent) |
| 621 | 637 | } |
| 622 | 638 | |
| 623 | 639 | /// Same as [`snippet_block`], but adapts the applicability level by the rules of |
| 624 | 640 | /// [`snippet_with_applicability`]. |
| 625 | pub fn snippet_block_with_applicability( | |
| 626 | sess: &impl HasSession, | |
| 641 | pub fn snippet_block_with_applicability<'sm>( | |
| 642 | sm: impl HasSourceMap<'sm>, | |
| 627 | 643 | span: Span, |
| 628 | 644 | default: &str, |
| 629 | 645 | indent_relative_to: Option<Span>, |
| 630 | 646 | applicability: &mut Applicability, |
| 631 | 647 | ) -> String { |
| 632 | let snip = snippet_with_applicability(sess, span, default, applicability); | |
| 633 | let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); | |
| 648 | let snip = snippet_with_applicability(sm, span, default, applicability); | |
| 649 | let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); | |
| 634 | 650 | reindent_multiline(&snip, true, indent) |
| 635 | 651 | } |
| 636 | 652 | |
| 637 | 653 | /// Combination of [`snippet_block`] and [`snippet_with_context`]. |
| 638 | pub fn snippet_block_with_context( | |
| 639 | sess: &impl HasSession, | |
| 654 | pub fn snippet_block_with_context<'sm>( | |
| 655 | sm: impl HasSourceMap<'sm>, | |
| 640 | 656 | span: Span, |
| 641 | 657 | outer: SyntaxContext, |
| 642 | 658 | default: &str, |
| 643 | 659 | indent_relative_to: Option<Span>, |
| 644 | 660 | app: &mut Applicability, |
| 645 | 661 | ) -> (String, bool) { |
| 646 | let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app); | |
| 647 | let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); | |
| 662 | let (snip, from_macro) = snippet_with_context(sm, span, outer, default, app); | |
| 663 | let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); | |
| 648 | 664 | (reindent_multiline(&snip, true, indent), from_macro) |
| 649 | 665 | } |
| 650 | 666 | |
| ... | ... | @@ -658,18 +674,18 @@ pub fn snippet_block_with_context( |
| 658 | 674 | /// correctly get a snippet of `vec![]`. |
| 659 | 675 | /// |
| 660 | 676 | /// This will also return whether or not the snippet is a macro call. |
| 661 | pub fn snippet_with_context<'a>( | |
| 662 | sess: &impl HasSession, | |
| 677 | pub fn snippet_with_context<'a, 'sm>( | |
| 678 | sm: impl HasSourceMap<'sm>, | |
| 663 | 679 | span: Span, |
| 664 | 680 | outer: SyntaxContext, |
| 665 | 681 | default: &'a str, |
| 666 | 682 | applicability: &mut Applicability, |
| 667 | 683 | ) -> (Cow<'a, str>, bool) { |
| 668 | snippet_with_context_sess(sess.sess(), span, outer, default, applicability) | |
| 684 | snippet_with_context_sm(sm.source_map(), span, outer, default, applicability) | |
| 669 | 685 | } |
| 670 | 686 | |
| 671 | fn snippet_with_context_sess<'a>( | |
| 672 | sess: &Session, | |
| 687 | fn snippet_with_context_sm<'a>( | |
| 688 | sm: &SourceMap, | |
| 673 | 689 | span: Span, |
| 674 | 690 | outer: SyntaxContext, |
| 675 | 691 | default: &'a str, |
| ... | ... | @@ -677,10 +693,7 @@ fn snippet_with_context_sess<'a>( |
| 677 | 693 | ) -> (Cow<'a, str>, bool) { |
| 678 | 694 | // If it is just range desugaring, use the desugaring span since it may include parenthesis. |
| 679 | 695 | if span.desugaring_kind() == Some(DesugaringKind::RangeExpr) && span.parent_callsite().unwrap().ctxt() == outer { |
| 680 | return ( | |
| 681 | snippet_with_applicability_sess(sess, span, default, applicability), | |
| 682 | false, | |
| 683 | ); | |
| 696 | return (snippet_with_applicability_sm(sm, span, default, applicability), false); | |
| 684 | 697 | } |
| 685 | 698 | |
| 686 | 699 | let (span, is_macro_call) = walk_span_to_context(span, outer).map_or_else( |
| ... | ... | @@ -696,7 +709,7 @@ fn snippet_with_context_sess<'a>( |
| 696 | 709 | ); |
| 697 | 710 | |
| 698 | 711 | ( |
| 699 | snippet_with_applicability_sess(sess, span, default, applicability), | |
| 712 | snippet_with_applicability_sm(sm, span, default, applicability), | |
| 700 | 713 | is_macro_call, |
| 701 | 714 | ) |
| 702 | 715 | } |
| ... | ... | @@ -759,15 +772,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span { |
| 759 | 772 | /// writeln!(o, "") -> writeln!(o, "") |
| 760 | 773 | /// ^^ ^^^^ |
| 761 | 774 | /// ``` |
| 762 | pub fn expand_past_previous_comma(sess: &impl HasSession, span: Span) -> Span { | |
| 763 | let extended = sess.sess().source_map().span_extend_to_prev_char(span, ',', true); | |
| 775 | pub fn expand_past_previous_comma<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { | |
| 776 | let extended = sm.source_map().span_extend_to_prev_char(span, ',', true); | |
| 764 | 777 | extended.with_lo(extended.lo() - BytePos(1)) |
| 765 | 778 | } |
| 766 | 779 | |
| 767 | 780 | /// Converts `expr` to a `char` literal if it's a `str` literal containing a single |
| 768 | 781 | /// character (or a single byte with `ascii_only`) |
| 769 | pub fn str_literal_to_char_literal( | |
| 770 | sess: &impl HasSession, | |
| 782 | pub fn str_literal_to_char_literal<'sm>( | |
| 783 | sm: impl HasSourceMap<'sm>, | |
| 771 | 784 | expr: &Expr<'_>, |
| 772 | 785 | applicability: &mut Applicability, |
| 773 | 786 | ascii_only: bool, |
| ... | ... | @@ -782,7 +795,7 @@ pub fn str_literal_to_char_literal( |
| 782 | 795 | } |
| 783 | 796 | && len == 1 |
| 784 | 797 | { |
| 785 | let snip = snippet_with_applicability(sess, expr.span, string, applicability); | |
| 798 | let snip = snippet_with_applicability(sm, expr.span, string, applicability); | |
| 786 | 799 | let ch = if let StrStyle::Raw(nhash) = style { |
| 787 | 800 | let nhash = nhash as usize; |
| 788 | 801 | // for raw string: r##"a"## |
src/tools/clippy/clippy_utils/src/sym.rs+2-2| ... | ... | @@ -176,6 +176,8 @@ generate! { |
| 176 | 176 | checked_sub, |
| 177 | 177 | child_id, |
| 178 | 178 | child_kill, |
| 179 | chunks_exact, | |
| 180 | chunks_exact_mut, | |
| 179 | 181 | clamp, |
| 180 | 182 | clippy_utils, |
| 181 | 183 | clone_into, |
| ... | ... | @@ -209,8 +211,6 @@ generate! { |
| 209 | 211 | deprecated_in_future, |
| 210 | 212 | deref_mut_method, |
| 211 | 213 | diagnostics, |
| 212 | disallowed_profile, | |
| 213 | disallowed_profiles, | |
| 214 | 214 | disallowed_types, |
| 215 | 215 | drain, |
| 216 | 216 | dump, |
src/tools/clippy/clippy_utils/src/ty/mod.rs+110-21| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | #![allow(clippy::module_name_repetitions)] |
| 4 | 4 | |
| 5 | 5 | use core::ops::ControlFlow; |
| 6 | use rustc_abi::VariantIdx; | |
| 6 | use rustc_abi::{BackendRepr, FieldsShape, VariantIdx, Variants}; | |
| 7 | 7 | use rustc_ast::ast::Mutability; |
| 8 | 8 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
| 9 | 9 | use rustc_hir as hir; |
| ... | ... | @@ -17,7 +17,7 @@ use rustc_middle::mir::ConstValue; |
| 17 | 17 | use rustc_middle::mir::interpret::Scalar; |
| 18 | 18 | use rustc_middle::traits::EvaluationResult; |
| 19 | 19 | use rustc_middle::ty::adjustment::{Adjust, Adjustment, DerefAdjustKind}; |
| 20 | use rustc_middle::ty::layout::ValidityRequirement; | |
| 20 | use rustc_middle::ty::layout::{LayoutError, LayoutOf, TyAndLayout}; | |
| 21 | 21 | use rustc_middle::ty::{ |
| 22 | 22 | self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, BoundVarIndexKind, FnSig, GenericArg, |
| 23 | 23 | GenericArgKind, GenericArgsRef, IntTy, ProjectionAliasTy, Region, RegionKind, TraitRef, Ty, TyCtxt, |
| ... | ... | @@ -34,7 +34,7 @@ use std::{debug_assert_matches, iter, mem}; |
| 34 | 34 | |
| 35 | 35 | use crate::paths::{PathNS, lookup_path_str}; |
| 36 | 36 | use crate::res::{MaybeDef, MaybeQPath}; |
| 37 | use crate::sym; | |
| 37 | use crate::{over, sym}; | |
| 38 | 38 | |
| 39 | 39 | mod type_certainty; |
| 40 | 40 | pub use type_certainty::expr_type_is_certain; |
| ... | ... | @@ -486,8 +486,8 @@ pub fn peel_n_ty_refs(mut ty: Ty<'_>, n: usize) -> (Ty<'_>, Option<Mutability>) |
| 486 | 486 | /// and `false` for: |
| 487 | 487 | /// - `Result<u32, String>` and `Result<usize, String>` |
| 488 | 488 | pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { |
| 489 | match (&a.kind(), &b.kind()) { | |
| 490 | (&ty::Adt(did_a, args_a), &ty::Adt(did_b, args_b)) => { | |
| 489 | match (a.kind(), b.kind()) { | |
| 490 | (ty::Adt(did_a, args_a), ty::Adt(did_b, args_b)) => { | |
| 491 | 491 | if did_a != did_b { |
| 492 | 492 | return false; |
| 493 | 493 | } |
| ... | ... | @@ -500,35 +500,112 @@ pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { |
| 500 | 500 | _ => true, |
| 501 | 501 | }) |
| 502 | 502 | }, |
| 503 | (ty::Ref(_, a, mut_a), ty::Ref(_, b, mut_b)) => mut_a == mut_b && same_type_modulo_regions(*a, *b), | |
| 504 | (ty::Tuple(as_), ty::Tuple(bs)) => over(as_, bs, |a, b| same_type_modulo_regions(*a, *b)), | |
| 505 | (ty::Array(a, na), ty::Array(b, nb)) => na == nb && same_type_modulo_regions(*a, *b), | |
| 503 | 506 | _ => a == b, |
| 504 | 507 | } |
| 505 | 508 | } |
| 506 | 509 | |
| 507 | 510 | /// Checks if a given type looks safe to be uninitialized. |
| 508 | 511 | pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { |
| 509 | let typing_env = cx.typing_env().with_post_analysis_normalized(cx.tcx); | |
| 510 | cx.tcx | |
| 511 | .check_validity_requirement((ValidityRequirement::Uninit, typing_env.as_query_input(ty))) | |
| 512 | .unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty)) | |
| 512 | match cx.layout_of(ty) { | |
| 513 | Ok(layout) => is_uninit_value_valid_for_layout(cx, layout), | |
| 514 | // The type layout is either not concrete enough yet or too large, fall back to structural check instead | |
| 515 | Err(LayoutError::TooGeneric(_) | LayoutError::SizeOverflow(_)) => is_uninit_value_valid_for_ty_fallback(cx, ty), | |
| 516 | Err(_) => false, | |
| 517 | } | |
| 518 | } | |
| 519 | ||
| 520 | fn is_uninit_value_valid_for_layout<'tcx>(cx: &LateContext<'tcx>, layout: TyAndLayout<'tcx>) -> bool { | |
| 521 | // ZSTs contribute no bytes to the vector buffer | |
| 522 | if layout.layout.is_zst() { | |
| 523 | return true; | |
| 524 | } | |
| 525 | ||
| 526 | match layout.layout.backend_repr { | |
| 527 | BackendRepr::Scalar(s) => s.is_uninit_valid(), | |
| 528 | BackendRepr::ScalarPair(a, b) => a.is_uninit_valid() && b.is_uninit_valid(), | |
| 529 | BackendRepr::SimdVector { element, count } => count == 0 || element.is_uninit_valid(), | |
| 530 | BackendRepr::SimdScalableVector { element, .. } => element.is_uninit_valid(), | |
| 531 | // Here validity is determined by the structural fields instead. | |
| 532 | BackendRepr::Memory { .. } => match &layout.layout.variants { | |
| 533 | Variants::Single { .. } => match &layout.layout.fields { | |
| 534 | FieldsShape::Primitive => { | |
| 535 | debug_assert!(false, "Both Scalar primitives and ! should be handled above."); | |
| 536 | false | |
| 537 | }, | |
| 538 | // Arrays are valid if empty, or if their elements are valid. | |
| 539 | FieldsShape::Array { count, .. } => { | |
| 540 | if *count == 0 { | |
| 541 | true | |
| 542 | } else { | |
| 543 | is_uninit_value_valid_for_layout(cx, layout.field(cx, 0)) | |
| 544 | } | |
| 545 | }, | |
| 546 | // Structs like types are valid only if all fields are valid. | |
| 547 | FieldsShape::Arbitrary { offsets, .. } => { | |
| 548 | (0..offsets.len()).all(|i| is_uninit_value_valid_for_layout(cx, layout.field(cx, i))) | |
| 549 | }, | |
| 550 | // Unions are valid if at least one field is valid. | |
| 551 | FieldsShape::Union(count) => { | |
| 552 | (0..count.get()).any(|i| is_uninit_value_valid_for_layout(cx, layout.field(cx, i))) | |
| 553 | }, | |
| 554 | }, | |
| 555 | // Types with no valid variants must be uninhabited | |
| 556 | Variants::Empty => true, | |
| 557 | // Enum like with multiple inhabited variants have a discriminant, they cannot be uninitialized. | |
| 558 | Variants::Multiple { .. } => false, | |
| 559 | }, | |
| 560 | } | |
| 513 | 561 | } |
| 514 | 562 | |
| 515 | /// A fallback for polymorphic types, which are not supported by `check_validity_requirement`. | |
| 563 | /// Fallback for polymorphic types where `layout_of` fails | |
| 516 | 564 | fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { |
| 565 | let typing_env = cx.typing_env().with_post_analysis_normalized(cx.tcx); | |
| 566 | ||
| 517 | 567 | match *ty.kind() { |
| 518 | 568 | // The array length may be polymorphic, let's try the inner type. |
| 519 | ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), | |
| 569 | ty::Array(component, len) => { | |
| 570 | // Zero-length arrays are always valid | |
| 571 | if len.try_to_target_usize(cx.tcx) == Some(0) { | |
| 572 | return true; | |
| 573 | } | |
| 574 | is_uninit_value_valid_for_ty(cx, component) | |
| 575 | }, | |
| 520 | 576 | // Peek through tuples and try their fallbacks. |
| 521 | 577 | ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), |
| 522 | // Unions are always fine right now. | |
| 523 | // This includes MaybeUninit, the main way people use uninitialized memory. | |
| 524 | ty::Adt(adt, _) if adt.is_union() => true, | |
| 578 | // For Unions, check if any field is uninit | |
| 579 | ty::Adt(adt, args) if adt.is_union() => adt.all_fields().any(|field| { | |
| 580 | let unnormalized_field_ty = field.ty(cx.tcx, args); | |
| 581 | let Ok(field_ty) = cx.tcx.try_normalize_erasing_regions(typing_env, unnormalized_field_ty) else { | |
| 582 | debug_assert!( | |
| 583 | false, | |
| 584 | "failed to normalize field type `{unnormalized_field_ty:?}`, ParamEnv is likely set incorrectly." | |
| 585 | ); | |
| 586 | return false; | |
| 587 | }; | |
| 588 | is_uninit_value_valid_for_ty(cx, field_ty) | |
| 589 | }), | |
| 525 | 590 | // Types (e.g. `UnsafeCell<MaybeUninit<T>>`) that recursively contain only types that can be uninit |
| 526 | 591 | // can themselves be uninit too. |
| 527 | // This purposefully ignores enums as they may have a discriminant that can't be uninit. | |
| 528 | ty::Adt(adt, args) if adt.is_struct() => adt | |
| 529 | .all_fields() | |
| 530 | .all(|field| is_uninit_value_valid_for_ty(cx, field.ty(cx.tcx, args).skip_norm_wip())), | |
| 531 | // For the rest, conservatively assume that they cannot be uninit. | |
| 592 | // This also applies for single variant enums, whose validity is determined by their fields. | |
| 593 | ty::Adt(adt, args) if adt.is_struct() || adt.variants().len() == 1 => adt.all_fields().all(|field| { | |
| 594 | let unnormalized_field_ty = field.ty(cx.tcx, args); | |
| 595 | let Ok(field_ty) = cx.tcx.try_normalize_erasing_regions(typing_env, unnormalized_field_ty) else { | |
| 596 | debug_assert!( | |
| 597 | false, | |
| 598 | "failed to normalize field type `{unnormalized_field_ty:?}`, ParamEnv is likely set incorrectly." | |
| 599 | ); | |
| 600 | return false; | |
| 601 | }; | |
| 602 | ||
| 603 | is_uninit_value_valid_for_ty(cx, field_ty) | |
| 604 | }), | |
| 605 | // Without a usable whole type layout, | |
| 606 | // conservatively reject remaining enum cases | |
| 607 | ty::Adt(adt, _) if adt.is_enum() => false, | |
| 608 | // Conservatively reject remaining types | |
| 532 | 609 | _ => false, |
| 533 | 610 | } |
| 534 | 611 | } |
| ... | ... | @@ -1049,9 +1126,13 @@ pub fn make_projection<'tcx>( |
| 1049 | 1126 | assert_generic_args_match(tcx, assoc_item.def_id, args); |
| 1050 | 1127 | |
| 1051 | 1128 | let kind = if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(assoc_item.def_id)) { |
| 1052 | ty::AliasTyKind::Inherent { def_id: assoc_item.def_id } | |
| 1129 | ty::AliasTyKind::Inherent { | |
| 1130 | def_id: assoc_item.def_id, | |
| 1131 | } | |
| 1053 | 1132 | } else { |
| 1054 | ty::AliasTyKind::Projection { def_id: assoc_item.def_id } | |
| 1133 | ty::AliasTyKind::Projection { | |
| 1134 | def_id: assoc_item.def_id, | |
| 1135 | } | |
| 1055 | 1136 | }; |
| 1056 | 1137 | |
| 1057 | 1138 | Some(AliasTy::new_from_args(tcx, kind, args)) |
| ... | ... | @@ -1335,6 +1416,14 @@ pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t |
| 1335 | 1416 | } |
| 1336 | 1417 | } |
| 1337 | 1418 | |
| 1419 | /// Check if `ty` is an `Option<T>` or a `Result<T, E>` and return its argument type (`T`) if it is. | |
| 1420 | pub fn option_or_result_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { | |
| 1421 | match ty.kind() { | |
| 1422 | ty::Adt(adt, args) if matches!(adt.opt_diag_name(cx), Some(sym::Option | sym::Result)) => Some(args.type_at(0)), | |
| 1423 | _ => None, | |
| 1424 | } | |
| 1425 | } | |
| 1426 | ||
| 1338 | 1427 | /// Check if a Ty<'_> of `Iterator` contains any mutable access to non-owning types by checking if |
| 1339 | 1428 | /// it contains fields of mutable references or pointers, or references/pointers to non-`Freeze` |
| 1340 | 1429 | /// types, or `PhantomData` types containing any of the previous. This can be used to check whether |
src/tools/clippy/clippy_utils/src/usage.rs+2-2| ... | ... | @@ -195,7 +195,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { |
| 195 | 195 | } |
| 196 | 196 | |
| 197 | 197 | pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool { |
| 198 | for_each_expr(cx, v, |e| { | |
| 198 | for_each_expr(cx.tcx, v, |e| { | |
| 199 | 199 | if e.res_local_id() == Some(local_id) { |
| 200 | 200 | ControlFlow::Break(()) |
| 201 | 201 | } else { |
| ... | ... | @@ -220,7 +220,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr |
| 220 | 220 | let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id); |
| 221 | 221 | |
| 222 | 222 | let mut past_expr = false; |
| 223 | for_each_expr(cx, block, |e| { | |
| 223 | for_each_expr(cx.tcx, block, |e| { | |
| 224 | 224 | if past_expr { |
| 225 | 225 | if e.res_local_id() == Some(local_id) { |
| 226 | 226 | ControlFlow::Break(()) |
src/tools/clippy/clippy_utils/src/visitors.rs+68-88| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use crate::get_enclosing_block; |
| 2 | 2 | use crate::msrvs::Msrv; |
| 3 | use crate::qualify_min_const_fn::is_stable_const_fn; | |
| 3 | use crate::qualify_min_const_fn::is_stable_const_fn_at; | |
| 4 | 4 | use crate::res::MaybeResPath; |
| 5 | 5 | use crate::ty::needs_ordered_drop; |
| 6 | 6 | use core::ops::ControlFlow; |
| ... | ... | @@ -8,8 +8,8 @@ use rustc_ast::visit::{VisitorResult, try_visit}; |
| 8 | 8 | use rustc_hir::def::{CtorKind, DefKind, Res}; |
| 9 | 9 | use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr}; |
| 10 | 10 | use rustc_hir::{ |
| 11 | self as hir, AmbigArg, AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, | |
| 12 | ItemKind, LetExpr, Pat, QPath, Stmt, StructTailExpr, UnOp, UnsafeSource, | |
| 11 | self as hir, AmbigArg, AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, CRATE_HIR_ID, Expr, ExprKind, HirId, | |
| 12 | ItemId, ItemKind, LetExpr, Pat, QPath, Stmt, StructTailExpr, UnOp, UnsafeSource, | |
| 13 | 13 | }; |
| 14 | 14 | use rustc_lint::LateContext; |
| 15 | 15 | use rustc_middle::hir::nested_filter; |
| ... | ... | @@ -145,7 +145,7 @@ pub fn for_each_expr_without_closures<'tcx, B, C: Continue>( |
| 145 | 145 | /// Calls the given function once for each expression contained. This will enter bodies, but not |
| 146 | 146 | /// nested items. |
| 147 | 147 | pub fn for_each_expr<'tcx, B, C: Continue>( |
| 148 | cx: &LateContext<'tcx>, | |
| 148 | tcx: TyCtxt<'tcx>, | |
| 149 | 149 | node: impl Visitable<'tcx>, |
| 150 | 150 | f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>, |
| 151 | 151 | ) -> Option<B> { |
| ... | ... | @@ -188,7 +188,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>( |
| 188 | 188 | ControlFlow::Continue(()) |
| 189 | 189 | } |
| 190 | 190 | } |
| 191 | let mut v = V { tcx: cx.tcx, f }; | |
| 191 | let mut v = V { tcx, f }; | |
| 192 | 192 | node.visit(&mut v).break_value() |
| 193 | 193 | } |
| 194 | 194 | |
| ... | ... | @@ -299,7 +299,7 @@ where |
| 299 | 299 | |
| 300 | 300 | /// Checks if the given resolved path is used in the given body. |
| 301 | 301 | pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { |
| 302 | for_each_expr(cx, cx.tcx.hir_body(body).value, |e| { | |
| 302 | for_each_expr(cx.tcx, cx.tcx.hir_body(body).value, |e| { | |
| 303 | 303 | if let ExprKind::Path(p) = &e.kind |
| 304 | 304 | && cx.qpath_res(p, e.hir_id) == res |
| 305 | 305 | { |
| ... | ... | @@ -312,7 +312,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { |
| 312 | 312 | |
| 313 | 313 | /// Checks if the given local is used. |
| 314 | 314 | pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { |
| 315 | for_each_expr(cx, visitable, |e| { | |
| 315 | for_each_expr(cx.tcx, visitable, |e| { | |
| 316 | 316 | if e.res_local_id() == Some(id) { |
| 317 | 317 | ControlFlow::Break(()) |
| 318 | 318 | } else { |
| ... | ... | @@ -322,89 +322,69 @@ pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tc |
| 322 | 322 | .is_some() |
| 323 | 323 | } |
| 324 | 324 | |
| 325 | /// Checks if the given expression is a constant. | |
| 326 | pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { | |
| 327 | struct V<'a, 'tcx> { | |
| 328 | cx: &'a LateContext<'tcx>, | |
| 329 | } | |
| 330 | ||
| 331 | impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { | |
| 332 | type Result = ControlFlow<()>; | |
| 333 | type NestedFilter = intravisit::nested_filter::None; | |
| 334 | ||
| 335 | fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result { | |
| 336 | match e.kind { | |
| 337 | ExprKind::ConstBlock(_) => return ControlFlow::Continue(()), | |
| 338 | ExprKind::Call( | |
| 339 | &Expr { | |
| 340 | kind: ExprKind::Path(ref p), | |
| 341 | hir_id, | |
| 342 | .. | |
| 343 | }, | |
| 344 | _, | |
| 345 | ) if self | |
| 346 | .cx | |
| 347 | .qpath_res(p, hir_id) | |
| 348 | .opt_def_id() | |
| 349 | .is_some_and(|id| is_stable_const_fn(self.cx, id, Msrv::default())) => {}, | |
| 350 | ExprKind::MethodCall(..) | |
| 351 | if self | |
| 352 | .cx | |
| 353 | .typeck_results() | |
| 354 | .type_dependent_def_id(e.hir_id) | |
| 355 | .is_some_and(|id| is_stable_const_fn(self.cx, id, Msrv::default())) => {}, | |
| 356 | ExprKind::Binary(_, lhs, rhs) | |
| 357 | if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty() | |
| 358 | && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {}, | |
| 359 | ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_raw_ptr() => (), | |
| 360 | ExprKind::Unary(_, e) if self.cx.typeck_results().expr_ty(e).peel_refs().is_primitive_ty() => (), | |
| 361 | ExprKind::Index(base, _, _) | |
| 362 | if matches!( | |
| 363 | self.cx.typeck_results().expr_ty(base).peel_refs().kind(), | |
| 364 | ty::Slice(_) | ty::Array(..) | |
| 365 | ) => {}, | |
| 366 | ExprKind::Path(ref p) | |
| 367 | if matches!( | |
| 368 | self.cx.qpath_res(p, e.hir_id), | |
| 369 | Res::Def( | |
| 370 | DefKind::Const { .. } | |
| 371 | | DefKind::AssocConst { .. } | |
| 372 | | DefKind::AnonConst | |
| 373 | | DefKind::ConstParam | |
| 374 | | DefKind::Ctor(..) | |
| 375 | | DefKind::Fn | |
| 376 | | DefKind::AssocFn, | |
| 377 | _ | |
| 378 | ) | Res::SelfCtor(_) | |
| 379 | ) => {}, | |
| 380 | ||
| 381 | ExprKind::AddrOf(..) | |
| 382 | | ExprKind::Array(_) | |
| 383 | | ExprKind::Block(..) | |
| 384 | | ExprKind::Cast(..) | |
| 385 | | ExprKind::DropTemps(_) | |
| 386 | | ExprKind::Field(..) | |
| 387 | | ExprKind::If(..) | |
| 388 | | ExprKind::Let(..) | |
| 389 | | ExprKind::Lit(_) | |
| 390 | | ExprKind::Match(..) | |
| 391 | | ExprKind::Repeat(..) | |
| 392 | | ExprKind::Struct(..) | |
| 393 | | ExprKind::Tup(_) | |
| 394 | | ExprKind::Type(..) | |
| 395 | | ExprKind::UnsafeBinderCast(..) => (), | |
| 396 | ||
| 397 | _ => { | |
| 398 | return ControlFlow::Break(()); | |
| 325 | /// Checks if the given expression can be evaluated as a constant at the specified node | |
| 326 | pub fn is_const_evaluatable<'tcx>(tcx: TyCtxt<'tcx>, typeck: &'tcx TypeckResults<'tcx>, e: &'tcx Expr<'_>) -> bool { | |
| 327 | for_each_expr(tcx, e, move |e| { | |
| 328 | match e.kind { | |
| 329 | ExprKind::ConstBlock(_) => return ControlFlow::Continue(Descend::No), | |
| 330 | ExprKind::Call( | |
| 331 | &Expr { | |
| 332 | kind: ExprKind::Path(ref p), | |
| 333 | hir_id, | |
| 334 | .. | |
| 399 | 335 | }, |
| 400 | } | |
| 336 | _, | |
| 337 | ) if typeck | |
| 338 | .qpath_res(p, hir_id) | |
| 339 | .opt_def_id() | |
| 340 | .is_some_and(|id| is_stable_const_fn_at(tcx, CRATE_HIR_ID, id, Msrv::default())) => {}, | |
| 341 | ExprKind::MethodCall(..) | |
| 342 | if typeck | |
| 343 | .type_dependent_def_id(e.hir_id) | |
| 344 | .is_some_and(|id| is_stable_const_fn_at(tcx, CRATE_HIR_ID, id, Msrv::default())) => {}, | |
| 345 | ExprKind::Binary(_, lhs, rhs) | |
| 346 | if typeck.expr_ty(lhs).peel_refs().is_primitive_ty() | |
| 347 | && typeck.expr_ty(rhs).peel_refs().is_primitive_ty() => {}, | |
| 348 | ExprKind::Unary(UnOp::Deref, e) if typeck.expr_ty(e).is_raw_ptr() => (), | |
| 349 | ExprKind::Unary(_, e) if typeck.expr_ty(e).peel_refs().is_primitive_ty() => (), | |
| 350 | ExprKind::Index(base, _, _) | |
| 351 | if matches!(typeck.expr_ty(base).peel_refs().kind(), ty::Slice(_) | ty::Array(..)) => {}, | |
| 352 | ExprKind::Path(ref p) | |
| 353 | if matches!( | |
| 354 | typeck.qpath_res(p, e.hir_id), | |
| 355 | Res::Def( | |
| 356 | DefKind::Const { .. } | |
| 357 | | DefKind::AssocConst { .. } | |
| 358 | | DefKind::AnonConst | |
| 359 | | DefKind::ConstParam | |
| 360 | | DefKind::Ctor(..) | |
| 361 | | DefKind::Fn | |
| 362 | | DefKind::AssocFn, | |
| 363 | _ | |
| 364 | ) | Res::SelfCtor(_) | |
| 365 | ) => {}, | |
| 366 | ||
| 367 | ExprKind::AddrOf(..) | |
| 368 | | ExprKind::Array(_) | |
| 369 | | ExprKind::Block(..) | |
| 370 | | ExprKind::Cast(..) | |
| 371 | | ExprKind::DropTemps(_) | |
| 372 | | ExprKind::Field(..) | |
| 373 | | ExprKind::If(..) | |
| 374 | | ExprKind::Let(..) | |
| 375 | | ExprKind::Lit(_) | |
| 376 | | ExprKind::Match(..) | |
| 377 | | ExprKind::Repeat(..) | |
| 378 | | ExprKind::Struct(..) | |
| 379 | | ExprKind::Tup(_) | |
| 380 | | ExprKind::Type(..) | |
| 381 | | ExprKind::UnsafeBinderCast(..) => {}, | |
| 401 | 382 | |
| 402 | walk_expr(self, e) | |
| 383 | _ => return ControlFlow::Break(()), | |
| 403 | 384 | } |
| 404 | } | |
| 405 | ||
| 406 | let mut v = V { cx }; | |
| 407 | v.visit_expr(e).is_continue() | |
| 385 | ControlFlow::Continue(Descend::Yes) | |
| 386 | }) | |
| 387 | .is_none() | |
| 408 | 388 | } |
| 409 | 389 | |
| 410 | 390 | /// Checks if the given expression performs an unsafe operation outside of an unsafe block. |
| ... | ... | @@ -785,7 +765,7 @@ pub fn local_used_once<'tcx>( |
| 785 | 765 | ) -> Option<&'tcx Expr<'tcx>> { |
| 786 | 766 | let mut expr = None; |
| 787 | 767 | |
| 788 | let cf = for_each_expr(cx, visitable, |e| { | |
| 768 | let cf = for_each_expr(cx.tcx, visitable, |e| { | |
| 789 | 769 | if e.res_local_id() == Some(id) && expr.replace(e).is_some() { |
| 790 | 770 | ControlFlow::Break(()) |
| 791 | 771 | } else { |
src/tools/clippy/rust-toolchain.toml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | [toolchain] |
| 2 | 2 | # begin autogenerated nightly |
| 3 | channel = "nightly-2026-06-11" | |
| 3 | channel = "nightly-2026-06-25" | |
| 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/tests/ui-toml/disallowed_profiles_methods/clippy.toml deleted-13| ... | ... | @@ -1,13 +0,0 @@ |
| 1 | disallowed-methods = [ | |
| 2 | { path = "std::mem::drop" } | |
| 3 | ] | |
| 4 | ||
| 5 | [profiles.forward_pass] | |
| 6 | disallowed-methods = [ | |
| 7 | { path = "alloc::vec::Vec::push", reason = "push is forbidden in forward profile" } | |
| 8 | ] | |
| 9 | ||
| 10 | [profiles.export] | |
| 11 | disallowed-methods = [ | |
| 12 | { path = "core::option::Option::unwrap" } | |
| 13 | ] |
src/tools/clippy/tests/ui-toml/disallowed_profiles_methods/main.rs deleted-78| ... | ... | @@ -1,78 +0,0 @@ |
| 1 | #![warn(clippy::disallowed_methods)] | |
| 2 | #![allow( | |
| 3 | unused, | |
| 4 | clippy::no_effect, | |
| 5 | clippy::needless_borrow, | |
| 6 | clippy::vec_init_then_push, | |
| 7 | clippy::unnecessary_literal_unwrap | |
| 8 | )] | |
| 9 | ||
| 10 | fn default_violation() { | |
| 11 | let value = String::from("test"); | |
| 12 | std::mem::drop(value); //~ ERROR: use of a disallowed method `std::mem::drop` | |
| 13 | } | |
| 14 | ||
| 15 | #[expect(clippy::disallowed_methods)] | |
| 16 | fn expected_violation() { | |
| 17 | let value = String::from("test"); | |
| 18 | std::mem::drop(value); | |
| 19 | } | |
| 20 | ||
| 21 | #[clippy::disallowed_profile("forward_pass")] | |
| 22 | fn forward_profile() { | |
| 23 | let mut values = Vec::new(); | |
| 24 | values.push(1); //~ ERROR: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) | |
| 25 | } | |
| 26 | ||
| 27 | #[clippy::disallowed_profile("export")] | |
| 28 | fn export_profile() { | |
| 29 | let value = Some(1); | |
| 30 | value.unwrap(); //~ ERROR: use of a disallowed method `core::option::Option::unwrap` (profile: export) | |
| 31 | } | |
| 32 | ||
| 33 | #[clippy::disallowed_profile("unknown_profile")] | |
| 34 | //~^ ERROR: unknown profile `unknown_profile` for | |
| 35 | //~| ERROR: unknown profile `unknown_profile` for | |
| 36 | fn unknown_profile() { | |
| 37 | let mut values = Vec::new(); | |
| 38 | values.push(1); | |
| 39 | // unknown profile falls back to the default list | |
| 40 | std::mem::drop(values); //~ ERROR: use of a disallowed method `std::mem::drop` | |
| 41 | } | |
| 42 | ||
| 43 | #[clippy::disallowed_profiles("forward_pass", "export")] | |
| 44 | fn merged_profiles() { | |
| 45 | let mut values = Vec::new(); | |
| 46 | values.push(1); //~ ERROR: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) | |
| 47 | let value = Some(1); | |
| 48 | value.unwrap(); //~ ERROR: use of a disallowed method `core::option::Option::unwrap` (profile: export) | |
| 49 | } | |
| 50 | ||
| 51 | // `#[expect(clippy::disallowed_methods)]` silences the body warning and the unknown-profile | |
| 52 | // warning tagged under `DISALLOWED_METHODS`, but not the one tagged under `DISALLOWED_TYPES`. | |
| 53 | #[expect(clippy::disallowed_methods)] | |
| 54 | #[clippy::disallowed_profile("unknown_profile_expect_before")] | |
| 55 | //~^ ERROR: unknown profile `unknown_profile_expect_before` for `clippy::disallowed_types` | |
| 56 | fn expect_before_unknown_profile() { | |
| 57 | let value = String::from("test"); | |
| 58 | std::mem::drop(value); | |
| 59 | } | |
| 60 | ||
| 61 | #[clippy::disallowed_profile("unknown_profile_expect_after")] | |
| 62 | //~^ ERROR: unknown profile `unknown_profile_expect_after` for `clippy::disallowed_types` | |
| 63 | #[expect(clippy::disallowed_methods)] | |
| 64 | fn expect_after_unknown_profile() { | |
| 65 | let value = String::from("test"); | |
| 66 | std::mem::drop(value); | |
| 67 | } | |
| 68 | ||
| 69 | fn main() { | |
| 70 | default_violation(); | |
| 71 | expected_violation(); | |
| 72 | forward_profile(); | |
| 73 | export_profile(); | |
| 74 | unknown_profile(); | |
| 75 | merged_profiles(); | |
| 76 | expect_before_unknown_profile(); | |
| 77 | expect_after_unknown_profile(); | |
| 78 | } |
src/tools/clippy/tests/ui-toml/disallowed_profiles_methods/main.stderr deleted-72| ... | ... | @@ -1,72 +0,0 @@ |
| 1 | error: use of a disallowed method `std::mem::drop` | |
| 2 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:12:5 | |
| 3 | | | |
| 4 | LL | std::mem::drop(value); | |
| 5 | | ^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: `-D clippy::disallowed-methods` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` | |
| 9 | ||
| 10 | error: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) | |
| 11 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:24:12 | |
| 12 | | | |
| 13 | LL | values.push(1); | |
| 14 | | ^^^^ | |
| 15 | | | |
| 16 | = note: push is forbidden in forward profile | |
| 17 | ||
| 18 | error: use of a disallowed method `core::option::Option::unwrap` (profile: export) | |
| 19 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:30:11 | |
| 20 | | | |
| 21 | LL | value.unwrap(); | |
| 22 | | ^^^^^^ | |
| 23 | ||
| 24 | error: `clippy::disallowed_profile` references unknown profile `unknown_profile` for `clippy::disallowed_methods` | |
| 25 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:33:30 | |
| 26 | | | |
| 27 | LL | #[clippy::disallowed_profile("unknown_profile")] | |
| 28 | | ^^^^^^^^^^^^^^^^^ | |
| 29 | ||
| 30 | error: `clippy::disallowed_profile` references unknown profile `unknown_profile` for `clippy::disallowed_types` | |
| 31 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:33:30 | |
| 32 | | | |
| 33 | LL | #[clippy::disallowed_profile("unknown_profile")] | |
| 34 | | ^^^^^^^^^^^^^^^^^ | |
| 35 | | | |
| 36 | = note: `-D clippy::disallowed-types` implied by `-D warnings` | |
| 37 | = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` | |
| 38 | ||
| 39 | error: use of a disallowed method `std::mem::drop` | |
| 40 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:40:5 | |
| 41 | | | |
| 42 | LL | std::mem::drop(values); | |
| 43 | | ^^^^^^^^^^^^^^ | |
| 44 | ||
| 45 | error: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass) | |
| 46 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:46:12 | |
| 47 | | | |
| 48 | LL | values.push(1); | |
| 49 | | ^^^^ | |
| 50 | | | |
| 51 | = note: push is forbidden in forward profile | |
| 52 | ||
| 53 | error: use of a disallowed method `core::option::Option::unwrap` (profile: export) | |
| 54 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:48:11 | |
| 55 | | | |
| 56 | LL | value.unwrap(); | |
| 57 | | ^^^^^^ | |
| 58 | ||
| 59 | error: `clippy::disallowed_profile` references unknown profile `unknown_profile_expect_before` for `clippy::disallowed_types` | |
| 60 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:54:30 | |
| 61 | | | |
| 62 | LL | #[clippy::disallowed_profile("unknown_profile_expect_before")] | |
| 63 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 64 | ||
| 65 | error: `clippy::disallowed_profile` references unknown profile `unknown_profile_expect_after` for `clippy::disallowed_types` | |
| 66 | --> tests/ui-toml/disallowed_profiles_methods/main.rs:61:30 | |
| 67 | | | |
| 68 | LL | #[clippy::disallowed_profile("unknown_profile_expect_after")] | |
| 69 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 70 | ||
| 71 | error: aborting due to 10 previous errors | |
| 72 |
src/tools/clippy/tests/ui-toml/disallowed_profiles_types/clippy.toml deleted-13| ... | ... | @@ -1,13 +0,0 @@ |
| 1 | disallowed-types = [ | |
| 2 | { path = "std::rc::Rc" } | |
| 3 | ] | |
| 4 | ||
| 5 | [profiles.forward_pass] | |
| 6 | disallowed-types = [ | |
| 7 | { path = "std::cell::RefCell", reason = "Prefer shared references" } | |
| 8 | ] | |
| 9 | ||
| 10 | [profiles.export] | |
| 11 | disallowed-types = [ | |
| 12 | { path = "std::sync::Mutex" } | |
| 13 | ] |
src/tools/clippy/tests/ui-toml/disallowed_profiles_types/main.rs deleted-61| ... | ... | @@ -1,61 +0,0 @@ |
| 1 | #![warn(clippy::disallowed_types)] | |
| 2 | #![allow(dead_code)] | |
| 3 | ||
| 4 | use std::rc::Rc; //~ ERROR: use of a disallowed type `std::rc::Rc` | |
| 5 | use std::sync::Mutex; | |
| 6 | ||
| 7 | struct Wrapper; | |
| 8 | ||
| 9 | fn default_type() { | |
| 10 | let _value: Rc<i32> = todo!(); //~ ERROR: use of a disallowed type `std::rc::Rc` | |
| 11 | } | |
| 12 | ||
| 13 | #[clippy::disallowed_profile("forward_pass")] | |
| 14 | fn forward_profile() { | |
| 15 | let _value: std::cell::RefCell<i32> = todo!(); //~ ERROR: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) | |
| 16 | } | |
| 17 | ||
| 18 | #[clippy::disallowed_profile("export")] | |
| 19 | fn export_profile() { | |
| 20 | let _value: Mutex<i32> = todo!(); //~ ERROR: use of a disallowed type `std::sync::Mutex` (profile: export) | |
| 21 | } | |
| 22 | ||
| 23 | #[clippy::disallowed_profile("unknown_type_profile")] | |
| 24 | //~^ ERROR: unknown profile `unknown_type_profile` for | |
| 25 | //~| ERROR: unknown profile `unknown_type_profile` for | |
| 26 | fn unknown_profile() { | |
| 27 | let _other = 1u32; | |
| 28 | let _fallback: Rc<i32> = todo!(); //~ ERROR: use of a disallowed type `std::rc::Rc` | |
| 29 | } | |
| 30 | ||
| 31 | #[clippy::disallowed_profiles("forward_pass", "export")] | |
| 32 | fn merged_profiles() { | |
| 33 | let _value: std::cell::RefCell<i32> = todo!(); //~ ERROR: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) | |
| 34 | let _other: Mutex<i32> = todo!(); //~ ERROR: use of a disallowed type `std::sync::Mutex` (profile: export) | |
| 35 | } | |
| 36 | ||
| 37 | // `#[expect(clippy::disallowed_types)]` silences the body warning and the unknown-profile | |
| 38 | // warning tagged under `DISALLOWED_TYPES`, but not one tagged under `DISALLOWED_METHODS`. | |
| 39 | #[expect(clippy::disallowed_types)] | |
| 40 | #[clippy::disallowed_profile("unknown_type_profile_expect_before")] | |
| 41 | //~^ ERROR: unknown profile `unknown_type_profile_expect_before` for `clippy::disallowed_methods` | |
| 42 | fn expect_before_unknown_profile() { | |
| 43 | let _value: Rc<i32> = todo!(); | |
| 44 | } | |
| 45 | ||
| 46 | #[clippy::disallowed_profile("unknown_type_profile_expect_after")] | |
| 47 | //~^ ERROR: unknown profile `unknown_type_profile_expect_after` for `clippy::disallowed_methods` | |
| 48 | #[expect(clippy::disallowed_types)] | |
| 49 | fn expect_after_unknown_profile() { | |
| 50 | let _value: Rc<i32> = todo!(); | |
| 51 | } | |
| 52 | ||
| 53 | fn main() { | |
| 54 | default_type(); | |
| 55 | forward_profile(); | |
| 56 | export_profile(); | |
| 57 | unknown_profile(); | |
| 58 | merged_profiles(); | |
| 59 | expect_before_unknown_profile(); | |
| 60 | expect_after_unknown_profile(); | |
| 61 | } |
src/tools/clippy/tests/ui-toml/disallowed_profiles_types/main.stderr deleted-78| ... | ... | @@ -1,78 +0,0 @@ |
| 1 | error: use of a disallowed type `std::rc::Rc` | |
| 2 | --> tests/ui-toml/disallowed_profiles_types/main.rs:4:1 | |
| 3 | | | |
| 4 | LL | use std::rc::Rc; | |
| 5 | | ^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: `-D clippy::disallowed-types` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` | |
| 9 | ||
| 10 | error: use of a disallowed type `std::rc::Rc` | |
| 11 | --> tests/ui-toml/disallowed_profiles_types/main.rs:10:17 | |
| 12 | | | |
| 13 | LL | let _value: Rc<i32> = todo!(); | |
| 14 | | ^^^^^^^ | |
| 15 | ||
| 16 | error: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) | |
| 17 | --> tests/ui-toml/disallowed_profiles_types/main.rs:15:17 | |
| 18 | | | |
| 19 | LL | let _value: std::cell::RefCell<i32> = todo!(); | |
| 20 | | ^^^^^^^^^^^^^^^^^^^^^^^ | |
| 21 | | | |
| 22 | = note: Prefer shared references | |
| 23 | ||
| 24 | error: use of a disallowed type `std::sync::Mutex` (profile: export) | |
| 25 | --> tests/ui-toml/disallowed_profiles_types/main.rs:20:17 | |
| 26 | | | |
| 27 | LL | let _value: Mutex<i32> = todo!(); | |
| 28 | | ^^^^^^^^^^ | |
| 29 | ||
| 30 | error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile` for `clippy::disallowed_methods` | |
| 31 | --> tests/ui-toml/disallowed_profiles_types/main.rs:23:30 | |
| 32 | | | |
| 33 | LL | #[clippy::disallowed_profile("unknown_type_profile")] | |
| 34 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
| 35 | | | |
| 36 | = note: `-D clippy::disallowed-methods` implied by `-D warnings` | |
| 37 | = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` | |
| 38 | ||
| 39 | error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile` for `clippy::disallowed_types` | |
| 40 | --> tests/ui-toml/disallowed_profiles_types/main.rs:23:30 | |
| 41 | | | |
| 42 | LL | #[clippy::disallowed_profile("unknown_type_profile")] | |
| 43 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
| 44 | ||
| 45 | error: use of a disallowed type `std::rc::Rc` | |
| 46 | --> tests/ui-toml/disallowed_profiles_types/main.rs:28:20 | |
| 47 | | | |
| 48 | LL | let _fallback: Rc<i32> = todo!(); | |
| 49 | | ^^^^^^^ | |
| 50 | ||
| 51 | error: use of a disallowed type `std::cell::RefCell` (profile: forward_pass) | |
| 52 | --> tests/ui-toml/disallowed_profiles_types/main.rs:33:17 | |
| 53 | | | |
| 54 | LL | let _value: std::cell::RefCell<i32> = todo!(); | |
| 55 | | ^^^^^^^^^^^^^^^^^^^^^^^ | |
| 56 | | | |
| 57 | = note: Prefer shared references | |
| 58 | ||
| 59 | error: use of a disallowed type `std::sync::Mutex` (profile: export) | |
| 60 | --> tests/ui-toml/disallowed_profiles_types/main.rs:34:17 | |
| 61 | | | |
| 62 | LL | let _other: Mutex<i32> = todo!(); | |
| 63 | | ^^^^^^^^^^ | |
| 64 | ||
| 65 | error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile_expect_before` for `clippy::disallowed_methods` | |
| 66 | --> tests/ui-toml/disallowed_profiles_types/main.rs:40:30 | |
| 67 | | | |
| 68 | LL | #[clippy::disallowed_profile("unknown_type_profile_expect_before")] | |
| 69 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 70 | ||
| 71 | error: `clippy::disallowed_profile` references unknown profile `unknown_type_profile_expect_after` for `clippy::disallowed_methods` | |
| 72 | --> tests/ui-toml/disallowed_profiles_types/main.rs:46:30 | |
| 73 | | | |
| 74 | LL | #[clippy::disallowed_profile("unknown_type_profile_expect_after")] | |
| 75 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 76 | ||
| 77 | error: aborting due to 11 previous errors | |
| 78 |
src/tools/clippy/tests/ui-toml/needless_late_init/clippy.toml created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | check-grouped-late-init = false |
src/tools/clippy/tests/ui-toml/needless_late_init/needless_late_init.rs created+64| ... | ... | @@ -0,0 +1,64 @@ |
| 1 | //@check-pass | |
| 2 | ||
| 3 | fn main() {} | |
| 4 | ||
| 5 | fn issue16330() { | |
| 6 | let a; | |
| 7 | let b; | |
| 8 | if true { | |
| 9 | a = 1; | |
| 10 | b = 2; | |
| 11 | } else { | |
| 12 | a = 3; | |
| 13 | b = 4; | |
| 14 | } | |
| 15 | ||
| 16 | let a; | |
| 17 | let mut b = 1; | |
| 18 | let c; | |
| 19 | if true { | |
| 20 | b = 1; | |
| 21 | a = 2; | |
| 22 | c = 3; | |
| 23 | } else { | |
| 24 | b = 6; | |
| 25 | a = 4; | |
| 26 | c = 5; | |
| 27 | } | |
| 28 | ||
| 29 | let b; | |
| 30 | { | |
| 31 | let a; | |
| 32 | let c; | |
| 33 | if true { | |
| 34 | b = 1; | |
| 35 | a = 2; | |
| 36 | c = 3; | |
| 37 | } else { | |
| 38 | b = 6; | |
| 39 | a = 4; | |
| 40 | c = 5; | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 44 | let a; | |
| 45 | let b; | |
| 46 | let c; | |
| 47 | match 1 { | |
| 48 | 1 => { | |
| 49 | a = 1; | |
| 50 | b = 2; | |
| 51 | c = 3; | |
| 52 | }, | |
| 53 | _ if false => { | |
| 54 | a = 4; | |
| 55 | b = 5; | |
| 56 | c = 6; | |
| 57 | }, | |
| 58 | _ => { | |
| 59 | a = 7; | |
| 60 | b = 8; | |
| 61 | c = 9; | |
| 62 | }, | |
| 63 | } | |
| 64 | } |
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr+3-3| ... | ... | @@ -33,6 +33,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect |
| 33 | 33 | avoid-breaking-exported-api |
| 34 | 34 | await-holding-invalid-types |
| 35 | 35 | cargo-ignore-publish |
| 36 | check-grouped-late-init | |
| 36 | 37 | check-incompatible-msrv-in-tests |
| 37 | 38 | check-inconsistent-struct-field-initializers |
| 38 | 39 | check-private-items |
| ... | ... | @@ -70,7 +71,6 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect |
| 70 | 71 | module-items-ordered-within-groupings |
| 71 | 72 | msrv |
| 72 | 73 | pass-by-value-size-limit |
| 73 | profiles | |
| 74 | 74 | pub-underscore-fields-behavior |
| 75 | 75 | recursive-self-in-type-definitions |
| 76 | 76 | semicolon-inside-block-ignore-singleline |
| ... | ... | @@ -135,6 +135,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect |
| 135 | 135 | avoid-breaking-exported-api |
| 136 | 136 | await-holding-invalid-types |
| 137 | 137 | cargo-ignore-publish |
| 138 | check-grouped-late-init | |
| 138 | 139 | check-incompatible-msrv-in-tests |
| 139 | 140 | check-inconsistent-struct-field-initializers |
| 140 | 141 | check-private-items |
| ... | ... | @@ -172,7 +173,6 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect |
| 172 | 173 | module-items-ordered-within-groupings |
| 173 | 174 | msrv |
| 174 | 175 | pass-by-value-size-limit |
| 175 | profiles | |
| 176 | 176 | pub-underscore-fields-behavior |
| 177 | 177 | recursive-self-in-type-definitions |
| 178 | 178 | semicolon-inside-block-ignore-singleline |
| ... | ... | @@ -237,6 +237,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni |
| 237 | 237 | avoid-breaking-exported-api |
| 238 | 238 | await-holding-invalid-types |
| 239 | 239 | cargo-ignore-publish |
| 240 | check-grouped-late-init | |
| 240 | 241 | check-incompatible-msrv-in-tests |
| 241 | 242 | check-inconsistent-struct-field-initializers |
| 242 | 243 | check-private-items |
| ... | ... | @@ -274,7 +275,6 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni |
| 274 | 275 | module-items-ordered-within-groupings |
| 275 | 276 | msrv |
| 276 | 277 | pass-by-value-size-limit |
| 277 | profiles | |
| 278 | 278 | pub-underscore-fields-behavior |
| 279 | 279 | recursive-self-in-type-definitions |
| 280 | 280 | semicolon-inside-block-ignore-singleline |
src/tools/clippy/tests/ui/author/issue_17240.rs created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | //@ check-pass | |
| 2 | // Ensure that a proper body is used when printing paths (`x`) | |
| 3 | // if the attribute is placed on an item. | |
| 4 | #[clippy::author] | |
| 5 | fn main() { | |
| 6 | let x = 42i32; | |
| 7 | _ = -x; | |
| 8 | } |
src/tools/clippy/tests/ui/author/issue_17240.stdout created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | if let ExprKind::Block(block, None) = expr.kind | |
| 2 | && block.stmts.len() == 2 | |
| 3 | && let StmtKind::Let(local) = block.stmts[0].kind | |
| 4 | && let Some(init) = local.init | |
| 5 | && let ExprKind::Lit(ref lit) = init.kind | |
| 6 | && let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node | |
| 7 | && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind | |
| 8 | && name.as_str() == "x" | |
| 9 | && let StmtKind::Semi(e) = block.stmts[1].kind | |
| 10 | && let ExprKind::Block(block1, None) = e.kind | |
| 11 | && block1.stmts.len() == 1 | |
| 12 | && let StmtKind::Let(local1) = block1.stmts[0].kind | |
| 13 | && let Some(init1) = local1.init | |
| 14 | && let ExprKind::Unary(UnOp::Neg, inner) = init1.kind | |
| 15 | && let PatKind::Wild = local1.pat.kind | |
| 16 | && block1.expr.is_none() | |
| 17 | && block.expr.is_none() | |
| 18 | { | |
| 19 | // report your lint here | |
| 20 | } |
src/tools/clippy/tests/ui/auxiliary/unnecessary_unwrap_unchecked_helper.rs created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | #![allow(unused, clippy::missing_safety_doc)] | |
| 2 | ||
| 3 | pub fn lol() -> Option<u32> { | |
| 4 | Some(0) | |
| 5 | } | |
| 6 | ||
| 7 | pub unsafe fn lol_unchecked() -> u32 { | |
| 8 | 0 | |
| 9 | } | |
| 10 | ||
| 11 | pub fn kek() -> Option<u32> { | |
| 12 | Some(0) | |
| 13 | } | |
| 14 | ||
| 15 | unsafe fn kek_unchecked() -> u32 { | |
| 16 | 0 | |
| 17 | } |
src/tools/clippy/tests/ui/by_ref_peekable_peek.1.fixed created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | #![warn(clippy::by_ref_peekable_peek)] | |
| 2 | ||
| 3 | struct S; | |
| 4 | ||
| 5 | impl S { | |
| 6 | fn by_ref(&mut self) -> impl Iterator<Item = i32> { | |
| 7 | std::iter::empty() | |
| 8 | } | |
| 9 | } | |
| 10 | ||
| 11 | macro_rules! mac { | |
| 12 | ($x:expr) => { | |
| 13 | $x.by_ref().peekable().peek() | |
| 14 | }; | |
| 15 | } | |
| 16 | ||
| 17 | fn with_non_clone_parameter(i: &mut impl Iterator<Item = i32>) { | |
| 18 | // This won't suggest `.clone().next().as_ref()` as `i` is not `Clone` | |
| 19 | let _: Option<&i32> = i.next().as_ref(); | |
| 20 | //~^ by_ref_peekable_peek | |
| 21 | } | |
| 22 | ||
| 23 | fn with_cloneable_local_iterator(a: Vec<i32>) { | |
| 24 | let mut i = a.into_iter(); | |
| 25 | let _: Option<&i32> = i.clone().next().as_ref(); | |
| 26 | //~^ by_ref_peekable_peek | |
| 27 | } | |
| 28 | ||
| 29 | fn with_cloneable_local_iterator_from_macro() { | |
| 30 | macro_rules! mac { | |
| 31 | () => { | |
| 32 | [1, 2, 3].into_iter() | |
| 33 | }; | |
| 34 | } | |
| 35 | let mut i = mac!(); | |
| 36 | let _: Option<&i32> = i.clone().next().as_ref(); | |
| 37 | //~^ by_ref_peekable_peek | |
| 38 | } | |
| 39 | ||
| 40 | fn main() { | |
| 41 | let mut iter = [1, 2, 3].into_iter(); | |
| 42 | let _: Option<&i32> = iter.clone().next().as_ref(); | |
| 43 | //~^ by_ref_peekable_peek | |
| 44 | #[expect(clippy::needless_borrow)] | |
| 45 | #[allow(clippy::unnecessary_mut_passed)] // For the `.clone().next().as_ref()` suggestion | |
| 46 | let _: Option<&i32> = (&mut iter).clone().next().as_ref(); | |
| 47 | //~^ by_ref_peekable_peek | |
| 48 | ||
| 49 | // Do not lint if `by_ref()` is not the one on `Iterator` | |
| 50 | let _: Option<&i32> = S.by_ref().peekable().peek(); | |
| 51 | ||
| 52 | // Do not lint if coming from a macro, as we cannot ensure | |
| 53 | // that all uses of `.by_ref()` will be `Iterator::by_ref()`. | |
| 54 | let _: Option<&i32> = mac!(iter); | |
| 55 | } |
src/tools/clippy/tests/ui/by_ref_peekable_peek.2.fixed created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | #![warn(clippy::by_ref_peekable_peek)] | |
| 2 | ||
| 3 | struct S; | |
| 4 | ||
| 5 | impl S { | |
| 6 | fn by_ref(&mut self) -> impl Iterator<Item = i32> { | |
| 7 | std::iter::empty() | |
| 8 | } | |
| 9 | } | |
| 10 | ||
| 11 | macro_rules! mac { | |
| 12 | ($x:expr) => { | |
| 13 | $x.by_ref().peekable().peek() | |
| 14 | }; | |
| 15 | } | |
| 16 | ||
| 17 | fn with_non_clone_parameter(i: &mut impl Iterator<Item = i32>) { | |
| 18 | // This won't suggest `.clone().next().as_ref()` as `i` is not `Clone` | |
| 19 | let _: Option<&i32> = i.next().as_ref(); | |
| 20 | //~^ by_ref_peekable_peek | |
| 21 | } | |
| 22 | ||
| 23 | fn with_cloneable_local_iterator(a: Vec<i32>) { | |
| 24 | let mut i = a.into_iter(); | |
| 25 | let _: Option<&i32> = i.next().as_ref(); | |
| 26 | //~^ by_ref_peekable_peek | |
| 27 | } | |
| 28 | ||
| 29 | fn with_cloneable_local_iterator_from_macro() { | |
| 30 | macro_rules! mac { | |
| 31 | () => { | |
| 32 | [1, 2, 3].into_iter() | |
| 33 | }; | |
| 34 | } | |
| 35 | let mut i = mac!(); | |
| 36 | let _: Option<&i32> = i.next().as_ref(); | |
| 37 | //~^ by_ref_peekable_peek | |
| 38 | } | |
| 39 | ||
| 40 | fn main() { | |
| 41 | let mut iter = [1, 2, 3].into_iter(); | |
| 42 | let _: Option<&i32> = iter.next().as_ref(); | |
| 43 | //~^ by_ref_peekable_peek | |
| 44 | #[expect(clippy::needless_borrow)] | |
| 45 | #[allow(clippy::unnecessary_mut_passed)] // For the `.clone().next().as_ref()` suggestion | |
| 46 | let _: Option<&i32> = (&mut iter).next().as_ref(); | |
| 47 | //~^ by_ref_peekable_peek | |
| 48 | ||
| 49 | // Do not lint if `by_ref()` is not the one on `Iterator` | |
| 50 | let _: Option<&i32> = S.by_ref().peekable().peek(); | |
| 51 | ||
| 52 | // Do not lint if coming from a macro, as we cannot ensure | |
| 53 | // that all uses of `.by_ref()` will be `Iterator::by_ref()`. | |
| 54 | let _: Option<&i32> = mac!(iter); | |
| 55 | } |
src/tools/clippy/tests/ui/by_ref_peekable_peek.3.fixed created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | #![warn(clippy::by_ref_peekable_peek)] | |
| 2 | ||
| 3 | struct S; | |
| 4 | ||
| 5 | impl S { | |
| 6 | fn by_ref(&mut self) -> impl Iterator<Item = i32> { | |
| 7 | std::iter::empty() | |
| 8 | } | |
| 9 | } | |
| 10 | ||
| 11 | macro_rules! mac { | |
| 12 | ($x:expr) => { | |
| 13 | $x.by_ref().peekable().peek() | |
| 14 | }; | |
| 15 | } | |
| 16 | ||
| 17 | fn with_non_clone_parameter(i: &mut impl Iterator<Item = i32>) { | |
| 18 | // This won't suggest `.clone().next().as_ref()` as `i` is not `Clone` | |
| 19 | let _: Option<&i32> = i.next().as_ref(); | |
| 20 | //~^ by_ref_peekable_peek | |
| 21 | } | |
| 22 | ||
| 23 | fn with_cloneable_local_iterator(a: Vec<i32>) { | |
| 24 | let mut i = a.into_iter().peekable(); | |
| 25 | let _: Option<&i32> = i.peek(); | |
| 26 | //~^ by_ref_peekable_peek | |
| 27 | } | |
| 28 | ||
| 29 | fn with_cloneable_local_iterator_from_macro() { | |
| 30 | macro_rules! mac { | |
| 31 | () => { | |
| 32 | [1, 2, 3].into_iter() | |
| 33 | }; | |
| 34 | } | |
| 35 | let mut i = mac!().peekable(); | |
| 36 | let _: Option<&i32> = i.peek(); | |
| 37 | //~^ by_ref_peekable_peek | |
| 38 | } | |
| 39 | ||
| 40 | fn main() { | |
| 41 | let mut iter = [1, 2, 3].into_iter().peekable(); | |
| 42 | let _: Option<&i32> = iter.peek(); | |
| 43 | //~^ by_ref_peekable_peek | |
| 44 | #[expect(clippy::needless_borrow)] | |
| 45 | #[allow(clippy::unnecessary_mut_passed)] // For the `.clone().next().as_ref()` suggestion | |
| 46 | let _: Option<&i32> = (&mut iter).clone().next().as_ref(); | |
| 47 | //~^ by_ref_peekable_peek | |
| 48 | ||
| 49 | // Do not lint if `by_ref()` is not the one on `Iterator` | |
| 50 | let _: Option<&i32> = S.by_ref().peekable().peek(); | |
| 51 | ||
| 52 | // Do not lint if coming from a macro, as we cannot ensure | |
| 53 | // that all uses of `.by_ref()` will be `Iterator::by_ref()`. | |
| 54 | let _: Option<&i32> = mac!(iter); | |
| 55 | } |
src/tools/clippy/tests/ui/by_ref_peekable_peek.rs created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | #![warn(clippy::by_ref_peekable_peek)] | |
| 2 | ||
| 3 | struct S; | |
| 4 | ||
| 5 | impl S { | |
| 6 | fn by_ref(&mut self) -> impl Iterator<Item = i32> { | |
| 7 | std::iter::empty() | |
| 8 | } | |
| 9 | } | |
| 10 | ||
| 11 | macro_rules! mac { | |
| 12 | ($x:expr) => { | |
| 13 | $x.by_ref().peekable().peek() | |
| 14 | }; | |
| 15 | } | |
| 16 | ||
| 17 | fn with_non_clone_parameter(i: &mut impl Iterator<Item = i32>) { | |
| 18 | // This won't suggest `.clone().next().as_ref()` as `i` is not `Clone` | |
| 19 | let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 20 | //~^ by_ref_peekable_peek | |
| 21 | } | |
| 22 | ||
| 23 | fn with_cloneable_local_iterator(a: Vec<i32>) { | |
| 24 | let mut i = a.into_iter(); | |
| 25 | let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 26 | //~^ by_ref_peekable_peek | |
| 27 | } | |
| 28 | ||
| 29 | fn with_cloneable_local_iterator_from_macro() { | |
| 30 | macro_rules! mac { | |
| 31 | () => { | |
| 32 | [1, 2, 3].into_iter() | |
| 33 | }; | |
| 34 | } | |
| 35 | let mut i = mac!(); | |
| 36 | let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 37 | //~^ by_ref_peekable_peek | |
| 38 | } | |
| 39 | ||
| 40 | fn main() { | |
| 41 | let mut iter = [1, 2, 3].into_iter(); | |
| 42 | let _: Option<&i32> = iter.by_ref().peekable().peek(); | |
| 43 | //~^ by_ref_peekable_peek | |
| 44 | #[expect(clippy::needless_borrow)] | |
| 45 | #[allow(clippy::unnecessary_mut_passed)] // For the `.clone().next().as_ref()` suggestion | |
| 46 | let _: Option<&i32> = (&mut iter).by_ref().peekable().peek(); | |
| 47 | //~^ by_ref_peekable_peek | |
| 48 | ||
| 49 | // Do not lint if `by_ref()` is not the one on `Iterator` | |
| 50 | let _: Option<&i32> = S.by_ref().peekable().peek(); | |
| 51 | ||
| 52 | // Do not lint if coming from a macro, as we cannot ensure | |
| 53 | // that all uses of `.by_ref()` will be `Iterator::by_ref()`. | |
| 54 | let _: Option<&i32> = mac!(iter); | |
| 55 | } |
src/tools/clippy/tests/ui/by_ref_peekable_peek.stderr created+101| ... | ... | @@ -0,0 +1,101 @@ |
| 1 | error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output | |
| 2 | --> tests/ui/by_ref_peekable_peek.rs:19:27 | |
| 3 | | | |
| 4 | LL | let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = help: you might want to transform the iterator itself using `.peekable()` without using `.by_ref()` | |
| 8 | = note: `-D clippy::by-ref-peekable-peek` implied by `-D warnings` | |
| 9 | = help: to override `-D warnings` add `#[allow(clippy::by_ref_peekable_peek)]` | |
| 10 | help: to advance the underlying iterator, use | |
| 11 | | | |
| 12 | LL - let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 13 | LL + let _: Option<&i32> = i.next().as_ref(); | |
| 14 | | | |
| 15 | ||
| 16 | error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output | |
| 17 | --> tests/ui/by_ref_peekable_peek.rs:25:27 | |
| 18 | | | |
| 19 | LL | let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 20 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 21 | | | |
| 22 | help: to peek the first item without advancing the underlying iterator, use | |
| 23 | | | |
| 24 | LL - let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 25 | LL + let _: Option<&i32> = i.clone().next().as_ref(); | |
| 26 | | | |
| 27 | help: to advance the underlying iterator, use | |
| 28 | | | |
| 29 | LL - let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 30 | LL + let _: Option<&i32> = i.next().as_ref(); | |
| 31 | | | |
| 32 | help: to make the iterator peekable, use | |
| 33 | | | |
| 34 | LL ~ let mut i = a.into_iter().peekable(); | |
| 35 | LL ~ let _: Option<&i32> = i.peek(); | |
| 36 | | | |
| 37 | ||
| 38 | error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output | |
| 39 | --> tests/ui/by_ref_peekable_peek.rs:36:27 | |
| 40 | | | |
| 41 | LL | let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 42 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 43 | | | |
| 44 | help: to peek the first item without advancing the underlying iterator, use | |
| 45 | | | |
| 46 | LL - let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 47 | LL + let _: Option<&i32> = i.clone().next().as_ref(); | |
| 48 | | | |
| 49 | help: to advance the underlying iterator, use | |
| 50 | | | |
| 51 | LL - let _: Option<&i32> = i.by_ref().peekable().peek(); | |
| 52 | LL + let _: Option<&i32> = i.next().as_ref(); | |
| 53 | | | |
| 54 | help: to make the iterator peekable, use | |
| 55 | | | |
| 56 | LL ~ let mut i = mac!().peekable(); | |
| 57 | LL ~ let _: Option<&i32> = i.peek(); | |
| 58 | | | |
| 59 | ||
| 60 | error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output | |
| 61 | --> tests/ui/by_ref_peekable_peek.rs:42:27 | |
| 62 | | | |
| 63 | LL | let _: Option<&i32> = iter.by_ref().peekable().peek(); | |
| 64 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 65 | | | |
| 66 | help: to peek the first item without advancing the underlying iterator, use | |
| 67 | | | |
| 68 | LL - let _: Option<&i32> = iter.by_ref().peekable().peek(); | |
| 69 | LL + let _: Option<&i32> = iter.clone().next().as_ref(); | |
| 70 | | | |
| 71 | help: to advance the underlying iterator, use | |
| 72 | | | |
| 73 | LL - let _: Option<&i32> = iter.by_ref().peekable().peek(); | |
| 74 | LL + let _: Option<&i32> = iter.next().as_ref(); | |
| 75 | | | |
| 76 | help: to make the iterator peekable, use | |
| 77 | | | |
| 78 | LL ~ let mut iter = [1, 2, 3].into_iter().peekable(); | |
| 79 | LL ~ let _: Option<&i32> = iter.peek(); | |
| 80 | | | |
| 81 | ||
| 82 | error: calling `.by_ref().peekable().peek()` will advance the underlying iterator and consume its first output | |
| 83 | --> tests/ui/by_ref_peekable_peek.rs:46:27 | |
| 84 | | | |
| 85 | LL | let _: Option<&i32> = (&mut iter).by_ref().peekable().peek(); | |
| 86 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 87 | | | |
| 88 | = help: you might want to transform the iterator itself using `.peekable()` without using `.by_ref()` | |
| 89 | help: to peek the first item without advancing the underlying iterator, use | |
| 90 | | | |
| 91 | LL - let _: Option<&i32> = (&mut iter).by_ref().peekable().peek(); | |
| 92 | LL + let _: Option<&i32> = (&mut iter).clone().next().as_ref(); | |
| 93 | | | |
| 94 | help: to advance the underlying iterator, use | |
| 95 | | | |
| 96 | LL - let _: Option<&i32> = (&mut iter).by_ref().peekable().peek(); | |
| 97 | LL + let _: Option<&i32> = (&mut iter).next().as_ref(); | |
| 98 | | | |
| 99 | ||
| 100 | error: aborting due to 5 previous errors | |
| 101 |
src/tools/clippy/tests/ui/chunks_exact_to_as_chunks.rs created+43| ... | ... | @@ -0,0 +1,43 @@ |
| 1 | #![warn(clippy::chunks_exact_to_as_chunks)] | |
| 2 | #![allow(unused)] | |
| 3 | ||
| 4 | fn main() { | |
| 5 | let slice = [1, 2, 3, 4, 5, 6, 7, 8]; | |
| 6 | ||
| 7 | // Should trigger lint - literal constant | |
| 8 | let mut it = slice.chunks_exact(4); | |
| 9 | //~^ chunks_exact_to_as_chunks | |
| 10 | for chunk in it {} | |
| 11 | ||
| 12 | // Should trigger lint - const value | |
| 13 | const CHUNK_SIZE: usize = 4; | |
| 14 | let mut it = slice.chunks_exact(CHUNK_SIZE); | |
| 15 | //~^ chunks_exact_to_as_chunks | |
| 16 | for chunk in it {} | |
| 17 | ||
| 18 | // Should NOT trigger - runtime value | |
| 19 | let size = 4; | |
| 20 | let mut it = slice.chunks_exact(size); | |
| 21 | for chunk in it {} | |
| 22 | ||
| 23 | // Should trigger lint - with remainder | |
| 24 | let mut it = slice.chunks_exact(3); | |
| 25 | //~^ chunks_exact_to_as_chunks | |
| 26 | for chunk in &mut it {} | |
| 27 | for e in it.remainder() {} | |
| 28 | ||
| 29 | // Should trigger - mutable variant | |
| 30 | let mut arr = [1, 2, 3, 4, 5, 6, 7, 8]; | |
| 31 | let mut it = arr.chunks_exact_mut(4); | |
| 32 | //~^ chunks_exact_to_as_chunks | |
| 33 | for chunk in it {} | |
| 34 | ||
| 35 | // Should NOT trigger - type must unify with another branch | |
| 36 | let condition = true; | |
| 37 | let y = 3; | |
| 38 | let _ = if condition { | |
| 39 | slice.chunks_exact(5) | |
| 40 | } else { | |
| 41 | slice.chunks_exact(y) | |
| 42 | }; | |
| 43 | } |
src/tools/clippy/tests/ui/chunks_exact_to_as_chunks.stderr created+56| ... | ... | @@ -0,0 +1,56 @@ |
| 1 | error: using `chunks_exact` with a constant chunk size | |
| 2 | --> tests/ui/chunks_exact_to_as_chunks.rs:8:24 | |
| 3 | | | |
| 4 | LL | let mut it = slice.chunks_exact(4); | |
| 5 | | ^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | help: consider using `as_chunks::<4>()` instead | |
| 8 | --> tests/ui/chunks_exact_to_as_chunks.rs:8:24 | |
| 9 | | | |
| 10 | LL | let mut it = slice.chunks_exact(4); | |
| 11 | | ^^^^^^^^^^^^^^^ | |
| 12 | = note: you can access the chunks using `it.0.iter()`, and the remainder using `it.1` | |
| 13 | = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings` | |
| 14 | = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]` | |
| 15 | ||
| 16 | error: using `chunks_exact` with a constant chunk size | |
| 17 | --> tests/ui/chunks_exact_to_as_chunks.rs:14:24 | |
| 18 | | | |
| 19 | LL | let mut it = slice.chunks_exact(CHUNK_SIZE); | |
| 20 | | ^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 21 | | | |
| 22 | help: consider using `as_chunks::<CHUNK_SIZE>()` instead | |
| 23 | --> tests/ui/chunks_exact_to_as_chunks.rs:14:24 | |
| 24 | | | |
| 25 | LL | let mut it = slice.chunks_exact(CHUNK_SIZE); | |
| 26 | | ^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 27 | = note: you can access the chunks using `it.0.iter()`, and the remainder using `it.1` | |
| 28 | ||
| 29 | error: using `chunks_exact` with a constant chunk size | |
| 30 | --> tests/ui/chunks_exact_to_as_chunks.rs:24:24 | |
| 31 | | | |
| 32 | LL | let mut it = slice.chunks_exact(3); | |
| 33 | | ^^^^^^^^^^^^^^^ | |
| 34 | | | |
| 35 | help: consider using `as_chunks::<3>()` instead | |
| 36 | --> tests/ui/chunks_exact_to_as_chunks.rs:24:24 | |
| 37 | | | |
| 38 | LL | let mut it = slice.chunks_exact(3); | |
| 39 | | ^^^^^^^^^^^^^^^ | |
| 40 | = note: you can access the chunks using `it.0.iter()`, and the remainder using `it.1` | |
| 41 | ||
| 42 | error: using `chunks_exact_mut` with a constant chunk size | |
| 43 | --> tests/ui/chunks_exact_to_as_chunks.rs:31:22 | |
| 44 | | | |
| 45 | LL | let mut it = arr.chunks_exact_mut(4); | |
| 46 | | ^^^^^^^^^^^^^^^^^^^ | |
| 47 | | | |
| 48 | help: consider using `as_chunks_mut::<4>()` instead | |
| 49 | --> tests/ui/chunks_exact_to_as_chunks.rs:31:22 | |
| 50 | | | |
| 51 | LL | let mut it = arr.chunks_exact_mut(4); | |
| 52 | | ^^^^^^^^^^^^^^^^^^^ | |
| 53 | = note: you can access the chunks using `it.0.iter()`, and the remainder using `it.1` | |
| 54 | ||
| 55 | error: aborting due to 4 previous errors | |
| 56 |
src/tools/clippy/tests/ui/clear_with_drain.fixed-30| ... | ... | @@ -20,11 +20,6 @@ fn vec_range() { |
| 20 | 20 | let mut v = vec![1, 2, 3]; |
| 21 | 21 | v.clear(); |
| 22 | 22 | //~^ clear_with_drain |
| 23 | ||
| 24 | // Do lint | |
| 25 | let mut v = vec![1, 2, 3]; | |
| 26 | v.clear(); | |
| 27 | //~^ clear_with_drain | |
| 28 | 23 | } |
| 29 | 24 | |
| 30 | 25 | fn vec_range_from() { |
| ... | ... | @@ -45,11 +40,6 @@ fn vec_range_from() { |
| 45 | 40 | let mut v = vec![1, 2, 3]; |
| 46 | 41 | v.clear(); |
| 47 | 42 | //~^ clear_with_drain |
| 48 | ||
| 49 | // Do lint | |
| 50 | let mut v = vec![1, 2, 3]; | |
| 51 | v.clear(); | |
| 52 | //~^ clear_with_drain | |
| 53 | 43 | } |
| 54 | 44 | |
| 55 | 45 | fn vec_range_full() { |
| ... | ... | @@ -124,11 +114,6 @@ fn vec_deque_range() { |
| 124 | 114 | let mut deque = VecDeque::from([1, 2, 3]); |
| 125 | 115 | deque.clear(); |
| 126 | 116 | //~^ clear_with_drain |
| 127 | ||
| 128 | // Do lint | |
| 129 | let mut deque = VecDeque::from([1, 2, 3]); | |
| 130 | deque.clear(); | |
| 131 | //~^ clear_with_drain | |
| 132 | 117 | } |
| 133 | 118 | |
| 134 | 119 | fn vec_deque_range_from() { |
| ... | ... | @@ -149,11 +134,6 @@ fn vec_deque_range_from() { |
| 149 | 134 | let mut deque = VecDeque::from([1, 2, 3]); |
| 150 | 135 | deque.clear(); |
| 151 | 136 | //~^ clear_with_drain |
| 152 | ||
| 153 | // Do lint | |
| 154 | let mut deque = VecDeque::from([1, 2, 3]); | |
| 155 | deque.clear(); | |
| 156 | //~^ clear_with_drain | |
| 157 | 137 | } |
| 158 | 138 | |
| 159 | 139 | fn vec_deque_range_full() { |
| ... | ... | @@ -228,11 +208,6 @@ fn string_range() { |
| 228 | 208 | let mut s = String::from("Hello, world!"); |
| 229 | 209 | s.clear(); |
| 230 | 210 | //~^ clear_with_drain |
| 231 | ||
| 232 | // Do lint | |
| 233 | let mut s = String::from("Hello, world!"); | |
| 234 | s.clear(); | |
| 235 | //~^ clear_with_drain | |
| 236 | 211 | } |
| 237 | 212 | |
| 238 | 213 | fn string_range_from() { |
| ... | ... | @@ -253,11 +228,6 @@ fn string_range_from() { |
| 253 | 228 | let mut s = String::from("Hello, world!"); |
| 254 | 229 | s.clear(); |
| 255 | 230 | //~^ clear_with_drain |
| 256 | ||
| 257 | // Do lint | |
| 258 | let mut s = String::from("Hello, world!"); | |
| 259 | s.clear(); | |
| 260 | //~^ clear_with_drain | |
| 261 | 231 | } |
| 262 | 232 | |
| 263 | 233 | fn string_range_full() { |
src/tools/clippy/tests/ui/clear_with_drain.rs-30| ... | ... | @@ -20,11 +20,6 @@ fn vec_range() { |
| 20 | 20 | let mut v = vec![1, 2, 3]; |
| 21 | 21 | v.drain(0..v.len()); |
| 22 | 22 | //~^ clear_with_drain |
| 23 | ||
| 24 | // Do lint | |
| 25 | let mut v = vec![1, 2, 3]; | |
| 26 | v.drain(usize::MIN..v.len()); | |
| 27 | //~^ clear_with_drain | |
| 28 | 23 | } |
| 29 | 24 | |
| 30 | 25 | fn vec_range_from() { |
| ... | ... | @@ -45,11 +40,6 @@ fn vec_range_from() { |
| 45 | 40 | let mut v = vec![1, 2, 3]; |
| 46 | 41 | v.drain(0..); |
| 47 | 42 | //~^ clear_with_drain |
| 48 | ||
| 49 | // Do lint | |
| 50 | let mut v = vec![1, 2, 3]; | |
| 51 | v.drain(usize::MIN..); | |
| 52 | //~^ clear_with_drain | |
| 53 | 43 | } |
| 54 | 44 | |
| 55 | 45 | fn vec_range_full() { |
| ... | ... | @@ -124,11 +114,6 @@ fn vec_deque_range() { |
| 124 | 114 | let mut deque = VecDeque::from([1, 2, 3]); |
| 125 | 115 | deque.drain(0..deque.len()); |
| 126 | 116 | //~^ clear_with_drain |
| 127 | ||
| 128 | // Do lint | |
| 129 | let mut deque = VecDeque::from([1, 2, 3]); | |
| 130 | deque.drain(usize::MIN..deque.len()); | |
| 131 | //~^ clear_with_drain | |
| 132 | 117 | } |
| 133 | 118 | |
| 134 | 119 | fn vec_deque_range_from() { |
| ... | ... | @@ -149,11 +134,6 @@ fn vec_deque_range_from() { |
| 149 | 134 | let mut deque = VecDeque::from([1, 2, 3]); |
| 150 | 135 | deque.drain(0..); |
| 151 | 136 | //~^ clear_with_drain |
| 152 | ||
| 153 | // Do lint | |
| 154 | let mut deque = VecDeque::from([1, 2, 3]); | |
| 155 | deque.drain(usize::MIN..); | |
| 156 | //~^ clear_with_drain | |
| 157 | 137 | } |
| 158 | 138 | |
| 159 | 139 | fn vec_deque_range_full() { |
| ... | ... | @@ -228,11 +208,6 @@ fn string_range() { |
| 228 | 208 | let mut s = String::from("Hello, world!"); |
| 229 | 209 | s.drain(0..s.len()); |
| 230 | 210 | //~^ clear_with_drain |
| 231 | ||
| 232 | // Do lint | |
| 233 | let mut s = String::from("Hello, world!"); | |
| 234 | s.drain(usize::MIN..s.len()); | |
| 235 | //~^ clear_with_drain | |
| 236 | 211 | } |
| 237 | 212 | |
| 238 | 213 | fn string_range_from() { |
| ... | ... | @@ -253,11 +228,6 @@ fn string_range_from() { |
| 253 | 228 | let mut s = String::from("Hello, world!"); |
| 254 | 229 | s.drain(0..); |
| 255 | 230 | //~^ clear_with_drain |
| 256 | ||
| 257 | // Do lint | |
| 258 | let mut s = String::from("Hello, world!"); | |
| 259 | s.drain(usize::MIN..); | |
| 260 | //~^ clear_with_drain | |
| 261 | 231 | } |
| 262 | 232 | |
| 263 | 233 | fn string_range_full() { |
src/tools/clippy/tests/ui/clear_with_drain.stderr+15-51| ... | ... | @@ -8,124 +8,88 @@ LL | v.drain(0..v.len()); |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::clear_with_drain)]` |
| 9 | 9 | |
| 10 | 10 | error: `drain` used to clear a `Vec` |
| 11 | --> tests/ui/clear_with_drain.rs:26:7 | |
| 12 | | | |
| 13 | LL | v.drain(usize::MIN..v.len()); | |
| 14 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` | |
| 15 | ||
| 16 | error: `drain` used to clear a `Vec` | |
| 17 | --> tests/ui/clear_with_drain.rs:46:7 | |
| 11 | --> tests/ui/clear_with_drain.rs:41:7 | |
| 18 | 12 | | |
| 19 | 13 | LL | v.drain(0..); |
| 20 | 14 | | ^^^^^^^^^^ help: try: `clear()` |
| 21 | 15 | |
| 22 | 16 | error: `drain` used to clear a `Vec` |
| 23 | --> tests/ui/clear_with_drain.rs:51:7 | |
| 24 | | | |
| 25 | LL | v.drain(usize::MIN..); | |
| 26 | | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` | |
| 27 | ||
| 28 | error: `drain` used to clear a `Vec` | |
| 29 | --> tests/ui/clear_with_drain.rs:68:7 | |
| 17 | --> tests/ui/clear_with_drain.rs:58:7 | |
| 30 | 18 | | |
| 31 | 19 | LL | v.drain(..); |
| 32 | 20 | | ^^^^^^^^^ help: try: `clear()` |
| 33 | 21 | |
| 34 | 22 | error: `drain` used to clear a `Vec` |
| 35 | --> tests/ui/clear_with_drain.rs:86:7 | |
| 23 | --> tests/ui/clear_with_drain.rs:76:7 | |
| 36 | 24 | | |
| 37 | 25 | LL | v.drain(..v.len()); |
| 38 | 26 | | ^^^^^^^^^^^^^^^^ help: try: `clear()` |
| 39 | 27 | |
| 40 | 28 | error: `drain` used to clear a `VecDeque` |
| 41 | --> tests/ui/clear_with_drain.rs:125:11 | |
| 29 | --> tests/ui/clear_with_drain.rs:115:11 | |
| 42 | 30 | | |
| 43 | 31 | LL | deque.drain(0..deque.len()); |
| 44 | 32 | | ^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` |
| 45 | 33 | |
| 46 | 34 | error: `drain` used to clear a `VecDeque` |
| 47 | --> tests/ui/clear_with_drain.rs:130:11 | |
| 48 | | | |
| 49 | LL | deque.drain(usize::MIN..deque.len()); | |
| 50 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` | |
| 51 | ||
| 52 | error: `drain` used to clear a `VecDeque` | |
| 53 | --> tests/ui/clear_with_drain.rs:150:11 | |
| 35 | --> tests/ui/clear_with_drain.rs:135:11 | |
| 54 | 36 | | |
| 55 | 37 | LL | deque.drain(0..); |
| 56 | 38 | | ^^^^^^^^^^ help: try: `clear()` |
| 57 | 39 | |
| 58 | 40 | error: `drain` used to clear a `VecDeque` |
| 59 | --> tests/ui/clear_with_drain.rs:155:11 | |
| 60 | | | |
| 61 | LL | deque.drain(usize::MIN..); | |
| 62 | | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` | |
| 63 | ||
| 64 | error: `drain` used to clear a `VecDeque` | |
| 65 | --> tests/ui/clear_with_drain.rs:172:11 | |
| 41 | --> tests/ui/clear_with_drain.rs:152:11 | |
| 66 | 42 | | |
| 67 | 43 | LL | deque.drain(..); |
| 68 | 44 | | ^^^^^^^^^ help: try: `clear()` |
| 69 | 45 | |
| 70 | 46 | error: `drain` used to clear a `VecDeque` |
| 71 | --> tests/ui/clear_with_drain.rs:190:11 | |
| 47 | --> tests/ui/clear_with_drain.rs:170:11 | |
| 72 | 48 | | |
| 73 | 49 | LL | deque.drain(..deque.len()); |
| 74 | 50 | | ^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` |
| 75 | 51 | |
| 76 | 52 | error: `drain` used to clear a `String` |
| 77 | --> tests/ui/clear_with_drain.rs:229:7 | |
| 53 | --> tests/ui/clear_with_drain.rs:209:7 | |
| 78 | 54 | | |
| 79 | 55 | LL | s.drain(0..s.len()); |
| 80 | 56 | | ^^^^^^^^^^^^^^^^^ help: try: `clear()` |
| 81 | 57 | |
| 82 | 58 | error: `drain` used to clear a `String` |
| 83 | --> tests/ui/clear_with_drain.rs:234:7 | |
| 84 | | | |
| 85 | LL | s.drain(usize::MIN..s.len()); | |
| 86 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` | |
| 87 | ||
| 88 | error: `drain` used to clear a `String` | |
| 89 | --> tests/ui/clear_with_drain.rs:254:7 | |
| 59 | --> tests/ui/clear_with_drain.rs:229:7 | |
| 90 | 60 | | |
| 91 | 61 | LL | s.drain(0..); |
| 92 | 62 | | ^^^^^^^^^^ help: try: `clear()` |
| 93 | 63 | |
| 94 | 64 | error: `drain` used to clear a `String` |
| 95 | --> tests/ui/clear_with_drain.rs:259:7 | |
| 96 | | | |
| 97 | LL | s.drain(usize::MIN..); | |
| 98 | | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` | |
| 99 | ||
| 100 | error: `drain` used to clear a `String` | |
| 101 | --> tests/ui/clear_with_drain.rs:276:7 | |
| 65 | --> tests/ui/clear_with_drain.rs:246:7 | |
| 102 | 66 | | |
| 103 | 67 | LL | s.drain(..); |
| 104 | 68 | | ^^^^^^^^^ help: try: `clear()` |
| 105 | 69 | |
| 106 | 70 | error: `drain` used to clear a `String` |
| 107 | --> tests/ui/clear_with_drain.rs:294:7 | |
| 71 | --> tests/ui/clear_with_drain.rs:264:7 | |
| 108 | 72 | | |
| 109 | 73 | LL | s.drain(..s.len()); |
| 110 | 74 | | ^^^^^^^^^^^^^^^^ help: try: `clear()` |
| 111 | 75 | |
| 112 | 76 | error: `drain` used to clear a `HashSet` |
| 113 | --> tests/ui/clear_with_drain.rs:333:9 | |
| 77 | --> tests/ui/clear_with_drain.rs:303:9 | |
| 114 | 78 | | |
| 115 | 79 | LL | set.drain(); |
| 116 | 80 | | ^^^^^^^ help: try: `clear()` |
| 117 | 81 | |
| 118 | 82 | error: `drain` used to clear a `HashMap` |
| 119 | --> tests/ui/clear_with_drain.rs:353:9 | |
| 83 | --> tests/ui/clear_with_drain.rs:323:9 | |
| 120 | 84 | | |
| 121 | 85 | LL | map.drain(); |
| 122 | 86 | | ^^^^^^^ help: try: `clear()` |
| 123 | 87 | |
| 124 | 88 | error: `drain` used to clear a `BinaryHeap` |
| 125 | --> tests/ui/clear_with_drain.rs:373:10 | |
| 89 | --> tests/ui/clear_with_drain.rs:343:10 | |
| 126 | 90 | | |
| 127 | 91 | LL | heap.drain(); |
| 128 | 92 | | ^^^^^^^ help: try: `clear()` |
| 129 | 93 | |
| 130 | error: aborting due to 21 previous errors | |
| 94 | error: aborting due to 15 previous errors | |
| 131 | 95 |
src/tools/clippy/tests/ui/crashes/ice-16950.rs created+27| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | //@check-pass | |
| 2 | #![feature(trivial_bounds)] | |
| 3 | ||
| 4 | struct Helper<T>(T); | |
| 5 | ||
| 6 | trait Unsized<T: ?Sized> { | |
| 7 | const SIZE: usize = usize::MAX; | |
| 8 | } | |
| 9 | ||
| 10 | impl<T: ?Sized> Unsized<T> for T {} | |
| 11 | ||
| 12 | impl<T> Helper<T> { | |
| 13 | const SIZE: usize = size_of::<T>(); | |
| 14 | } | |
| 15 | ||
| 16 | struct TrickClippy(str); | |
| 17 | ||
| 18 | impl TrickClippy { | |
| 19 | fn trick_clippy() -> bool | |
| 20 | where | |
| 21 | Self: Sized, | |
| 22 | { | |
| 23 | Helper::<Self>::SIZE == str::SIZE | |
| 24 | } | |
| 25 | } | |
| 26 | ||
| 27 | fn main() {} |
src/tools/clippy/tests/ui/drain_collect.stderr+20-20| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | error: you seem to be trying to move all elements into a new `BinaryHeap` | |
| 1 | error: draining all elements of a collection into a new collection of the same type | |
| 2 | 2 | --> tests/ui/drain_collect.rs:6:5 |
| 3 | 3 | | |
| 4 | 4 | LL | b.drain().collect() |
| 5 | | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 5 | | ^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 6 | 6 | | |
| 7 | 7 | note: the lint level is defined here |
| 8 | 8 | --> tests/ui/drain_collect.rs:1:9 |
| ... | ... | @@ -10,59 +10,59 @@ note: the lint level is defined here |
| 10 | 10 | LL | #![deny(clippy::drain_collect)] |
| 11 | 11 | | ^^^^^^^^^^^^^^^^^^^^^ |
| 12 | 12 | |
| 13 | error: you seem to be trying to move all elements into a new `HashMap` | |
| 13 | error: draining all elements of a collection into a new collection of the same type | |
| 14 | 14 | --> tests/ui/drain_collect.rs:15:5 |
| 15 | 15 | | |
| 16 | 16 | LL | b.drain().collect() |
| 17 | | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 17 | | ^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 18 | 18 | |
| 19 | error: you seem to be trying to move all elements into a new `HashSet` | |
| 19 | error: draining all elements of a collection into a new collection of the same type | |
| 20 | 20 | --> tests/ui/drain_collect.rs:24:5 |
| 21 | 21 | | |
| 22 | 22 | LL | b.drain().collect() |
| 23 | | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 23 | | ^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 24 | 24 | |
| 25 | error: you seem to be trying to move all elements into a new `Vec` | |
| 25 | error: draining all elements of a collection into a new collection of the same type | |
| 26 | 26 | --> tests/ui/drain_collect.rs:33:5 |
| 27 | 27 | | |
| 28 | 28 | LL | b.drain(..).collect() |
| 29 | | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 29 | | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 30 | 30 | |
| 31 | error: you seem to be trying to move all elements into a new `Vec` | |
| 31 | error: draining all elements of a collection into a new collection of the same type | |
| 32 | 32 | --> tests/ui/drain_collect.rs:42:5 |
| 33 | 33 | | |
| 34 | 34 | LL | b.drain(..).collect() |
| 35 | | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 35 | | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 36 | 36 | |
| 37 | error: you seem to be trying to move all elements into a new `Vec` | |
| 37 | error: draining all elements of a collection into a new collection of the same type | |
| 38 | 38 | --> tests/ui/drain_collect.rs:47:5 |
| 39 | 39 | | |
| 40 | 40 | LL | b.drain(0..).collect() |
| 41 | | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 41 | | ^^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 42 | 42 | |
| 43 | error: you seem to be trying to move all elements into a new `Vec` | |
| 43 | error: draining all elements of a collection into a new collection of the same type | |
| 44 | 44 | --> tests/ui/drain_collect.rs:52:5 |
| 45 | 45 | | |
| 46 | 46 | LL | b.drain(..b.len()).collect() |
| 47 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 47 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 48 | 48 | |
| 49 | error: you seem to be trying to move all elements into a new `Vec` | |
| 49 | error: draining all elements of a collection into a new collection of the same type | |
| 50 | 50 | --> tests/ui/drain_collect.rs:57:5 |
| 51 | 51 | | |
| 52 | 52 | LL | b.drain(0..b.len()).collect() |
| 53 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 53 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 54 | 54 | |
| 55 | error: you seem to be trying to move all elements into a new `Vec` | |
| 55 | error: draining all elements of a collection into a new collection of the same type | |
| 56 | 56 | --> tests/ui/drain_collect.rs:63:5 |
| 57 | 57 | | |
| 58 | 58 | LL | b.drain(..).collect() |
| 59 | | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` | |
| 59 | | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(&mut b)` | |
| 60 | 60 | |
| 61 | error: you seem to be trying to move all elements into a new `String` | |
| 61 | error: draining all elements of a collection into a new collection of the same type | |
| 62 | 62 | --> tests/ui/drain_collect.rs:72:5 |
| 63 | 63 | | |
| 64 | 64 | LL | b.drain(..).collect() |
| 65 | | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` | |
| 65 | | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `std::mem::take(b)` | |
| 66 | 66 | |
| 67 | 67 | error: aborting due to 10 previous errors |
| 68 | 68 |
src/tools/clippy/tests/ui/drain_collect_nostd.stderr+2-2| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | error: you seem to be trying to move all elements into a new `Vec` | |
| 1 | error: draining all elements of a collection into a new collection of the same type | |
| 2 | 2 | --> tests/ui/drain_collect_nostd.rs:7:5 |
| 3 | 3 | | |
| 4 | 4 | LL | v.drain(..).collect() |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `core::mem::take(v)` | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^ help: use `mem::take` to avoid creating a new allocation: `core::mem::take(v)` | |
| 6 | 6 | | |
| 7 | 7 | = note: `-D clippy::drain-collect` implied by `-D warnings` |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::drain_collect)]` |
src/tools/clippy/tests/ui/extra_unused_lifetimes.rs+14| ... | ... | @@ -211,4 +211,18 @@ mod proc_macro_generated { |
| 211 | 211 | } |
| 212 | 212 | } |
| 213 | 213 | |
| 214 | mod issue17255 { | |
| 215 | ||
| 216 | trait AnotherSimpleTrait<'a> {} | |
| 217 | ||
| 218 | macro_rules! mac { | |
| 219 | ($lt:lifetime, $t:ident, $tr:path) => { | |
| 220 | impl<$t: for<'lt> $tr> AnotherSimpleTrait<'_> for $t {} | |
| 221 | }; | |
| 222 | } | |
| 223 | ||
| 224 | // Do not lint code expanded from macros | |
| 225 | mac!('a, T, super::SimplerTrait); | |
| 226 | } | |
| 227 | ||
| 214 | 228 | fn main() {} |
src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.rs+15| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | //@no-rustfix | |
| 2 | ||
| 1 | 3 | #![warn(clippy::extra_unused_type_parameters)] |
| 2 | 4 | |
| 3 | 5 | fn unused_where_clause<T, U>(x: U) |
| ... | ... | @@ -24,4 +26,17 @@ where |
| 24 | 26 | unimplemented!(); |
| 25 | 27 | } |
| 26 | 28 | |
| 29 | // The fix just removes the type parameter from the definition of `unused_ty`, but it doesn't adjust | |
| 30 | // its callsites, leading to compilation errors. | |
| 31 | mod issue15884 { | |
| 32 | fn unused_ty<T>(x: u8) { | |
| 33 | //~^ extra_unused_type_parameters | |
| 34 | unimplemented!() | |
| 35 | } | |
| 36 | ||
| 37 | fn main() { | |
| 38 | unused_ty::<String>(0); | |
| 39 | } | |
| 40 | } | |
| 41 | ||
| 27 | 42 | fn main() {} |
src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.stderr+16-4| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: type parameter `T` goes unused in function definition |
| 2 | --> tests/ui/extra_unused_type_parameters_unfixable.rs:3:24 | |
| 2 | --> tests/ui/extra_unused_type_parameters_unfixable.rs:5:24 | |
| 3 | 3 | | |
| 4 | 4 | LL | fn unused_where_clause<T, U>(x: U) |
| 5 | 5 | | ^ |
| ... | ... | @@ -9,7 +9,7 @@ LL | fn unused_where_clause<T, U>(x: U) |
| 9 | 9 | = help: to override `-D warnings` add `#[allow(clippy::extra_unused_type_parameters)]` |
| 10 | 10 | |
| 11 | 11 | error: type parameters go unused in function definition: T, V |
| 12 | --> tests/ui/extra_unused_type_parameters_unfixable.rs:11:30 | |
| 12 | --> tests/ui/extra_unused_type_parameters_unfixable.rs:13:30 | |
| 13 | 13 | | |
| 14 | 14 | LL | fn unused_multi_where_clause<T, U, V: Default>(x: U) |
| 15 | 15 | | ^ ^^^^^^^^^^ |
| ... | ... | @@ -17,12 +17,24 @@ LL | fn unused_multi_where_clause<T, U, V: Default>(x: U) |
| 17 | 17 | = help: consider removing the parameters |
| 18 | 18 | |
| 19 | 19 | error: type parameters go unused in function definition: T, U, V |
| 20 | --> tests/ui/extra_unused_type_parameters_unfixable.rs:19:28 | |
| 20 | --> tests/ui/extra_unused_type_parameters_unfixable.rs:21:28 | |
| 21 | 21 | | |
| 22 | 22 | LL | fn unused_all_where_clause<T, U: Default, V: Default>() |
| 23 | 23 | | ^ ^^^^^^^^^^ ^^^^^^^^^^ |
| 24 | 24 | | |
| 25 | 25 | = help: consider removing the parameters |
| 26 | 26 | |
| 27 | error: aborting due to 3 previous errors | |
| 27 | error: type parameter `T` goes unused in function definition | |
| 28 | --> tests/ui/extra_unused_type_parameters_unfixable.rs:32:17 | |
| 29 | | | |
| 30 | LL | fn unused_ty<T>(x: u8) { | |
| 31 | | ^^^ | |
| 32 | | | |
| 33 | help: consider removing the parameter | |
| 34 | | | |
| 35 | LL - fn unused_ty<T>(x: u8) { | |
| 36 | LL + fn unused_ty(x: u8) { | |
| 37 | | | |
| 38 | ||
| 39 | error: aborting due to 4 previous errors | |
| 28 | 40 |
src/tools/clippy/tests/ui/filter_next.fixed created+63| ... | ... | @@ -0,0 +1,63 @@ |
| 1 | //@aux-build:option_helpers.rs | |
| 2 | #![warn(clippy::filter_next)] | |
| 3 | #![expect(clippy::disallowed_names)] | |
| 4 | #![allow(clippy::useless_vec)] | |
| 5 | ||
| 6 | extern crate option_helpers; | |
| 7 | ||
| 8 | use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives}; | |
| 9 | ||
| 10 | fn main() {} | |
| 11 | ||
| 12 | fn filter_next() { | |
| 13 | let v = [3, 2, 1, 0, -1, -2, -3]; | |
| 14 | ||
| 15 | // Single-line case. | |
| 16 | let _ = v.iter().find(|&x| *x < 0); | |
| 17 | //~^ filter_next | |
| 18 | ||
| 19 | let _ = v.iter().rfind(|&x| *x < 0); | |
| 20 | //~^ filter_next | |
| 21 | ||
| 22 | // Multi-line case. | |
| 23 | #[rustfmt::skip] | |
| 24 | let _ = v.iter().find(|&x| { | |
| 25 | //~^ filter_next | |
| 26 | *x < 0 | |
| 27 | }); | |
| 28 | ||
| 29 | #[rustfmt::skip] | |
| 30 | let _ = v.iter().rfind(|&x| { | |
| 31 | //~^ filter_next | |
| 32 | *x < 0 | |
| 33 | }); | |
| 34 | ||
| 35 | // Check that we don't lint if the caller is not an `Iterator`. | |
| 36 | let foo = IteratorFalsePositives { foo: 0 }; | |
| 37 | let _ = foo.filter().next(); | |
| 38 | ||
| 39 | let foo = IteratorMethodFalsePositives {}; | |
| 40 | let _ = foo.filter(42).next(); | |
| 41 | } | |
| 42 | ||
| 43 | fn filter_next_back() { | |
| 44 | let v = [3, 2, 1, 0, -1, -2, -3]; | |
| 45 | ||
| 46 | // Check that we don't lint if the caller is not an `Iterator`. | |
| 47 | let foo = IteratorFalsePositives { foo: 0 }; | |
| 48 | let _ = foo.filter().next_back(); | |
| 49 | ||
| 50 | let foo = IteratorMethodFalsePositives {}; | |
| 51 | let _ = foo.filter(42).next_back(); | |
| 52 | } | |
| 53 | ||
| 54 | #[clippy::msrv = "1.27"] | |
| 55 | fn msrv_1_27() { | |
| 56 | let _ = vec![1].into_iter().rfind(|&x| x < 0); | |
| 57 | //~^ filter_next | |
| 58 | } | |
| 59 | ||
| 60 | #[clippy::msrv = "1.26"] | |
| 61 | fn msrv_1_26() { | |
| 62 | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 63 | } |
src/tools/clippy/tests/ui/filter_next.rs created+65| ... | ... | @@ -0,0 +1,65 @@ |
| 1 | //@aux-build:option_helpers.rs | |
| 2 | #![warn(clippy::filter_next)] | |
| 3 | #![expect(clippy::disallowed_names)] | |
| 4 | #![allow(clippy::useless_vec)] | |
| 5 | ||
| 6 | extern crate option_helpers; | |
| 7 | ||
| 8 | use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives}; | |
| 9 | ||
| 10 | fn main() {} | |
| 11 | ||
| 12 | fn filter_next() { | |
| 13 | let v = [3, 2, 1, 0, -1, -2, -3]; | |
| 14 | ||
| 15 | // Single-line case. | |
| 16 | let _ = v.iter().filter(|&x| *x < 0).next(); | |
| 17 | //~^ filter_next | |
| 18 | ||
| 19 | let _ = v.iter().filter(|&x| *x < 0).next_back(); | |
| 20 | //~^ filter_next | |
| 21 | ||
| 22 | // Multi-line case. | |
| 23 | #[rustfmt::skip] | |
| 24 | let _ = v.iter().filter(|&x| { | |
| 25 | //~^ filter_next | |
| 26 | *x < 0 | |
| 27 | } | |
| 28 | ).next(); | |
| 29 | ||
| 30 | #[rustfmt::skip] | |
| 31 | let _ = v.iter().filter(|&x| { | |
| 32 | //~^ filter_next | |
| 33 | *x < 0 | |
| 34 | } | |
| 35 | ).next_back(); | |
| 36 | ||
| 37 | // Check that we don't lint if the caller is not an `Iterator`. | |
| 38 | let foo = IteratorFalsePositives { foo: 0 }; | |
| 39 | let _ = foo.filter().next(); | |
| 40 | ||
| 41 | let foo = IteratorMethodFalsePositives {}; | |
| 42 | let _ = foo.filter(42).next(); | |
| 43 | } | |
| 44 | ||
| 45 | fn filter_next_back() { | |
| 46 | let v = [3, 2, 1, 0, -1, -2, -3]; | |
| 47 | ||
| 48 | // Check that we don't lint if the caller is not an `Iterator`. | |
| 49 | let foo = IteratorFalsePositives { foo: 0 }; | |
| 50 | let _ = foo.filter().next_back(); | |
| 51 | ||
| 52 | let foo = IteratorMethodFalsePositives {}; | |
| 53 | let _ = foo.filter(42).next_back(); | |
| 54 | } | |
| 55 | ||
| 56 | #[clippy::msrv = "1.27"] | |
| 57 | fn msrv_1_27() { | |
| 58 | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 59 | //~^ filter_next | |
| 60 | } | |
| 61 | ||
| 62 | #[clippy::msrv = "1.26"] | |
| 63 | fn msrv_1_26() { | |
| 64 | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 65 | } |
src/tools/clippy/tests/ui/filter_next.stderr created+78| ... | ... | @@ -0,0 +1,78 @@ |
| 1 | error: called `filter(..).next()` on an `Iterator` | |
| 2 | --> tests/ui/filter_next.rs:16:13 | |
| 3 | | | |
| 4 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: `-D clippy::filter-next` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` | |
| 9 | help: use `.find(..)` instead | |
| 10 | | | |
| 11 | LL - let _ = v.iter().filter(|&x| *x < 0).next(); | |
| 12 | LL + let _ = v.iter().find(|&x| *x < 0); | |
| 13 | | | |
| 14 | ||
| 15 | error: called `filter(..).next_back()` on an `DoubleEndedIterator` | |
| 16 | --> tests/ui/filter_next.rs:19:13 | |
| 17 | | | |
| 18 | LL | let _ = v.iter().filter(|&x| *x < 0).next_back(); | |
| 19 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 20 | | | |
| 21 | help: use `.rfind(..)` instead | |
| 22 | | | |
| 23 | LL - let _ = v.iter().filter(|&x| *x < 0).next_back(); | |
| 24 | LL + let _ = v.iter().rfind(|&x| *x < 0); | |
| 25 | | | |
| 26 | ||
| 27 | error: called `filter(..).next()` on an `Iterator` | |
| 28 | --> tests/ui/filter_next.rs:24:13 | |
| 29 | | | |
| 30 | LL | let _ = v.iter().filter(|&x| { | |
| 31 | | _____________^ | |
| 32 | LL | | | |
| 33 | LL | | *x < 0 | |
| 34 | LL | | } | |
| 35 | LL | | ).next(); | |
| 36 | | |___________________________^ | |
| 37 | | | |
| 38 | help: use `.find(..)` instead | |
| 39 | | | |
| 40 | LL ~ let _ = v.iter().find(|&x| { | |
| 41 | LL + | |
| 42 | LL + *x < 0 | |
| 43 | LL ~ }); | |
| 44 | | | |
| 45 | ||
| 46 | error: called `filter(..).next_back()` on an `DoubleEndedIterator` | |
| 47 | --> tests/ui/filter_next.rs:31:13 | |
| 48 | | | |
| 49 | LL | let _ = v.iter().filter(|&x| { | |
| 50 | | _____________^ | |
| 51 | LL | | | |
| 52 | LL | | *x < 0 | |
| 53 | LL | | } | |
| 54 | LL | | ).next_back(); | |
| 55 | | |________________________________^ | |
| 56 | | | |
| 57 | help: use `.rfind(..)` instead | |
| 58 | | | |
| 59 | LL ~ let _ = v.iter().rfind(|&x| { | |
| 60 | LL + | |
| 61 | LL + *x < 0 | |
| 62 | LL ~ }); | |
| 63 | | | |
| 64 | ||
| 65 | error: called `filter(..).next_back()` on an `DoubleEndedIterator` | |
| 66 | --> tests/ui/filter_next.rs:58:13 | |
| 67 | | | |
| 68 | LL | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 69 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 70 | | | |
| 71 | help: use `.rfind(..)` instead | |
| 72 | | | |
| 73 | LL - let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 74 | LL + let _ = vec![1].into_iter().rfind(|&x| x < 0); | |
| 75 | | | |
| 76 | ||
| 77 | error: aborting due to 5 previous errors | |
| 78 |
src/tools/clippy/tests/ui/filter_next_unfixable.rs created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | //@no-rustfix | |
| 2 | #![warn(clippy::filter_next)] | |
| 3 | ||
| 4 | fn main() {} | |
| 5 | ||
| 6 | // The fixed version doesn't compile, as `iter` isn't `mut`. | |
| 7 | // We do emit a note suggesting adding it, but not an autofix | |
| 8 | pub fn issue10029() { | |
| 9 | { | |
| 10 | let iter = (0..10); | |
| 11 | let _ = iter.filter(|_| true).next(); | |
| 12 | //~^ filter_next | |
| 13 | } | |
| 14 | { | |
| 15 | let iter = (0..10); | |
| 16 | let _ = iter.filter(|_| true).next_back(); | |
| 17 | //~^ filter_next | |
| 18 | } | |
| 19 | } |
src/tools/clippy/tests/ui/filter_next_unfixable.stderr created+38| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | error: called `filter(..).next()` on an `Iterator` | |
| 2 | --> tests/ui/filter_next_unfixable.rs:11:17 | |
| 3 | | | |
| 4 | LL | let _ = iter.filter(|_| true).next(); | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | help: you will also need to make `iter` mutable, because `find` takes `&mut self` | |
| 8 | --> tests/ui/filter_next_unfixable.rs:10:13 | |
| 9 | | | |
| 10 | LL | let iter = (0..10); | |
| 11 | | ^^^^ | |
| 12 | = note: `-D clippy::filter-next` implied by `-D warnings` | |
| 13 | = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` | |
| 14 | help: use `.find(..)` instead | |
| 15 | | | |
| 16 | LL - let _ = iter.filter(|_| true).next(); | |
| 17 | LL + let _ = iter.find(|_| true); | |
| 18 | | | |
| 19 | ||
| 20 | error: called `filter(..).next_back()` on an `DoubleEndedIterator` | |
| 21 | --> tests/ui/filter_next_unfixable.rs:16:17 | |
| 22 | | | |
| 23 | LL | let _ = iter.filter(|_| true).next_back(); | |
| 24 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 25 | | | |
| 26 | help: you will also need to make `iter` mutable, because `rfind` takes `&mut self` | |
| 27 | --> tests/ui/filter_next_unfixable.rs:15:13 | |
| 28 | | | |
| 29 | LL | let iter = (0..10); | |
| 30 | | ^^^^ | |
| 31 | help: use `.rfind(..)` instead | |
| 32 | | | |
| 33 | LL - let _ = iter.filter(|_| true).next_back(); | |
| 34 | LL + let _ = iter.rfind(|_| true); | |
| 35 | | | |
| 36 | ||
| 37 | error: aborting due to 2 previous errors | |
| 38 |
src/tools/clippy/tests/ui/floating_point_mul_add.stderr+21-20| ... | ... | @@ -1,121 +1,122 @@ |
| 1 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 1 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 2 | 2 | --> tests/ui/floating_point_mul_add.rs:19:13 |
| 3 | 3 | | |
| 4 | 4 | LL | let _ = a * b + c; |
| 5 | 5 | | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` |
| 6 | 6 | | |
| 7 | = note: the performance gain from `mul_add` may vary depending on the target architecture | |
| 7 | 8 | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` |
| 8 | 9 | = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` |
| 9 | 10 | |
| 10 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 11 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 11 | 12 | --> tests/ui/floating_point_mul_add.rs:21:13 |
| 12 | 13 | | |
| 13 | 14 | LL | let _ = a * b - c; |
| 14 | 15 | | ^^^^^^^^^ help: consider using: `a.mul_add(b, -c)` |
| 15 | 16 | |
| 16 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 17 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 17 | 18 | --> tests/ui/floating_point_mul_add.rs:23:13 |
| 18 | 19 | | |
| 19 | 20 | LL | let _ = c + a * b; |
| 20 | 21 | | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` |
| 21 | 22 | |
| 22 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 23 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 23 | 24 | --> tests/ui/floating_point_mul_add.rs:25:13 |
| 24 | 25 | | |
| 25 | 26 | LL | let _ = c - a * b; |
| 26 | 27 | | ^^^^^^^^^ help: consider using: `a.mul_add(-b, c)` |
| 27 | 28 | |
| 28 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 29 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 29 | 30 | --> tests/ui/floating_point_mul_add.rs:27:13 |
| 30 | 31 | | |
| 31 | 32 | LL | let _ = a + 2.0 * 4.0; |
| 32 | 33 | | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` |
| 33 | 34 | |
| 34 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 35 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 35 | 36 | --> tests/ui/floating_point_mul_add.rs:29:13 |
| 36 | 37 | | |
| 37 | 38 | LL | let _ = a + 2. * 4.; |
| 38 | 39 | | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` |
| 39 | 40 | |
| 40 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 41 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 41 | 42 | --> tests/ui/floating_point_mul_add.rs:32:13 |
| 42 | 43 | | |
| 43 | 44 | LL | let _ = (a * b) + c; |
| 44 | 45 | | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` |
| 45 | 46 | |
| 46 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 47 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 47 | 48 | --> tests/ui/floating_point_mul_add.rs:34:13 |
| 48 | 49 | | |
| 49 | 50 | LL | let _ = c + (a * b); |
| 50 | 51 | | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` |
| 51 | 52 | |
| 52 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 53 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 53 | 54 | --> tests/ui/floating_point_mul_add.rs:36:13 |
| 54 | 55 | | |
| 55 | 56 | LL | let _ = a * b * c + d; |
| 56 | 57 | | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` |
| 57 | 58 | |
| 58 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 59 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 59 | 60 | --> tests/ui/floating_point_mul_add.rs:39:13 |
| 60 | 61 | | |
| 61 | 62 | LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; |
| 62 | 63 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` |
| 63 | 64 | |
| 64 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 65 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 65 | 66 | --> tests/ui/floating_point_mul_add.rs:41:13 |
| 66 | 67 | | |
| 67 | 68 | LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; |
| 68 | 69 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` |
| 69 | 70 | |
| 70 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 71 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 71 | 72 | --> tests/ui/floating_point_mul_add.rs:44:13 |
| 72 | 73 | | |
| 73 | 74 | LL | let _ = (a * a + b).sqrt(); |
| 74 | 75 | | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` |
| 75 | 76 | |
| 76 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 77 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 77 | 78 | --> tests/ui/floating_point_mul_add.rs:48:13 |
| 78 | 79 | | |
| 79 | 80 | LL | let _ = a - (b * u as f64); |
| 80 | 81 | | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)` |
| 81 | 82 | |
| 82 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 83 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 83 | 84 | --> tests/ui/floating_point_mul_add.rs:102:13 |
| 84 | 85 | | |
| 85 | 86 | LL | let _ = 0.5 + 2.0 * x; |
| 86 | 87 | | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(x, 0.5)` |
| 87 | 88 | |
| 88 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 89 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 89 | 90 | --> tests/ui/floating_point_mul_add.rs:104:13 |
| 90 | 91 | | |
| 91 | 92 | LL | let _ = 2.0 * x + 0.5; |
| 92 | 93 | | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(x, 0.5)` |
| 93 | 94 | |
| 94 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 95 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 95 | 96 | --> tests/ui/floating_point_mul_add.rs:107:13 |
| 96 | 97 | | |
| 97 | 98 | LL | let _ = x + 2.0 * 4.0; |
| 98 | 99 | | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, x)` |
| 99 | 100 | |
| 100 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 101 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 101 | 102 | --> tests/ui/floating_point_mul_add.rs:111:13 |
| 102 | 103 | | |
| 103 | 104 | LL | let _ = y * 2.0 + 0.5; |
| 104 | 105 | | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(2.0, 0.5)` |
| 105 | 106 | |
| 106 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 107 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 107 | 108 | --> tests/ui/floating_point_mul_add.rs:113:13 |
| 108 | 109 | | |
| 109 | 110 | LL | let _ = 1.0 * 2.0 + 0.5; |
| 110 | 111 | | ^^^^^^^^^^^^^^^ help: consider using: `1.0f64.mul_add(2.0, 0.5)` |
| 111 | 112 | |
| 112 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 113 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 113 | 114 | --> tests/ui/floating_point_mul_add.rs:122:5 |
| 114 | 115 | | |
| 115 | 116 | LL | a += b * c; |
| 116 | 117 | | ^^^^^^^^^^ help: consider using: `a = b.mul_add(c, a)` |
| 117 | 118 | |
| 118 | error: multiply and add expressions can be calculated more efficiently and accurately | |
| 119 | error: multiply and add expressions may be calculated more efficiently and accurately | |
| 119 | 120 | --> tests/ui/floating_point_mul_add.rs:125:5 |
| 120 | 121 | | |
| 121 | 122 | LL | a -= b * c; |
src/tools/clippy/tests/ui/let_underscore_future.rs+8| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | use std::future::Future; |
| 2 | use std::pin::Pin; | |
| 2 | 3 | |
| 3 | 4 | async fn some_async_fn() {} |
| 4 | 5 | |
| ... | ... | @@ -10,6 +11,10 @@ fn custom() -> impl Future<Output = ()> { |
| 10 | 11 | |
| 11 | 12 | fn do_something_to_future(future: &mut impl Future<Output = ()>) {} |
| 12 | 13 | |
| 14 | fn boxed() -> Pin<Box<dyn Future<Output = ()>>> { | |
| 15 | Box::pin(async {}) | |
| 16 | } | |
| 17 | ||
| 13 | 18 | fn main() { |
| 14 | 19 | let _ = some_async_fn(); |
| 15 | 20 | //~^ let_underscore_future |
| ... | ... | @@ -21,4 +26,7 @@ fn main() { |
| 21 | 26 | do_something_to_future(&mut future); |
| 22 | 27 | let _ = future; |
| 23 | 28 | //~^ let_underscore_future |
| 29 | ||
| 30 | // Typed bindings are an intentional discard, see also `let_underscore_untyped`. | |
| 31 | let _: Pin<Box<dyn Future<Output = ()>>> = boxed(); | |
| 24 | 32 | } |
src/tools/clippy/tests/ui/let_underscore_future.stderr+3-3| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: non-binding `let` on a future |
| 2 | --> tests/ui/let_underscore_future.rs:14:5 | |
| 2 | --> tests/ui/let_underscore_future.rs:19:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | let _ = some_async_fn(); |
| 5 | 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -9,7 +9,7 @@ LL | let _ = some_async_fn(); |
| 9 | 9 | = help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]` |
| 10 | 10 | |
| 11 | 11 | error: non-binding `let` on a future |
| 12 | --> tests/ui/let_underscore_future.rs:17:5 | |
| 12 | --> tests/ui/let_underscore_future.rs:22:5 | |
| 13 | 13 | | |
| 14 | 14 | LL | let _ = custom(); |
| 15 | 15 | | ^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -17,7 +17,7 @@ LL | let _ = custom(); |
| 17 | 17 | = help: consider awaiting the future or dropping explicitly with `std::mem::drop` |
| 18 | 18 | |
| 19 | 19 | error: non-binding `let` on a future |
| 20 | --> tests/ui/let_underscore_future.rs:22:5 | |
| 20 | --> tests/ui/let_underscore_future.rs:27:5 | |
| 21 | 21 | | |
| 22 | 22 | LL | let _ = future; |
| 23 | 23 | | ^^^^^^^^^^^^^^^ |
src/tools/clippy/tests/ui/manual_abs_diff.fixed+1| ... | ... | @@ -51,6 +51,7 @@ fn main() { |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | 53 | // FIXME: bunch of patterns that should be linted |
| 54 | #[expect(clippy::needless_late_init)] | |
| 54 | 55 | fn fixme() { |
| 55 | 56 | let a: usize = 5; |
| 56 | 57 | let b: usize = 3; |
src/tools/clippy/tests/ui/manual_abs_diff.rs+1| ... | ... | @@ -61,6 +61,7 @@ fn main() { |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | 63 | // FIXME: bunch of patterns that should be linted |
| 64 | #[expect(clippy::needless_late_init)] | |
| 64 | 65 | fn fixme() { |
| 65 | 66 | let a: usize = 5; |
| 66 | 67 | let b: usize = 3; |
src/tools/clippy/tests/ui/manual_abs_diff.stderr+1-1| ... | ... | @@ -80,7 +80,7 @@ LL | let _ = if a > b { (a - b) as u32 } else { (b - a) as u32 }; |
| 80 | 80 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)` |
| 81 | 81 | |
| 82 | 82 | error: manual absolute difference pattern without using `abs_diff` |
| 83 | --> tests/ui/manual_abs_diff.rs:119:5 | |
| 83 | --> tests/ui/manual_abs_diff.rs:120:5 | |
| 84 | 84 | | |
| 85 | 85 | LL | / if a < b { |
| 86 | 86 | LL | | |
src/tools/clippy/tests/ui/manual_option_zip.fixed+23-5| ... | ... | @@ -21,11 +21,6 @@ fn should_lint() { |
| 21 | 21 | let _ = None::<i32>.zip(b); |
| 22 | 22 | //~^ manual_option_zip |
| 23 | 23 | |
| 24 | // with function call as map receiver | |
| 25 | let a: Option<i32> = Some(1); | |
| 26 | let _ = a.zip(get_option()); | |
| 27 | //~^ manual_option_zip | |
| 28 | ||
| 29 | 24 | // tuple order reversed: (inner, outer) instead of (outer, inner) |
| 30 | 25 | let a: Option<i32> = Some(1); |
| 31 | 26 | let b: Option<i32> = Some(2); |
| ... | ... | @@ -123,3 +118,26 @@ fn issue16968() { |
| 123 | 118 | let opts = [1, 2]; |
| 124 | 119 | let _ = a.and_then(|a| opts.into_iter().find(|b| *b == a).map(|b| (a, b))); |
| 125 | 120 | } |
| 121 | ||
| 122 | fn issue17253() { | |
| 123 | // don't trigger the lint if map receiver is a lazy evaluated expression | |
| 124 | // because `a.zip(b_func())` requires eager evaluation of the argument, | |
| 125 | // preventing the otherwise conditional execution of `b_func()` | |
| 126 | ||
| 127 | use std::hint::black_box; | |
| 128 | let a: Option<i32> = Some(1); | |
| 129 | ||
| 130 | // conditional function call | |
| 131 | let _ = a.and_then(|a| black_box(get_option()).map(|b| (a, b))); | |
| 132 | ||
| 133 | let mut b = 2; | |
| 134 | ||
| 135 | // conditional side effects | |
| 136 | let _ = a.and_then(|a| { | |
| 137 | { | |
| 138 | b /= 2; | |
| 139 | Some(b) | |
| 140 | } | |
| 141 | .map(|b| (a, b)) | |
| 142 | }); | |
| 143 | } |
src/tools/clippy/tests/ui/manual_option_zip.rs+23-5| ... | ... | @@ -21,11 +21,6 @@ fn should_lint() { |
| 21 | 21 | let _ = None::<i32>.and_then(|a| b.map(|b| (a, b))); |
| 22 | 22 | //~^ manual_option_zip |
| 23 | 23 | |
| 24 | // with function call as map receiver | |
| 25 | let a: Option<i32> = Some(1); | |
| 26 | let _ = a.and_then(|a| get_option().map(|b| (a, b))); | |
| 27 | //~^ manual_option_zip | |
| 28 | ||
| 29 | 24 | // tuple order reversed: (inner, outer) instead of (outer, inner) |
| 30 | 25 | let a: Option<i32> = Some(1); |
| 31 | 26 | let b: Option<i32> = Some(2); |
| ... | ... | @@ -123,3 +118,26 @@ fn issue16968() { |
| 123 | 118 | let opts = [1, 2]; |
| 124 | 119 | let _ = a.and_then(|a| opts.into_iter().find(|b| *b == a).map(|b| (a, b))); |
| 125 | 120 | } |
| 121 | ||
| 122 | fn issue17253() { | |
| 123 | // don't trigger the lint if map receiver is a lazy evaluated expression | |
| 124 | // because `a.zip(b_func())` requires eager evaluation of the argument, | |
| 125 | // preventing the otherwise conditional execution of `b_func()` | |
| 126 | ||
| 127 | use std::hint::black_box; | |
| 128 | let a: Option<i32> = Some(1); | |
| 129 | ||
| 130 | // conditional function call | |
| 131 | let _ = a.and_then(|a| black_box(get_option()).map(|b| (a, b))); | |
| 132 | ||
| 133 | let mut b = 2; | |
| 134 | ||
| 135 | // conditional side effects | |
| 136 | let _ = a.and_then(|a| { | |
| 137 | { | |
| 138 | b /= 2; | |
| 139 | Some(b) | |
| 140 | } | |
| 141 | .map(|b| (a, b)) | |
| 142 | }); | |
| 143 | } |
src/tools/clippy/tests/ui/manual_option_zip.stderr+5-11| ... | ... | @@ -20,34 +20,28 @@ LL | let _ = None::<i32>.and_then(|a| b.map(|b| (a, b))); |
| 20 | 20 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `None::<i32>.zip(b)` |
| 21 | 21 | |
| 22 | 22 | error: manual implementation of `Option::zip` |
| 23 | --> tests/ui/manual_option_zip.rs:26:13 | |
| 24 | | | |
| 25 | LL | let _ = a.and_then(|a| get_option().map(|b| (a, b))); | |
| 26 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(get_option())` | |
| 27 | ||
| 28 | error: manual implementation of `Option::zip` | |
| 29 | --> tests/ui/manual_option_zip.rs:32:13 | |
| 23 | --> tests/ui/manual_option_zip.rs:27:13 | |
| 30 | 24 | | |
| 31 | 25 | LL | let _ = a.and_then(|a| b.map(|b| (b, a))); |
| 32 | 26 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.zip(a)` |
| 33 | 27 | |
| 34 | 28 | error: manual implementation of `Option::zip` |
| 35 | --> tests/ui/manual_option_zip.rs:39:13 | |
| 29 | --> tests/ui/manual_option_zip.rs:34:13 | |
| 36 | 30 | | |
| 37 | 31 | LL | let _ = a.and_then(|a| { b.map(|b| (a, b)) }); |
| 38 | 32 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)` |
| 39 | 33 | |
| 40 | 34 | error: manual implementation of `Option::zip` |
| 41 | --> tests/ui/manual_option_zip.rs:42:13 | |
| 35 | --> tests/ui/manual_option_zip.rs:37:13 | |
| 42 | 36 | | |
| 43 | 37 | LL | let _ = a.and_then(|a| b.map(|b| { (a, b) })); |
| 44 | 38 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)` |
| 45 | 39 | |
| 46 | 40 | error: manual implementation of `Option::zip` |
| 47 | --> tests/ui/manual_option_zip.rs:45:13 | |
| 41 | --> tests/ui/manual_option_zip.rs:40:13 | |
| 48 | 42 | | |
| 49 | 43 | LL | let _ = a.and_then(|a| { b.map(|b| { (a, b) }) }); |
| 50 | 44 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)` |
| 51 | 45 | |
| 52 | error: aborting due to 8 previous errors | |
| 46 | error: aborting due to 7 previous errors | |
| 53 | 47 |
src/tools/clippy/tests/ui/manual_slice_fill.fixed+32| ... | ... | @@ -34,6 +34,38 @@ fn should_lint() { |
| 34 | 34 | some_slice.fill(0); |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | fn should_lint_direct_mutref_array(s: &mut [u8; 1]) { | |
| 38 | s.fill(0); | |
| 39 | } | |
| 40 | ||
| 41 | fn should_lint_direct_mutref_array_non_zero(s: &mut [u8; 4]) { | |
| 42 | s.fill(42); | |
| 43 | } | |
| 44 | ||
| 45 | fn should_lint_direct_mutref_array_variable(s: &mut [i32; 3]) { | |
| 46 | let x = 7; | |
| 47 | s.fill(x); | |
| 48 | } | |
| 49 | ||
| 50 | fn should_not_lint_direct_mutref_array_fn(s: &mut [usize; 2]) { | |
| 51 | for slot in s { | |
| 52 | *slot = num(); | |
| 53 | } | |
| 54 | } | |
| 55 | ||
| 56 | fn should_not_lint_direct_mutref_array_iter_used(s: &mut [u8; 3]) { | |
| 57 | for slot in s { | |
| 58 | *slot = !*slot; | |
| 59 | } | |
| 60 | } | |
| 61 | ||
| 62 | fn should_not_lint_direct_mutref_array_extra_stmt(s: &mut [u8; 2]) { | |
| 63 | for slot in s { | |
| 64 | *slot = 0; | |
| 65 | println!("foo"); | |
| 66 | } | |
| 67 | } | |
| 68 | ||
| 37 | 69 | fn should_not_lint() { |
| 38 | 70 | let mut some_slice = [1, 2, 3, 4, 5]; |
| 39 | 71 |
src/tools/clippy/tests/ui/manual_slice_fill.rs+41| ... | ... | @@ -47,6 +47,47 @@ fn should_lint() { |
| 47 | 47 | } |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | fn should_lint_direct_mutref_array(s: &mut [u8; 1]) { | |
| 51 | for slot in s { | |
| 52 | //~^ manual_slice_fill | |
| 53 | *slot = 0; | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | fn should_lint_direct_mutref_array_non_zero(s: &mut [u8; 4]) { | |
| 58 | for slot in s { | |
| 59 | //~^ manual_slice_fill | |
| 60 | *slot = 42; | |
| 61 | } | |
| 62 | } | |
| 63 | ||
| 64 | fn should_lint_direct_mutref_array_variable(s: &mut [i32; 3]) { | |
| 65 | let x = 7; | |
| 66 | for slot in s { | |
| 67 | //~^ manual_slice_fill | |
| 68 | *slot = x; | |
| 69 | } | |
| 70 | } | |
| 71 | ||
| 72 | fn should_not_lint_direct_mutref_array_fn(s: &mut [usize; 2]) { | |
| 73 | for slot in s { | |
| 74 | *slot = num(); | |
| 75 | } | |
| 76 | } | |
| 77 | ||
| 78 | fn should_not_lint_direct_mutref_array_iter_used(s: &mut [u8; 3]) { | |
| 79 | for slot in s { | |
| 80 | *slot = !*slot; | |
| 81 | } | |
| 82 | } | |
| 83 | ||
| 84 | fn should_not_lint_direct_mutref_array_extra_stmt(s: &mut [u8; 2]) { | |
| 85 | for slot in s { | |
| 86 | *slot = 0; | |
| 87 | println!("foo"); | |
| 88 | } | |
| 89 | } | |
| 90 | ||
| 50 | 91 | fn should_not_lint() { |
| 51 | 92 | let mut some_slice = [1, 2, 3, 4, 5]; |
| 52 | 93 |
src/tools/clippy/tests/ui/manual_slice_fill.stderr+28-1| ... | ... | @@ -38,5 +38,32 @@ LL | | // foo |
| 38 | 38 | LL | | } |
| 39 | 39 | | |_____^ help: try: `some_slice.fill(0);` |
| 40 | 40 | |
| 41 | error: aborting due to 4 previous errors | |
| 41 | error: manually filling a slice | |
| 42 | --> tests/ui/manual_slice_fill.rs:51:5 | |
| 43 | | | |
| 44 | LL | / for slot in s { | |
| 45 | LL | | | |
| 46 | LL | | *slot = 0; | |
| 47 | LL | | } | |
| 48 | | |_____^ help: try: `s.fill(0);` | |
| 49 | ||
| 50 | error: manually filling a slice | |
| 51 | --> tests/ui/manual_slice_fill.rs:58:5 | |
| 52 | | | |
| 53 | LL | / for slot in s { | |
| 54 | LL | | | |
| 55 | LL | | *slot = 42; | |
| 56 | LL | | } | |
| 57 | | |_____^ help: try: `s.fill(42);` | |
| 58 | ||
| 59 | error: manually filling a slice | |
| 60 | --> tests/ui/manual_slice_fill.rs:66:5 | |
| 61 | | | |
| 62 | LL | / for slot in s { | |
| 63 | LL | | | |
| 64 | LL | | *slot = x; | |
| 65 | LL | | } | |
| 66 | | |_____^ help: try: `s.fill(x);` | |
| 67 | ||
| 68 | error: aborting due to 7 previous errors | |
| 42 | 69 |
src/tools/clippy/tests/ui/map_unwrap_or.rs+7| ... | ... | @@ -161,3 +161,10 @@ fn issue15752() { |
| 161 | 161 | x.map(|y| y.0).unwrap_or(&[]); |
| 162 | 162 | //~^ map_unwrap_or |
| 163 | 163 | } |
| 164 | ||
| 165 | fn issue16901() { | |
| 166 | let raw = String::from("scope:value"); | |
| 167 | let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw); | |
| 168 | //~^ map_unwrap_or | |
| 169 | let _: &str = after_scope; | |
| 170 | } |
src/tools/clippy/tests/ui/map_unwrap_or.stderr+7-1| ... | ... | @@ -238,5 +238,11 @@ error: called `map(<f>).unwrap_or(<a>)` on an `Option` value |
| 238 | 238 | LL | x.map(|y| y.0).unwrap_or(&[]); |
| 239 | 239 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 240 | 240 | |
| 241 | error: aborting due to 16 previous errors | |
| 241 | error: called `map(<f>).unwrap_or(<a>)` on an `Option` value | |
| 242 | --> tests/ui/map_unwrap_or.rs:167:23 | |
| 243 | | | |
| 244 | LL | let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw); | |
| 245 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 246 | ||
| 247 | error: aborting due to 17 previous errors | |
| 242 | 248 |
src/tools/clippy/tests/ui/methods.rs+1-66| ... | ... | @@ -1,36 +1,10 @@ |
| 1 | //@aux-build:option_helpers.rs | |
| 2 | ||
| 3 | #![allow( | |
| 4 | clippy::disallowed_names, | |
| 5 | clippy::default_trait_access, | |
| 6 | clippy::let_underscore_untyped, | |
| 7 | clippy::missing_docs_in_private_items, | |
| 8 | clippy::missing_safety_doc, | |
| 9 | clippy::non_ascii_literal, | |
| 10 | clippy::new_without_default, | |
| 11 | clippy::needless_pass_by_value, | |
| 12 | clippy::needless_lifetimes, | |
| 13 | clippy::elidable_lifetime_names, | |
| 14 | clippy::print_stdout, | |
| 15 | clippy::must_use_candidate, | |
| 16 | clippy::use_self, | |
| 17 | clippy::useless_format, | |
| 18 | clippy::wrong_self_convention, | |
| 19 | clippy::unused_async, | |
| 20 | clippy::unused_self, | |
| 21 | clippy::useless_vec | |
| 22 | )] | |
| 23 | ||
| 24 | #[macro_use] | |
| 25 | extern crate option_helpers; | |
| 1 | #![warn(clippy::filter_next, clippy::new_ret_no_self)] | |
| 26 | 2 | |
| 27 | 3 | use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; |
| 28 | 4 | use std::ops::Mul; |
| 29 | 5 | use std::rc::{self, Rc}; |
| 30 | 6 | use std::sync::{self, Arc}; |
| 31 | 7 | |
| 32 | use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives}; | |
| 33 | ||
| 34 | 8 | struct Lt<'a> { |
| 35 | 9 | foo: &'a u32, |
| 36 | 10 | } |
| ... | ... | @@ -115,43 +89,4 @@ impl Mul<T> for T { |
| 115 | 89 | } |
| 116 | 90 | } |
| 117 | 91 | |
| 118 | /// Checks implementation of `FILTER_NEXT` lint. | |
| 119 | #[rustfmt::skip] | |
| 120 | fn filter_next() { | |
| 121 | let v = vec![3, 2, 1, 0, -1, -2, -3]; | |
| 122 | ||
| 123 | // Multi-line case. | |
| 124 | let _ = v.iter().filter(|&x| { | |
| 125 | //~^ filter_next | |
| 126 | *x < 0 | |
| 127 | } | |
| 128 | ).next(); | |
| 129 | ||
| 130 | // Check that we don't lint if the caller is not an `Iterator`. | |
| 131 | let foo = IteratorFalsePositives { foo: 0 }; | |
| 132 | let _ = foo.filter().next(); | |
| 133 | ||
| 134 | let foo = IteratorMethodFalsePositives {}; | |
| 135 | let _ = foo.filter(42).next(); | |
| 136 | } | |
| 137 | ||
| 138 | #[rustfmt::skip] | |
| 139 | fn filter_next_back() { | |
| 140 | let v = vec![3, 2, 1, 0, -1, -2, -3]; | |
| 141 | ||
| 142 | // Multi-line case. | |
| 143 | let _ = v.iter().filter(|&x| { | |
| 144 | //~^ filter_next | |
| 145 | *x < 0 | |
| 146 | } | |
| 147 | ).next_back(); | |
| 148 | ||
| 149 | // Check that we don't lint if the caller is not an `Iterator`. | |
| 150 | let foo = IteratorFalsePositives { foo: 0 }; | |
| 151 | let _ = foo.filter().next_back(); | |
| 152 | ||
| 153 | let foo = IteratorMethodFalsePositives {}; | |
| 154 | let _ = foo.filter(42).next_back(); | |
| 155 | } | |
| 156 | ||
| 157 | 92 | fn main() {} |
src/tools/clippy/tests/ui/methods.stderr+2-27| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: methods called `new` usually return `Self` |
| 2 | --> tests/ui/methods.rs:102:5 | |
| 2 | --> tests/ui/methods.rs:76:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | / fn new() -> i32 { |
| 5 | 5 | LL | | |
| ... | ... | @@ -10,30 +10,5 @@ LL | | } |
| 10 | 10 | = note: `-D clippy::new-ret-no-self` implied by `-D warnings` |
| 11 | 11 | = help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]` |
| 12 | 12 | |
| 13 | error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead | |
| 14 | --> tests/ui/methods.rs:124:13 | |
| 15 | | | |
| 16 | LL | let _ = v.iter().filter(|&x| { | |
| 17 | | _____________^ | |
| 18 | LL | | | |
| 19 | LL | | *x < 0 | |
| 20 | LL | | } | |
| 21 | LL | | ).next(); | |
| 22 | | |___________________________^ | |
| 23 | | | |
| 24 | = note: `-D clippy::filter-next` implied by `-D warnings` | |
| 25 | = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` | |
| 26 | ||
| 27 | error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead | |
| 28 | --> tests/ui/methods.rs:143:13 | |
| 29 | | | |
| 30 | LL | let _ = v.iter().filter(|&x| { | |
| 31 | | _____________^ | |
| 32 | LL | | | |
| 33 | LL | | *x < 0 | |
| 34 | LL | | } | |
| 35 | LL | | ).next_back(); | |
| 36 | | |________________________________^ | |
| 37 | ||
| 38 | error: aborting due to 3 previous errors | |
| 13 | error: aborting due to 1 previous error | |
| 39 | 14 |
src/tools/clippy/tests/ui/methods_fixable.fixed deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | #![warn(clippy::filter_next)] | |
| 2 | #![allow(clippy::useless_vec)] | |
| 3 | ||
| 4 | /// Checks implementation of `FILTER_NEXT` lint. | |
| 5 | fn main() { | |
| 6 | let v = vec![3, 2, 1, 0, -1, -2, -3]; | |
| 7 | ||
| 8 | // Single-line case. | |
| 9 | let _ = v.iter().find(|&x| *x < 0); | |
| 10 | //~^ filter_next | |
| 11 | ||
| 12 | let _ = v.iter().rfind(|&x| *x < 0); | |
| 13 | //~^ filter_next | |
| 14 | } | |
| 15 | ||
| 16 | #[clippy::msrv = "1.27"] | |
| 17 | fn msrv_1_27() { | |
| 18 | let _ = vec![1].into_iter().rfind(|&x| x < 0); | |
| 19 | //~^ filter_next | |
| 20 | } | |
| 21 | ||
| 22 | #[clippy::msrv = "1.26"] | |
| 23 | fn msrv_1_26() { | |
| 24 | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 25 | } |
src/tools/clippy/tests/ui/methods_fixable.rs deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | #![warn(clippy::filter_next)] | |
| 2 | #![allow(clippy::useless_vec)] | |
| 3 | ||
| 4 | /// Checks implementation of `FILTER_NEXT` lint. | |
| 5 | fn main() { | |
| 6 | let v = vec![3, 2, 1, 0, -1, -2, -3]; | |
| 7 | ||
| 8 | // Single-line case. | |
| 9 | let _ = v.iter().filter(|&x| *x < 0).next(); | |
| 10 | //~^ filter_next | |
| 11 | ||
| 12 | let _ = v.iter().filter(|&x| *x < 0).next_back(); | |
| 13 | //~^ filter_next | |
| 14 | } | |
| 15 | ||
| 16 | #[clippy::msrv = "1.27"] | |
| 17 | fn msrv_1_27() { | |
| 18 | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 19 | //~^ filter_next | |
| 20 | } | |
| 21 | ||
| 22 | #[clippy::msrv = "1.26"] | |
| 23 | fn msrv_1_26() { | |
| 24 | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 25 | } |
src/tools/clippy/tests/ui/methods_fixable.stderr deleted-23| ... | ... | @@ -1,23 +0,0 @@ |
| 1 | error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead | |
| 2 | --> tests/ui/methods_fixable.rs:9:13 | |
| 3 | | | |
| 4 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().find(|&x| *x < 0)` | |
| 6 | | | |
| 7 | = note: `-D clippy::filter-next` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` | |
| 9 | ||
| 10 | error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead | |
| 11 | --> tests/ui/methods_fixable.rs:12:13 | |
| 12 | | | |
| 13 | LL | let _ = v.iter().filter(|&x| *x < 0).next_back(); | |
| 14 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().rfind(|&x| *x < 0)` | |
| 15 | ||
| 16 | error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead | |
| 17 | --> tests/ui/methods_fixable.rs:18:13 | |
| 18 | | | |
| 19 | LL | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back(); | |
| 20 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec![1].into_iter().rfind(|&x| x < 0)` | |
| 21 | ||
| 22 | error: aborting due to 3 previous errors | |
| 23 |
src/tools/clippy/tests/ui/methods_unfixable.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | #![warn(clippy::filter_next)] | |
| 2 | //@no-rustfix | |
| 3 | fn main() {} | |
| 4 | ||
| 5 | pub fn issue10029() { | |
| 6 | let iter = (0..10); | |
| 7 | let _ = iter.filter(|_| true).next(); | |
| 8 | //~^ filter_next | |
| 9 | } |
src/tools/clippy/tests/ui/methods_unfixable.stderr deleted-16| ... | ... | @@ -1,16 +0,0 @@ |
| 1 | error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead | |
| 2 | --> tests/ui/methods_unfixable.rs:7:13 | |
| 3 | | | |
| 4 | LL | let _ = iter.filter(|_| true).next(); | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)` | |
| 6 | | | |
| 7 | help: you will also need to make `iter` mutable, because `find` takes `&mut self` | |
| 8 | --> tests/ui/methods_unfixable.rs:6:9 | |
| 9 | | | |
| 10 | LL | let iter = (0..10); | |
| 11 | | ^^^^ | |
| 12 | = note: `-D clippy::filter-next` implied by `-D warnings` | |
| 13 | = help: to override `-D warnings` add `#[allow(clippy::filter_next)]` | |
| 14 | ||
| 15 | error: aborting due to 1 previous error | |
| 16 |
src/tools/clippy/tests/ui/min_ident_chars.rs+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | //@aux-build:proc_macros.rs |
| 2 | #![allow(irrefutable_let_patterns, nonstandard_style, unused)] | |
| 3 | #![allow(clippy::struct_field_names)] | |
| 4 | 2 | #![warn(clippy::min_ident_chars)] |
| 3 | #![expect(irrefutable_let_patterns, nonstandard_style)] | |
| 4 | #![allow(clippy::struct_field_names)] | |
| 5 | 5 | |
| 6 | 6 | extern crate proc_macros; |
| 7 | 7 | use proc_macros::{external, with_span}; |
src/tools/clippy/tests/ui/min_max.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | #![allow(clippy::manual_clamp)] | |
| 1 | #![warn(clippy::min_max)] | |
| 2 | #![expect(clippy::manual_clamp)] | |
| 2 | 3 | |
| 3 | 4 | use std::cmp::{max as my_max, max, min as my_min, min}; |
| 4 | 5 |
src/tools/clippy/tests/ui/min_max.stderr+15-14| ... | ... | @@ -1,79 +1,80 @@ |
| 1 | 1 | error: this `min`/`max` combination leads to constant result |
| 2 | --> tests/ui/min_max.rs:21:5 | |
| 2 | --> tests/ui/min_max.rs:22:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | min(1, max(3, x)); |
| 5 | 5 | | ^^^^^^^^^^^^^^^^^ |
| 6 | 6 | | |
| 7 | = note: `#[deny(clippy::min_max)]` on by default | |
| 7 | = note: `-D clippy::min-max` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::min_max)]` | |
| 8 | 9 | |
| 9 | 10 | error: this `min`/`max` combination leads to constant result |
| 10 | --> tests/ui/min_max.rs:24:5 | |
| 11 | --> tests/ui/min_max.rs:25:5 | |
| 11 | 12 | | |
| 12 | 13 | LL | min(max(3, x), 1); |
| 13 | 14 | | ^^^^^^^^^^^^^^^^^ |
| 14 | 15 | |
| 15 | 16 | error: this `min`/`max` combination leads to constant result |
| 16 | --> tests/ui/min_max.rs:27:5 | |
| 17 | --> tests/ui/min_max.rs:28:5 | |
| 17 | 18 | | |
| 18 | 19 | LL | max(min(x, 1), 3); |
| 19 | 20 | | ^^^^^^^^^^^^^^^^^ |
| 20 | 21 | |
| 21 | 22 | error: this `min`/`max` combination leads to constant result |
| 22 | --> tests/ui/min_max.rs:30:5 | |
| 23 | --> tests/ui/min_max.rs:31:5 | |
| 23 | 24 | | |
| 24 | 25 | LL | max(3, min(x, 1)); |
| 25 | 26 | | ^^^^^^^^^^^^^^^^^ |
| 26 | 27 | |
| 27 | 28 | error: this `min`/`max` combination leads to constant result |
| 28 | --> tests/ui/min_max.rs:33:5 | |
| 29 | --> tests/ui/min_max.rs:34:5 | |
| 29 | 30 | | |
| 30 | 31 | LL | my_max(3, my_min(x, 1)); |
| 31 | 32 | | ^^^^^^^^^^^^^^^^^^^^^^^ |
| 32 | 33 | |
| 33 | 34 | error: this `min`/`max` combination leads to constant result |
| 34 | --> tests/ui/min_max.rs:44:5 | |
| 35 | --> tests/ui/min_max.rs:45:5 | |
| 35 | 36 | | |
| 36 | 37 | LL | min("Apple", max("Zoo", s)); |
| 37 | 38 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 38 | 39 | |
| 39 | 40 | error: this `min`/`max` combination leads to constant result |
| 40 | --> tests/ui/min_max.rs:47:5 | |
| 41 | --> tests/ui/min_max.rs:48:5 | |
| 41 | 42 | | |
| 42 | 43 | LL | max(min(s, "Apple"), "Zoo"); |
| 43 | 44 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 44 | 45 | |
| 45 | 46 | error: this `min`/`max` combination leads to constant result |
| 46 | --> tests/ui/min_max.rs:53:5 | |
| 47 | --> tests/ui/min_max.rs:54:5 | |
| 47 | 48 | | |
| 48 | 49 | LL | x.min(1).max(3); |
| 49 | 50 | | ^^^^^^^^^^^^^^^ |
| 50 | 51 | |
| 51 | 52 | error: this `min`/`max` combination leads to constant result |
| 52 | --> tests/ui/min_max.rs:56:5 | |
| 53 | --> tests/ui/min_max.rs:57:5 | |
| 53 | 54 | | |
| 54 | 55 | LL | x.max(3).min(1); |
| 55 | 56 | | ^^^^^^^^^^^^^^^ |
| 56 | 57 | |
| 57 | 58 | error: this `min`/`max` combination leads to constant result |
| 58 | --> tests/ui/min_max.rs:59:5 | |
| 59 | --> tests/ui/min_max.rs:60:5 | |
| 59 | 60 | | |
| 60 | 61 | LL | f.max(3f32).min(1f32); |
| 61 | 62 | | ^^^^^^^^^^^^^^^^^^^^^ |
| 62 | 63 | |
| 63 | 64 | error: this `min`/`max` combination leads to constant result |
| 64 | --> tests/ui/min_max.rs:66:5 | |
| 65 | --> tests/ui/min_max.rs:67:5 | |
| 65 | 66 | | |
| 66 | 67 | LL | max(x.min(1), 3); |
| 67 | 68 | | ^^^^^^^^^^^^^^^^ |
| 68 | 69 | |
| 69 | 70 | error: this `min`/`max` combination leads to constant result |
| 70 | --> tests/ui/min_max.rs:71:5 | |
| 71 | --> tests/ui/min_max.rs:72:5 | |
| 71 | 72 | | |
| 72 | 73 | LL | s.max("Zoo").min("Apple"); |
| 73 | 74 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 74 | 75 | |
| 75 | 76 | error: this `min`/`max` combination leads to constant result |
| 76 | --> tests/ui/min_max.rs:74:5 | |
| 77 | --> tests/ui/min_max.rs:75:5 | |
| 77 | 78 | | |
| 78 | 79 | LL | s.min("Apple").max("Zoo"); |
| 79 | 80 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
src/tools/clippy/tests/ui/min_rust_version_attr.rs-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | #![allow(clippy::redundant_clone)] | |
| 2 | 1 | #![feature(custom_inner_attributes)] |
| 3 | 2 | |
| 4 | 3 | fn main() {} |
src/tools/clippy/tests/ui/min_rust_version_attr.stderr+6-6| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: approximate value of `f{32, 64}::consts::LOG2_10` found |
| 2 | --> tests/ui/min_rust_version_attr.rs:13:19 | |
| 2 | --> tests/ui/min_rust_version_attr.rs:12:19 | |
| 3 | 3 | | |
| 4 | 4 | LL | let log2_10 = 3.321928094887362; |
| 5 | 5 | | ^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -8,7 +8,7 @@ LL | let log2_10 = 3.321928094887362; |
| 8 | 8 | = note: `#[deny(clippy::approx_constant)]` on by default |
| 9 | 9 | |
| 10 | 10 | error: approximate value of `f{32, 64}::consts::LOG2_10` found |
| 11 | --> tests/ui/min_rust_version_attr.rs:19:19 | |
| 11 | --> tests/ui/min_rust_version_attr.rs:18:19 | |
| 12 | 12 | | |
| 13 | 13 | LL | let log2_10 = 3.321928094887362; |
| 14 | 14 | | ^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -16,7 +16,7 @@ LL | let log2_10 = 3.321928094887362; |
| 16 | 16 | = help: consider using the constant directly |
| 17 | 17 | |
| 18 | 18 | error: approximate value of `f{32, 64}::consts::LOG2_10` found |
| 19 | --> tests/ui/min_rust_version_attr.rs:30:19 | |
| 19 | --> tests/ui/min_rust_version_attr.rs:29:19 | |
| 20 | 20 | | |
| 21 | 21 | LL | let log2_10 = 3.321928094887362; |
| 22 | 22 | | ^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -24,7 +24,7 @@ LL | let log2_10 = 3.321928094887362; |
| 24 | 24 | = help: consider using the constant directly |
| 25 | 25 | |
| 26 | 26 | error: approximate value of `f{32, 64}::consts::LOG2_10` found |
| 27 | --> tests/ui/min_rust_version_attr.rs:41:19 | |
| 27 | --> tests/ui/min_rust_version_attr.rs:40:19 | |
| 28 | 28 | | |
| 29 | 29 | LL | let log2_10 = 3.321928094887362; |
| 30 | 30 | | ^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -32,7 +32,7 @@ LL | let log2_10 = 3.321928094887362; |
| 32 | 32 | = help: consider using the constant directly |
| 33 | 33 | |
| 34 | 34 | error: approximate value of `f{32, 64}::consts::LOG2_10` found |
| 35 | --> tests/ui/min_rust_version_attr.rs:52:19 | |
| 35 | --> tests/ui/min_rust_version_attr.rs:51:19 | |
| 36 | 36 | | |
| 37 | 37 | LL | let log2_10 = 3.321928094887362; |
| 38 | 38 | | ^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -40,7 +40,7 @@ LL | let log2_10 = 3.321928094887362; |
| 40 | 40 | = help: consider using the constant directly |
| 41 | 41 | |
| 42 | 42 | error: approximate value of `f{32, 64}::consts::LOG2_10` found |
| 43 | --> tests/ui/min_rust_version_attr.rs:60:27 | |
| 43 | --> tests/ui/min_rust_version_attr.rs:59:27 | |
| 44 | 44 | | |
| 45 | 45 | LL | let log2_10 = 3.321928094887362; |
| 46 | 46 | | ^^^^^^^^^^^^^^^^^ |
src/tools/clippy/tests/ui/mismatching_type_param_order.rs-1| ... | ... | @@ -1,5 +1,4 @@ |
| 1 | 1 | #![warn(clippy::mismatching_type_param_order)] |
| 2 | #![allow(clippy::disallowed_names, clippy::needless_lifetimes)] | |
| 3 | 2 | |
| 4 | 3 | fn main() { |
| 5 | 4 | struct Foo<A, B> { |
src/tools/clippy/tests/ui/mismatching_type_param_order.stderr+10-10| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: `Foo` has a similarly named generic type parameter `B` in its declaration, but in a different order |
| 2 | --> tests/ui/mismatching_type_param_order.rs:11:20 | |
| 2 | --> tests/ui/mismatching_type_param_order.rs:10:20 | |
| 3 | 3 | | |
| 4 | 4 | LL | impl<B, A> Foo<B, A> {} |
| 5 | 5 | | ^ |
| ... | ... | @@ -9,7 +9,7 @@ LL | impl<B, A> Foo<B, A> {} |
| 9 | 9 | = help: to override `-D warnings` add `#[allow(clippy::mismatching_type_param_order)]` |
| 10 | 10 | |
| 11 | 11 | error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order |
| 12 | --> tests/ui/mismatching_type_param_order.rs:11:23 | |
| 12 | --> tests/ui/mismatching_type_param_order.rs:10:23 | |
| 13 | 13 | | |
| 14 | 14 | LL | impl<B, A> Foo<B, A> {} |
| 15 | 15 | | ^ |
| ... | ... | @@ -17,7 +17,7 @@ LL | impl<B, A> Foo<B, A> {} |
| 17 | 17 | = help: try `B`, or a name that does not conflict with `Foo`'s generic params |
| 18 | 18 | |
| 19 | 19 | error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order |
| 20 | --> tests/ui/mismatching_type_param_order.rs:16:23 | |
| 20 | --> tests/ui/mismatching_type_param_order.rs:15:23 | |
| 21 | 21 | | |
| 22 | 22 | LL | impl<C, A> Foo<C, A> {} |
| 23 | 23 | | ^ |
| ... | ... | @@ -25,7 +25,7 @@ LL | impl<C, A> Foo<C, A> {} |
| 25 | 25 | = help: try `B`, or a name that does not conflict with `Foo`'s generic params |
| 26 | 26 | |
| 27 | 27 | error: `FooLifetime` has a similarly named generic type parameter `B` in its declaration, but in a different order |
| 28 | --> tests/ui/mismatching_type_param_order.rs:28:44 | |
| 28 | --> tests/ui/mismatching_type_param_order.rs:27:44 | |
| 29 | 29 | | |
| 30 | 30 | LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} |
| 31 | 31 | | ^ |
| ... | ... | @@ -33,7 +33,7 @@ LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} |
| 33 | 33 | = help: try `A`, or a name that does not conflict with `FooLifetime`'s generic params |
| 34 | 34 | |
| 35 | 35 | error: `FooLifetime` has a similarly named generic type parameter `A` in its declaration, but in a different order |
| 36 | --> tests/ui/mismatching_type_param_order.rs:28:47 | |
| 36 | --> tests/ui/mismatching_type_param_order.rs:27:47 | |
| 37 | 37 | | |
| 38 | 38 | LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} |
| 39 | 39 | | ^ |
| ... | ... | @@ -41,7 +41,7 @@ LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} |
| 41 | 41 | = help: try `B`, or a name that does not conflict with `FooLifetime`'s generic params |
| 42 | 42 | |
| 43 | 43 | error: `FooEnum` has a similarly named generic type parameter `C` in its declaration, but in a different order |
| 44 | --> tests/ui/mismatching_type_param_order.rs:46:27 | |
| 44 | --> tests/ui/mismatching_type_param_order.rs:45:27 | |
| 45 | 45 | | |
| 46 | 46 | LL | impl<C, A, B> FooEnum<C, A, B> {} |
| 47 | 47 | | ^ |
| ... | ... | @@ -49,7 +49,7 @@ LL | impl<C, A, B> FooEnum<C, A, B> {} |
| 49 | 49 | = help: try `A`, or a name that does not conflict with `FooEnum`'s generic params |
| 50 | 50 | |
| 51 | 51 | error: `FooEnum` has a similarly named generic type parameter `A` in its declaration, but in a different order |
| 52 | --> tests/ui/mismatching_type_param_order.rs:46:30 | |
| 52 | --> tests/ui/mismatching_type_param_order.rs:45:30 | |
| 53 | 53 | | |
| 54 | 54 | LL | impl<C, A, B> FooEnum<C, A, B> {} |
| 55 | 55 | | ^ |
| ... | ... | @@ -57,7 +57,7 @@ LL | impl<C, A, B> FooEnum<C, A, B> {} |
| 57 | 57 | = help: try `B`, or a name that does not conflict with `FooEnum`'s generic params |
| 58 | 58 | |
| 59 | 59 | error: `FooEnum` has a similarly named generic type parameter `B` in its declaration, but in a different order |
| 60 | --> tests/ui/mismatching_type_param_order.rs:46:33 | |
| 60 | --> tests/ui/mismatching_type_param_order.rs:45:33 | |
| 61 | 61 | | |
| 62 | 62 | LL | impl<C, A, B> FooEnum<C, A, B> {} |
| 63 | 63 | | ^ |
| ... | ... | @@ -65,7 +65,7 @@ LL | impl<C, A, B> FooEnum<C, A, B> {} |
| 65 | 65 | = help: try `C`, or a name that does not conflict with `FooEnum`'s generic params |
| 66 | 66 | |
| 67 | 67 | error: `FooUnion` has a similarly named generic type parameter `B` in its declaration, but in a different order |
| 68 | --> tests/ui/mismatching_type_param_order.rs:60:31 | |
| 68 | --> tests/ui/mismatching_type_param_order.rs:59:31 | |
| 69 | 69 | | |
| 70 | 70 | LL | impl<B: Copy, A> FooUnion<B, A> where A: Copy {} |
| 71 | 71 | | ^ |
| ... | ... | @@ -73,7 +73,7 @@ LL | impl<B: Copy, A> FooUnion<B, A> where A: Copy {} |
| 73 | 73 | = help: try `A`, or a name that does not conflict with `FooUnion`'s generic params |
| 74 | 74 | |
| 75 | 75 | error: `FooUnion` has a similarly named generic type parameter `A` in its declaration, but in a different order |
| 76 | --> tests/ui/mismatching_type_param_order.rs:60:34 | |
| 76 | --> tests/ui/mismatching_type_param_order.rs:59:34 | |
| 77 | 77 | | |
| 78 | 78 | LL | impl<B: Copy, A> FooUnion<B, A> where A: Copy {} |
| 79 | 79 | | ^ |
src/tools/clippy/tests/ui/misnamed_getters.fixed+1-2| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | #![allow(unused)] | |
| 2 | #![allow(clippy::struct_field_names)] | |
| 3 | 1 | #![warn(clippy::misnamed_getters)] |
| 2 | #![expect(clippy::struct_field_names)] | |
| 4 | 3 | |
| 5 | 4 | struct A { |
| 6 | 5 | a: u8, |
src/tools/clippy/tests/ui/misnamed_getters.rs+1-2| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | #![allow(unused)] | |
| 2 | #![allow(clippy::struct_field_names)] | |
| 3 | 1 | #![warn(clippy::misnamed_getters)] |
| 2 | #![expect(clippy::struct_field_names)] | |
| 4 | 3 | |
| 5 | 4 | struct A { |
| 6 | 5 | a: u8, |
src/tools/clippy/tests/ui/misnamed_getters.stderr+18-18| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: getter function appears to return the wrong field |
| 2 | --> tests/ui/misnamed_getters.rs:12:5 | |
| 2 | --> tests/ui/misnamed_getters.rs:11:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | / fn a(&self) -> &u8 { |
| 5 | 5 | LL | | |
| ... | ... | @@ -13,7 +13,7 @@ LL | | } |
| 13 | 13 | = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]` |
| 14 | 14 | |
| 15 | 15 | error: getter function appears to return the wrong field |
| 16 | --> tests/ui/misnamed_getters.rs:17:5 | |
| 16 | --> tests/ui/misnamed_getters.rs:16:5 | |
| 17 | 17 | | |
| 18 | 18 | LL | / fn a_mut(&mut self) -> &mut u8 { |
| 19 | 19 | LL | | |
| ... | ... | @@ -24,7 +24,7 @@ LL | | } |
| 24 | 24 | | |_____^ |
| 25 | 25 | |
| 26 | 26 | error: getter function appears to return the wrong field |
| 27 | --> tests/ui/misnamed_getters.rs:23:5 | |
| 27 | --> tests/ui/misnamed_getters.rs:22:5 | |
| 28 | 28 | | |
| 29 | 29 | LL | / fn b(self) -> u8 { |
| 30 | 30 | LL | | |
| ... | ... | @@ -35,7 +35,7 @@ LL | | } |
| 35 | 35 | | |_____^ |
| 36 | 36 | |
| 37 | 37 | error: getter function appears to return the wrong field |
| 38 | --> tests/ui/misnamed_getters.rs:29:5 | |
| 38 | --> tests/ui/misnamed_getters.rs:28:5 | |
| 39 | 39 | | |
| 40 | 40 | LL | / fn b_mut(&mut self) -> &mut u8 { |
| 41 | 41 | LL | | |
| ... | ... | @@ -46,7 +46,7 @@ LL | | } |
| 46 | 46 | | |_____^ |
| 47 | 47 | |
| 48 | 48 | error: getter function appears to return the wrong field |
| 49 | --> tests/ui/misnamed_getters.rs:35:5 | |
| 49 | --> tests/ui/misnamed_getters.rs:34:5 | |
| 50 | 50 | | |
| 51 | 51 | LL | / fn c(&self) -> &u8 { |
| 52 | 52 | LL | | |
| ... | ... | @@ -57,7 +57,7 @@ LL | | } |
| 57 | 57 | | |_____^ |
| 58 | 58 | |
| 59 | 59 | error: getter function appears to return the wrong field |
| 60 | --> tests/ui/misnamed_getters.rs:41:5 | |
| 60 | --> tests/ui/misnamed_getters.rs:40:5 | |
| 61 | 61 | | |
| 62 | 62 | LL | / fn c_mut(&mut self) -> &mut u8 { |
| 63 | 63 | LL | | |
| ... | ... | @@ -68,7 +68,7 @@ LL | | } |
| 68 | 68 | | |_____^ |
| 69 | 69 | |
| 70 | 70 | error: getter function appears to return the wrong field |
| 71 | --> tests/ui/misnamed_getters.rs:54:5 | |
| 71 | --> tests/ui/misnamed_getters.rs:53:5 | |
| 72 | 72 | | |
| 73 | 73 | LL | / unsafe fn a(&self) -> &u8 { |
| 74 | 74 | LL | | |
| ... | ... | @@ -79,7 +79,7 @@ LL | | } |
| 79 | 79 | | |_____^ |
| 80 | 80 | |
| 81 | 81 | error: getter function appears to return the wrong field |
| 82 | --> tests/ui/misnamed_getters.rs:59:5 | |
| 82 | --> tests/ui/misnamed_getters.rs:58:5 | |
| 83 | 83 | | |
| 84 | 84 | LL | / unsafe fn a_mut(&mut self) -> &mut u8 { |
| 85 | 85 | LL | | |
| ... | ... | @@ -90,7 +90,7 @@ LL | | } |
| 90 | 90 | | |_____^ |
| 91 | 91 | |
| 92 | 92 | error: getter function appears to return the wrong field |
| 93 | --> tests/ui/misnamed_getters.rs:65:5 | |
| 93 | --> tests/ui/misnamed_getters.rs:64:5 | |
| 94 | 94 | | |
| 95 | 95 | LL | / unsafe fn b(self) -> u8 { |
| 96 | 96 | LL | | |
| ... | ... | @@ -101,7 +101,7 @@ LL | | } |
| 101 | 101 | | |_____^ |
| 102 | 102 | |
| 103 | 103 | error: getter function appears to return the wrong field |
| 104 | --> tests/ui/misnamed_getters.rs:71:5 | |
| 104 | --> tests/ui/misnamed_getters.rs:70:5 | |
| 105 | 105 | | |
| 106 | 106 | LL | / unsafe fn b_mut(&mut self) -> &mut u8 { |
| 107 | 107 | LL | | |
| ... | ... | @@ -112,7 +112,7 @@ LL | | } |
| 112 | 112 | | |_____^ |
| 113 | 113 | |
| 114 | 114 | error: getter function appears to return the wrong field |
| 115 | --> tests/ui/misnamed_getters.rs:85:5 | |
| 115 | --> tests/ui/misnamed_getters.rs:84:5 | |
| 116 | 116 | | |
| 117 | 117 | LL | / unsafe fn a_unchecked(&self) -> &u8 { |
| 118 | 118 | LL | | |
| ... | ... | @@ -123,7 +123,7 @@ LL | | } |
| 123 | 123 | | |_____^ |
| 124 | 124 | |
| 125 | 125 | error: getter function appears to return the wrong field |
| 126 | --> tests/ui/misnamed_getters.rs:90:5 | |
| 126 | --> tests/ui/misnamed_getters.rs:89:5 | |
| 127 | 127 | | |
| 128 | 128 | LL | / unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { |
| 129 | 129 | LL | | |
| ... | ... | @@ -134,7 +134,7 @@ LL | | } |
| 134 | 134 | | |_____^ |
| 135 | 135 | |
| 136 | 136 | error: getter function appears to return the wrong field |
| 137 | --> tests/ui/misnamed_getters.rs:96:5 | |
| 137 | --> tests/ui/misnamed_getters.rs:95:5 | |
| 138 | 138 | | |
| 139 | 139 | LL | / unsafe fn b_unchecked(self) -> u8 { |
| 140 | 140 | LL | | |
| ... | ... | @@ -145,7 +145,7 @@ LL | | } |
| 145 | 145 | | |_____^ |
| 146 | 146 | |
| 147 | 147 | error: getter function appears to return the wrong field |
| 148 | --> tests/ui/misnamed_getters.rs:102:5 | |
| 148 | --> tests/ui/misnamed_getters.rs:101:5 | |
| 149 | 149 | | |
| 150 | 150 | LL | / unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { |
| 151 | 151 | LL | | |
| ... | ... | @@ -156,7 +156,7 @@ LL | | } |
| 156 | 156 | | |_____^ |
| 157 | 157 | |
| 158 | 158 | error: getter function appears to return the wrong field |
| 159 | --> tests/ui/misnamed_getters.rs:136:5 | |
| 159 | --> tests/ui/misnamed_getters.rs:135:5 | |
| 160 | 160 | | |
| 161 | 161 | LL | / fn a(&self) -> &u8 { |
| 162 | 162 | LL | | |
| ... | ... | @@ -167,7 +167,7 @@ LL | | } |
| 167 | 167 | | |_____^ |
| 168 | 168 | |
| 169 | 169 | error: getter function appears to return the wrong field |
| 170 | --> tests/ui/misnamed_getters.rs:141:5 | |
| 170 | --> tests/ui/misnamed_getters.rs:140:5 | |
| 171 | 171 | | |
| 172 | 172 | LL | / fn a_mut(&mut self) -> &mut u8 { |
| 173 | 173 | LL | | |
| ... | ... | @@ -178,7 +178,7 @@ LL | | } |
| 178 | 178 | | |_____^ |
| 179 | 179 | |
| 180 | 180 | error: getter function appears to return the wrong field |
| 181 | --> tests/ui/misnamed_getters.rs:147:5 | |
| 181 | --> tests/ui/misnamed_getters.rs:146:5 | |
| 182 | 182 | | |
| 183 | 183 | LL | / fn d(&self) -> &u8 { |
| 184 | 184 | LL | | |
| ... | ... | @@ -189,7 +189,7 @@ LL | | } |
| 189 | 189 | | |_____^ |
| 190 | 190 | |
| 191 | 191 | error: getter function appears to return the wrong field |
| 192 | --> tests/ui/misnamed_getters.rs:152:5 | |
| 192 | --> tests/ui/misnamed_getters.rs:151:5 | |
| 193 | 193 | | |
| 194 | 194 | LL | / fn d_mut(&mut self) -> &mut u8 { |
| 195 | 195 | LL | | |
src/tools/clippy/tests/ui/misnamed_getters_2021.fixed-2| ... | ... | @@ -1,6 +1,4 @@ |
| 1 | 1 | //@edition: 2021 |
| 2 | #![allow(unused)] | |
| 3 | #![allow(clippy::struct_field_names)] | |
| 4 | 2 | #![warn(clippy::misnamed_getters)] |
| 5 | 3 | |
| 6 | 4 | // Edition 2021 specific check, where `unsafe` blocks are not required |
src/tools/clippy/tests/ui/misnamed_getters_2021.rs-2| ... | ... | @@ -1,6 +1,4 @@ |
| 1 | 1 | //@edition: 2021 |
| 2 | #![allow(unused)] | |
| 3 | #![allow(clippy::struct_field_names)] | |
| 4 | 2 | #![warn(clippy::misnamed_getters)] |
| 5 | 3 | |
| 6 | 4 | // Edition 2021 specific check, where `unsafe` blocks are not required |
src/tools/clippy/tests/ui/misnamed_getters_2021.stderr+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: getter function appears to return the wrong field |
| 2 | --> tests/ui/misnamed_getters_2021.rs:15:5 | |
| 2 | --> tests/ui/misnamed_getters_2021.rs:13:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | / unsafe fn a(&self) -> &u8 { |
| 5 | 5 | LL | | |
src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed+2-1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | #![warn(clippy::misrefactored_assign_op)] | |
| 2 | #![deny(clippy::assign_op_pattern)] | |
| 1 | 3 | #![allow(clippy::eq_op)] |
| 2 | #![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] | |
| 3 | 4 | |
| 4 | 5 | fn main() { |
| 5 | 6 | let mut a = 5; |
src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed+2-1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | #![warn(clippy::misrefactored_assign_op)] | |
| 2 | #![deny(clippy::assign_op_pattern)] | |
| 1 | 3 | #![allow(clippy::eq_op)] |
| 2 | #![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] | |
| 3 | 4 | |
| 4 | 5 | fn main() { |
| 5 | 6 | let mut a = 5; |
src/tools/clippy/tests/ui/misrefactored_assign_op.rs+2-1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | #![warn(clippy::misrefactored_assign_op)] | |
| 2 | #![deny(clippy::assign_op_pattern)] | |
| 1 | 3 | #![allow(clippy::eq_op)] |
| 2 | #![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] | |
| 3 | 4 | |
| 4 | 5 | fn main() { |
| 5 | 6 | let mut a = 5; |
src/tools/clippy/tests/ui/misrefactored_assign_op.stderr+9-9| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: variable appears on both sides of an assignment operation |
| 2 | --> tests/ui/misrefactored_assign_op.rs:6:5 | |
| 2 | --> tests/ui/misrefactored_assign_op.rs:7:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | a += a + 1; |
| 5 | 5 | | ^^^^^^^^^^ |
| ... | ... | @@ -18,7 +18,7 @@ LL + a = a + a + 1; |
| 18 | 18 | | |
| 19 | 19 | |
| 20 | 20 | error: variable appears on both sides of an assignment operation |
| 21 | --> tests/ui/misrefactored_assign_op.rs:9:5 | |
| 21 | --> tests/ui/misrefactored_assign_op.rs:10:5 | |
| 22 | 22 | | |
| 23 | 23 | LL | a += 1 + a; |
| 24 | 24 | | ^^^^^^^^^^ |
| ... | ... | @@ -35,7 +35,7 @@ LL + a = a + 1 + a; |
| 35 | 35 | | |
| 36 | 36 | |
| 37 | 37 | error: variable appears on both sides of an assignment operation |
| 38 | --> tests/ui/misrefactored_assign_op.rs:12:5 | |
| 38 | --> tests/ui/misrefactored_assign_op.rs:13:5 | |
| 39 | 39 | | |
| 40 | 40 | LL | a -= a - 1; |
| 41 | 41 | | ^^^^^^^^^^ |
| ... | ... | @@ -52,7 +52,7 @@ LL + a = a - (a - 1); |
| 52 | 52 | | |
| 53 | 53 | |
| 54 | 54 | error: variable appears on both sides of an assignment operation |
| 55 | --> tests/ui/misrefactored_assign_op.rs:15:5 | |
| 55 | --> tests/ui/misrefactored_assign_op.rs:16:5 | |
| 56 | 56 | | |
| 57 | 57 | LL | a *= a * 99; |
| 58 | 58 | | ^^^^^^^^^^^ |
| ... | ... | @@ -69,7 +69,7 @@ LL + a = a * a * 99; |
| 69 | 69 | | |
| 70 | 70 | |
| 71 | 71 | error: variable appears on both sides of an assignment operation |
| 72 | --> tests/ui/misrefactored_assign_op.rs:18:5 | |
| 72 | --> tests/ui/misrefactored_assign_op.rs:19:5 | |
| 73 | 73 | | |
| 74 | 74 | LL | a *= 42 * a; |
| 75 | 75 | | ^^^^^^^^^^^ |
| ... | ... | @@ -86,7 +86,7 @@ LL + a = a * 42 * a; |
| 86 | 86 | | |
| 87 | 87 | |
| 88 | 88 | error: variable appears on both sides of an assignment operation |
| 89 | --> tests/ui/misrefactored_assign_op.rs:21:5 | |
| 89 | --> tests/ui/misrefactored_assign_op.rs:22:5 | |
| 90 | 90 | | |
| 91 | 91 | LL | a /= a / 2; |
| 92 | 92 | | ^^^^^^^^^^ |
| ... | ... | @@ -103,7 +103,7 @@ LL + a = a / (a / 2); |
| 103 | 103 | | |
| 104 | 104 | |
| 105 | 105 | error: variable appears on both sides of an assignment operation |
| 106 | --> tests/ui/misrefactored_assign_op.rs:24:5 | |
| 106 | --> tests/ui/misrefactored_assign_op.rs:25:5 | |
| 107 | 107 | | |
| 108 | 108 | LL | a %= a % 5; |
| 109 | 109 | | ^^^^^^^^^^ |
| ... | ... | @@ -120,7 +120,7 @@ LL + a = a % (a % 5); |
| 120 | 120 | | |
| 121 | 121 | |
| 122 | 122 | error: variable appears on both sides of an assignment operation |
| 123 | --> tests/ui/misrefactored_assign_op.rs:27:5 | |
| 123 | --> tests/ui/misrefactored_assign_op.rs:28:5 | |
| 124 | 124 | | |
| 125 | 125 | LL | a &= a & 1; |
| 126 | 126 | | ^^^^^^^^^^ |
| ... | ... | @@ -137,7 +137,7 @@ LL + a = a & a & 1; |
| 137 | 137 | | |
| 138 | 138 | |
| 139 | 139 | error: variable appears on both sides of an assignment operation |
| 140 | --> tests/ui/misrefactored_assign_op.rs:30:5 | |
| 140 | --> tests/ui/misrefactored_assign_op.rs:31:5 | |
| 141 | 141 | | |
| 142 | 142 | LL | a *= a * a; |
| 143 | 143 | | ^^^^^^^^^^ |
src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | #![allow(unused)] | |
| 2 | 1 | #![warn(clippy::missing_asserts_for_indexing)] |
| 3 | 2 | |
| 4 | 3 | fn sum(v: &[u8]) -> u8 { |
src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr+10-10| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: indexing into a slice multiple times without an `assert` |
| 2 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:5:5 | |
| 2 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:4:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | v[0] + v[1] + v[2] + v[3] + v[4] |
| 5 | 5 | | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ |
| ... | ... | @@ -10,7 +10,7 @@ LL | v[0] + v[1] + v[2] + v[3] + v[4] |
| 10 | 10 | = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]` |
| 11 | 11 | |
| 12 | 12 | error: indexing into a slice multiple times without an `assert` |
| 13 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:10:13 | |
| 13 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:9:13 | |
| 14 | 14 | | |
| 15 | 15 | LL | let _ = v[0]; |
| 16 | 16 | | ^^^^ |
| ... | ... | @@ -21,7 +21,7 @@ LL | let _ = v[1..4]; |
| 21 | 21 | = help: consider asserting the length before indexing: `assert!(v.len() > 3);` |
| 22 | 22 | |
| 23 | 23 | error: indexing into a slice multiple times without an `assert` |
| 24 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 | |
| 24 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:16:13 | |
| 25 | 25 | | |
| 26 | 26 | LL | let a = v[0]; |
| 27 | 27 | | ^^^^ |
| ... | ... | @@ -34,7 +34,7 @@ LL | let c = v[2]; |
| 34 | 34 | = help: consider asserting the length before indexing: `assert!(v.len() > 2);` |
| 35 | 35 | |
| 36 | 36 | error: indexing into a slice multiple times without an `assert` |
| 37 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 | |
| 37 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:25:13 | |
| 38 | 38 | | |
| 39 | 39 | LL | let _ = v1[0] + v1[12]; |
| 40 | 40 | | ^^^^^ ^^^^^^ |
| ... | ... | @@ -42,7 +42,7 @@ LL | let _ = v1[0] + v1[12]; |
| 42 | 42 | = help: consider asserting the length before indexing: `assert!(v1.len() > 12);` |
| 43 | 43 | |
| 44 | 44 | error: indexing into a slice multiple times without an `assert` |
| 45 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 | |
| 45 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:27:13 | |
| 46 | 46 | | |
| 47 | 47 | LL | let _ = v2[5] + v2[15]; |
| 48 | 48 | | ^^^^^ ^^^^^^ |
| ... | ... | @@ -50,7 +50,7 @@ LL | let _ = v2[5] + v2[15]; |
| 50 | 50 | = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` |
| 51 | 51 | |
| 52 | 52 | error: indexing into a slice multiple times without an `assert` |
| 53 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 | |
| 53 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:34:13 | |
| 54 | 54 | | |
| 55 | 55 | LL | let _ = v2[5] + v2[15]; |
| 56 | 56 | | ^^^^^ ^^^^^^ |
| ... | ... | @@ -58,7 +58,7 @@ LL | let _ = v2[5] + v2[15]; |
| 58 | 58 | = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` |
| 59 | 59 | |
| 60 | 60 | error: indexing into a slice multiple times without an `assert` |
| 61 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 | |
| 61 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:44:13 | |
| 62 | 62 | | |
| 63 | 63 | LL | let _ = f.v[0] + f.v[1]; |
| 64 | 64 | | ^^^^^^ ^^^^^^ |
| ... | ... | @@ -66,7 +66,7 @@ LL | let _ = f.v[0] + f.v[1]; |
| 66 | 66 | = help: consider asserting the length before indexing: `assert!(f.v.len() > 1);` |
| 67 | 67 | |
| 68 | 68 | error: indexing into a slice multiple times without an `assert` |
| 69 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 | |
| 69 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:58:13 | |
| 70 | 70 | | |
| 71 | 71 | LL | let _ = x[0] + x[1]; |
| 72 | 72 | | ^^^^ ^^^^ |
| ... | ... | @@ -74,7 +74,7 @@ LL | let _ = x[0] + x[1]; |
| 74 | 74 | = help: consider asserting the length before indexing: `assert!(x.len() > 1);` |
| 75 | 75 | |
| 76 | 76 | error: indexing into a slice multiple times without an `assert` |
| 77 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13 | |
| 77 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:76:13 | |
| 78 | 78 | | |
| 79 | 79 | LL | let _ = v1[1] + v1[2]; |
| 80 | 80 | | ^^^^^ ^^^^^ |
| ... | ... | @@ -82,7 +82,7 @@ LL | let _ = v1[1] + v1[2]; |
| 82 | 82 | = help: consider asserting the length before indexing: `assert!(v1.len() > 2);` |
| 83 | 83 | |
| 84 | 84 | error: indexing into a slice multiple times without an `assert` |
| 85 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13 | |
| 85 | --> tests/ui/missing_asserts_for_indexing_unfixable.rs:84:13 | |
| 86 | 86 | | |
| 87 | 87 | LL | let _ = v1[0] + v1[1] + v1[2]; |
| 88 | 88 | | ^^^^^ ^^^^^ ^^^^^ |
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | #![warn(clippy::missing_const_for_fn)] |
| 2 | #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] | |
| 2 | #![expect(clippy::let_and_return)] | |
| 3 | 3 | #![feature(const_trait_impl)] |
| 4 | 4 | |
| 5 | 5 | use std::mem::transmute; |
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | #![warn(clippy::missing_const_for_fn)] |
| 2 | #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] | |
| 2 | #![expect(clippy::let_and_return)] | |
| 3 | 3 | #![feature(const_trait_impl)] |
| 4 | 4 | |
| 5 | 5 | use std::mem::transmute; |
src/tools/clippy/tests/ui/missing_fields_in_debug.rs-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | #![allow(unused)] | |
| 2 | 1 | #![warn(clippy::missing_fields_in_debug)] |
| 3 | 2 | |
| 4 | 3 | use std::fmt; |
src/tools/clippy/tests/ui/missing_fields_in_debug.stderr+8-8| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: manual `Debug` impl does not include all fields |
| 2 | --> tests/ui/missing_fields_in_debug.rs:14:1 | |
| 2 | --> tests/ui/missing_fields_in_debug.rs:13:1 | |
| 3 | 3 | | |
| 4 | 4 | LL | / impl fmt::Debug for NamedStruct1Ignored { |
| 5 | 5 | ... | |
| ... | ... | @@ -7,7 +7,7 @@ LL | | } |
| 7 | 7 | | |_^ |
| 8 | 8 | | |
| 9 | 9 | note: this field is unused |
| 10 | --> tests/ui/missing_fields_in_debug.rs:11:5 | |
| 10 | --> tests/ui/missing_fields_in_debug.rs:10:5 | |
| 11 | 11 | | |
| 12 | 12 | LL | hidden: u32, |
| 13 | 13 | | ^^^^^^^^^^^ |
| ... | ... | @@ -17,7 +17,7 @@ LL | hidden: u32, |
| 17 | 17 | = help: to override `-D warnings` add `#[allow(clippy::missing_fields_in_debug)]` |
| 18 | 18 | |
| 19 | 19 | error: manual `Debug` impl does not include all fields |
| 20 | --> tests/ui/missing_fields_in_debug.rs:34:1 | |
| 20 | --> tests/ui/missing_fields_in_debug.rs:33:1 | |
| 21 | 21 | | |
| 22 | 22 | LL | / impl fmt::Debug for NamedStructMultipleIgnored { |
| 23 | 23 | ... | |
| ... | ... | @@ -25,17 +25,17 @@ LL | | } |
| 25 | 25 | | |_^ |
| 26 | 26 | | |
| 27 | 27 | note: this field is unused |
| 28 | --> tests/ui/missing_fields_in_debug.rs:28:5 | |
| 28 | --> tests/ui/missing_fields_in_debug.rs:27:5 | |
| 29 | 29 | | |
| 30 | 30 | LL | hidden: u32, |
| 31 | 31 | | ^^^^^^^^^^^ |
| 32 | 32 | note: this field is unused |
| 33 | --> tests/ui/missing_fields_in_debug.rs:29:5 | |
| 33 | --> tests/ui/missing_fields_in_debug.rs:28:5 | |
| 34 | 34 | | |
| 35 | 35 | LL | hidden2: String, |
| 36 | 36 | | ^^^^^^^^^^^^^^^ |
| 37 | 37 | note: this field is unused |
| 38 | --> tests/ui/missing_fields_in_debug.rs:31:5 | |
| 38 | --> tests/ui/missing_fields_in_debug.rs:30:5 | |
| 39 | 39 | | |
| 40 | 40 | LL | hidden4: ((((u8), u16), u32), u64), |
| 41 | 41 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -43,7 +43,7 @@ LL | hidden4: ((((u8), u16), u32), u64), |
| 43 | 43 | = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields |
| 44 | 44 | |
| 45 | 45 | error: manual `Debug` impl does not include all fields |
| 46 | --> tests/ui/missing_fields_in_debug.rs:97:1 | |
| 46 | --> tests/ui/missing_fields_in_debug.rs:96:1 | |
| 47 | 47 | | |
| 48 | 48 | LL | / impl fmt::Debug for MultiExprDebugImpl { |
| 49 | 49 | LL | | |
| ... | ... | @@ -54,7 +54,7 @@ LL | | } |
| 54 | 54 | | |_^ |
| 55 | 55 | | |
| 56 | 56 | note: this field is unused |
| 57 | --> tests/ui/missing_fields_in_debug.rs:93:5 | |
| 57 | --> tests/ui/missing_fields_in_debug.rs:92:5 | |
| 58 | 58 | | |
| 59 | 59 | LL | b: String, |
| 60 | 60 | | ^^^^^^^^^ |
src/tools/clippy/tests/ui/missing_inline.rs+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | #![crate_type = "dylib"] |
| 3 | 3 | // When denying at the crate level, be sure to not get random warnings from the |
| 4 | 4 | // injected intrinsics by the compiler. |
| 5 | #![allow(dead_code, non_snake_case)] | |
| 5 | #![expect(non_snake_case)] | |
| 6 | 6 | |
| 7 | 7 | type Typedef = String; |
| 8 | 8 | pub type PubTypedef = String; |
src/tools/clippy/tests/ui/missing_inline.stderr+6-6| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | error: missing `#[inline]` for a function | |
| 1 | error: missing `#[inline]` on a publicly callable function | |
| 2 | 2 | --> tests/ui/missing_inline.rs:20:1 |
| 3 | 3 | | |
| 4 | 4 | LL | pub fn pub_foo() {} |
| ... | ... | @@ -7,31 +7,31 @@ LL | pub fn pub_foo() {} |
| 7 | 7 | = note: `-D clippy::missing-inline-in-public-items` implied by `-D warnings` |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::missing_inline_in_public_items)]` |
| 9 | 9 | |
| 10 | error: missing `#[inline]` for a default trait method | |
| 10 | error: missing `#[inline]` on a publicly callable function | |
| 11 | 11 | --> tests/ui/missing_inline.rs:39:5 |
| 12 | 12 | | |
| 13 | 13 | LL | fn PubBar_b() {} |
| 14 | 14 | | ^^^^^^^^^^^^^^^^ |
| 15 | 15 | |
| 16 | error: missing `#[inline]` for a method | |
| 16 | error: missing `#[inline]` on a publicly callable function | |
| 17 | 17 | --> tests/ui/missing_inline.rs:56:5 |
| 18 | 18 | | |
| 19 | 19 | LL | fn PubBar_a() {} |
| 20 | 20 | | ^^^^^^^^^^^^^^^^ |
| 21 | 21 | |
| 22 | error: missing `#[inline]` for a method | |
| 22 | error: missing `#[inline]` on a publicly callable function | |
| 23 | 23 | --> tests/ui/missing_inline.rs:60:5 |
| 24 | 24 | | |
| 25 | 25 | LL | fn PubBar_b() {} |
| 26 | 26 | | ^^^^^^^^^^^^^^^^ |
| 27 | 27 | |
| 28 | error: missing `#[inline]` for a method | |
| 28 | error: missing `#[inline]` on a publicly callable function | |
| 29 | 29 | --> tests/ui/missing_inline.rs:64:5 |
| 30 | 30 | | |
| 31 | 31 | LL | fn PubBar_c() {} |
| 32 | 32 | | ^^^^^^^^^^^^^^^^ |
| 33 | 33 | |
| 34 | error: missing `#[inline]` for a method | |
| 34 | error: missing `#[inline]` on a publicly callable function | |
| 35 | 35 | --> tests/ui/missing_inline.rs:76:5 |
| 36 | 36 | | |
| 37 | 37 | LL | pub fn PubFooImpl() {} |
src/tools/clippy/tests/ui/missing_inline_executable.stderr+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | error: missing `#[inline]` for a function | |
| 1 | error: missing `#[inline]` on a publicly callable function | |
| 2 | 2 | --> tests/ui/missing_inline_executable.rs:3:1 |
| 3 | 3 | | |
| 4 | 4 | LL | pub fn foo() {} |
src/tools/clippy/tests/ui/missing_panics_doc.rs+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | //@aux-build:macro_rules.rs |
| 2 | 2 | #![warn(clippy::missing_panics_doc)] |
| 3 | #![allow(clippy::option_map_unit_fn, clippy::unnecessary_literal_unwrap)] | |
| 3 | #![expect(clippy::option_map_unit_fn, clippy::unnecessary_literal_unwrap)] | |
| 4 | 4 | |
| 5 | 5 | #[macro_use] |
| 6 | 6 | extern crate macro_rules; |
src/tools/clippy/tests/ui/missing_spin_loop.fixed+1-2| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | #![warn(clippy::missing_spin_loop)] |
| 2 | #![allow(clippy::bool_comparison)] | |
| 3 | #![allow(unused_braces)] | |
| 2 | #![expect(clippy::bool_comparison)] | |
| 4 | 3 | |
| 5 | 4 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 6 | 5 |
src/tools/clippy/tests/ui/missing_spin_loop.rs+1-2| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | #![warn(clippy::missing_spin_loop)] |
| 2 | #![allow(clippy::bool_comparison)] | |
| 3 | #![allow(unused_braces)] | |
| 2 | #![expect(clippy::bool_comparison)] | |
| 4 | 3 | |
| 5 | 4 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 6 | 5 |
src/tools/clippy/tests/ui/missing_spin_loop.stderr+6-6| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: busy-waiting loop should at least have a spin loop hint |
| 2 | --> tests/ui/missing_spin_loop.rs:10:37 | |
| 2 | --> tests/ui/missing_spin_loop.rs:9:37 | |
| 3 | 3 | | |
| 4 | 4 | LL | while b.load(Ordering::Acquire) {} |
| 5 | 5 | | ^^ help: try: `{ std::hint::spin_loop() }` |
| ... | ... | @@ -8,31 +8,31 @@ LL | while b.load(Ordering::Acquire) {} |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::missing_spin_loop)]` |
| 9 | 9 | |
| 10 | 10 | error: busy-waiting loop should at least have a spin loop hint |
| 11 | --> tests/ui/missing_spin_loop.rs:13:37 | |
| 11 | --> tests/ui/missing_spin_loop.rs:12:37 | |
| 12 | 12 | | |
| 13 | 13 | LL | while !b.load(Ordering::SeqCst) {} |
| 14 | 14 | | ^^ help: try: `{ std::hint::spin_loop() }` |
| 15 | 15 | |
| 16 | 16 | error: busy-waiting loop should at least have a spin loop hint |
| 17 | --> tests/ui/missing_spin_loop.rs:16:46 | |
| 17 | --> tests/ui/missing_spin_loop.rs:15:46 | |
| 18 | 18 | | |
| 19 | 19 | LL | while b.load(Ordering::Acquire) == false {} |
| 20 | 20 | | ^^ help: try: `{ std::hint::spin_loop() }` |
| 21 | 21 | |
| 22 | 22 | error: busy-waiting loop should at least have a spin loop hint |
| 23 | --> tests/ui/missing_spin_loop.rs:19:49 | |
| 23 | --> tests/ui/missing_spin_loop.rs:18:49 | |
| 24 | 24 | | |
| 25 | 25 | LL | while { true == b.load(Ordering::Acquire) } {} |
| 26 | 26 | | ^^ help: try: `{ std::hint::spin_loop() }` |
| 27 | 27 | |
| 28 | 28 | error: busy-waiting loop should at least have a spin loop hint |
| 29 | --> tests/ui/missing_spin_loop.rs:22:93 | |
| 29 | --> tests/ui/missing_spin_loop.rs:21:93 | |
| 30 | 30 | | |
| 31 | 31 | LL | while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) {} |
| 32 | 32 | | ^^ help: try: `{ std::hint::spin_loop() }` |
| 33 | 33 | |
| 34 | 34 | error: busy-waiting loop should at least have a spin loop hint |
| 35 | --> tests/ui/missing_spin_loop.rs:25:94 | |
| 35 | --> tests/ui/missing_spin_loop.rs:24:94 | |
| 36 | 36 | | |
| 37 | 37 | LL | while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {} |
| 38 | 38 | | ^^ help: try: `{ std::hint::spin_loop() }` |
src/tools/clippy/tests/ui/missing_trait_methods.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | #![allow(unused, clippy::needless_lifetimes)] | |
| 2 | 1 | #![warn(clippy::missing_trait_methods)] |
| 2 | #![expect(clippy::needless_lifetimes)] | |
| 3 | 3 | |
| 4 | 4 | trait A { |
| 5 | 5 | fn provided() {} |
src/tools/clippy/tests/ui/missing_transmute_annotations.fixed+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | //@aux-build:macro_rules.rs |
| 2 | 2 | |
| 3 | 3 | #![warn(clippy::missing_transmute_annotations)] |
| 4 | #![allow(clippy::let_with_type_underscore)] | |
| 4 | #![expect(clippy::let_with_type_underscore)] | |
| 5 | 5 | |
| 6 | 6 | #[macro_use] |
| 7 | 7 | extern crate macro_rules; |
src/tools/clippy/tests/ui/missing_transmute_annotations.rs+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | //@aux-build:macro_rules.rs |
| 2 | 2 | |
| 3 | 3 | #![warn(clippy::missing_transmute_annotations)] |
| 4 | #![allow(clippy::let_with_type_underscore)] | |
| 4 | #![expect(clippy::let_with_type_underscore)] | |
| 5 | 5 | |
| 6 | 6 | #[macro_use] |
| 7 | 7 | extern crate macro_rules; |
src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed+2-4| ... | ... | @@ -1,10 +1,8 @@ |
| 1 | 1 | //@aux-build: proc_macros.rs |
| 2 | 2 | |
| 3 | #![allow( | |
| 4 | dead_code, | |
| 5 | unused_variables, | |
| 3 | #![warn(clippy::mistyped_literal_suffixes)] | |
| 4 | #![expect( | |
| 6 | 5 | overflowing_literals, |
| 7 | clippy::excessive_precision, | |
| 8 | 6 | clippy::inconsistent_digit_grouping, |
| 9 | 7 | clippy::unusual_byte_groupings |
| 10 | 8 | )] |
src/tools/clippy/tests/ui/mistyped_literal_suffix.rs+2-4| ... | ... | @@ -1,10 +1,8 @@ |
| 1 | 1 | //@aux-build: proc_macros.rs |
| 2 | 2 | |
| 3 | #![allow( | |
| 4 | dead_code, | |
| 5 | unused_variables, | |
| 3 | #![warn(clippy::mistyped_literal_suffixes)] | |
| 4 | #![expect( | |
| 6 | 5 | overflowing_literals, |
| 7 | clippy::excessive_precision, | |
| 8 | 6 | clippy::inconsistent_digit_grouping, |
| 9 | 7 | clippy::unusual_byte_groupings |
| 10 | 8 | )] |
src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr+18-17| ... | ... | @@ -1,97 +1,98 @@ |
| 1 | 1 | error: mistyped literal suffix |
| 2 | --> tests/ui/mistyped_literal_suffix.rs:16:18 | |
| 2 | --> tests/ui/mistyped_literal_suffix.rs:14:18 | |
| 3 | 3 | | |
| 4 | 4 | LL | let fail14 = 2_32; |
| 5 | 5 | | ^^^^ help: did you mean to write: `2_i32` |
| 6 | 6 | | |
| 7 | = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default | |
| 7 | = note: `-D clippy::mistyped-literal-suffixes` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::mistyped_literal_suffixes)]` | |
| 8 | 9 | |
| 9 | 10 | error: mistyped literal suffix |
| 10 | --> tests/ui/mistyped_literal_suffix.rs:18:18 | |
| 11 | --> tests/ui/mistyped_literal_suffix.rs:16:18 | |
| 11 | 12 | | |
| 12 | 13 | LL | let fail15 = 4_64; |
| 13 | 14 | | ^^^^ help: did you mean to write: `4_i64` |
| 14 | 15 | |
| 15 | 16 | error: mistyped literal suffix |
| 16 | --> tests/ui/mistyped_literal_suffix.rs:20:18 | |
| 17 | --> tests/ui/mistyped_literal_suffix.rs:18:18 | |
| 17 | 18 | | |
| 18 | 19 | LL | let fail16 = 7_8; // |
| 19 | 20 | | ^^^ help: did you mean to write: `7_i8` |
| 20 | 21 | |
| 21 | 22 | error: mistyped literal suffix |
| 22 | --> tests/ui/mistyped_literal_suffix.rs:23:18 | |
| 23 | --> tests/ui/mistyped_literal_suffix.rs:21:18 | |
| 23 | 24 | | |
| 24 | 25 | LL | let fail17 = 23_16; // |
| 25 | 26 | | ^^^^^ help: did you mean to write: `23_i16` |
| 26 | 27 | |
| 27 | 28 | error: mistyped literal suffix |
| 28 | --> tests/ui/mistyped_literal_suffix.rs:28:18 | |
| 29 | --> tests/ui/mistyped_literal_suffix.rs:26:18 | |
| 29 | 30 | | |
| 30 | 31 | LL | let fail20 = 2__8; // |
| 31 | 32 | | ^^^^ help: did you mean to write: `2_i8` |
| 32 | 33 | |
| 33 | 34 | error: mistyped literal suffix |
| 34 | --> tests/ui/mistyped_literal_suffix.rs:31:18 | |
| 35 | --> tests/ui/mistyped_literal_suffix.rs:29:18 | |
| 35 | 36 | | |
| 36 | 37 | LL | let fail21 = 4___16; // |
| 37 | 38 | | ^^^^^^ help: did you mean to write: `4_i16` |
| 38 | 39 | |
| 39 | 40 | error: mistyped literal suffix |
| 40 | --> tests/ui/mistyped_literal_suffix.rs:36:18 | |
| 41 | --> tests/ui/mistyped_literal_suffix.rs:34:18 | |
| 41 | 42 | | |
| 42 | 43 | LL | let fail25 = 1E2_32; |
| 43 | 44 | | ^^^^^^ help: did you mean to write: `1E2_f32` |
| 44 | 45 | |
| 45 | 46 | error: mistyped literal suffix |
| 46 | --> tests/ui/mistyped_literal_suffix.rs:38:18 | |
| 47 | --> tests/ui/mistyped_literal_suffix.rs:36:18 | |
| 47 | 48 | | |
| 48 | 49 | LL | let fail26 = 43E7_64; |
| 49 | 50 | | ^^^^^^^ help: did you mean to write: `43E7_f64` |
| 50 | 51 | |
| 51 | 52 | error: mistyped literal suffix |
| 52 | --> tests/ui/mistyped_literal_suffix.rs:40:18 | |
| 53 | --> tests/ui/mistyped_literal_suffix.rs:38:18 | |
| 53 | 54 | | |
| 54 | 55 | LL | let fail27 = 243E17_32; |
| 55 | 56 | | ^^^^^^^^^ help: did you mean to write: `243E17_f32` |
| 56 | 57 | |
| 57 | 58 | error: mistyped literal suffix |
| 58 | --> tests/ui/mistyped_literal_suffix.rs:42:18 | |
| 59 | --> tests/ui/mistyped_literal_suffix.rs:40:18 | |
| 59 | 60 | | |
| 60 | 61 | LL | let fail28 = 241251235E723_64; |
| 61 | 62 | | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64` |
| 62 | 63 | |
| 63 | 64 | error: mistyped literal suffix |
| 64 | --> tests/ui/mistyped_literal_suffix.rs:47:18 | |
| 65 | --> tests/ui/mistyped_literal_suffix.rs:45:18 | |
| 65 | 66 | | |
| 66 | 67 | LL | let fail30 = 127_8; // should be i8 |
| 67 | 68 | | ^^^^^ help: did you mean to write: `127_i8` |
| 68 | 69 | |
| 69 | 70 | error: mistyped literal suffix |
| 70 | --> tests/ui/mistyped_literal_suffix.rs:50:18 | |
| 71 | --> tests/ui/mistyped_literal_suffix.rs:48:18 | |
| 71 | 72 | | |
| 72 | 73 | LL | let fail31 = 240_8; // should be u8 |
| 73 | 74 | | ^^^^^ help: did you mean to write: `240_u8` |
| 74 | 75 | |
| 75 | 76 | error: mistyped literal suffix |
| 76 | --> tests/ui/mistyped_literal_suffix.rs:54:18 | |
| 77 | --> tests/ui/mistyped_literal_suffix.rs:52:18 | |
| 77 | 78 | | |
| 78 | 79 | LL | let fail33 = 0x1234_16; |
| 79 | 80 | | ^^^^^^^^^ help: did you mean to write: `0x1234_i16` |
| 80 | 81 | |
| 81 | 82 | error: mistyped literal suffix |
| 82 | --> tests/ui/mistyped_literal_suffix.rs:56:18 | |
| 83 | --> tests/ui/mistyped_literal_suffix.rs:54:18 | |
| 83 | 84 | | |
| 84 | 85 | LL | let fail34 = 0xABCD_16; |
| 85 | 86 | | ^^^^^^^^^ help: did you mean to write: `0xABCD_u16` |
| 86 | 87 | |
| 87 | 88 | error: mistyped literal suffix |
| 88 | --> tests/ui/mistyped_literal_suffix.rs:59:18 | |
| 89 | --> tests/ui/mistyped_literal_suffix.rs:57:18 | |
| 89 | 90 | | |
| 90 | 91 | LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64 |
| 91 | 92 | | ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64` |
| 92 | 93 | |
| 93 | 94 | error: mistyped literal suffix |
| 94 | --> tests/ui/mistyped_literal_suffix.rs:67:13 | |
| 95 | --> tests/ui/mistyped_literal_suffix.rs:65:13 | |
| 95 | 96 | | |
| 96 | 97 | LL | let _ = 1.12345E1_32; |
| 97 | 98 | | ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32` |
src/tools/clippy/tests/ui/module_name_repetitions.rs-1| ... | ... | @@ -1,7 +1,6 @@ |
| 1 | 1 | //@compile-flags: --test |
| 2 | 2 | |
| 3 | 3 | #![warn(clippy::module_name_repetitions)] |
| 4 | #![allow(dead_code)] | |
| 5 | 4 | |
| 6 | 5 | pub mod foo { |
| 7 | 6 | pub fn foo() {} |
src/tools/clippy/tests/ui/module_name_repetitions.stderr+6-6| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: item name starts with its containing module's name |
| 2 | --> tests/ui/module_name_repetitions.rs:8:12 | |
| 2 | --> tests/ui/module_name_repetitions.rs:7:12 | |
| 3 | 3 | | |
| 4 | 4 | LL | pub fn foo_bar() {} |
| 5 | 5 | | ^^^^^^^ |
| ... | ... | @@ -8,31 +8,31 @@ LL | pub fn foo_bar() {} |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]` |
| 9 | 9 | |
| 10 | 10 | error: item name ends with its containing module's name |
| 11 | --> tests/ui/module_name_repetitions.rs:11:12 | |
| 11 | --> tests/ui/module_name_repetitions.rs:10:12 | |
| 12 | 12 | | |
| 13 | 13 | LL | pub fn bar_foo() {} |
| 14 | 14 | | ^^^^^^^ |
| 15 | 15 | |
| 16 | 16 | error: item name starts with its containing module's name |
| 17 | --> tests/ui/module_name_repetitions.rs:14:16 | |
| 17 | --> tests/ui/module_name_repetitions.rs:13:16 | |
| 18 | 18 | | |
| 19 | 19 | LL | pub struct FooCake; |
| 20 | 20 | | ^^^^^^^ |
| 21 | 21 | |
| 22 | 22 | error: item name ends with its containing module's name |
| 23 | --> tests/ui/module_name_repetitions.rs:17:14 | |
| 23 | --> tests/ui/module_name_repetitions.rs:16:14 | |
| 24 | 24 | | |
| 25 | 25 | LL | pub enum CakeFoo {} |
| 26 | 26 | | ^^^^^^^ |
| 27 | 27 | |
| 28 | 28 | error: item name starts with its containing module's name |
| 29 | --> tests/ui/module_name_repetitions.rs:20:16 | |
| 29 | --> tests/ui/module_name_repetitions.rs:19:16 | |
| 30 | 30 | | |
| 31 | 31 | LL | pub struct Foo7Bar; |
| 32 | 32 | | ^^^^^^^ |
| 33 | 33 | |
| 34 | 34 | error: item name starts with its containing module's name |
| 35 | --> tests/ui/module_name_repetitions.rs:33:20 | |
| 35 | --> tests/ui/module_name_repetitions.rs:32:20 | |
| 36 | 36 | | |
| 37 | 37 | LL | pub use error::FooError; |
| 38 | 38 | | ^^^^^^^^ |
src/tools/clippy/tests/ui/modulo_arithmetic_float.rs+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | #![feature(f128)] |
| 2 | 2 | #![feature(f16)] |
| 3 | 3 | #![warn(clippy::modulo_arithmetic)] |
| 4 | #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] | |
| 4 | #![expect(clippy::no_effect)] | |
| 5 | 5 | |
| 6 | 6 | fn main() { |
| 7 | 7 | // Lint when both sides are const and of the opposite sign |
src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | #![warn(clippy::modulo_arithmetic)] |
| 2 | #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] | |
| 2 | #![expect(clippy::no_effect)] | |
| 3 | 3 | |
| 4 | 4 | fn main() { |
| 5 | 5 | // Lint on signed integral numbers |
src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs+1-6| ... | ... | @@ -1,10 +1,5 @@ |
| 1 | 1 | #![warn(clippy::modulo_arithmetic)] |
| 2 | #![allow( | |
| 3 | clippy::no_effect, | |
| 4 | clippy::unnecessary_operation, | |
| 5 | clippy::modulo_one, | |
| 6 | clippy::identity_op | |
| 7 | )] | |
| 2 | #![expect(clippy::identity_op, clippy::modulo_one, clippy::no_effect)] | |
| 8 | 3 | |
| 9 | 4 | fn main() { |
| 10 | 5 | // Lint when both sides are const and of the opposite sign |
src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr+17-17| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: you are using modulo operator on constants with different signs: `-1 % 2` |
| 2 | --> tests/ui/modulo_arithmetic_integral_const.rs:11:5 | |
| 2 | --> tests/ui/modulo_arithmetic_integral_const.rs:6:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | -1 % 2; |
| 5 | 5 | | ^^^^^^ |
| ... | ... | @@ -10,7 +10,7 @@ LL | -1 % 2; |
| 10 | 10 | = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]` |
| 11 | 11 | |
| 12 | 12 | error: you are using modulo operator on constants with different signs: `1 % -2` |
| 13 | --> tests/ui/modulo_arithmetic_integral_const.rs:14:5 | |
| 13 | --> tests/ui/modulo_arithmetic_integral_const.rs:9:5 | |
| 14 | 14 | | |
| 15 | 15 | LL | 1 % -2; |
| 16 | 16 | | ^^^^^^ |
| ... | ... | @@ -19,7 +19,7 @@ LL | 1 % -2; |
| 19 | 19 | = note: or consider using `rem_euclid` or similar function |
| 20 | 20 | |
| 21 | 21 | error: you are using modulo operator on constants with different signs: `-1 % 3` |
| 22 | --> tests/ui/modulo_arithmetic_integral_const.rs:17:5 | |
| 22 | --> tests/ui/modulo_arithmetic_integral_const.rs:12:5 | |
| 23 | 23 | | |
| 24 | 24 | LL | (1 - 2) % (1 + 2); |
| 25 | 25 | | ^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -28,7 +28,7 @@ LL | (1 - 2) % (1 + 2); |
| 28 | 28 | = note: or consider using `rem_euclid` or similar function |
| 29 | 29 | |
| 30 | 30 | error: you are using modulo operator on constants with different signs: `3 % -1` |
| 31 | --> tests/ui/modulo_arithmetic_integral_const.rs:20:5 | |
| 31 | --> tests/ui/modulo_arithmetic_integral_const.rs:15:5 | |
| 32 | 32 | | |
| 33 | 33 | LL | (1 + 2) % (1 - 2); |
| 34 | 34 | | ^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -37,7 +37,7 @@ LL | (1 + 2) % (1 - 2); |
| 37 | 37 | = note: or consider using `rem_euclid` or similar function |
| 38 | 38 | |
| 39 | 39 | error: you are using modulo operator on constants with different signs: `-35 % 300000` |
| 40 | --> tests/ui/modulo_arithmetic_integral_const.rs:23:5 | |
| 40 | --> tests/ui/modulo_arithmetic_integral_const.rs:18:5 | |
| 41 | 41 | | |
| 42 | 42 | LL | 35 * (7 - 4 * 2) % (-500 * -600); |
| 43 | 43 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -46,7 +46,7 @@ LL | 35 * (7 - 4 * 2) % (-500 * -600); |
| 46 | 46 | = note: or consider using `rem_euclid` or similar function |
| 47 | 47 | |
| 48 | 48 | error: you are using modulo operator on constants with different signs: `-1 % 2` |
| 49 | --> tests/ui/modulo_arithmetic_integral_const.rs:26:5 | |
| 49 | --> tests/ui/modulo_arithmetic_integral_const.rs:21:5 | |
| 50 | 50 | | |
| 51 | 51 | LL | -1i8 % 2i8; |
| 52 | 52 | | ^^^^^^^^^^ |
| ... | ... | @@ -55,7 +55,7 @@ LL | -1i8 % 2i8; |
| 55 | 55 | = note: or consider using `rem_euclid` or similar function |
| 56 | 56 | |
| 57 | 57 | error: you are using modulo operator on constants with different signs: `1 % -2` |
| 58 | --> tests/ui/modulo_arithmetic_integral_const.rs:29:5 | |
| 58 | --> tests/ui/modulo_arithmetic_integral_const.rs:24:5 | |
| 59 | 59 | | |
| 60 | 60 | LL | 1i8 % -2i8; |
| 61 | 61 | | ^^^^^^^^^^ |
| ... | ... | @@ -64,7 +64,7 @@ LL | 1i8 % -2i8; |
| 64 | 64 | = note: or consider using `rem_euclid` or similar function |
| 65 | 65 | |
| 66 | 66 | error: you are using modulo operator on constants with different signs: `-1 % 2` |
| 67 | --> tests/ui/modulo_arithmetic_integral_const.rs:32:5 | |
| 67 | --> tests/ui/modulo_arithmetic_integral_const.rs:27:5 | |
| 68 | 68 | | |
| 69 | 69 | LL | -1i16 % 2i16; |
| 70 | 70 | | ^^^^^^^^^^^^ |
| ... | ... | @@ -73,7 +73,7 @@ LL | -1i16 % 2i16; |
| 73 | 73 | = note: or consider using `rem_euclid` or similar function |
| 74 | 74 | |
| 75 | 75 | error: you are using modulo operator on constants with different signs: `1 % -2` |
| 76 | --> tests/ui/modulo_arithmetic_integral_const.rs:35:5 | |
| 76 | --> tests/ui/modulo_arithmetic_integral_const.rs:30:5 | |
| 77 | 77 | | |
| 78 | 78 | LL | 1i16 % -2i16; |
| 79 | 79 | | ^^^^^^^^^^^^ |
| ... | ... | @@ -82,7 +82,7 @@ LL | 1i16 % -2i16; |
| 82 | 82 | = note: or consider using `rem_euclid` or similar function |
| 83 | 83 | |
| 84 | 84 | error: you are using modulo operator on constants with different signs: `-1 % 2` |
| 85 | --> tests/ui/modulo_arithmetic_integral_const.rs:38:5 | |
| 85 | --> tests/ui/modulo_arithmetic_integral_const.rs:33:5 | |
| 86 | 86 | | |
| 87 | 87 | LL | -1i32 % 2i32; |
| 88 | 88 | | ^^^^^^^^^^^^ |
| ... | ... | @@ -91,7 +91,7 @@ LL | -1i32 % 2i32; |
| 91 | 91 | = note: or consider using `rem_euclid` or similar function |
| 92 | 92 | |
| 93 | 93 | error: you are using modulo operator on constants with different signs: `1 % -2` |
| 94 | --> tests/ui/modulo_arithmetic_integral_const.rs:41:5 | |
| 94 | --> tests/ui/modulo_arithmetic_integral_const.rs:36:5 | |
| 95 | 95 | | |
| 96 | 96 | LL | 1i32 % -2i32; |
| 97 | 97 | | ^^^^^^^^^^^^ |
| ... | ... | @@ -100,7 +100,7 @@ LL | 1i32 % -2i32; |
| 100 | 100 | = note: or consider using `rem_euclid` or similar function |
| 101 | 101 | |
| 102 | 102 | error: you are using modulo operator on constants with different signs: `-1 % 2` |
| 103 | --> tests/ui/modulo_arithmetic_integral_const.rs:44:5 | |
| 103 | --> tests/ui/modulo_arithmetic_integral_const.rs:39:5 | |
| 104 | 104 | | |
| 105 | 105 | LL | -1i64 % 2i64; |
| 106 | 106 | | ^^^^^^^^^^^^ |
| ... | ... | @@ -109,7 +109,7 @@ LL | -1i64 % 2i64; |
| 109 | 109 | = note: or consider using `rem_euclid` or similar function |
| 110 | 110 | |
| 111 | 111 | error: you are using modulo operator on constants with different signs: `1 % -2` |
| 112 | --> tests/ui/modulo_arithmetic_integral_const.rs:47:5 | |
| 112 | --> tests/ui/modulo_arithmetic_integral_const.rs:42:5 | |
| 113 | 113 | | |
| 114 | 114 | LL | 1i64 % -2i64; |
| 115 | 115 | | ^^^^^^^^^^^^ |
| ... | ... | @@ -118,7 +118,7 @@ LL | 1i64 % -2i64; |
| 118 | 118 | = note: or consider using `rem_euclid` or similar function |
| 119 | 119 | |
| 120 | 120 | error: you are using modulo operator on constants with different signs: `-1 % 2` |
| 121 | --> tests/ui/modulo_arithmetic_integral_const.rs:50:5 | |
| 121 | --> tests/ui/modulo_arithmetic_integral_const.rs:45:5 | |
| 122 | 122 | | |
| 123 | 123 | LL | -1i128 % 2i128; |
| 124 | 124 | | ^^^^^^^^^^^^^^ |
| ... | ... | @@ -127,7 +127,7 @@ LL | -1i128 % 2i128; |
| 127 | 127 | = note: or consider using `rem_euclid` or similar function |
| 128 | 128 | |
| 129 | 129 | error: you are using modulo operator on constants with different signs: `1 % -2` |
| 130 | --> tests/ui/modulo_arithmetic_integral_const.rs:53:5 | |
| 130 | --> tests/ui/modulo_arithmetic_integral_const.rs:48:5 | |
| 131 | 131 | | |
| 132 | 132 | LL | 1i128 % -2i128; |
| 133 | 133 | | ^^^^^^^^^^^^^^ |
| ... | ... | @@ -136,7 +136,7 @@ LL | 1i128 % -2i128; |
| 136 | 136 | = note: or consider using `rem_euclid` or similar function |
| 137 | 137 | |
| 138 | 138 | error: you are using modulo operator on constants with different signs: `-1 % 2` |
| 139 | --> tests/ui/modulo_arithmetic_integral_const.rs:56:5 | |
| 139 | --> tests/ui/modulo_arithmetic_integral_const.rs:51:5 | |
| 140 | 140 | | |
| 141 | 141 | LL | -1isize % 2isize; |
| 142 | 142 | | ^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -145,7 +145,7 @@ LL | -1isize % 2isize; |
| 145 | 145 | = note: or consider using `rem_euclid` or similar function |
| 146 | 146 | |
| 147 | 147 | error: you are using modulo operator on constants with different signs: `1 % -2` |
| 148 | --> tests/ui/modulo_arithmetic_integral_const.rs:59:5 | |
| 148 | --> tests/ui/modulo_arithmetic_integral_const.rs:54:5 | |
| 149 | 149 | | |
| 150 | 150 | LL | 1isize % -2isize; |
| 151 | 151 | | ^^^^^^^^^^^^^^^^ |
src/tools/clippy/tests/ui/modulo_one.rs+1-2| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | #![warn(clippy::modulo_one)] |
| 2 | #![allow(unconditional_panic)] | |
| 3 | #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::identity_op)] | |
| 2 | #![expect(clippy::identity_op, clippy::no_effect)] | |
| 4 | 3 | |
| 5 | 4 | static STATIC_ONE: usize = 2 - 1; |
| 6 | 5 | static STATIC_NEG_ONE: i64 = 1 - 2; |
src/tools/clippy/tests/ui/modulo_one.stderr+6-6| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: any number modulo 1 will be 0 |
| 2 | --> tests/ui/modulo_one.rs:9:5 | |
| 2 | --> tests/ui/modulo_one.rs:8:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | 10 % 1; |
| 5 | 5 | | ^^^^^^ |
| ... | ... | @@ -8,31 +8,31 @@ LL | 10 % 1; |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::modulo_one)]` |
| 9 | 9 | |
| 10 | 10 | error: any number modulo -1 will panic/overflow or result in 0 |
| 11 | --> tests/ui/modulo_one.rs:12:5 | |
| 11 | --> tests/ui/modulo_one.rs:11:5 | |
| 12 | 12 | | |
| 13 | 13 | LL | 10 % -1; |
| 14 | 14 | | ^^^^^^^ |
| 15 | 15 | |
| 16 | 16 | error: any number modulo -1 will panic/overflow or result in 0 |
| 17 | --> tests/ui/modulo_one.rs:17:5 | |
| 17 | --> tests/ui/modulo_one.rs:16:5 | |
| 18 | 18 | | |
| 19 | 19 | LL | i32::MIN % (-1); |
| 20 | 20 | | ^^^^^^^^^^^^^^^ |
| 21 | 21 | |
| 22 | 22 | error: any number modulo 1 will be 0 |
| 23 | --> tests/ui/modulo_one.rs:24:5 | |
| 23 | --> tests/ui/modulo_one.rs:23:5 | |
| 24 | 24 | | |
| 25 | 25 | LL | 2 % ONE; |
| 26 | 26 | | ^^^^^^^ |
| 27 | 27 | |
| 28 | 28 | error: any number modulo -1 will panic/overflow or result in 0 |
| 29 | --> tests/ui/modulo_one.rs:29:5 | |
| 29 | --> tests/ui/modulo_one.rs:28:5 | |
| 30 | 30 | | |
| 31 | 31 | LL | 2 % NEG_ONE; |
| 32 | 32 | | ^^^^^^^^^^^ |
| 33 | 33 | |
| 34 | 34 | error: any number modulo -1 will panic/overflow or result in 0 |
| 35 | --> tests/ui/modulo_one.rs:35:5 | |
| 35 | --> tests/ui/modulo_one.rs:34:5 | |
| 36 | 36 | | |
| 37 | 37 | LL | INT_MIN % NEG_ONE; |
| 38 | 38 | | ^^^^^^^^^^^^^^^^^ |
src/tools/clippy/tests/ui/msrv_attributes_without_early_lints.rs-1| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | //@check-pass |
| 2 | 2 | |
| 3 | #![allow(clippy::all, clippy::pedantic, clippy::restriction, clippy::nursery)] | |
| 4 | 3 | #![forbid(clippy::ptr_as_ptr)] |
| 5 | 4 | |
| 6 | 5 | /// MSRV checking in late passes skips checking the parent nodes if no early pass sees a |
src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs+3-3| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | //@needs-asm-support |
| 2 | 2 | //@aux-build:proc_macros.rs |
| 3 | #![warn(clippy::multiple_unsafe_ops_per_block)] | |
| 3 | 4 | #![expect( |
| 4 | 5 | dropping_copy_types, |
| 5 | clippy::unnecessary_operation, | |
| 6 | clippy::unnecessary_literal_unwrap | |
| 6 | clippy::unnecessary_literal_unwrap, | |
| 7 | clippy::unnecessary_operation | |
| 7 | 8 | )] |
| 8 | #![warn(clippy::multiple_unsafe_ops_per_block)] | |
| 9 | 9 | |
| 10 | 10 | extern crate proc_macros; |
| 11 | 11 | use proc_macros::external; |
src/tools/clippy/tests/ui/must_use_candidates.fixed-6| ... | ... | @@ -1,10 +1,4 @@ |
| 1 | 1 | #![feature(never_type)] |
| 2 | #![allow( | |
| 3 | unused_mut, | |
| 4 | clippy::redundant_allocation, | |
| 5 | clippy::needless_pass_by_ref_mut, | |
| 6 | static_mut_refs | |
| 7 | )] | |
| 8 | 2 | #![warn(clippy::must_use_candidate)] |
| 9 | 3 | use std::rc::Rc; |
| 10 | 4 | use std::sync::Arc; |
src/tools/clippy/tests/ui/must_use_candidates.rs-6| ... | ... | @@ -1,10 +1,4 @@ |
| 1 | 1 | #![feature(never_type)] |
| 2 | #![allow( | |
| 3 | unused_mut, | |
| 4 | clippy::redundant_allocation, | |
| 5 | clippy::needless_pass_by_ref_mut, | |
| 6 | static_mut_refs | |
| 7 | )] | |
| 8 | 2 | #![warn(clippy::must_use_candidate)] |
| 9 | 3 | use std::rc::Rc; |
| 10 | 4 | use std::sync::Arc; |
src/tools/clippy/tests/ui/must_use_candidates.stderr+7-7| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: this function could have a `#[must_use]` attribute |
| 2 | --> tests/ui/must_use_candidates.rs:16:8 | |
| 2 | --> tests/ui/must_use_candidates.rs:10:8 | |
| 3 | 3 | | |
| 4 | 4 | LL | pub fn pure(i: u8) -> u8 { |
| 5 | 5 | | ^^^^ |
| ... | ... | @@ -13,7 +13,7 @@ LL | pub fn pure(i: u8) -> u8 { |
| 13 | 13 | | |
| 14 | 14 | |
| 15 | 15 | error: this method could have a `#[must_use]` attribute |
| 16 | --> tests/ui/must_use_candidates.rs:22:12 | |
| 16 | --> tests/ui/must_use_candidates.rs:16:12 | |
| 17 | 17 | | |
| 18 | 18 | LL | pub fn inherent_pure(&self) -> u8 { |
| 19 | 19 | | ^^^^^^^^^^^^^ |
| ... | ... | @@ -25,7 +25,7 @@ LL ~ pub fn inherent_pure(&self) -> u8 { |
| 25 | 25 | | |
| 26 | 26 | |
| 27 | 27 | error: this function could have a `#[must_use]` attribute |
| 28 | --> tests/ui/must_use_candidates.rs:54:8 | |
| 28 | --> tests/ui/must_use_candidates.rs:48:8 | |
| 29 | 29 | | |
| 30 | 30 | LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { |
| 31 | 31 | | ^^^^^^^^^^^ |
| ... | ... | @@ -37,7 +37,7 @@ LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { |
| 37 | 37 | | |
| 38 | 38 | |
| 39 | 39 | error: this function could have a `#[must_use]` attribute |
| 40 | --> tests/ui/must_use_candidates.rs:67:8 | |
| 40 | --> tests/ui/must_use_candidates.rs:61:8 | |
| 41 | 41 | | |
| 42 | 42 | LL | pub fn rcd(_x: Rc<u32>) -> bool { |
| 43 | 43 | | ^^^ |
| ... | ... | @@ -49,7 +49,7 @@ LL | pub fn rcd(_x: Rc<u32>) -> bool { |
| 49 | 49 | | |
| 50 | 50 | |
| 51 | 51 | error: this function could have a `#[must_use]` attribute |
| 52 | --> tests/ui/must_use_candidates.rs:76:8 | |
| 52 | --> tests/ui/must_use_candidates.rs:70:8 | |
| 53 | 53 | | |
| 54 | 54 | LL | pub fn arcd(_x: Arc<u32>) -> bool { |
| 55 | 55 | | ^^^^ |
| ... | ... | @@ -61,7 +61,7 @@ LL | pub fn arcd(_x: Arc<u32>) -> bool { |
| 61 | 61 | | |
| 62 | 62 | |
| 63 | 63 | error: this function could have a `#[must_use]` attribute |
| 64 | --> tests/ui/must_use_candidates.rs:108:8 | |
| 64 | --> tests/ui/must_use_candidates.rs:102:8 | |
| 65 | 65 | | |
| 66 | 66 | LL | pub fn result_uninhabited() -> Result<i32, std::convert::Infallible> { |
| 67 | 67 | | ^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -74,7 +74,7 @@ LL | pub fn result_uninhabited() -> Result<i32, std::convert::Infallible> { |
| 74 | 74 | | |
| 75 | 75 | |
| 76 | 76 | error: this function could have a `#[must_use]` attribute |
| 77 | --> tests/ui/must_use_candidates.rs:113:8 | |
| 77 | --> tests/ui/must_use_candidates.rs:107:8 | |
| 78 | 78 | | |
| 79 | 79 | LL | pub fn controlflow_uninhabited() -> std::ops::ControlFlow<std::convert::Infallible, i32> { |
| 80 | 80 | | ^^^^^^^^^^^^^^^^^^^^^^^ |
src/tools/clippy/tests/ui/must_use_unit.fixed+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | //@aux-build:proc_macros.rs |
| 2 | 2 | |
| 3 | 3 | #![warn(clippy::must_use_unit)] |
| 4 | #![allow(clippy::unused_unit)] | |
| 4 | #![expect(clippy::unused_unit)] | |
| 5 | 5 | |
| 6 | 6 | extern crate proc_macros; |
| 7 | 7 | use proc_macros::external; |
src/tools/clippy/tests/ui/must_use_unit.rs+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | //@aux-build:proc_macros.rs |
| 2 | 2 | |
| 3 | 3 | #![warn(clippy::must_use_unit)] |
| 4 | #![allow(clippy::unused_unit)] | |
| 4 | #![expect(clippy::unused_unit)] | |
| 5 | 5 | |
| 6 | 6 | extern crate proc_macros; |
| 7 | 7 | use proc_macros::external; |
src/tools/clippy/tests/ui/mut_from_ref.rs+4-5| ... | ... | @@ -1,11 +1,10 @@ |
| 1 | #![allow( | |
| 2 | unused, | |
| 1 | #![warn(clippy::mut_from_ref)] | |
| 2 | #![expect( | |
| 3 | clippy::boxed_local, | |
| 3 | 4 | clippy::needless_lifetimes, |
| 4 | 5 | clippy::needless_pass_by_ref_mut, |
| 5 | clippy::redundant_allocation, | |
| 6 | clippy::boxed_local | |
| 6 | clippy::redundant_allocation | |
| 7 | 7 | )] |
| 8 | #![warn(clippy::mut_from_ref)] | |
| 9 | 8 | |
| 10 | 9 | struct Foo; |
| 11 | 10 |
src/tools/clippy/tests/ui/mut_from_ref.stderr+16-16| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | error: mutable borrow from immutable input(s) |
| 2 | --> tests/ui/mut_from_ref.rs:13:39 | |
| 2 | --> tests/ui/mut_from_ref.rs:12:39 | |
| 3 | 3 | | |
| 4 | 4 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { |
| 5 | 5 | | ^^^^^^^^ |
| 6 | 6 | | |
| 7 | 7 | note: immutable borrow here |
| 8 | --> tests/ui/mut_from_ref.rs:13:29 | |
| 8 | --> tests/ui/mut_from_ref.rs:12:29 | |
| 9 | 9 | | |
| 10 | 10 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { |
| 11 | 11 | | ^^^^^ |
| ... | ... | @@ -13,85 +13,85 @@ LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { |
| 13 | 13 | = help: to override `-D warnings` add `#[allow(clippy::mut_from_ref)]` |
| 14 | 14 | |
| 15 | 15 | error: mutable borrow from immutable input(s) |
| 16 | --> tests/ui/mut_from_ref.rs:21:25 | |
| 16 | --> tests/ui/mut_from_ref.rs:20:25 | |
| 17 | 17 | | |
| 18 | 18 | LL | fn ouch(x: &Foo) -> &mut Foo; |
| 19 | 19 | | ^^^^^^^^ |
| 20 | 20 | | |
| 21 | 21 | note: immutable borrow here |
| 22 | --> tests/ui/mut_from_ref.rs:21:16 | |
| 22 | --> tests/ui/mut_from_ref.rs:20:16 | |
| 23 | 23 | | |
| 24 | 24 | LL | fn ouch(x: &Foo) -> &mut Foo; |
| 25 | 25 | | ^^^^ |
| 26 | 26 | |
| 27 | 27 | error: mutable borrow from immutable input(s) |
| 28 | --> tests/ui/mut_from_ref.rs:31:21 | |
| 28 | --> tests/ui/mut_from_ref.rs:30:21 | |
| 29 | 29 | | |
| 30 | 30 | LL | fn fail(x: &u32) -> &mut u16 { |
| 31 | 31 | | ^^^^^^^^ |
| 32 | 32 | | |
| 33 | 33 | note: immutable borrow here |
| 34 | --> tests/ui/mut_from_ref.rs:31:12 | |
| 34 | --> tests/ui/mut_from_ref.rs:30:12 | |
| 35 | 35 | | |
| 36 | 36 | LL | fn fail(x: &u32) -> &mut u16 { |
| 37 | 37 | | ^^^^ |
| 38 | 38 | |
| 39 | 39 | error: mutable borrow from immutable input(s) |
| 40 | --> tests/ui/mut_from_ref.rs:37:50 | |
| 40 | --> tests/ui/mut_from_ref.rs:36:50 | |
| 41 | 41 | | |
| 42 | 42 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { |
| 43 | 43 | | ^^^^^^^^^^^ |
| 44 | 44 | | |
| 45 | 45 | note: immutable borrow here |
| 46 | --> tests/ui/mut_from_ref.rs:37:25 | |
| 46 | --> tests/ui/mut_from_ref.rs:36:25 | |
| 47 | 47 | | |
| 48 | 48 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { |
| 49 | 49 | | ^^^^^^^ |
| 50 | 50 | |
| 51 | 51 | error: mutable borrow from immutable input(s) |
| 52 | --> tests/ui/mut_from_ref.rs:43:67 | |
| 52 | --> tests/ui/mut_from_ref.rs:42:67 | |
| 53 | 53 | | |
| 54 | 54 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { |
| 55 | 55 | | ^^^^^^^^^^^ |
| 56 | 56 | | |
| 57 | 57 | note: immutable borrow here |
| 58 | --> tests/ui/mut_from_ref.rs:43:27 | |
| 58 | --> tests/ui/mut_from_ref.rs:42:27 | |
| 59 | 59 | | |
| 60 | 60 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { |
| 61 | 61 | | ^^^^^^^ ^^^^^^^ |
| 62 | 62 | |
| 63 | 63 | error: mutable borrow from immutable input(s) |
| 64 | --> tests/ui/mut_from_ref.rs:49:46 | |
| 64 | --> tests/ui/mut_from_ref.rs:48:46 | |
| 65 | 65 | | |
| 66 | 66 | LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 { |
| 67 | 67 | | ^^^^^^^^^^^ |
| 68 | 68 | | |
| 69 | 69 | note: immutable borrow here |
| 70 | --> tests/ui/mut_from_ref.rs:49:24 | |
| 70 | --> tests/ui/mut_from_ref.rs:48:24 | |
| 71 | 71 | | |
| 72 | 72 | LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 { |
| 73 | 73 | | ^^^^^^^ ^^^^^^^ |
| 74 | 74 | |
| 75 | 75 | error: mutable borrow from immutable input(s) |
| 76 | --> tests/ui/mut_from_ref.rs:55:37 | |
| 76 | --> tests/ui/mut_from_ref.rs:54:37 | |
| 77 | 77 | | |
| 78 | 78 | LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 { |
| 79 | 79 | | ^^^^^^^^^^^ |
| 80 | 80 | | |
| 81 | 81 | note: immutable borrow here |
| 82 | --> tests/ui/mut_from_ref.rs:55:24 | |
| 82 | --> tests/ui/mut_from_ref.rs:54:24 | |
| 83 | 83 | | |
| 84 | 84 | LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 { |
| 85 | 85 | | ^^^^^^^ |
| 86 | 86 | |
| 87 | 87 | error: mutable borrow from immutable input(s) |
| 88 | --> tests/ui/mut_from_ref.rs:85:35 | |
| 88 | --> tests/ui/mut_from_ref.rs:84:35 | |
| 89 | 89 | | |
| 90 | 90 | LL | unsafe fn also_broken(x: &u32) -> &mut u32 { |
| 91 | 91 | | ^^^^^^^^ |
| 92 | 92 | | |
| 93 | 93 | note: immutable borrow here |
| 94 | --> tests/ui/mut_from_ref.rs:85:26 | |
| 94 | --> tests/ui/mut_from_ref.rs:84:26 | |
| 95 | 95 | | |
| 96 | 96 | LL | unsafe fn also_broken(x: &u32) -> &mut u32 { |
| 97 | 97 | | ^^^^ |
src/tools/clippy/tests/ui/mut_mut.fixed-8| ... | ... | @@ -1,13 +1,6 @@ |
| 1 | 1 | //@aux-build:proc_macros.rs |
| 2 | 2 | |
| 3 | 3 | #![warn(clippy::mut_mut)] |
| 4 | #![allow(unused)] | |
| 5 | #![allow( | |
| 6 | clippy::no_effect, | |
| 7 | clippy::uninlined_format_args, | |
| 8 | clippy::unnecessary_operation, | |
| 9 | clippy::needless_pass_by_ref_mut | |
| 10 | )] | |
| 11 | 4 | |
| 12 | 5 | extern crate proc_macros; |
| 13 | 6 | use proc_macros::{external, inline_macros}; |
| ... | ... | @@ -26,7 +19,6 @@ macro_rules! mut_ptr { |
| 26 | 19 | }; |
| 27 | 20 | } |
| 28 | 21 | |
| 29 | #[allow(unused_mut, unused_variables)] | |
| 30 | 22 | #[inline_macros] |
| 31 | 23 | fn main() { |
| 32 | 24 | let mut x = &mut 1u32; |
src/tools/clippy/tests/ui/mut_mut.rs-8| ... | ... | @@ -1,13 +1,6 @@ |
| 1 | 1 | //@aux-build:proc_macros.rs |
| 2 | 2 | |
| 3 | 3 | #![warn(clippy::mut_mut)] |
| 4 | #![allow(unused)] | |
| 5 | #![allow( | |
| 6 | clippy::no_effect, | |
| 7 | clippy::uninlined_format_args, | |
| 8 | clippy::unnecessary_operation, | |
| 9 | clippy::needless_pass_by_ref_mut | |
| 10 | )] | |
| 11 | 4 | |
| 12 | 5 | extern crate proc_macros; |
| 13 | 6 | use proc_macros::{external, inline_macros}; |
| ... | ... | @@ -26,7 +19,6 @@ macro_rules! mut_ptr { |
| 26 | 19 | }; |
| 27 | 20 | } |
| 28 | 21 | |
| 29 | #[allow(unused_mut, unused_variables)] | |
| 30 | 22 | #[inline_macros] |
| 31 | 23 | fn main() { |
| 32 | 24 | let mut x = &mut &mut 1u32; |
src/tools/clippy/tests/ui/mut_mut.stderr+7-7| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: a type of form `&mut &mut _` |
| 2 | --> tests/ui/mut_mut.rs:15:11 | |
| 2 | --> tests/ui/mut_mut.rs:8:11 | |
| 3 | 3 | | |
| 4 | 4 | LL | fn fun(x: &mut &mut u32) { |
| 5 | 5 | | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32` |
| ... | ... | @@ -8,37 +8,37 @@ LL | fn fun(x: &mut &mut u32) { |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]` |
| 9 | 9 | |
| 10 | 10 | error: an expression of form `&mut &mut _` |
| 11 | --> tests/ui/mut_mut.rs:32:17 | |
| 11 | --> tests/ui/mut_mut.rs:24:17 | |
| 12 | 12 | | |
| 13 | 13 | LL | let mut x = &mut &mut 1u32; |
| 14 | 14 | | ^^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 1u32` |
| 15 | 15 | |
| 16 | 16 | error: this expression mutably borrows a mutable reference |
| 17 | --> tests/ui/mut_mut.rs:35:21 | |
| 17 | --> tests/ui/mut_mut.rs:27:21 | |
| 18 | 18 | | |
| 19 | 19 | LL | let mut y = &mut x; |
| 20 | 20 | | ^^^^^^ help: reborrow instead: `&mut *x` |
| 21 | 21 | |
| 22 | 22 | error: an expression of form `&mut &mut _` |
| 23 | --> tests/ui/mut_mut.rs:40:32 | |
| 23 | --> tests/ui/mut_mut.rs:32:32 | |
| 24 | 24 | | |
| 25 | 25 | LL | let y: &mut &mut u32 = &mut &mut 2; |
| 26 | 26 | | ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 2` |
| 27 | 27 | |
| 28 | 28 | error: a type of form `&mut &mut _` |
| 29 | --> tests/ui/mut_mut.rs:40:16 | |
| 29 | --> tests/ui/mut_mut.rs:32:16 | |
| 30 | 30 | | |
| 31 | 31 | LL | let y: &mut &mut u32 = &mut &mut 2; |
| 32 | 32 | | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32` |
| 33 | 33 | |
| 34 | 34 | error: an expression of form `&mut &mut _` |
| 35 | --> tests/ui/mut_mut.rs:46:37 | |
| 35 | --> tests/ui/mut_mut.rs:38:37 | |
| 36 | 36 | | |
| 37 | 37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; |
| 38 | 38 | | ^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut 2` |
| 39 | 39 | |
| 40 | 40 | error: a type of form `&mut &mut _` |
| 41 | --> tests/ui/mut_mut.rs:46:16 | |
| 41 | --> tests/ui/mut_mut.rs:38:16 | |
| 42 | 42 | | |
| 43 | 43 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; |
| 44 | 44 | | ^^^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut u32` |
src/tools/clippy/tests/ui/mut_mut_unfixable.rs-1| ... | ... | @@ -1,7 +1,6 @@ |
| 1 | 1 | //@no-rustfix |
| 2 | 2 | |
| 3 | 3 | #![warn(clippy::mut_mut)] |
| 4 | #![allow(unused)] | |
| 5 | 4 | #![expect(clippy::no_effect)] |
| 6 | 5 | |
| 7 | 6 | //! removing the extra `&mut`s will break the derefs |
src/tools/clippy/tests/ui/mut_mut_unfixable.stderr+6-6| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: a type of form `&mut &mut _` |
| 2 | --> tests/ui/mut_mut_unfixable.rs:9:11 | |
| 2 | --> tests/ui/mut_mut_unfixable.rs:8:11 | |
| 3 | 3 | | |
| 4 | 4 | LL | fn fun(x: &mut &mut u32) -> bool { |
| 5 | 5 | | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32` |
| ... | ... | @@ -8,31 +8,31 @@ LL | fn fun(x: &mut &mut u32) -> bool { |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]` |
| 9 | 9 | |
| 10 | 10 | error: an expression of form `&mut &mut _` |
| 11 | --> tests/ui/mut_mut_unfixable.rs:15:17 | |
| 11 | --> tests/ui/mut_mut_unfixable.rs:14:17 | |
| 12 | 12 | | |
| 13 | 13 | LL | let mut x = &mut &mut 1u32; |
| 14 | 14 | | ^^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 1u32` |
| 15 | 15 | |
| 16 | 16 | error: this expression mutably borrows a mutable reference |
| 17 | --> tests/ui/mut_mut_unfixable.rs:18:21 | |
| 17 | --> tests/ui/mut_mut_unfixable.rs:17:21 | |
| 18 | 18 | | |
| 19 | 19 | LL | let mut y = &mut x; |
| 20 | 20 | | ^^^^^^ help: reborrow instead: `&mut *x` |
| 21 | 21 | |
| 22 | 22 | error: an expression of form `&mut &mut _` |
| 23 | --> tests/ui/mut_mut_unfixable.rs:24:17 | |
| 23 | --> tests/ui/mut_mut_unfixable.rs:23:17 | |
| 24 | 24 | | |
| 25 | 25 | LL | let y = &mut &mut 2; |
| 26 | 26 | | ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 2` |
| 27 | 27 | |
| 28 | 28 | error: an expression of form `&mut &mut _` |
| 29 | --> tests/ui/mut_mut_unfixable.rs:30:17 | |
| 29 | --> tests/ui/mut_mut_unfixable.rs:29:17 | |
| 30 | 30 | | |
| 31 | 31 | LL | let y = &mut &mut &mut 2; |
| 32 | 32 | | ^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut 2` |
| 33 | 33 | |
| 34 | 34 | error: an expression of form `&mut &mut _` |
| 35 | --> tests/ui/mut_mut_unfixable.rs:39:17 | |
| 35 | --> tests/ui/mut_mut_unfixable.rs:38:17 | |
| 36 | 36 | | |
| 37 | 37 | LL | let y = &mut &mut x; |
| 38 | 38 | | ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut x` |
src/tools/clippy/tests/ui/mut_mutex_lock.fixed-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | #![allow(dead_code, unused_mut)] | |
| 2 | 1 | #![warn(clippy::mut_mutex_lock)] |
| 3 | 2 | |
| 4 | 3 | use std::sync::{Arc, Mutex}; |
src/tools/clippy/tests/ui/mut_mutex_lock.rs-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | #![allow(dead_code, unused_mut)] | |
| 2 | 1 | #![warn(clippy::mut_mutex_lock)] |
| 3 | 2 | |
| 4 | 3 | use std::sync::{Arc, Mutex}; |
src/tools/clippy/tests/ui/mut_mutex_lock.stderr+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference |
| 2 | --> tests/ui/mut_mutex_lock.rs:10:33 | |
| 2 | --> tests/ui/mut_mutex_lock.rs:9:33 | |
| 3 | 3 | | |
| 4 | 4 | LL | let mut value = value_mutex.lock().unwrap(); |
| 5 | 5 | | ^^^^ help: change this to: `get_mut` |
| ... | ... | @@ -8,7 +8,7 @@ LL | let mut value = value_mutex.lock().unwrap(); |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::mut_mutex_lock)]` |
| 9 | 9 | |
| 10 | 10 | error: calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference |
| 11 | --> tests/ui/mut_mutex_lock.rs:16:43 | |
| 11 | --> tests/ui/mut_mutex_lock.rs:15:43 | |
| 12 | 12 | | |
| 13 | 13 | LL | let mut value = mut_ref_mut_ref_mutex.lock().unwrap(); |
| 14 | 14 | | ^^^^ help: change this to: `get_mut` |
src/tools/clippy/tests/ui/mut_range_bound.rs+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | #![allow(unused)] | |
| 1 | #![warn(clippy::mut_range_bound)] | |
| 2 | 2 | |
| 3 | 3 | fn main() {} |
| 4 | 4 |
src/tools/clippy/tests/ui/mutex_atomic.fixed+2-3| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | #![warn(clippy::mutex_integer)] | |
| 2 | #![warn(clippy::mutex_atomic)] | |
| 3 | #![allow(clippy::borrow_as_ptr)] | |
| 1 | #![warn(clippy::mutex_atomic, clippy::mutex_integer)] | |
| 2 | #![expect(clippy::borrow_as_ptr)] | |
| 4 | 3 | |
| 5 | 4 | use std::sync::Mutex; |
| 6 | 5 |
src/tools/clippy/tests/ui/mutex_atomic.rs+2-3| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | #![warn(clippy::mutex_integer)] | |
| 2 | #![warn(clippy::mutex_atomic)] | |
| 3 | #![allow(clippy::borrow_as_ptr)] | |
| 1 | #![warn(clippy::mutex_atomic, clippy::mutex_integer)] | |
| 2 | #![expect(clippy::borrow_as_ptr)] | |
| 4 | 3 | |
| 5 | 4 | use std::sync::Mutex; |
| 6 | 5 |
src/tools/clippy/tests/ui/mutex_atomic.stderr+15-15| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: using a `Mutex` where an atomic would do |
| 2 | --> tests/ui/mutex_atomic.rs:8:13 | |
| 2 | --> tests/ui/mutex_atomic.rs:7:13 | |
| 3 | 3 | | |
| 4 | 4 | LL | let _ = Mutex::new(true); |
| 5 | 5 | | ^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -14,7 +14,7 @@ LL + let _ = std::sync::atomic::AtomicBool::new(true); |
| 14 | 14 | | |
| 15 | 15 | |
| 16 | 16 | error: using a `Mutex` where an atomic would do |
| 17 | --> tests/ui/mutex_atomic.rs:11:13 | |
| 17 | --> tests/ui/mutex_atomic.rs:10:13 | |
| 18 | 18 | | |
| 19 | 19 | LL | let _ = Mutex::new(5usize); |
| 20 | 20 | | ^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -27,7 +27,7 @@ LL + let _ = std::sync::atomic::AtomicUsize::new(5usize); |
| 27 | 27 | | |
| 28 | 28 | |
| 29 | 29 | error: using a `Mutex` where an atomic would do |
| 30 | --> tests/ui/mutex_atomic.rs:14:13 | |
| 30 | --> tests/ui/mutex_atomic.rs:13:13 | |
| 31 | 31 | | |
| 32 | 32 | LL | let _ = Mutex::new(9isize); |
| 33 | 33 | | ^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -40,7 +40,7 @@ LL + let _ = std::sync::atomic::AtomicIsize::new(9isize); |
| 40 | 40 | | |
| 41 | 41 | |
| 42 | 42 | error: using a `Mutex` where an atomic would do |
| 43 | --> tests/ui/mutex_atomic.rs:21:13 | |
| 43 | --> tests/ui/mutex_atomic.rs:20:13 | |
| 44 | 44 | | |
| 45 | 45 | LL | let _ = Mutex::new(&mut x as *mut u32); |
| 46 | 46 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -53,7 +53,7 @@ LL + let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32); |
| 53 | 53 | | |
| 54 | 54 | |
| 55 | 55 | error: using a `Mutex` where an atomic would do |
| 56 | --> tests/ui/mutex_atomic.rs:24:13 | |
| 56 | --> tests/ui/mutex_atomic.rs:23:13 | |
| 57 | 57 | | |
| 58 | 58 | LL | let _ = Mutex::new(0u32); |
| 59 | 59 | | ^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -68,7 +68,7 @@ LL + let _ = std::sync::atomic::AtomicU32::new(0u32); |
| 68 | 68 | | |
| 69 | 69 | |
| 70 | 70 | error: using a `Mutex` where an atomic would do |
| 71 | --> tests/ui/mutex_atomic.rs:27:13 | |
| 71 | --> tests/ui/mutex_atomic.rs:26:13 | |
| 72 | 72 | | |
| 73 | 73 | LL | let _ = Mutex::new(0i32); |
| 74 | 74 | | ^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -81,7 +81,7 @@ LL + let _ = std::sync::atomic::AtomicI32::new(0i32); |
| 81 | 81 | | |
| 82 | 82 | |
| 83 | 83 | error: using a `Mutex` where an atomic would do |
| 84 | --> tests/ui/mutex_atomic.rs:31:13 | |
| 84 | --> tests/ui/mutex_atomic.rs:30:13 | |
| 85 | 85 | | |
| 86 | 86 | LL | let _ = Mutex::new(0u8); |
| 87 | 87 | | ^^^^^^^^^^^^^^^ |
| ... | ... | @@ -94,7 +94,7 @@ LL + let _ = std::sync::atomic::AtomicU8::new(0u8); |
| 94 | 94 | | |
| 95 | 95 | |
| 96 | 96 | error: using a `Mutex` where an atomic would do |
| 97 | --> tests/ui/mutex_atomic.rs:34:13 | |
| 97 | --> tests/ui/mutex_atomic.rs:33:13 | |
| 98 | 98 | | |
| 99 | 99 | LL | let _ = Mutex::new(0i16); |
| 100 | 100 | | ^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -107,7 +107,7 @@ LL + let _ = std::sync::atomic::AtomicI16::new(0i16); |
| 107 | 107 | | |
| 108 | 108 | |
| 109 | 109 | error: using a `Mutex` where an atomic would do |
| 110 | --> tests/ui/mutex_atomic.rs:37:25 | |
| 110 | --> tests/ui/mutex_atomic.rs:36:25 | |
| 111 | 111 | | |
| 112 | 112 | LL | let _x: Mutex<i8> = Mutex::new(0); |
| 113 | 113 | | ^^^^^^^^^^^^^ |
| ... | ... | @@ -120,7 +120,7 @@ LL + let _x = std::sync::atomic::AtomicI8::new(0); |
| 120 | 120 | | |
| 121 | 121 | |
| 122 | 122 | error: using a `Mutex` where an atomic would do |
| 123 | --> tests/ui/mutex_atomic.rs:41:13 | |
| 123 | --> tests/ui/mutex_atomic.rs:40:13 | |
| 124 | 124 | | |
| 125 | 125 | LL | let _ = Mutex::new(X); |
| 126 | 126 | | ^^^^^^^^^^^^^ |
| ... | ... | @@ -133,7 +133,7 @@ LL + let _ = std::sync::atomic::AtomicI64::new(X); |
| 133 | 133 | | |
| 134 | 134 | |
| 135 | 135 | error: using a `Mutex` where an atomic would do |
| 136 | --> tests/ui/mutex_atomic.rs:53:30 | |
| 136 | --> tests/ui/mutex_atomic.rs:52:30 | |
| 137 | 137 | | |
| 138 | 138 | LL | static MTX: Mutex<u32> = Mutex::new(0); |
| 139 | 139 | | ^^^^^^^^^^^^^ |
| ... | ... | @@ -146,7 +146,7 @@ LL + static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32 |
| 146 | 146 | | |
| 147 | 147 | |
| 148 | 148 | error: using a `Mutex` where an atomic would do |
| 149 | --> tests/ui/mutex_atomic.rs:56:15 | |
| 149 | --> tests/ui/mutex_atomic.rs:55:15 | |
| 150 | 150 | | |
| 151 | 151 | LL | let mtx = Mutex::new(0); |
| 152 | 152 | | ^^^^^^^^^^^^^ |
| ... | ... | @@ -159,7 +159,7 @@ LL + let mtx = std::sync::atomic::AtomicI32::new(0); |
| 159 | 159 | | |
| 160 | 160 | |
| 161 | 161 | error: using a `Mutex` where an atomic would do |
| 162 | --> tests/ui/mutex_atomic.rs:60:22 | |
| 162 | --> tests/ui/mutex_atomic.rs:59:22 | |
| 163 | 163 | | |
| 164 | 164 | LL | let reassigned = mtx; |
| 165 | 165 | | ^^^ |
| ... | ... | @@ -168,7 +168,7 @@ LL | let reassigned = mtx; |
| 168 | 168 | = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` |
| 169 | 169 | |
| 170 | 170 | error: using a `Mutex` where an atomic would do |
| 171 | --> tests/ui/mutex_atomic.rs:65:35 | |
| 171 | --> tests/ui/mutex_atomic.rs:64:35 | |
| 172 | 172 | | |
| 173 | 173 | LL | let (funky_mtx): Mutex<u64> = Mutex::new(0); |
| 174 | 174 | | ^^^^^^^^^^^^^ |
| ... | ... | @@ -181,7 +181,7 @@ LL + let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); |
| 181 | 181 | | |
| 182 | 182 | |
| 183 | 183 | error: using a `Mutex` where an atomic would do |
| 184 | --> tests/ui/mutex_atomic.rs:76:13 | |
| 184 | --> tests/ui/mutex_atomic.rs:75:13 | |
| 185 | 185 | | |
| 186 | 186 | LL | let _ = Mutex::new(test_expr!(1)); |
| 187 | 187 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | #![warn(clippy::needless_arbitrary_self_type)] |
| 2 | #![allow(unused_mut, clippy::needless_lifetimes)] | |
| 2 | #![expect(clippy::needless_lifetimes)] | |
| 3 | 3 | |
| 4 | 4 | pub enum ValType { |
| 5 | 5 | A, |
src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | #![warn(clippy::needless_arbitrary_self_type)] |
| 2 | #![allow(unused_mut, clippy::needless_lifetimes)] | |
| 2 | #![expect(clippy::needless_lifetimes)] | |
| 3 | 3 | |
| 4 | 4 | pub enum ValType { |
| 5 | 5 | A, |
src/tools/clippy/tests/ui/needless_bitwise_bool.fixed+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | #![warn(clippy::needless_bitwise_bool)] |
| 2 | #![allow(clippy::const_is_empty)] | |
| 2 | #![expect(clippy::const_is_empty)] | |
| 3 | 3 | |
| 4 | 4 | fn returns_bool() -> bool { |
| 5 | 5 | true |
src/tools/clippy/tests/ui/needless_bitwise_bool.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | #![warn(clippy::needless_bitwise_bool)] |
| 2 | #![allow(clippy::const_is_empty)] | |
| 2 | #![expect(clippy::const_is_empty)] | |
| 3 | 3 | |
| 4 | 4 | fn returns_bool() -> bool { |
| 5 | 5 | true |
src/tools/clippy/tests/ui/needless_bool/fixable.fixed+2-12| ... | ... | @@ -1,15 +1,6 @@ |
| 1 | 1 | #![warn(clippy::needless_bool)] |
| 2 | #![allow( | |
| 3 | unused, | |
| 4 | dead_code, | |
| 5 | clippy::no_effect, | |
| 6 | clippy::if_same_then_else, | |
| 7 | clippy::equatable_if_let, | |
| 8 | clippy::needless_ifs, | |
| 9 | clippy::needless_return, | |
| 10 | clippy::self_named_constructors, | |
| 11 | clippy::struct_field_names | |
| 12 | )] | |
| 2 | #![allow(clippy::no_effect)] | |
| 3 | #![expect(clippy::needless_return)] | |
| 13 | 4 | |
| 14 | 5 | use std::cell::Cell; |
| 15 | 6 | |
| ... | ... | @@ -21,7 +12,6 @@ macro_rules! bool_comparison_trigger { |
| 21 | 12 | $($i: (Cell<bool>, bool, bool)),+ |
| 22 | 13 | } |
| 23 | 14 | |
| 24 | #[allow(dead_code)] | |
| 25 | 15 | impl Trigger { |
| 26 | 16 | pub fn trigger(&self, key: &str) -> bool { |
| 27 | 17 | $( |
src/tools/clippy/tests/ui/needless_bool/fixable.rs+2-12| ... | ... | @@ -1,15 +1,6 @@ |
| 1 | 1 | #![warn(clippy::needless_bool)] |
| 2 | #![allow( | |
| 3 | unused, | |
| 4 | dead_code, | |
| 5 | clippy::no_effect, | |
| 6 | clippy::if_same_then_else, | |
| 7 | clippy::equatable_if_let, | |
| 8 | clippy::needless_ifs, | |
| 9 | clippy::needless_return, | |
| 10 | clippy::self_named_constructors, | |
| 11 | clippy::struct_field_names | |
| 12 | )] | |
| 2 | #![allow(clippy::no_effect)] | |
| 3 | #![expect(clippy::needless_return)] | |
| 13 | 4 | |
| 14 | 5 | use std::cell::Cell; |
| 15 | 6 | |
| ... | ... | @@ -21,7 +12,6 @@ macro_rules! bool_comparison_trigger { |
| 21 | 12 | $($i: (Cell<bool>, bool, bool)),+ |
| 22 | 13 | } |
| 23 | 14 | |
| 24 | #[allow(dead_code)] | |
| 25 | 15 | impl Trigger { |
| 26 | 16 | pub fn trigger(&self, key: &str) -> bool { |
| 27 | 17 | $( |
src/tools/clippy/tests/ui/needless_bool/fixable.stderr+25-25| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: this if-then-else expression returns a bool literal |
| 2 | --> tests/ui/needless_bool/fixable.rs:41:5 | |
| 2 | --> tests/ui/needless_bool/fixable.rs:31:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | / if x { |
| 5 | 5 | LL | | true |
| ... | ... | @@ -12,7 +12,7 @@ LL | | }; |
| 12 | 12 | = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` |
| 13 | 13 | |
| 14 | 14 | error: this if-then-else expression returns a bool literal |
| 15 | --> tests/ui/needless_bool/fixable.rs:47:5 | |
| 15 | --> tests/ui/needless_bool/fixable.rs:37:5 | |
| 16 | 16 | | |
| 17 | 17 | LL | / if x { |
| 18 | 18 | LL | | false |
| ... | ... | @@ -22,7 +22,7 @@ LL | | }; |
| 22 | 22 | | |_____^ help: you can reduce it to: `!x` |
| 23 | 23 | |
| 24 | 24 | error: this if-then-else expression returns a bool literal |
| 25 | --> tests/ui/needless_bool/fixable.rs:53:5 | |
| 25 | --> tests/ui/needless_bool/fixable.rs:43:5 | |
| 26 | 26 | | |
| 27 | 27 | LL | / if x && y { |
| 28 | 28 | LL | | false |
| ... | ... | @@ -32,7 +32,7 @@ LL | | }; |
| 32 | 32 | | |_____^ help: you can reduce it to: `!(x && y)` |
| 33 | 33 | |
| 34 | 34 | error: this if-then-else expression returns a bool literal |
| 35 | --> tests/ui/needless_bool/fixable.rs:62:5 | |
| 35 | --> tests/ui/needless_bool/fixable.rs:52:5 | |
| 36 | 36 | | |
| 37 | 37 | LL | / if a == b { |
| 38 | 38 | LL | | false |
| ... | ... | @@ -42,7 +42,7 @@ LL | | }; |
| 42 | 42 | | |_____^ help: you can reduce it to: `a != b` |
| 43 | 43 | |
| 44 | 44 | error: this if-then-else expression returns a bool literal |
| 45 | --> tests/ui/needless_bool/fixable.rs:68:5 | |
| 45 | --> tests/ui/needless_bool/fixable.rs:58:5 | |
| 46 | 46 | | |
| 47 | 47 | LL | / if a != b { |
| 48 | 48 | LL | | false |
| ... | ... | @@ -52,7 +52,7 @@ LL | | }; |
| 52 | 52 | | |_____^ help: you can reduce it to: `a == b` |
| 53 | 53 | |
| 54 | 54 | error: this if-then-else expression returns a bool literal |
| 55 | --> tests/ui/needless_bool/fixable.rs:74:5 | |
| 55 | --> tests/ui/needless_bool/fixable.rs:64:5 | |
| 56 | 56 | | |
| 57 | 57 | LL | / if a < b { |
| 58 | 58 | LL | | false |
| ... | ... | @@ -62,7 +62,7 @@ LL | | }; |
| 62 | 62 | | |_____^ help: you can reduce it to: `a >= b` |
| 63 | 63 | |
| 64 | 64 | error: this if-then-else expression returns a bool literal |
| 65 | --> tests/ui/needless_bool/fixable.rs:80:5 | |
| 65 | --> tests/ui/needless_bool/fixable.rs:70:5 | |
| 66 | 66 | | |
| 67 | 67 | LL | / if a <= b { |
| 68 | 68 | LL | | false |
| ... | ... | @@ -72,7 +72,7 @@ LL | | }; |
| 72 | 72 | | |_____^ help: you can reduce it to: `a > b` |
| 73 | 73 | |
| 74 | 74 | error: this if-then-else expression returns a bool literal |
| 75 | --> tests/ui/needless_bool/fixable.rs:86:5 | |
| 75 | --> tests/ui/needless_bool/fixable.rs:76:5 | |
| 76 | 76 | | |
| 77 | 77 | LL | / if a > b { |
| 78 | 78 | LL | | false |
| ... | ... | @@ -82,7 +82,7 @@ LL | | }; |
| 82 | 82 | | |_____^ help: you can reduce it to: `a <= b` |
| 83 | 83 | |
| 84 | 84 | error: this if-then-else expression returns a bool literal |
| 85 | --> tests/ui/needless_bool/fixable.rs:92:5 | |
| 85 | --> tests/ui/needless_bool/fixable.rs:82:5 | |
| 86 | 86 | | |
| 87 | 87 | LL | / if a >= b { |
| 88 | 88 | LL | | false |
| ... | ... | @@ -92,7 +92,7 @@ LL | | }; |
| 92 | 92 | | |_____^ help: you can reduce it to: `a < b` |
| 93 | 93 | |
| 94 | 94 | error: this if-then-else expression returns a bool literal |
| 95 | --> tests/ui/needless_bool/fixable.rs:121:5 | |
| 95 | --> tests/ui/needless_bool/fixable.rs:111:5 | |
| 96 | 96 | | |
| 97 | 97 | LL | / if x { |
| 98 | 98 | LL | | return true; |
| ... | ... | @@ -102,7 +102,7 @@ LL | | }; |
| 102 | 102 | | |_____^ help: you can reduce it to: `return x` |
| 103 | 103 | |
| 104 | 104 | error: this if-then-else expression returns a bool literal |
| 105 | --> tests/ui/needless_bool/fixable.rs:130:5 | |
| 105 | --> tests/ui/needless_bool/fixable.rs:120:5 | |
| 106 | 106 | | |
| 107 | 107 | LL | / if x { |
| 108 | 108 | LL | | return false; |
| ... | ... | @@ -112,7 +112,7 @@ LL | | }; |
| 112 | 112 | | |_____^ help: you can reduce it to: `return !x` |
| 113 | 113 | |
| 114 | 114 | error: this if-then-else expression returns a bool literal |
| 115 | --> tests/ui/needless_bool/fixable.rs:139:5 | |
| 115 | --> tests/ui/needless_bool/fixable.rs:129:5 | |
| 116 | 116 | | |
| 117 | 117 | LL | / if x && y { |
| 118 | 118 | LL | | return true; |
| ... | ... | @@ -122,7 +122,7 @@ LL | | }; |
| 122 | 122 | | |_____^ help: you can reduce it to: `return x && y` |
| 123 | 123 | |
| 124 | 124 | error: this if-then-else expression returns a bool literal |
| 125 | --> tests/ui/needless_bool/fixable.rs:148:5 | |
| 125 | --> tests/ui/needless_bool/fixable.rs:138:5 | |
| 126 | 126 | | |
| 127 | 127 | LL | / if x && y { |
| 128 | 128 | LL | | return false; |
| ... | ... | @@ -132,7 +132,7 @@ LL | | }; |
| 132 | 132 | | |_____^ help: you can reduce it to: `return !(x && y)` |
| 133 | 133 | |
| 134 | 134 | error: equality checks against true are unnecessary |
| 135 | --> tests/ui/needless_bool/fixable.rs:157:8 | |
| 135 | --> tests/ui/needless_bool/fixable.rs:147:8 | |
| 136 | 136 | | |
| 137 | 137 | LL | if x == true {}; |
| 138 | 138 | | ^^^^^^^^^ help: try: `x` |
| ... | ... | @@ -141,25 +141,25 @@ LL | if x == true {}; |
| 141 | 141 | = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` |
| 142 | 142 | |
| 143 | 143 | error: equality checks against false can be replaced by a negation |
| 144 | --> tests/ui/needless_bool/fixable.rs:162:8 | |
| 144 | --> tests/ui/needless_bool/fixable.rs:152:8 | |
| 145 | 145 | | |
| 146 | 146 | LL | if x == false {}; |
| 147 | 147 | | ^^^^^^^^^^ help: try: `!x` |
| 148 | 148 | |
| 149 | 149 | error: equality checks against true are unnecessary |
| 150 | --> tests/ui/needless_bool/fixable.rs:173:8 | |
| 150 | --> tests/ui/needless_bool/fixable.rs:163:8 | |
| 151 | 151 | | |
| 152 | 152 | LL | if x == true {}; |
| 153 | 153 | | ^^^^^^^^^ help: try: `x` |
| 154 | 154 | |
| 155 | 155 | error: equality checks against false can be replaced by a negation |
| 156 | --> tests/ui/needless_bool/fixable.rs:175:8 | |
| 156 | --> tests/ui/needless_bool/fixable.rs:165:8 | |
| 157 | 157 | | |
| 158 | 158 | LL | if x == false {}; |
| 159 | 159 | | ^^^^^^^^^^ help: try: `!x` |
| 160 | 160 | |
| 161 | 161 | error: this if-then-else expression returns a bool literal |
| 162 | --> tests/ui/needless_bool/fixable.rs:185:12 | |
| 162 | --> tests/ui/needless_bool/fixable.rs:175:12 | |
| 163 | 163 | | |
| 164 | 164 | LL | } else if returns_bool() { |
| 165 | 165 | | ____________^ |
| ... | ... | @@ -170,7 +170,7 @@ LL | | }; |
| 170 | 170 | | |_____^ help: you can reduce it to: `{ !returns_bool() }` |
| 171 | 171 | |
| 172 | 172 | error: this if-then-else expression returns a bool literal |
| 173 | --> tests/ui/needless_bool/fixable.rs:199:5 | |
| 173 | --> tests/ui/needless_bool/fixable.rs:189:5 | |
| 174 | 174 | | |
| 175 | 175 | LL | / if unsafe { no(4) } & 1 != 0 { |
| 176 | 176 | LL | | true |
| ... | ... | @@ -180,37 +180,37 @@ LL | | }; |
| 180 | 180 | | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` |
| 181 | 181 | |
| 182 | 182 | error: this if-then-else expression returns a bool literal |
| 183 | --> tests/ui/needless_bool/fixable.rs:205:30 | |
| 183 | --> tests/ui/needless_bool/fixable.rs:195:30 | |
| 184 | 184 | | |
| 185 | 185 | LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; |
| 186 | 186 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0` |
| 187 | 187 | |
| 188 | 188 | error: this if-then-else expression returns a bool literal |
| 189 | --> tests/ui/needless_bool/fixable.rs:209:9 | |
| 189 | --> tests/ui/needless_bool/fixable.rs:199:9 | |
| 190 | 190 | | |
| 191 | 191 | LL | if unsafe { no(4) } & 1 != 0 { true } else { false } |
| 192 | 192 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` |
| 193 | 193 | |
| 194 | 194 | error: this if-then-else expression returns a bool literal |
| 195 | --> tests/ui/needless_bool/fixable.rs:221:14 | |
| 195 | --> tests/ui/needless_bool/fixable.rs:211:14 | |
| 196 | 196 | | |
| 197 | 197 | LL | let _x = if a && b { true } else { false }.then(|| todo!()); |
| 198 | 198 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` |
| 199 | 199 | |
| 200 | 200 | error: this if-then-else expression returns a bool literal |
| 201 | --> tests/ui/needless_bool/fixable.rs:223:14 | |
| 201 | --> tests/ui/needless_bool/fixable.rs:213:14 | |
| 202 | 202 | | |
| 203 | 203 | LL | let _x = if a && b { true } else { false } as u8; |
| 204 | 204 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` |
| 205 | 205 | |
| 206 | 206 | error: this if-then-else expression returns a bool literal |
| 207 | --> tests/ui/needless_bool/fixable.rs:227:14 | |
| 207 | --> tests/ui/needless_bool/fixable.rs:217:14 | |
| 208 | 208 | | |
| 209 | 209 | LL | let _x = if a { true } else { false }.then(|| todo!()); |
| 210 | 210 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `a` |
| 211 | 211 | |
| 212 | 212 | error: this if-then-else expression returns a bool literal |
| 213 | --> tests/ui/needless_bool/fixable.rs:239:5 | |
| 213 | --> tests/ui/needless_bool/fixable.rs:229:5 | |
| 214 | 214 | | |
| 215 | 215 | LL | / if test_expr!(x) { |
| 216 | 216 | LL | | true |
src/tools/clippy/tests/ui/needless_bool/simple.rs+1-8| ... | ... | @@ -1,12 +1,5 @@ |
| 1 | 1 | #![warn(clippy::needless_bool)] |
| 2 | #![allow( | |
| 3 | unused, | |
| 4 | dead_code, | |
| 5 | clippy::no_effect, | |
| 6 | clippy::if_same_then_else, | |
| 7 | clippy::needless_return, | |
| 8 | clippy::branches_sharing_code | |
| 9 | )] | |
| 2 | #![expect(clippy::if_same_then_else, clippy::needless_return)] | |
| 10 | 3 | |
| 11 | 4 | fn main() { |
| 12 | 5 | let x = true; |
src/tools/clippy/tests/ui/needless_bool/simple.stderr+4-4| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: this if-then-else expression will always return true |
| 2 | --> tests/ui/needless_bool/simple.rs:14:5 | |
| 2 | --> tests/ui/needless_bool/simple.rs:7:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | / if x { |
| 5 | 5 | LL | | true |
| ... | ... | @@ -12,7 +12,7 @@ LL | | }; |
| 12 | 12 | = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` |
| 13 | 13 | |
| 14 | 14 | error: this if-then-else expression will always return false |
| 15 | --> tests/ui/needless_bool/simple.rs:20:5 | |
| 15 | --> tests/ui/needless_bool/simple.rs:13:5 | |
| 16 | 16 | | |
| 17 | 17 | LL | / if x { |
| 18 | 18 | LL | | false |
| ... | ... | @@ -22,7 +22,7 @@ LL | | }; |
| 22 | 22 | | |_____^ |
| 23 | 23 | |
| 24 | 24 | error: this if-then-else expression will always return true |
| 25 | --> tests/ui/needless_bool/simple.rs:36:5 | |
| 25 | --> tests/ui/needless_bool/simple.rs:29:5 | |
| 26 | 26 | | |
| 27 | 27 | LL | / if x { |
| 28 | 28 | LL | | return true; |
| ... | ... | @@ -32,7 +32,7 @@ LL | | }; |
| 32 | 32 | | |_____^ |
| 33 | 33 | |
| 34 | 34 | error: this if-then-else expression will always return false |
| 35 | --> tests/ui/needless_bool/simple.rs:45:5 | |
| 35 | --> tests/ui/needless_bool/simple.rs:38:5 | |
| 36 | 36 | | |
| 37 | 37 | LL | / if x { |
| 38 | 38 | LL | | return false; |
src/tools/clippy/tests/ui/needless_bool_assign.fixed-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | #![allow(unused)] | |
| 2 | 1 | #![warn(clippy::needless_bool_assign)] |
| 3 | 2 | |
| 4 | 3 | fn random() -> bool { |
src/tools/clippy/tests/ui/needless_bool_assign.rs-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | #![allow(unused)] | |
| 2 | 1 | #![warn(clippy::needless_bool_assign)] |
| 3 | 2 | |
| 4 | 3 | fn random() -> bool { |
src/tools/clippy/tests/ui/needless_bool_assign.stderr+7-7| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: this if-then-else expression assigns a bool literal |
| 2 | --> tests/ui/needless_bool_assign.rs:13:5 | |
| 2 | --> tests/ui/needless_bool_assign.rs:12:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | / if random() && random() { |
| 5 | 5 | LL | | a.field = true; |
| ... | ... | @@ -12,7 +12,7 @@ LL | | } |
| 12 | 12 | = help: to override `-D warnings` add `#[allow(clippy::needless_bool_assign)]` |
| 13 | 13 | |
| 14 | 14 | error: this if-then-else expression assigns a bool literal |
| 15 | --> tests/ui/needless_bool_assign.rs:19:5 | |
| 15 | --> tests/ui/needless_bool_assign.rs:18:5 | |
| 16 | 16 | | |
| 17 | 17 | LL | / if random() && random() { |
| 18 | 18 | LL | | a.field = false; |
| ... | ... | @@ -22,7 +22,7 @@ LL | | } |
| 22 | 22 | | |_____^ help: you can reduce it to: `a.field = !(random() && random());` |
| 23 | 23 | |
| 24 | 24 | error: this if-then-else expression assigns a bool literal |
| 25 | --> tests/ui/needless_bool_assign.rs:34:5 | |
| 25 | --> tests/ui/needless_bool_assign.rs:33:5 | |
| 26 | 26 | | |
| 27 | 27 | LL | / if random() { |
| 28 | 28 | LL | | a.field = true; |
| ... | ... | @@ -32,7 +32,7 @@ LL | | } |
| 32 | 32 | | |_____^ help: you can reduce it to: `random(); a.field = true;` |
| 33 | 33 | |
| 34 | 34 | error: this `if` has identical blocks |
| 35 | --> tests/ui/needless_bool_assign.rs:34:17 | |
| 35 | --> tests/ui/needless_bool_assign.rs:33:17 | |
| 36 | 36 | | |
| 37 | 37 | LL | if random() { |
| 38 | 38 | | _________________^ |
| ... | ... | @@ -41,7 +41,7 @@ LL | | } else { |
| 41 | 41 | | |_____^ |
| 42 | 42 | | |
| 43 | 43 | note: same as this |
| 44 | --> tests/ui/needless_bool_assign.rs:36:12 | |
| 44 | --> tests/ui/needless_bool_assign.rs:35:12 | |
| 45 | 45 | | |
| 46 | 46 | LL | } else { |
| 47 | 47 | | ____________^ |
| ... | ... | @@ -52,7 +52,7 @@ LL | | } |
| 52 | 52 | = help: to override `-D warnings` add `#[allow(clippy::if_same_then_else)]` |
| 53 | 53 | |
| 54 | 54 | error: this if-then-else expression assigns a bool literal |
| 55 | --> tests/ui/needless_bool_assign.rs:54:12 | |
| 55 | --> tests/ui/needless_bool_assign.rs:53:12 | |
| 56 | 56 | | |
| 57 | 57 | LL | } else if x || y { |
| 58 | 58 | | ____________^ |
| ... | ... | @@ -63,7 +63,7 @@ LL | | } |
| 63 | 63 | | |_____^ help: you can reduce it to: `{ z = x || y; }` |
| 64 | 64 | |
| 65 | 65 | error: this if-then-else expression assigns a bool literal |
| 66 | --> tests/ui/needless_bool_assign.rs:77:5 | |
| 66 | --> tests/ui/needless_bool_assign.rs:76:5 | |
| 67 | 67 | | |
| 68 | 68 | LL | / if invoke!(must_keep, x, y) { |
| 69 | 69 | LL | | dot_0!(skip) = false; |
src/tools/clippy/tests/ui/needless_late_init.fixed+177-14| ... | ... | @@ -185,25 +185,24 @@ fn does_not_lint() { |
| 185 | 185 | }; |
| 186 | 186 | |
| 187 | 187 | // using tuples would be possible, but not always preferable |
| 188 | let x; | |
| 189 | let y; | |
| 190 | if true { | |
| 191 | x = 1; | |
| 192 | y = 2; | |
| 188 | ||
| 189 | ||
| 190 | let (x, y) = if true { | |
| 191 | //~^ needless_late_init | |
| 192 | (1, 2) | |
| 193 | 193 | } else { |
| 194 | x = 3; | |
| 195 | y = 4; | |
| 196 | } | |
| 194 | (3, 4) | |
| 195 | }; | |
| 197 | 196 | |
| 198 | // could match with a smarter heuristic to avoid multiple assignments | |
| 199 | let x; | |
| 200 | if true { | |
| 197 | ||
| 198 | //~^ needless_late_init | |
| 199 | let x = if true { | |
| 201 | 200 | let mut y = 5; |
| 202 | 201 | y = 6; |
| 203 | x = y; | |
| 202 | y | |
| 204 | 203 | } else { |
| 205 | x = 2; | |
| 206 | } | |
| 204 | 2 | |
| 205 | }; | |
| 207 | 206 | |
| 208 | 207 | let (x, y); |
| 209 | 208 | if true { |
| ... | ... | @@ -299,3 +298,167 @@ fn issue9895() { |
| 299 | 298 | //~^ needless_late_init |
| 300 | 299 | let r = 5; |
| 301 | 300 | } |
| 301 | ||
| 302 | fn if_or_match_in_block_expr() { | |
| 303 | ||
| 304 | //~^ needless_late_init | |
| 305 | let z = if true { | |
| 306 | 1 | |
| 307 | } else { | |
| 308 | 2 | |
| 309 | }; | |
| 310 | } | |
| 311 | ||
| 312 | fn issue16330() { | |
| 313 | // Late init in both if branches, should lint | |
| 314 | ||
| 315 | ||
| 316 | let (a, b) = if true { | |
| 317 | //~^ needless_late_init | |
| 318 | (1, 2) | |
| 319 | } else { | |
| 320 | (3, 4) | |
| 321 | }; | |
| 322 | ||
| 323 | // One of the variables is not late init, should not lint | |
| 324 | let a; | |
| 325 | let mut b = 1; | |
| 326 | let c; | |
| 327 | if true { | |
| 328 | b = 1; | |
| 329 | a = 2; | |
| 330 | c = 3; | |
| 331 | } else { | |
| 332 | b = 6; | |
| 333 | a = 4; | |
| 334 | c = 5; | |
| 335 | } | |
| 336 | ||
| 337 | // One of the variables is defined outside the block, should not lint | |
| 338 | let b; | |
| 339 | { | |
| 340 | let a; | |
| 341 | let c; | |
| 342 | if true { | |
| 343 | b = 1; | |
| 344 | a = 2; | |
| 345 | c = 3; | |
| 346 | } else { | |
| 347 | b = 6; | |
| 348 | a = 4; | |
| 349 | c = 5; | |
| 350 | } | |
| 351 | } | |
| 352 | ||
| 353 | // Late init in all match arms, should lint | |
| 354 | ||
| 355 | ||
| 356 | ||
| 357 | let (a, b, c) = match 1 { | |
| 358 | //~^ needless_late_init | |
| 359 | 1 => { | |
| 360 | (1, 2, 3) | |
| 361 | }, | |
| 362 | _ if false => { | |
| 363 | (4, 5, 6) | |
| 364 | }, | |
| 365 | _ => { | |
| 366 | (7, 8, 9) | |
| 367 | }, | |
| 368 | }; | |
| 369 | ||
| 370 | // Late init in all if branches, should lint | |
| 371 | ||
| 372 | ||
| 373 | ||
| 374 | let (a, b, c) = if true { | |
| 375 | //~^ needless_late_init | |
| 376 | (1, 2, 3) | |
| 377 | } else if false { | |
| 378 | (4, 5, 6) | |
| 379 | } else { | |
| 380 | (7, 8, 9) | |
| 381 | }; | |
| 382 | ||
| 383 | // One of the variables is not assigned in all branches, should not lint | |
| 384 | let a; | |
| 385 | let b; | |
| 386 | let c; | |
| 387 | if true { | |
| 388 | a = 1; | |
| 389 | b = 2; | |
| 390 | c = 3; | |
| 391 | } else if false { | |
| 392 | a = 4; | |
| 393 | c = 6; | |
| 394 | } else { | |
| 395 | a = 7; | |
| 396 | b = 8; | |
| 397 | c = 9; | |
| 398 | } | |
| 399 | ||
| 400 | // One of the variables is assigned multiple times, should not lint | |
| 401 | let mut a; | |
| 402 | let b; | |
| 403 | if true { | |
| 404 | a = 1; | |
| 405 | b = 2; | |
| 406 | a = 3; | |
| 407 | } else { | |
| 408 | a = 4; | |
| 409 | b = 5; | |
| 410 | } | |
| 411 | ||
| 412 | // One of the variables is assigned in a nested block, should not lint | |
| 413 | let a; | |
| 414 | let b; | |
| 415 | if true { | |
| 416 | a = 1; | |
| 417 | b = 2; | |
| 418 | } else { | |
| 419 | a = 4; | |
| 420 | { | |
| 421 | b = 5; | |
| 422 | } | |
| 423 | } | |
| 424 | ||
| 425 | // The order of the variables is different in different branches, should not lint | |
| 426 | let a; | |
| 427 | let b; | |
| 428 | if true { | |
| 429 | a = 1; | |
| 430 | b = 2; | |
| 431 | } else { | |
| 432 | b = 5; | |
| 433 | a = 4; | |
| 434 | } | |
| 435 | ||
| 436 | // Later assignments depend on the earlier ones, should only lint the last ones | |
| 437 | let a; | |
| 438 | let b; | |
| 439 | ||
| 440 | //~^ needless_late_init | |
| 441 | let c = if true { | |
| 442 | a = 1; | |
| 443 | b = a + 1; | |
| 444 | b + 1 | |
| 445 | } else { | |
| 446 | a = 4; | |
| 447 | b = a + 2; | |
| 448 | b + 2 | |
| 449 | }; | |
| 450 | let a; | |
| 451 | let b; | |
| 452 | ||
| 453 | ||
| 454 | let (c, d) = if true { | |
| 455 | //~^ needless_late_init | |
| 456 | a = 1; | |
| 457 | b = a + 1; | |
| 458 | (b + 1, 1) | |
| 459 | } else { | |
| 460 | a = 4; | |
| 461 | b = a + 2; | |
| 462 | (b + 2, 2) | |
| 463 | }; | |
| 464 | } |
src/tools/clippy/tests/ui/needless_late_init.rs+182-1| ... | ... | @@ -188,6 +188,7 @@ fn does_not_lint() { |
| 188 | 188 | let x; |
| 189 | 189 | let y; |
| 190 | 190 | if true { |
| 191 | //~^ needless_late_init | |
| 191 | 192 | x = 1; |
| 192 | 193 | y = 2; |
| 193 | 194 | } else { |
| ... | ... | @@ -195,8 +196,8 @@ fn does_not_lint() { |
| 195 | 196 | y = 4; |
| 196 | 197 | } |
| 197 | 198 | |
| 198 | // could match with a smarter heuristic to avoid multiple assignments | |
| 199 | 199 | let x; |
| 200 | //~^ needless_late_init | |
| 200 | 201 | if true { |
| 201 | 202 | let mut y = 5; |
| 202 | 203 | y = 6; |
| ... | ... | @@ -299,3 +300,183 @@ fn issue9895() { |
| 299 | 300 | //~^ needless_late_init |
| 300 | 301 | (r = 5); |
| 301 | 302 | } |
| 303 | ||
| 304 | fn if_or_match_in_block_expr() { | |
| 305 | let z; | |
| 306 | //~^ needless_late_init | |
| 307 | if true { | |
| 308 | z = 1; | |
| 309 | } else { | |
| 310 | z = 2; | |
| 311 | } | |
| 312 | } | |
| 313 | ||
| 314 | fn issue16330() { | |
| 315 | // Late init in both if branches, should lint | |
| 316 | let a; | |
| 317 | let b; | |
| 318 | if true { | |
| 319 | //~^ needless_late_init | |
| 320 | a = 1; | |
| 321 | b = 2; | |
| 322 | } else { | |
| 323 | a = 3; | |
| 324 | b = 4; | |
| 325 | } | |
| 326 | ||
| 327 | // One of the variables is not late init, should not lint | |
| 328 | let a; | |
| 329 | let mut b = 1; | |
| 330 | let c; | |
| 331 | if true { | |
| 332 | b = 1; | |
| 333 | a = 2; | |
| 334 | c = 3; | |
| 335 | } else { | |
| 336 | b = 6; | |
| 337 | a = 4; | |
| 338 | c = 5; | |
| 339 | } | |
| 340 | ||
| 341 | // One of the variables is defined outside the block, should not lint | |
| 342 | let b; | |
| 343 | { | |
| 344 | let a; | |
| 345 | let c; | |
| 346 | if true { | |
| 347 | b = 1; | |
| 348 | a = 2; | |
| 349 | c = 3; | |
| 350 | } else { | |
| 351 | b = 6; | |
| 352 | a = 4; | |
| 353 | c = 5; | |
| 354 | } | |
| 355 | } | |
| 356 | ||
| 357 | // Late init in all match arms, should lint | |
| 358 | let a; | |
| 359 | let b; | |
| 360 | let c; | |
| 361 | match 1 { | |
| 362 | //~^ needless_late_init | |
| 363 | 1 => { | |
| 364 | a = 1; | |
| 365 | b = 2; | |
| 366 | c = 3; | |
| 367 | }, | |
| 368 | _ if false => { | |
| 369 | a = 4; | |
| 370 | b = 5; | |
| 371 | c = 6; | |
| 372 | }, | |
| 373 | _ => { | |
| 374 | a = 7; | |
| 375 | b = 8; | |
| 376 | c = 9; | |
| 377 | }, | |
| 378 | } | |
| 379 | ||
| 380 | // Late init in all if branches, should lint | |
| 381 | let a; | |
| 382 | let b; | |
| 383 | let c; | |
| 384 | if true { | |
| 385 | //~^ needless_late_init | |
| 386 | a = 1; | |
| 387 | b = 2; | |
| 388 | c = 3; | |
| 389 | } else if false { | |
| 390 | a = 4; | |
| 391 | b = 5; | |
| 392 | c = 6; | |
| 393 | } else { | |
| 394 | a = 7; | |
| 395 | b = 8; | |
| 396 | c = 9; | |
| 397 | } | |
| 398 | ||
| 399 | // One of the variables is not assigned in all branches, should not lint | |
| 400 | let a; | |
| 401 | let b; | |
| 402 | let c; | |
| 403 | if true { | |
| 404 | a = 1; | |
| 405 | b = 2; | |
| 406 | c = 3; | |
| 407 | } else if false { | |
| 408 | a = 4; | |
| 409 | c = 6; | |
| 410 | } else { | |
| 411 | a = 7; | |
| 412 | b = 8; | |
| 413 | c = 9; | |
| 414 | } | |
| 415 | ||
| 416 | // One of the variables is assigned multiple times, should not lint | |
| 417 | let mut a; | |
| 418 | let b; | |
| 419 | if true { | |
| 420 | a = 1; | |
| 421 | b = 2; | |
| 422 | a = 3; | |
| 423 | } else { | |
| 424 | a = 4; | |
| 425 | b = 5; | |
| 426 | } | |
| 427 | ||
| 428 | // One of the variables is assigned in a nested block, should not lint | |
| 429 | let a; | |
| 430 | let b; | |
| 431 | if true { | |
| 432 | a = 1; | |
| 433 | b = 2; | |
| 434 | } else { | |
| 435 | a = 4; | |
| 436 | { | |
| 437 | b = 5; | |
| 438 | } | |
| 439 | } | |
| 440 | ||
| 441 | // The order of the variables is different in different branches, should not lint | |
| 442 | let a; | |
| 443 | let b; | |
| 444 | if true { | |
| 445 | a = 1; | |
| 446 | b = 2; | |
| 447 | } else { | |
| 448 | b = 5; | |
| 449 | a = 4; | |
| 450 | } | |
| 451 | ||
| 452 | // Later assignments depend on the earlier ones, should only lint the last ones | |
| 453 | let a; | |
| 454 | let b; | |
| 455 | let c; | |
| 456 | //~^ needless_late_init | |
| 457 | if true { | |
| 458 | a = 1; | |
| 459 | b = a + 1; | |
| 460 | c = b + 1; | |
| 461 | } else { | |
| 462 | a = 4; | |
| 463 | b = a + 2; | |
| 464 | c = b + 2; | |
| 465 | } | |
| 466 | let a; | |
| 467 | let b; | |
| 468 | let c; | |
| 469 | let d; | |
| 470 | if true { | |
| 471 | //~^ needless_late_init | |
| 472 | a = 1; | |
| 473 | b = a + 1; | |
| 474 | c = b + 1; | |
| 475 | d = 1; | |
| 476 | } else { | |
| 477 | a = 4; | |
| 478 | b = a + 2; | |
| 479 | c = b + 2; | |
| 480 | d = 2; | |
| 481 | } | |
| 482 | } |
src/tools/clippy/tests/ui/needless_late_init.stderr+193-2| ... | ... | @@ -276,7 +276,50 @@ LL ~ }; |
| 276 | 276 | | |
| 277 | 277 | |
| 278 | 278 | error: unneeded late initialization |
| 279 | --> tests/ui/needless_late_init.rs:298:5 | |
| 279 | --> tests/ui/needless_late_init.rs:199:5 | |
| 280 | | | |
| 281 | LL | let x; | |
| 282 | | ^^^^^^ | |
| 283 | | | |
| 284 | help: move the declaration `x` here and remove the assignments from the branches | |
| 285 | | | |
| 286 | LL ~ | |
| 287 | LL | | |
| 288 | LL ~ let x = if true { | |
| 289 | LL | let mut y = 5; | |
| 290 | LL | y = 6; | |
| 291 | LL ~ y | |
| 292 | LL | } else { | |
| 293 | LL ~ 2 | |
| 294 | LL ~ }; | |
| 295 | | | |
| 296 | ||
| 297 | error: unneeded late initialization | |
| 298 | --> tests/ui/needless_late_init.rs:190:5 | |
| 299 | | | |
| 300 | LL | / if true { | |
| 301 | LL | | | |
| 302 | LL | | x = 1; | |
| 303 | LL | | y = 2; | |
| 304 | ... | | |
| 305 | LL | | y = 4; | |
| 306 | LL | | } | |
| 307 | | |_____^ | |
| 308 | | | |
| 309 | help: move the declarations here and remove the assignments from the branches | |
| 310 | | | |
| 311 | LL ~ | |
| 312 | LL ~ | |
| 313 | LL ~ let (x, y) = if true { | |
| 314 | LL | | |
| 315 | LL ~ (1, 2) | |
| 316 | LL | } else { | |
| 317 | LL ~ (3, 4) | |
| 318 | LL ~ }; | |
| 319 | | | |
| 320 | ||
| 321 | error: unneeded late initialization | |
| 322 | --> tests/ui/needless_late_init.rs:299:5 | |
| 280 | 323 | | |
| 281 | 324 | LL | let r; |
| 282 | 325 | | ^^^^^^ created here |
| ... | ... | @@ -291,5 +334,153 @@ LL | |
| 291 | 334 | LL ~ let r = 5; |
| 292 | 335 | | |
| 293 | 336 | |
| 294 | error: aborting due to 17 previous errors | |
| 337 | error: unneeded late initialization | |
| 338 | --> tests/ui/needless_late_init.rs:305:5 | |
| 339 | | | |
| 340 | LL | let z; | |
| 341 | | ^^^^^^ | |
| 342 | | | |
| 343 | help: move the declaration `z` here and remove the assignments from the branches | |
| 344 | | | |
| 345 | LL ~ | |
| 346 | LL | | |
| 347 | LL ~ let z = if true { | |
| 348 | LL ~ 1 | |
| 349 | LL | } else { | |
| 350 | LL ~ 2 | |
| 351 | LL ~ }; | |
| 352 | | | |
| 353 | ||
| 354 | error: unneeded late initialization | |
| 355 | --> tests/ui/needless_late_init.rs:455:5 | |
| 356 | | | |
| 357 | LL | let c; | |
| 358 | | ^^^^^^ | |
| 359 | | | |
| 360 | help: move the declaration `c` here and remove the assignments from the branches | |
| 361 | | | |
| 362 | LL ~ | |
| 363 | LL | | |
| 364 | LL ~ let c = if true { | |
| 365 | LL | a = 1; | |
| 366 | LL | b = a + 1; | |
| 367 | LL ~ b + 1 | |
| 368 | LL | } else { | |
| 369 | LL | a = 4; | |
| 370 | LL | b = a + 2; | |
| 371 | LL ~ b + 2 | |
| 372 | LL ~ }; | |
| 373 | | | |
| 374 | ||
| 375 | error: unneeded late initialization | |
| 376 | --> tests/ui/needless_late_init.rs:318:5 | |
| 377 | | | |
| 378 | LL | / if true { | |
| 379 | LL | | | |
| 380 | LL | | a = 1; | |
| 381 | LL | | b = 2; | |
| 382 | ... | | |
| 383 | LL | | b = 4; | |
| 384 | LL | | } | |
| 385 | | |_____^ | |
| 386 | | | |
| 387 | help: move the declarations here and remove the assignments from the branches | |
| 388 | | | |
| 389 | LL ~ | |
| 390 | LL ~ | |
| 391 | LL ~ let (a, b) = if true { | |
| 392 | LL | | |
| 393 | LL ~ (1, 2) | |
| 394 | LL | } else { | |
| 395 | LL ~ (3, 4) | |
| 396 | LL ~ }; | |
| 397 | | | |
| 398 | ||
| 399 | error: unneeded late initialization | |
| 400 | --> tests/ui/needless_late_init.rs:361:5 | |
| 401 | | | |
| 402 | LL | / match 1 { | |
| 403 | LL | | | |
| 404 | LL | | 1 => { | |
| 405 | LL | | a = 1; | |
| 406 | ... | | |
| 407 | LL | | }, | |
| 408 | LL | | } | |
| 409 | | |_____^ | |
| 410 | | | |
| 411 | help: move the declarations here and remove the assignments from the `match` arms | |
| 412 | | | |
| 413 | LL ~ | |
| 414 | LL ~ | |
| 415 | LL ~ | |
| 416 | LL ~ let (a, b, c) = match 1 { | |
| 417 | LL | | |
| 418 | LL | 1 => { | |
| 419 | LL ~ (1, 2, 3) | |
| 420 | LL | }, | |
| 421 | LL | _ if false => { | |
| 422 | LL ~ (4, 5, 6) | |
| 423 | LL | }, | |
| 424 | LL | _ => { | |
| 425 | LL ~ (7, 8, 9) | |
| 426 | LL | }, | |
| 427 | LL ~ }; | |
| 428 | | | |
| 429 | ||
| 430 | error: unneeded late initialization | |
| 431 | --> tests/ui/needless_late_init.rs:384:5 | |
| 432 | | | |
| 433 | LL | / if true { | |
| 434 | LL | | | |
| 435 | LL | | a = 1; | |
| 436 | LL | | b = 2; | |
| 437 | ... | | |
| 438 | LL | | c = 9; | |
| 439 | LL | | } | |
| 440 | | |_____^ | |
| 441 | | | |
| 442 | help: move the declarations here and remove the assignments from the branches | |
| 443 | | | |
| 444 | LL ~ | |
| 445 | LL ~ | |
| 446 | LL ~ | |
| 447 | LL ~ let (a, b, c) = if true { | |
| 448 | LL | | |
| 449 | LL ~ (1, 2, 3) | |
| 450 | LL | } else if false { | |
| 451 | LL ~ (4, 5, 6) | |
| 452 | LL | } else { | |
| 453 | LL ~ (7, 8, 9) | |
| 454 | LL ~ }; | |
| 455 | | | |
| 456 | ||
| 457 | error: unneeded late initialization | |
| 458 | --> tests/ui/needless_late_init.rs:470:5 | |
| 459 | | | |
| 460 | LL | / if true { | |
| 461 | LL | | | |
| 462 | LL | | a = 1; | |
| 463 | LL | | b = a + 1; | |
| 464 | ... | | |
| 465 | LL | | d = 2; | |
| 466 | LL | | } | |
| 467 | | |_____^ | |
| 468 | | | |
| 469 | help: move the declarations here and remove the assignments from the branches | |
| 470 | | | |
| 471 | LL ~ | |
| 472 | LL ~ | |
| 473 | LL ~ let (c, d) = if true { | |
| 474 | LL | | |
| 475 | LL | a = 1; | |
| 476 | LL | b = a + 1; | |
| 477 | LL ~ (b + 1, 1) | |
| 478 | LL | } else { | |
| 479 | LL | a = 4; | |
| 480 | LL | b = a + 2; | |
| 481 | LL ~ (b + 2, 2) | |
| 482 | LL ~ }; | |
| 483 | | | |
| 484 | ||
| 485 | error: aborting due to 25 previous errors | |
| 295 | 486 |
src/tools/clippy/tests/ui/ref_patterns.rs+10| ... | ... | @@ -19,4 +19,14 @@ fn use_in_binding() { |
| 19 | 19 | fn use_in_parameter(ref x: i32) {} |
| 20 | 20 | //~^ ref_patterns |
| 21 | 21 | |
| 22 | struct Foo {} | |
| 23 | ||
| 24 | // shouldn't trigger the lint | |
| 25 | #[automatically_derived] | |
| 26 | impl Foo { | |
| 27 | fn foo() { | |
| 28 | if let Some(ref x) = Some(1) {} | |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 22 | 32 | fn main() {} |
src/tools/clippy/tests/ui/std_instead_of_core.fixed+20| ... | ... | @@ -96,3 +96,23 @@ fn issue15579() { |
| 96 | 96 | |
| 97 | 97 | let layout = alloc::Layout::new::<u8>(); |
| 98 | 98 | } |
| 99 | ||
| 100 | #[warn(clippy::std_instead_of_core)] | |
| 101 | fn issue13158_core_io() { | |
| 102 | // items moved from std::io into core::io are stable in an unstable module. | |
| 103 | use std::io::ErrorKind; | |
| 104 | } | |
| 105 | ||
| 106 | #[clippy::msrv = "1.40"] | |
| 107 | fn issue13158_msrv_1_40(_: &dyn std::panic::UnwindSafe) {} | |
| 108 | ||
| 109 | #[clippy::msrv = "1.41"] | |
| 110 | fn issue13158_msrv_1_41(_: &dyn core::panic::UnwindSafe) {} | |
| 111 | //~^ std_instead_of_core | |
| 112 | ||
| 113 | #[clippy::msrv = "1.80"] | |
| 114 | fn issue13158_msrv_1_80(_: &dyn std::error::Error) {} | |
| 115 | ||
| 116 | #[clippy::msrv = "1.81"] | |
| 117 | fn issue13158_msrv_1_81(_: &dyn core::error::Error) {} | |
| 118 | //~^ std_instead_of_core |
src/tools/clippy/tests/ui/std_instead_of_core.rs+20| ... | ... | @@ -96,3 +96,23 @@ fn issue15579() { |
| 96 | 96 | |
| 97 | 97 | let layout = alloc::Layout::new::<u8>(); |
| 98 | 98 | } |
| 99 | ||
| 100 | #[warn(clippy::std_instead_of_core)] | |
| 101 | fn issue13158_core_io() { | |
| 102 | // items moved from std::io into core::io are stable in an unstable module. | |
| 103 | use std::io::ErrorKind; | |
| 104 | } | |
| 105 | ||
| 106 | #[clippy::msrv = "1.40"] | |
| 107 | fn issue13158_msrv_1_40(_: &dyn std::panic::UnwindSafe) {} | |
| 108 | ||
| 109 | #[clippy::msrv = "1.41"] | |
| 110 | fn issue13158_msrv_1_41(_: &dyn std::panic::UnwindSafe) {} | |
| 111 | //~^ std_instead_of_core | |
| 112 | ||
| 113 | #[clippy::msrv = "1.80"] | |
| 114 | fn issue13158_msrv_1_80(_: &dyn std::error::Error) {} | |
| 115 | ||
| 116 | #[clippy::msrv = "1.81"] | |
| 117 | fn issue13158_msrv_1_81(_: &dyn std::error::Error) {} | |
| 118 | //~^ std_instead_of_core |
src/tools/clippy/tests/ui/std_instead_of_core.stderr+13-1| ... | ... | @@ -97,5 +97,17 @@ error: used import from `std` instead of `core` |
| 97 | 97 | LL | fn msrv_1_77(_: std::net::IpAddr) {} |
| 98 | 98 | | ^^^ help: consider importing the item from `core`: `core` |
| 99 | 99 | |
| 100 | error: aborting due to 15 previous errors | |
| 100 | error: used import from `std` instead of `core` | |
| 101 | --> tests/ui/std_instead_of_core.rs:110:33 | |
| 102 | | | |
| 103 | LL | fn issue13158_msrv_1_41(_: &dyn std::panic::UnwindSafe) {} | |
| 104 | | ^^^ help: consider importing the item from `core`: `core` | |
| 105 | ||
| 106 | error: used import from `std` instead of `core` | |
| 107 | --> tests/ui/std_instead_of_core.rs:117:33 | |
| 108 | | | |
| 109 | LL | fn issue13158_msrv_1_81(_: &dyn std::error::Error) {} | |
| 110 | | ^^^ help: consider importing the item from `core`: `core` | |
| 111 | ||
| 112 | error: aborting due to 17 previous errors | |
| 101 | 113 |
src/tools/clippy/tests/ui/std_instead_of_core_unfixable.rs+11| ... | ... | @@ -14,3 +14,14 @@ fn issue15143() { |
| 14 | 14 | //~^ std_instead_of_core |
| 15 | 15 | //~| std_instead_of_alloc |
| 16 | 16 | } |
| 17 | ||
| 18 | #[rustfmt::skip] | |
| 19 | fn pr16964() { | |
| 20 | use std::{ | |
| 21 | borrow::Cow, | |
| 22 | //~^ std_instead_of_alloc | |
| 23 | collections::BTreeSet, | |
| 24 | //~^ std_instead_of_alloc | |
| 25 | ffi::OsString, | |
| 26 | }; | |
| 27 | } |
src/tools/clippy/tests/ui/std_instead_of_core_unfixable.stderr+17-1| ... | ... | @@ -26,5 +26,21 @@ LL | use std::{error::Error, vec::Vec, fs::File}; |
| 26 | 26 | = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` |
| 27 | 27 | = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` |
| 28 | 28 | |
| 29 | error: aborting due to 3 previous errors | |
| 29 | error: used import from `std` instead of `alloc` | |
| 30 | --> tests/ui/std_instead_of_core_unfixable.rs:21:17 | |
| 31 | | | |
| 32 | LL | borrow::Cow, | |
| 33 | | ^^^ | |
| 34 | | | |
| 35 | = help: consider importing the item from `alloc` | |
| 36 | ||
| 37 | error: used import from `std` instead of `alloc` | |
| 38 | --> tests/ui/std_instead_of_core_unfixable.rs:23:22 | |
| 39 | | | |
| 40 | LL | collections::BTreeSet, | |
| 41 | | ^^^^^^^^ | |
| 42 | | | |
| 43 | = help: consider importing the item from `alloc` | |
| 44 | ||
| 45 | error: aborting due to 5 previous errors | |
| 30 | 46 |
src/tools/clippy/tests/ui/uninit_vec.rs+122| ... | ... | @@ -205,3 +205,125 @@ fn main() { |
| 205 | 205 | } |
| 206 | 206 | } |
| 207 | 207 | } |
| 208 | ||
| 209 | mod issue_11715 { | |
| 210 | use std::mem::MaybeUninit; | |
| 211 | #[cfg(target_pointer_width = "64")] | |
| 212 | const HUGE: usize = 4_294_967_296; | |
| 213 | #[cfg(target_pointer_width = "32")] | |
| 214 | const HUGE: usize = 268_435_455; | |
| 215 | ||
| 216 | fn large_maybeuninit_vec_ice() { | |
| 217 | let mut v: Vec<[MaybeUninit<u64>; HUGE]> = Vec::with_capacity(1); | |
| 218 | unsafe { v.set_len(1) }; | |
| 219 | } | |
| 220 | ||
| 221 | fn large_u8_vec_ice() { | |
| 222 | let mut v: Vec<[u8; HUGE]> = Vec::with_capacity(1); | |
| 223 | //~^ uninit_vec | |
| 224 | unsafe { v.set_len(1) }; | |
| 225 | } | |
| 226 | ||
| 227 | fn large_nested_maybeuninit_vec_ice() { | |
| 228 | let mut v: Vec<[[MaybeUninit<u64>; HUGE]; 2]> = Vec::with_capacity(1); | |
| 229 | unsafe { v.set_len(1) }; | |
| 230 | } | |
| 231 | ||
| 232 | struct HeavyWrapperSafe([MaybeUninit<u64>; HUGE]); | |
| 233 | fn large_struct_maybeuninit_vec_ice() { | |
| 234 | let mut v: Vec<HeavyWrapperSafe> = Vec::with_capacity(1); | |
| 235 | unsafe { v.set_len(1) }; | |
| 236 | } | |
| 237 | ||
| 238 | struct HeavyWrapperUnsafe([u8; HUGE]); | |
| 239 | fn large_struct_u8_vec_ice() { | |
| 240 | let mut v: Vec<HeavyWrapperUnsafe> = Vec::with_capacity(1); | |
| 241 | //~^ uninit_vec | |
| 242 | unsafe { v.set_len(1) }; | |
| 243 | } | |
| 244 | ||
| 245 | #[allow(clippy::large_enum_variant)] | |
| 246 | enum HeavyEnum { | |
| 247 | A([MaybeUninit<u64>; HUGE]), | |
| 248 | B, | |
| 249 | } | |
| 250 | fn large_enum_vec_ice() { | |
| 251 | let mut v: Vec<HeavyEnum> = Vec::with_capacity(1); | |
| 252 | //~^ uninit_vec | |
| 253 | unsafe { v.set_len(1) }; | |
| 254 | } | |
| 255 | ||
| 256 | enum Uninhabited {} | |
| 257 | fn uninhabited_enum() { | |
| 258 | let mut v: Vec<Uninhabited> = Vec::with_capacity(1); | |
| 259 | unsafe { v.set_len(1) }; | |
| 260 | } | |
| 261 | ||
| 262 | enum SingleVariant { | |
| 263 | OnlyOne, | |
| 264 | } | |
| 265 | fn single_variant_enum() { | |
| 266 | let mut v: Vec<SingleVariant> = Vec::with_capacity(1); | |
| 267 | unsafe { v.set_len(1) }; | |
| 268 | } | |
| 269 | ||
| 270 | enum OneVariantU8 { | |
| 271 | ThisOne([u8; HUGE]), | |
| 272 | } | |
| 273 | fn one_variant_u8() { | |
| 274 | let mut v: Vec<OneVariantU8> = Vec::with_capacity(1); | |
| 275 | //~^ uninit_vec | |
| 276 | unsafe { v.set_len(1) }; | |
| 277 | } | |
| 278 | ||
| 279 | enum OneVariantMaybeUninit { | |
| 280 | ThisOne([MaybeUninit<u8>; HUGE]), | |
| 281 | } | |
| 282 | fn one_variant_maybe_uninit() { | |
| 283 | let mut v: Vec<OneVariantMaybeUninit> = Vec::with_capacity(1); | |
| 284 | unsafe { v.set_len(1) }; | |
| 285 | } | |
| 286 | ||
| 287 | fn generic_vec_lints<T>() { | |
| 288 | let mut v: Vec<T> = Vec::with_capacity(1); | |
| 289 | //~^ uninit_vec | |
| 290 | unsafe { v.set_len(1) }; | |
| 291 | } | |
| 292 | ||
| 293 | fn generic_vec_maybeuninit<T>() { | |
| 294 | let mut v: Vec<MaybeUninit<T>> = Vec::with_capacity(1); | |
| 295 | unsafe { v.set_len(1) }; | |
| 296 | } | |
| 297 | ||
| 298 | trait Assoc { | |
| 299 | type Item; | |
| 300 | } | |
| 301 | fn projection_vec_lints<T: Assoc>() { | |
| 302 | let mut v: Vec<<T as Assoc>::Item> = Vec::with_capacity(1); | |
| 303 | //~^ uninit_vec | |
| 304 | unsafe { v.set_len(1) }; | |
| 305 | } | |
| 306 | ||
| 307 | struct Concrete; | |
| 308 | impl Assoc for Concrete { | |
| 309 | type Item = MaybeUninit<u8>; | |
| 310 | } | |
| 311 | fn normalized_projection_vec_ok() { | |
| 312 | let mut v: Vec<<Concrete as Assoc>::Item> = Vec::with_capacity(1); | |
| 313 | unsafe { v.set_len(1) }; | |
| 314 | } | |
| 315 | ||
| 316 | enum E<T, U> { | |
| 317 | Foo(MaybeUninit<T>), | |
| 318 | Bar(U), | |
| 319 | } | |
| 320 | fn enum_uninhabited_zst() { | |
| 321 | let mut v: Vec<E<u8, core::convert::Infallible>> = Vec::with_capacity(1); | |
| 322 | unsafe { v.set_len(1) }; | |
| 323 | } | |
| 324 | fn enum_uninhabited_non_zst() { | |
| 325 | let mut v: Vec<E<u8, (u8, core::convert::Infallible)>> = Vec::with_capacity(1); | |
| 326 | //~^ uninit_vec | |
| 327 | unsafe { v.set_len(1) }; | |
| 328 | } | |
| 329 | } |
src/tools/clippy/tests/ui/uninit_vec.stderr+78-1| ... | ... | @@ -159,5 +159,82 @@ LL | vec.set_len(1); |
| 159 | 159 | | |
| 160 | 160 | = help: initialize the buffer or wrap the content in `MaybeUninit` |
| 161 | 161 | |
| 162 | error: aborting due to 15 previous errors | |
| 162 | error: calling `set_len()` immediately after reserving a buffer creates uninitialized values | |
| 163 | --> tests/ui/uninit_vec.rs:222:9 | |
| 164 | | | |
| 165 | LL | let mut v: Vec<[u8; HUGE]> = Vec::with_capacity(1); | |
| 166 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 167 | LL | | |
| 168 | LL | unsafe { v.set_len(1) }; | |
| 169 | | ^^^^^^^^^^^^ | |
| 170 | | | |
| 171 | = help: initialize the buffer or wrap the content in `MaybeUninit` | |
| 172 | ||
| 173 | error: calling `set_len()` immediately after reserving a buffer creates uninitialized values | |
| 174 | --> tests/ui/uninit_vec.rs:240:9 | |
| 175 | | | |
| 176 | LL | let mut v: Vec<HeavyWrapperUnsafe> = Vec::with_capacity(1); | |
| 177 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 178 | LL | | |
| 179 | LL | unsafe { v.set_len(1) }; | |
| 180 | | ^^^^^^^^^^^^ | |
| 181 | | | |
| 182 | = help: initialize the buffer or wrap the content in `MaybeUninit` | |
| 183 | ||
| 184 | error: calling `set_len()` immediately after reserving a buffer creates uninitialized values | |
| 185 | --> tests/ui/uninit_vec.rs:251:9 | |
| 186 | | | |
| 187 | LL | let mut v: Vec<HeavyEnum> = Vec::with_capacity(1); | |
| 188 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 189 | LL | | |
| 190 | LL | unsafe { v.set_len(1) }; | |
| 191 | | ^^^^^^^^^^^^ | |
| 192 | | | |
| 193 | = help: initialize the buffer or wrap the content in `MaybeUninit` | |
| 194 | ||
| 195 | error: calling `set_len()` immediately after reserving a buffer creates uninitialized values | |
| 196 | --> tests/ui/uninit_vec.rs:274:9 | |
| 197 | | | |
| 198 | LL | let mut v: Vec<OneVariantU8> = Vec::with_capacity(1); | |
| 199 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 200 | LL | | |
| 201 | LL | unsafe { v.set_len(1) }; | |
| 202 | | ^^^^^^^^^^^^ | |
| 203 | | | |
| 204 | = help: initialize the buffer or wrap the content in `MaybeUninit` | |
| 205 | ||
| 206 | error: calling `set_len()` immediately after reserving a buffer creates uninitialized values | |
| 207 | --> tests/ui/uninit_vec.rs:288:9 | |
| 208 | | | |
| 209 | LL | let mut v: Vec<T> = Vec::with_capacity(1); | |
| 210 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 211 | LL | | |
| 212 | LL | unsafe { v.set_len(1) }; | |
| 213 | | ^^^^^^^^^^^^ | |
| 214 | | | |
| 215 | = help: initialize the buffer or wrap the content in `MaybeUninit` | |
| 216 | ||
| 217 | error: calling `set_len()` immediately after reserving a buffer creates uninitialized values | |
| 218 | --> tests/ui/uninit_vec.rs:302:9 | |
| 219 | | | |
| 220 | LL | let mut v: Vec<<T as Assoc>::Item> = Vec::with_capacity(1); | |
| 221 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 222 | LL | | |
| 223 | LL | unsafe { v.set_len(1) }; | |
| 224 | | ^^^^^^^^^^^^ | |
| 225 | | | |
| 226 | = help: initialize the buffer or wrap the content in `MaybeUninit` | |
| 227 | ||
| 228 | error: calling `set_len()` immediately after reserving a buffer creates uninitialized values | |
| 229 | --> tests/ui/uninit_vec.rs:325:9 | |
| 230 | | | |
| 231 | LL | let mut v: Vec<E<u8, (u8, core::convert::Infallible)>> = Vec::with_capacity(1); | |
| 232 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 233 | LL | | |
| 234 | LL | unsafe { v.set_len(1) }; | |
| 235 | | ^^^^^^^^^^^^ | |
| 236 | | | |
| 237 | = help: initialize the buffer or wrap the content in `MaybeUninit` | |
| 238 | ||
| 239 | error: aborting due to 22 previous errors | |
| 163 | 240 |
src/tools/clippy/tests/ui/unnecessary_box_returns.rs+17| ... | ... | @@ -71,6 +71,23 @@ impl HasHuge { |
| 71 | 71 | } |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | // don't lint (issue #17202): the size of `[T; N]` depends on a const generic parameter | |
| 75 | fn const_generic_array<const N: usize, T>(value: Box<[T; N]>) -> Box<[T; N]> { | |
| 76 | value | |
| 77 | } | |
| 78 | ||
| 79 | // don't lint (issue #17202): the size of `[T; 10]` depends on the generic element type | |
| 80 | fn generic_element_array<T>(value: Box<[T; 10]>) -> Box<[T; 10]> { | |
| 81 | value | |
| 82 | } | |
| 83 | ||
| 84 | // lint: the size of `Vec<T>` is known regardless of the generic element type | |
| 85 | #[expect(clippy::box_collection)] | |
| 86 | fn generic_vec<T>(value: Box<Vec<T>>) -> Box<Vec<T>> { | |
| 87 | //~^ unnecessary_box_returns | |
| 88 | value | |
| 89 | } | |
| 90 | ||
| 74 | 91 | fn main() { |
| 75 | 92 | // don't lint: this is a closure |
| 76 | 93 | let a = || -> Box<usize> { Box::new(5) }; |
src/tools/clippy/tests/ui/unnecessary_box_returns.stderr+9-1| ... | ... | @@ -32,5 +32,13 @@ LL | fn _bxed_foo() -> Box<Foo> { |
| 32 | 32 | | |
| 33 | 33 | = help: changing this also requires a change to the return expressions in this function |
| 34 | 34 | |
| 35 | error: aborting due to 4 previous errors | |
| 35 | error: boxed return of the sized type `std::vec::Vec<T>` | |
| 36 | --> tests/ui/unnecessary_box_returns.rs:86:42 | |
| 37 | | | |
| 38 | LL | fn generic_vec<T>(value: Box<Vec<T>>) -> Box<Vec<T>> { | |
| 39 | | ^^^^^^^^^^^ help: try: `std::vec::Vec<T>` | |
| 40 | | | |
| 41 | = help: changing this also requires a change to the return expressions in this function | |
| 42 | ||
| 43 | error: aborting due to 5 previous errors | |
| 36 | 44 |
src/tools/clippy/tests/ui/unnecessary_cast.fixed+24| ... | ... | @@ -1,7 +1,9 @@ |
| 1 | 1 | //@aux-build:extern_fake_libc.rs |
| 2 | #![feature(const_trait_impl, const_ops)] | |
| 2 | 3 | #![warn(clippy::unnecessary_cast)] |
| 3 | 4 | #![allow( |
| 4 | 5 | clippy::borrow_as_ptr, |
| 6 | clippy::identity_op, | |
| 5 | 7 | clippy::multiple_bound_locations, |
| 6 | 8 | clippy::no_effect, |
| 7 | 9 | clippy::nonstandard_macro_braces, |
| ... | ... | @@ -656,3 +658,25 @@ fn issue16475() -> *const u8 { |
| 656 | 658 | //~^ unnecessary_cast |
| 657 | 659 | } |
| 658 | 660 | } |
| 661 | ||
| 662 | // Make sure that the calculated values aren't changed by the fixes. | |
| 663 | const _: () = { | |
| 664 | use std::convert::identity; | |
| 665 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64).overflowing_shr(1_u32).0); | |
| 666 | //~^ unnecessary_cast | |
| 667 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64).overflowing_shr(1_u32).0); | |
| 668 | //~^ unnecessary_cast | |
| 669 | assert!(0 == (!identity(!0_u64) as u64).overflowing_shr(1_u32).0); | |
| 670 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64 + 0).overflowing_shr(1_u32).0); | |
| 671 | //~^ unnecessary_cast | |
| 672 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!(0_u64 + 0)).overflowing_shr(1_u32).0); | |
| 673 | //~^ unnecessary_cast | |
| 674 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!((0 + 0) as u64)).overflowing_shr(1_u32).0); | |
| 675 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0_u64).overflowing_shr(1_u32).0); | |
| 676 | //~^ unnecessary_cast | |
| 677 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0_u64) as u64).overflowing_shr(1_u32).0); | |
| 678 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0_u64)).overflowing_shr(1_u32).0); | |
| 679 | //~^ unnecessary_cast | |
| 680 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0_u64 + 0).overflowing_shr(1_u32).0); | |
| 681 | //~^ unnecessary_cast | |
| 682 | }; |
src/tools/clippy/tests/ui/unnecessary_cast.rs+24| ... | ... | @@ -1,7 +1,9 @@ |
| 1 | 1 | //@aux-build:extern_fake_libc.rs |
| 2 | #![feature(const_trait_impl, const_ops)] | |
| 2 | 3 | #![warn(clippy::unnecessary_cast)] |
| 3 | 4 | #![allow( |
| 4 | 5 | clippy::borrow_as_ptr, |
| 6 | clippy::identity_op, | |
| 5 | 7 | clippy::multiple_bound_locations, |
| 6 | 8 | clippy::no_effect, |
| 7 | 9 | clippy::nonstandard_macro_braces, |
| ... | ... | @@ -656,3 +658,25 @@ fn issue16475() -> *const u8 { |
| 656 | 658 | //~^ unnecessary_cast |
| 657 | 659 | } |
| 658 | 660 | } |
| 661 | ||
| 662 | // Make sure that the calculated values aren't changed by the fixes. | |
| 663 | const _: () = { | |
| 664 | use std::convert::identity; | |
| 665 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64).overflowing_shr(1_u32).0); | |
| 666 | //~^ unnecessary_cast | |
| 667 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64 as u64).overflowing_shr(1_u32).0); | |
| 668 | //~^ unnecessary_cast | |
| 669 | assert!(0 == (!identity(!0_u64) as u64).overflowing_shr(1_u32).0); | |
| 670 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64 + 0).overflowing_shr(1_u32).0); | |
| 671 | //~^ unnecessary_cast | |
| 672 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!(0 as u64 + 0)).overflowing_shr(1_u32).0); | |
| 673 | //~^ unnecessary_cast | |
| 674 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!((0 + 0) as u64)).overflowing_shr(1_u32).0); | |
| 675 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64).overflowing_shr(1_u32).0); | |
| 676 | //~^ unnecessary_cast | |
| 677 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0_u64) as u64).overflowing_shr(1_u32).0); | |
| 678 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0 as u64)).overflowing_shr(1_u32).0); | |
| 679 | //~^ unnecessary_cast | |
| 680 | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64 + 0).overflowing_shr(1_u32).0); | |
| 681 | //~^ unnecessary_cast | |
| 682 | }; |
src/tools/clippy/tests/ui/unnecessary_cast.stderr+108-66| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error: casting raw pointers to the same type and constness is unnecessary (`*const T` -> `*const T`) |
| 2 | --> tests/ui/unnecessary_cast.rs:19:5 | |
| 2 | --> tests/ui/unnecessary_cast.rs:21:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | ptr as *const T |
| 5 | 5 | | ^^^^^^^^^^^^^^^ help: try: `ptr` |
| ... | ... | @@ -8,388 +8,430 @@ LL | ptr as *const T |
| 8 | 8 | = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` |
| 9 | 9 | |
| 10 | 10 | error: casting integer literal to `i32` is unnecessary |
| 11 | --> tests/ui/unnecessary_cast.rs:55:5 | |
| 11 | --> tests/ui/unnecessary_cast.rs:57:5 | |
| 12 | 12 | | |
| 13 | 13 | LL | 1i32 as i32; |
| 14 | 14 | | ^^^^^^^^^^^ help: try: `1_i32` |
| 15 | 15 | |
| 16 | 16 | error: casting float literal to `f32` is unnecessary |
| 17 | --> tests/ui/unnecessary_cast.rs:57:5 | |
| 17 | --> tests/ui/unnecessary_cast.rs:59:5 | |
| 18 | 18 | | |
| 19 | 19 | LL | 1f32 as f32; |
| 20 | 20 | | ^^^^^^^^^^^ help: try: `1_f32` |
| 21 | 21 | |
| 22 | 22 | error: casting to the same type is unnecessary (`bool` -> `bool`) |
| 23 | --> tests/ui/unnecessary_cast.rs:59:5 | |
| 23 | --> tests/ui/unnecessary_cast.rs:61:5 | |
| 24 | 24 | | |
| 25 | 25 | LL | false as bool; |
| 26 | 26 | | ^^^^^^^^^^^^^ help: try: `false` |
| 27 | 27 | |
| 28 | 28 | error: casting integer literal to `i32` is unnecessary |
| 29 | --> tests/ui/unnecessary_cast.rs:63:5 | |
| 29 | --> tests/ui/unnecessary_cast.rs:65:5 | |
| 30 | 30 | | |
| 31 | 31 | LL | -1_i32 as i32; |
| 32 | 32 | | ^^^^^^^^^^^^^ help: try: `-1_i32` |
| 33 | 33 | |
| 34 | 34 | error: casting integer literal to `i32` is unnecessary |
| 35 | --> tests/ui/unnecessary_cast.rs:65:5 | |
| 35 | --> tests/ui/unnecessary_cast.rs:67:5 | |
| 36 | 36 | | |
| 37 | 37 | LL | - 1_i32 as i32; |
| 38 | 38 | | ^^^^^^^^^^^^^^ help: try: `- 1_i32` |
| 39 | 39 | |
| 40 | 40 | error: casting float literal to `f32` is unnecessary |
| 41 | --> tests/ui/unnecessary_cast.rs:67:5 | |
| 41 | --> tests/ui/unnecessary_cast.rs:69:5 | |
| 42 | 42 | | |
| 43 | 43 | LL | -1f32 as f32; |
| 44 | 44 | | ^^^^^^^^^^^^ help: try: `-1_f32` |
| 45 | 45 | |
| 46 | 46 | error: casting integer literal to `i32` is unnecessary |
| 47 | --> tests/ui/unnecessary_cast.rs:69:5 | |
| 47 | --> tests/ui/unnecessary_cast.rs:71:5 | |
| 48 | 48 | | |
| 49 | 49 | LL | 1_i32 as i32; |
| 50 | 50 | | ^^^^^^^^^^^^ help: try: `1_i32` |
| 51 | 51 | |
| 52 | 52 | error: casting float literal to `f32` is unnecessary |
| 53 | --> tests/ui/unnecessary_cast.rs:71:5 | |
| 53 | --> tests/ui/unnecessary_cast.rs:73:5 | |
| 54 | 54 | | |
| 55 | 55 | LL | 1_f32 as f32; |
| 56 | 56 | | ^^^^^^^^^^^^ help: try: `1_f32` |
| 57 | 57 | |
| 58 | 58 | error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) |
| 59 | --> tests/ui/unnecessary_cast.rs:74:22 | |
| 59 | --> tests/ui/unnecessary_cast.rs:76:22 | |
| 60 | 60 | | |
| 61 | 61 | LL | let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8; |
| 62 | 62 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` |
| 63 | 63 | |
| 64 | 64 | error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) |
| 65 | --> tests/ui/unnecessary_cast.rs:77:5 | |
| 65 | --> tests/ui/unnecessary_cast.rs:79:5 | |
| 66 | 66 | | |
| 67 | 67 | LL | [1u8, 2].as_ptr() as *const u8; |
| 68 | 68 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` |
| 69 | 69 | |
| 70 | 70 | error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`) |
| 71 | --> tests/ui/unnecessary_cast.rs:80:5 | |
| 71 | --> tests/ui/unnecessary_cast.rs:82:5 | |
| 72 | 72 | | |
| 73 | 73 | LL | [1u8, 2].as_mut_ptr() as *mut u8; |
| 74 | 74 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()` |
| 75 | 75 | |
| 76 | 76 | error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) |
| 77 | --> tests/ui/unnecessary_cast.rs:92:5 | |
| 77 | --> tests/ui/unnecessary_cast.rs:94:5 | |
| 78 | 78 | | |
| 79 | 79 | LL | owo::<u32>([1u32].as_ptr()) as *const u32; |
| 80 | 80 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::<u32>([1u32].as_ptr())` |
| 81 | 81 | |
| 82 | 82 | error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) |
| 83 | --> tests/ui/unnecessary_cast.rs:94:5 | |
| 83 | --> tests/ui/unnecessary_cast.rs:96:5 | |
| 84 | 84 | | |
| 85 | 85 | LL | uwu::<u32, u8>([1u32].as_ptr()) as *const u8; |
| 86 | 86 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u8>([1u32].as_ptr())` |
| 87 | 87 | |
| 88 | 88 | error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) |
| 89 | --> tests/ui/unnecessary_cast.rs:97:5 | |
| 89 | --> tests/ui/unnecessary_cast.rs:99:5 | |
| 90 | 90 | | |
| 91 | 91 | LL | uwu::<u32, u32>([1u32].as_ptr()) as *const u32; |
| 92 | 92 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u32>([1u32].as_ptr())` |
| 93 | 93 | |
| 94 | 94 | error: casting to the same type is unnecessary (`u32` -> `u32`) |
| 95 | --> tests/ui/unnecessary_cast.rs:133:5 | |
| 95 | --> tests/ui/unnecessary_cast.rs:135:5 | |
| 96 | 96 | | |
| 97 | 97 | LL | aaa() as u32; |
| 98 | 98 | | ^^^^^^^^^^^^ help: try: `aaa()` |
| 99 | 99 | |
| 100 | 100 | error: casting to the same type is unnecessary (`u32` -> `u32`) |
| 101 | --> tests/ui/unnecessary_cast.rs:136:5 | |
| 101 | --> tests/ui/unnecessary_cast.rs:138:5 | |
| 102 | 102 | | |
| 103 | 103 | LL | x as u32; |
| 104 | 104 | | ^^^^^^^^ help: try: `x` |
| 105 | 105 | |
| 106 | 106 | error: casting to the same type is unnecessary (`u32` -> `u32`) |
| 107 | --> tests/ui/unnecessary_cast.rs:138:5 | |
| 107 | --> tests/ui/unnecessary_cast.rs:140:5 | |
| 108 | 108 | | |
| 109 | 109 | LL | bbb() as u32; |
| 110 | 110 | | ^^^^^^^^^^^^ help: try: `bbb()` |
| 111 | 111 | |
| 112 | 112 | error: casting to the same type is unnecessary (`u32` -> `u32`) |
| 113 | --> tests/ui/unnecessary_cast.rs:141:5 | |
| 113 | --> tests/ui/unnecessary_cast.rs:143:5 | |
| 114 | 114 | | |
| 115 | 115 | LL | x as u32; |
| 116 | 116 | | ^^^^^^^^ help: try: `x` |
| 117 | 117 | |
| 118 | 118 | error: casting integer literal to `f32` is unnecessary |
| 119 | --> tests/ui/unnecessary_cast.rs:174:9 | |
| 119 | --> tests/ui/unnecessary_cast.rs:176:9 | |
| 120 | 120 | | |
| 121 | 121 | LL | 100 as f32; |
| 122 | 122 | | ^^^^^^^^^^ help: try: `100_f32` |
| 123 | 123 | |
| 124 | 124 | error: casting integer literal to `f64` is unnecessary |
| 125 | --> tests/ui/unnecessary_cast.rs:176:9 | |
| 125 | --> tests/ui/unnecessary_cast.rs:178:9 | |
| 126 | 126 | | |
| 127 | 127 | LL | 100 as f64; |
| 128 | 128 | | ^^^^^^^^^^ help: try: `100_f64` |
| 129 | 129 | |
| 130 | 130 | error: casting integer literal to `f64` is unnecessary |
| 131 | --> tests/ui/unnecessary_cast.rs:178:9 | |
| 131 | --> tests/ui/unnecessary_cast.rs:180:9 | |
| 132 | 132 | | |
| 133 | 133 | LL | 100_i32 as f64; |
| 134 | 134 | | ^^^^^^^^^^^^^^ help: try: `100_f64` |
| 135 | 135 | |
| 136 | 136 | error: casting integer literal to `f32` is unnecessary |
| 137 | --> tests/ui/unnecessary_cast.rs:180:17 | |
| 137 | --> tests/ui/unnecessary_cast.rs:182:17 | |
| 138 | 138 | | |
| 139 | 139 | LL | let _ = -100 as f32; |
| 140 | 140 | | ^^^^^^^^^^^ help: try: `-100_f32` |
| 141 | 141 | |
| 142 | 142 | error: casting integer literal to `f64` is unnecessary |
| 143 | --> tests/ui/unnecessary_cast.rs:182:17 | |
| 143 | --> tests/ui/unnecessary_cast.rs:184:17 | |
| 144 | 144 | | |
| 145 | 145 | LL | let _ = -100 as f64; |
| 146 | 146 | | ^^^^^^^^^^^ help: try: `-100_f64` |
| 147 | 147 | |
| 148 | 148 | error: casting integer literal to `f64` is unnecessary |
| 149 | --> tests/ui/unnecessary_cast.rs:184:17 | |
| 149 | --> tests/ui/unnecessary_cast.rs:186:17 | |
| 150 | 150 | | |
| 151 | 151 | LL | let _ = -100_i32 as f64; |
| 152 | 152 | | ^^^^^^^^^^^^^^^ help: try: `-100_f64` |
| 153 | 153 | |
| 154 | 154 | error: casting float literal to `f32` is unnecessary |
| 155 | --> tests/ui/unnecessary_cast.rs:186:9 | |
| 155 | --> tests/ui/unnecessary_cast.rs:188:9 | |
| 156 | 156 | | |
| 157 | 157 | LL | 100. as f32; |
| 158 | 158 | | ^^^^^^^^^^^ help: try: `100_f32` |
| 159 | 159 | |
| 160 | 160 | error: casting float literal to `f64` is unnecessary |
| 161 | --> tests/ui/unnecessary_cast.rs:188:9 | |
| 161 | --> tests/ui/unnecessary_cast.rs:190:9 | |
| 162 | 162 | | |
| 163 | 163 | LL | 100. as f64; |
| 164 | 164 | | ^^^^^^^^^^^ help: try: `100_f64` |
| 165 | 165 | |
| 166 | 166 | error: casting integer literal to `u32` is unnecessary |
| 167 | --> tests/ui/unnecessary_cast.rs:201:9 | |
| 167 | --> tests/ui/unnecessary_cast.rs:203:9 | |
| 168 | 168 | | |
| 169 | 169 | LL | 1 as u32; |
| 170 | 170 | | ^^^^^^^^ help: try: `1_u32` |
| 171 | 171 | |
| 172 | 172 | error: casting integer literal to `i32` is unnecessary |
| 173 | --> tests/ui/unnecessary_cast.rs:203:9 | |
| 173 | --> tests/ui/unnecessary_cast.rs:205:9 | |
| 174 | 174 | | |
| 175 | 175 | LL | 0x10 as i32; |
| 176 | 176 | | ^^^^^^^^^^^ help: try: `0x10_i32` |
| 177 | 177 | |
| 178 | 178 | error: casting integer literal to `usize` is unnecessary |
| 179 | --> tests/ui/unnecessary_cast.rs:205:9 | |
| 179 | --> tests/ui/unnecessary_cast.rs:207:9 | |
| 180 | 180 | | |
| 181 | 181 | LL | 0b10 as usize; |
| 182 | 182 | | ^^^^^^^^^^^^^ help: try: `0b10_usize` |
| 183 | 183 | |
| 184 | 184 | error: casting integer literal to `u16` is unnecessary |
| 185 | --> tests/ui/unnecessary_cast.rs:207:9 | |
| 185 | --> tests/ui/unnecessary_cast.rs:209:9 | |
| 186 | 186 | | |
| 187 | 187 | LL | 0o73 as u16; |
| 188 | 188 | | ^^^^^^^^^^^ help: try: `0o73_u16` |
| 189 | 189 | |
| 190 | 190 | error: casting integer literal to `u32` is unnecessary |
| 191 | --> tests/ui/unnecessary_cast.rs:209:9 | |
| 191 | --> tests/ui/unnecessary_cast.rs:211:9 | |
| 192 | 192 | | |
| 193 | 193 | LL | 1_000_000_000 as u32; |
| 194 | 194 | | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` |
| 195 | 195 | |
| 196 | 196 | error: casting float literal to `f64` is unnecessary |
| 197 | --> tests/ui/unnecessary_cast.rs:212:9 | |
| 197 | --> tests/ui/unnecessary_cast.rs:214:9 | |
| 198 | 198 | | |
| 199 | 199 | LL | 1.0 as f64; |
| 200 | 200 | | ^^^^^^^^^^ help: try: `1.0_f64` |
| 201 | 201 | |
| 202 | 202 | error: casting float literal to `f32` is unnecessary |
| 203 | --> tests/ui/unnecessary_cast.rs:214:9 | |
| 203 | --> tests/ui/unnecessary_cast.rs:216:9 | |
| 204 | 204 | | |
| 205 | 205 | LL | 0.5 as f32; |
| 206 | 206 | | ^^^^^^^^^^ help: try: `0.5_f32` |
| 207 | 207 | |
| 208 | 208 | error: casting integer literal to `i32` is unnecessary |
| 209 | --> tests/ui/unnecessary_cast.rs:219:17 | |
| 209 | --> tests/ui/unnecessary_cast.rs:221:17 | |
| 210 | 210 | | |
| 211 | 211 | LL | let _ = -1 as i32; |
| 212 | 212 | | ^^^^^^^^^ help: try: `-1_i32` |
| 213 | 213 | |
| 214 | 214 | error: casting float literal to `f32` is unnecessary |
| 215 | --> tests/ui/unnecessary_cast.rs:221:17 | |
| 215 | --> tests/ui/unnecessary_cast.rs:223:17 | |
| 216 | 216 | | |
| 217 | 217 | LL | let _ = -1.0 as f32; |
| 218 | 218 | | ^^^^^^^^^^^ help: try: `-1.0_f32` |
| 219 | 219 | |
| 220 | 220 | error: casting to the same type is unnecessary (`i32` -> `i32`) |
| 221 | --> tests/ui/unnecessary_cast.rs:228:18 | |
| 221 | --> tests/ui/unnecessary_cast.rs:230:18 | |
| 222 | 222 | | |
| 223 | 223 | LL | let _ = &(x as i32); |
| 224 | 224 | | ^^^^^^^^^^ help: try: `{ x }` |
| 225 | 225 | |
| 226 | 226 | error: casting integer literal to `i32` is unnecessary |
| 227 | --> tests/ui/unnecessary_cast.rs:235:22 | |
| 227 | --> tests/ui/unnecessary_cast.rs:237:22 | |
| 228 | 228 | | |
| 229 | 229 | LL | let _: i32 = -(1) as i32; |
| 230 | 230 | | ^^^^^^^^^^^ help: try: `-1_i32` |
| 231 | 231 | |
| 232 | 232 | error: casting integer literal to `i64` is unnecessary |
| 233 | --> tests/ui/unnecessary_cast.rs:238:22 | |
| 233 | --> tests/ui/unnecessary_cast.rs:240:22 | |
| 234 | 234 | | |
| 235 | 235 | LL | let _: i64 = -(1) as i64; |
| 236 | 236 | | ^^^^^^^^^^^ help: try: `-1_i64` |
| 237 | 237 | |
| 238 | 238 | error: casting float literal to `f64` is unnecessary |
| 239 | --> tests/ui/unnecessary_cast.rs:246:22 | |
| 239 | --> tests/ui/unnecessary_cast.rs:248:22 | |
| 240 | 240 | | |
| 241 | 241 | LL | let _: f64 = (-8.0 as f64).exp(); |
| 242 | 242 | | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)` |
| 243 | 243 | |
| 244 | 244 | error: casting float literal to `f64` is unnecessary |
| 245 | --> tests/ui/unnecessary_cast.rs:249:23 | |
| 245 | --> tests/ui/unnecessary_cast.rs:251:23 | |
| 246 | 246 | | |
| 247 | 247 | LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior |
| 248 | 248 | | ^^^^^^^^^^^^ help: try: `8.0_f64` |
| 249 | 249 | |
| 250 | 250 | error: casting to the same type is unnecessary (`f32` -> `f32`) |
| 251 | --> tests/ui/unnecessary_cast.rs:259:20 | |
| 251 | --> tests/ui/unnecessary_cast.rs:261:20 | |
| 252 | 252 | | |
| 253 | 253 | LL | let _num = foo() as f32; |
| 254 | 254 | | ^^^^^^^^^^^^ help: try: `foo()` |
| 255 | 255 | |
| 256 | 256 | error: casting to the same type is unnecessary (`usize` -> `usize`) |
| 257 | --> tests/ui/unnecessary_cast.rs:270:9 | |
| 257 | --> tests/ui/unnecessary_cast.rs:272:9 | |
| 258 | 258 | | |
| 259 | 259 | LL | (*x as usize).pow(2) |
| 260 | 260 | | ^^^^^^^^^^^^^ help: try: `(*x)` |
| 261 | 261 | |
| 262 | 262 | error: casting to the same type is unnecessary (`usize` -> `usize`) |
| 263 | --> tests/ui/unnecessary_cast.rs:278:31 | |
| 263 | --> tests/ui/unnecessary_cast.rs:280:31 | |
| 264 | 264 | | |
| 265 | 265 | LL | assert_eq!(vec.len(), x as usize); |
| 266 | 266 | | ^^^^^^^^^^ help: try: `x` |
| 267 | 267 | |
| 268 | 268 | error: casting to the same type is unnecessary (`i64` -> `i64`) |
| 269 | --> tests/ui/unnecessary_cast.rs:281:17 | |
| 269 | --> tests/ui/unnecessary_cast.rs:283:17 | |
| 270 | 270 | | |
| 271 | 271 | LL | let _ = (5i32 as i64 as i64).abs(); |
| 272 | 272 | | ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)` |
| 273 | 273 | |
| 274 | 274 | error: casting to the same type is unnecessary (`i64` -> `i64`) |
| 275 | --> tests/ui/unnecessary_cast.rs:284:17 | |
| 275 | --> tests/ui/unnecessary_cast.rs:286:17 | |
| 276 | 276 | | |
| 277 | 277 | LL | let _ = 5i32 as i64 as i64; |
| 278 | 278 | | ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64` |
| 279 | 279 | |
| 280 | 280 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 281 | --> tests/ui/unnecessary_cast.rs:563:24 | |
| 281 | --> tests/ui/unnecessary_cast.rs:565:24 | |
| 282 | 282 | | |
| 283 | 283 | LL | id::<Out<f64>>(1.0_f64.pow_like(2) as f64 * &a).view(); |
| 284 | 284 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` |
| 285 | 285 | |
| 286 | 286 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 287 | --> tests/ui/unnecessary_cast.rs:567:26 | |
| 287 | --> tests/ui/unnecessary_cast.rs:569:26 | |
| 288 | 288 | | |
| 289 | 289 | LL | s.id::<Out<f64>>(1.0_f64.pow_like(2) as f64 * &a).view(); |
| 290 | 290 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` |
| 291 | 291 | |
| 292 | 292 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 293 | --> tests/ui/unnecessary_cast.rs:571:26 | |
| 293 | --> tests/ui/unnecessary_cast.rs:573:26 | |
| 294 | 294 | | |
| 295 | 295 | LL | wrap::<Out<f64>>(1.0_f64.pow_like(2) as f64 * &a).inner.view(); |
| 296 | 296 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` |
| 297 | 297 | |
| 298 | 298 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 299 | --> tests/ui/unnecessary_cast.rs:575:28 | |
| 299 | --> tests/ui/unnecessary_cast.rs:577:28 | |
| 300 | 300 | | |
| 301 | 301 | LL | s.wrap::<Out<f64>>(1.0_f64.pow_like(2) as f64 * &a).inner.view(); |
| 302 | 302 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` |
| 303 | 303 | |
| 304 | 304 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 305 | --> tests/ui/unnecessary_cast.rs:591:31 | |
| 305 | --> tests/ui/unnecessary_cast.rs:593:31 | |
| 306 | 306 | | |
| 307 | 307 | LL | let _ = receiver.take(1.0_f64.pow_like_single_impl(2) as f64).abs(); |
| 308 | 308 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)` |
| 309 | 309 | |
| 310 | 310 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 311 | --> tests/ui/unnecessary_cast.rs:601:20 | |
| 311 | --> tests/ui/unnecessary_cast.rs:603:20 | |
| 312 | 312 | | |
| 313 | 313 | LL | let _ = id(1.0_f64.powi(2) as f64).abs(); |
| 314 | 314 | | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` |
| 315 | 315 | |
| 316 | 316 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 317 | --> tests/ui/unnecessary_cast.rs:604:22 | |
| 317 | --> tests/ui/unnecessary_cast.rs:606:22 | |
| 318 | 318 | | |
| 319 | 319 | LL | let _ = wrap(1.0_f64.powi(2) as f64).inner.abs(); |
| 320 | 320 | | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` |
| 321 | 321 | |
| 322 | 322 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 323 | --> tests/ui/unnecessary_cast.rs:607:22 | |
| 323 | --> tests/ui/unnecessary_cast.rs:609:22 | |
| 324 | 324 | | |
| 325 | 325 | LL | let _ = s.id(1.0_f64.powi(2) as f64).abs(); |
| 326 | 326 | | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` |
| 327 | 327 | |
| 328 | 328 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 329 | --> tests/ui/unnecessary_cast.rs:610:24 | |
| 329 | --> tests/ui/unnecessary_cast.rs:612:24 | |
| 330 | 330 | | |
| 331 | 331 | LL | let _ = s.wrap(1.0_f64.powi(2) as f64).inner.abs(); |
| 332 | 332 | | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` |
| 333 | 333 | |
| 334 | 334 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 335 | --> tests/ui/unnecessary_cast.rs:613:20 | |
| 335 | --> tests/ui/unnecessary_cast.rs:615:20 | |
| 336 | 336 | | |
| 337 | 337 | LL | let _ = id(1.0_f64.powi(2) as f64 * &a); |
| 338 | 338 | | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` |
| 339 | 339 | |
| 340 | 340 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 341 | --> tests/ui/unnecessary_cast.rs:616:22 | |
| 341 | --> tests/ui/unnecessary_cast.rs:618:22 | |
| 342 | 342 | | |
| 343 | 343 | LL | let _ = s.id(1.0_f64.powi(2) as f64 * &a); |
| 344 | 344 | | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` |
| 345 | 345 | |
| 346 | 346 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 347 | --> tests/ui/unnecessary_cast.rs:629:17 | |
| 347 | --> tests/ui/unnecessary_cast.rs:631:17 | |
| 348 | 348 | | |
| 349 | 349 | LL | let _ = 1.0_f64.pow_like(0.5) as f64; |
| 350 | 350 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(0.5)` |
| 351 | 351 | |
| 352 | 352 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 353 | --> tests/ui/unnecessary_cast.rs:632:17 | |
| 353 | --> tests/ui/unnecessary_cast.rs:634:17 | |
| 354 | 354 | | |
| 355 | 355 | LL | let _ = 1.0_f64.pow_like(2) as f64; |
| 356 | 356 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)` |
| 357 | 357 | |
| 358 | 358 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 359 | --> tests/ui/unnecessary_cast.rs:635:17 | |
| 359 | --> tests/ui/unnecessary_cast.rs:637:17 | |
| 360 | 360 | | |
| 361 | 361 | LL | let _ = (1.0_f64.powi(2) as f64).abs(); |
| 362 | 362 | | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)` |
| 363 | 363 | |
| 364 | 364 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 365 | --> tests/ui/unnecessary_cast.rs:638:17 | |
| 365 | --> tests/ui/unnecessary_cast.rs:640:17 | |
| 366 | 366 | | |
| 367 | 367 | LL | let _ = ((Y + 2) as f64).abs(); |
| 368 | 368 | | ^^^^^^^^^^^^^^^^ help: try: `((Y + 2))` |
| 369 | 369 | |
| 370 | 370 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 371 | --> tests/ui/unnecessary_cast.rs:641:18 | |
| 371 | --> tests/ui/unnecessary_cast.rs:643:18 | |
| 372 | 372 | | |
| 373 | 373 | LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + 1.0_f64).abs(); |
| 374 | 374 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)` |
| 375 | 375 | |
| 376 | 376 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 377 | --> tests/ui/unnecessary_cast.rs:644:18 | |
| 377 | --> tests/ui/unnecessary_cast.rs:646:18 | |
| 378 | 378 | | |
| 379 | 379 | LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + ONE).abs(); |
| 380 | 380 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)` |
| 381 | 381 | |
| 382 | 382 | error: casting to the same type is unnecessary (`f64` -> `f64`) |
| 383 | --> tests/ui/unnecessary_cast.rs:647:18 | |
| 383 | --> tests/ui/unnecessary_cast.rs:649:18 | |
| 384 | 384 | | |
| 385 | 385 | LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + one).abs(); |
| 386 | 386 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)` |
| 387 | 387 | |
| 388 | 388 | error: casting raw pointers to the same type and constness is unnecessary (`*const *const u8` -> `*const *const u8`) |
| 389 | --> tests/ui/unnecessary_cast.rs:655:10 | |
| 389 | --> tests/ui/unnecessary_cast.rs:657:10 | |
| 390 | 390 | | |
| 391 | 391 | LL | *(&NONE as *const _ as *const _ as *const *const u8 as *const *const u8) |
| 392 | 392 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&NONE as *const _ as *const _ as *const *const u8)` |
| 393 | 393 | |
| 394 | error: aborting due to 65 previous errors | |
| 394 | error: casting integer literal to `u64` is unnecessary | |
| 395 | --> tests/ui/unnecessary_cast.rs:665:45 | |
| 396 | | | |
| 397 | LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64).overflowing_shr(1_u32).0); | |
| 398 | | ^^^^^^^^^^^ help: try: `(!0_u64)` | |
| 399 | ||
| 400 | error: casting to the same type is unnecessary (`u64` -> `u64`) | |
| 401 | --> tests/ui/unnecessary_cast.rs:667:45 | |
| 402 | | | |
| 403 | LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64 as u64).overflowing_shr(1_u32).0); | |
| 404 | | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)` | |
| 405 | ||
| 406 | error: casting integer literal to `u64` is unnecessary | |
| 407 | --> tests/ui/unnecessary_cast.rs:670:46 | |
| 408 | | | |
| 409 | LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64 + 0).overflowing_shr(1_u32).0); | |
| 410 | | ^^^^^^^^^ help: try: `!0_u64` | |
| 411 | ||
| 412 | error: casting integer literal to `u64` is unnecessary | |
| 413 | --> tests/ui/unnecessary_cast.rs:672:48 | |
| 414 | | | |
| 415 | LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!(0 as u64 + 0)).overflowing_shr(1_u32).0); | |
| 416 | | ^^^^^^^^ help: try: `0_u64` | |
| 417 | ||
| 418 | error: casting integer literal to `u64` is unnecessary | |
| 419 | --> tests/ui/unnecessary_cast.rs:675:54 | |
| 420 | | | |
| 421 | LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64).overflowing_shr(1_u32).0); | |
| 422 | | ^^^^^^^^^ help: try: `!0_u64` | |
| 423 | ||
| 424 | error: casting integer literal to `u64` is unnecessary | |
| 425 | --> tests/ui/unnecessary_cast.rs:678:56 | |
| 426 | | | |
| 427 | LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0 as u64)).overflowing_shr(1_u32).0); | |
| 428 | | ^^^^^^^^ help: try: `0_u64` | |
| 429 | ||
| 430 | error: casting integer literal to `u64` is unnecessary | |
| 431 | --> tests/ui/unnecessary_cast.rs:680:54 | |
| 432 | | | |
| 433 | LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64 + 0).overflowing_shr(1_u32).0); | |
| 434 | | ^^^^^^^^^ help: try: `!0_u64` | |
| 435 | ||
| 436 | error: aborting due to 72 previous errors | |
| 395 | 437 |
src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed+12| ... | ... | @@ -240,6 +240,18 @@ fn main() { |
| 240 | 240 | let _: Result<usize, usize> = res.or_else(|err| Ok(err)); |
| 241 | 241 | } |
| 242 | 242 | |
| 243 | fn issue11672() { | |
| 244 | // needs turbofish to disambiguate | |
| 245 | let _ = true.then_some::<&[u8]>({ &[] }); | |
| 246 | //~^ unnecessary_lazy_evaluations | |
| 247 | } | |
| 248 | ||
| 249 | fn issue11672_as() { | |
| 250 | // Return type annotation helps type inference and removing it can break code | |
| 251 | let _ = None.get_or_insert({ &[] } as &[u8]); | |
| 252 | //~^ unnecessary_lazy_evaluations | |
| 253 | } | |
| 254 | ||
| 243 | 255 | #[allow(unused)] |
| 244 | 256 | fn issue9485() { |
| 245 | 257 | // should not lint, is in proc macro |
src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs+12| ... | ... | @@ -240,6 +240,18 @@ fn main() { |
| 240 | 240 | let _: Result<usize, usize> = res.or_else(|err| Ok(err)); |
| 241 | 241 | } |
| 242 | 242 | |
| 243 | fn issue11672() { | |
| 244 | // needs turbofish to disambiguate | |
| 245 | let _ = true.then(|| -> &[u8] { &[] }); | |
| 246 | //~^ unnecessary_lazy_evaluations | |
| 247 | } | |
| 248 | ||
| 249 | fn issue11672_as() { | |
| 250 | // Return type annotation helps type inference and removing it can break code | |
| 251 | let _ = None.get_or_insert_with(|| -> &[u8] { &[] }); | |
| 252 | //~^ unnecessary_lazy_evaluations | |
| 253 | } | |
| 254 | ||
| 243 | 255 | #[allow(unused)] |
| 244 | 256 | fn issue9485() { |
| 245 | 257 | // should not lint, is in proc macro |
src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr+48-24| ... | ... | @@ -484,7 +484,31 @@ LL + or(Ok(ext_str.some_field)); |
| 484 | 484 | | |
| 485 | 485 | |
| 486 | 486 | error: unnecessary closure used with `bool::then` |
| 487 | --> tests/ui/unnecessary_lazy_eval.rs:259:14 | |
| 487 | --> tests/ui/unnecessary_lazy_eval.rs:245:13 | |
| 488 | | | |
| 489 | LL | let _ = true.then(|| -> &[u8] { &[] }); | |
| 490 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 491 | | | |
| 492 | help: use `then_some` instead | |
| 493 | | | |
| 494 | LL - let _ = true.then(|| -> &[u8] { &[] }); | |
| 495 | LL + let _ = true.then_some::<&[u8]>({ &[] }); | |
| 496 | | | |
| 497 | ||
| 498 | error: unnecessary closure used to substitute value for `Option::None` | |
| 499 | --> tests/ui/unnecessary_lazy_eval.rs:251:13 | |
| 500 | | | |
| 501 | LL | let _ = None.get_or_insert_with(|| -> &[u8] { &[] }); | |
| 502 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 503 | | | |
| 504 | help: use `get_or_insert` instead | |
| 505 | | | |
| 506 | LL - let _ = None.get_or_insert_with(|| -> &[u8] { &[] }); | |
| 507 | LL + let _ = None.get_or_insert({ &[] } as &[u8]); | |
| 508 | | | |
| 509 | ||
| 510 | error: unnecessary closure used with `bool::then` | |
| 511 | --> tests/ui/unnecessary_lazy_eval.rs:271:14 | |
| 488 | 512 | | |
| 489 | 513 | LL | let _x = false.then(|| i32::MAX + 1); |
| 490 | 514 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -496,7 +520,7 @@ LL + let _x = false.then_some(i32::MAX + 1); |
| 496 | 520 | | |
| 497 | 521 | |
| 498 | 522 | error: unnecessary closure used with `bool::then` |
| 499 | --> tests/ui/unnecessary_lazy_eval.rs:261:14 | |
| 523 | --> tests/ui/unnecessary_lazy_eval.rs:273:14 | |
| 500 | 524 | | |
| 501 | 525 | LL | let _x = false.then(|| i32::MAX * 2); |
| 502 | 526 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -508,7 +532,7 @@ LL + let _x = false.then_some(i32::MAX * 2); |
| 508 | 532 | | |
| 509 | 533 | |
| 510 | 534 | error: unnecessary closure used with `bool::then` |
| 511 | --> tests/ui/unnecessary_lazy_eval.rs:263:14 | |
| 535 | --> tests/ui/unnecessary_lazy_eval.rs:275:14 | |
| 512 | 536 | | |
| 513 | 537 | LL | let _x = false.then(|| i32::MAX - 1); |
| 514 | 538 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -520,7 +544,7 @@ LL + let _x = false.then_some(i32::MAX - 1); |
| 520 | 544 | | |
| 521 | 545 | |
| 522 | 546 | error: unnecessary closure used with `bool::then` |
| 523 | --> tests/ui/unnecessary_lazy_eval.rs:265:14 | |
| 547 | --> tests/ui/unnecessary_lazy_eval.rs:277:14 | |
| 524 | 548 | | |
| 525 | 549 | LL | let _x = false.then(|| i32::MIN - 1); |
| 526 | 550 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -532,7 +556,7 @@ LL + let _x = false.then_some(i32::MIN - 1); |
| 532 | 556 | | |
| 533 | 557 | |
| 534 | 558 | error: unnecessary closure used with `bool::then` |
| 535 | --> tests/ui/unnecessary_lazy_eval.rs:267:14 | |
| 559 | --> tests/ui/unnecessary_lazy_eval.rs:279:14 | |
| 536 | 560 | | |
| 537 | 561 | LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); |
| 538 | 562 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -544,7 +568,7 @@ LL + let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2); |
| 544 | 568 | | |
| 545 | 569 | |
| 546 | 570 | error: unnecessary closure used with `bool::then` |
| 547 | --> tests/ui/unnecessary_lazy_eval.rs:269:14 | |
| 571 | --> tests/ui/unnecessary_lazy_eval.rs:281:14 | |
| 548 | 572 | | |
| 549 | 573 | LL | let _x = false.then(|| 255u8 << 7); |
| 550 | 574 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -556,7 +580,7 @@ LL + let _x = false.then_some(255u8 << 7); |
| 556 | 580 | | |
| 557 | 581 | |
| 558 | 582 | error: unnecessary closure used with `bool::then` |
| 559 | --> tests/ui/unnecessary_lazy_eval.rs:271:14 | |
| 583 | --> tests/ui/unnecessary_lazy_eval.rs:283:14 | |
| 560 | 584 | | |
| 561 | 585 | LL | let _x = false.then(|| 255u8 << 8); |
| 562 | 586 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -568,7 +592,7 @@ LL + let _x = false.then_some(255u8 << 8); |
| 568 | 592 | | |
| 569 | 593 | |
| 570 | 594 | error: unnecessary closure used with `bool::then` |
| 571 | --> tests/ui/unnecessary_lazy_eval.rs:273:14 | |
| 595 | --> tests/ui/unnecessary_lazy_eval.rs:285:14 | |
| 572 | 596 | | |
| 573 | 597 | LL | let _x = false.then(|| 255u8 >> 8); |
| 574 | 598 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -580,7 +604,7 @@ LL + let _x = false.then_some(255u8 >> 8); |
| 580 | 604 | | |
| 581 | 605 | |
| 582 | 606 | error: unnecessary closure used with `bool::then` |
| 583 | --> tests/ui/unnecessary_lazy_eval.rs:276:14 | |
| 607 | --> tests/ui/unnecessary_lazy_eval.rs:288:14 | |
| 584 | 608 | | |
| 585 | 609 | LL | let _x = false.then(|| i32::MAX + -1); |
| 586 | 610 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -592,7 +616,7 @@ LL + let _x = false.then_some(i32::MAX + -1); |
| 592 | 616 | | |
| 593 | 617 | |
| 594 | 618 | error: unnecessary closure used with `bool::then` |
| 595 | --> tests/ui/unnecessary_lazy_eval.rs:278:14 | |
| 619 | --> tests/ui/unnecessary_lazy_eval.rs:290:14 | |
| 596 | 620 | | |
| 597 | 621 | LL | let _x = false.then(|| -i32::MAX); |
| 598 | 622 | | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -604,7 +628,7 @@ LL + let _x = false.then_some(-i32::MAX); |
| 604 | 628 | | |
| 605 | 629 | |
| 606 | 630 | error: unnecessary closure used with `bool::then` |
| 607 | --> tests/ui/unnecessary_lazy_eval.rs:280:14 | |
| 631 | --> tests/ui/unnecessary_lazy_eval.rs:292:14 | |
| 608 | 632 | | |
| 609 | 633 | LL | let _x = false.then(|| -i32::MIN); |
| 610 | 634 | | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -616,7 +640,7 @@ LL + let _x = false.then_some(-i32::MIN); |
| 616 | 640 | | |
| 617 | 641 | |
| 618 | 642 | error: unnecessary closure used with `bool::then` |
| 619 | --> tests/ui/unnecessary_lazy_eval.rs:283:14 | |
| 643 | --> tests/ui/unnecessary_lazy_eval.rs:295:14 | |
| 620 | 644 | | |
| 621 | 645 | LL | let _x = false.then(|| 255 >> -7); |
| 622 | 646 | | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -628,7 +652,7 @@ LL + let _x = false.then_some(255 >> -7); |
| 628 | 652 | | |
| 629 | 653 | |
| 630 | 654 | error: unnecessary closure used with `bool::then` |
| 631 | --> tests/ui/unnecessary_lazy_eval.rs:285:14 | |
| 655 | --> tests/ui/unnecessary_lazy_eval.rs:297:14 | |
| 632 | 656 | | |
| 633 | 657 | LL | let _x = false.then(|| 255 << -1); |
| 634 | 658 | | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -640,7 +664,7 @@ LL + let _x = false.then_some(255 << -1); |
| 640 | 664 | | |
| 641 | 665 | |
| 642 | 666 | error: unnecessary closure used with `bool::then` |
| 643 | --> tests/ui/unnecessary_lazy_eval.rs:287:14 | |
| 667 | --> tests/ui/unnecessary_lazy_eval.rs:299:14 | |
| 644 | 668 | | |
| 645 | 669 | LL | let _x = false.then(|| 1 / 0); |
| 646 | 670 | | ^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -652,7 +676,7 @@ LL + let _x = false.then_some(1 / 0); |
| 652 | 676 | | |
| 653 | 677 | |
| 654 | 678 | error: unnecessary closure used with `bool::then` |
| 655 | --> tests/ui/unnecessary_lazy_eval.rs:289:14 | |
| 679 | --> tests/ui/unnecessary_lazy_eval.rs:301:14 | |
| 656 | 680 | | |
| 657 | 681 | LL | let _x = false.then(|| x << -1); |
| 658 | 682 | | ^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -664,7 +688,7 @@ LL + let _x = false.then_some(x << -1); |
| 664 | 688 | | |
| 665 | 689 | |
| 666 | 690 | error: unnecessary closure used with `bool::then` |
| 667 | --> tests/ui/unnecessary_lazy_eval.rs:291:14 | |
| 691 | --> tests/ui/unnecessary_lazy_eval.rs:303:14 | |
| 668 | 692 | | |
| 669 | 693 | LL | let _x = false.then(|| x << 2); |
| 670 | 694 | | ^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -676,7 +700,7 @@ LL + let _x = false.then_some(x << 2); |
| 676 | 700 | | |
| 677 | 701 | |
| 678 | 702 | error: unnecessary closure used with `bool::then` |
| 679 | --> tests/ui/unnecessary_lazy_eval.rs:301:14 | |
| 703 | --> tests/ui/unnecessary_lazy_eval.rs:313:14 | |
| 680 | 704 | | |
| 681 | 705 | LL | let _x = false.then(|| x / 0); |
| 682 | 706 | | ^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -688,7 +712,7 @@ LL + let _x = false.then_some(x / 0); |
| 688 | 712 | | |
| 689 | 713 | |
| 690 | 714 | error: unnecessary closure used with `bool::then` |
| 691 | --> tests/ui/unnecessary_lazy_eval.rs:303:14 | |
| 715 | --> tests/ui/unnecessary_lazy_eval.rs:315:14 | |
| 692 | 716 | | |
| 693 | 717 | LL | let _x = false.then(|| x % 0); |
| 694 | 718 | | ^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -700,7 +724,7 @@ LL + let _x = false.then_some(x % 0); |
| 700 | 724 | | |
| 701 | 725 | |
| 702 | 726 | error: unnecessary closure used with `bool::then` |
| 703 | --> tests/ui/unnecessary_lazy_eval.rs:306:14 | |
| 727 | --> tests/ui/unnecessary_lazy_eval.rs:318:14 | |
| 704 | 728 | | |
| 705 | 729 | LL | let _x = false.then(|| 1 / -1); |
| 706 | 730 | | ^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -712,7 +736,7 @@ LL + let _x = false.then_some(1 / -1); |
| 712 | 736 | | |
| 713 | 737 | |
| 714 | 738 | error: unnecessary closure used with `bool::then` |
| 715 | --> tests/ui/unnecessary_lazy_eval.rs:308:14 | |
| 739 | --> tests/ui/unnecessary_lazy_eval.rs:320:14 | |
| 716 | 740 | | |
| 717 | 741 | LL | let _x = false.then(|| i32::MIN / -1); |
| 718 | 742 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -724,7 +748,7 @@ LL + let _x = false.then_some(i32::MIN / -1); |
| 724 | 748 | | |
| 725 | 749 | |
| 726 | 750 | error: unnecessary closure used with `bool::then` |
| 727 | --> tests/ui/unnecessary_lazy_eval.rs:311:14 | |
| 751 | --> tests/ui/unnecessary_lazy_eval.rs:323:14 | |
| 728 | 752 | | |
| 729 | 753 | LL | let _x = false.then(|| i32::MIN / 0); |
| 730 | 754 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -736,7 +760,7 @@ LL + let _x = false.then_some(i32::MIN / 0); |
| 736 | 760 | | |
| 737 | 761 | |
| 738 | 762 | error: unnecessary closure used with `bool::then` |
| 739 | --> tests/ui/unnecessary_lazy_eval.rs:313:14 | |
| 763 | --> tests/ui/unnecessary_lazy_eval.rs:325:14 | |
| 740 | 764 | | |
| 741 | 765 | LL | let _x = false.then(|| 4 / 2); |
| 742 | 766 | | ^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -748,7 +772,7 @@ LL + let _x = false.then_some(4 / 2); |
| 748 | 772 | | |
| 749 | 773 | |
| 750 | 774 | error: unnecessary closure used with `bool::then` |
| 751 | --> tests/ui/unnecessary_lazy_eval.rs:321:14 | |
| 775 | --> tests/ui/unnecessary_lazy_eval.rs:333:14 | |
| 752 | 776 | | |
| 753 | 777 | LL | let _x = false.then(|| f1 + f2); |
| 754 | 778 | | ^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -759,5 +783,5 @@ LL - let _x = false.then(|| f1 + f2); |
| 759 | 783 | LL + let _x = false.then_some(f1 + f2); |
| 760 | 784 | | |
| 761 | 785 | |
| 762 | error: aborting due to 63 previous errors | |
| 786 | error: aborting due to 65 previous errors | |
| 763 | 787 |
src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs+2-6| ... | ... | @@ -12,6 +12,8 @@ fn main() { |
| 12 | 12 | // fix will break type inference |
| 13 | 13 | let _ = Ok(1).unwrap_or_else(|()| 2); |
| 14 | 14 | //~^ unnecessary_lazy_evaluations |
| 15 | let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 }); | |
| 16 | //~^ unnecessary_lazy_evaluations | |
| 15 | 17 | |
| 16 | 18 | mod e { |
| 17 | 19 | pub struct E; |
| ... | ... | @@ -26,9 +28,3 @@ fn main() { |
| 26 | 28 | let arr = [(Some(1),)]; |
| 27 | 29 | Some(&0).and_then(|&i| arr[i].0); |
| 28 | 30 | } |
| 29 | ||
| 30 | fn issue11672() { | |
| 31 | // Return type annotation helps type inference and removing it can break code | |
| 32 | let _ = true.then(|| -> &[u8] { &[] }); | |
| 33 | //~^ unnecessary_lazy_evaluations | |
| 34 | } |
src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr+14-14| ... | ... | @@ -13,7 +13,19 @@ LL + let _ = Ok(1).unwrap_or(2); |
| 13 | 13 | | |
| 14 | 14 | |
| 15 | 15 | error: unnecessary closure used to substitute value for `Result::Err` |
| 16 | --> tests/ui/unnecessary_lazy_eval_unfixable.rs:19:13 | |
| 16 | --> tests/ui/unnecessary_lazy_eval_unfixable.rs:15:13 | |
| 17 | | | |
| 18 | LL | let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 }); | |
| 19 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 20 | | | |
| 21 | help: use `unwrap_or` instead | |
| 22 | | | |
| 23 | LL - let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 }); | |
| 24 | LL + let _ = Ok(1).unwrap_or({ 2 } as i32); | |
| 25 | | | |
| 26 | ||
| 27 | error: unnecessary closure used to substitute value for `Result::Err` | |
| 28 | --> tests/ui/unnecessary_lazy_eval_unfixable.rs:21:13 | |
| 17 | 29 | | |
| 18 | 30 | LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); |
| 19 | 31 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -25,7 +37,7 @@ LL + let _ = Ok(1).unwrap_or(2); |
| 25 | 37 | | |
| 26 | 38 | |
| 27 | 39 | error: unnecessary closure used to substitute value for `Result::Err` |
| 28 | --> tests/ui/unnecessary_lazy_eval_unfixable.rs:22:13 | |
| 40 | --> tests/ui/unnecessary_lazy_eval_unfixable.rs:24:13 | |
| 29 | 41 | | |
| 30 | 42 | LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); |
| 31 | 43 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -36,17 +48,5 @@ LL - let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); |
| 36 | 48 | LL + let _ = Ok(1).unwrap_or(2); |
| 37 | 49 | | |
| 38 | 50 | |
| 39 | error: unnecessary closure used with `bool::then` | |
| 40 | --> tests/ui/unnecessary_lazy_eval_unfixable.rs:32:13 | |
| 41 | | | |
| 42 | LL | let _ = true.then(|| -> &[u8] { &[] }); | |
| 43 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 44 | | | |
| 45 | help: use `then_some` instead | |
| 46 | | | |
| 47 | LL - let _ = true.then(|| -> &[u8] { &[] }); | |
| 48 | LL + let _ = true.then_some({ &[] }); | |
| 49 | | | |
| 50 | ||
| 51 | 51 | error: aborting due to 4 previous errors |
| 52 | 52 |
src/tools/clippy/tests/ui/unnecessary_sort_by.fixed+4-4| ... | ... | @@ -19,9 +19,9 @@ fn unnecessary_sort_by() { |
| 19 | 19 | //~^ unnecessary_sort_by |
| 20 | 20 | // Reverse examples |
| 21 | 21 | vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow |
| 22 | vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs())); | |
| 22 | vec.sort_by_key(|a| std::cmp::Reverse((a + 5).abs())); | |
| 23 | 23 | //~^ unnecessary_sort_by |
| 24 | vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b))); | |
| 24 | vec.sort_unstable_by_key(|a| std::cmp::Reverse(id(-a))); | |
| 25 | 25 | //~^ unnecessary_sort_by |
| 26 | 26 | // Negative examples (shouldn't be changed) |
| 27 | 27 | let c = &7; |
| ... | ... | @@ -99,9 +99,9 @@ mod issue_6001 { |
| 99 | 99 | args.sort_unstable_by_key(|a| a.name()); |
| 100 | 100 | //~^ unnecessary_sort_by |
| 101 | 101 | // Reverse |
| 102 | args.sort_by_key(|b| std::cmp::Reverse(b.name())); | |
| 102 | args.sort_by_key(|a| std::cmp::Reverse(a.name())); | |
| 103 | 103 | //~^ unnecessary_sort_by |
| 104 | args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name())); | |
| 104 | args.sort_unstable_by_key(|a| std::cmp::Reverse(a.name())); | |
| 105 | 105 | //~^ unnecessary_sort_by |
| 106 | 106 | } |
| 107 | 107 | } |
src/tools/clippy/tests/ui/unnecessary_sort_by.stderr+4-4| ... | ... | @@ -57,7 +57,7 @@ LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); |
| 57 | 57 | help: try |
| 58 | 58 | | |
| 59 | 59 | LL - vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); |
| 60 | LL + vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs())); | |
| 60 | LL + vec.sort_by_key(|a| std::cmp::Reverse((a + 5).abs())); | |
| 61 | 61 | | |
| 62 | 62 | |
| 63 | 63 | error: consider using `sort_unstable_by_key` |
| ... | ... | @@ -69,7 +69,7 @@ LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); |
| 69 | 69 | help: try |
| 70 | 70 | | |
| 71 | 71 | LL - vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); |
| 72 | LL + vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b))); | |
| 72 | LL + vec.sort_unstable_by_key(|a| std::cmp::Reverse(id(-a))); | |
| 73 | 73 | | |
| 74 | 74 | |
| 75 | 75 | error: consider using `sort_by_key` |
| ... | ... | @@ -129,7 +129,7 @@ LL | args.sort_by(|a, b| b.name().cmp(&a.name())); |
| 129 | 129 | help: try |
| 130 | 130 | | |
| 131 | 131 | LL - args.sort_by(|a, b| b.name().cmp(&a.name())); |
| 132 | LL + args.sort_by_key(|b| std::cmp::Reverse(b.name())); | |
| 132 | LL + args.sort_by_key(|a| std::cmp::Reverse(a.name())); | |
| 133 | 133 | | |
| 134 | 134 | |
| 135 | 135 | error: consider using `sort_unstable_by_key` |
| ... | ... | @@ -141,7 +141,7 @@ LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); |
| 141 | 141 | help: try |
| 142 | 142 | | |
| 143 | 143 | LL - args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); |
| 144 | LL + args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name())); | |
| 144 | LL + args.sort_unstable_by_key(|a| std::cmp::Reverse(a.name())); | |
| 145 | 145 | | |
| 146 | 146 | |
| 147 | 147 | error: consider using `sort_by_key` |
src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.fixed+2-2| ... | ... | @@ -15,8 +15,8 @@ fn issue_11524() -> Vec<i32> { |
| 15 | 15 | fn issue_11524_2() -> Vec<i32> { |
| 16 | 16 | let mut vec = vec![1, 2, 3]; |
| 17 | 17 | |
| 18 | // Should lint and suggest `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` | |
| 19 | vec.sort_by_key(|b| core::cmp::Reverse(b + 1)); | |
| 18 | // Should lint and suggest `vec.sort_by_key(|a| core::cmp::Reverse(a + 1));` | |
| 19 | vec.sort_by_key(|a| core::cmp::Reverse(a + 1)); | |
| 20 | 20 | //~^ unnecessary_sort_by |
| 21 | 21 | vec |
| 22 | 22 | } |
src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.rs+1-1| ... | ... | @@ -15,7 +15,7 @@ fn issue_11524() -> Vec<i32> { |
| 15 | 15 | fn issue_11524_2() -> Vec<i32> { |
| 16 | 16 | let mut vec = vec![1, 2, 3]; |
| 17 | 17 | |
| 18 | // Should lint and suggest `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` | |
| 18 | // Should lint and suggest `vec.sort_by_key(|a| core::cmp::Reverse(a + 1));` | |
| 19 | 19 | vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); |
| 20 | 20 | //~^ unnecessary_sort_by |
| 21 | 21 | vec |
src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.stderr+1-1| ... | ... | @@ -21,7 +21,7 @@ LL | vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); |
| 21 | 21 | help: try |
| 22 | 22 | | |
| 23 | 23 | LL - vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); |
| 24 | LL + vec.sort_by_key(|b| core::cmp::Reverse(b + 1)); | |
| 24 | LL + vec.sort_by_key(|a| core::cmp::Reverse(a + 1)); | |
| 25 | 25 | | |
| 26 | 26 | |
| 27 | 27 | error: aborting due to 2 previous errors |
src/tools/clippy/tests/ui/unnecessary_trailing_comma.fixed+1-1| ... | ... | @@ -26,9 +26,9 @@ fn simple() { |
| 26 | 26 | println!{"Foo{{,}}"}; //~ unnecessary_trailing_comma |
| 27 | 27 | println!{"Foo(,"}; //~ unnecessary_trailing_comma |
| 28 | 28 | println!{"Foo[,"}; //~ unnecessary_trailing_comma |
| 29 | println!(concat!("Foo", "=", "{}"), 1); //~ unnecessary_trailing_comma | |
| 29 | 30 | |
| 30 | 31 | // This should eventually work, but requires more work |
| 31 | println!(concat!("Foo", "=", "{}"), 1,); | |
| 32 | 32 | println!("No params", /*"a,){ */); |
| 33 | 33 | println!("No params" /* "a,){*/, /*"a,){ */); |
| 34 | 34 |
src/tools/clippy/tests/ui/unnecessary_trailing_comma.rs+1-1| ... | ... | @@ -26,9 +26,9 @@ fn simple() { |
| 26 | 26 | println!{"Foo{{,}}", }; //~ unnecessary_trailing_comma |
| 27 | 27 | println!{"Foo(,", }; //~ unnecessary_trailing_comma |
| 28 | 28 | println!{"Foo[,", }; //~ unnecessary_trailing_comma |
| 29 | println!(concat!("Foo", "=", "{}"), 1,); //~ unnecessary_trailing_comma | |
| 29 | 30 | |
| 30 | 31 | // This should eventually work, but requires more work |
| 31 | println!(concat!("Foo", "=", "{}"), 1,); | |
| 32 | 32 | println!("No params", /*"a,){ */); |
| 33 | 33 | println!("No params" /* "a,){*/, /*"a,){ */); |
| 34 | 34 |
src/tools/clippy/tests/ui/unnecessary_trailing_comma.stderr+7-1| ... | ... | @@ -115,5 +115,11 @@ error: unnecessary trailing comma |
| 115 | 115 | LL | println!{"Foo[,", }; |
| 116 | 116 | | ^^ help: remove the trailing comma |
| 117 | 117 | |
| 118 | error: aborting due to 19 previous errors | |
| 118 | error: unnecessary trailing comma | |
| 119 | --> tests/ui/unnecessary_trailing_comma.rs:29:42 | |
| 120 | | | |
| 121 | LL | println!(concat!("Foo", "=", "{}"), 1,); | |
| 122 | | ^ help: remove the trailing comma | |
| 123 | ||
| 124 | error: aborting due to 20 previous errors | |
| 119 | 125 |
src/tools/clippy/tests/ui/unnecessary_unwrap_unchecked.fixed created+104| ... | ... | @@ -0,0 +1,104 @@ |
| 1 | //@aux-build:unnecessary_unwrap_unchecked_helper.rs | |
| 2 | //@aux-build:proc_macros.rs | |
| 3 | #![warn(clippy::unnecessary_unwrap_unchecked)] | |
| 4 | ||
| 5 | use proc_macros::{external, with_span}; | |
| 6 | ||
| 7 | #[rustfmt::skip] | |
| 8 | use unnecessary_unwrap_unchecked_helper::{lol, kek}; | |
| 9 | ||
| 10 | mod b { | |
| 11 | pub fn test_fn() -> Option<u32> { | |
| 12 | Some(0) | |
| 13 | } | |
| 14 | ||
| 15 | pub unsafe fn test_fn_unchecked() -> u32 { | |
| 16 | 0 | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | fn test_fn() -> Option<u32> { | |
| 21 | Some(0) | |
| 22 | } | |
| 23 | ||
| 24 | unsafe fn test_fn_unchecked() -> u32 { | |
| 25 | 0 | |
| 26 | } | |
| 27 | ||
| 28 | struct A; | |
| 29 | ||
| 30 | impl A { | |
| 31 | fn a(&self) -> Option<u32> { | |
| 32 | Some(0) | |
| 33 | } | |
| 34 | ||
| 35 | unsafe fn a_unchecked(&self) -> u32 { | |
| 36 | 0 | |
| 37 | } | |
| 38 | ||
| 39 | fn an_assoc_fn() -> Option<u32> { | |
| 40 | Some(0) | |
| 41 | } | |
| 42 | ||
| 43 | unsafe fn an_assoc_fn_unchecked() -> u32 { | |
| 44 | 0 | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | struct B; | |
| 49 | ||
| 50 | impl B { | |
| 51 | fn b(&self) -> Option<u32> { | |
| 52 | Some(0) | |
| 53 | } | |
| 54 | } | |
| 55 | ||
| 56 | impl B { | |
| 57 | unsafe fn b_unchecked(&self) -> u32 { | |
| 58 | 0 | |
| 59 | } | |
| 60 | } | |
| 61 | ||
| 62 | fn main() { | |
| 63 | let string_slice = unsafe { std::str::from_utf8_unchecked(&[]) }; | |
| 64 | //~^ unnecessary_unwrap_unchecked | |
| 65 | let a = unsafe { A::a_unchecked(&A) }; | |
| 66 | //~^ unnecessary_unwrap_unchecked | |
| 67 | let a = unsafe { | |
| 68 | let a = A; | |
| 69 | a.a_unchecked() | |
| 70 | }; | |
| 71 | //~^^ unnecessary_unwrap_unchecked | |
| 72 | let an_assoc_fn = unsafe { A::an_assoc_fn_unchecked() }; | |
| 73 | //~^ unnecessary_unwrap_unchecked | |
| 74 | let extern_fn = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() }; | |
| 75 | //~^ unnecessary_unwrap_unchecked | |
| 76 | let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() }; | |
| 77 | //~^ unnecessary_unwrap_unchecked | |
| 78 | let local_fn = unsafe { b::test_fn_unchecked() }; | |
| 79 | //~^ unnecessary_unwrap_unchecked | |
| 80 | ||
| 81 | // Don't lint: unlike `kek`, `kek_unchecked` isn't accessible from here | |
| 82 | let extern_pub_fn = unsafe { kek().unwrap_unchecked() }; | |
| 83 | ||
| 84 | // Don't lint: `B::b` and `B::b_unchecked` come from distinct impl blocks | |
| 85 | // (even though that wouldn't actually make the suggestion invalid in this case) | |
| 86 | let b = unsafe { | |
| 87 | let b = B; | |
| 88 | b.b().unwrap_unchecked() | |
| 89 | }; | |
| 90 | ||
| 91 | macro_rules! local { | |
| 92 | () => {{ | |
| 93 | unsafe { ::std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 94 | }}; | |
| 95 | } | |
| 96 | local!(); | |
| 97 | external! { | |
| 98 | unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 99 | } | |
| 100 | with_span! { | |
| 101 | span | |
| 102 | unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 103 | } | |
| 104 | } |
src/tools/clippy/tests/ui/unnecessary_unwrap_unchecked.rs created+104| ... | ... | @@ -0,0 +1,104 @@ |
| 1 | //@aux-build:unnecessary_unwrap_unchecked_helper.rs | |
| 2 | //@aux-build:proc_macros.rs | |
| 3 | #![warn(clippy::unnecessary_unwrap_unchecked)] | |
| 4 | ||
| 5 | use proc_macros::{external, with_span}; | |
| 6 | ||
| 7 | #[rustfmt::skip] | |
| 8 | use unnecessary_unwrap_unchecked_helper::{lol, kek}; | |
| 9 | ||
| 10 | mod b { | |
| 11 | pub fn test_fn() -> Option<u32> { | |
| 12 | Some(0) | |
| 13 | } | |
| 14 | ||
| 15 | pub unsafe fn test_fn_unchecked() -> u32 { | |
| 16 | 0 | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | fn test_fn() -> Option<u32> { | |
| 21 | Some(0) | |
| 22 | } | |
| 23 | ||
| 24 | unsafe fn test_fn_unchecked() -> u32 { | |
| 25 | 0 | |
| 26 | } | |
| 27 | ||
| 28 | struct A; | |
| 29 | ||
| 30 | impl A { | |
| 31 | fn a(&self) -> Option<u32> { | |
| 32 | Some(0) | |
| 33 | } | |
| 34 | ||
| 35 | unsafe fn a_unchecked(&self) -> u32 { | |
| 36 | 0 | |
| 37 | } | |
| 38 | ||
| 39 | fn an_assoc_fn() -> Option<u32> { | |
| 40 | Some(0) | |
| 41 | } | |
| 42 | ||
| 43 | unsafe fn an_assoc_fn_unchecked() -> u32 { | |
| 44 | 0 | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | struct B; | |
| 49 | ||
| 50 | impl B { | |
| 51 | fn b(&self) -> Option<u32> { | |
| 52 | Some(0) | |
| 53 | } | |
| 54 | } | |
| 55 | ||
| 56 | impl B { | |
| 57 | unsafe fn b_unchecked(&self) -> u32 { | |
| 58 | 0 | |
| 59 | } | |
| 60 | } | |
| 61 | ||
| 62 | fn main() { | |
| 63 | let string_slice = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 64 | //~^ unnecessary_unwrap_unchecked | |
| 65 | let a = unsafe { A::a(&A).unwrap_unchecked() }; | |
| 66 | //~^ unnecessary_unwrap_unchecked | |
| 67 | let a = unsafe { | |
| 68 | let a = A; | |
| 69 | a.a().unwrap_unchecked() | |
| 70 | }; | |
| 71 | //~^^ unnecessary_unwrap_unchecked | |
| 72 | let an_assoc_fn = unsafe { A::an_assoc_fn().unwrap_unchecked() }; | |
| 73 | //~^ unnecessary_unwrap_unchecked | |
| 74 | let extern_fn = unsafe { lol().unwrap_unchecked() }; | |
| 75 | //~^ unnecessary_unwrap_unchecked | |
| 76 | let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol().unwrap_unchecked() }; | |
| 77 | //~^ unnecessary_unwrap_unchecked | |
| 78 | let local_fn = unsafe { b::test_fn().unwrap_unchecked() }; | |
| 79 | //~^ unnecessary_unwrap_unchecked | |
| 80 | ||
| 81 | // Don't lint: unlike `kek`, `kek_unchecked` isn't accessible from here | |
| 82 | let extern_pub_fn = unsafe { kek().unwrap_unchecked() }; | |
| 83 | ||
| 84 | // Don't lint: `B::b` and `B::b_unchecked` come from distinct impl blocks | |
| 85 | // (even though that wouldn't actually make the suggestion invalid in this case) | |
| 86 | let b = unsafe { | |
| 87 | let b = B; | |
| 88 | b.b().unwrap_unchecked() | |
| 89 | }; | |
| 90 | ||
| 91 | macro_rules! local { | |
| 92 | () => {{ | |
| 93 | unsafe { ::std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 94 | }}; | |
| 95 | } | |
| 96 | local!(); | |
| 97 | external! { | |
| 98 | unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 99 | } | |
| 100 | with_span! { | |
| 101 | span | |
| 102 | unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 103 | } | |
| 104 | } |
src/tools/clippy/tests/ui/unnecessary_unwrap_unchecked.stderr created+88| ... | ... | @@ -0,0 +1,88 @@ |
| 1 | error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists | |
| 2 | --> tests/ui/unnecessary_unwrap_unchecked.rs:63:33 | |
| 3 | | | |
| 4 | LL | let string_slice = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: `-D clippy::unnecessary-unwrap-unchecked` implied by `-D warnings` | |
| 8 | = help: to override `-D warnings` add `#[allow(clippy::unnecessary_unwrap_unchecked)]` | |
| 9 | help: use `std::str::from_utf8_unchecked` instead, and remove the call to `.unwrap_unchecked()` | |
| 10 | | | |
| 11 | LL - let string_slice = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() }; | |
| 12 | LL + let string_slice = unsafe { std::str::from_utf8_unchecked(&[]) }; | |
| 13 | | | |
| 14 | ||
| 15 | error: usage of `unwrap_unchecked` when an `_unchecked` variant of the method exists | |
| 16 | --> tests/ui/unnecessary_unwrap_unchecked.rs:65:22 | |
| 17 | | | |
| 18 | LL | let a = unsafe { A::a(&A).unwrap_unchecked() }; | |
| 19 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 20 | | | |
| 21 | help: use `A::a_unchecked` instead, and remove the call to `.unwrap_unchecked()` | |
| 22 | | | |
| 23 | LL - let a = unsafe { A::a(&A).unwrap_unchecked() }; | |
| 24 | LL + let a = unsafe { A::a_unchecked(&A) }; | |
| 25 | | | |
| 26 | ||
| 27 | error: usage of `unwrap_unchecked` when an `_unchecked` variant of the method exists | |
| 28 | --> tests/ui/unnecessary_unwrap_unchecked.rs:69:9 | |
| 29 | | | |
| 30 | LL | a.a().unwrap_unchecked() | |
| 31 | | ^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 32 | | | |
| 33 | help: use `A::a_unchecked` instead, and remove the call to `.unwrap_unchecked()` | |
| 34 | | | |
| 35 | LL - a.a().unwrap_unchecked() | |
| 36 | LL + a.a_unchecked() | |
| 37 | | | |
| 38 | ||
| 39 | error: usage of `unwrap_unchecked` when an `_unchecked` variant of the associated function exists | |
| 40 | --> tests/ui/unnecessary_unwrap_unchecked.rs:72:32 | |
| 41 | | | |
| 42 | LL | let an_assoc_fn = unsafe { A::an_assoc_fn().unwrap_unchecked() }; | |
| 43 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 44 | | | |
| 45 | help: use `A::an_assoc_fn_unchecked` instead, and remove the call to `.unwrap_unchecked()` | |
| 46 | | | |
| 47 | LL - let an_assoc_fn = unsafe { A::an_assoc_fn().unwrap_unchecked() }; | |
| 48 | LL + let an_assoc_fn = unsafe { A::an_assoc_fn_unchecked() }; | |
| 49 | | | |
| 50 | ||
| 51 | error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists | |
| 52 | --> tests/ui/unnecessary_unwrap_unchecked.rs:74:30 | |
| 53 | | | |
| 54 | LL | let extern_fn = unsafe { lol().unwrap_unchecked() }; | |
| 55 | | ^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 56 | | | |
| 57 | help: use `unnecessary_unwrap_unchecked_helper::lol_unchecked` instead, and remove the call to `.unwrap_unchecked()` | |
| 58 | | | |
| 59 | LL - let extern_fn = unsafe { lol().unwrap_unchecked() }; | |
| 60 | LL + let extern_fn = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() }; | |
| 61 | | | |
| 62 | ||
| 63 | error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists | |
| 64 | --> tests/ui/unnecessary_unwrap_unchecked.rs:76:40 | |
| 65 | | | |
| 66 | LL | let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol().unwrap_unchecked() }; | |
| 67 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 68 | | | |
| 69 | help: use `unnecessary_unwrap_unchecked_helper::lol_unchecked` instead, and remove the call to `.unwrap_unchecked()` | |
| 70 | | | |
| 71 | LL - let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol().unwrap_unchecked() }; | |
| 72 | LL + let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() }; | |
| 73 | | | |
| 74 | ||
| 75 | error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists | |
| 76 | --> tests/ui/unnecessary_unwrap_unchecked.rs:78:29 | |
| 77 | | | |
| 78 | LL | let local_fn = unsafe { b::test_fn().unwrap_unchecked() }; | |
| 79 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 80 | | | |
| 81 | help: use `b::test_fn_unchecked` instead, and remove the call to `.unwrap_unchecked()` | |
| 82 | | | |
| 83 | LL - let local_fn = unsafe { b::test_fn().unwrap_unchecked() }; | |
| 84 | LL + let local_fn = unsafe { b::test_fn_unchecked() }; | |
| 85 | | | |
| 86 | ||
| 87 | error: aborting due to 7 previous errors | |
| 88 |
src/tools/clippy/triagebot.toml+5| ... | ... | @@ -60,6 +60,11 @@ labels = ["S-waiting-on-concerns"] |
| 60 | 60 | [view-all-comments-link] |
| 61 | 61 | threshold = 20 |
| 62 | 62 | |
| 63 | # Allows `merge` and `delegate` commands for merging a PR | |
| 64 | # Documentation at: https://forge.rust-lang.org/triagebot/merge.html | |
| 65 | [merge] | |
| 66 | type = "merge-queue" | |
| 67 | ||
| 63 | 68 | [notify-zulip."lint-nominated"] |
| 64 | 69 | zulip_stream = 577190 # #clippy/fcp |
| 65 | 70 | topic = "FCP rust-clippy#{number}: {title}" |