authorbors <bors@rust-lang.org> 2026-06-26 10:54:14 UTC
committerbors <bors@rust-lang.org> 2026-06-26 10:54:14 UTC
logeb6346c659ccb0468a1477c716ca5450a1fa9ba1
tree7c7221bb5a863bc8e05ff7b9ceecbde0c1f237a8
parent40557f6225e337d68c8d4f086557ce54135f5dd9
parent91c04dfcad15fc8d72681f5578a1183f5f29b332

Auto merge of #158403 - flip1995:clippy-subtree-update, r=Manishearth

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]) ->
5858 // or is it using a more efficient representation?
5959 match bytes.len() % 8 {
6060 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 );
6166 let context = &cx.context;
6267 let byte_type = context.new_type::<u64>();
6368 let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 8);
6469 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| {
6874 context.new_rvalue_from_long(
6975 byte_type,
7076 // 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]) ->
7985 context.new_array_constructor(None, typ, &elements)
8086 }
8187 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 );
8293 let context = &cx.context;
8394 let byte_type = context.new_type::<u32>();
8495 let typ = new_array_type(context, None, byte_type, bytes.len() as u64 / 4);
8596 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| {
89101 context.new_rvalue_from_int(
90102 byte_type,
91103 match cx.sess().target.options.endian {
src/tools/clippy/.github/FUNDING.yml created+2
......@@ -0,0 +1,2 @@
1github: rustfoundation
2custom: [ "rust-lang.org/funding" ]
src/tools/clippy/.github/workflows/clippy_dev.yml+1-1
......@@ -16,7 +16,7 @@ jobs:
1616 steps:
1717 # Setup
1818 - name: Checkout
19 uses: actions/checkout@v6
19 uses: actions/checkout@v7
2020 with:
2121 # Unsetting this would make so that any malicious package could get our Github Token
2222 persist-credentials: false
src/tools/clippy/.github/workflows/clippy_mq.yml+4-4
......@@ -34,7 +34,7 @@ jobs:
3434 steps:
3535 # Setup
3636 - name: Checkout
37 uses: actions/checkout@v6
37 uses: actions/checkout@v7
3838 with:
3939 persist-credentials: false
4040
......@@ -94,7 +94,7 @@ jobs:
9494 steps:
9595 # Setup
9696 - name: Checkout
97 uses: actions/checkout@v6
97 uses: actions/checkout@v7
9898 with:
9999 persist-credentials: false
100100
......@@ -112,7 +112,7 @@ jobs:
112112 steps:
113113 # Setup
114114 - name: Checkout
115 uses: actions/checkout@v6
115 uses: actions/checkout@v7
116116 with:
117117 persist-credentials: false
118118
......@@ -168,7 +168,7 @@ jobs:
168168 steps:
169169 # Setup
170170 - name: Checkout
171 uses: actions/checkout@v6
171 uses: actions/checkout@v7
172172 with:
173173 persist-credentials: false
174174
src/tools/clippy/.github/workflows/clippy_pr.yml+1-1
......@@ -24,7 +24,7 @@ jobs:
2424 steps:
2525 # Setup
2626 - name: Checkout
27 uses: actions/checkout@v6
27 uses: actions/checkout@v7
2828 with:
2929 # Unsetting this would make so that any malicious package could get our Github Token
3030 persist-credentials: false
src/tools/clippy/.github/workflows/deploy.yml+2-2
......@@ -25,13 +25,13 @@ jobs:
2525 steps:
2626 # Setup
2727 - name: Checkout
28 uses: actions/checkout@v6
28 uses: actions/checkout@v7
2929 with:
3030 # Unsetting this would make so that any malicious package could get our Github Token
3131 persist-credentials: false
3232
3333 - name: Checkout
34 uses: actions/checkout@v6
34 uses: actions/checkout@v7
3535 with:
3636 ref: ${{ env.TARGET_BRANCH }}
3737 path: 'out'
src/tools/clippy/.github/workflows/lintcheck.yml+3-3
......@@ -24,7 +24,7 @@ jobs:
2424
2525 steps:
2626 - name: Checkout
27 uses: actions/checkout@v6
27 uses: actions/checkout@v7
2828 with:
2929 fetch-depth: 2
3030 # Unsetting this would make so that any malicious package could get our Github Token
......@@ -80,7 +80,7 @@ jobs:
8080
8181 steps:
8282 - name: Checkout
83 uses: actions/checkout@v6
83 uses: actions/checkout@v7
8484 with:
8585 # Unsetting this would make so that any malicious package could get our Github Token
8686 persist-credentials: false
......@@ -113,7 +113,7 @@ jobs:
113113
114114 steps:
115115 - name: Checkout
116 uses: actions/checkout@v6
116 uses: actions/checkout@v7
117117 with:
118118 # Unsetting this would make so that any malicious package could get our Github Token
119119 persist-credentials: false
src/tools/clippy/.github/workflows/remark.yml+1-1
......@@ -14,7 +14,7 @@ jobs:
1414 steps:
1515 # Setup
1616 - name: Checkout
17 uses: actions/checkout@v6
17 uses: actions/checkout@v7
1818 with:
1919 # Unsetting this would make so that any malicious package could get our Github Token
2020 persist-credentials: false
src/tools/clippy/CHANGELOG.md+4-1
......@@ -6670,6 +6670,7 @@ Released 2018-09-13
66706670[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
66716671[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
66726672[`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
66736674[`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices
66746675[`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len
66756676[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
......@@ -6694,6 +6695,7 @@ Released 2018-09-13
66946695[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
66956696[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
66966697[`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
66976699[`clear_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#clear_with_drain
66986700[`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref
66996701[`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy
......@@ -7457,6 +7459,7 @@ Released 2018-09-13
74577459[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
74587460[`unnecessary_trailing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_trailing_comma
74597461[`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
74607463[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
74617464[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
74627465[`unneeded_struct_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_struct_pattern
......@@ -7571,6 +7574,7 @@ Released 2018-09-13
75717574[`avoid-breaking-exported-api`]: https://doc.rust-lang.org/clippy/lint_configuration.html#avoid-breaking-exported-api
75727575[`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types
75737576[`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
75747578[`check-incompatible-msrv-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-incompatible-msrv-in-tests
75757579[`check-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-inconsistent-struct-field-initializers
75767580[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items
......@@ -7608,7 +7612,6 @@ Released 2018-09-13
76087612[`module-items-ordered-within-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-items-ordered-within-groupings
76097613[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv
76107614[`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
76127615[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior
76137616[`recursive-self-in-type-definitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#recursive-self-in-type-definitions
76147617[`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:
1515 clippy_check:
1616 runs-on: ubuntu-latest
1717 steps:
18 - uses: actions/checkout@v6
18 - uses: actions/checkout@v7
1919 - name: Run Clippy
2020 run: cargo clippy --all-targets --all-features
2121```
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
452452* [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata)
453453
454454
455## `check-grouped-late-init`
456Whether to check for grouped late initializations from multiple `let` statements.
457
458#### Example
459```rust
460let a;
461let b;
462if true {
463 a = 1;
464 b = 2;
465} else {
466 a = 3;
467 b = 4;
468}
469```
470Use instead:
471```rust
472let (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
455486## `check-incompatible-msrv-in-tests`
456487Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code.
457488
......@@ -986,28 +1017,6 @@ The minimum size (in bytes) to consider a type for passing by reference instead
9861017* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
9871018
9881019
989## `profiles`
990Named profiles of disallowed items (unrelated to Cargo build profiles).
991
992#### Example
993
994```toml
995[profiles.persistent]
996disallowed-methods = [{ path = "std::env::temp_dir" }]
997disallowed-types = [{ path = "std::time::Instant", reason = "use our custom time API" }]
998
999[profiles.single_threaded]
1000disallowed-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
10111020## `pub-underscore-fields-behavior`
10121021Lint "public" fields in a struct that are prefixed with an underscore based on their
10131022exported visibility, or whether they are marked as "pub".
src/tools/clippy/clippy_config/src/conf.rs+28-207
......@@ -1,13 +1,12 @@
11use crate::ClippyConfiguration;
22use 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,
55 SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind,
66 SourceItemOrderingTraitAssocItemKinds, SourceItemOrderingWithinModuleItemGroupings,
77};
88use clippy_utils::msrvs::Msrv;
99use itertools::Itertools;
10use rustc_data_structures::fx::FxHashMap;
1110use rustc_errors::Applicability;
1211use rustc_session::Session;
1312use rustc_span::edit_distance::edit_distance;
......@@ -223,74 +222,12 @@ macro_rules! deserialize {
223222 }};
224223}
225224
226macro_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
248macro_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
287225macro_rules! define_Conf {
288226 ($(
289227 $(#[doc = $doc:literal])+
290228 $(#[conf_deprecated($dep:literal, $new_conf:ident)])?
291229 $(#[default_text = $default_text:expr])?
292230 $(#[disallowed_paths_allow_replacements = $replacements_allowed:expr])?
293 $(#[profiles = $profiles:expr])?
294231 $(#[lints($($for_lints:ident),* $(,)?)])?
295232 $name:ident: $ty:ty = $default:expr,
296233 )*) => {
......@@ -345,20 +282,10 @@ macro_rules! define_Conf {
345282
346283 match field {
347284 $(Field::$name => {
348 let field_span = name.span();
349285 // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning.
350286 $(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)?);
362289 // Was this field set previously?
363290 if $name.is_some() {
364291 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 {
415342 )
416343}
417344
418fn 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
492fn 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
533345define_Conf! {
534346 /// Which crates to allow absolute paths from
535347 #[lints(absolute_paths)]
......@@ -742,6 +554,30 @@ define_Conf! {
742554 /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
743555 #[lints(cargo_common_metadata)]
744556 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,
745581 /// Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code.
746582 #[lints(incompatible_msrv)]
747583 check_incompatible_msrv_in_tests: bool = false,
......@@ -1029,21 +865,6 @@ define_Conf! {
1029865 /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
1030866 #[lints(large_types_passed_by_value)]
1031867 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(),
1047868 /// Lint "public" fields in a struct that are prefixed with an underscore based on their
1048869 /// exported visibility, or whether they are marked as "pub".
1049870 #[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
5757 }
5858}
5959
60#[derive(Debug, Default, Deserialize, Serialize)]
61#[serde(deny_unknown_fields, rename_all = "kebab-case")]
62pub 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
6960// `DisallowedPathEnum` is an implementation detail to enable the `Deserialize` implementation just
7061// above. `DisallowedPathEnum` is not meant to be used outside of this file.
7162#[derive(Debug, Deserialize, Serialize)]
src/tools/clippy/clippy_lints/src/absolute_paths.rs+1-1
......@@ -12,7 +12,7 @@ use rustc_span::symbol::kw;
1212
1313declare_clippy_lint! {
1414 /// ### 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`.
1616 ///
1717 /// ### Why restrict this?
1818 /// 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 {
5252 _ => return,
5353 }
5454 && 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)
5658 && let Some((Constant::Bool(assert_val), const_src)) =
5759 ConstEvalCtxt::new(cx).eval_with_source(condition, macro_call.span.ctxt())
5860 && 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 @@
11use super::{Attribute, NON_MINIMAL_CFG};
22use clippy_utils::diagnostics::span_lint_and_then;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use rustc_ast::{MetaItemInner, MetaItemKind};
55use rustc_errors::Applicability;
66use rustc_lint::EarlyContext;
......@@ -29,7 +29,7 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[MetaItemInner]) {
2929 meta.span,
3030 "unneeded sub `cfg` when there is only one condition",
3131 |diag| {
32 if let Some(snippet) = list[0].span().get_source_text(cx) {
32 if let Some(snippet) = list[0].span().get_text(cx) {
3333 diag.span_suggestion(
3434 meta.span,
3535 "try",
src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs+3-3
......@@ -1,6 +1,6 @@
11use super::{Attribute, UNNECESSARY_CLIPPY_CFG};
22use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use itertools::Itertools;
55use rustc_ast::AttrStyle;
66use rustc_errors::Applicability;
......@@ -32,7 +32,7 @@ pub(super) fn check(
3232 return;
3333 }
3434 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) {
3636 span_lint_and_sugg(
3737 cx,
3838 UNNECESSARY_CLIPPY_CFG,
......@@ -48,7 +48,7 @@ pub(super) fn check(
4848 );
4949 }
5050 } 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(",");
5252 span_lint_and_note(
5353 cx,
5454 UNNECESSARY_CLIPPY_CFG,
src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs+2-2
......@@ -1,7 +1,7 @@
11use super::USELESS_ATTRIBUTE;
22use super::utils::{is_lint_level, is_word, namespace_and_lint};
33use clippy_utils::diagnostics::span_lint_and_then;
4use clippy_utils::source::{SpanRangeExt, first_line_of_span};
4use clippy_utils::source::{SpanExt, first_line_of_span};
55use clippy_utils::sym;
66use rustc_ast::{Attribute, Item, ItemKind};
77use rustc_errors::Applicability;
......@@ -74,7 +74,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
7474 }
7575 let line_span = first_line_of_span(cx, attr.span);
7676
77 if let Some(src) = line_span.get_source_text(cx)
77 if let Some(src) = line_span.get_text(cx)
7878 && src.contains("#[")
7979 {
8080 #[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};
33use clippy_utils::higher::has_let_expr;
44use clippy_utils::msrvs::{self, Msrv};
55use clippy_utils::res::MaybeDef;
6use clippy_utils::source::{SpanRangeExt, snippet_with_context};
6use clippy_utils::source::{SpanExt, snippet_with_context};
77use clippy_utils::sugg::Sugg;
88use clippy_utils::ty::implements_trait;
99use clippy_utils::{eq_expr_value, sym};
......@@ -157,30 +157,30 @@ fn check_inverted_bool_in_condition(
157157
158158 let suggestion = match (left.kind, right.kind) {
159159 (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 {
161161 return;
162162 };
163 let Some(right) = right_sub.span.get_source_text(cx) else {
163 let Some(right) = right_sub.span.get_text(cx) else {
164164 return;
165165 };
166166 let Some(op) = bin_op_eq_str(op) else { return };
167167 format!("{left} {op} {right}")
168168 },
169169 (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 {
171171 return;
172172 };
173 let Some(right) = right.span.get_source_text(cx) else {
173 let Some(right) = right.span.get_text(cx) else {
174174 return;
175175 };
176176 let Some(op) = inverted_bin_op_eq_str(op) else { return };
177177 format!("{left} {op} {right}")
178178 },
179179 (_, 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 {
181181 return;
182182 };
183 let Some(right) = right_sub.span.get_source_text(cx) else {
183 let Some(right) = right_sub.span.get_text(cx) else {
184184 return;
185185 };
186186 let Some(op) = inverted_bin_op_eq_str(op) else { return };
......@@ -392,12 +392,8 @@ impl SuggestContext<'_, '_, '_> {
392392 }
393393 },
394394 &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)?);
401397 },
402398 }
403399 Some(())
......@@ -452,10 +448,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio
452448 .map(|arg| simplify_not(cx, curr_msrv, arg))
453449 .collect::<Option<Vec<_>>>()?
454450 .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)?))
459452 })
460453 },
461454 ExprKind::Closure(closure) => {
......@@ -463,13 +456,13 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio
463456 let params = body
464457 .params
465458 .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()))
467460 .collect::<Option<Vec<_>>>()?
468461 .join(", ");
469462 let negated = simplify_not(cx, curr_msrv, body.value)?;
470463 Some(format!("|{params}| {negated}"))
471464 },
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()),
473466 _ => None,
474467 }
475468}
src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs+2-2
......@@ -1,6 +1,6 @@
11use crate::reference::DEREF_ADDROF;
22use clippy_utils::diagnostics::span_lint_and_then;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::ty::implements_trait;
55use clippy_utils::{
66 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 {
8282 // If the new borrow might be itself borrowed mutably and the original reference is not a temporary
8383 // value, do not propose to use it directly.
8484 && (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)
8686 {
8787 // `&*x` can be needed to shorten the borrow of `x`. Replacing it with `x` can be
8888 // 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 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use clippy_utils::sym;
44use rustc_errors::Applicability;
55use rustc_hir::{Expr, ExprKind};
......@@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
2020 && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity().skip_norm_wip()
2121 && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
2222 && 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)
2424 {
2525 // `as_mut_ptr` might not exist
2626 let applicability = Applicability::MaybeIncorrect;
src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::is_in_const_context;
33use clippy_utils::msrvs::{self, Msrv};
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use clippy_utils::sugg::Sugg;
66use clippy_utils::ty::is_isize_or_usize;
77use rustc_errors::Applicability;
......@@ -40,7 +40,7 @@ pub(super) fn check(
4040 diag.help("an `as` cast can become silently lossy if the types change in the future");
4141 let mut applicability = Applicability::MachineApplicable;
4242 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 {
4444 return;
4545 };
4646 match cast_to_hir.kind {
src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::res::{MaybeDef, MaybeResPath};
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::{expr_or_init, std_or_core, sym};
55use rustc_ast::LitKind;
66use rustc_errors::Applicability;
......@@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to:
2525
2626 let sugg = if let TyKind::Infer(()) = ptr_ty.ty.kind {
2727 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) {
2929 format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()")
3030 } else {
3131 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 {
249249fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) {
250250 let mut usages = Vec::new();
251251
252 for_each_expr(cx, body.value, |expr| {
252 for_each_expr(cx.tcx, body.value, |expr| {
253253 if let ExprKind::Path(ref qpath) = expr.kind
254254 && !expr.span.from_expansion()
255255 && 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 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::numeric_literal::NumericLiteral;
33use clippy_utils::res::MaybeResPath as _;
4use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability};
4use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability};
55use clippy_utils::sugg::has_enclosing_paren;
66use clippy_utils::visitors::{Visitable, for_each_expr_without_closures};
77use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, sym};
......@@ -113,7 +113,7 @@ pub(super) fn check<'tcx>(
113113 let literal_str = &cast_str;
114114
115115 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)
117117 && cast_to.is_floating_point()
118118 && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node)
119119 && let from_nbits = 128 - n.get().leading_zeros()
......@@ -140,7 +140,7 @@ pub(super) fn check<'tcx>(
140140 | LitKind::Float(_, LitFloatType::Suffixed(_))
141141 if cast_from.kind() == cast_to.kind() =>
142142 {
143 if let Some(src) = cast_expr.span.get_source_text(cx)
143 if let Some(src) = cast_expr.span.get_text(cx)
144144 && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node)
145145 {
146146 lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
......@@ -232,7 +232,7 @@ fn lint_unnecessary_cast(
232232 // (-1).foo() instead of -1.foo())
233233 let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
234234 && let ExprKind::MethodCall(..) = parent_expr.kind
235 && literal_str.starts_with('-')
235 && literal_str.starts_with(['-', '!'])
236236 {
237237 format!("({literal_str}_{cast_to})")
238238 } else {
......@@ -253,7 +253,7 @@ fn lint_unnecessary_cast(
253253fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<Lit> {
254254 match expr.kind {
255255 ExprKind::Lit(lit) => Some(lit),
256 ExprKind::Unary(UnOp::Neg, e) => {
256 ExprKind::Unary(UnOp::Neg | UnOp::Not, e) => {
257257 if let ExprKind::Lit(lit) = e.kind {
258258 Some(lit)
259259 } else {
src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::msrvs::{self, Msrv};
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core};
55use rustc_errors::Applicability;
66use rustc_hir::{Expr, Mutability, Ty, TyKind};
......@@ -21,7 +21,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>
2121
2222 let sugg = if let TyKind::Infer(()) = mut_ty.ty.kind {
2323 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) {
2525 format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()")
2626 } else {
2727 return;
src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs+11-10
......@@ -64,15 +64,8 @@ impl<'a> ClonedRefToSliceRefs<'a> {
6464
6565impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> {
6666 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
7669 // mutable references would have a different meaning
7770 && mutability.is_not()
7871
......@@ -81,10 +74,18 @@ impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> {
8174
8275 // check for clones
8376 && 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 })
8485 && let Some(adjustment) = is_needless_clone_or_equivalent(cx, recv, path.ident.name, item.hir_id)
8586
8687 // 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))
8889
8990 // get appropriate crate for `slice::from_ref`
9091 && 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 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::span_lint_and_help;
33use clippy_utils::res::MaybeDef;
4use clippy_utils::source::{IntoSpan, SpanRangeExt};
4use clippy_utils::source::{IntoSpan, SpanExt};
55use clippy_utils::visitors::for_each_expr_without_closures;
66use clippy_utils::{LimitStack, get_async_fn_body, sym};
77use core::ops::ControlFlow;
src/tools/clippy/clippy_lints/src/collapsible_if.rs+3-3
......@@ -1,7 +1,7 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::span_lint_hir_and_then;
33use clippy_utils::msrvs::Msrv;
4use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
4use clippy_utils::source::{IntoSpan as _, SpanExt, snippet, snippet_block_with_applicability};
55use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text};
66use rustc_ast::{BinOpKind, MetaItemInner};
77use rustc_errors::Applicability;
......@@ -319,7 +319,7 @@ pub(super) fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> {
319319 }
320320}
321321
322fn span_extract_keyword(cx: &impl HasSession, span: Span, keyword: &str) -> Option<Span> {
322fn span_extract_keyword(cx: &LateContext<'_>, span: Span, keyword: &str) -> Option<Span> {
323323 span.with_source_text(cx, |snippet| {
324324 tokenize_with_text(snippet)
325325 .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
335335}
336336
337337/// Peel the parentheses from an `if` expression, e.g. `((if true {} else {}))`.
338pub(super) fn peel_parens(cx: &impl HasSession, mut span: Span) -> (Span, Span, Span) {
338pub(super) fn peel_parens(cx: &LateContext<'_>, mut span: Span) -> (Span, Span, Span) {
339339 use crate::rustc_span::Pos;
340340
341341 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
7979 let mut has_read_access = false;
8080
8181 // Inspect all expressions and sub-expressions in the block.
82 for_each_expr(cx, block, |expr| {
82 for_each_expr(cx.tcx, block, |expr| {
8383 // Ignore expressions that are not simply `id`.
8484 if expr.res_local_id() != Some(id) {
8585 return ControlFlow::Continue(());
src/tools/clippy/clippy_lints/src/declared_lints.rs+3
......@@ -361,11 +361,13 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
361361 crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO,
362362 crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO,
363363 crate::methods::BIND_INSTEAD_OF_MAP_INFO,
364 crate::methods::BY_REF_PEEKABLE_PEEK_INFO,
364365 crate::methods::BYTES_COUNT_TO_LEN_INFO,
365366 crate::methods::BYTES_NTH_INFO,
366367 crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO,
367368 crate::methods::CHARS_LAST_CMP_INFO,
368369 crate::methods::CHARS_NEXT_CMP_INFO,
370 crate::methods::CHUNKS_EXACT_TO_AS_CHUNKS_INFO,
369371 crate::methods::CLEAR_WITH_DRAIN_INFO,
370372 crate::methods::CLONE_ON_COPY_INFO,
371373 crate::methods::CLONE_ON_REF_PTR_INFO,
......@@ -507,6 +509,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
507509 crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
508510 crate::methods::UNNECESSARY_SORT_BY_INFO,
509511 crate::methods::UNNECESSARY_TO_OWNED_INFO,
512 crate::methods::UNNECESSARY_UNWRAP_UNCHECKED_INFO,
510513 crate::methods::UNWRAP_OR_DEFAULT_INFO,
511514 crate::methods::UNWRAP_USED_INFO,
512515 crate::methods::USELESS_ASREF_INFO,
src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::is_ty_alias;
3use clippy_utils::source::SpanRangeExt as _;
3use clippy_utils::source::SpanExt as _;
44use hir::ExprKind;
55use hir::def::Res;
66use rustc_errors::Applicability;
......@@ -78,7 +78,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs {
7878 && !base.is_suggestable_infer_ty()
7979 {
8080 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('<')) {
8282 // Remove `<`, '>` has already been removed by the existing removal expression.
8383 removals.push((expr.span.with_hi(qpath.qself_span().lo()), String::new()));
8484 }
src/tools/clippy/clippy_lints/src/disallowed_methods.rs+6-119
......@@ -1,18 +1,13 @@
11use clippy_config::Conf;
22use clippy_config::types::{DisallowedPath, create_disallowed_map};
3use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
4use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver};
3use clippy_utils::diagnostics::span_lint_and_then;
54use clippy_utils::paths::PathNS;
6use clippy_utils::sym;
7use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8use rustc_data_structures::smallvec::SmallVec;
95use rustc_hir::def::{CtorKind, DefKind, Res};
106use rustc_hir::def_id::DefIdMap;
117use rustc_hir::{Expr, ExprKind};
128use rustc_lint::{LateContext, LateLintPass};
139use rustc_middle::ty::TyCtxt;
1410use rustc_session::impl_lint_pass;
15use rustc_span::{Span, Symbol};
1611
1712declare_clippy_lint! {
1813 /// ### What it does
......@@ -60,19 +55,6 @@ declare_clippy_lint! {
6055 /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.
6156 /// xs.push(123); // Vec::push is _not_ disallowed in the config.
6257 /// ```
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 /// ```
7658 #[clippy::version = "1.49.0"]
7759 pub DISALLOWED_METHODS,
7860 style,
......@@ -82,22 +64,12 @@ declare_clippy_lint! {
8264impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
8365
8466pub 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)>,
9568}
9669
9770impl DisallowedMethods {
98 #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration.
9971 pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
100 let (default, _) = create_disallowed_map(
72 let (disallowed, _) = create_disallowed_map(
10173 tcx,
10274 &conf.disallowed_methods,
10375 PathNS::Value,
......@@ -110,62 +82,7 @@ impl DisallowedMethods {
11082 "function",
11183 false,
11284 );
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 }
16986 }
17087}
17188
......@@ -181,43 +98,13 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
18198 },
18299 _ => return,
183100 };
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) {
215102 span_lint_and_then(
216103 cx,
217104 DISALLOWED_METHODS,
218105 span,
219106 format!("use of a disallowed method `{path}`"),
220 |diag| diag_amendment(diag),
107 disallowed_path.diag_amendment(span),
221108 );
222109 }
223110 }
src/tools/clippy/clippy_lints/src/disallowed_types.rs+29-138
......@@ -1,18 +1,15 @@
11use clippy_config::Conf;
22use clippy_config::types::{DisallowedPath, create_disallowed_map};
3use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
4use clippy_utils::disallowed_profiles::{ProfileEntry, ProfileResolver};
3use clippy_utils::diagnostics::span_lint_and_then;
54use clippy_utils::paths::PathNS;
6use clippy_utils::sym;
7use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8use rustc_data_structures::smallvec::SmallVec;
5use rustc_data_structures::fx::FxHashMap;
96use rustc_hir::def::{DefKind, Res};
107use rustc_hir::def_id::DefIdMap;
118use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
129use rustc_lint::{LateContext, LateLintPass};
1310use rustc_middle::ty::TyCtxt;
1411use rustc_session::impl_lint_pass;
15use rustc_span::{Span, Symbol};
12use rustc_span::Span;
1613
1714declare_clippy_lint! {
1815 /// ### What it does
......@@ -54,17 +51,6 @@ declare_clippy_lint! {
5451 /// // A similar type that is allowed by the config
5552 /// use std::collections::HashMap;
5653 /// ```
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 /// ```
6854 #[clippy::version = "1.55.0"]
6955 pub DISALLOWED_TYPES,
7056 style,
......@@ -73,127 +59,37 @@ declare_clippy_lint! {
7359
7460impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
7561
76struct TypeLookup {
62pub struct DisallowedTypes {
7763 def_ids: DefIdMap<(&'static str, &'static DisallowedPath)>,
7864 prim_tys: FxHashMap<PrimTy, (&'static str, &'static DisallowedPath)>,
7965}
8066
81impl 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
96pub 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
10967impl DisallowedTypes {
110 #[allow(rustc::potential_query_instability)] // Profiles are sorted for deterministic iteration.
11168 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 }
15578 }
15679
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 );
19793 }
19894}
19995
......@@ -215,22 +111,17 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
215111 if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind
216112 && let Some(res) = path.res.type_ns
217113 {
218 self.check_res_emit(cx, item.hir_id(), &res, item.span);
114 self.check_res_emit(cx, &res, item.span);
219115 }
220116 }
221117
222118 fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx, AmbigArg>) {
223119 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);
225121 }
226122 }
227123
228124 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);
235126 }
236127}
src/tools/clippy/clippy_lints/src/doc/missing_headers.rs+1-1
......@@ -99,7 +99,7 @@ pub fn check(
9999fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
100100 let mut panic_span = None;
101101 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| {
103103 if is_inside_always_const_context(cx.tcx, expr.hir_id) {
104104 return ControlFlow::<!>::Continue(());
105105 }
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
11241124
11251125 let mut containers = Vec::new();
11261126
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
11271130 let mut events = events.peekable();
11281131
11291132 while let Some((event, range)) = events.next() {
......@@ -1238,19 +1241,29 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
12381241 if let End(TagEnd::Item) = event {
12391242 containers.pop();
12401243 }
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 }
12541267 }
12551268 }
12561269 },
......@@ -1331,7 +1344,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
13311344 // Don't check the text associated with external URLs
13321345 continue;
13331346 }
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 }
13351350 doc_suspicious_footnotes::check(cx, doc, range, &fragments, attrs);
13361351 }
13371352 }
src/tools/clippy/clippy_lints/src/double_parens.rs+2-2
......@@ -1,8 +1,8 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::source::{HasSession, SpanRangeExt, snippet_with_applicability, snippet_with_context};
2use clippy_utils::source::{SpanExt, snippet_with_applicability, snippet_with_context};
33use rustc_ast::ast::{Expr, ExprKind, MethodCall};
44use rustc_errors::Applicability;
5use rustc_lint::{EarlyContext, EarlyLintPass};
5use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
66use rustc_session::declare_lint_pass;
77
88declare_clippy_lint! {
src/tools/clippy/clippy_lints/src/empty_enums.rs+1-1
......@@ -51,7 +51,7 @@ declare_clippy_lint! {
5151 /// [visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html
5252 #[clippy::version = "pre 1.29.0"]
5353 pub EMPTY_ENUMS,
54 pedantic,
54 nursery,
5555 "enum with no variants"
5656}
5757
src/tools/clippy/clippy_lints/src/empty_line_after.rs+2-2
......@@ -1,7 +1,7 @@
11use std::borrow::Cow;
22
33use clippy_utils::diagnostics::span_lint_and_then;
4use clippy_utils::source::{SpanRangeExt, snippet_indent};
4use clippy_utils::source::{SpanExt, snippet_indent};
55use clippy_utils::tokenize_with_text;
66use itertools::Itertools;
77use rustc_ast::token::CommentKind;
......@@ -288,7 +288,7 @@ impl<'a> Gap<'a> {
288288 let prev_stop = prev_chunk.last()?;
289289 let next_stop = next_chunk.first()?;
290290 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)?;
292292
293293 let mut has_comment = false;
294294 let mut empty_lines = Vec::new();
src/tools/clippy/clippy_lints/src/empty_with_brackets.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::attrs::span_contains_cfg;
22use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::span_contains_non_whitespace;
55use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
66use rustc_errors::Applicability;
......@@ -192,7 +192,7 @@ impl LateLintPass<'_> for EmptyWithBrackets {
192192 // Span of the parentheses in variant definition
193193 let span = variant.span.with_lo(variant.ident.span.hi());
194194 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))
196196 .with_hi(span.hi() - BytePos(1));
197197 if span_contains_non_whitespace(cx, span_inner, false) {
198198 continue;
src/tools/clippy/clippy_lints/src/entry.rs+1-1
......@@ -604,7 +604,7 @@ fn is_any_expr_in_map_used<'tcx>(
604604 map: &'tcx Expr<'tcx>,
605605 expr: &'tcx Expr<'tcx>,
606606) -> bool {
607 for_each_expr(cx, map, |e| {
607 for_each_expr(cx.tcx, map, |e| {
608608 if spanless_eq.eq_expr(ctxt, e, expr) {
609609 return ControlFlow::Break(());
610610 }
src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs+1-1
......@@ -102,7 +102,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
102102 fn emit_sugg(&self, spans: Vec<Span>, msg: String, help: &'static str) {
103103 let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect();
104104 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);
106106 });
107107 }
108108
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<'_>) {
9191 cx,
9292 SUBOPTIMAL_FLOPS,
9393 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",
9595 |diag| {
9696 let maybe_neg_sugg = |expr, app: &mut _| {
9797 let sugg = Sugg::hir_with_applicability(cx, expr, "_", app);
......@@ -120,6 +120,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
120120 },
121121 app,
122122 );
123 diag.note_once("the performance gain from `mul_add` may vary depending on the target architecture");
123124 },
124125 );
125126}
src/tools/clippy/clippy_lints/src/format.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, first_node_in_macro, matching_root_macro_call};
3use clippy_utils::source::{SpanRangeExt, snippet_with_context};
3use clippy_utils::source::{SpanExt, snippet_with_context};
44use clippy_utils::sugg::Sugg;
55use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait};
66use rustc_errors::Applicability;
......@@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
6969 ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
7070 ([], [_]) => {
7171 // 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 {
7373 return;
7474 };
7575 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::{
1010};
1111use clippy_utils::msrvs::{self, Msrv};
1212use clippy_utils::res::MaybeDef;
13use clippy_utils::source::{SpanRangeExt, snippet, snippet_opt};
13use clippy_utils::source::{SpanExt, snippet, snippet_opt};
1414use clippy_utils::ty::implements_trait;
1515use clippy_utils::{is_from_proc_macro, is_in_test, peel_hir_expr_while, sym, trait_ref_of_method};
1616use itertools::Itertools;
......@@ -380,7 +380,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
380380 /// Check if there is a comma after the last format macro arg.
381381 fn check_trailing_comma(&self) {
382382 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)
384384 && let Some(src) = src.strip_suffix([')', ']', '}'])
385385 && let src = src.trim_end_matches(|c: char| c.is_whitespace() && c != '\n')
386386 && let Some(src) = src.strip_suffix(',')
......@@ -694,7 +694,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
694694 count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter())
695695 && implements_trait(cx, target, display_trait_id, &[])
696696 && 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)
698698 {
699699 let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
700700 if n_needed_derefs == 0 && !needs_ref {
src/tools/clippy/clippy_lints/src/four_forward_slashes.rs+2-2
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::SpanRangeExt as _;
2use clippy_utils::source::SpanExt as _;
33use itertools::Itertools;
44use rustc_errors::Applicability;
55use rustc_hir::Item;
......@@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes {
8686
8787 // If the comment contains a bare CR (not followed by a LF), do not propose an auto-fix
8888 // 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) {
9090 diag.help(msg)
9191 .note("bare CR characters are not allowed in doc comments");
9292 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;
55use clippy_utils::macros::span_is_local;
66use clippy_utils::msrvs::{self, Msrv};
77use clippy_utils::res::MaybeResPath;
8use clippy_utils::source::SpanRangeExt;
8use clippy_utils::source::SpanExt;
99use rustc_errors::Applicability;
1010use rustc_hir::intravisit::{Visitor, walk_path};
1111use rustc_hir::{
......@@ -197,8 +197,8 @@ fn convert_to_from(
197197 return None;
198198 };
199199
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)?;
202202
203203 let mut suggestions = vec![
204204 // 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(
163163 );
164164 } else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
165165 // 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;
172171 }
173172
174173 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>(
5050
5151 if !raw_ptrs.is_empty() {
5252 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| {
5454 match e.kind {
5555 hir::ExprKind::Call(f, args) if is_unsafe_fn(cx, typeck.expr_ty(f)) => {
5656 for arg in args {
src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs+2-2
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use rustc_hir as hir;
44use rustc_hir::def_id::LocalDefId;
55use rustc_hir::intravisit::FnKind;
......@@ -23,7 +23,7 @@ pub(super) fn check_fn(
2323 }
2424
2525 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| {
2727 let mut in_comment = false;
2828 let mut code_in_line;
2929
src/tools/clippy/clippy_lints/src/if_not_else.rs+11-12
......@@ -1,7 +1,7 @@
11use clippy_utils::consts::is_zero_integer_const;
22use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
33use clippy_utils::is_else_clause;
4use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_context};
4use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_context};
55use rustc_errors::Applicability;
66use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
77use rustc_lint::{LateContext, LateLintPass};
......@@ -104,28 +104,27 @@ impl LateLintPass<'_> for IfNotElse {
104104 }
105105}
106106
107fn make_sugg<'a>(
108 sess: &impl HasSession,
107fn make_sugg(
108 cx: &LateContext<'_>,
109109 expr_span: Span,
110 cond_kind: &'a ExprKind<'a>,
110 cond_kind: &ExprKind<'_>,
111111 cond_inner: Span,
112112 els_span: Span,
113 default: &'a str,
113 default: &str,
114114 applicability: &mut Applicability,
115115) -> 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);
120119 let suggestion = match cond_kind {
121120 ExprKind::Unary(UnOp::Not, cond_rest) => {
122121 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);
124123 format!("if {cond_rest_snip} {els_snip} else {cond_inner_snip}")
125124 },
126125 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);
129128
130129 format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}")
131130 },
src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs+1-1
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::res::MaybeResPath;
3use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet};
3use clippy_utils::source::{IntoSpan, SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet};
44use clippy_utils::ty::needs_ordered_drop;
55use clippy_utils::visitors::for_each_expr_without_closures;
66use clippy_utils::{
src/tools/clippy/clippy_lints/src/implicit_hasher.rs+1-1
......@@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass;
1313use rustc_span::Span;
1414
1515use clippy_utils::diagnostics::span_lint_and_then;
16use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet, snippet_with_context};
16use clippy_utils::source::{IntoSpan, SpanExt, snippet, snippet_with_context};
1717use clippy_utils::sym;
1818
1919declare_clippy_lint! {
src/tools/clippy/clippy_lints/src/incompatible_msrv.rs+3-2
......@@ -193,10 +193,11 @@ impl IncompatibleMsrv {
193193 }
194194 }
195195
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)
198198 && let Availability::Since(version) = self.get_def_id_availability(cx.tcx, def_id, needs_const)
199199 && version > current
200 && (self.check_in_tests || !is_in_test(cx.tcx, node))
200201 {
201202 span_lint_and_then(
202203 cx,
src/tools/clippy/clippy_lints/src/ineffective_open_options.rs+1-1
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::res::MaybeDef;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::{peel_blocks, peel_hir_expr_while, sym};
55use rustc_ast::LitKind;
66use rustc_errors::Applicability;
src/tools/clippy/clippy_lints/src/inline_trait_bounds.rs+2-2
......@@ -1,11 +1,11 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::{HasSession, snippet};
2use clippy_utils::source::snippet;
33use clippy_utils::sym;
44use rustc_ast::ast::{Fn, FnRetTy, GenericParam, GenericParamKind};
55use rustc_ast::visit::{FnCtxt, FnKind};
66use rustc_ast::{HasAttrs as _, NodeId};
77use rustc_errors::Applicability;
8use rustc_lint::{EarlyContext, EarlyLintPass};
8use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
99use rustc_session::impl_lint_pass;
1010use rustc_span::Span;
1111
src/tools/clippy/clippy_lints/src/items_after_test_module.rs+2-2
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_hir_and_then;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
44use rustc_errors::{Applicability, SuggestionStyle};
55use rustc_hir::{HirId, Item, ItemKind, Mod};
......@@ -99,7 +99,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
9999 if let Some(prev) = mod_pos.checked_sub(1)
100100 && let prev = cx.tcx.hir_item(module.item_ids[prev])
101101 && 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)
103103 {
104104 diag.multipart_suggestion_with_style(
105105 "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};
22
33use clippy_config::Conf;
44use clippy_utils::diagnostics::span_lint_and_then;
5use clippy_utils::source::{HasSession, SpanRangeExt};
5use clippy_utils::source::SpanExt;
66use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_in_test};
77use rustc_errors::Diag;
88use rustc_hir::def_id::LocalDefId;
......@@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames {
197197 // TODO: Is there a cleaner, robust way to ask this question?
198198 // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data",
199199 // 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)
201201 && is_ident(&name)
202202 {
203203 // If the local is an ordinary named variable,
......@@ -228,11 +228,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames {
228228
229229 if fn_span.from_expansion() {
230230 // 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()) {
232232 return;
233233 }
234234
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());
236236 span_lint_and_then(
237237 cx,
238238 LARGE_STACK_FRAMES,
src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::span_lint_and_then;
33use clippy_utils::msrvs::{self, Msrv};
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use clippy_utils::{is_from_proc_macro, sym};
66use hir::def_id::DefId;
77use rustc_errors::Applicability;
......@@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
121121 && let QPath::TypeRelative(ty, last_segment) = qpath
122122 && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
123123 && 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)
125125 && ty.span.eq_ctxt(last_segment.ident.span)
126126 {
127127 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;
22use clippy_utils::diagnostics::span_lint_and_sugg;
33use clippy_utils::msrvs::Msrv;
44use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
5use clippy_utils::source::{SpanRangeExt, snippet_with_context};
5use clippy_utils::source::{SpanExt, snippet_with_context};
66use clippy_utils::sugg::{Sugg, has_enclosing_paren};
77use clippy_utils::ty::implements_trait;
88use clippy_utils::{parent_item_name, peel_ref_operators, sym};
......@@ -261,7 +261,7 @@ impl LenZero {
261261}
262262
263263fn 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 {
265265 return span;
266266 };
267267 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 {
162162 );
163163 },
164164 );
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()
166167 && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[])
167168 {
168169 #[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 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::is_from_proc_macro;
3use clippy_utils::source::{IntoSpan, SpanRangeExt};
3use clippy_utils::source::{IntoSpan, SpanExt};
44use rustc_ast::{Local, TyKind};
55use rustc_errors::Applicability;
66use 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
454454 // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
455455 // Due to the architecture of the compiler, currently `cfg_attr` attributes on crate
456456 // 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))));
460458
461459 let format_args_storage = FormatArgsStorage::default();
462460 let attr_storage = AttrStorage::default();
......@@ -531,7 +529,6 @@ rustc_lint::early_lint_methods!(
531529 PartialPubFields: partial_pub_fields::PartialPubFields = partial_pub_fields::PartialPubFields,
532530 UnderscoreTyped: let_with_type_underscore::UnderscoreTyped = let_with_type_underscore::UnderscoreTyped,
533531 ExcessiveNesting: excessive_nesting::ExcessiveNesting = excessive_nesting::ExcessiveNesting::new(conf),
534 RefPatterns: ref_patterns::RefPatterns = ref_patterns::RefPatterns,
535532 NeedlessElse: needless_else::NeedlessElse = needless_else::NeedlessElse,
536533 RawStrings: raw_strings::RawStrings = raw_strings::RawStrings::new(conf),
537534 Visibility: visibility::Visibility = visibility::Visibility,
......@@ -729,7 +726,7 @@ rustc_lint::late_lint_methods!(
729726 UndocumentedUnsafeBlocks: undocumented_unsafe_blocks::UndocumentedUnsafeBlocks = undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(conf),
730727 FormatArgs: format_args::FormatArgs<'tcx> = format_args::FormatArgs::new(tcx, conf, format_args.clone()),
731728 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),
733730 ReturnSelfNotMustUse: return_self_not_must_use::ReturnSelfNotMustUse = return_self_not_must_use::ReturnSelfNotMustUse,
734731 NumberedFields: init_numbered_fields::NumberedFields = init_numbered_fields::NumberedFields,
735732 ManualBits: manual_bits::ManualBits = manual_bits::ManualBits::new(conf),
......@@ -859,6 +856,7 @@ rustc_lint::late_lint_methods!(
859856 ByteCharSlice: byte_char_slices::ByteCharSlice = byte_char_slices::ByteCharSlice,
860857 ManualAssertEq: manual_assert_eq::ManualAssertEq = manual_assert_eq::ManualAssertEq,
861858 WithCapacityZero: with_capacity_zero::WithCapacityZero = with_capacity_zero::WithCapacityZero,
859 RefPatterns: ref_patterns::RefPatterns = ref_patterns::RefPatterns,
862860 // add late passes here, used by `cargo dev new_lint`
863861 ]]
864862);
src/tools/clippy/clippy_lints/src/lifetimes.rs+3-1
......@@ -161,7 +161,9 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
161161 }
162162
163163 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 }
165167 }
166168
167169 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 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::span_lint_and_then;
33use clippy_utils::numeric_literal::{NumericLiteral, Radix};
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use rustc_ast::ast::{Expr, ExprKind, LitKind};
66use rustc_ast::token;
77use rustc_errors::Applicability;
......@@ -207,7 +207,9 @@ pub struct LiteralDigitGrouping {
207207
208208impl EarlyLintPass for LiteralDigitGrouping {
209209 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
210 // `NumericLiteral::from_lit_kind` only accepts integer and float literals.
210211 if let ExprKind::Lit(lit) = expr.kind
212 && matches!(lit.kind, token::LitKind::Integer | token::LitKind::Float)
211213 && !expr.span.in_external_macro(cx.sess().source_map())
212214 {
213215 self.check_lit(cx, lit, expr.span);
......@@ -226,7 +228,7 @@ impl LiteralDigitGrouping {
226228 }
227229
228230 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)
230232 && let Ok(lit_kind) = LitKind::from_token_lit(lit)
231233 && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
232234 {
......@@ -418,7 +420,9 @@ pub struct DecimalLiteralRepresentation {
418420
419421impl EarlyLintPass for DecimalLiteralRepresentation {
420422 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
423 // Only integer tokens can produce `LitKind::Int`.
421424 if let ExprKind::Lit(lit) = expr.kind
425 && lit.kind == token::LitKind::Integer
422426 && !expr.span.in_external_macro(cx.sess().source_map())
423427 {
424428 self.check_lit(cx, lit, expr.span);
......@@ -436,10 +440,10 @@ impl DecimalLiteralRepresentation {
436440 // Lint integral literals.
437441 if let Ok(lit_kind) = LitKind::from_token_lit(lit)
438442 && 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)
440445 && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
441446 && num_lit.radix == Radix::Decimal
442 && val >= u128::from(self.threshold)
443447 {
444448 let hex = format!("{val:#X}");
445449 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
4848 && let PatKind::Binding(_, binding_id, ..) = pat.kind
4949 {
5050 // 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| {
5252 if expr.res_local_id() == Some(binding_id) {
5353 check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
5454 }
......@@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr
5656 });
5757 } else if let PatKind::Binding(_, binding_id, ..) = pat.kind {
5858 // Bound as a tuple, look for `tup.0`
59 for_each_expr(cx, body, |expr| {
59 for_each_expr(cx.tcx, body, |expr| {
6060 if let ExprKind::Field(e, field) = expr.kind
6161 && e.res_local_id() == Some(binding_id)
6262 && 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;
1313use rustc_hir::def::Res;
1414use rustc_hir::{Expr, ExprKind, Pat};
1515use rustc_lint::LateContext;
16use rustc_middle::ty;
1617use rustc_span::{Spanned, sym};
1718
1819use super::MANUAL_SLICE_FILL;
......@@ -84,6 +85,24 @@ pub(super) fn check<'tcx>(
8485 {
8586 sugg(cx, body, expr, recv_path.span, assignval.span);
8687 }
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 }
87106}
88107
89108fn sugg<'tcx>(
src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs+1-1
......@@ -1,7 +1,7 @@
11use super::UNUSED_ENUMERATE_INDEX;
22use clippy_utils::diagnostics::span_lint_hir_and_then;
33use clippy_utils::res::MaybeDef;
4use clippy_utils::source::{SpanRangeExt, walk_span_to_context};
4use clippy_utils::source::{SpanExt, walk_span_to_context};
55use clippy_utils::{expr_or_init, pat_is_wild, sym};
66use rustc_errors::Applicability;
77use rustc_hir::{Closure, Expr, ExprKind, Pat, PatKind, TyKind};
src/tools/clippy/clippy_lints/src/manual_async_fn.rs+4-4
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block};
2use clippy_utils::source::{SpanExt, position_before_rarrow, snippet_block};
33use rustc_errors::Applicability;
44use rustc_hir::intravisit::FnKind;
55use rustc_hir::{
......@@ -76,8 +76,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
7676 "this function can be simplified using the `async fn` syntax",
7777 |diag| {
7878 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)
8181 && let Some(ret_pos) = position_before_rarrow(&header_snip)
8282 && let Some((_, ret_snip)) = suggested_ret(cx, output)
8383 {
......@@ -185,6 +185,6 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str,
185185 Some((sugg, String::new()))
186186 } else {
187187 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}")))
189189 }
190190}
src/tools/clippy/clippy_lints/src/manual_clamp.rs+29-9
......@@ -140,7 +140,13 @@ struct InputMinMax<'tcx> {
140140
141141impl<'tcx> LateLintPass<'tcx> for ManualClamp {
142142 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 {
144150 let suggestion = is_if_elseif_else_pattern(cx, expr)
145151 .or_else(|| is_max_min_pattern(cx, expr))
146152 .or_else(|| is_call_max_min_pattern(cx, expr))
......@@ -155,6 +161,15 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
155161 }
156162
157163 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
158173 if is_in_const_context(cx) || !self.msrv.meets(cx, msrvs::CLAMP) {
159174 return;
160175 }
......@@ -293,18 +308,19 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx
293308/// ```
294309fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
295310 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 }
296318 && (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point()
297319 || 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
299320 && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point()
300321 || cx.ty_based_def(receiver).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord))
301322 {
302323 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 };
308324 Some(ClampSuggestion {
309325 params: InputMinMax {
310326 input,
......@@ -367,12 +383,16 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
367383 && let Some(inner_seg) = segment(cx, inner_fn)
368384 && let Some(outer_seg) = segment(cx, outer_fn)
369385 {
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 ) {
371391 (true, false) => (second, first),
372392 (false, true) => (first, second),
373393 _ => return None,
374394 };
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();
376396 let (min, max) = match (inner_seg, outer_seg) {
377397 (FunctionType::CmpMin, FunctionType::CmpMax) => (outer_arg, inner_arg),
378398 (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;
44use clippy_utils::is_from_proc_macro;
55use clippy_utils::msrvs::{self, Msrv};
66use clippy_utils::res::MaybeResPath;
7use clippy_utils::source::SpanRangeExt;
7use clippy_utils::source::SpanExt;
88use rustc_errors::Applicability;
99use rustc_hir::def::DefKind;
1010use rustc_hir::def_id::DefId;
......@@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
157157 // case somebody does that for some reason
158158 && (const_1.is_pos_infinity() && const_2.is_neg_infinity()
159159 || 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)
161161 {
162162 let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
163163 (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;
22use clippy_utils::diagnostics::span_lint_hir_and_then;
33use clippy_utils::msrvs::{self, Msrv};
44use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
5use clippy_utils::source::SpanRangeExt;
5use clippy_utils::source::SpanExt;
66use clippy_utils::sym;
77use clippy_utils::visitors::{is_local_used, local_used_once};
88use rustc_errors::Applicability;
......@@ -105,8 +105,8 @@ impl LateLintPass<'_> for ManualHashOne {
105105 finish_expr.span,
106106 "manual implementation of `BuildHasher::hash_one`",
107107 |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)
110110 {
111111 diag.multipart_suggestion(
112112 "try",
src/tools/clippy/clippy_lints/src/manual_range_patterns.rs+3-3
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use rustc_ast::LitKind;
44use rustc_data_structures::fx::FxHashSet;
55use rustc_errors::Applicability;
......@@ -143,8 +143,8 @@ impl LateLintPass<'_> for ManualRangePatterns {
143143 pat.span,
144144 "this OR pattern can be rewritten using a range",
145145 |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)
148148 {
149149 diag.span_suggestion(
150150 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;
22use clippy_utils::higher::{If, IfLetOrMatch};
33use clippy_utils::msrvs::Msrv;
44use clippy_utils::res::{MaybeDef, MaybeResPath};
5use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet};
5use clippy_utils::source::{IntoSpan, SpanExt, snippet};
66use clippy_utils::usage::mutated_variables;
77use clippy_utils::visitors::is_local_used;
88use 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 @@
11use clippy_utils::consts::ConstEvalCtxt;
22use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
3use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline};
3use clippy_utils::source::{SpanExt as _, indent_of, reindent_multiline};
44use rustc_ast::{BindingMode, ByRef};
55use rustc_errors::Applicability;
66use rustc_hir::def::Res;
......@@ -160,7 +160,7 @@ fn handle(
160160 );
161161 } else if let Some(ty_name) = find_type_name(cx, cx.typeck_results().expr_ty(condition))
162162 && 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)
164164 && let Some(indent) = indent_of(cx, expr.span)
165165 && ConstEvalCtxt::new(cx).eval_local(body_none, expr.span.ctxt()).is_some()
166166 {
src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::res::MaybeResPath;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::{SpanlessEq, fulfill_or_allowed, hash_expr, is_lint_allowed, search_same};
55use core::cmp::Ordering;
66use core::{iter, slice};
......@@ -152,7 +152,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
152152 if let Some(((_, dest), src)) = split
153153 && let Some(pat_snippets) = group
154154 .iter()
155 .map(|(_, arm)| arm.pat.span.get_source_text(cx))
155 .map(|(_, arm)| arm.pat.span.get_text(cx))
156156 .collect::<Option<Vec<_>>>()
157157 {
158158 let suggs = src
src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
22use clippy_utils::res::MaybeDef;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
55use rustc_errors::Applicability;
66use rustc_hir::def::{CtorKind, DefKind, Res};
......@@ -119,7 +119,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
119119 wildcard_ident.map_or(String::new(), |ident| {
120120 ident
121121 .span
122 .get_source_text(cx)
122 .get_text(cx)
123123 .map_or_else(|| format!("{} @ ", ident.name), |s| format!("{s} @ "))
124124 }),
125125 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;
2626
2727use clippy_config::Conf;
2828use clippy_utils::msrvs::{self, Msrv};
29use clippy_utils::source::walk_span_to_context;
29use clippy_utils::source::SpanExt;
3030use 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,
3232};
3333use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
34use rustc_lexer::{TokenKind, is_whitespace};
3435use rustc_lint::{LateContext, LateLintPass, LintContext};
3536use rustc_session::impl_lint_pass;
36use rustc_span::{SpanData, SyntaxContext};
37use rustc_span::Span;
3738
3839declare_clippy_lint! {
3940 /// ### What it does
......@@ -1084,34 +1085,38 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
10841085 try_err::check(cx, expr, ex);
10851086 }
10861087
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 {
10881111 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)) {
10921115 match_same_arms::check(cx, arms);
10931116 }
10941117
10951118 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);
11151120 match_bool::check(cx, ex, arms, expr);
11161121 overlapping_arms::check(cx, ex, arms);
11171122 match_wild_enum::check(cx, ex, arms);
......@@ -1216,64 +1221,51 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
12161221 }
12171222}
12181223
1219/// Checks if there are any arms with a `#[cfg(..)]` attribute.
1220fn 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]
1232fn 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
12721261 }
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
12771269 }
12781270}
12791271
src/tools/clippy/clippy_lints/src/matches/single_match.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use 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,
44};
55use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs};
66use 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};
2222/// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty
2323/// match arms.
2424fn 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"/*"))
2626}
2727
2828pub(crate) fn check<'tcx>(
src/tools/clippy/clippy_lints/src/methods/by_ref_peekable_peek.rs created+84
......@@ -0,0 +1,84 @@
1use crate::clippy_utils::res::MaybeTypeckRes;
2use clippy_utils::diagnostics::span_lint_and_then;
3use clippy_utils::res::{MaybeDef, MaybeResPath as _};
4use clippy_utils::sugg::Sugg;
5use clippy_utils::sym;
6use clippy_utils::ty::implements_trait;
7use rustc_ast::BindingMode;
8use rustc_errors::Applicability;
9use rustc_hir::{Expr, ExprKind, LetStmt, Node, PatKind};
10use rustc_lint::LateContext;
11use rustc_middle::ty;
12
13use super::BY_REF_PEEKABLE_PEEK;
14
15pub(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 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::msrvs::{self, Msrv};
33use clippy_utils::res::MaybeDef;
4use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
4use clippy_utils::source::{SpanExt, indent_of, reindent_multiline};
55use clippy_utils::sym;
66use rustc_ast::ast::LitKind;
77use rustc_errors::Applicability;
......@@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
5151 "case-sensitive file extension comparison",
5252 |diag| {
5353 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) {
5555 let recv_source = if cx.typeck_results().expr_ty(recv).is_ref() {
5656 recv_source.to_owned()
5757 } else {
src/tools/clippy/clippy_lints/src/methods/chunks_exact_to_as_chunks.rs created+104
......@@ -0,0 +1,104 @@
1use super::CHUNKS_EXACT_TO_AS_CHUNKS;
2use clippy_utils::diagnostics::span_lint_and_then;
3use clippy_utils::msrvs::{self, Msrv};
4use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
5use clippy_utils::source::snippet_with_context;
6use clippy_utils::visitors::is_const_evaluatable;
7use clippy_utils::{get_expr_use_site, sym};
8use rustc_errors::Applicability;
9use rustc_hir::{Expr, ExprKind, Node, PatKind};
10use rustc_lint::LateContext;
11use rustc_middle::ty;
12use rustc_span::{DesugaringKind, ExpnKind, Span, Symbol};
13
14pub(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 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::res::MaybeDef;
3use clippy_utils::{is_range_full, sym};
2use clippy_utils::res::{MaybeDef, MaybeResPath};
3use clippy_utils::{is_full_collection_range, sym};
44use rustc_errors::Applicability;
5use rustc_hir::{Expr, ExprKind, LangItem, QPath};
5use rustc_hir::{Expr, LangItem};
66use rustc_lint::LateContext;
77use rustc_span::Span;
88
......@@ -16,8 +16,7 @@ const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap,
1616pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: Option<&Expr<'_>>) {
1717 if let Some(arg) = arg {
1818 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)
2120 {
2221 suggest(cx, expr, recv, span);
2322 }
src/tools/clippy/clippy_lints/src/methods/drain_collect.rs+20-56
......@@ -1,67 +1,31 @@
11use crate::methods::DRAIN_COLLECT;
22use clippy_utils::diagnostics::span_lint_and_sugg;
3use clippy_utils::res::MaybeDef;
3use clippy_utils::res::{MaybeDef, MaybeResPath};
44use clippy_utils::source::snippet;
5use clippy_utils::{is_range_full, std_or_core, sym};
5use clippy_utils::{is_full_collection_range, std_or_core, sym};
66use rustc_errors::Applicability;
7use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath};
7use rustc_hir::Expr;
88use rustc_lint::LateContext;
99use rustc_middle::ty;
10use rustc_middle::ty::Ty;
11use rustc_span::Symbol;
1210
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
19fn 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}`.
30fn 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`
37fn 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}`.
44fn 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
51pub(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))
11pub(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))
6125 && let Some(exec_context) = std_or_core(cx)
6226 {
6327 let recv = snippet(cx, recv.span, "<expr>");
64 let sugg = if let ty::Ref(..) = recv_ty.kind() {
28 let sugg = if is_ref {
6529 format!("{exec_context}::mem::take({recv})")
6630 } else {
6731 format!("{exec_context}::mem::take(&mut {recv})")
......@@ -71,8 +35,8 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re
7135 cx,
7236 DRAIN_COLLECT,
7337 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",
7640 sugg,
7741 Applicability::MachineApplicable,
7842 );
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
100100}
101101
102102fn 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| {
104104 if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. })
105105 && !is_inside_always_const_context(cx.tcx, expr.hir_id)
106106 {
src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs+2-2
......@@ -1,7 +1,7 @@
11use super::FILTER_MAP_BOOL_THEN;
22use clippy_utils::diagnostics::span_lint_and_then;
33use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
4use clippy_utils::source::{SpanRangeExt, snippet_with_context};
4use clippy_utils::source::{SpanExt, snippet_with_context};
55use clippy_utils::ty::is_copy;
66use clippy_utils::{CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, peel_blocks, sym};
77use rustc_ast::Mutability;
......@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
4343 .iter()
4444 .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
4545 .count()
46 && let Some(param_snippet) = param.span.get_source_text(cx)
46 && let Some(param_snippet) = param.span.get_text(cx)
4747 {
4848 let mut applicability = Applicability::MachineApplicable;
4949 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 @@
1use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
2use clippy_utils::source::snippet;
1use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::snippet_with_applicability;
33use clippy_utils::ty::implements_trait;
44use clippy_utils::{path_to_local_with_projections, sym};
55use rustc_ast::{BindingMode, Mutability};
66use rustc_errors::Applicability;
7use rustc_hir as hir;
7use rustc_hir::{Expr, Node, PatKind};
88use rustc_lint::LateContext;
99
1010use super::FILTER_NEXT;
1111
12#[derive(Copy, Clone)]
12#[derive(Clone, Copy)]
1313pub(super) enum Direction {
1414 Forward,
1515 Backward,
......@@ -17,15 +17,13 @@ pub(super) enum Direction {
1717
1818/// lint use of `filter().next()` for `Iterator` and `filter().next_back()` for
1919/// `DoubleEndedIterator`
20pub(super) fn check<'tcx>(
21 cx: &LateContext<'tcx>,
22 expr: &'tcx hir::Expr<'_>,
23 recv: &'tcx hir::Expr<'_>,
24 filter_arg: &'tcx hir::Expr<'_>,
20pub(super) fn check(
21 cx: &LateContext<'_>,
22 expr: &Expr<'_>,
23 recv: &Expr<'_>,
24 filter_arg: &Expr<'_>,
2525 direction: Direction,
2626) {
27 // lint if caller of `.filter().next()` is an Iterator or `.filter().next_back()` is a
28 // DoubleEndedIterator
2927 let (required_trait, next_method, find_method) = match direction {
3028 Direction::Forward => (sym::Iterator, "next", "find"),
3129 Direction::Backward => (sym::DoubleEndedIterator, "next_back", "rfind"),
......@@ -37,30 +35,31 @@ pub(super) fn check<'tcx>(
3735 {
3836 return;
3937 }
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
5351 {
54 (Applicability::Unspecified, Some((pat.span, ident)))
52 app = Applicability::Unspecified;
53 Some((pat.span, ident))
5554 } else {
56 (Applicability::MachineApplicable, None)
55 None
5756 };
5857
59 diag.span_suggestion(
58 diag.span_suggestion_verbose(
6059 expr.span,
61 "try",
60 format!("use `.{find_method}(..)` instead"),
6261 format!("{iter_snippet}.{find_method}({filter_snippet})"),
63 applicability,
62 app,
6463 );
6564
6665 if let Some((pat_span, ident)) = pat {
......@@ -69,8 +68,6 @@ pub(super) fn check<'tcx>(
6968 format!("you will also need to make `{ident}` mutable, because `{find_method}` takes `&mut self`"),
7069 );
7170 }
72 });
73 } else {
74 span_lint(cx, FILTER_NEXT, expr.span, msg);
75 }
71 },
72 );
7673}
src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs+4-4
......@@ -1,7 +1,8 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::{is_range_full, sym};
2use clippy_utils::res::MaybeResPath;
3use clippy_utils::{is_full_collection_range, sym};
34use rustc_errors::Applicability;
4use rustc_hir::{Expr, ExprKind, QPath};
5use rustc_hir::{Expr, ExprKind};
56use rustc_lint::LateContext;
67use rustc_span::Span;
78
......@@ -12,8 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
1213 && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
1314 && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did())
1415 && 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)
1717 {
1818 span_lint_and_sugg(
1919 cx,
src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::msrvs::{self, Msrv};
33use clippy_utils::res::{MaybeDef, MaybeResPath};
4use clippy_utils::source::{IntoSpan, SpanRangeExt};
4use clippy_utils::source::{IntoSpan, SpanExt};
55use clippy_utils::ty::get_field_by_name;
66use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
77use clippy_utils::{ExprUseNode, get_expr_use_site, sym};
......@@ -47,7 +47,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
4747 let can_lint = for_each_expr_without_closures(block.stmts, |e| {
4848 if let ExprKind::Closure(c) = e.kind {
4949 // 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| {
5151 if e.res_local_id() == Some(arg_id) {
5252 let (kind, same_ctxt) = check_use(cx, ctxt, e);
5353 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 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
3use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
3use clippy_utils::source::{SpanExt, indent_of, reindent_multiline};
44use rustc_errors::Applicability;
55use rustc_hir::LangItem::{ResultErr, ResultOk};
66use rustc_hir::{Expr, ExprKind, PatKind};
......@@ -27,8 +27,8 @@ pub(super) fn check<'tcx>(
2727 && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind
2828 && err_path.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr)
2929 && 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)
3232 && let Some(indent) = indent_of(cx, expr.span)
3333 {
3434 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 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::eager_or_lazy::switch_to_eager_eval;
23use clippy_utils::msrvs::{self, Msrv};
34use clippy_utils::peel_blocks;
45use clippy_utils::res::{MaybeDef, MaybeResPath};
......@@ -29,6 +30,8 @@ pub(super) fn check<'tcx>(
2930 && let ExprKind::MethodCall(method_path, map_recv, [map_arg], _) = peel_blocks(outer_value).kind
3031 && method_path.ident.name == sym::map
3132 && 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)
3235 // `b` does not reference the outer closure parameter `a`.
3336 && !local_used_in(cx, outer_param_id, map_recv)
3437 // `|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;
22use clippy_utils::is_from_proc_macro;
33use clippy_utils::msrvs::{self, Msrv};
44use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
5use clippy_utils::source::SpanRangeExt;
5use clippy_utils::source::SpanExt;
66use clippy_utils::ty::implements_trait;
77use rustc_errors::Applicability;
88use rustc_hir::def::{DefKind, Res};
......@@ -31,14 +31,12 @@ pub(super) fn check<'tcx>(
3131 && let ExprKind::Closure(closure) = acc.kind
3232 && msrv.meets(cx, msrvs::ITERATOR_TRY_FOLD)
3333 && !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))
3735 {
3836 let init_snip = rest
3937 .is_empty()
4038 .then_some(first.span)
41 .and_then(|span| span.get_source_text(cx))
39 .and_then(|span| span.get_text(cx))
4240 .map_or_else(|| "...".to_owned(), |src| src.to_owned());
4341
4442 span_lint_and_sugg(
src/tools/clippy/clippy_lints/src/methods/map_all_any_identity.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::is_expr_identity_function;
33use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use rustc_errors::Applicability;
66use rustc_hir::Expr;
77use rustc_lint::LateContext;
......@@ -24,7 +24,7 @@ pub(super) fn check(
2424 && cx.ty_based_def(recv).opt_parent(cx).is_diag_item(cx, sym::Iterator)
2525 && is_expr_identity_function(cx, any_arg)
2626 && 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)
2828 {
2929 span_lint_and_then(
3030 cx,
src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs+4-4
......@@ -128,10 +128,10 @@ pub(super) fn check<'tcx>(
128128 (SuggestedKind::AndThen, _) => "and_then",
129129 (SuggestedKind::IsVariantAnd, sym::Result) => "is_ok_and",
130130 (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.
135135 return;
136136 },
137137 _ => "map_or",
src/tools/clippy/clippy_lints/src/methods/mod.rs+114-9
......@@ -1,4 +1,5 @@
11mod bind_instead_of_map;
2mod by_ref_peekable_peek;
23mod bytecount;
34mod bytes_count_to_len;
45mod bytes_nth;
......@@ -9,6 +10,7 @@ mod chars_last_cmp;
910mod chars_last_cmp_with_unwrap;
1011mod chars_next_cmp;
1112mod chars_next_cmp_with_unwrap;
13mod chunks_exact_to_as_chunks;
1214mod clear_with_drain;
1315mod clone_on_copy;
1416mod clone_on_ref_ptr;
......@@ -141,6 +143,7 @@ mod unnecessary_map_or_else;
141143mod unnecessary_min_or_max;
142144mod unnecessary_sort_by;
143145mod unnecessary_to_owned;
146mod unnecessary_unwrap_unchecked;
144147mod unwrap_expect_used;
145148mod useless_asref;
146149mod useless_nonzero_new_unchecked;
......@@ -201,6 +204,39 @@ declare_clippy_lint! {
201204 "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"
202205}
203206
207declare_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
204240declare_clippy_lint! {
205241 /// ### What it does
206242 /// It checks for `str::bytes().count()` and suggests replacing it with
......@@ -329,6 +365,32 @@ declare_clippy_lint! {
329365 "using `.chars().next()` to check if a string starts with a char"
330366}
331367
368declare_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
332394declare_clippy_lint! {
333395 /// ### What it does
334396 /// Checks for usage of `.drain(..)` for the sole purpose of clearing a container.
......@@ -4541,6 +4603,34 @@ declare_clippy_lint! {
45414603 "unnecessary calls to `to_owned`-like functions"
45424604}
45434605
4606declare_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
45444634declare_clippy_lint! {
45454635 /// ### What it does
45464636 /// Checks for usages of the following functions with an argument that constructs a default value
......@@ -4835,9 +4925,11 @@ impl_lint_pass!(Methods => [
48354925 BIND_INSTEAD_OF_MAP,
48364926 BYTES_COUNT_TO_LEN,
48374927 BYTES_NTH,
4928 BY_REF_PEEKABLE_PEEK,
48384929 CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
48394930 CHARS_LAST_CMP,
48404931 CHARS_NEXT_CMP,
4932 CHUNKS_EXACT_TO_AS_CHUNKS,
48414933 CLEAR_WITH_DRAIN,
48424934 CLONED_INSTEAD_OF_COPIED,
48434935 CLONE_ON_COPY,
......@@ -4979,6 +5071,7 @@ impl_lint_pass!(Methods => [
49795071 UNNECESSARY_RESULT_MAP_OR_ELSE,
49805072 UNNECESSARY_SORT_BY,
49815073 UNNECESSARY_TO_OWNED,
5074 UNNECESSARY_UNWRAP_UNCHECKED,
49825075 UNWRAP_OR_DEFAULT,
49835076 UNWRAP_USED,
49845077 USELESS_ASREF,
......@@ -5198,12 +5291,15 @@ impl Methods {
51985291 _ => {},
51995292 }
52005293 },
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 },
52015297 (sym::and_then, [arg]) => {
52025298 manual_option_zip::check(cx, expr, recv, arg, self.msrv);
52035299 let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
52045300 let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
52055301 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);
52075303 if !ule_and_linted {
52085304 return_and_then::check(cx, expr, recv, arg);
52095305 }
......@@ -5277,8 +5373,10 @@ impl Methods {
52775373 manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
52785374 }
52795375 },
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 _ => {},
52825380 },
52835381 _ => {},
52845382 }
......@@ -5333,7 +5431,11 @@ impl Methods {
53335431 }
53345432 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
53355433 },
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, []) => {
53375439 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
53385440 },
53395441 (sym::extend, [arg]) => {
......@@ -5439,7 +5541,7 @@ impl Methods {
54395541 get_last_with_len::check(cx, expr, recv, arg);
54405542 },
54415543 (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);
54435545 },
54445546 (sym::hash, [arg]) => {
54455547 unit_hash::check(cx, expr, recv, arg);
......@@ -5594,16 +5696,19 @@ impl Methods {
55945696 ptr_offset_by_literal::check(cx, expr, self.msrv);
55955697 },
55965698 (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);
55985700 },
55995701 (sym::open, [_]) => {
56005702 open_options::check(cx, expr, recv);
56015703 },
56025704 (sym::or_else, [arg]) => {
56035705 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);
56055707 }
56065708 },
5709 (sym::peek, []) => {
5710 by_ref_peekable_peek::check(cx, expr, recv);
5711 },
56075712 (sym::push, [arg]) => {
56085713 path_buf_push_overwrite::check(cx, expr, arg);
56095714 },
......@@ -5699,7 +5804,7 @@ impl Methods {
56995804 if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) {
57005805 return;
57015806 }
5702 unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
5807 unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some", true);
57035808 },
57045809 (sym::try_into, []) if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::TryInto) => {
57055810 unnecessary_fallible_conversions::check_method(cx, expr);
......@@ -5789,7 +5894,7 @@ impl Methods {
57895894 );
57905895 },
57915896 _ => {
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);
57935898 },
57945899 }
57955900 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;
88use super::NEEDLESS_CHARACTER_ITERATION;
99use super::utils::get_last_chain_binding_hir_id;
1010use clippy_utils::diagnostics::span_lint_and_sugg;
11use clippy_utils::source::SpanRangeExt;
11use clippy_utils::source::SpanExt;
1212use clippy_utils::{peel_blocks, sym};
1313
1414fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> {
......@@ -36,7 +36,7 @@ fn handle_expr(
3636 && receiver.res_local_id() == Some(first_param)
3737 && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs()
3838 && *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)
4040 {
4141 span_lint_and_sugg(
4242 cx,
......@@ -78,7 +78,7 @@ fn handle_expr(
7878 if revert != is_all
7979 && fn_path.ty_rel_def(cx).is_diag_item(cx, sym::char_is_ascii)
8080 && 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)
8282 {
8383 span_lint_and_sugg(
8484 cx,
src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::res::{MaybeDef, MaybeResPath};
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::sym;
55use clippy_utils::usage::local_used_after_expr;
66use rustc_errors::Applicability;
......@@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name
3232 expr.span,
3333 "derefed type is same as origin",
3434 "try",
35 recv.span.get_source_text(cx).unwrap().to_owned(),
35 recv.span.get_text(cx).unwrap().to_owned(),
3636 Applicability::MachineApplicable,
3737 );
3838 }
src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs+25-8
......@@ -30,9 +30,26 @@ pub(super) fn check<'tcx>(
3030 args: &'tcx [hir::Expr<'_>],
3131 msrv: Msrv,
3232) {
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
3350 if let [arg] = args {
3451 let inner_arg = peel_blocks(arg);
35 for_each_expr(cx, inner_arg, |ex| {
52 for_each_expr(cx.tcx, inner_arg, |ex| {
3653 // `or_fun_call` lint needs to take nested expr into account,
3754 // but `unwrap_or_default` lint doesn't, we don't want something like:
3855 // `opt.unwrap_or(Foo { inner: String::default(), other: 1 })` to get replaced by
......@@ -72,7 +89,7 @@ pub(super) fn check<'tcx>(
7289 // `map_or` takes two arguments
7390 if let [arg, lambda] = args {
7491 let inner_arg = peel_blocks(arg);
75 for_each_expr(cx, inner_arg, |ex| {
92 for_each_expr(cx.tcx, inner_arg, |ex| {
7693 let is_top_most_expr = ex.hir_id == inner_arg.hir_id;
7794 match ex.kind {
7895 hir::ExprKind::Call(fun, fun_args) => {
......@@ -112,6 +129,12 @@ fn check_unwrap_or_default(
112129 method_span: Span,
113130 msrv: Msrv,
114131) -> 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
115138 let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs();
116139
117140 // Check MSRV, but only for `Result::unwrap_or_default`
......@@ -150,12 +173,6 @@ fn check_unwrap_or_default(
150173 }
151174 };
152175
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
159176 let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| {
160177 cx.tcx
161178 .inherent_impls(adt_def.did())
src/tools/clippy/clippy_lints/src/methods/ptr_offset_by_literal.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::msrvs::{self, Msrv};
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::sym;
55use rustc_ast::LitKind;
66use rustc_errors::Applicability;
......@@ -92,7 +92,7 @@ fn expr_as_literal<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti
9292}
9393
9494fn 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)?;
9696 let text = peel_parens_str(&text);
9797 Some(text.trim_end_matches("isize").trim_end_matches('_').to_string())
9898}
src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs+3-3
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
3use clippy_utils::source::{SpanRangeExt as _, snippet_with_applicability};
3use clippy_utils::source::{SpanExt as _, snippet_with_applicability};
44use clippy_utils::{SpanlessEq, get_parent_expr, higher, is_integer_literal, sym};
55use rustc_errors::Applicability;
66use rustc_hir::{Expr, ExprKind, Node, Pat, PatKind, QPath};
......@@ -49,8 +49,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
4949 ),
5050 )];
5151 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)
5454 {
5555 suggestions.extend([(left, snip_right.to_string()), (right, snip_left.to_string())]);
5656 } else {
src/tools/clippy/clippy_lints/src/methods/str_split.rs+3-2
......@@ -22,8 +22,9 @@ pub(super) fn check<'a>(
2222 // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`.
2323 if let ExprKind::MethodCall(trim_method_name, trim_recv, [], trim_span) = split_recv.kind
2424 && 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)
2728 && let ExprKind::Lit(split_lit) = split_arg.kind
2829 && matches!(
2930 split_lit.node,
src/tools/clippy/clippy_lints/src/methods/str_splitn.rs+1-1
......@@ -214,7 +214,7 @@ fn indirect_usage<'tcx>(
214214 }) = stmt.kind
215215 {
216216 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| {
218218 if e.res_local_id() == Some(binding) {
219219 path_to_binding = Some(e);
220220 }
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;
22use clippy_utils::is_from_proc_macro;
33use clippy_utils::msrvs::{self, Msrv};
44use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
5use clippy_utils::source::SpanRangeExt;
5use clippy_utils::source::SpanExt;
66use itertools::Itertools;
77use rustc_ast::LitKind;
88use rustc_errors::Applicability;
......@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
3535 }
3636 && msrv.meets(cx, msrvs::MATCHES_MACRO)
3737 && !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)
3939 {
4040 // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then
4141 // 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 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33
44use rustc_errors::Applicability;
55use rustc_hir::{Expr, ExprKind};
......@@ -29,8 +29,8 @@ pub(super) fn check(
2929 };
3030
3131 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)
3434 {
3535 let (sugg_span, suggestion) = if is_some {
3636 (
src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs+5-5
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
22use clippy_utils::res::MaybeDef;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::sym;
55
66use rustc_errors::Applicability;
......@@ -39,11 +39,11 @@ pub(super) fn check(
3939 return;
4040 };
4141 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)
4444 {
4545 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)
4747 {
4848 format!("::{generics_snippet}")
4949 } else {
......@@ -64,7 +64,7 @@ pub(super) fn check(
6464 suggestion,
6565 Applicability::MaybeIncorrect,
6666 );
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) {
6868 let full_span = get_caller.span.with_hi(call_span.hi());
6969
7070 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;
22use clippy_utils::diagnostics::span_lint_and_then;
33use clippy_utils::higher::ForLoop;
44use clippy_utils::res::MaybeResPath;
5use clippy_utils::source::SpanRangeExt;
5use clippy_utils::source::SpanExt;
66use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
77use clippy_utils::visitors::for_each_expr_without_closures;
88use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr};
......@@ -42,7 +42,7 @@ pub fn check_for_loop_iter(
4242 && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent)
4343 && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body)
4444 && !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)
4646 {
4747 // Issue 12098
4848 // https://github.com/rust-lang/rust-clippy/issues/12098
......@@ -102,7 +102,7 @@ pub fn check_for_loop_iter(
102102 && implements_trait(cx, collection_ty, into_iterator_trait_id, &[])
103103 && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item)
104104 && 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)
106106 {
107107 collection_snippet
108108 } else {
src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs+40-16
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::res::MaybeDef;
3use clippy_utils::source::snippet;
3use clippy_utils::source::{snippet, snippet_with_applicability};
44use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage};
55use hir::FnRetTy;
66use rustc_errors::Applicability;
......@@ -18,6 +18,7 @@ pub(super) fn check<'tcx>(
1818 recv: &'tcx hir::Expr<'_>,
1919 arg: &'tcx hir::Expr<'_>,
2020 simplify_using: &str,
21 use_turbofish: bool,
2122) -> bool {
2223 let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option);
2324 let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result);
......@@ -46,23 +47,43 @@ pub(super) fn check<'tcx>(
4647 } else {
4748 "unnecessary closure used with `bool::then`"
4849 };
49 let applicability = if body
50
51 let mut applicability = Applicability::MachineApplicable;
52 if body
5053 .params
5154 .iter()
5255 // 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 },
6687 };
6788
6889 // This is a duplicate of what's happening in clippy_lints::methods::method_call,
......@@ -73,7 +94,10 @@ pub(super) fn check<'tcx>(
7394 diag.span_suggestion_verbose(
7495 span,
7596 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 ),
77101 applicability,
78102 );
79103 });
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<
262262 if mirrored_exprs(left_expr, right_expr, &binding_map, BindingSource::Left) {
263263 (left_expr, l_pat.span, false)
264264 } 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)
266274 } else {
267275 return None;
268276 };
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};
33use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
44use clippy_utils::msrvs::{self, Msrv};
55use clippy_utils::res::MaybeDef;
6use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_context};
6use clippy_utils::source::{SpanExt, snippet, snippet_with_context};
77use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_and_count_ty_refs};
88use clippy_utils::visitors::find_all_ret_expressions;
99use 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(
217217 && let parent_ty = cx.typeck_results().expr_ty(parent)
218218 && implements_trait(cx, parent_ty, iterator_trait_id, &[])
219219 && 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)
221221 // If the receiver is a `Cow`, we can't remove the `into_owned` generally, see https://github.com/rust-lang/rust-clippy/issues/13624.
222222 && !cx.typeck_results().expr_ty(receiver).is_diag_item(cx, sym::Cow)
223223 // 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>,
313313fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
314314 if let Some(parent) = get_parent_expr(cx, expr)
315315 && 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)
318318 {
319319 // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x`
320320 // 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
712712 && let arg_ty = arg_ty.peel_refs()
713713 // For now we limit this lint to `String` and `Vec`.
714714 && (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)
716716 {
717717 span_lint_and_sugg(
718718 cx,
src/tools/clippy/clippy_lints/src/methods/unnecessary_unwrap_unchecked.rs created+276
......@@ -0,0 +1,276 @@
1use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::res::MaybeQPath;
3use clippy_utils::ty::{option_or_result_arg_ty, same_type_modulo_regions};
4use clippy_utils::{is_from_proc_macro, last_path_segment, over};
5use rustc_errors::Applicability;
6use rustc_hir::def::{DefKind, Namespace, Res};
7use rustc_hir::def_id::DefId;
8use rustc_hir::{Body, Expr, ExprKind, PatKind, Safety};
9use rustc_lint::LateContext;
10use rustc_middle::ty::{self, Ty};
11use rustc_span::Span;
12use rustc_span::symbol::Ident;
13
14use super::UNNECESSARY_UNWRAP_UNCHECKED;
15
16#[derive(Clone, Copy, Debug)]
17enum Variant {
18 /// Free `fn` in a module
19 Fn,
20 /// Associated item from an `impl`
21 Assoc(AssocKind),
22}
23
24impl 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)]
42enum AssocKind {
43 /// No `self`: `fn new() -> Self`
44 Fn,
45 /// Has `self`: `fn ty<'tcx>(&self) -> Ty<'tcx>`
46 Method,
47}
48
49impl AssocKind {
50 fn new(fn_has_self_parameter: bool) -> Self {
51 if fn_has_self_parameter { Self::Method } else { Self::Fn }
52 }
53}
54
55fn 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`]
65fn 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`]
103fn 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`
131fn 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
186pub(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
7979 }
8080 },
8181 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 };
8287 if cx.typeck_results().expr_ty(receiver).is_floating_point()
8388 || cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Ord)
8489 {
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)
9091 } else {
9192 None
9293 }
src/tools/clippy/clippy_lints/src/misc_early/mod.rs+9-5
......@@ -333,11 +333,15 @@ impl EarlyLintPass for MiscEarlyLints {
333333 }
334334
335335 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 {
341345 MiscEarlyLints::check_lit(cx, lit, expr.span);
342346 }
343347 }
src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs+2-2
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use itertools::Itertools;
44use rustc_ast::ast::{Pat, PatKind};
55use rustc_lint::EarlyContext;
......@@ -59,7 +59,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
5959 .iter()
6060 .filter_map(|f| match f.pat.kind {
6161 PatKind::Wild => None,
62 _ => f.span.get_source_text(cx),
62 _ => f.span.get_text(cx),
6363 })
6464 .format(", "),
6565 ));
src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::span_lint_and_sugg;
33use clippy_utils::paths::{PathNS, lookup_path_str};
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use rustc_errors::Applicability;
66use rustc_hir::def::Res;
77use rustc_hir::def_id::DefIdMap;
......@@ -78,7 +78,7 @@ impl LateLintPass<'_> for ImportRename {
7878 && let Some(name) = self.renames.get(&id)
7979 // Remove semicolon since it is not present for nested imports
8080 && 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)
8282 && let Some(import) = match snip.split_once(" as ") {
8383 None => Some(snip.as_str()),
8484 Some((import, rename)) => {
src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs+2-2
......@@ -109,7 +109,7 @@ fn should_lint<'tcx>(
109109 // Is there a call to `DebugStruct::debug_struct`? Do lint if there is.
110110 let mut has_debug_struct = false;
111111
112 for_each_expr(cx, block, |expr| {
112 for_each_expr(cx.tcx, block, |expr| {
113113 if let ExprKind::MethodCall(path, recv, ..) = &expr.kind {
114114 let recv_ty = typeck_results.expr_ty(recv).peel_refs();
115115
......@@ -166,7 +166,7 @@ fn check_struct<'tcx>(
166166 let mut has_direct_field_access = false;
167167 let mut field_accesses = FxHashSet::default();
168168
169 for_each_expr(cx, block, |expr| {
169 for_each_expr(cx.tcx, block, |expr| {
170170 if let ExprKind::Field(target, ident) = expr.kind
171171 && let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs()
172172 && target_ty == self_ty
src/tools/clippy/clippy_lints/src/missing_inline.rs+28-123
......@@ -1,8 +1,6 @@
1use clippy_utils::diagnostics::{span_lint, span_lint_hir};
2use rustc_hir::def_id::DefId;
3use rustc_hir::{self as hir, Attribute, find_attr};
4use rustc_lint::{LateContext, LateLintPass, LintContext};
5use rustc_middle::ty::AssocContainer;
1use clippy_utils::diagnostics::span_lint;
2use rustc_hir::{ImplItem, ImplItemKind, Item, ItemKind, OwnerId, TraitFn, TraitItem, TraitItemKind, find_attr};
3use rustc_lint::{LateContext, LateLintPass};
64use rustc_session::config::CrateType;
75use rustc_session::declare_lint_pass;
86use rustc_span::Span;
......@@ -66,134 +64,41 @@ declare_clippy_lint! {
6664
6765declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]);
6866
69fn 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 }
67fn 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 );
8381 }
8482}
8583
8684impl<'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);
14888 }
14989 }
15090
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
15894 {
159 return;
95 check(cx, item.owner_id, item.span);
16096 }
97 }
16198
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);
187102 }
188
189 let attrs = cx.tcx.hir_attrs(impl_item.hir_id());
190 check_missing_inline_attrs(cx, attrs, impl_item.span, desc, None);
191103 }
192104}
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
196fn 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;
66use rustc_span::Span;
77
88use clippy_utils::diagnostics::span_lint;
9use clippy_utils::source::SpanRangeExt;
9use clippy_utils::source::SpanExt;
1010
1111declare_clippy_lint! {
1212 /// ### What it does
src/tools/clippy/clippy_lints/src/mutex_atomic.rs+1-1
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::res::MaybeDef;
3use clippy_utils::source::{IntoSpan, SpanRangeExt};
3use clippy_utils::source::{IntoSpan, SpanExt};
44use clippy_utils::sugg::Sugg;
55use clippy_utils::ty::ty_from_hir_ty;
66use rustc_errors::{Applicability, Diag};
src/tools/clippy/clippy_lints/src/needless_else.rs+2-2
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::source::{IntoSpan, SpanRangeExt};
2use clippy_utils::source::{IntoSpan, SpanExt};
33use rustc_ast::ast::{Expr, ExprKind};
44use rustc_errors::Applicability;
55use rustc_lint::{EarlyContext, EarlyLintPass};
......@@ -43,7 +43,7 @@ impl EarlyLintPass for NeedlessElse {
4343 && !else_clause.span.from_expansion()
4444 && block.stmts.is_empty()
4545 && 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| {
4747 // Ignore else blocks that contain comments or #[cfg]s
4848 !src.contains(['/', '#'])
4949 })
src/tools/clippy/clippy_lints/src/needless_ifs.rs+3-3
......@@ -1,7 +1,7 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::higher::If;
33use clippy_utils::is_from_proc_macro;
4use clippy_utils::source::{SpanRangeExt, walk_span_to_context};
4use clippy_utils::source::{SpanExt, walk_span_to_context};
55use rustc_errors::Applicability;
66use rustc_hir::{ExprKind, Stmt, StmtKind};
77use rustc_lint::{LateContext, LateLintPass, LintContext};
......@@ -48,7 +48,7 @@ impl LateLintPass<'_> for NeedlessIfs {
4848 && block.stmts.is_empty()
4949 && block.expr.is_none()
5050 && !expr.span.in_external_macro(cx.sess().source_map())
51 && then.span.check_source_text(cx, |src| {
51 && then.span.check_text(cx, |src| {
5252 // Ignore
5353 // - empty macro expansions
5454 // - empty reptitions in macro expansions
......@@ -58,7 +58,7 @@ impl LateLintPass<'_> for NeedlessIfs {
5858 .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace() || ch == b'\x0b')
5959 })
6060 && 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)
6262 && !is_from_proc_macro(cx, expr)
6363 {
6464 span_lint_and_sugg(
src/tools/clippy/clippy_lints/src/needless_late_init.rs+349-196
......@@ -1,16 +1,19 @@
1use clippy_config::Conf;
12use clippy_utils::diagnostics::span_lint_and_then;
23use clippy_utils::res::MaybeResPath;
3use clippy_utils::source::{SourceText, SpanRangeExt, snippet};
4use clippy_utils::source::snippet_with_applicability;
45use clippy_utils::ty::needs_ordered_drop;
56use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used};
67use core::ops::ControlFlow;
78use rustc_errors::{Applicability, MultiSpan};
89use 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,
1012};
1113use rustc_lint::{LateContext, LateLintPass};
12use rustc_session::declare_lint_pass;
14use rustc_session::impl_lint_pass;
1315use rustc_span::Span;
16use std::borrow::Cow;
1417
1518declare_clippy_lint! {
1619 /// ### What it does
......@@ -61,17 +64,126 @@ declare_clippy_lint! {
6164 "late initializations that can be replaced by a `let` statement with an initializer"
6265}
6366
64declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]);
67impl_lint_pass!(NeedlessLateInit<'_> => [NEEDLESS_LATE_INIT]);
6568
66fn 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(())
69pub struct NeedlessLateInit<'tcx> {
70 check_grouped_late_init: bool,
71 grouped_late_inits: Vec<(HirId, HirIdMap<GroupedLateInit<'tcx>>)>,
72}
73
74impl<'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(),
7279 }
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 }
75187}
76188
77189fn contains_let(cond: &Expr<'_>) -> bool {
......@@ -99,112 +211,35 @@ fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
99211}
100212
101213#[derive(Debug)]
102struct LocalAssign {
214struct LocalAssign<'tcx> {
103215 lhs_id: HirId,
104 rhs_span: Span,
216 rhs: &'tcx Expr<'tcx>,
105217 span: Span,
106218}
107219
108impl LocalAssign {
109 fn from_expr(expr: &Expr<'_>, span: Span) -> Option<Self> {
220impl<'tcx> LocalAssign<'tcx> {
221 fn new(expr: &'tcx Expr<'tcx>, span: Span) -> Option<Self> {
110222 if expr.span.from_expansion() {
111223 return None;
112224 }
113225
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 {
120230 lhs_id: lhs.res_local_id()?,
121 rhs_span: rhs.span.source_callsite(),
231 rhs,
122232 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
159fn 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 });
174234 }
175235
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
203237 }
204238}
205239
240#[derive(Debug)]
206241struct Usage<'tcx> {
207 stmt: &'tcx Stmt<'tcx>,
242 span: Span,
208243 expr: &'tcx Expr<'tcx>,
209244 needs_semi: bool,
210245}
......@@ -226,20 +261,34 @@ fn first_usage<'tcx>(
226261 .find(|&stmt| is_local_used(cx, stmt, binding_id))
227262 .and_then(|stmt| match stmt.kind {
228263 StmtKind::Expr(expr) => Some(Usage {
229 stmt,
264 span: stmt.span,
230265 expr,
231266 needs_semi: true,
232267 }),
233268 StmtKind::Semi(expr) => Some(Usage {
234 stmt,
269 span: stmt.span,
235270 expr,
236271 needs_semi: false,
237272 }),
238273 _ => None,
239274 })
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 })
240285}
241286
242fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option<SourceText> {
287fn local_snippet_without_semicolon<'a>(
288 cx: &LateContext<'_>,
289 local: &LetStmt<'_>,
290 applicability: &mut Applicability,
291) -> Cow<'a, str> {
243292 let span = local.span.with_hi(match local.ty {
244293 // let <pat>: <ty>;
245294 // ~~~~~~~~~~~~~~~
......@@ -249,105 +298,70 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) ->
249298 None => local.pat.span.hi(),
250299 });
251300
252 span.get_source_text(cx)
301 snippet_with_applicability(cx, span, "..", applicability)
253302}
254303
255fn 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)]
305struct LocalAssignGroup<'tcx>(Vec<LocalAssign<'tcx>>);
306
307impl<'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;
307333 }
308334
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 }
335349
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)
345354 }
355}
346356
347 Some(())
357#[derive(Debug)]
358struct GroupedLateInit<'tcx> {
359 usage: Usage<'tcx>,
360 assigns: Vec<LocalAssignGroup<'tcx>>,
361 decls: HirIdMap<&'tcx LetStmt<'tcx>>,
348362}
349363
350impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
364impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit<'tcx> {
351365 fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
352366 let mut parents = cx.tcx.hir_parent_iter(local.hir_id);
353367 if let LetStmt {
......@@ -362,8 +376,147 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
362376 } = local
363377 && let Some((_, Node::Stmt(local_stmt))) = parents.next()
364378 && let Some((_, Node::Block(block))) = parents.next()
379 && let Some(usage) = first_usage(cx, *binding_id, local_stmt.hir_id, block)
365380 {
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 }
367520 }
368521 }
369522}
src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs+2-3
......@@ -1,7 +1,6 @@
11use super::needless_pass_by_value::requires_exact_signature;
22use clippy_config::Conf;
33use clippy_utils::diagnostics::span_lint_hir_and_then;
4use clippy_utils::source::HasSession as _;
54use clippy_utils::visitors::for_each_expr;
65use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self};
76use core::ops::ControlFlow;
......@@ -207,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
207206 // We retrieve all the closures declared in the function because they will not be found
208207 // by `euv::Delegate`.
209208 let mut closures: FxIndexSet<LocalDefId> = FxIndexSet::default();
210 for_each_expr(cx, body, |expr| {
209 for_each_expr(cx.tcx, body, |expr| {
211210 if let ExprKind::Closure(closure) = expr.kind {
212211 closures.insert(closure.def_id);
213212 }
......@@ -269,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
269268 // If the argument is never used mutably, we emit the warning.
270269 let sp = input.span;
271270 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(
273272 inner_ty.ty.span.shrink_to_lo(),
274273 "mut",
275274 true,
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs+3-3
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::res::{MaybeDef, MaybeResPath};
3use clippy_utils::source::{SpanRangeExt, snippet};
3use clippy_utils::source::{SpanExt, snippet};
44use clippy_utils::ty::{implements_trait, implements_trait_with_env_from_iter, is_copy};
55use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
66use clippy_utils::{is_self, peel_hir_ty_options, strip_pat_refs, sym};
......@@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
248248 for (span, suggestion) in clone_spans {
249249 diag.span_suggestion(
250250 span,
251 span.get_source_text(cx).map_or_else(
251 span.get_text(cx).map_or_else(
252252 || "change the call to".to_owned(),
253253 |src| format!("change `{src}` to"),
254254 ),
......@@ -275,7 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
275275 for (span, suggestion) in clone_spans {
276276 diag.span_suggestion(
277277 span,
278 span.get_source_text(cx).map_or_else(
278 span.get_text(cx).map_or_else(
279279 || "change the call to".to_owned(),
280280 |src| format!("change `{src}` to"),
281281 ),
src/tools/clippy/clippy_lints/src/no_effect.rs+4-4
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
22use clippy_utils::res::MaybeResPath;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::ty::{expr_type_is_certain, has_drop};
55use clippy_utils::{in_automatically_derived, is_inside_always_const_context, is_lint_allowed, peel_blocks};
66use rustc_errors::Applicability;
......@@ -278,8 +278,8 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
278278 if let ExprKind::Index(..) = &expr.kind {
279279 if !is_inside_always_const_context(cx.tcx, expr.hir_id)
280280 && 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)
283283 {
284284 span_lint_hir_and_then(
285285 cx,
......@@ -300,7 +300,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
300300 } else {
301301 let mut snippet = String::new();
302302 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) {
304304 snippet.push_str(&snip);
305305 snippet.push_str("; ");
306306 } else {
src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs+3-3
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::source::{SpanRangeExt, snippet_with_applicability};
2use clippy_utils::source::{SpanExt, snippet_with_applicability};
33use clippy_utils::sym;
44use rustc_errors::Applicability;
55use rustc_hir::{Expr, ExprKind};
......@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
5252 && param.span.eq_ctxt(expr.span)
5353 && param
5454 .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', ..]))
5656 {
5757 show_error(cx, param);
5858 }
......@@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
6565 && param.span.eq_ctxt(expr.span)
6666 && param
6767 .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', ..]))
6969 {
7070 show_error(cx, param);
7171 }
src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs+1-1
......@@ -198,7 +198,7 @@ impl LazyInfo {
198198
199199 // visit body to collect `Lazy::new` calls
200200 let mut new_fn_calls = FxIndexMap::default();
201 for_each_expr::<(), ()>(cx, body, |ex| {
201 for_each_expr::<(), ()>(cx.tcx, body, |ex| {
202202 if let Some((fn_did, call_span)) = fn_def_id_and_span_from_body(cx, ex, body_id)
203203 && paths::ONCE_CELL_SYNC_LAZY_NEW.matches(cx, fn_did)
204204 {
src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_config::Conf;
22use clippy_config::types::MacroMatcher;
33use clippy_utils::diagnostics::span_lint_and_sugg;
4use clippy_utils::source::{SourceText, SpanRangeExt};
4use clippy_utils::source::{SourceText, SpanExt};
55use rustc_ast::ast;
66use rustc_data_structures::fx::{FxHashMap, FxHashSet};
77use rustc_errors::Applicability;
......@@ -129,7 +129,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace
129129 if let ExpnKind::Macro(MacroKind::Bang, mac_name) = expn_data.kind
130130 && let name = mac_name.as_str()
131131 && 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)
133133 // we must check only invocation sites
134134 // https://github.com/rust-lang/rust-clippy/issues/7422
135135 && 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 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use rustc_ast::token::LitKind;
44use rustc_ast::{Expr, ExprKind};
55use rustc_errors::Applicability;
......@@ -86,7 +86,7 @@ impl EarlyLintPass for OctalEscapes {
8686
8787 // Last check to make sure the source text matches what we read from the string.
8888 // 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() {
9090 [b'\\', b'0', lo] => lo == c_lo,
9191 [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo,
9292 _ => false,
src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs+3-3
......@@ -1,7 +1,7 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::msrvs::Msrv;
33use clippy_utils::qualify_min_const_fn::is_stable_const_fn;
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use clippy_utils::ty::implements_trait;
66use clippy_utils::visitors::for_each_expr_without_closures;
77use clippy_utils::{binop_traits, eq_expr_value, is_in_const_context, trait_ref_of_method};
......@@ -74,8 +74,8 @@ pub(super) fn check<'tcx>(
7474 expr.span,
7575 "manual implementation of an assign operation",
7676 |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)
7979 {
8080 diag.span_suggestion(
8181 expr.span,
src/tools/clippy/clippy_lints/src/operators/decimal_bitwise_operands.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_utils::diagnostics::span_lint_and_help;
22use clippy_utils::numeric_literal;
33use clippy_utils::numeric_literal::NumericLiteral;
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use rustc_ast::LitKind;
66use rustc_data_structures::packed::Pu128;
77use rustc_hir::{BinOpKind, Expr, ExprKind};
......@@ -40,7 +40,7 @@ fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
4040 if let LitKind::Int(Pu128(val), _) = lit.node
4141 && !is_single_digit(val)
4242 && !is_power_of_twoish(val)
43 && let Some(src) = lit.span.get_source_text(cx)
43 && let Some(src) = lit.span.get_text(cx)
4444 && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node)
4545 && num_lit.is_decimal()
4646 {
src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs+3-3
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use clippy_utils::{eq_expr_value, sugg};
44use rustc_errors::Applicability;
55use rustc_hir as hir;
......@@ -43,8 +43,8 @@ fn lint_misrefactored_assign_op(
4343 expr.span,
4444 "variable appears on both sides of an assignment operation",
4545 |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)
4848 {
4949 let a = &sugg::Sugg::hir(cx, assignee, "..");
5050 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 {
6464
6565fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
6666 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| {
6868 let Some(macro_call) = root_macro_call_first_node(cx, e) else {
6969 return ControlFlow::Continue(Descend::Yes);
7070 };
src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs+4-4
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils::res::{MaybeDef, MaybeResPath};
3use clippy_utils::source::{SpanRangeExt, snippet};
3use clippy_utils::source::{SpanExt, snippet};
44use clippy_utils::sym;
55use rustc_ast::{LitKind, StrStyle};
66use rustc_errors::Applicability;
......@@ -73,7 +73,7 @@ impl PathbufPushSearcher<'_> {
7373 && let Some(arg) = self.arg
7474 && let ExprKind::Lit(x) = arg.kind
7575 && 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)
7777 {
7878 Some(format!(" = PathBuf::from({s});"))
7979 } else {
......@@ -83,8 +83,8 @@ impl PathbufPushSearcher<'_> {
8383
8484 fn gen_pathbuf_join(&self, cx: &LateContext<'_>) -> Option<String> {
8585 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)?;
8888 Some(format!(" = {init_val}.join({arg_str});"))
8989 }
9090
src/tools/clippy/clippy_lints/src/ptr/ptr_arg.rs+4-4
......@@ -1,7 +1,7 @@
11use super::PTR_ARG;
22use clippy_utils::diagnostics::span_lint_hir_and_then;
33use clippy_utils::res::MaybeResPath;
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_expr_use_or_unification_node, is_lint_allowed, sym};
66use hir::LifetimeKind;
77use rustc_abi::ExternAbi;
......@@ -55,7 +55,7 @@ pub(super) fn check_body<'tcx>(
5555 .chain(result.replacements.iter().map(|r| {
5656 (
5757 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),
5959 )
6060 }))
6161 .collect(),
......@@ -156,7 +156,7 @@ impl fmt::Display for DerefTyDisplay<'_, '_> {
156156 DerefTy::Path => f.write_str("Path"),
157157 DerefTy::Slice(hir_ty, ty) => {
158158 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)) {
160160 Some(s) => f.write_str(&s)?,
161161 None => ty.fmt(f)?,
162162 }
......@@ -279,7 +279,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
279279 diag.span_suggestion(
280280 hir_ty.span,
281281 "change this to",
282 match ty.span().get_source_text(cx) {
282 match ty.span().get_text(cx) {
283283 Some(s) => format!("&{}{s}", mutability.prefix_str()),
284284 None => format!("&{}{}", mutability.prefix_str(), args.type_at(1)),
285285 },
src/tools/clippy/clippy_lints/src/question_mark.rs+8-1
......@@ -629,6 +629,11 @@ fn is_inferred_ret_closure(expr: &Expr<'_>) -> bool {
629629
630630impl<'tcx> LateLintPass<'tcx> for QuestionMark {
631631 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
632637 if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) || !self.msrv.meets(cx, msrvs::QUESTION_MARK_OPERATOR)
633638 {
634639 return;
......@@ -646,7 +651,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
646651 return;
647652 }
648653
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()
650657 && !is_in_const_context(cx)
651658 && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id)
652659 && 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};
33use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
44use clippy_utils::msrvs::{self, Msrv};
55use clippy_utils::res::MaybeResPath;
6use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability};
6use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability};
77use clippy_utils::sugg::Sugg;
88use clippy_utils::ty::implements_trait;
99use clippy_utils::{
......@@ -191,14 +191,21 @@ impl Ranges {
191191impl<'tcx> LateLintPass<'tcx> for Ranges {
192192 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
193193 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 )
194198 && self.msrv.meets(cx, msrvs::RANGE_CONTAINS)
199 && !is_in_const_context(cx)
195200 {
196201 check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
197202 }
198203
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 }
202209 }
203210}
204211
......@@ -210,10 +217,6 @@ fn check_possible_range_contains(
210217 expr: &Expr<'_>,
211218 span: Span,
212219) {
213 if is_in_const_context(cx) {
214 return;
215 }
216
217220 let combine_and = match op {
218221 BinOpKind::And | BinOpKind::BitAnd => true,
219222 BinOpKind::Or | BinOpKind::BitOr => false,
......@@ -300,7 +303,7 @@ fn check_possible_range_contains(
300303 if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind
301304 && op == lhs_op.node
302305 && 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| {
304307 // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong
305308 src.matches('(').count() == src.matches(')').count()
306309 })
......@@ -481,54 +484,58 @@ fn can_switch_ranges<'tcx>(
481484}
482485
483486// exclusive range plus one: `x..(y+1)`
484fn check_exclusive_range_plus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
487fn check_exclusive_range_plus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, range: &higher::Range<'tcx>) {
485488 check_range_switch(
486489 cx,
487490 expr,
491 range,
488492 RangeLimits::HalfOpen,
489493 y_plus_one,
490494 RANGE_PLUS_ONE,
491495 "an inclusive range would be more readable",
492 "..=",
493496 );
494497}
495498
496499// inclusive range minus one: `x..=(y-1)`
497fn check_inclusive_range_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
500fn check_inclusive_range_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, range: &higher::Range<'tcx>) {
498501 check_range_switch(
499502 cx,
500503 expr,
504 range,
501505 RangeLimits::Closed,
502506 y_minus_one,
503507 RANGE_MINUS_ONE,
504508 "an exclusive range would be more readable",
505 "..",
506509 );
507510}
508511
509512/// 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.
511514fn check_range_switch<'tcx>(
512515 cx: &LateContext<'tcx>,
513516 expr: &'tcx Expr<'_>,
517 range: &higher::Range<'tcx>,
514518 kind: RangeLimits,
515519 predicate: impl for<'hir> FnOnce(&Expr<'hir>) -> Option<&'hir Expr<'hir>>,
516520 lint: &'static Lint,
517521 msg: &'static str,
518 operator: &str,
519522) {
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
527529 && span.can_be_used_for_suggestions()
528530 && limits == kind
529531 && let Some(y) = predicate(end)
530532 && can_switch_ranges(cx, span.ctxt(), expr, kind, cx.typeck_results().expr_ty(y))
531533 {
534 // Suggest the opposite range limits to the ones being checked.
535 let operator = match kind {
536 RangeLimits::HalfOpen => "..=",
537 RangeLimits::Closed => "..",
538 };
532539 span_lint_and_then(cx, lint, span, msg, |diag| {
533540 let mut app = Applicability::MachineApplicable;
534541 let start = start.map_or(String::new(), |x| {
......@@ -550,7 +557,7 @@ fn check_range_switch<'tcx>(
550557 }
551558}
552559
553fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
560fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>, range: &higher::Range<'_>) {
554561 fn inside_indexing_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
555562 matches!(
556563 get_parent_expr(cx, expr),
......@@ -580,12 +587,12 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
580587 }
581588 }
582589
583 if let Some(higher::Range {
590 if let higher::Range {
584591 start: Some(start),
585592 end: Some(end),
586593 limits,
587594 span,
588 }) = higher::Range::hir(cx, expr)
595 } = *range
589596 && let ty = cx.typeck_results().expr_ty(start)
590597 && let ty::Int(_) | ty::Uint(_) = ty.kind()
591598 && let ecx = ConstEvalCtxt::new(cx)
src/tools/clippy/clippy_lints/src/raw_strings.rs+3-3
......@@ -1,6 +1,6 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::span_lint_and_then;
3use clippy_utils::source::{SpanRangeExt, snippet_opt};
3use clippy_utils::source::{SpanExt, snippet_opt};
44use rustc_ast::ast::{Expr, ExprKind};
55use rustc_ast::token::LitKind;
66use rustc_errors::Applicability;
......@@ -74,7 +74,7 @@ impl EarlyLintPass for RawStrings {
7474 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
7575 if let ExprKind::FormatArgs(format_args) = &expr.kind
7676 && !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'))
7878 && let Some(str) = snippet_opt(cx.sess(), format_args.span)
7979 && let count_hash = str.bytes().skip(1).take_while(|b| *b == b'#').count()
8080 && let Some(str) = str.get(count_hash + 2..str.len() - count_hash - 1)
......@@ -97,7 +97,7 @@ impl EarlyLintPass for RawStrings {
9797 _ => return,
9898 }
9999 && !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))
101101 {
102102 self.check_raw_string(cx, lit.symbol.as_str(), expr.span, prefix, max, lit.kind.descr());
103103 }
src/tools/clippy/clippy_lints/src/redundant_clone.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
22use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage};
33use clippy_utils::res::MaybeDef;
4use clippy_utils::source::SpanRangeExt;
4use clippy_utils::source::SpanExt;
55use clippy_utils::ty::{has_drop, is_copy, peel_and_count_ty_refs};
66use clippy_utils::{fn_has_unsatisfiable_preds, sym};
77use rustc_errors::Applicability;
......@@ -214,7 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
214214 .unwrap_crate_local()
215215 .lint_root;
216216
217 if let Some(snip) = span.get_source_text(cx)
217 if let Some(snip) = span.get_text(cx)
218218 && let Some(dot) = snip.rfind('.')
219219 {
220220 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 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::HasSession;
32use rustc_errors::Applicability;
43use rustc_hir::def::{DefKind, Res};
54use rustc_hir::{Item, ItemKind, UseKind};
......@@ -49,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
4948 && !cx.effective_visibilities.is_exported(item.owner_id.def_id)
5049 && self.is_exported.last() == Some(&false)
5150 && !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())
5352 {
5453 let span = item
5554 .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
144144
145145 // Also check that within the body of the function there is also no function call
146146 // 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| {
148148 if let ExprKind::Path(qpath) = &expr.kind
149149 && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id()
150150 && let Some(name) = tcx.opt_item_name(def_id)
src/tools/clippy/clippy_lints/src/ref_patterns.rs+7-5
......@@ -1,6 +1,7 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use rustc_ast::ast::{BindingMode, Pat, PatKind};
3use rustc_lint::{EarlyContext, EarlyLintPass};
2use clippy_utils::in_automatically_derived;
3use rustc_hir::{BindingMode, Pat, PatKind};
4use rustc_lint::{LateContext, LateLintPass};
45use rustc_session::declare_lint_pass;
56
67declare_clippy_lint! {
......@@ -29,10 +30,11 @@ declare_clippy_lint! {
2930
3031declare_lint_pass!(RefPatterns => [REF_PATTERNS]);
3132
32impl EarlyLintPass for RefPatterns {
33 fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
34 if let PatKind::Ident(BindingMode::REF, _, _) = pat.kind
33impl<'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
3536 && !pat.span.from_expansion()
37 && !in_automatically_derived(cx.tcx, pat.hir_id)
3638 {
3739 #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
3840 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};
55use clippy_utils::paths;
66use clippy_utils::paths::PathLookup;
77use clippy_utils::res::MaybeQPath;
8use clippy_utils::source::SpanRangeExt;
8use clippy_utils::source::SpanExt;
99use rustc_ast::ast::{LitKind, StrStyle};
1010use rustc_hir::def_id::DefIdMap;
1111use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId};
......@@ -190,7 +190,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescape
190190 };
191191
192192 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)
194194 && let Some(inner) = literal_snippet.get(offset as usize..)
195195 // Only convert to native rustc spans if the parsed regex matches the
196196 // 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<'_>)
6767 }
6868}
6969fn 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| {
7171 if let Some(def_id) = fn_def_id(cx, e)
7272 && cx
7373 .tcx
src/tools/clippy/clippy_lints/src/semicolon_block.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::span_lint_and_then;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use rustc_errors::Applicability;
55use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
66use rustc_lint::{LateContext, LateLintPass, LintContext};
......@@ -94,7 +94,7 @@ impl SemicolonBlock {
9494 // ({ 0 }); // if we remove this `;`, this will parse as a `({ 0 })(5);` function call
9595 // (5);
9696 // }
97 if remove_span.check_source_text(cx, |src| src.contains(')')) {
97 if remove_span.check_text(cx, |src| src.contains(')')) {
9898 return;
9999 }
100100
src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs+1-1
......@@ -127,7 +127,7 @@ fn find_insert_calls<'tcx>(
127127 contains_expr: &OpExpr<'tcx>,
128128 expr: &'tcx Expr<'_>,
129129) -> Option<OpExpr<'tcx>> {
130 for_each_expr(cx, expr, |e| {
130 for_each_expr(cx.tcx, expr, |e| {
131131 if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym::insert)
132132 && SpanlessEq::new(cx).eq_expr(SyntaxContext::root(), contains_expr.receiver, insert_expr.receiver)
133133 && 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>(
199199 id: HirId,
200200 except: Option<HirId>,
201201) -> bool {
202 for_each_expr(cx, visitable, |e| {
202 for_each_expr(cx.tcx, visitable, |e| {
203203 if except.is_some_and(|it| it == e.hir_id) {
204204 ControlFlow::Continue(Descend::No)
205205 } 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 {
146146 // ```
147147 let mut macros = Vec::new();
148148
149 let mut import_usage_visitor = ImportUsageVisitor::default();
150149 for item in items {
151150 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 {
152162 import_usage_visitor.visit_item(item);
153163 }
154164
155165 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) {
159167 self.found.entry(usage.item_id).or_default().push(usage);
160168 }
161169 }
src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs+2-2
......@@ -1,7 +1,7 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::higher::{Range, VecArgs};
33use clippy_utils::macros::root_macro_call_first_node;
4use clippy_utils::source::{SpanRangeExt, snippet_with_context};
4use clippy_utils::source::{SpanExt, snippet_with_context};
55use clippy_utils::ty::implements_trait;
66use clippy_utils::{is_no_std_crate, sym};
77use rustc_ast::{LitIntType, LitKind, RangeLimits, UintTy};
......@@ -91,7 +91,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
9191 return;
9292 };
9393
94 let Some(snippet) = span.get_source_text(cx) else {
94 let Some(snippet) = span.get_text(cx) else {
9595 return;
9696 };
9797 // `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>>
238238/// Does not catch individually moved items
239239fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: Msrv) -> bool {
240240 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,
255256 }
256257 }
257258
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<
147147
148148 // We want to retrieve all the comparisons done.
149149 // 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> {
151151 match sub_expr.kind {
152152 ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => {
153153 if left.res_local_id() == Some(binding)
......@@ -230,13 +230,13 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns {
230230 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
231231 if !expr.span.from_expansion()
232232 && 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()
235233 && let method_name = method.ident.name
236234 && let Some(&(_, pos)) = PATTERN_METHODS
237235 .iter()
238236 .find(|(array_method_name, _)| *array_method_name == method_name)
239237 && let Some(arg) = args.get(pos)
238 && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind()
239 && ty.is_str()
240240 {
241241 check_single_char_pattern_lint(cx, arg);
242242
src/tools/clippy/clippy_lints/src/trait_bounds.rs+3-6
......@@ -1,7 +1,7 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
33use clippy_utils::msrvs::{self, Msrv};
4use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability};
4use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability};
55use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro};
66use core::hash::{Hash, Hasher};
77use itertools::Itertools;
......@@ -212,10 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
212212 bounds_span = bounds_span.to(bound.span);
213213 }
214214
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(" + ");
219216
220217 span_lint_and_sugg(
221218 cx,
......@@ -451,7 +448,7 @@ fn rollup_traits<'cx, 'tcx>(
451448
452449 let traits = comparable_bounds
453450 .iter()
454 .filter_map(|&(_, span)| span.get_source_text(cx))
451 .filter_map(|&(_, span)| span.get_text(cx))
455452 .join(" + ");
456453
457454 span_lint_and_sugg(
src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs+3-3
......@@ -1,7 +1,7 @@
11use std::borrow::Cow;
22
33use clippy_utils::diagnostics::span_lint_and_then;
4use clippy_utils::source::{HasSession, SpanRangeExt as _};
4use clippy_utils::source::SpanExt as _;
55use rustc_errors::Applicability;
66use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind};
77use rustc_lint::LateContext;
......@@ -114,8 +114,8 @@ fn ty_cannot_be_named(ty: Ty<'_>) -> bool {
114114 )
115115}
116116
117fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> {
118 span.with_source_text(sess, |name| {
117fn maybe_name_by_expr<'a>(cx: &LateContext<'_>, span: Span, default: &'a str) -> Cow<'a, str> {
118 span.with_source_text(cx, |name| {
119119 (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into())
120120 })
121121 .flatten()
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs+1-1
......@@ -393,7 +393,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>(
393393 }
394394
395395 // 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 {
397397 hir::ExprKind::Block(
398398 Block {
399399 rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs+15-26
......@@ -1,4 +1,4 @@
1use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
1use clippy_utils::diagnostics::span_lint_and_then;
22use rustc_hir::def_id::DefId;
33use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
44use rustc_lint::{LateContext, LateLintPass};
......@@ -180,32 +180,21 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
180180 let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
181181 let arg_indices = get_args_to_check(cx, expr, args.len(), fn_mut_trait, ord_trait, partial_ord_trait);
182182 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 \
191190 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 );
209198 }
210199 }
211200 }
src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs+3-3
......@@ -1,7 +1,7 @@
11use std::iter;
22
33use clippy_utils::diagnostics::span_lint_and_then;
4use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
4use clippy_utils::source::{SpanExt, indent_of, reindent_multiline};
55use clippy_utils::sugg::Sugg;
66use clippy_utils::ty::expr_type_is_certain;
77use 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_
8585 && block.expr.is_none()
8686 && let Some(last_stmt) = block.stmts.iter().last()
8787 && 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)
8989 {
9090 Some((last_stmt.span, snip))
9191 } else {
......@@ -117,7 +117,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_
117117 .filter_map(|arg| get_expr_snippet_with_type_certainty(cx, arg))
118118 .collect();
119119
120 if let Some(call_snippet) = expr.span.get_source_text(cx) {
120 if let Some(call_snippet) = expr.span.get_text(cx) {
121121 if arg_snippets_without_redundant_exprs.is_empty()
122122 && let suggestions = args_to_recover
123123 .iter()
src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs+8-3
......@@ -1,10 +1,10 @@
11use clippy_config::Conf;
22use clippy_utils::diagnostics::span_lint_and_then;
3use clippy_utils::ty::approx_ty_size;
43use rustc_errors::Applicability;
54use rustc_hir::def_id::LocalDefId;
65use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
76use rustc_lint::{LateContext, LateLintPass};
7use rustc_middle::ty::layout::LayoutOf;
88use rustc_session::impl_lint_pass;
99use rustc_span::Symbol;
1010
......@@ -81,8 +81,13 @@ impl UnnecessaryBoxReturns {
8181
8282 // It's sometimes useful to return Box<T> if T is unsized, so don't lint those.
8383 // 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 {
8691 span_lint_and_then(
8792 cx,
8893 UNNECESSARY_BOX_RETURNS,
src/tools/clippy/clippy_lints/src/unnecessary_mut_passed.rs+1-1
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use rustc_errors::Applicability;
44use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
55use rustc_lint::{LateContext, LateLintPass};
src/tools/clippy/clippy_lints/src/unused_async.rs+2-2
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
22use clippy_utils::is_def_id_trait_method;
3use clippy_utils::source::{HasSession, snippet_with_applicability, walk_span_to_context};
3use clippy_utils::source::{snippet_with_applicability, walk_span_to_context};
44use clippy_utils::usage::is_todo_unimplemented_stub;
55use rustc_errors::Applicability;
66use rustc_hir::def::DefKind;
......@@ -303,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
303303 // evaluate the expression, to immediately evaluate the expression.
304304 let mut app = Applicability::MaybeIncorrect;
305305
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);
307307
308308 let signature_snippet = snippet_with_applicability(cx, signature_span, "_", &mut app);
309309 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 @@
11use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::source::{SpanRangeExt, position_before_rarrow};
2use clippy_utils::source::{SpanExt, position_before_rarrow};
33use clippy_utils::{is_never_expr, is_unit_expr};
44use rustc_ast::{Block, StmtKind};
55use rustc_errors::Applicability;
src/tools/clippy/clippy_lints/src/useless_conversion.rs+4-4
......@@ -132,8 +132,8 @@ fn into_iter_bound<'tcx>(
132132/// Extracts the receiver of a `.into_iter()` method call.
133133fn into_iter_call<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Option<&'hir Expr<'hir>> {
134134 if let ExprKind::MethodCall(name, recv, [], _) = expr.kind
135 && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IntoIterator)
136135 && name.ident.name == sym::into_iter
136 && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IntoIterator)
137137 {
138138 Some(recv)
139139 } else {
......@@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
208208 },
209209
210210 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) {
212212 let a = cx.typeck_results().expr_ty(e);
213213 let b = cx.typeck_results().expr_ty(recv);
214214 if same_type_modulo_regions(a, b) {
......@@ -393,8 +393,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
393393 );
394394 }
395395 }
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)
398398 && let a = cx.typeck_results().expr_ty(e)
399399 && let b = cx.typeck_results().expr_ty(recv)
400400 && 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;
77use clippy_utils::consts::{ConstEvalCtxt, Constant};
88use clippy_utils::diagnostics::span_lint_hir_and_then;
99use clippy_utils::msrvs::{self, Msrv};
10use clippy_utils::source::SpanRangeExt;
10use clippy_utils::source::SpanExt;
1111use clippy_utils::ty::is_copy;
1212use clippy_utils::visitors::for_each_local_use_after_expr;
1313use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_parent_expr, higher, is_in_test, span_contains_comment};
......@@ -285,10 +285,10 @@ impl SuggestedType {
285285 assert!(args_span.is_none_or(|s| !s.from_expansion()));
286286 assert!(len_span.is_none_or(|s| !s.from_expansion()));
287287
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"));
289289 let maybe_args = maybe_args.as_deref().unwrap_or_default();
290290 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"))
292292 .map(|st| format!("; {st}"))
293293 .unwrap_or_default();
294294
src/tools/clippy/clippy_lints/src/utils/author.rs+26-8
......@@ -6,11 +6,11 @@ use rustc_ast::ast::{LitFloatType, LitKind};
66use rustc_data_structures::fx::FxHashMap;
77use rustc_hir::def_id::DefId;
88use 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,
1010 FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr,
1111};
1212use rustc_lint::{LateContext, LateLintPass};
13use rustc_middle::ty::{FloatTy, IntTy, UintTy};
13use rustc_middle::ty::{FloatTy, IntTy, TypeckResults, UintTy};
1414use rustc_session::declare_lint_pass;
1515use rustc_span::symbol::{Ident, Symbol};
1616use std::cell::Cell;
......@@ -137,15 +137,31 @@ impl<'tcx> LateLintPass<'tcx> for Author {
137137
138138fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
139139 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 );
143148 }
144149}
145150
146151fn 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.
156fn check_node_with_body(
157 cx: &LateContext<'_>,
158 hir_id: HirId,
159 f: impl Fn(&PrintVisitor<'_, '_>),
160 body: Option<&Body<'_>>,
161) {
147162 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));
149165 println!("{{");
150166 println!(" // report your lint here");
151167 println!("}}");
......@@ -199,6 +215,7 @@ impl<T: Display> Display for OptionPat<T> {
199215
200216struct PrintVisitor<'a, 'tcx> {
201217 cx: &'a LateContext<'tcx>,
218 typeck_results: &'tcx TypeckResults<'tcx>,
202219 /// Fields are the current index that needs to be appended to pattern
203220 /// binding names
204221 ids: Cell<FxHashMap<&'static str, u32>>,
......@@ -207,9 +224,10 @@ struct PrintVisitor<'a, 'tcx> {
207224}
208225
209226impl<'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 {
211228 Self {
212229 cx,
230 typeck_results,
213231 ids: Cell::default(),
214232 first: Cell::new(true),
215233 }
......@@ -291,7 +309,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
291309 }
292310
293311 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()
295313 && !id.is_local()
296314 {
297315 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 @@
11use clippy_utils::macros::FormatArgsStorage;
2use clippy_utils::source::SpanRangeExt;
3use itertools::Itertools;
2use clippy_utils::source::{SpanExt, walk_span_to_context};
43use rustc_ast::{Crate, Expr, ExprKind, FormatArgs};
54use rustc_data_structures::fx::FxHashMap;
65use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
7use rustc_lint::{EarlyContext, EarlyLintPass};
6use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
87use rustc_session::impl_lint_pass;
9use rustc_span::{Span, hygiene};
10use std::iter::once;
8use rustc_span::source_map::SourceMap;
9use rustc_span::{Span, SpanData};
1110use std::mem;
1211
1312/// Populates [`FormatArgsStorage`] with AST [`FormatArgs`] nodes
1413pub struct FormatArgsCollector {
1514 format_args: FxHashMap<Span, FormatArgs>,
15 parent_spans: Vec<SpanData>,
1616 storage: FormatArgsStorage,
1717}
1818
......@@ -20,6 +20,7 @@ impl FormatArgsCollector {
2020 pub fn new(storage: FormatArgsStorage) -> Self {
2121 Self {
2222 format_args: FxHashMap::default(),
23 parent_spans: Vec::new(),
2324 storage,
2425 }
2526 }
......@@ -30,7 +31,7 @@ impl_lint_pass!(FormatArgsCollector => []);
3031impl EarlyLintPass for FormatArgsCollector {
3132 fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
3233 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) {
3435 return;
3536 }
3637
......@@ -43,53 +44,99 @@ impl EarlyLintPass for FormatArgsCollector {
4344 }
4445}
4546
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/// ```
65fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool {
66 let ctxt = args.span.ctxt();
47impl 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 };
67107
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 });
75129
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)
93139 })
94 })
140 .is_none()
141 }
95142}
src/tools/clippy/clippy_lints/src/visibility.rs+2-2
......@@ -1,5 +1,5 @@
11use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::SpanRangeExt;
2use clippy_utils::source::SpanExt;
33use rustc_ast::ast::{Item, VisibilityKind};
44use rustc_errors::Applicability;
55use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
......@@ -152,5 +152,5 @@ impl EarlyLintPass for Visibility {
152152}
153153
154154fn 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"))
156156}
src/tools/clippy/clippy_lints/src/write/literal.rs+3-3
......@@ -1,6 +1,6 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::macros::format_arg_removal_span;
3use clippy_utils::source::SpanRangeExt;
3use clippy_utils::source::SpanExt;
44use clippy_utils::sym;
55use rustc_ast::token::LitKind;
66use rustc_ast::{
......@@ -48,7 +48,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str)
4848 && let Some(arg) = format_args.arguments.by_index(index)
4949 && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind
5050 && !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)
5252 {
5353 let (replacement, replace_raw) = match lit.kind {
5454 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)
7171 _ => continue,
7272 };
7373
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 {
7575 continue;
7676 };
7777 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 @@
11use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils::macros::MacroCall;
3use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma};
3use clippy_utils::source::{SpanExt, expand_past_previous_comma};
44use clippy_utils::sym;
55use rustc_ast::{FormatArgs, FormatArgsPiece};
66use rustc_errors::Applicability;
......@@ -48,7 +48,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call:
4848 format!("using `{name}!()` with a format string that ends in a single newline"),
4949 |diag| {
5050 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 {
5252 return;
5353 };
5454
src/tools/clippy/clippy_lints_internal/src/lib.rs+19-11
......@@ -63,15 +63,23 @@ static LINTS: &[&Lint] = &[
6363pub fn register_lints(store: &mut LintStore) {
6464 store.register_lints(LINTS);
6565
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 }));
7785}
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>(
541541 cx: &LateContext<'tcx>,
542542 cond: &'tcx Expr<'_>,
543543) -> 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| {
545545 if let Some(res) = extract_is_diag_item(cx, cond_part) {
546546 ControlFlow::Break((cond_part.span, res))
547547 } else {
......@@ -554,7 +554,7 @@ fn extract_nested_is_diagnostic_item<'tcx>(
554554 cx: &LateContext<'tcx>,
555555 cond: &'tcx Expr<'_>,
556556) -> 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| {
558558 if let Some(res) = extract_is_diagnostic_item(cx, cond_part) {
559559 ControlFlow::Break((cond_part.span, res))
560560 } 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:
88
99<!-- begin autogenerated nightly -->
1010```
11nightly-2026-06-11
11nightly-2026-06-25
1212```
1313<!-- end autogenerated nightly -->
1414
src/tools/clippy/clippy_utils/src/attrs.rs+7-4
......@@ -1,6 +1,6 @@
11//! Utility functions for attributes, including Clippy's built-in ones
22
3use crate::source::SpanRangeExt;
3use crate::source::SpanExt;
44use crate::{sym, tokenize_with_text};
55use rustc_ast::attr::AttributeExt;
66use rustc_errors::Applicability;
......@@ -37,8 +37,6 @@ pub fn check_clippy_attr<A: AttributeExt>(sess: &Session, attr: &A) {
3737 | sym::version
3838 | sym::cognitive_complexity
3939 | sym::dump
40 | sym::disallowed_profile
41 | sym::disallowed_profiles
4240 | sym::msrv
4341 | sym::has_significant_drop
4442 | sym::format_args => {},
......@@ -107,7 +105,12 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
107105
108106/// Checks whether the given span contains a `#[cfg(..)]` attribute
109107pub 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
111114 let mut iter = tokenize_with_text(src);
112115
113116 // Search for the token sequence [`#`, `[`, `cfg`]
src/tools/clippy/clippy_utils/src/consts.rs+20-10
......@@ -5,7 +5,7 @@
55#![expect(clippy::float_cmp)]
66
77use crate::res::MaybeDef;
8use crate::source::{SpanRangeExt, walk_span_to_context};
8use crate::source::{SpanExt, walk_span_to_context};
99use crate::{clip, is_direct_expn_of, sext, sym, unsext};
1010
1111use rustc_abi::Size;
......@@ -522,9 +522,9 @@ pub fn eval_int(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<FullInt> {
522522///
523523/// See the module level documentation for some context.
524524pub 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>,
528528 source: Cell<ConstantSource>,
529529 ctxt: Cell<SyntaxContext>,
530530}
......@@ -885,12 +885,22 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
885885 _ => return None,
886886 };
887887
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
888902 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())
894904 .ok()
895905 }
896906
......@@ -934,7 +944,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
934944 if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt)
935945 && let expr_lo = expr_span.lo()
936946 && 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)
938948 && let Some(src) = src.as_str()
939949 {
940950 use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace};
src/tools/clippy/clippy_utils/src/disallowed_profiles.rs deleted-180
......@@ -1,180 +0,0 @@
1use crate::sym;
2use rustc_ast::ast::{LitKind, MetaItemInner};
3use rustc_data_structures::fx::FxHashMap;
4use rustc_data_structures::smallvec::SmallVec;
5use rustc_hir::{Attribute, HirId};
6use rustc_lint::LateContext;
7use 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)]
16pub 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)]
28pub struct ProfileSelection {
29 entries: SmallVec<[ProfileEntry; 2]>,
30}
31
32impl 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)]
47pub struct ProfileResolver {
48 cache: FxHashMap<HirId, Option<ProfileSelection>>,
49}
50
51impl 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
95fn 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
160fn 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
170fn 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 @@
1111
1212use crate::consts::{ConstEvalCtxt, FullInt};
1313use crate::sym;
14use crate::ty::{all_predicates_of, is_copy};
14use crate::ty::all_predicates_of;
1515use crate::visitors::is_const_evaluatable;
1616use rustc_hir::def::{DefKind, Res};
1717use rustc_hir::def_id::DefId;
1818use rustc_hir::intravisit::{Visitor, walk_expr};
1919use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp};
2020use rustc_lint::LateContext;
21use rustc_middle::ty;
2221use rustc_middle::ty::adjustment::{Adjust, DerefAdjustKind};
22use rustc_middle::ty::{self, TyCtxt};
2323use rustc_span::Symbol;
2424use std::{cmp, ops};
2525
......@@ -48,17 +48,17 @@ impl ops::BitOrAssign for EagernessSuggestion {
4848}
4949
5050/// Determine the eagerness of the given function call.
51fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
51fn fn_eagerness(tcx: TyCtxt<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
5252 use EagernessSuggestion::{Eager, Lazy, NoChange};
5353
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(),
5656 None => return Lazy,
5757 };
5858
5959 if (matches!(name, sym::is_empty | sym::len) || name.as_str().starts_with("as_")) && have_one_arg {
6060 if matches!(
61 cx.tcx.crate_name(fn_id.krate),
61 tcx.crate_name(fn_id.krate),
6262 sym::std | sym::core | sym::alloc | sym::proc_macro
6363 ) {
6464 Eager
......@@ -71,22 +71,20 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
7171 // Due to the limited operations on these types functions should be fairly cheap.
7272 if def.variants().iter().flat_map(|v| v.fields.iter()).any(|x| {
7373 matches!(
74 cx.tcx
75 .type_of(x.did)
74 tcx.type_of(x.did)
7675 .instantiate_identity()
7776 .skip_norm_wip()
7877 .peel_refs()
7978 .kind(),
8079 ty::Param(_)
8180 )
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,
8483 _ => true,
8584 }) && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
8685 {
8786 // Limit the function to either `(self) -> bool` or `(&self) -> bool`
88 match &**cx
89 .tcx
87 match &**tcx
9088 .fn_sig(fn_id)
9189 .instantiate_identity()
9290 .skip_norm_wip()
......@@ -104,14 +102,12 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
104102 }
105103}
106104
107fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
105fn res_has_significant_drop(res: Res, ecx: &ConstEvalCtxt<'_>, e: &Expr<'_>) -> bool {
108106 if let Res::Def(DefKind::Ctor(..) | DefKind::Variant | DefKind::Enum | DefKind::Struct, _)
109107 | Res::SelfCtor(_)
110108 | Res::SelfTyAlias { .. } = res
111109 {
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)
115111 } else {
116112 false
117113 }
......@@ -119,12 +115,12 @@ fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> boo
119115
120116#[expect(clippy::too_many_lines)]
121117fn 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>,
124120 eagerness: EagernessSuggestion,
125121 }
126122
127 impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
123 impl<'tcx> Visitor<'tcx> for V<'tcx> {
128124 fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
129125 use EagernessSuggestion::{ForceNoChange, Lazy, NoChange};
130126 if self.eagerness == ForceNoChange {
......@@ -134,8 +130,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
134130 // Autoderef through a user-defined `Deref` impl can have side-effects,
135131 // so don't suggest changing it.
136132 if self
137 .cx
138 .typeck_results()
133 .ecx
134 .typeck
139135 .expr_adjustments(e)
140136 .iter()
141137 .any(|adj| matches!(adj.kind, Adjust::Deref(DerefAdjustKind::Overloaded(_))))
......@@ -152,58 +148,62 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
152148 ..
153149 },
154150 args,
155 ) => match self.cx.qpath_res(path, hir_id) {
151 ) => match self.ecx.typeck.qpath_res(path, hir_id) {
156152 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) {
158154 self.eagerness = ForceNoChange;
159155 return;
160156 }
161157 },
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) => (),
163159 // 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) => {
165161 self.eagerness |= NoChange;
166162 return;
167163 },
168164 Res::Def(_, id) => match path {
169165 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 );
172172 },
173173 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());
175175 },
176176 },
177177 _ => self.eagerness = Lazy,
178178 },
179179 // 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) => {
181181 self.eagerness |= NoChange;
182182 return;
183183 },
184184 #[expect(clippy::match_same_arms)] // arm pattern can't be merged due to `ref`, see rust#105778
185185 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) {
187187 self.eagerness = ForceNoChange;
188188 return;
189189 }
190190 },
191191 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) {
193193 self.eagerness = ForceNoChange;
194194 return;
195195 }
196196 },
197197 ExprKind::MethodCall(name, ..) => {
198198 self.eagerness |= self
199 .cx
200 .typeck_results()
199 .ecx
200 .typeck
201201 .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));
203203 },
204204 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() {
207207 self.eagerness |= NoChange;
208208 } else {
209209 self.eagerness = Lazy;
......@@ -211,24 +211,19 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
211211 },
212212
213213 // `-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() => {
215215 self.eagerness |= NoChange;
216216 },
217217
218218 // 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() => {
222220 self.eagerness |= NoChange;
223221 },
224222 // 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() => (),
226224 ExprKind::Unary(UnOp::Deref, _) => self.eagerness |= NoChange,
227225 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(_),) => {},
232227
233228 // `>>` and `<<` panic when the right-hand side is greater than or equal to the number of bits in the
234229 // type of the left-hand side, or is negative.
......@@ -236,18 +231,16 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
236231 // overflow with constants, the compiler emits an error for it and the programmer will have to fix it.
237232 // Thus, we would realistically only delay the lint.
238233 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() =>
241235 {
242236 self.eagerness |= NoChange;
243237 },
244238
245239 ExprKind::Binary(op, left, right)
246240 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))
251244 && matches!(
252245 (left, right),
253246 // `1 / x`: x might be zero
......@@ -265,16 +258,14 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
265258 // error and it's good to have the eagerness warning up front when the user fixes the logic error.
266259 ExprKind::Binary(op, left, right)
267260 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()) =>
271263 {
272264 self.eagerness |= NoChange;
273265 },
274266
275267 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() => {},
278269
279270 // Can't be moved into a closure
280271 ExprKind::Break(..)
......@@ -322,7 +313,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
322313 }
323314
324315 let mut v = V {
325 cx,
316 ecx: ConstEvalCtxt::new(cx),
326317 eagerness: EagernessSuggestion::Eager,
327318 };
328319 v.visit_expr(e);
src/tools/clippy/clippy_utils/src/hir_utils.rs+2-2
......@@ -1,6 +1,6 @@
11use crate::consts::ConstEvalCtxt;
22use crate::macros::macro_backtrace;
3use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context};
3use crate::source::{SpanExt, SpanRange, walk_span_to_context};
44use crate::{sym, tokenize_with_text};
55use core::mem;
66use rustc_ast::ast;
......@@ -1036,7 +1036,7 @@ fn reduce_exprkind<'hir>(
10361036 // `{}` => `()`
10371037 ([], None)
10381038 if block.span.ctxt() != eval_ctxt
1039 || block.span.check_source_text(cx, |src| {
1039 || block.span.check_text(cx, |src| {
10401040 tokenize(src, FrontmatterAllowed::No)
10411041 .map(|t| t.kind)
10421042 .filter(|t| {
src/tools/clippy/clippy_utils/src/lib.rs+22-58
......@@ -46,7 +46,6 @@ mod check_proc_macro;
4646pub mod comparisons;
4747pub mod consts;
4848pub mod diagnostics;
49pub mod disallowed_profiles;
5049pub mod eager_or_lazy;
5150pub mod higher;
5251mod hir_utils;
......@@ -116,14 +115,14 @@ use rustc_span::hygiene::{ExpnKind, MacroKind};
116115use rustc_span::source_map::SourceMap;
117116use rustc_span::symbol::{Ident, Symbol, kw};
118117use rustc_span::{InnerSpan, Span, SyntaxContext};
119use source::{SpanRangeExt, walk_span_to_context};
118use source::{SpanExt, walk_span_to_context};
120119use visitors::{Visitable, for_each_unconsumed_temporary};
121120
122121use crate::ast_utils::unordered_over;
123use crate::consts::ConstEvalCtxt;
124122use crate::higher::Range;
125123use crate::msrvs::Msrv;
126124use crate::res::{MaybeDef, MaybeQPath, MaybeResPath};
125use crate::source::HasSourceMap;
127126use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
128127use crate::visitors::for_each_expr_without_closures;
129128
......@@ -1329,59 +1328,23 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
13291328 })
13301329}
13311330
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`.
1346pub 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.
1332pub fn is_full_collection_range(cx: &LateContext<'_>, container: Option<HirId>, expr: &Expr<'_>) -> bool {
13481333 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
13751339 {
1376 container_path.res == path.res
1340 seg.ident.name == sym::len && recv.res_local_id() == Some(container)
13771341 } else {
13781342 false
13791343 }
1380 },
1381 });
1382 return start_is_none_or_min && end_is_none_or_max;
1344 })
1345 } else {
1346 false
13831347 }
1384 false
13851348}
13861349
13871350/// 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
28802843
28812844/// Checks whether a given span has any comment token
28822845/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
2883pub fn span_contains_comment(cx: &impl source::HasSession, span: Span) -> bool {
2884 span.check_source_text(cx, |snippet| {
2846pub fn span_contains_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool {
2847 span.check_text(sm, |snippet| {
28852848 tokenize(snippet, FrontmatterAllowed::No).any(|token| {
28862849 matches!(
28872850 token.kind,
......@@ -2895,8 +2858,8 @@ pub fn span_contains_comment(cx: &impl source::HasSession, span: Span) -> bool {
28952858/// token, including comments unless `skip_comments` is set.
28962859/// This is useful to determine if there are any actual code tokens in the span that are omitted in
28972860/// the late pass, such as platform-specific code.
2898pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool {
2899 span.check_source_text(cx, |snippet| {
2861pub fn span_contains_non_whitespace<'sm>(sm: impl HasSourceMap<'sm>, span: Span, skip_comments: bool) -> bool {
2862 span.check_text(sm, |snippet| {
29002863 tokenize_with_text(snippet).any(|(token, _, _)| match token {
29012864 TokenKind::Whitespace => false,
29022865 TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments,
......@@ -2904,18 +2867,19 @@ pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, sk
29042867 })
29052868 })
29062869}
2870
29072871/// Returns all the comments a given span contains
29082872///
29092873/// Comments are returned wrapped with their relevant delimiters
2910pub fn span_extract_comment(cx: &impl source::HasSession, span: Span) -> String {
2911 span_extract_comments(cx, span).join("\n")
2874pub fn span_extract_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> String {
2875 span_extract_comments(sm, span).join("\n")
29122876}
29132877
29142878/// Returns all the comments a given span contains.
29152879///
29162880/// Comments are returned wrapped with their relevant delimiters.
2917pub fn span_extract_comments(cx: &impl source::HasSession, span: Span) -> Vec<String> {
2918 span.with_source_text(cx, |snippet| {
2881pub fn span_extract_comments<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Vec<String> {
2882 span.with_source_text(sm, |snippet| {
29192883 tokenize_with_text(snippet)
29202884 .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
29212885 .map(|(_, s, _)| s.to_string())
src/tools/clippy/clippy_utils/src/msrvs.rs+32-10
......@@ -3,8 +3,9 @@ use rustc_ast::Attribute;
33use rustc_ast::attr::AttributeExt;
44use rustc_attr_parsing::parse_version;
55use rustc_data_structures::smallvec::SmallVec;
6use rustc_hir::RustcVersion;
6use rustc_hir::{HirId, RustcVersion};
77use rustc_lint::LateContext;
8use rustc_middle::ty::TyCtxt;
89use rustc_session::Session;
910use rustc_span::Symbol;
1011use serde::Deserialize;
......@@ -26,7 +27,7 @@ msrv_aliases! {
2627 1,97,0 { ISOLATE_LOWEST_ONE }
2728 1,93,0 { VEC_DEQUE_POP_BACK_IF, VEC_DEQUE_POP_FRONT_IF }
2829 1,91,0 { DURATION_FROM_MINUTES_HOURS }
29 1,88,0 { LET_CHAINS }
30 1,88,0 { LET_CHAINS, AS_CHUNKS }
3031 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST }
3132 1,86,0 { VEC_POP_IF }
3233 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL, WAKER_NOOP }
......@@ -118,16 +119,29 @@ impl Msrv {
118119 /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations
119120 pub fn current(self, cx: &LateContext<'_>) -> Option<RustcVersion> {
120121 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
128125 }
126 }
129127
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)
131145 }
132146
133147 /// Checks if a required version from [this module](self) is met at the current node
......@@ -138,6 +152,14 @@ impl Msrv {
138152 self.current(cx).is_none_or(|msrv| msrv >= required)
139153 }
140154
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
141163 pub fn read_cargo(&mut self, sess: &Session) {
142164 let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
143165 .ok()
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs+12-10
......@@ -6,9 +6,8 @@
66use crate::msrvs::{self, Msrv};
77use hir::LangItem;
88use rustc_const_eval::check_consts::ConstCx;
9use rustc_hir as hir;
109use rustc_hir::def_id::DefId;
11use rustc_hir::{RustcVersion, StableSince};
10use rustc_hir::{self as hir, HirId, RustcVersion, StableSince};
1211use rustc_infer::infer::TyCtxtInferExt;
1312use rustc_infer::traits::Obligation;
1413use rustc_lint::LateContext;
......@@ -420,14 +419,17 @@ fn check_terminator<'tcx>(
420419
421420/// Checks if the given `def_id` is a stable const fn, in respect to the given MSRV.
422421pub 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.
426pub 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
426429 .lookup_const_stability(def_id)
427430 .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))
431433 })
432434 .is_none_or(|const_stab| {
433435 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
441443 StableSince::Err(_) => return false,
442444 };
443445
444 msrv.meets(cx, const_stab_rust_version)
446 msrv.meets_at(tcx, node, const_stab_rust_version)
445447 } else {
446448 // 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()
448450 }
449451 })
450452}
src/tools/clippy/clippy_utils/src/source.rs+98-85
......@@ -20,27 +20,38 @@ use std::borrow::Cow;
2020use std::fmt;
2121use std::ops::{Deref, Index, Range};
2222
23pub trait HasSession {
24 fn sess(&self) -> &Session;
23pub trait HasSourceMap<'sm>: Copy {
24 #[must_use]
25 fn source_map(self) -> &'sm SourceMap;
2526}
26impl HasSession for Session {
27 fn sess(&self) -> &Session {
27impl<'sm> HasSourceMap<'sm> for &'sm SourceMap {
28 #[inline]
29 fn source_map(self) -> &'sm SourceMap {
2830 self
2931 }
3032}
31impl HasSession for TyCtxt<'_> {
32 fn sess(&self) -> &Session {
33 self.sess
33impl<'sm> HasSourceMap<'sm> for &'sm Session {
34 #[inline]
35 fn source_map(self) -> &'sm SourceMap {
36 self.source_map()
3437 }
3538}
36impl HasSession for EarlyContext<'_> {
37 fn sess(&self) -> &Session {
38 ::rustc_lint::LintContext::sess(self)
39impl<'sm> HasSourceMap<'sm> for TyCtxt<'sm> {
40 #[inline]
41 fn source_map(self) -> &'sm SourceMap {
42 self.sess.source_map()
3943 }
4044}
41impl HasSession for LateContext<'_> {
42 fn sess(&self) -> &Session {
43 self.tcx.sess()
45impl<'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}
51impl<'sm> HasSourceMap<'sm> for &LateContext<'sm> {
52 #[inline]
53 fn source_map(self) -> &'sm SourceMap {
54 self.tcx.sess.source_map()
4455 }
4556}
4657
......@@ -95,39 +106,39 @@ impl IntoSpan for Range<BytePos> {
95106 }
96107}
97108
98pub trait SpanRangeExt: SpanRange {
109pub trait SpanExt: SpanRange {
99110 /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed,
100111 /// 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)
103114 }
104115
105116 /// Gets the source file, and range in the file, of the given span. Returns `None` if the span
106117 /// 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())
109120 }
110121
111122 /// Calls the given function with the source text referenced and returns the value. Returns
112123 /// `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)
115126 }
116127
117128 /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the
118129 /// 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)
121132 }
122133
123134 /// Calls the given function with the both the text of the source file and the referenced range,
124135 /// 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>(
126137 self,
127 cx: &impl HasSession,
138 sm: impl HasSourceMap<'sm>,
128139 f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T,
129140 ) -> 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)
131142 }
132143
133144 /// 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 {
135146 /// retrieved, or no result is returned.
136147 ///
137148 /// The new range must reside within the same source file.
138 fn map_range(
149 fn map_range<'sm>(
139150 self,
140 cx: &impl HasSession,
151 sm: impl HasSourceMap<'sm>,
141152 f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range<usize>) -> Option<Range<usize>>,
142153 ) -> Option<Range<BytePos>> {
143 map_range(cx.sess().source_map(), self.into_range(), f)
154 map_range(sm.source_map(), self.into_range(), f)
144155 }
145156
146157 /// Extends the range to include all preceding whitespace characters.
......@@ -156,16 +167,16 @@ pub trait SpanRangeExt: SpanRange {
156167 ///
157168 /// When the range points to `foo`, suggesting to remove the range after it's been extended will
158169 /// 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())
161172 }
162173
163174 /// 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())
166177 }
167178}
168impl<T: SpanRange> SpanRangeExt for T {}
179impl<T: SpanRange> SpanExt for T {}
169180
170181/// Handle to a range of text in a source file.
171182pub struct SourceText(SourceFileRange);
......@@ -353,15 +364,15 @@ impl SourceFileRange {
353364}
354365
355366/// Like [`snippet_block`], but add braces if the expr is not an `ExprKind::Block` with no label.
356pub fn expr_block(
357 sess: &impl HasSession,
367pub fn expr_block<'sm>(
368 sm: impl HasSourceMap<'sm>,
358369 expr: &Expr<'_>,
359370 outer: SyntaxContext,
360371 default: &str,
361372 indent_relative_to: Option<Span>,
362373 app: &mut Applicability,
363374) -> 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);
365376 if !from_macro
366377 && let ExprKind::Block(block, None) = expr.kind
367378 && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
......@@ -386,13 +397,13 @@ pub fn expr_block(
386397/// let x = ();
387398/// // ^^^^^^^^^^
388399/// ```
389pub 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))
400pub 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))
391402}
392403
393fn 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| {
404fn 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| {
396407 snip.find(|c: char| !c.is_whitespace())
397408 .map(|pos| line_span.lo() + BytePos::from_usize(pos))
398409 })
......@@ -407,9 +418,9 @@ fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option<BytePo
407418/// let x = ();
408419/// // ^^^^^^^^^^^^^^
409420/// ```
410fn line_span(sess: &impl HasSession, span: Span) -> Span {
421fn line_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span {
411422 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();
413424 let line_start = sf.lines()[line];
414425 let line_start = sf.absolute_position(line_start);
415426 span.with_lo(line_start)
......@@ -423,13 +434,13 @@ fn line_span(sess: &impl HasSession, span: Span) -> Span {
423434/// let x = ();
424435/// // ^^ -- will return 4
425436/// ```
426pub 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()))
437pub 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()))
428439}
429440
430441/// Gets a snippet of the indentation of the line of a span
431pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> {
432 snippet_opt(sess, line_span(sess, span)).map(|mut s| {
442pub fn snippet_indent<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option<String> {
443 snippet_opt(sm, line_span(sm, span)).map(|mut s| {
433444 let len = s.len() - s.trim_start().len();
434445 s.truncate(len);
435446 s
......@@ -441,8 +452,8 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> {
441452// sources that the user has no control over.
442453// For some reason these attributes don't have any expansion info on them, so
443454// we have to check it this way until there is a better way.
444pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool {
445 if let Some(snippet) = snippet_opt(sess, span)
455pub fn is_present_in_source<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool {
456 if let Some(snippet) = snippet_opt(sm, span)
446457 && snippet.is_empty()
447458 {
448459 return false;
......@@ -534,8 +545,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>,
534545/// snippet(cx, span1, "..") // -> "value"
535546/// snippet(cx, span2, "..") // -> "Vec::new()"
536547/// ```
537pub 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)
548pub 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)
539550}
540551
541552/// 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<
547558///
548559/// If the span might realistically contain a macro call (e.g. `vec![]`), consider using
549560/// [`snippet_with_context`] instead.
550pub fn snippet_with_applicability<'a>(
551 sess: &impl HasSession,
561pub fn snippet_with_applicability<'a, 'sm>(
562 sm: impl HasSourceMap<'sm>,
552563 span: Span,
553564 default: &'a str,
554565 applicability: &mut Applicability,
555566) -> Cow<'a, str> {
556 snippet_with_applicability_sess(sess.sess(), span, default, applicability)
567 snippet_with_applicability_sm(sm.source_map(), span, default, applicability)
557568}
558569
559fn snippet_with_applicability_sess<'a>(
560 sess: &Session,
570fn snippet_with_applicability_sm<'a>(
571 sm: &SourceMap,
561572 span: Span,
562573 default: &'a str,
563574 applicability: &mut Applicability,
......@@ -565,7 +576,7 @@ fn snippet_with_applicability_sess<'a>(
565576 if *applicability != Applicability::Unspecified && span.from_expansion() {
566577 *applicability = Applicability::MaybeIncorrect;
567578 }
568 if let Some(t) = snippet_opt(sess, span) {
579 if let Some(t) = snippet_opt(sm, span) {
569580 Cow::Owned(t)
570581 } else {
571582 if *applicability == Applicability::MachineApplicable {
......@@ -576,8 +587,8 @@ fn snippet_with_applicability_sess<'a>(
576587}
577588
578589/// Converts a span to a code snippet. Returns `None` if not available.
579pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option<String> {
580 sess.sess().source_map().span_to_snippet(span).ok()
590pub fn snippet_opt<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option<String> {
591 sm.source_map().span_to_snippet(span).ok()
581592}
582593
583594/// 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> {
614625/// } // aligned with `if`
615626/// ```
616627/// Note that the first line of the snippet always has 0 indentation.
617pub 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));
628pub 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));
620636 reindent_multiline(&snip, true, indent)
621637}
622638
623639/// Same as [`snippet_block`], but adapts the applicability level by the rules of
624640/// [`snippet_with_applicability`].
625pub fn snippet_block_with_applicability(
626 sess: &impl HasSession,
641pub fn snippet_block_with_applicability<'sm>(
642 sm: impl HasSourceMap<'sm>,
627643 span: Span,
628644 default: &str,
629645 indent_relative_to: Option<Span>,
630646 applicability: &mut Applicability,
631647) -> 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));
634650 reindent_multiline(&snip, true, indent)
635651}
636652
637653/// Combination of [`snippet_block`] and [`snippet_with_context`].
638pub fn snippet_block_with_context(
639 sess: &impl HasSession,
654pub fn snippet_block_with_context<'sm>(
655 sm: impl HasSourceMap<'sm>,
640656 span: Span,
641657 outer: SyntaxContext,
642658 default: &str,
643659 indent_relative_to: Option<Span>,
644660 app: &mut Applicability,
645661) -> (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));
648664 (reindent_multiline(&snip, true, indent), from_macro)
649665}
650666
......@@ -658,18 +674,18 @@ pub fn snippet_block_with_context(
658674/// correctly get a snippet of `vec![]`.
659675///
660676/// This will also return whether or not the snippet is a macro call.
661pub fn snippet_with_context<'a>(
662 sess: &impl HasSession,
677pub fn snippet_with_context<'a, 'sm>(
678 sm: impl HasSourceMap<'sm>,
663679 span: Span,
664680 outer: SyntaxContext,
665681 default: &'a str,
666682 applicability: &mut Applicability,
667683) -> (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)
669685}
670686
671fn snippet_with_context_sess<'a>(
672 sess: &Session,
687fn snippet_with_context_sm<'a>(
688 sm: &SourceMap,
673689 span: Span,
674690 outer: SyntaxContext,
675691 default: &'a str,
......@@ -677,10 +693,7 @@ fn snippet_with_context_sess<'a>(
677693) -> (Cow<'a, str>, bool) {
678694 // If it is just range desugaring, use the desugaring span since it may include parenthesis.
679695 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);
684697 }
685698
686699 let (span, is_macro_call) = walk_span_to_context(span, outer).map_or_else(
......@@ -696,7 +709,7 @@ fn snippet_with_context_sess<'a>(
696709 );
697710
698711 (
699 snippet_with_applicability_sess(sess, span, default, applicability),
712 snippet_with_applicability_sm(sm, span, default, applicability),
700713 is_macro_call,
701714 )
702715}
......@@ -759,15 +772,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
759772/// writeln!(o, "") -> writeln!(o, "")
760773/// ^^ ^^^^
761774/// ```
762pub 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);
775pub 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);
764777 extended.with_lo(extended.lo() - BytePos(1))
765778}
766779
767780/// Converts `expr` to a `char` literal if it's a `str` literal containing a single
768781/// character (or a single byte with `ascii_only`)
769pub fn str_literal_to_char_literal(
770 sess: &impl HasSession,
782pub fn str_literal_to_char_literal<'sm>(
783 sm: impl HasSourceMap<'sm>,
771784 expr: &Expr<'_>,
772785 applicability: &mut Applicability,
773786 ascii_only: bool,
......@@ -782,7 +795,7 @@ pub fn str_literal_to_char_literal(
782795 }
783796 && len == 1
784797 {
785 let snip = snippet_with_applicability(sess, expr.span, string, applicability);
798 let snip = snippet_with_applicability(sm, expr.span, string, applicability);
786799 let ch = if let StrStyle::Raw(nhash) = style {
787800 let nhash = nhash as usize;
788801 // for raw string: r##"a"##
src/tools/clippy/clippy_utils/src/sym.rs+2-2
......@@ -176,6 +176,8 @@ generate! {
176176 checked_sub,
177177 child_id,
178178 child_kill,
179 chunks_exact,
180 chunks_exact_mut,
179181 clamp,
180182 clippy_utils,
181183 clone_into,
......@@ -209,8 +211,6 @@ generate! {
209211 deprecated_in_future,
210212 deref_mut_method,
211213 diagnostics,
212 disallowed_profile,
213 disallowed_profiles,
214214 disallowed_types,
215215 drain,
216216 dump,
src/tools/clippy/clippy_utils/src/ty/mod.rs+110-21
......@@ -3,7 +3,7 @@
33#![allow(clippy::module_name_repetitions)]
44
55use core::ops::ControlFlow;
6use rustc_abi::VariantIdx;
6use rustc_abi::{BackendRepr, FieldsShape, VariantIdx, Variants};
77use rustc_ast::ast::Mutability;
88use rustc_data_structures::fx::{FxHashMap, FxHashSet};
99use rustc_hir as hir;
......@@ -17,7 +17,7 @@ use rustc_middle::mir::ConstValue;
1717use rustc_middle::mir::interpret::Scalar;
1818use rustc_middle::traits::EvaluationResult;
1919use rustc_middle::ty::adjustment::{Adjust, Adjustment, DerefAdjustKind};
20use rustc_middle::ty::layout::ValidityRequirement;
20use rustc_middle::ty::layout::{LayoutError, LayoutOf, TyAndLayout};
2121use rustc_middle::ty::{
2222 self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, BoundVarIndexKind, FnSig, GenericArg,
2323 GenericArgKind, GenericArgsRef, IntTy, ProjectionAliasTy, Region, RegionKind, TraitRef, Ty, TyCtxt,
......@@ -34,7 +34,7 @@ use std::{debug_assert_matches, iter, mem};
3434
3535use crate::paths::{PathNS, lookup_path_str};
3636use crate::res::{MaybeDef, MaybeQPath};
37use crate::sym;
37use crate::{over, sym};
3838
3939mod type_certainty;
4040pub 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>)
486486/// and `false` for:
487487/// - `Result<u32, String>` and `Result<usize, String>`
488488pub 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)) => {
491491 if did_a != did_b {
492492 return false;
493493 }
......@@ -500,35 +500,112 @@ pub fn same_type_modulo_regions<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
500500 _ => true,
501501 })
502502 },
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),
503506 _ => a == b,
504507 }
505508}
506509
507510/// Checks if a given type looks safe to be uninitialized.
508511pub 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
520fn 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 }
513561}
514562
515/// A fallback for polymorphic types, which are not supported by `check_validity_requirement`.
563/// Fallback for polymorphic types where `layout_of` fails
516564fn 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
517567 match *ty.kind() {
518568 // 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 },
520576 // Peek through tuples and try their fallbacks.
521577 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 }),
525590 // Types (e.g. `UnsafeCell<MaybeUninit<T>>`) that recursively contain only types that can be uninit
526591 // 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
532609 _ => false,
533610 }
534611}
......@@ -1049,9 +1126,13 @@ pub fn make_projection<'tcx>(
10491126 assert_generic_args_match(tcx, assoc_item.def_id, args);
10501127
10511128 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 }
10531132 } else {
1054 ty::AliasTyKind::Projection { def_id: assoc_item.def_id }
1133 ty::AliasTyKind::Projection {
1134 def_id: assoc_item.def_id,
1135 }
10551136 };
10561137
10571138 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
13351416 }
13361417}
13371418
1419/// Check if `ty` is an `Option<T>` or a `Result<T, E>` and return its argument type (`T`) if it is.
1420pub 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
13381427/// Check if a Ty<'_> of `Iterator` contains any mutable access to non-owning types by checking if
13391428/// it contains fields of mutable references or pointers, or references/pointers to non-`Freeze`
13401429/// 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 {
195195}
196196
197197pub 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| {
199199 if e.res_local_id() == Some(local_id) {
200200 ControlFlow::Break(())
201201 } else {
......@@ -220,7 +220,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
220220 let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id);
221221
222222 let mut past_expr = false;
223 for_each_expr(cx, block, |e| {
223 for_each_expr(cx.tcx, block, |e| {
224224 if past_expr {
225225 if e.res_local_id() == Some(local_id) {
226226 ControlFlow::Break(())
src/tools/clippy/clippy_utils/src/visitors.rs+68-88
......@@ -1,6 +1,6 @@
11use crate::get_enclosing_block;
22use crate::msrvs::Msrv;
3use crate::qualify_min_const_fn::is_stable_const_fn;
3use crate::qualify_min_const_fn::is_stable_const_fn_at;
44use crate::res::MaybeResPath;
55use crate::ty::needs_ordered_drop;
66use core::ops::ControlFlow;
......@@ -8,8 +8,8 @@ use rustc_ast::visit::{VisitorResult, try_visit};
88use rustc_hir::def::{CtorKind, DefKind, Res};
99use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr};
1010use 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,
1313};
1414use rustc_lint::LateContext;
1515use rustc_middle::hir::nested_filter;
......@@ -145,7 +145,7 @@ pub fn for_each_expr_without_closures<'tcx, B, C: Continue>(
145145/// Calls the given function once for each expression contained. This will enter bodies, but not
146146/// nested items.
147147pub fn for_each_expr<'tcx, B, C: Continue>(
148 cx: &LateContext<'tcx>,
148 tcx: TyCtxt<'tcx>,
149149 node: impl Visitable<'tcx>,
150150 f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
151151) -> Option<B> {
......@@ -188,7 +188,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
188188 ControlFlow::Continue(())
189189 }
190190 }
191 let mut v = V { tcx: cx.tcx, f };
191 let mut v = V { tcx, f };
192192 node.visit(&mut v).break_value()
193193}
194194
......@@ -299,7 +299,7 @@ where
299299
300300/// Checks if the given resolved path is used in the given body.
301301pub 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| {
303303 if let ExprKind::Path(p) = &e.kind
304304 && cx.qpath_res(p, e.hir_id) == res
305305 {
......@@ -312,7 +312,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
312312
313313/// Checks if the given local is used.
314314pub 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| {
316316 if e.res_local_id() == Some(id) {
317317 ControlFlow::Break(())
318318 } else {
......@@ -322,89 +322,69 @@ pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tc
322322 .is_some()
323323}
324324
325/// Checks if the given expression is a constant.
326pub 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
326pub 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 ..
399335 },
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(..) => {},
401382
402 walk_expr(self, e)
383 _ => return ControlFlow::Break(()),
403384 }
404 }
405
406 let mut v = V { cx };
407 v.visit_expr(e).is_continue()
385 ControlFlow::Continue(Descend::Yes)
386 })
387 .is_none()
408388}
409389
410390/// Checks if the given expression performs an unsafe operation outside of an unsafe block.
......@@ -785,7 +765,7 @@ pub fn local_used_once<'tcx>(
785765) -> Option<&'tcx Expr<'tcx>> {
786766 let mut expr = None;
787767
788 let cf = for_each_expr(cx, visitable, |e| {
768 let cf = for_each_expr(cx.tcx, visitable, |e| {
789769 if e.res_local_id() == Some(id) && expr.replace(e).is_some() {
790770 ControlFlow::Break(())
791771 } else {
src/tools/clippy/rust-toolchain.toml+1-1
......@@ -1,6 +1,6 @@
11[toolchain]
22# begin autogenerated nightly
3channel = "nightly-2026-06-11"
3channel = "nightly-2026-06-25"
44# end autogenerated nightly
55components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
66profile = "minimal"
src/tools/clippy/tests/ui-toml/disallowed_profiles_methods/clippy.toml deleted-13
......@@ -1,13 +0,0 @@
1disallowed-methods = [
2 { path = "std::mem::drop" }
3]
4
5[profiles.forward_pass]
6disallowed-methods = [
7 { path = "alloc::vec::Vec::push", reason = "push is forbidden in forward profile" }
8]
9
10[profiles.export]
11disallowed-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
10fn 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)]
16fn expected_violation() {
17 let value = String::from("test");
18 std::mem::drop(value);
19}
20
21#[clippy::disallowed_profile("forward_pass")]
22fn 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")]
28fn 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
36fn 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")]
44fn 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`
56fn 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)]
64fn expect_after_unknown_profile() {
65 let value = String::from("test");
66 std::mem::drop(value);
67}
68
69fn 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 @@
1error: use of a disallowed method `std::mem::drop`
2 --> tests/ui-toml/disallowed_profiles_methods/main.rs:12:5
3 |
4LL | 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
10error: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass)
11 --> tests/ui-toml/disallowed_profiles_methods/main.rs:24:12
12 |
13LL | values.push(1);
14 | ^^^^
15 |
16 = note: push is forbidden in forward profile
17
18error: use of a disallowed method `core::option::Option::unwrap` (profile: export)
19 --> tests/ui-toml/disallowed_profiles_methods/main.rs:30:11
20 |
21LL | value.unwrap();
22 | ^^^^^^
23
24error: `clippy::disallowed_profile` references unknown profile `unknown_profile` for `clippy::disallowed_methods`
25 --> tests/ui-toml/disallowed_profiles_methods/main.rs:33:30
26 |
27LL | #[clippy::disallowed_profile("unknown_profile")]
28 | ^^^^^^^^^^^^^^^^^
29
30error: `clippy::disallowed_profile` references unknown profile `unknown_profile` for `clippy::disallowed_types`
31 --> tests/ui-toml/disallowed_profiles_methods/main.rs:33:30
32 |
33LL | #[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
39error: use of a disallowed method `std::mem::drop`
40 --> tests/ui-toml/disallowed_profiles_methods/main.rs:40:5
41 |
42LL | std::mem::drop(values);
43 | ^^^^^^^^^^^^^^
44
45error: use of a disallowed method `alloc::vec::Vec::push` (profile: forward_pass)
46 --> tests/ui-toml/disallowed_profiles_methods/main.rs:46:12
47 |
48LL | values.push(1);
49 | ^^^^
50 |
51 = note: push is forbidden in forward profile
52
53error: use of a disallowed method `core::option::Option::unwrap` (profile: export)
54 --> tests/ui-toml/disallowed_profiles_methods/main.rs:48:11
55 |
56LL | value.unwrap();
57 | ^^^^^^
58
59error: `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 |
62LL | #[clippy::disallowed_profile("unknown_profile_expect_before")]
63 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
64
65error: `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 |
68LL | #[clippy::disallowed_profile("unknown_profile_expect_after")]
69 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
70
71error: aborting due to 10 previous errors
72
src/tools/clippy/tests/ui-toml/disallowed_profiles_types/clippy.toml deleted-13
......@@ -1,13 +0,0 @@
1disallowed-types = [
2 { path = "std::rc::Rc" }
3]
4
5[profiles.forward_pass]
6disallowed-types = [
7 { path = "std::cell::RefCell", reason = "Prefer shared references" }
8]
9
10[profiles.export]
11disallowed-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
4use std::rc::Rc; //~ ERROR: use of a disallowed type `std::rc::Rc`
5use std::sync::Mutex;
6
7struct Wrapper;
8
9fn 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")]
14fn 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")]
19fn 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
26fn 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")]
32fn 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`
42fn 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)]
49fn expect_after_unknown_profile() {
50 let _value: Rc<i32> = todo!();
51}
52
53fn 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 @@
1error: use of a disallowed type `std::rc::Rc`
2 --> tests/ui-toml/disallowed_profiles_types/main.rs:4:1
3 |
4LL | 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
10error: use of a disallowed type `std::rc::Rc`
11 --> tests/ui-toml/disallowed_profiles_types/main.rs:10:17
12 |
13LL | let _value: Rc<i32> = todo!();
14 | ^^^^^^^
15
16error: use of a disallowed type `std::cell::RefCell` (profile: forward_pass)
17 --> tests/ui-toml/disallowed_profiles_types/main.rs:15:17
18 |
19LL | let _value: std::cell::RefCell<i32> = todo!();
20 | ^^^^^^^^^^^^^^^^^^^^^^^
21 |
22 = note: Prefer shared references
23
24error: use of a disallowed type `std::sync::Mutex` (profile: export)
25 --> tests/ui-toml/disallowed_profiles_types/main.rs:20:17
26 |
27LL | let _value: Mutex<i32> = todo!();
28 | ^^^^^^^^^^
29
30error: `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 |
33LL | #[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
39error: `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 |
42LL | #[clippy::disallowed_profile("unknown_type_profile")]
43 | ^^^^^^^^^^^^^^^^^^^^^^
44
45error: use of a disallowed type `std::rc::Rc`
46 --> tests/ui-toml/disallowed_profiles_types/main.rs:28:20
47 |
48LL | let _fallback: Rc<i32> = todo!();
49 | ^^^^^^^
50
51error: use of a disallowed type `std::cell::RefCell` (profile: forward_pass)
52 --> tests/ui-toml/disallowed_profiles_types/main.rs:33:17
53 |
54LL | let _value: std::cell::RefCell<i32> = todo!();
55 | ^^^^^^^^^^^^^^^^^^^^^^^
56 |
57 = note: Prefer shared references
58
59error: use of a disallowed type `std::sync::Mutex` (profile: export)
60 --> tests/ui-toml/disallowed_profiles_types/main.rs:34:17
61 |
62LL | let _other: Mutex<i32> = todo!();
63 | ^^^^^^^^^^
64
65error: `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 |
68LL | #[clippy::disallowed_profile("unknown_type_profile_expect_before")]
69 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
70
71error: `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 |
74LL | #[clippy::disallowed_profile("unknown_type_profile_expect_after")]
75 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76
77error: aborting due to 11 previous errors
78
src/tools/clippy/tests/ui-toml/needless_late_init/clippy.toml created+1
......@@ -0,0 +1 @@
1check-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
3fn main() {}
4
5fn 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
3333 avoid-breaking-exported-api
3434 await-holding-invalid-types
3535 cargo-ignore-publish
36 check-grouped-late-init
3637 check-incompatible-msrv-in-tests
3738 check-inconsistent-struct-field-initializers
3839 check-private-items
......@@ -70,7 +71,6 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
7071 module-items-ordered-within-groupings
7172 msrv
7273 pass-by-value-size-limit
73 profiles
7474 pub-underscore-fields-behavior
7575 recursive-self-in-type-definitions
7676 semicolon-inside-block-ignore-singleline
......@@ -135,6 +135,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
135135 avoid-breaking-exported-api
136136 await-holding-invalid-types
137137 cargo-ignore-publish
138 check-grouped-late-init
138139 check-incompatible-msrv-in-tests
139140 check-inconsistent-struct-field-initializers
140141 check-private-items
......@@ -172,7 +173,6 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
172173 module-items-ordered-within-groupings
173174 msrv
174175 pass-by-value-size-limit
175 profiles
176176 pub-underscore-fields-behavior
177177 recursive-self-in-type-definitions
178178 semicolon-inside-block-ignore-singleline
......@@ -237,6 +237,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
237237 avoid-breaking-exported-api
238238 await-holding-invalid-types
239239 cargo-ignore-publish
240 check-grouped-late-init
240241 check-incompatible-msrv-in-tests
241242 check-inconsistent-struct-field-initializers
242243 check-private-items
......@@ -274,7 +275,6 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
274275 module-items-ordered-within-groupings
275276 msrv
276277 pass-by-value-size-limit
277 profiles
278278 pub-underscore-fields-behavior
279279 recursive-self-in-type-definitions
280280 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]
5fn main() {
6 let x = 42i32;
7 _ = -x;
8}
src/tools/clippy/tests/ui/author/issue_17240.stdout created+20
......@@ -0,0 +1,20 @@
1if 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
3pub fn lol() -> Option<u32> {
4 Some(0)
5}
6
7pub unsafe fn lol_unchecked() -> u32 {
8 0
9}
10
11pub fn kek() -> Option<u32> {
12 Some(0)
13}
14
15unsafe 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
3struct S;
4
5impl S {
6 fn by_ref(&mut self) -> impl Iterator<Item = i32> {
7 std::iter::empty()
8 }
9}
10
11macro_rules! mac {
12 ($x:expr) => {
13 $x.by_ref().peekable().peek()
14 };
15}
16
17fn 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
23fn 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
29fn 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
40fn 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
3struct S;
4
5impl S {
6 fn by_ref(&mut self) -> impl Iterator<Item = i32> {
7 std::iter::empty()
8 }
9}
10
11macro_rules! mac {
12 ($x:expr) => {
13 $x.by_ref().peekable().peek()
14 };
15}
16
17fn 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
23fn 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
29fn 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
40fn 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
3struct S;
4
5impl S {
6 fn by_ref(&mut self) -> impl Iterator<Item = i32> {
7 std::iter::empty()
8 }
9}
10
11macro_rules! mac {
12 ($x:expr) => {
13 $x.by_ref().peekable().peek()
14 };
15}
16
17fn 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
23fn 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
29fn 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
40fn 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
3struct S;
4
5impl S {
6 fn by_ref(&mut self) -> impl Iterator<Item = i32> {
7 std::iter::empty()
8 }
9}
10
11macro_rules! mac {
12 ($x:expr) => {
13 $x.by_ref().peekable().peek()
14 };
15}
16
17fn 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
23fn 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
29fn 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
40fn 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 @@
1error: 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 |
4LL | 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)]`
10help: to advance the underlying iterator, use
11 |
12LL - let _: Option<&i32> = i.by_ref().peekable().peek();
13LL + let _: Option<&i32> = i.next().as_ref();
14 |
15
16error: 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 |
19LL | let _: Option<&i32> = i.by_ref().peekable().peek();
20 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21 |
22help: to peek the first item without advancing the underlying iterator, use
23 |
24LL - let _: Option<&i32> = i.by_ref().peekable().peek();
25LL + let _: Option<&i32> = i.clone().next().as_ref();
26 |
27help: to advance the underlying iterator, use
28 |
29LL - let _: Option<&i32> = i.by_ref().peekable().peek();
30LL + let _: Option<&i32> = i.next().as_ref();
31 |
32help: to make the iterator peekable, use
33 |
34LL ~ let mut i = a.into_iter().peekable();
35LL ~ let _: Option<&i32> = i.peek();
36 |
37
38error: 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 |
41LL | let _: Option<&i32> = i.by_ref().peekable().peek();
42 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43 |
44help: to peek the first item without advancing the underlying iterator, use
45 |
46LL - let _: Option<&i32> = i.by_ref().peekable().peek();
47LL + let _: Option<&i32> = i.clone().next().as_ref();
48 |
49help: to advance the underlying iterator, use
50 |
51LL - let _: Option<&i32> = i.by_ref().peekable().peek();
52LL + let _: Option<&i32> = i.next().as_ref();
53 |
54help: to make the iterator peekable, use
55 |
56LL ~ let mut i = mac!().peekable();
57LL ~ let _: Option<&i32> = i.peek();
58 |
59
60error: 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 |
63LL | let _: Option<&i32> = iter.by_ref().peekable().peek();
64 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65 |
66help: to peek the first item without advancing the underlying iterator, use
67 |
68LL - let _: Option<&i32> = iter.by_ref().peekable().peek();
69LL + let _: Option<&i32> = iter.clone().next().as_ref();
70 |
71help: to advance the underlying iterator, use
72 |
73LL - let _: Option<&i32> = iter.by_ref().peekable().peek();
74LL + let _: Option<&i32> = iter.next().as_ref();
75 |
76help: to make the iterator peekable, use
77 |
78LL ~ let mut iter = [1, 2, 3].into_iter().peekable();
79LL ~ let _: Option<&i32> = iter.peek();
80 |
81
82error: 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 |
85LL | 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()`
89help: to peek the first item without advancing the underlying iterator, use
90 |
91LL - let _: Option<&i32> = (&mut iter).by_ref().peekable().peek();
92LL + let _: Option<&i32> = (&mut iter).clone().next().as_ref();
93 |
94help: to advance the underlying iterator, use
95 |
96LL - let _: Option<&i32> = (&mut iter).by_ref().peekable().peek();
97LL + let _: Option<&i32> = (&mut iter).next().as_ref();
98 |
99
100error: 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
4fn 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 @@
1error: using `chunks_exact` with a constant chunk size
2 --> tests/ui/chunks_exact_to_as_chunks.rs:8:24
3 |
4LL | let mut it = slice.chunks_exact(4);
5 | ^^^^^^^^^^^^^^^
6 |
7help: consider using `as_chunks::<4>()` instead
8 --> tests/ui/chunks_exact_to_as_chunks.rs:8:24
9 |
10LL | 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
16error: using `chunks_exact` with a constant chunk size
17 --> tests/ui/chunks_exact_to_as_chunks.rs:14:24
18 |
19LL | let mut it = slice.chunks_exact(CHUNK_SIZE);
20 | ^^^^^^^^^^^^^^^^^^^^^^^^
21 |
22help: consider using `as_chunks::<CHUNK_SIZE>()` instead
23 --> tests/ui/chunks_exact_to_as_chunks.rs:14:24
24 |
25LL | 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
29error: using `chunks_exact` with a constant chunk size
30 --> tests/ui/chunks_exact_to_as_chunks.rs:24:24
31 |
32LL | let mut it = slice.chunks_exact(3);
33 | ^^^^^^^^^^^^^^^
34 |
35help: consider using `as_chunks::<3>()` instead
36 --> tests/ui/chunks_exact_to_as_chunks.rs:24:24
37 |
38LL | 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
42error: using `chunks_exact_mut` with a constant chunk size
43 --> tests/ui/chunks_exact_to_as_chunks.rs:31:22
44 |
45LL | let mut it = arr.chunks_exact_mut(4);
46 | ^^^^^^^^^^^^^^^^^^^
47 |
48help: consider using `as_chunks_mut::<4>()` instead
49 --> tests/ui/chunks_exact_to_as_chunks.rs:31:22
50 |
51LL | 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
55error: aborting due to 4 previous errors
56
src/tools/clippy/tests/ui/clear_with_drain.fixed-30
......@@ -20,11 +20,6 @@ fn vec_range() {
2020 let mut v = vec![1, 2, 3];
2121 v.clear();
2222 //~^ clear_with_drain
23
24 // Do lint
25 let mut v = vec![1, 2, 3];
26 v.clear();
27 //~^ clear_with_drain
2823}
2924
3025fn vec_range_from() {
......@@ -45,11 +40,6 @@ fn vec_range_from() {
4540 let mut v = vec![1, 2, 3];
4641 v.clear();
4742 //~^ clear_with_drain
48
49 // Do lint
50 let mut v = vec![1, 2, 3];
51 v.clear();
52 //~^ clear_with_drain
5343}
5444
5545fn vec_range_full() {
......@@ -124,11 +114,6 @@ fn vec_deque_range() {
124114 let mut deque = VecDeque::from([1, 2, 3]);
125115 deque.clear();
126116 //~^ clear_with_drain
127
128 // Do lint
129 let mut deque = VecDeque::from([1, 2, 3]);
130 deque.clear();
131 //~^ clear_with_drain
132117}
133118
134119fn vec_deque_range_from() {
......@@ -149,11 +134,6 @@ fn vec_deque_range_from() {
149134 let mut deque = VecDeque::from([1, 2, 3]);
150135 deque.clear();
151136 //~^ clear_with_drain
152
153 // Do lint
154 let mut deque = VecDeque::from([1, 2, 3]);
155 deque.clear();
156 //~^ clear_with_drain
157137}
158138
159139fn vec_deque_range_full() {
......@@ -228,11 +208,6 @@ fn string_range() {
228208 let mut s = String::from("Hello, world!");
229209 s.clear();
230210 //~^ clear_with_drain
231
232 // Do lint
233 let mut s = String::from("Hello, world!");
234 s.clear();
235 //~^ clear_with_drain
236211}
237212
238213fn string_range_from() {
......@@ -253,11 +228,6 @@ fn string_range_from() {
253228 let mut s = String::from("Hello, world!");
254229 s.clear();
255230 //~^ clear_with_drain
256
257 // Do lint
258 let mut s = String::from("Hello, world!");
259 s.clear();
260 //~^ clear_with_drain
261231}
262232
263233fn string_range_full() {
src/tools/clippy/tests/ui/clear_with_drain.rs-30
......@@ -20,11 +20,6 @@ fn vec_range() {
2020 let mut v = vec![1, 2, 3];
2121 v.drain(0..v.len());
2222 //~^ 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
2823}
2924
3025fn vec_range_from() {
......@@ -45,11 +40,6 @@ fn vec_range_from() {
4540 let mut v = vec![1, 2, 3];
4641 v.drain(0..);
4742 //~^ clear_with_drain
48
49 // Do lint
50 let mut v = vec![1, 2, 3];
51 v.drain(usize::MIN..);
52 //~^ clear_with_drain
5343}
5444
5545fn vec_range_full() {
......@@ -124,11 +114,6 @@ fn vec_deque_range() {
124114 let mut deque = VecDeque::from([1, 2, 3]);
125115 deque.drain(0..deque.len());
126116 //~^ 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
132117}
133118
134119fn vec_deque_range_from() {
......@@ -149,11 +134,6 @@ fn vec_deque_range_from() {
149134 let mut deque = VecDeque::from([1, 2, 3]);
150135 deque.drain(0..);
151136 //~^ 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
157137}
158138
159139fn vec_deque_range_full() {
......@@ -228,11 +208,6 @@ fn string_range() {
228208 let mut s = String::from("Hello, world!");
229209 s.drain(0..s.len());
230210 //~^ 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
236211}
237212
238213fn string_range_from() {
......@@ -253,11 +228,6 @@ fn string_range_from() {
253228 let mut s = String::from("Hello, world!");
254229 s.drain(0..);
255230 //~^ clear_with_drain
256
257 // Do lint
258 let mut s = String::from("Hello, world!");
259 s.drain(usize::MIN..);
260 //~^ clear_with_drain
261231}
262232
263233fn string_range_full() {
src/tools/clippy/tests/ui/clear_with_drain.stderr+15-51
......@@ -8,124 +8,88 @@ LL | v.drain(0..v.len());
88 = help: to override `-D warnings` add `#[allow(clippy::clear_with_drain)]`
99
1010error: `drain` used to clear a `Vec`
11 --> tests/ui/clear_with_drain.rs:26:7
12 |
13LL | v.drain(usize::MIN..v.len());
14 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
15
16error: `drain` used to clear a `Vec`
17 --> tests/ui/clear_with_drain.rs:46:7
11 --> tests/ui/clear_with_drain.rs:41:7
1812 |
1913LL | v.drain(0..);
2014 | ^^^^^^^^^^ help: try: `clear()`
2115
2216error: `drain` used to clear a `Vec`
23 --> tests/ui/clear_with_drain.rs:51:7
24 |
25LL | v.drain(usize::MIN..);
26 | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
27
28error: `drain` used to clear a `Vec`
29 --> tests/ui/clear_with_drain.rs:68:7
17 --> tests/ui/clear_with_drain.rs:58:7
3018 |
3119LL | v.drain(..);
3220 | ^^^^^^^^^ help: try: `clear()`
3321
3422error: `drain` used to clear a `Vec`
35 --> tests/ui/clear_with_drain.rs:86:7
23 --> tests/ui/clear_with_drain.rs:76:7
3624 |
3725LL | v.drain(..v.len());
3826 | ^^^^^^^^^^^^^^^^ help: try: `clear()`
3927
4028error: `drain` used to clear a `VecDeque`
41 --> tests/ui/clear_with_drain.rs:125:11
29 --> tests/ui/clear_with_drain.rs:115:11
4230 |
4331LL | deque.drain(0..deque.len());
4432 | ^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
4533
4634error: `drain` used to clear a `VecDeque`
47 --> tests/ui/clear_with_drain.rs:130:11
48 |
49LL | deque.drain(usize::MIN..deque.len());
50 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
51
52error: `drain` used to clear a `VecDeque`
53 --> tests/ui/clear_with_drain.rs:150:11
35 --> tests/ui/clear_with_drain.rs:135:11
5436 |
5537LL | deque.drain(0..);
5638 | ^^^^^^^^^^ help: try: `clear()`
5739
5840error: `drain` used to clear a `VecDeque`
59 --> tests/ui/clear_with_drain.rs:155:11
60 |
61LL | deque.drain(usize::MIN..);
62 | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
63
64error: `drain` used to clear a `VecDeque`
65 --> tests/ui/clear_with_drain.rs:172:11
41 --> tests/ui/clear_with_drain.rs:152:11
6642 |
6743LL | deque.drain(..);
6844 | ^^^^^^^^^ help: try: `clear()`
6945
7046error: `drain` used to clear a `VecDeque`
71 --> tests/ui/clear_with_drain.rs:190:11
47 --> tests/ui/clear_with_drain.rs:170:11
7248 |
7349LL | deque.drain(..deque.len());
7450 | ^^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
7551
7652error: `drain` used to clear a `String`
77 --> tests/ui/clear_with_drain.rs:229:7
53 --> tests/ui/clear_with_drain.rs:209:7
7854 |
7955LL | s.drain(0..s.len());
8056 | ^^^^^^^^^^^^^^^^^ help: try: `clear()`
8157
8258error: `drain` used to clear a `String`
83 --> tests/ui/clear_with_drain.rs:234:7
84 |
85LL | s.drain(usize::MIN..s.len());
86 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
87
88error: `drain` used to clear a `String`
89 --> tests/ui/clear_with_drain.rs:254:7
59 --> tests/ui/clear_with_drain.rs:229:7
9060 |
9161LL | s.drain(0..);
9262 | ^^^^^^^^^^ help: try: `clear()`
9363
9464error: `drain` used to clear a `String`
95 --> tests/ui/clear_with_drain.rs:259:7
96 |
97LL | s.drain(usize::MIN..);
98 | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()`
99
100error: `drain` used to clear a `String`
101 --> tests/ui/clear_with_drain.rs:276:7
65 --> tests/ui/clear_with_drain.rs:246:7
10266 |
10367LL | s.drain(..);
10468 | ^^^^^^^^^ help: try: `clear()`
10569
10670error: `drain` used to clear a `String`
107 --> tests/ui/clear_with_drain.rs:294:7
71 --> tests/ui/clear_with_drain.rs:264:7
10872 |
10973LL | s.drain(..s.len());
11074 | ^^^^^^^^^^^^^^^^ help: try: `clear()`
11175
11276error: `drain` used to clear a `HashSet`
113 --> tests/ui/clear_with_drain.rs:333:9
77 --> tests/ui/clear_with_drain.rs:303:9
11478 |
11579LL | set.drain();
11680 | ^^^^^^^ help: try: `clear()`
11781
11882error: `drain` used to clear a `HashMap`
119 --> tests/ui/clear_with_drain.rs:353:9
83 --> tests/ui/clear_with_drain.rs:323:9
12084 |
12185LL | map.drain();
12286 | ^^^^^^^ help: try: `clear()`
12387
12488error: `drain` used to clear a `BinaryHeap`
125 --> tests/ui/clear_with_drain.rs:373:10
89 --> tests/ui/clear_with_drain.rs:343:10
12690 |
12791LL | heap.drain();
12892 | ^^^^^^^ help: try: `clear()`
12993
130error: aborting due to 21 previous errors
94error: aborting due to 15 previous errors
13195
src/tools/clippy/tests/ui/crashes/ice-16950.rs created+27
......@@ -0,0 +1,27 @@
1//@check-pass
2#![feature(trivial_bounds)]
3
4struct Helper<T>(T);
5
6trait Unsized<T: ?Sized> {
7 const SIZE: usize = usize::MAX;
8}
9
10impl<T: ?Sized> Unsized<T> for T {}
11
12impl<T> Helper<T> {
13 const SIZE: usize = size_of::<T>();
14}
15
16struct TrickClippy(str);
17
18impl TrickClippy {
19 fn trick_clippy() -> bool
20 where
21 Self: Sized,
22 {
23 Helper::<Self>::SIZE == str::SIZE
24 }
25}
26
27fn main() {}
src/tools/clippy/tests/ui/drain_collect.stderr+20-20
......@@ -1,8 +1,8 @@
1error: you seem to be trying to move all elements into a new `BinaryHeap`
1error: draining all elements of a collection into a new collection of the same type
22 --> tests/ui/drain_collect.rs:6:5
33 |
44LL | 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)`
66 |
77note: the lint level is defined here
88 --> tests/ui/drain_collect.rs:1:9
......@@ -10,59 +10,59 @@ note: the lint level is defined here
1010LL | #![deny(clippy::drain_collect)]
1111 | ^^^^^^^^^^^^^^^^^^^^^
1212
13error: you seem to be trying to move all elements into a new `HashMap`
13error: draining all elements of a collection into a new collection of the same type
1414 --> tests/ui/drain_collect.rs:15:5
1515 |
1616LL | 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)`
1818
19error: you seem to be trying to move all elements into a new `HashSet`
19error: draining all elements of a collection into a new collection of the same type
2020 --> tests/ui/drain_collect.rs:24:5
2121 |
2222LL | 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)`
2424
25error: you seem to be trying to move all elements into a new `Vec`
25error: draining all elements of a collection into a new collection of the same type
2626 --> tests/ui/drain_collect.rs:33:5
2727 |
2828LL | 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)`
3030
31error: you seem to be trying to move all elements into a new `Vec`
31error: draining all elements of a collection into a new collection of the same type
3232 --> tests/ui/drain_collect.rs:42:5
3333 |
3434LL | 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)`
3636
37error: you seem to be trying to move all elements into a new `Vec`
37error: draining all elements of a collection into a new collection of the same type
3838 --> tests/ui/drain_collect.rs:47:5
3939 |
4040LL | 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)`
4242
43error: you seem to be trying to move all elements into a new `Vec`
43error: draining all elements of a collection into a new collection of the same type
4444 --> tests/ui/drain_collect.rs:52:5
4545 |
4646LL | 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)`
4848
49error: you seem to be trying to move all elements into a new `Vec`
49error: draining all elements of a collection into a new collection of the same type
5050 --> tests/ui/drain_collect.rs:57:5
5151 |
5252LL | 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)`
5454
55error: you seem to be trying to move all elements into a new `Vec`
55error: draining all elements of a collection into a new collection of the same type
5656 --> tests/ui/drain_collect.rs:63:5
5757 |
5858LL | 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)`
6060
61error: you seem to be trying to move all elements into a new `String`
61error: draining all elements of a collection into a new collection of the same type
6262 --> tests/ui/drain_collect.rs:72:5
6363 |
6464LL | 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)`
6666
6767error: aborting due to 10 previous errors
6868
src/tools/clippy/tests/ui/drain_collect_nostd.stderr+2-2
......@@ -1,8 +1,8 @@
1error: you seem to be trying to move all elements into a new `Vec`
1error: draining all elements of a collection into a new collection of the same type
22 --> tests/ui/drain_collect_nostd.rs:7:5
33 |
44LL | 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)`
66 |
77 = note: `-D clippy::drain-collect` implied by `-D warnings`
88 = 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 {
211211 }
212212}
213213
214mod 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
214228fn main() {}
src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.rs+15
......@@ -1,3 +1,5 @@
1//@no-rustfix
2
13#![warn(clippy::extra_unused_type_parameters)]
24
35fn unused_where_clause<T, U>(x: U)
......@@ -24,4 +26,17 @@ where
2426 unimplemented!();
2527}
2628
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.
31mod 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
2742fn main() {}
src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.stderr+16-4
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | fn unused_where_clause<T, U>(x: U)
55 | ^
......@@ -9,7 +9,7 @@ LL | fn unused_where_clause<T, U>(x: U)
99 = help: to override `-D warnings` add `#[allow(clippy::extra_unused_type_parameters)]`
1010
1111error: 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
1313 |
1414LL | fn unused_multi_where_clause<T, U, V: Default>(x: U)
1515 | ^ ^^^^^^^^^^
......@@ -17,12 +17,24 @@ LL | fn unused_multi_where_clause<T, U, V: Default>(x: U)
1717 = help: consider removing the parameters
1818
1919error: 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
2121 |
2222LL | fn unused_all_where_clause<T, U: Default, V: Default>()
2323 | ^ ^^^^^^^^^^ ^^^^^^^^^^
2424 |
2525 = help: consider removing the parameters
2626
27error: aborting due to 3 previous errors
27error: type parameter `T` goes unused in function definition
28 --> tests/ui/extra_unused_type_parameters_unfixable.rs:32:17
29 |
30LL | fn unused_ty<T>(x: u8) {
31 | ^^^
32 |
33help: consider removing the parameter
34 |
35LL - fn unused_ty<T>(x: u8) {
36LL + fn unused_ty(x: u8) {
37 |
38
39error: aborting due to 4 previous errors
2840
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
6extern crate option_helpers;
7
8use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives};
9
10fn main() {}
11
12fn 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
43fn 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"]
55fn msrv_1_27() {
56 let _ = vec![1].into_iter().rfind(|&x| x < 0);
57 //~^ filter_next
58}
59
60#[clippy::msrv = "1.26"]
61fn 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
6extern crate option_helpers;
7
8use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives};
9
10fn main() {}
11
12fn 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
45fn 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"]
57fn 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"]
63fn 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 @@
1error: called `filter(..).next()` on an `Iterator`
2 --> tests/ui/filter_next.rs:16:13
3 |
4LL | 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)]`
9help: use `.find(..)` instead
10 |
11LL - let _ = v.iter().filter(|&x| *x < 0).next();
12LL + let _ = v.iter().find(|&x| *x < 0);
13 |
14
15error: called `filter(..).next_back()` on an `DoubleEndedIterator`
16 --> tests/ui/filter_next.rs:19:13
17 |
18LL | let _ = v.iter().filter(|&x| *x < 0).next_back();
19 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20 |
21help: use `.rfind(..)` instead
22 |
23LL - let _ = v.iter().filter(|&x| *x < 0).next_back();
24LL + let _ = v.iter().rfind(|&x| *x < 0);
25 |
26
27error: called `filter(..).next()` on an `Iterator`
28 --> tests/ui/filter_next.rs:24:13
29 |
30LL | let _ = v.iter().filter(|&x| {
31 | _____________^
32LL | |
33LL | | *x < 0
34LL | | }
35LL | | ).next();
36 | |___________________________^
37 |
38help: use `.find(..)` instead
39 |
40LL ~ let _ = v.iter().find(|&x| {
41LL +
42LL + *x < 0
43LL ~ });
44 |
45
46error: called `filter(..).next_back()` on an `DoubleEndedIterator`
47 --> tests/ui/filter_next.rs:31:13
48 |
49LL | let _ = v.iter().filter(|&x| {
50 | _____________^
51LL | |
52LL | | *x < 0
53LL | | }
54LL | | ).next_back();
55 | |________________________________^
56 |
57help: use `.rfind(..)` instead
58 |
59LL ~ let _ = v.iter().rfind(|&x| {
60LL +
61LL + *x < 0
62LL ~ });
63 |
64
65error: called `filter(..).next_back()` on an `DoubleEndedIterator`
66 --> tests/ui/filter_next.rs:58:13
67 |
68LL | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back();
69 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
70 |
71help: use `.rfind(..)` instead
72 |
73LL - let _ = vec![1].into_iter().filter(|&x| x < 0).next_back();
74LL + let _ = vec![1].into_iter().rfind(|&x| x < 0);
75 |
76
77error: 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
4fn 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
8pub 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 @@
1error: called `filter(..).next()` on an `Iterator`
2 --> tests/ui/filter_next_unfixable.rs:11:17
3 |
4LL | let _ = iter.filter(|_| true).next();
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6 |
7help: you will also need to make `iter` mutable, because `find` takes `&mut self`
8 --> tests/ui/filter_next_unfixable.rs:10:13
9 |
10LL | 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)]`
14help: use `.find(..)` instead
15 |
16LL - let _ = iter.filter(|_| true).next();
17LL + let _ = iter.find(|_| true);
18 |
19
20error: called `filter(..).next_back()` on an `DoubleEndedIterator`
21 --> tests/ui/filter_next_unfixable.rs:16:17
22 |
23LL | let _ = iter.filter(|_| true).next_back();
24 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
25 |
26help: you will also need to make `iter` mutable, because `rfind` takes `&mut self`
27 --> tests/ui/filter_next_unfixable.rs:15:13
28 |
29LL | let iter = (0..10);
30 | ^^^^
31help: use `.rfind(..)` instead
32 |
33LL - let _ = iter.filter(|_| true).next_back();
34LL + let _ = iter.rfind(|_| true);
35 |
36
37error: aborting due to 2 previous errors
38
src/tools/clippy/tests/ui/floating_point_mul_add.stderr+21-20
......@@ -1,121 +1,122 @@
1error: multiply and add expressions can be calculated more efficiently and accurately
1error: multiply and add expressions may be calculated more efficiently and accurately
22 --> tests/ui/floating_point_mul_add.rs:19:13
33 |
44LL | let _ = a * b + c;
55 | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
66 |
7 = note: the performance gain from `mul_add` may vary depending on the target architecture
78 = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
89 = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]`
910
10error: multiply and add expressions can be calculated more efficiently and accurately
11error: multiply and add expressions may be calculated more efficiently and accurately
1112 --> tests/ui/floating_point_mul_add.rs:21:13
1213 |
1314LL | let _ = a * b - c;
1415 | ^^^^^^^^^ help: consider using: `a.mul_add(b, -c)`
1516
16error: multiply and add expressions can be calculated more efficiently and accurately
17error: multiply and add expressions may be calculated more efficiently and accurately
1718 --> tests/ui/floating_point_mul_add.rs:23:13
1819 |
1920LL | let _ = c + a * b;
2021 | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
2122
22error: multiply and add expressions can be calculated more efficiently and accurately
23error: multiply and add expressions may be calculated more efficiently and accurately
2324 --> tests/ui/floating_point_mul_add.rs:25:13
2425 |
2526LL | let _ = c - a * b;
2627 | ^^^^^^^^^ help: consider using: `a.mul_add(-b, c)`
2728
28error: multiply and add expressions can be calculated more efficiently and accurately
29error: multiply and add expressions may be calculated more efficiently and accurately
2930 --> tests/ui/floating_point_mul_add.rs:27:13
3031 |
3132LL | let _ = a + 2.0 * 4.0;
3233 | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)`
3334
34error: multiply and add expressions can be calculated more efficiently and accurately
35error: multiply and add expressions may be calculated more efficiently and accurately
3536 --> tests/ui/floating_point_mul_add.rs:29:13
3637 |
3738LL | let _ = a + 2. * 4.;
3839 | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)`
3940
40error: multiply and add expressions can be calculated more efficiently and accurately
41error: multiply and add expressions may be calculated more efficiently and accurately
4142 --> tests/ui/floating_point_mul_add.rs:32:13
4243 |
4344LL | let _ = (a * b) + c;
4445 | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
4546
46error: multiply and add expressions can be calculated more efficiently and accurately
47error: multiply and add expressions may be calculated more efficiently and accurately
4748 --> tests/ui/floating_point_mul_add.rs:34:13
4849 |
4950LL | let _ = c + (a * b);
5051 | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
5152
52error: multiply and add expressions can be calculated more efficiently and accurately
53error: multiply and add expressions may be calculated more efficiently and accurately
5354 --> tests/ui/floating_point_mul_add.rs:36:13
5455 |
5556LL | let _ = a * b * c + d;
5657 | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)`
5758
58error: multiply and add expressions can be calculated more efficiently and accurately
59error: multiply and add expressions may be calculated more efficiently and accurately
5960 --> tests/ui/floating_point_mul_add.rs:39:13
6061 |
6162LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c;
6263 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))`
6364
64error: multiply and add expressions can be calculated more efficiently and accurately
65error: multiply and add expressions may be calculated more efficiently and accurately
6566 --> tests/ui/floating_point_mul_add.rs:41:13
6667 |
6768LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64;
6869 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)`
6970
70error: multiply and add expressions can be calculated more efficiently and accurately
71error: multiply and add expressions may be calculated more efficiently and accurately
7172 --> tests/ui/floating_point_mul_add.rs:44:13
7273 |
7374LL | let _ = (a * a + b).sqrt();
7475 | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)`
7576
76error: multiply and add expressions can be calculated more efficiently and accurately
77error: multiply and add expressions may be calculated more efficiently and accurately
7778 --> tests/ui/floating_point_mul_add.rs:48:13
7879 |
7980LL | let _ = a - (b * u as f64);
8081 | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)`
8182
82error: multiply and add expressions can be calculated more efficiently and accurately
83error: multiply and add expressions may be calculated more efficiently and accurately
8384 --> tests/ui/floating_point_mul_add.rs:102:13
8485 |
8586LL | let _ = 0.5 + 2.0 * x;
8687 | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(x, 0.5)`
8788
88error: multiply and add expressions can be calculated more efficiently and accurately
89error: multiply and add expressions may be calculated more efficiently and accurately
8990 --> tests/ui/floating_point_mul_add.rs:104:13
9091 |
9192LL | let _ = 2.0 * x + 0.5;
9293 | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(x, 0.5)`
9394
94error: multiply and add expressions can be calculated more efficiently and accurately
95error: multiply and add expressions may be calculated more efficiently and accurately
9596 --> tests/ui/floating_point_mul_add.rs:107:13
9697 |
9798LL | let _ = x + 2.0 * 4.0;
9899 | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, x)`
99100
100error: multiply and add expressions can be calculated more efficiently and accurately
101error: multiply and add expressions may be calculated more efficiently and accurately
101102 --> tests/ui/floating_point_mul_add.rs:111:13
102103 |
103104LL | let _ = y * 2.0 + 0.5;
104105 | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(2.0, 0.5)`
105106
106error: multiply and add expressions can be calculated more efficiently and accurately
107error: multiply and add expressions may be calculated more efficiently and accurately
107108 --> tests/ui/floating_point_mul_add.rs:113:13
108109 |
109110LL | let _ = 1.0 * 2.0 + 0.5;
110111 | ^^^^^^^^^^^^^^^ help: consider using: `1.0f64.mul_add(2.0, 0.5)`
111112
112error: multiply and add expressions can be calculated more efficiently and accurately
113error: multiply and add expressions may be calculated more efficiently and accurately
113114 --> tests/ui/floating_point_mul_add.rs:122:5
114115 |
115116LL | a += b * c;
116117 | ^^^^^^^^^^ help: consider using: `a = b.mul_add(c, a)`
117118
118error: multiply and add expressions can be calculated more efficiently and accurately
119error: multiply and add expressions may be calculated more efficiently and accurately
119120 --> tests/ui/floating_point_mul_add.rs:125:5
120121 |
121122LL | a -= b * c;
src/tools/clippy/tests/ui/let_underscore_future.rs+8
......@@ -1,4 +1,5 @@
11use std::future::Future;
2use std::pin::Pin;
23
34async fn some_async_fn() {}
45
......@@ -10,6 +11,10 @@ fn custom() -> impl Future<Output = ()> {
1011
1112fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
1213
14fn boxed() -> Pin<Box<dyn Future<Output = ()>>> {
15 Box::pin(async {})
16}
17
1318fn main() {
1419 let _ = some_async_fn();
1520 //~^ let_underscore_future
......@@ -21,4 +26,7 @@ fn main() {
2126 do_something_to_future(&mut future);
2227 let _ = future;
2328 //~^ let_underscore_future
29
30 // Typed bindings are an intentional discard, see also `let_underscore_untyped`.
31 let _: Pin<Box<dyn Future<Output = ()>>> = boxed();
2432}
src/tools/clippy/tests/ui/let_underscore_future.stderr+3-3
......@@ -1,5 +1,5 @@
11error: non-binding `let` on a future
2 --> tests/ui/let_underscore_future.rs:14:5
2 --> tests/ui/let_underscore_future.rs:19:5
33 |
44LL | let _ = some_async_fn();
55 | ^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -9,7 +9,7 @@ LL | let _ = some_async_fn();
99 = help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]`
1010
1111error: non-binding `let` on a future
12 --> tests/ui/let_underscore_future.rs:17:5
12 --> tests/ui/let_underscore_future.rs:22:5
1313 |
1414LL | let _ = custom();
1515 | ^^^^^^^^^^^^^^^^^
......@@ -17,7 +17,7 @@ LL | let _ = custom();
1717 = help: consider awaiting the future or dropping explicitly with `std::mem::drop`
1818
1919error: non-binding `let` on a future
20 --> tests/ui/let_underscore_future.rs:22:5
20 --> tests/ui/let_underscore_future.rs:27:5
2121 |
2222LL | let _ = future;
2323 | ^^^^^^^^^^^^^^^
src/tools/clippy/tests/ui/manual_abs_diff.fixed+1
......@@ -51,6 +51,7 @@ fn main() {
5151}
5252
5353// FIXME: bunch of patterns that should be linted
54#[expect(clippy::needless_late_init)]
5455fn fixme() {
5556 let a: usize = 5;
5657 let b: usize = 3;
src/tools/clippy/tests/ui/manual_abs_diff.rs+1
......@@ -61,6 +61,7 @@ fn main() {
6161}
6262
6363// FIXME: bunch of patterns that should be linted
64#[expect(clippy::needless_late_init)]
6465fn fixme() {
6566 let a: usize = 5;
6667 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 };
8080 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)`
8181
8282error: 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
8484 |
8585LL | / if a < b {
8686LL | |
src/tools/clippy/tests/ui/manual_option_zip.fixed+23-5
......@@ -21,11 +21,6 @@ fn should_lint() {
2121 let _ = None::<i32>.zip(b);
2222 //~^ manual_option_zip
2323
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
2924 // tuple order reversed: (inner, outer) instead of (outer, inner)
3025 let a: Option<i32> = Some(1);
3126 let b: Option<i32> = Some(2);
......@@ -123,3 +118,26 @@ fn issue16968() {
123118 let opts = [1, 2];
124119 let _ = a.and_then(|a| opts.into_iter().find(|b| *b == a).map(|b| (a, b)));
125120}
121
122fn 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() {
2121 let _ = None::<i32>.and_then(|a| b.map(|b| (a, b)));
2222 //~^ manual_option_zip
2323
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
2924 // tuple order reversed: (inner, outer) instead of (outer, inner)
3025 let a: Option<i32> = Some(1);
3126 let b: Option<i32> = Some(2);
......@@ -123,3 +118,26 @@ fn issue16968() {
123118 let opts = [1, 2];
124119 let _ = a.and_then(|a| opts.into_iter().find(|b| *b == a).map(|b| (a, b)));
125120}
121
122fn 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)));
2020 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `None::<i32>.zip(b)`
2121
2222error: manual implementation of `Option::zip`
23 --> tests/ui/manual_option_zip.rs:26:13
24 |
25LL | let _ = a.and_then(|a| get_option().map(|b| (a, b)));
26 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(get_option())`
27
28error: manual implementation of `Option::zip`
29 --> tests/ui/manual_option_zip.rs:32:13
23 --> tests/ui/manual_option_zip.rs:27:13
3024 |
3125LL | let _ = a.and_then(|a| b.map(|b| (b, a)));
3226 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.zip(a)`
3327
3428error: manual implementation of `Option::zip`
35 --> tests/ui/manual_option_zip.rs:39:13
29 --> tests/ui/manual_option_zip.rs:34:13
3630 |
3731LL | let _ = a.and_then(|a| { b.map(|b| (a, b)) });
3832 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)`
3933
4034error: manual implementation of `Option::zip`
41 --> tests/ui/manual_option_zip.rs:42:13
35 --> tests/ui/manual_option_zip.rs:37:13
4236 |
4337LL | let _ = a.and_then(|a| b.map(|b| { (a, b) }));
4438 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)`
4539
4640error: manual implementation of `Option::zip`
47 --> tests/ui/manual_option_zip.rs:45:13
41 --> tests/ui/manual_option_zip.rs:40:13
4842 |
4943LL | let _ = a.and_then(|a| { b.map(|b| { (a, b) }) });
5044 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)`
5145
52error: aborting due to 8 previous errors
46error: aborting due to 7 previous errors
5347
src/tools/clippy/tests/ui/manual_slice_fill.fixed+32
......@@ -34,6 +34,38 @@ fn should_lint() {
3434 some_slice.fill(0);
3535}
3636
37fn should_lint_direct_mutref_array(s: &mut [u8; 1]) {
38 s.fill(0);
39}
40
41fn should_lint_direct_mutref_array_non_zero(s: &mut [u8; 4]) {
42 s.fill(42);
43}
44
45fn should_lint_direct_mutref_array_variable(s: &mut [i32; 3]) {
46 let x = 7;
47 s.fill(x);
48}
49
50fn should_not_lint_direct_mutref_array_fn(s: &mut [usize; 2]) {
51 for slot in s {
52 *slot = num();
53 }
54}
55
56fn should_not_lint_direct_mutref_array_iter_used(s: &mut [u8; 3]) {
57 for slot in s {
58 *slot = !*slot;
59 }
60}
61
62fn 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
3769fn should_not_lint() {
3870 let mut some_slice = [1, 2, 3, 4, 5];
3971
src/tools/clippy/tests/ui/manual_slice_fill.rs+41
......@@ -47,6 +47,47 @@ fn should_lint() {
4747 }
4848}
4949
50fn should_lint_direct_mutref_array(s: &mut [u8; 1]) {
51 for slot in s {
52 //~^ manual_slice_fill
53 *slot = 0;
54 }
55}
56
57fn 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
64fn 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
72fn should_not_lint_direct_mutref_array_fn(s: &mut [usize; 2]) {
73 for slot in s {
74 *slot = num();
75 }
76}
77
78fn should_not_lint_direct_mutref_array_iter_used(s: &mut [u8; 3]) {
79 for slot in s {
80 *slot = !*slot;
81 }
82}
83
84fn 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
5091fn should_not_lint() {
5192 let mut some_slice = [1, 2, 3, 4, 5];
5293
src/tools/clippy/tests/ui/manual_slice_fill.stderr+28-1
......@@ -38,5 +38,32 @@ LL | | // foo
3838LL | | }
3939 | |_____^ help: try: `some_slice.fill(0);`
4040
41error: aborting due to 4 previous errors
41error: manually filling a slice
42 --> tests/ui/manual_slice_fill.rs:51:5
43 |
44LL | / for slot in s {
45LL | |
46LL | | *slot = 0;
47LL | | }
48 | |_____^ help: try: `s.fill(0);`
49
50error: manually filling a slice
51 --> tests/ui/manual_slice_fill.rs:58:5
52 |
53LL | / for slot in s {
54LL | |
55LL | | *slot = 42;
56LL | | }
57 | |_____^ help: try: `s.fill(42);`
58
59error: manually filling a slice
60 --> tests/ui/manual_slice_fill.rs:66:5
61 |
62LL | / for slot in s {
63LL | |
64LL | | *slot = x;
65LL | | }
66 | |_____^ help: try: `s.fill(x);`
67
68error: aborting due to 7 previous errors
4269
src/tools/clippy/tests/ui/map_unwrap_or.rs+7
......@@ -161,3 +161,10 @@ fn issue15752() {
161161 x.map(|y| y.0).unwrap_or(&[]);
162162 //~^ map_unwrap_or
163163}
164
165fn 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
238238LL | x.map(|y| y.0).unwrap_or(&[]);
239239 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
240240
241error: aborting due to 16 previous errors
241error: called `map(<f>).unwrap_or(<a>)` on an `Option` value
242 --> tests/ui/map_unwrap_or.rs:167:23
243 |
244LL | let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw);
245 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
246
247error: aborting due to 17 previous errors
242248
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]
25extern crate option_helpers;
1#![warn(clippy::filter_next, clippy::new_ret_no_self)]
262
273use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
284use std::ops::Mul;
295use std::rc::{self, Rc};
306use std::sync::{self, Arc};
317
32use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives};
33
348struct Lt<'a> {
359 foo: &'a u32,
3610}
......@@ -115,43 +89,4 @@ impl Mul<T> for T {
11589 }
11690}
11791
118/// Checks implementation of `FILTER_NEXT` lint.
119#[rustfmt::skip]
120fn 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]
139fn 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
15792fn main() {}
src/tools/clippy/tests/ui/methods.stderr+2-27
......@@ -1,5 +1,5 @@
11error: methods called `new` usually return `Self`
2 --> tests/ui/methods.rs:102:5
2 --> tests/ui/methods.rs:76:5
33 |
44LL | / fn new() -> i32 {
55LL | |
......@@ -10,30 +10,5 @@ LL | | }
1010 = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
1111 = help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]`
1212
13error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
14 --> tests/ui/methods.rs:124:13
15 |
16LL | let _ = v.iter().filter(|&x| {
17 | _____________^
18LL | |
19LL | | *x < 0
20LL | | }
21LL | | ).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
27error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead
28 --> tests/ui/methods.rs:143:13
29 |
30LL | let _ = v.iter().filter(|&x| {
31 | _____________^
32LL | |
33LL | | *x < 0
34LL | | }
35LL | | ).next_back();
36 | |________________________________^
37
38error: aborting due to 3 previous errors
13error: aborting due to 1 previous error
3914
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.
5fn 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"]
17fn msrv_1_27() {
18 let _ = vec![1].into_iter().rfind(|&x| x < 0);
19 //~^ filter_next
20}
21
22#[clippy::msrv = "1.26"]
23fn 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.
5fn 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"]
17fn 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"]
23fn 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 @@
1error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
2 --> tests/ui/methods_fixable.rs:9:13
3 |
4LL | 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
10error: 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 |
13LL | let _ = v.iter().filter(|&x| *x < 0).next_back();
14 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().rfind(|&x| *x < 0)`
15
16error: 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 |
19LL | let _ = vec![1].into_iter().filter(|&x| x < 0).next_back();
20 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec![1].into_iter().rfind(|&x| x < 0)`
21
22error: 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
3fn main() {}
4
5pub 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 @@
1error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
2 --> tests/ui/methods_unfixable.rs:7:13
3 |
4LL | let _ = iter.filter(|_| true).next();
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)`
6 |
7help: you will also need to make `iter` mutable, because `find` takes `&mut self`
8 --> tests/ui/methods_unfixable.rs:6:9
9 |
10LL | 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
15error: aborting due to 1 previous error
16
src/tools/clippy/tests/ui/min_ident_chars.rs+2-2
......@@ -1,7 +1,7 @@
11//@aux-build:proc_macros.rs
2#![allow(irrefutable_let_patterns, nonstandard_style, unused)]
3#![allow(clippy::struct_field_names)]
42#![warn(clippy::min_ident_chars)]
3#![expect(irrefutable_let_patterns, nonstandard_style)]
4#![allow(clippy::struct_field_names)]
55
66extern crate proc_macros;
77use 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)]
23
34use std::cmp::{max as my_max, max, min as my_min, min};
45
src/tools/clippy/tests/ui/min_max.stderr+15-14
......@@ -1,79 +1,80 @@
11error: this `min`/`max` combination leads to constant result
2 --> tests/ui/min_max.rs:21:5
2 --> tests/ui/min_max.rs:22:5
33 |
44LL | min(1, max(3, x));
55 | ^^^^^^^^^^^^^^^^^
66 |
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)]`
89
910error: this `min`/`max` combination leads to constant result
10 --> tests/ui/min_max.rs:24:5
11 --> tests/ui/min_max.rs:25:5
1112 |
1213LL | min(max(3, x), 1);
1314 | ^^^^^^^^^^^^^^^^^
1415
1516error: this `min`/`max` combination leads to constant result
16 --> tests/ui/min_max.rs:27:5
17 --> tests/ui/min_max.rs:28:5
1718 |
1819LL | max(min(x, 1), 3);
1920 | ^^^^^^^^^^^^^^^^^
2021
2122error: this `min`/`max` combination leads to constant result
22 --> tests/ui/min_max.rs:30:5
23 --> tests/ui/min_max.rs:31:5
2324 |
2425LL | max(3, min(x, 1));
2526 | ^^^^^^^^^^^^^^^^^
2627
2728error: this `min`/`max` combination leads to constant result
28 --> tests/ui/min_max.rs:33:5
29 --> tests/ui/min_max.rs:34:5
2930 |
3031LL | my_max(3, my_min(x, 1));
3132 | ^^^^^^^^^^^^^^^^^^^^^^^
3233
3334error: this `min`/`max` combination leads to constant result
34 --> tests/ui/min_max.rs:44:5
35 --> tests/ui/min_max.rs:45:5
3536 |
3637LL | min("Apple", max("Zoo", s));
3738 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
3839
3940error: this `min`/`max` combination leads to constant result
40 --> tests/ui/min_max.rs:47:5
41 --> tests/ui/min_max.rs:48:5
4142 |
4243LL | max(min(s, "Apple"), "Zoo");
4344 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
4445
4546error: this `min`/`max` combination leads to constant result
46 --> tests/ui/min_max.rs:53:5
47 --> tests/ui/min_max.rs:54:5
4748 |
4849LL | x.min(1).max(3);
4950 | ^^^^^^^^^^^^^^^
5051
5152error: this `min`/`max` combination leads to constant result
52 --> tests/ui/min_max.rs:56:5
53 --> tests/ui/min_max.rs:57:5
5354 |
5455LL | x.max(3).min(1);
5556 | ^^^^^^^^^^^^^^^
5657
5758error: this `min`/`max` combination leads to constant result
58 --> tests/ui/min_max.rs:59:5
59 --> tests/ui/min_max.rs:60:5
5960 |
6061LL | f.max(3f32).min(1f32);
6162 | ^^^^^^^^^^^^^^^^^^^^^
6263
6364error: this `min`/`max` combination leads to constant result
64 --> tests/ui/min_max.rs:66:5
65 --> tests/ui/min_max.rs:67:5
6566 |
6667LL | max(x.min(1), 3);
6768 | ^^^^^^^^^^^^^^^^
6869
6970error: this `min`/`max` combination leads to constant result
70 --> tests/ui/min_max.rs:71:5
71 --> tests/ui/min_max.rs:72:5
7172 |
7273LL | s.max("Zoo").min("Apple");
7374 | ^^^^^^^^^^^^^^^^^^^^^^^^^
7475
7576error: this `min`/`max` combination leads to constant result
76 --> tests/ui/min_max.rs:74:5
77 --> tests/ui/min_max.rs:75:5
7778 |
7879LL | s.min("Apple").max("Zoo");
7980 | ^^^^^^^^^^^^^^^^^^^^^^^^^
src/tools/clippy/tests/ui/min_rust_version_attr.rs-1
......@@ -1,4 +1,3 @@
1#![allow(clippy::redundant_clone)]
21#![feature(custom_inner_attributes)]
32
43fn main() {}
src/tools/clippy/tests/ui/min_rust_version_attr.stderr+6-6
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | let log2_10 = 3.321928094887362;
55 | ^^^^^^^^^^^^^^^^^
......@@ -8,7 +8,7 @@ LL | let log2_10 = 3.321928094887362;
88 = note: `#[deny(clippy::approx_constant)]` on by default
99
1010error: 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
1212 |
1313LL | let log2_10 = 3.321928094887362;
1414 | ^^^^^^^^^^^^^^^^^
......@@ -16,7 +16,7 @@ LL | let log2_10 = 3.321928094887362;
1616 = help: consider using the constant directly
1717
1818error: 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
2020 |
2121LL | let log2_10 = 3.321928094887362;
2222 | ^^^^^^^^^^^^^^^^^
......@@ -24,7 +24,7 @@ LL | let log2_10 = 3.321928094887362;
2424 = help: consider using the constant directly
2525
2626error: 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
2828 |
2929LL | let log2_10 = 3.321928094887362;
3030 | ^^^^^^^^^^^^^^^^^
......@@ -32,7 +32,7 @@ LL | let log2_10 = 3.321928094887362;
3232 = help: consider using the constant directly
3333
3434error: 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
3636 |
3737LL | let log2_10 = 3.321928094887362;
3838 | ^^^^^^^^^^^^^^^^^
......@@ -40,7 +40,7 @@ LL | let log2_10 = 3.321928094887362;
4040 = help: consider using the constant directly
4141
4242error: 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
4444 |
4545LL | let log2_10 = 3.321928094887362;
4646 | ^^^^^^^^^^^^^^^^^
src/tools/clippy/tests/ui/mismatching_type_param_order.rs-1
......@@ -1,5 +1,4 @@
11#![warn(clippy::mismatching_type_param_order)]
2#![allow(clippy::disallowed_names, clippy::needless_lifetimes)]
32
43fn main() {
54 struct Foo<A, B> {
src/tools/clippy/tests/ui/mismatching_type_param_order.stderr+10-10
......@@ -1,5 +1,5 @@
11error: `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
33 |
44LL | impl<B, A> Foo<B, A> {}
55 | ^
......@@ -9,7 +9,7 @@ LL | impl<B, A> Foo<B, A> {}
99 = help: to override `-D warnings` add `#[allow(clippy::mismatching_type_param_order)]`
1010
1111error: `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
1313 |
1414LL | impl<B, A> Foo<B, A> {}
1515 | ^
......@@ -17,7 +17,7 @@ LL | impl<B, A> Foo<B, A> {}
1717 = help: try `B`, or a name that does not conflict with `Foo`'s generic params
1818
1919error: `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
2121 |
2222LL | impl<C, A> Foo<C, A> {}
2323 | ^
......@@ -25,7 +25,7 @@ LL | impl<C, A> Foo<C, A> {}
2525 = help: try `B`, or a name that does not conflict with `Foo`'s generic params
2626
2727error: `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
2929 |
3030LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {}
3131 | ^
......@@ -33,7 +33,7 @@ LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {}
3333 = help: try `A`, or a name that does not conflict with `FooLifetime`'s generic params
3434
3535error: `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
3737 |
3838LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {}
3939 | ^
......@@ -41,7 +41,7 @@ LL | impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {}
4141 = help: try `B`, or a name that does not conflict with `FooLifetime`'s generic params
4242
4343error: `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
4545 |
4646LL | impl<C, A, B> FooEnum<C, A, B> {}
4747 | ^
......@@ -49,7 +49,7 @@ LL | impl<C, A, B> FooEnum<C, A, B> {}
4949 = help: try `A`, or a name that does not conflict with `FooEnum`'s generic params
5050
5151error: `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
5353 |
5454LL | impl<C, A, B> FooEnum<C, A, B> {}
5555 | ^
......@@ -57,7 +57,7 @@ LL | impl<C, A, B> FooEnum<C, A, B> {}
5757 = help: try `B`, or a name that does not conflict with `FooEnum`'s generic params
5858
5959error: `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
6161 |
6262LL | impl<C, A, B> FooEnum<C, A, B> {}
6363 | ^
......@@ -65,7 +65,7 @@ LL | impl<C, A, B> FooEnum<C, A, B> {}
6565 = help: try `C`, or a name that does not conflict with `FooEnum`'s generic params
6666
6767error: `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
6969 |
7070LL | impl<B: Copy, A> FooUnion<B, A> where A: Copy {}
7171 | ^
......@@ -73,7 +73,7 @@ LL | impl<B: Copy, A> FooUnion<B, A> where A: Copy {}
7373 = help: try `A`, or a name that does not conflict with `FooUnion`'s generic params
7474
7575error: `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
7777 |
7878LL | impl<B: Copy, A> FooUnion<B, A> where A: Copy {}
7979 | ^
src/tools/clippy/tests/ui/misnamed_getters.fixed+1-2
......@@ -1,6 +1,5 @@
1#![allow(unused)]
2#![allow(clippy::struct_field_names)]
31#![warn(clippy::misnamed_getters)]
2#![expect(clippy::struct_field_names)]
43
54struct A {
65 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)]
31#![warn(clippy::misnamed_getters)]
2#![expect(clippy::struct_field_names)]
43
54struct A {
65 a: u8,
src/tools/clippy/tests/ui/misnamed_getters.stderr+18-18
......@@ -1,5 +1,5 @@
11error: getter function appears to return the wrong field
2 --> tests/ui/misnamed_getters.rs:12:5
2 --> tests/ui/misnamed_getters.rs:11:5
33 |
44LL | / fn a(&self) -> &u8 {
55LL | |
......@@ -13,7 +13,7 @@ LL | | }
1313 = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]`
1414
1515error: getter function appears to return the wrong field
16 --> tests/ui/misnamed_getters.rs:17:5
16 --> tests/ui/misnamed_getters.rs:16:5
1717 |
1818LL | / fn a_mut(&mut self) -> &mut u8 {
1919LL | |
......@@ -24,7 +24,7 @@ LL | | }
2424 | |_____^
2525
2626error: getter function appears to return the wrong field
27 --> tests/ui/misnamed_getters.rs:23:5
27 --> tests/ui/misnamed_getters.rs:22:5
2828 |
2929LL | / fn b(self) -> u8 {
3030LL | |
......@@ -35,7 +35,7 @@ LL | | }
3535 | |_____^
3636
3737error: getter function appears to return the wrong field
38 --> tests/ui/misnamed_getters.rs:29:5
38 --> tests/ui/misnamed_getters.rs:28:5
3939 |
4040LL | / fn b_mut(&mut self) -> &mut u8 {
4141LL | |
......@@ -46,7 +46,7 @@ LL | | }
4646 | |_____^
4747
4848error: getter function appears to return the wrong field
49 --> tests/ui/misnamed_getters.rs:35:5
49 --> tests/ui/misnamed_getters.rs:34:5
5050 |
5151LL | / fn c(&self) -> &u8 {
5252LL | |
......@@ -57,7 +57,7 @@ LL | | }
5757 | |_____^
5858
5959error: getter function appears to return the wrong field
60 --> tests/ui/misnamed_getters.rs:41:5
60 --> tests/ui/misnamed_getters.rs:40:5
6161 |
6262LL | / fn c_mut(&mut self) -> &mut u8 {
6363LL | |
......@@ -68,7 +68,7 @@ LL | | }
6868 | |_____^
6969
7070error: getter function appears to return the wrong field
71 --> tests/ui/misnamed_getters.rs:54:5
71 --> tests/ui/misnamed_getters.rs:53:5
7272 |
7373LL | / unsafe fn a(&self) -> &u8 {
7474LL | |
......@@ -79,7 +79,7 @@ LL | | }
7979 | |_____^
8080
8181error: getter function appears to return the wrong field
82 --> tests/ui/misnamed_getters.rs:59:5
82 --> tests/ui/misnamed_getters.rs:58:5
8383 |
8484LL | / unsafe fn a_mut(&mut self) -> &mut u8 {
8585LL | |
......@@ -90,7 +90,7 @@ LL | | }
9090 | |_____^
9191
9292error: getter function appears to return the wrong field
93 --> tests/ui/misnamed_getters.rs:65:5
93 --> tests/ui/misnamed_getters.rs:64:5
9494 |
9595LL | / unsafe fn b(self) -> u8 {
9696LL | |
......@@ -101,7 +101,7 @@ LL | | }
101101 | |_____^
102102
103103error: getter function appears to return the wrong field
104 --> tests/ui/misnamed_getters.rs:71:5
104 --> tests/ui/misnamed_getters.rs:70:5
105105 |
106106LL | / unsafe fn b_mut(&mut self) -> &mut u8 {
107107LL | |
......@@ -112,7 +112,7 @@ LL | | }
112112 | |_____^
113113
114114error: getter function appears to return the wrong field
115 --> tests/ui/misnamed_getters.rs:85:5
115 --> tests/ui/misnamed_getters.rs:84:5
116116 |
117117LL | / unsafe fn a_unchecked(&self) -> &u8 {
118118LL | |
......@@ -123,7 +123,7 @@ LL | | }
123123 | |_____^
124124
125125error: getter function appears to return the wrong field
126 --> tests/ui/misnamed_getters.rs:90:5
126 --> tests/ui/misnamed_getters.rs:89:5
127127 |
128128LL | / unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
129129LL | |
......@@ -134,7 +134,7 @@ LL | | }
134134 | |_____^
135135
136136error: getter function appears to return the wrong field
137 --> tests/ui/misnamed_getters.rs:96:5
137 --> tests/ui/misnamed_getters.rs:95:5
138138 |
139139LL | / unsafe fn b_unchecked(self) -> u8 {
140140LL | |
......@@ -145,7 +145,7 @@ LL | | }
145145 | |_____^
146146
147147error: getter function appears to return the wrong field
148 --> tests/ui/misnamed_getters.rs:102:5
148 --> tests/ui/misnamed_getters.rs:101:5
149149 |
150150LL | / unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
151151LL | |
......@@ -156,7 +156,7 @@ LL | | }
156156 | |_____^
157157
158158error: getter function appears to return the wrong field
159 --> tests/ui/misnamed_getters.rs:136:5
159 --> tests/ui/misnamed_getters.rs:135:5
160160 |
161161LL | / fn a(&self) -> &u8 {
162162LL | |
......@@ -167,7 +167,7 @@ LL | | }
167167 | |_____^
168168
169169error: getter function appears to return the wrong field
170 --> tests/ui/misnamed_getters.rs:141:5
170 --> tests/ui/misnamed_getters.rs:140:5
171171 |
172172LL | / fn a_mut(&mut self) -> &mut u8 {
173173LL | |
......@@ -178,7 +178,7 @@ LL | | }
178178 | |_____^
179179
180180error: getter function appears to return the wrong field
181 --> tests/ui/misnamed_getters.rs:147:5
181 --> tests/ui/misnamed_getters.rs:146:5
182182 |
183183LL | / fn d(&self) -> &u8 {
184184LL | |
......@@ -189,7 +189,7 @@ LL | | }
189189 | |_____^
190190
191191error: getter function appears to return the wrong field
192 --> tests/ui/misnamed_getters.rs:152:5
192 --> tests/ui/misnamed_getters.rs:151:5
193193 |
194194LL | / fn d_mut(&mut self) -> &mut u8 {
195195LL | |
src/tools/clippy/tests/ui/misnamed_getters_2021.fixed-2
......@@ -1,6 +1,4 @@
11//@edition: 2021
2#![allow(unused)]
3#![allow(clippy::struct_field_names)]
42#![warn(clippy::misnamed_getters)]
53
64// Edition 2021 specific check, where `unsafe` blocks are not required
src/tools/clippy/tests/ui/misnamed_getters_2021.rs-2
......@@ -1,6 +1,4 @@
11//@edition: 2021
2#![allow(unused)]
3#![allow(clippy::struct_field_names)]
42#![warn(clippy::misnamed_getters)]
53
64// 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 @@
11error: 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
33 |
44LL | / unsafe fn a(&self) -> &u8 {
55LL | |
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)]
13#![allow(clippy::eq_op)]
2#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
34
45fn main() {
56 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)]
13#![allow(clippy::eq_op)]
2#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
34
45fn main() {
56 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)]
13#![allow(clippy::eq_op)]
2#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
34
45fn main() {
56 let mut a = 5;
src/tools/clippy/tests/ui/misrefactored_assign_op.stderr+9-9
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | a += a + 1;
55 | ^^^^^^^^^^
......@@ -18,7 +18,7 @@ LL + a = a + a + 1;
1818 |
1919
2020error: 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
2222 |
2323LL | a += 1 + a;
2424 | ^^^^^^^^^^
......@@ -35,7 +35,7 @@ LL + a = a + 1 + a;
3535 |
3636
3737error: 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
3939 |
4040LL | a -= a - 1;
4141 | ^^^^^^^^^^
......@@ -52,7 +52,7 @@ LL + a = a - (a - 1);
5252 |
5353
5454error: 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
5656 |
5757LL | a *= a * 99;
5858 | ^^^^^^^^^^^
......@@ -69,7 +69,7 @@ LL + a = a * a * 99;
6969 |
7070
7171error: 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
7373 |
7474LL | a *= 42 * a;
7575 | ^^^^^^^^^^^
......@@ -86,7 +86,7 @@ LL + a = a * 42 * a;
8686 |
8787
8888error: 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
9090 |
9191LL | a /= a / 2;
9292 | ^^^^^^^^^^
......@@ -103,7 +103,7 @@ LL + a = a / (a / 2);
103103 |
104104
105105error: 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
107107 |
108108LL | a %= a % 5;
109109 | ^^^^^^^^^^
......@@ -120,7 +120,7 @@ LL + a = a % (a % 5);
120120 |
121121
122122error: 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
124124 |
125125LL | a &= a & 1;
126126 | ^^^^^^^^^^
......@@ -137,7 +137,7 @@ LL + a = a & a & 1;
137137 |
138138
139139error: 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
141141 |
142142LL | a *= a * a;
143143 | ^^^^^^^^^^
src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs-1
......@@ -1,4 +1,3 @@
1#![allow(unused)]
21#![warn(clippy::missing_asserts_for_indexing)]
32
43fn sum(v: &[u8]) -> u8 {
src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr+10-10
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | v[0] + v[1] + v[2] + v[3] + v[4]
55 | ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
......@@ -10,7 +10,7 @@ LL | v[0] + v[1] + v[2] + v[3] + v[4]
1010 = help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]`
1111
1212error: 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
1414 |
1515LL | let _ = v[0];
1616 | ^^^^
......@@ -21,7 +21,7 @@ LL | let _ = v[1..4];
2121 = help: consider asserting the length before indexing: `assert!(v.len() > 3);`
2222
2323error: 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
2525 |
2626LL | let a = v[0];
2727 | ^^^^
......@@ -34,7 +34,7 @@ LL | let c = v[2];
3434 = help: consider asserting the length before indexing: `assert!(v.len() > 2);`
3535
3636error: 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
3838 |
3939LL | let _ = v1[0] + v1[12];
4040 | ^^^^^ ^^^^^^
......@@ -42,7 +42,7 @@ LL | let _ = v1[0] + v1[12];
4242 = help: consider asserting the length before indexing: `assert!(v1.len() > 12);`
4343
4444error: 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
4646 |
4747LL | let _ = v2[5] + v2[15];
4848 | ^^^^^ ^^^^^^
......@@ -50,7 +50,7 @@ LL | let _ = v2[5] + v2[15];
5050 = help: consider asserting the length before indexing: `assert!(v2.len() > 15);`
5151
5252error: 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
5454 |
5555LL | let _ = v2[5] + v2[15];
5656 | ^^^^^ ^^^^^^
......@@ -58,7 +58,7 @@ LL | let _ = v2[5] + v2[15];
5858 = help: consider asserting the length before indexing: `assert!(v2.len() > 15);`
5959
6060error: 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
6262 |
6363LL | let _ = f.v[0] + f.v[1];
6464 | ^^^^^^ ^^^^^^
......@@ -66,7 +66,7 @@ LL | let _ = f.v[0] + f.v[1];
6666 = help: consider asserting the length before indexing: `assert!(f.v.len() > 1);`
6767
6868error: 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
7070 |
7171LL | let _ = x[0] + x[1];
7272 | ^^^^ ^^^^
......@@ -74,7 +74,7 @@ LL | let _ = x[0] + x[1];
7474 = help: consider asserting the length before indexing: `assert!(x.len() > 1);`
7575
7676error: 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
7878 |
7979LL | let _ = v1[1] + v1[2];
8080 | ^^^^^ ^^^^^
......@@ -82,7 +82,7 @@ LL | let _ = v1[1] + v1[2];
8282 = help: consider asserting the length before indexing: `assert!(v1.len() > 2);`
8383
8484error: 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
8686 |
8787LL | let _ = v1[0] + v1[1] + v1[2];
8888 | ^^^^^ ^^^^^ ^^^^^
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed+1-1
......@@ -1,5 +1,5 @@
11#![warn(clippy::missing_const_for_fn)]
2#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
2#![expect(clippy::let_and_return)]
33#![feature(const_trait_impl)]
44
55use std::mem::transmute;
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs+1-1
......@@ -1,5 +1,5 @@
11#![warn(clippy::missing_const_for_fn)]
2#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
2#![expect(clippy::let_and_return)]
33#![feature(const_trait_impl)]
44
55use std::mem::transmute;
src/tools/clippy/tests/ui/missing_fields_in_debug.rs-1
......@@ -1,4 +1,3 @@
1#![allow(unused)]
21#![warn(clippy::missing_fields_in_debug)]
32
43use std::fmt;
src/tools/clippy/tests/ui/missing_fields_in_debug.stderr+8-8
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | / impl fmt::Debug for NamedStruct1Ignored {
55... |
......@@ -7,7 +7,7 @@ LL | | }
77 | |_^
88 |
99note: this field is unused
10 --> tests/ui/missing_fields_in_debug.rs:11:5
10 --> tests/ui/missing_fields_in_debug.rs:10:5
1111 |
1212LL | hidden: u32,
1313 | ^^^^^^^^^^^
......@@ -17,7 +17,7 @@ LL | hidden: u32,
1717 = help: to override `-D warnings` add `#[allow(clippy::missing_fields_in_debug)]`
1818
1919error: 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
2121 |
2222LL | / impl fmt::Debug for NamedStructMultipleIgnored {
2323... |
......@@ -25,17 +25,17 @@ LL | | }
2525 | |_^
2626 |
2727note: this field is unused
28 --> tests/ui/missing_fields_in_debug.rs:28:5
28 --> tests/ui/missing_fields_in_debug.rs:27:5
2929 |
3030LL | hidden: u32,
3131 | ^^^^^^^^^^^
3232note: this field is unused
33 --> tests/ui/missing_fields_in_debug.rs:29:5
33 --> tests/ui/missing_fields_in_debug.rs:28:5
3434 |
3535LL | hidden2: String,
3636 | ^^^^^^^^^^^^^^^
3737note: this field is unused
38 --> tests/ui/missing_fields_in_debug.rs:31:5
38 --> tests/ui/missing_fields_in_debug.rs:30:5
3939 |
4040LL | hidden4: ((((u8), u16), u32), u64),
4141 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -43,7 +43,7 @@ LL | hidden4: ((((u8), u16), u32), u64),
4343 = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields
4444
4545error: 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
4747 |
4848LL | / impl fmt::Debug for MultiExprDebugImpl {
4949LL | |
......@@ -54,7 +54,7 @@ LL | | }
5454 | |_^
5555 |
5656note: this field is unused
57 --> tests/ui/missing_fields_in_debug.rs:93:5
57 --> tests/ui/missing_fields_in_debug.rs:92:5
5858 |
5959LL | b: String,
6060 | ^^^^^^^^^
src/tools/clippy/tests/ui/missing_inline.rs+1-1
......@@ -2,7 +2,7 @@
22#![crate_type = "dylib"]
33// When denying at the crate level, be sure to not get random warnings from the
44// injected intrinsics by the compiler.
5#![allow(dead_code, non_snake_case)]
5#![expect(non_snake_case)]
66
77type Typedef = String;
88pub type PubTypedef = String;
src/tools/clippy/tests/ui/missing_inline.stderr+6-6
......@@ -1,4 +1,4 @@
1error: missing `#[inline]` for a function
1error: missing `#[inline]` on a publicly callable function
22 --> tests/ui/missing_inline.rs:20:1
33 |
44LL | pub fn pub_foo() {}
......@@ -7,31 +7,31 @@ LL | pub fn pub_foo() {}
77 = note: `-D clippy::missing-inline-in-public-items` implied by `-D warnings`
88 = help: to override `-D warnings` add `#[allow(clippy::missing_inline_in_public_items)]`
99
10error: missing `#[inline]` for a default trait method
10error: missing `#[inline]` on a publicly callable function
1111 --> tests/ui/missing_inline.rs:39:5
1212 |
1313LL | fn PubBar_b() {}
1414 | ^^^^^^^^^^^^^^^^
1515
16error: missing `#[inline]` for a method
16error: missing `#[inline]` on a publicly callable function
1717 --> tests/ui/missing_inline.rs:56:5
1818 |
1919LL | fn PubBar_a() {}
2020 | ^^^^^^^^^^^^^^^^
2121
22error: missing `#[inline]` for a method
22error: missing `#[inline]` on a publicly callable function
2323 --> tests/ui/missing_inline.rs:60:5
2424 |
2525LL | fn PubBar_b() {}
2626 | ^^^^^^^^^^^^^^^^
2727
28error: missing `#[inline]` for a method
28error: missing `#[inline]` on a publicly callable function
2929 --> tests/ui/missing_inline.rs:64:5
3030 |
3131LL | fn PubBar_c() {}
3232 | ^^^^^^^^^^^^^^^^
3333
34error: missing `#[inline]` for a method
34error: missing `#[inline]` on a publicly callable function
3535 --> tests/ui/missing_inline.rs:76:5
3636 |
3737LL | pub fn PubFooImpl() {}
src/tools/clippy/tests/ui/missing_inline_executable.stderr+1-1
......@@ -1,4 +1,4 @@
1error: missing `#[inline]` for a function
1error: missing `#[inline]` on a publicly callable function
22 --> tests/ui/missing_inline_executable.rs:3:1
33 |
44LL | pub fn foo() {}
src/tools/clippy/tests/ui/missing_panics_doc.rs+1-1
......@@ -1,6 +1,6 @@
11//@aux-build:macro_rules.rs
22#![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)]
44
55#[macro_use]
66extern crate macro_rules;
src/tools/clippy/tests/ui/missing_spin_loop.fixed+1-2
......@@ -1,6 +1,5 @@
11#![warn(clippy::missing_spin_loop)]
2#![allow(clippy::bool_comparison)]
3#![allow(unused_braces)]
2#![expect(clippy::bool_comparison)]
43
54use core::sync::atomic::{AtomicBool, Ordering};
65
src/tools/clippy/tests/ui/missing_spin_loop.rs+1-2
......@@ -1,6 +1,5 @@
11#![warn(clippy::missing_spin_loop)]
2#![allow(clippy::bool_comparison)]
3#![allow(unused_braces)]
2#![expect(clippy::bool_comparison)]
43
54use core::sync::atomic::{AtomicBool, Ordering};
65
src/tools/clippy/tests/ui/missing_spin_loop.stderr+6-6
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | while b.load(Ordering::Acquire) {}
55 | ^^ help: try: `{ std::hint::spin_loop() }`
......@@ -8,31 +8,31 @@ LL | while b.load(Ordering::Acquire) {}
88 = help: to override `-D warnings` add `#[allow(clippy::missing_spin_loop)]`
99
1010error: 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
1212 |
1313LL | while !b.load(Ordering::SeqCst) {}
1414 | ^^ help: try: `{ std::hint::spin_loop() }`
1515
1616error: 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
1818 |
1919LL | while b.load(Ordering::Acquire) == false {}
2020 | ^^ help: try: `{ std::hint::spin_loop() }`
2121
2222error: 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
2424 |
2525LL | while { true == b.load(Ordering::Acquire) } {}
2626 | ^^ help: try: `{ std::hint::spin_loop() }`
2727
2828error: 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
3030 |
3131LL | while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) {}
3232 | ^^ help: try: `{ std::hint::spin_loop() }`
3333
3434error: 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
3636 |
3737LL | while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {}
3838 | ^^ 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)]
21#![warn(clippy::missing_trait_methods)]
2#![expect(clippy::needless_lifetimes)]
33
44trait A {
55 fn provided() {}
src/tools/clippy/tests/ui/missing_transmute_annotations.fixed+1-1
......@@ -1,7 +1,7 @@
11//@aux-build:macro_rules.rs
22
33#![warn(clippy::missing_transmute_annotations)]
4#![allow(clippy::let_with_type_underscore)]
4#![expect(clippy::let_with_type_underscore)]
55
66#[macro_use]
77extern crate macro_rules;
src/tools/clippy/tests/ui/missing_transmute_annotations.rs+1-1
......@@ -1,7 +1,7 @@
11//@aux-build:macro_rules.rs
22
33#![warn(clippy::missing_transmute_annotations)]
4#![allow(clippy::let_with_type_underscore)]
4#![expect(clippy::let_with_type_underscore)]
55
66#[macro_use]
77extern crate macro_rules;
src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed+2-4
......@@ -1,10 +1,8 @@
11//@aux-build: proc_macros.rs
22
3#![allow(
4 dead_code,
5 unused_variables,
3#![warn(clippy::mistyped_literal_suffixes)]
4#![expect(
65 overflowing_literals,
7 clippy::excessive_precision,
86 clippy::inconsistent_digit_grouping,
97 clippy::unusual_byte_groupings
108)]
src/tools/clippy/tests/ui/mistyped_literal_suffix.rs+2-4
......@@ -1,10 +1,8 @@
11//@aux-build: proc_macros.rs
22
3#![allow(
4 dead_code,
5 unused_variables,
3#![warn(clippy::mistyped_literal_suffixes)]
4#![expect(
65 overflowing_literals,
7 clippy::excessive_precision,
86 clippy::inconsistent_digit_grouping,
97 clippy::unusual_byte_groupings
108)]
src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr+18-17
......@@ -1,97 +1,98 @@
11error: mistyped literal suffix
2 --> tests/ui/mistyped_literal_suffix.rs:16:18
2 --> tests/ui/mistyped_literal_suffix.rs:14:18
33 |
44LL | let fail14 = 2_32;
55 | ^^^^ help: did you mean to write: `2_i32`
66 |
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)]`
89
910error: mistyped literal suffix
10 --> tests/ui/mistyped_literal_suffix.rs:18:18
11 --> tests/ui/mistyped_literal_suffix.rs:16:18
1112 |
1213LL | let fail15 = 4_64;
1314 | ^^^^ help: did you mean to write: `4_i64`
1415
1516error: mistyped literal suffix
16 --> tests/ui/mistyped_literal_suffix.rs:20:18
17 --> tests/ui/mistyped_literal_suffix.rs:18:18
1718 |
1819LL | let fail16 = 7_8; //
1920 | ^^^ help: did you mean to write: `7_i8`
2021
2122error: mistyped literal suffix
22 --> tests/ui/mistyped_literal_suffix.rs:23:18
23 --> tests/ui/mistyped_literal_suffix.rs:21:18
2324 |
2425LL | let fail17 = 23_16; //
2526 | ^^^^^ help: did you mean to write: `23_i16`
2627
2728error: mistyped literal suffix
28 --> tests/ui/mistyped_literal_suffix.rs:28:18
29 --> tests/ui/mistyped_literal_suffix.rs:26:18
2930 |
3031LL | let fail20 = 2__8; //
3132 | ^^^^ help: did you mean to write: `2_i8`
3233
3334error: mistyped literal suffix
34 --> tests/ui/mistyped_literal_suffix.rs:31:18
35 --> tests/ui/mistyped_literal_suffix.rs:29:18
3536 |
3637LL | let fail21 = 4___16; //
3738 | ^^^^^^ help: did you mean to write: `4_i16`
3839
3940error: mistyped literal suffix
40 --> tests/ui/mistyped_literal_suffix.rs:36:18
41 --> tests/ui/mistyped_literal_suffix.rs:34:18
4142 |
4243LL | let fail25 = 1E2_32;
4344 | ^^^^^^ help: did you mean to write: `1E2_f32`
4445
4546error: mistyped literal suffix
46 --> tests/ui/mistyped_literal_suffix.rs:38:18
47 --> tests/ui/mistyped_literal_suffix.rs:36:18
4748 |
4849LL | let fail26 = 43E7_64;
4950 | ^^^^^^^ help: did you mean to write: `43E7_f64`
5051
5152error: mistyped literal suffix
52 --> tests/ui/mistyped_literal_suffix.rs:40:18
53 --> tests/ui/mistyped_literal_suffix.rs:38:18
5354 |
5455LL | let fail27 = 243E17_32;
5556 | ^^^^^^^^^ help: did you mean to write: `243E17_f32`
5657
5758error: mistyped literal suffix
58 --> tests/ui/mistyped_literal_suffix.rs:42:18
59 --> tests/ui/mistyped_literal_suffix.rs:40:18
5960 |
6061LL | let fail28 = 241251235E723_64;
6162 | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
6263
6364error: mistyped literal suffix
64 --> tests/ui/mistyped_literal_suffix.rs:47:18
65 --> tests/ui/mistyped_literal_suffix.rs:45:18
6566 |
6667LL | let fail30 = 127_8; // should be i8
6768 | ^^^^^ help: did you mean to write: `127_i8`
6869
6970error: mistyped literal suffix
70 --> tests/ui/mistyped_literal_suffix.rs:50:18
71 --> tests/ui/mistyped_literal_suffix.rs:48:18
7172 |
7273LL | let fail31 = 240_8; // should be u8
7374 | ^^^^^ help: did you mean to write: `240_u8`
7475
7576error: mistyped literal suffix
76 --> tests/ui/mistyped_literal_suffix.rs:54:18
77 --> tests/ui/mistyped_literal_suffix.rs:52:18
7778 |
7879LL | let fail33 = 0x1234_16;
7980 | ^^^^^^^^^ help: did you mean to write: `0x1234_i16`
8081
8182error: mistyped literal suffix
82 --> tests/ui/mistyped_literal_suffix.rs:56:18
83 --> tests/ui/mistyped_literal_suffix.rs:54:18
8384 |
8485LL | let fail34 = 0xABCD_16;
8586 | ^^^^^^^^^ help: did you mean to write: `0xABCD_u16`
8687
8788error: mistyped literal suffix
88 --> tests/ui/mistyped_literal_suffix.rs:59:18
89 --> tests/ui/mistyped_literal_suffix.rs:57:18
8990 |
9091LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64
9192 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64`
9293
9394error: mistyped literal suffix
94 --> tests/ui/mistyped_literal_suffix.rs:67:13
95 --> tests/ui/mistyped_literal_suffix.rs:65:13
9596 |
9697LL | let _ = 1.12345E1_32;
9798 | ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
src/tools/clippy/tests/ui/module_name_repetitions.rs-1
......@@ -1,7 +1,6 @@
11//@compile-flags: --test
22
33#![warn(clippy::module_name_repetitions)]
4#![allow(dead_code)]
54
65pub mod foo {
76 pub fn foo() {}
src/tools/clippy/tests/ui/module_name_repetitions.stderr+6-6
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | pub fn foo_bar() {}
55 | ^^^^^^^
......@@ -8,31 +8,31 @@ LL | pub fn foo_bar() {}
88 = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]`
99
1010error: 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
1212 |
1313LL | pub fn bar_foo() {}
1414 | ^^^^^^^
1515
1616error: 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
1818 |
1919LL | pub struct FooCake;
2020 | ^^^^^^^
2121
2222error: 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
2424 |
2525LL | pub enum CakeFoo {}
2626 | ^^^^^^^
2727
2828error: 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
3030 |
3131LL | pub struct Foo7Bar;
3232 | ^^^^^^^
3333
3434error: 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
3636 |
3737LL | pub use error::FooError;
3838 | ^^^^^^^^
src/tools/clippy/tests/ui/modulo_arithmetic_float.rs+1-1
......@@ -1,7 +1,7 @@
11#![feature(f128)]
22#![feature(f16)]
33#![warn(clippy::modulo_arithmetic)]
4#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)]
4#![expect(clippy::no_effect)]
55
66fn main() {
77 // 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 @@
11#![warn(clippy::modulo_arithmetic)]
2#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)]
2#![expect(clippy::no_effect)]
33
44fn main() {
55 // Lint on signed integral numbers
src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs+1-6
......@@ -1,10 +1,5 @@
11#![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)]
83
94fn main() {
105 // 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 @@
11error: 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
33 |
44LL | -1 % 2;
55 | ^^^^^^
......@@ -10,7 +10,7 @@ LL | -1 % 2;
1010 = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]`
1111
1212error: 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
1414 |
1515LL | 1 % -2;
1616 | ^^^^^^
......@@ -19,7 +19,7 @@ LL | 1 % -2;
1919 = note: or consider using `rem_euclid` or similar function
2020
2121error: 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
2323 |
2424LL | (1 - 2) % (1 + 2);
2525 | ^^^^^^^^^^^^^^^^^
......@@ -28,7 +28,7 @@ LL | (1 - 2) % (1 + 2);
2828 = note: or consider using `rem_euclid` or similar function
2929
3030error: 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
3232 |
3333LL | (1 + 2) % (1 - 2);
3434 | ^^^^^^^^^^^^^^^^^
......@@ -37,7 +37,7 @@ LL | (1 + 2) % (1 - 2);
3737 = note: or consider using `rem_euclid` or similar function
3838
3939error: 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
4141 |
4242LL | 35 * (7 - 4 * 2) % (-500 * -600);
4343 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -46,7 +46,7 @@ LL | 35 * (7 - 4 * 2) % (-500 * -600);
4646 = note: or consider using `rem_euclid` or similar function
4747
4848error: 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
5050 |
5151LL | -1i8 % 2i8;
5252 | ^^^^^^^^^^
......@@ -55,7 +55,7 @@ LL | -1i8 % 2i8;
5555 = note: or consider using `rem_euclid` or similar function
5656
5757error: 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
5959 |
6060LL | 1i8 % -2i8;
6161 | ^^^^^^^^^^
......@@ -64,7 +64,7 @@ LL | 1i8 % -2i8;
6464 = note: or consider using `rem_euclid` or similar function
6565
6666error: 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
6868 |
6969LL | -1i16 % 2i16;
7070 | ^^^^^^^^^^^^
......@@ -73,7 +73,7 @@ LL | -1i16 % 2i16;
7373 = note: or consider using `rem_euclid` or similar function
7474
7575error: 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
7777 |
7878LL | 1i16 % -2i16;
7979 | ^^^^^^^^^^^^
......@@ -82,7 +82,7 @@ LL | 1i16 % -2i16;
8282 = note: or consider using `rem_euclid` or similar function
8383
8484error: 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
8686 |
8787LL | -1i32 % 2i32;
8888 | ^^^^^^^^^^^^
......@@ -91,7 +91,7 @@ LL | -1i32 % 2i32;
9191 = note: or consider using `rem_euclid` or similar function
9292
9393error: 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
9595 |
9696LL | 1i32 % -2i32;
9797 | ^^^^^^^^^^^^
......@@ -100,7 +100,7 @@ LL | 1i32 % -2i32;
100100 = note: or consider using `rem_euclid` or similar function
101101
102102error: 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
104104 |
105105LL | -1i64 % 2i64;
106106 | ^^^^^^^^^^^^
......@@ -109,7 +109,7 @@ LL | -1i64 % 2i64;
109109 = note: or consider using `rem_euclid` or similar function
110110
111111error: 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
113113 |
114114LL | 1i64 % -2i64;
115115 | ^^^^^^^^^^^^
......@@ -118,7 +118,7 @@ LL | 1i64 % -2i64;
118118 = note: or consider using `rem_euclid` or similar function
119119
120120error: 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
122122 |
123123LL | -1i128 % 2i128;
124124 | ^^^^^^^^^^^^^^
......@@ -127,7 +127,7 @@ LL | -1i128 % 2i128;
127127 = note: or consider using `rem_euclid` or similar function
128128
129129error: 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
131131 |
132132LL | 1i128 % -2i128;
133133 | ^^^^^^^^^^^^^^
......@@ -136,7 +136,7 @@ LL | 1i128 % -2i128;
136136 = note: or consider using `rem_euclid` or similar function
137137
138138error: 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
140140 |
141141LL | -1isize % 2isize;
142142 | ^^^^^^^^^^^^^^^^
......@@ -145,7 +145,7 @@ LL | -1isize % 2isize;
145145 = note: or consider using `rem_euclid` or similar function
146146
147147error: 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
149149 |
150150LL | 1isize % -2isize;
151151 | ^^^^^^^^^^^^^^^^
src/tools/clippy/tests/ui/modulo_one.rs+1-2
......@@ -1,6 +1,5 @@
11#![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)]
43
54static STATIC_ONE: usize = 2 - 1;
65static STATIC_NEG_ONE: i64 = 1 - 2;
src/tools/clippy/tests/ui/modulo_one.stderr+6-6
......@@ -1,5 +1,5 @@
11error: any number modulo 1 will be 0
2 --> tests/ui/modulo_one.rs:9:5
2 --> tests/ui/modulo_one.rs:8:5
33 |
44LL | 10 % 1;
55 | ^^^^^^
......@@ -8,31 +8,31 @@ LL | 10 % 1;
88 = help: to override `-D warnings` add `#[allow(clippy::modulo_one)]`
99
1010error: 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
1212 |
1313LL | 10 % -1;
1414 | ^^^^^^^
1515
1616error: 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
1818 |
1919LL | i32::MIN % (-1);
2020 | ^^^^^^^^^^^^^^^
2121
2222error: any number modulo 1 will be 0
23 --> tests/ui/modulo_one.rs:24:5
23 --> tests/ui/modulo_one.rs:23:5
2424 |
2525LL | 2 % ONE;
2626 | ^^^^^^^
2727
2828error: 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
3030 |
3131LL | 2 % NEG_ONE;
3232 | ^^^^^^^^^^^
3333
3434error: 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
3636 |
3737LL | INT_MIN % NEG_ONE;
3838 | ^^^^^^^^^^^^^^^^^
src/tools/clippy/tests/ui/msrv_attributes_without_early_lints.rs-1
......@@ -1,6 +1,5 @@
11//@check-pass
22
3#![allow(clippy::all, clippy::pedantic, clippy::restriction, clippy::nursery)]
43#![forbid(clippy::ptr_as_ptr)]
54
65/// 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 @@
11//@needs-asm-support
22//@aux-build:proc_macros.rs
3#![warn(clippy::multiple_unsafe_ops_per_block)]
34#![expect(
45 dropping_copy_types,
5 clippy::unnecessary_operation,
6 clippy::unnecessary_literal_unwrap
6 clippy::unnecessary_literal_unwrap,
7 clippy::unnecessary_operation
78)]
8#![warn(clippy::multiple_unsafe_ops_per_block)]
99
1010extern crate proc_macros;
1111use proc_macros::external;
src/tools/clippy/tests/ui/must_use_candidates.fixed-6
......@@ -1,10 +1,4 @@
11#![feature(never_type)]
2#![allow(
3 unused_mut,
4 clippy::redundant_allocation,
5 clippy::needless_pass_by_ref_mut,
6 static_mut_refs
7)]
82#![warn(clippy::must_use_candidate)]
93use std::rc::Rc;
104use std::sync::Arc;
src/tools/clippy/tests/ui/must_use_candidates.rs-6
......@@ -1,10 +1,4 @@
11#![feature(never_type)]
2#![allow(
3 unused_mut,
4 clippy::redundant_allocation,
5 clippy::needless_pass_by_ref_mut,
6 static_mut_refs
7)]
82#![warn(clippy::must_use_candidate)]
93use std::rc::Rc;
104use std::sync::Arc;
src/tools/clippy/tests/ui/must_use_candidates.stderr+7-7
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | pub fn pure(i: u8) -> u8 {
55 | ^^^^
......@@ -13,7 +13,7 @@ LL | pub fn pure(i: u8) -> u8 {
1313 |
1414
1515error: 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
1717 |
1818LL | pub fn inherent_pure(&self) -> u8 {
1919 | ^^^^^^^^^^^^^
......@@ -25,7 +25,7 @@ LL ~ pub fn inherent_pure(&self) -> u8 {
2525 |
2626
2727error: 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
2929 |
3030LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
3131 | ^^^^^^^^^^^
......@@ -37,7 +37,7 @@ LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
3737 |
3838
3939error: 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
4141 |
4242LL | pub fn rcd(_x: Rc<u32>) -> bool {
4343 | ^^^
......@@ -49,7 +49,7 @@ LL | pub fn rcd(_x: Rc<u32>) -> bool {
4949 |
5050
5151error: 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
5353 |
5454LL | pub fn arcd(_x: Arc<u32>) -> bool {
5555 | ^^^^
......@@ -61,7 +61,7 @@ LL | pub fn arcd(_x: Arc<u32>) -> bool {
6161 |
6262
6363error: 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
6565 |
6666LL | pub fn result_uninhabited() -> Result<i32, std::convert::Infallible> {
6767 | ^^^^^^^^^^^^^^^^^^
......@@ -74,7 +74,7 @@ LL | pub fn result_uninhabited() -> Result<i32, std::convert::Infallible> {
7474 |
7575
7676error: 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
7878 |
7979LL | pub fn controlflow_uninhabited() -> std::ops::ControlFlow<std::convert::Infallible, i32> {
8080 | ^^^^^^^^^^^^^^^^^^^^^^^
src/tools/clippy/tests/ui/must_use_unit.fixed+1-1
......@@ -1,7 +1,7 @@
11//@aux-build:proc_macros.rs
22
33#![warn(clippy::must_use_unit)]
4#![allow(clippy::unused_unit)]
4#![expect(clippy::unused_unit)]
55
66extern crate proc_macros;
77use proc_macros::external;
src/tools/clippy/tests/ui/must_use_unit.rs+1-1
......@@ -1,7 +1,7 @@
11//@aux-build:proc_macros.rs
22
33#![warn(clippy::must_use_unit)]
4#![allow(clippy::unused_unit)]
4#![expect(clippy::unused_unit)]
55
66extern crate proc_macros;
77use 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,
34 clippy::needless_lifetimes,
45 clippy::needless_pass_by_ref_mut,
5 clippy::redundant_allocation,
6 clippy::boxed_local
6 clippy::redundant_allocation
77)]
8#![warn(clippy::mut_from_ref)]
98
109struct Foo;
1110
src/tools/clippy/tests/ui/mut_from_ref.stderr+16-16
......@@ -1,11 +1,11 @@
11error: mutable borrow from immutable input(s)
2 --> tests/ui/mut_from_ref.rs:13:39
2 --> tests/ui/mut_from_ref.rs:12:39
33 |
44LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo {
55 | ^^^^^^^^
66 |
77note: immutable borrow here
8 --> tests/ui/mut_from_ref.rs:13:29
8 --> tests/ui/mut_from_ref.rs:12:29
99 |
1010LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo {
1111 | ^^^^^
......@@ -13,85 +13,85 @@ LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo {
1313 = help: to override `-D warnings` add `#[allow(clippy::mut_from_ref)]`
1414
1515error: mutable borrow from immutable input(s)
16 --> tests/ui/mut_from_ref.rs:21:25
16 --> tests/ui/mut_from_ref.rs:20:25
1717 |
1818LL | fn ouch(x: &Foo) -> &mut Foo;
1919 | ^^^^^^^^
2020 |
2121note: immutable borrow here
22 --> tests/ui/mut_from_ref.rs:21:16
22 --> tests/ui/mut_from_ref.rs:20:16
2323 |
2424LL | fn ouch(x: &Foo) -> &mut Foo;
2525 | ^^^^
2626
2727error: mutable borrow from immutable input(s)
28 --> tests/ui/mut_from_ref.rs:31:21
28 --> tests/ui/mut_from_ref.rs:30:21
2929 |
3030LL | fn fail(x: &u32) -> &mut u16 {
3131 | ^^^^^^^^
3232 |
3333note: immutable borrow here
34 --> tests/ui/mut_from_ref.rs:31:12
34 --> tests/ui/mut_from_ref.rs:30:12
3535 |
3636LL | fn fail(x: &u32) -> &mut u16 {
3737 | ^^^^
3838
3939error: mutable borrow from immutable input(s)
40 --> tests/ui/mut_from_ref.rs:37:50
40 --> tests/ui/mut_from_ref.rs:36:50
4141 |
4242LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
4343 | ^^^^^^^^^^^
4444 |
4545note: immutable borrow here
46 --> tests/ui/mut_from_ref.rs:37:25
46 --> tests/ui/mut_from_ref.rs:36:25
4747 |
4848LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
4949 | ^^^^^^^
5050
5151error: mutable borrow from immutable input(s)
52 --> tests/ui/mut_from_ref.rs:43:67
52 --> tests/ui/mut_from_ref.rs:42:67
5353 |
5454LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
5555 | ^^^^^^^^^^^
5656 |
5757note: immutable borrow here
58 --> tests/ui/mut_from_ref.rs:43:27
58 --> tests/ui/mut_from_ref.rs:42:27
5959 |
6060LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
6161 | ^^^^^^^ ^^^^^^^
6262
6363error: mutable borrow from immutable input(s)
64 --> tests/ui/mut_from_ref.rs:49:46
64 --> tests/ui/mut_from_ref.rs:48:46
6565 |
6666LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 {
6767 | ^^^^^^^^^^^
6868 |
6969note: immutable borrow here
70 --> tests/ui/mut_from_ref.rs:49:24
70 --> tests/ui/mut_from_ref.rs:48:24
7171 |
7272LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 {
7373 | ^^^^^^^ ^^^^^^^
7474
7575error: mutable borrow from immutable input(s)
76 --> tests/ui/mut_from_ref.rs:55:37
76 --> tests/ui/mut_from_ref.rs:54:37
7777 |
7878LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 {
7979 | ^^^^^^^^^^^
8080 |
8181note: immutable borrow here
82 --> tests/ui/mut_from_ref.rs:55:24
82 --> tests/ui/mut_from_ref.rs:54:24
8383 |
8484LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 {
8585 | ^^^^^^^
8686
8787error: mutable borrow from immutable input(s)
88 --> tests/ui/mut_from_ref.rs:85:35
88 --> tests/ui/mut_from_ref.rs:84:35
8989 |
9090LL | unsafe fn also_broken(x: &u32) -> &mut u32 {
9191 | ^^^^^^^^
9292 |
9393note: immutable borrow here
94 --> tests/ui/mut_from_ref.rs:85:26
94 --> tests/ui/mut_from_ref.rs:84:26
9595 |
9696LL | unsafe fn also_broken(x: &u32) -> &mut u32 {
9797 | ^^^^
src/tools/clippy/tests/ui/mut_mut.fixed-8
......@@ -1,13 +1,6 @@
11//@aux-build:proc_macros.rs
22
33#![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)]
114
125extern crate proc_macros;
136use proc_macros::{external, inline_macros};
......@@ -26,7 +19,6 @@ macro_rules! mut_ptr {
2619 };
2720}
2821
29#[allow(unused_mut, unused_variables)]
3022#[inline_macros]
3123fn main() {
3224 let mut x = &mut 1u32;
src/tools/clippy/tests/ui/mut_mut.rs-8
......@@ -1,13 +1,6 @@
11//@aux-build:proc_macros.rs
22
33#![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)]
114
125extern crate proc_macros;
136use proc_macros::{external, inline_macros};
......@@ -26,7 +19,6 @@ macro_rules! mut_ptr {
2619 };
2720}
2821
29#[allow(unused_mut, unused_variables)]
3022#[inline_macros]
3123fn main() {
3224 let mut x = &mut &mut 1u32;
src/tools/clippy/tests/ui/mut_mut.stderr+7-7
......@@ -1,5 +1,5 @@
11error: a type of form `&mut &mut _`
2 --> tests/ui/mut_mut.rs:15:11
2 --> tests/ui/mut_mut.rs:8:11
33 |
44LL | fn fun(x: &mut &mut u32) {
55 | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32`
......@@ -8,37 +8,37 @@ LL | fn fun(x: &mut &mut u32) {
88 = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]`
99
1010error: an expression of form `&mut &mut _`
11 --> tests/ui/mut_mut.rs:32:17
11 --> tests/ui/mut_mut.rs:24:17
1212 |
1313LL | let mut x = &mut &mut 1u32;
1414 | ^^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 1u32`
1515
1616error: this expression mutably borrows a mutable reference
17 --> tests/ui/mut_mut.rs:35:21
17 --> tests/ui/mut_mut.rs:27:21
1818 |
1919LL | let mut y = &mut x;
2020 | ^^^^^^ help: reborrow instead: `&mut *x`
2121
2222error: an expression of form `&mut &mut _`
23 --> tests/ui/mut_mut.rs:40:32
23 --> tests/ui/mut_mut.rs:32:32
2424 |
2525LL | let y: &mut &mut u32 = &mut &mut 2;
2626 | ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 2`
2727
2828error: a type of form `&mut &mut _`
29 --> tests/ui/mut_mut.rs:40:16
29 --> tests/ui/mut_mut.rs:32:16
3030 |
3131LL | let y: &mut &mut u32 = &mut &mut 2;
3232 | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32`
3333
3434error: an expression of form `&mut &mut _`
35 --> tests/ui/mut_mut.rs:46:37
35 --> tests/ui/mut_mut.rs:38:37
3636 |
3737LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
3838 | ^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut 2`
3939
4040error: a type of form `&mut &mut _`
41 --> tests/ui/mut_mut.rs:46:16
41 --> tests/ui/mut_mut.rs:38:16
4242 |
4343LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
4444 | ^^^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut u32`
src/tools/clippy/tests/ui/mut_mut_unfixable.rs-1
......@@ -1,7 +1,6 @@
11//@no-rustfix
22
33#![warn(clippy::mut_mut)]
4#![allow(unused)]
54#![expect(clippy::no_effect)]
65
76//! removing the extra `&mut`s will break the derefs
src/tools/clippy/tests/ui/mut_mut_unfixable.stderr+6-6
......@@ -1,5 +1,5 @@
11error: a type of form `&mut &mut _`
2 --> tests/ui/mut_mut_unfixable.rs:9:11
2 --> tests/ui/mut_mut_unfixable.rs:8:11
33 |
44LL | fn fun(x: &mut &mut u32) -> bool {
55 | ^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut u32`
......@@ -8,31 +8,31 @@ LL | fn fun(x: &mut &mut u32) -> bool {
88 = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]`
99
1010error: an expression of form `&mut &mut _`
11 --> tests/ui/mut_mut_unfixable.rs:15:17
11 --> tests/ui/mut_mut_unfixable.rs:14:17
1212 |
1313LL | let mut x = &mut &mut 1u32;
1414 | ^^^^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 1u32`
1515
1616error: 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
1818 |
1919LL | let mut y = &mut x;
2020 | ^^^^^^ help: reborrow instead: `&mut *x`
2121
2222error: an expression of form `&mut &mut _`
23 --> tests/ui/mut_mut_unfixable.rs:24:17
23 --> tests/ui/mut_mut_unfixable.rs:23:17
2424 |
2525LL | let y = &mut &mut 2;
2626 | ^^^^^^^^^^^ help: remove the extra `&mut`: `&mut 2`
2727
2828error: an expression of form `&mut &mut _`
29 --> tests/ui/mut_mut_unfixable.rs:30:17
29 --> tests/ui/mut_mut_unfixable.rs:29:17
3030 |
3131LL | let y = &mut &mut &mut 2;
3232 | ^^^^^^^^^^^^^^^^ help: remove the extra `&mut`s: `&mut 2`
3333
3434error: an expression of form `&mut &mut _`
35 --> tests/ui/mut_mut_unfixable.rs:39:17
35 --> tests/ui/mut_mut_unfixable.rs:38:17
3636 |
3737LL | let y = &mut &mut x;
3838 | ^^^^^^^^^^^ 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)]
21#![warn(clippy::mut_mutex_lock)]
32
43use std::sync::{Arc, Mutex};
src/tools/clippy/tests/ui/mut_mutex_lock.rs-1
......@@ -1,4 +1,3 @@
1#![allow(dead_code, unused_mut)]
21#![warn(clippy::mut_mutex_lock)]
32
43use std::sync::{Arc, Mutex};
src/tools/clippy/tests/ui/mut_mutex_lock.stderr+2-2
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | let mut value = value_mutex.lock().unwrap();
55 | ^^^^ help: change this to: `get_mut`
......@@ -8,7 +8,7 @@ LL | let mut value = value_mutex.lock().unwrap();
88 = help: to override `-D warnings` add `#[allow(clippy::mut_mutex_lock)]`
99
1010error: 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
1212 |
1313LL | let mut value = mut_ref_mut_ref_mutex.lock().unwrap();
1414 | ^^^^ 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)]
22
33fn main() {}
44
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)]
43
54use std::sync::Mutex;
65
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)]
43
54use std::sync::Mutex;
65
src/tools/clippy/tests/ui/mutex_atomic.stderr+15-15
......@@ -1,5 +1,5 @@
11error: using a `Mutex` where an atomic would do
2 --> tests/ui/mutex_atomic.rs:8:13
2 --> tests/ui/mutex_atomic.rs:7:13
33 |
44LL | let _ = Mutex::new(true);
55 | ^^^^^^^^^^^^^^^^
......@@ -14,7 +14,7 @@ LL + let _ = std::sync::atomic::AtomicBool::new(true);
1414 |
1515
1616error: using a `Mutex` where an atomic would do
17 --> tests/ui/mutex_atomic.rs:11:13
17 --> tests/ui/mutex_atomic.rs:10:13
1818 |
1919LL | let _ = Mutex::new(5usize);
2020 | ^^^^^^^^^^^^^^^^^^
......@@ -27,7 +27,7 @@ LL + let _ = std::sync::atomic::AtomicUsize::new(5usize);
2727 |
2828
2929error: using a `Mutex` where an atomic would do
30 --> tests/ui/mutex_atomic.rs:14:13
30 --> tests/ui/mutex_atomic.rs:13:13
3131 |
3232LL | let _ = Mutex::new(9isize);
3333 | ^^^^^^^^^^^^^^^^^^
......@@ -40,7 +40,7 @@ LL + let _ = std::sync::atomic::AtomicIsize::new(9isize);
4040 |
4141
4242error: using a `Mutex` where an atomic would do
43 --> tests/ui/mutex_atomic.rs:21:13
43 --> tests/ui/mutex_atomic.rs:20:13
4444 |
4545LL | let _ = Mutex::new(&mut x as *mut u32);
4646 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -53,7 +53,7 @@ LL + let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32);
5353 |
5454
5555error: using a `Mutex` where an atomic would do
56 --> tests/ui/mutex_atomic.rs:24:13
56 --> tests/ui/mutex_atomic.rs:23:13
5757 |
5858LL | let _ = Mutex::new(0u32);
5959 | ^^^^^^^^^^^^^^^^
......@@ -68,7 +68,7 @@ LL + let _ = std::sync::atomic::AtomicU32::new(0u32);
6868 |
6969
7070error: using a `Mutex` where an atomic would do
71 --> tests/ui/mutex_atomic.rs:27:13
71 --> tests/ui/mutex_atomic.rs:26:13
7272 |
7373LL | let _ = Mutex::new(0i32);
7474 | ^^^^^^^^^^^^^^^^
......@@ -81,7 +81,7 @@ LL + let _ = std::sync::atomic::AtomicI32::new(0i32);
8181 |
8282
8383error: using a `Mutex` where an atomic would do
84 --> tests/ui/mutex_atomic.rs:31:13
84 --> tests/ui/mutex_atomic.rs:30:13
8585 |
8686LL | let _ = Mutex::new(0u8);
8787 | ^^^^^^^^^^^^^^^
......@@ -94,7 +94,7 @@ LL + let _ = std::sync::atomic::AtomicU8::new(0u8);
9494 |
9595
9696error: using a `Mutex` where an atomic would do
97 --> tests/ui/mutex_atomic.rs:34:13
97 --> tests/ui/mutex_atomic.rs:33:13
9898 |
9999LL | let _ = Mutex::new(0i16);
100100 | ^^^^^^^^^^^^^^^^
......@@ -107,7 +107,7 @@ LL + let _ = std::sync::atomic::AtomicI16::new(0i16);
107107 |
108108
109109error: using a `Mutex` where an atomic would do
110 --> tests/ui/mutex_atomic.rs:37:25
110 --> tests/ui/mutex_atomic.rs:36:25
111111 |
112112LL | let _x: Mutex<i8> = Mutex::new(0);
113113 | ^^^^^^^^^^^^^
......@@ -120,7 +120,7 @@ LL + let _x = std::sync::atomic::AtomicI8::new(0);
120120 |
121121
122122error: using a `Mutex` where an atomic would do
123 --> tests/ui/mutex_atomic.rs:41:13
123 --> tests/ui/mutex_atomic.rs:40:13
124124 |
125125LL | let _ = Mutex::new(X);
126126 | ^^^^^^^^^^^^^
......@@ -133,7 +133,7 @@ LL + let _ = std::sync::atomic::AtomicI64::new(X);
133133 |
134134
135135error: using a `Mutex` where an atomic would do
136 --> tests/ui/mutex_atomic.rs:53:30
136 --> tests/ui/mutex_atomic.rs:52:30
137137 |
138138LL | static MTX: Mutex<u32> = Mutex::new(0);
139139 | ^^^^^^^^^^^^^
......@@ -146,7 +146,7 @@ LL + static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32
146146 |
147147
148148error: using a `Mutex` where an atomic would do
149 --> tests/ui/mutex_atomic.rs:56:15
149 --> tests/ui/mutex_atomic.rs:55:15
150150 |
151151LL | let mtx = Mutex::new(0);
152152 | ^^^^^^^^^^^^^
......@@ -159,7 +159,7 @@ LL + let mtx = std::sync::atomic::AtomicI32::new(0);
159159 |
160160
161161error: using a `Mutex` where an atomic would do
162 --> tests/ui/mutex_atomic.rs:60:22
162 --> tests/ui/mutex_atomic.rs:59:22
163163 |
164164LL | let reassigned = mtx;
165165 | ^^^
......@@ -168,7 +168,7 @@ LL | let reassigned = mtx;
168168 = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
169169
170170error: using a `Mutex` where an atomic would do
171 --> tests/ui/mutex_atomic.rs:65:35
171 --> tests/ui/mutex_atomic.rs:64:35
172172 |
173173LL | let (funky_mtx): Mutex<u64> = Mutex::new(0);
174174 | ^^^^^^^^^^^^^
......@@ -181,7 +181,7 @@ LL + let (funky_mtx) = std::sync::atomic::AtomicU64::new(0);
181181 |
182182
183183error: using a `Mutex` where an atomic would do
184 --> tests/ui/mutex_atomic.rs:76:13
184 --> tests/ui/mutex_atomic.rs:75:13
185185 |
186186LL | let _ = Mutex::new(test_expr!(1));
187187 | ^^^^^^^^^^^^^^^^^^^^^^^^^
src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed+1-1
......@@ -1,5 +1,5 @@
11#![warn(clippy::needless_arbitrary_self_type)]
2#![allow(unused_mut, clippy::needless_lifetimes)]
2#![expect(clippy::needless_lifetimes)]
33
44pub enum ValType {
55 A,
src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs+1-1
......@@ -1,5 +1,5 @@
11#![warn(clippy::needless_arbitrary_self_type)]
2#![allow(unused_mut, clippy::needless_lifetimes)]
2#![expect(clippy::needless_lifetimes)]
33
44pub enum ValType {
55 A,
src/tools/clippy/tests/ui/needless_bitwise_bool.fixed+1-1
......@@ -1,5 +1,5 @@
11#![warn(clippy::needless_bitwise_bool)]
2#![allow(clippy::const_is_empty)]
2#![expect(clippy::const_is_empty)]
33
44fn returns_bool() -> bool {
55 true
src/tools/clippy/tests/ui/needless_bitwise_bool.rs+1-1
......@@ -1,5 +1,5 @@
11#![warn(clippy::needless_bitwise_bool)]
2#![allow(clippy::const_is_empty)]
2#![expect(clippy::const_is_empty)]
33
44fn returns_bool() -> bool {
55 true
src/tools/clippy/tests/ui/needless_bool/fixable.fixed+2-12
......@@ -1,15 +1,6 @@
11#![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)]
134
145use std::cell::Cell;
156
......@@ -21,7 +12,6 @@ macro_rules! bool_comparison_trigger {
2112 $($i: (Cell<bool>, bool, bool)),+
2213 }
2314
24 #[allow(dead_code)]
2515 impl Trigger {
2616 pub fn trigger(&self, key: &str) -> bool {
2717 $(
src/tools/clippy/tests/ui/needless_bool/fixable.rs+2-12
......@@ -1,15 +1,6 @@
11#![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)]
134
145use std::cell::Cell;
156
......@@ -21,7 +12,6 @@ macro_rules! bool_comparison_trigger {
2112 $($i: (Cell<bool>, bool, bool)),+
2213 }
2314
24 #[allow(dead_code)]
2515 impl Trigger {
2616 pub fn trigger(&self, key: &str) -> bool {
2717 $(
src/tools/clippy/tests/ui/needless_bool/fixable.stderr+25-25
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | / if x {
55LL | | true
......@@ -12,7 +12,7 @@ LL | | };
1212 = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]`
1313
1414error: 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
1616 |
1717LL | / if x {
1818LL | | false
......@@ -22,7 +22,7 @@ LL | | };
2222 | |_____^ help: you can reduce it to: `!x`
2323
2424error: 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
2626 |
2727LL | / if x && y {
2828LL | | false
......@@ -32,7 +32,7 @@ LL | | };
3232 | |_____^ help: you can reduce it to: `!(x && y)`
3333
3434error: 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
3636 |
3737LL | / if a == b {
3838LL | | false
......@@ -42,7 +42,7 @@ LL | | };
4242 | |_____^ help: you can reduce it to: `a != b`
4343
4444error: 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
4646 |
4747LL | / if a != b {
4848LL | | false
......@@ -52,7 +52,7 @@ LL | | };
5252 | |_____^ help: you can reduce it to: `a == b`
5353
5454error: 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
5656 |
5757LL | / if a < b {
5858LL | | false
......@@ -62,7 +62,7 @@ LL | | };
6262 | |_____^ help: you can reduce it to: `a >= b`
6363
6464error: 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
6666 |
6767LL | / if a <= b {
6868LL | | false
......@@ -72,7 +72,7 @@ LL | | };
7272 | |_____^ help: you can reduce it to: `a > b`
7373
7474error: 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
7676 |
7777LL | / if a > b {
7878LL | | false
......@@ -82,7 +82,7 @@ LL | | };
8282 | |_____^ help: you can reduce it to: `a <= b`
8383
8484error: 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
8686 |
8787LL | / if a >= b {
8888LL | | false
......@@ -92,7 +92,7 @@ LL | | };
9292 | |_____^ help: you can reduce it to: `a < b`
9393
9494error: 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
9696 |
9797LL | / if x {
9898LL | | return true;
......@@ -102,7 +102,7 @@ LL | | };
102102 | |_____^ help: you can reduce it to: `return x`
103103
104104error: 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
106106 |
107107LL | / if x {
108108LL | | return false;
......@@ -112,7 +112,7 @@ LL | | };
112112 | |_____^ help: you can reduce it to: `return !x`
113113
114114error: 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
116116 |
117117LL | / if x && y {
118118LL | | return true;
......@@ -122,7 +122,7 @@ LL | | };
122122 | |_____^ help: you can reduce it to: `return x && y`
123123
124124error: 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
126126 |
127127LL | / if x && y {
128128LL | | return false;
......@@ -132,7 +132,7 @@ LL | | };
132132 | |_____^ help: you can reduce it to: `return !(x && y)`
133133
134134error: equality checks against true are unnecessary
135 --> tests/ui/needless_bool/fixable.rs:157:8
135 --> tests/ui/needless_bool/fixable.rs:147:8
136136 |
137137LL | if x == true {};
138138 | ^^^^^^^^^ help: try: `x`
......@@ -141,25 +141,25 @@ LL | if x == true {};
141141 = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
142142
143143error: 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
145145 |
146146LL | if x == false {};
147147 | ^^^^^^^^^^ help: try: `!x`
148148
149149error: equality checks against true are unnecessary
150 --> tests/ui/needless_bool/fixable.rs:173:8
150 --> tests/ui/needless_bool/fixable.rs:163:8
151151 |
152152LL | if x == true {};
153153 | ^^^^^^^^^ help: try: `x`
154154
155155error: 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
157157 |
158158LL | if x == false {};
159159 | ^^^^^^^^^^ help: try: `!x`
160160
161161error: 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
163163 |
164164LL | } else if returns_bool() {
165165 | ____________^
......@@ -170,7 +170,7 @@ LL | | };
170170 | |_____^ help: you can reduce it to: `{ !returns_bool() }`
171171
172172error: 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
174174 |
175175LL | / if unsafe { no(4) } & 1 != 0 {
176176LL | | true
......@@ -180,37 +180,37 @@ LL | | };
180180 | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
181181
182182error: 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
184184 |
185185LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
186186 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
187187
188188error: 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
190190 |
191191LL | if unsafe { no(4) } & 1 != 0 { true } else { false }
192192 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
193193
194194error: 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
196196 |
197197LL | let _x = if a && b { true } else { false }.then(|| todo!());
198198 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)`
199199
200200error: 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
202202 |
203203LL | let _x = if a && b { true } else { false } as u8;
204204 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)`
205205
206206error: 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
208208 |
209209LL | let _x = if a { true } else { false }.then(|| todo!());
210210 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `a`
211211
212212error: 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
214214 |
215215LL | / if test_expr!(x) {
216216LL | | true
src/tools/clippy/tests/ui/needless_bool/simple.rs+1-8
......@@ -1,12 +1,5 @@
11#![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)]
103
114fn main() {
125 let x = true;
src/tools/clippy/tests/ui/needless_bool/simple.stderr+4-4
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | / if x {
55LL | | true
......@@ -12,7 +12,7 @@ LL | | };
1212 = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]`
1313
1414error: 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
1616 |
1717LL | / if x {
1818LL | | false
......@@ -22,7 +22,7 @@ LL | | };
2222 | |_____^
2323
2424error: 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
2626 |
2727LL | / if x {
2828LL | | return true;
......@@ -32,7 +32,7 @@ LL | | };
3232 | |_____^
3333
3434error: 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
3636 |
3737LL | / if x {
3838LL | | return false;
src/tools/clippy/tests/ui/needless_bool_assign.fixed-1
......@@ -1,4 +1,3 @@
1#![allow(unused)]
21#![warn(clippy::needless_bool_assign)]
32
43fn random() -> bool {
src/tools/clippy/tests/ui/needless_bool_assign.rs-1
......@@ -1,4 +1,3 @@
1#![allow(unused)]
21#![warn(clippy::needless_bool_assign)]
32
43fn random() -> bool {
src/tools/clippy/tests/ui/needless_bool_assign.stderr+7-7
......@@ -1,5 +1,5 @@
11error: 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
33 |
44LL | / if random() && random() {
55LL | | a.field = true;
......@@ -12,7 +12,7 @@ LL | | }
1212 = help: to override `-D warnings` add `#[allow(clippy::needless_bool_assign)]`
1313
1414error: 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
1616 |
1717LL | / if random() && random() {
1818LL | | a.field = false;
......@@ -22,7 +22,7 @@ LL | | }
2222 | |_____^ help: you can reduce it to: `a.field = !(random() && random());`
2323
2424error: 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
2626 |
2727LL | / if random() {
2828LL | | a.field = true;
......@@ -32,7 +32,7 @@ LL | | }
3232 | |_____^ help: you can reduce it to: `random(); a.field = true;`
3333
3434error: this `if` has identical blocks
35 --> tests/ui/needless_bool_assign.rs:34:17
35 --> tests/ui/needless_bool_assign.rs:33:17
3636 |
3737LL | if random() {
3838 | _________________^
......@@ -41,7 +41,7 @@ LL | | } else {
4141 | |_____^
4242 |
4343note: same as this
44 --> tests/ui/needless_bool_assign.rs:36:12
44 --> tests/ui/needless_bool_assign.rs:35:12
4545 |
4646LL | } else {
4747 | ____________^
......@@ -52,7 +52,7 @@ LL | | }
5252 = help: to override `-D warnings` add `#[allow(clippy::if_same_then_else)]`
5353
5454error: 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
5656 |
5757LL | } else if x || y {
5858 | ____________^
......@@ -63,7 +63,7 @@ LL | | }
6363 | |_____^ help: you can reduce it to: `{ z = x || y; }`
6464
6565error: 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
6767 |
6868LL | / if invoke!(must_keep, x, y) {
6969LL | | dot_0!(skip) = false;
src/tools/clippy/tests/ui/needless_late_init.fixed+177-14
......@@ -185,25 +185,24 @@ fn does_not_lint() {
185185 };
186186
187187 // 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)
193193 } else {
194 x = 3;
195 y = 4;
196 }
194 (3, 4)
195 };
197196
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 {
201200 let mut y = 5;
202201 y = 6;
203 x = y;
202 y
204203 } else {
205 x = 2;
206 }
204 2
205 };
207206
208207 let (x, y);
209208 if true {
......@@ -299,3 +298,167 @@ fn issue9895() {
299298 //~^ needless_late_init
300299 let r = 5;
301300}
301
302fn 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
312fn 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() {
188188 let x;
189189 let y;
190190 if true {
191 //~^ needless_late_init
191192 x = 1;
192193 y = 2;
193194 } else {
......@@ -195,8 +196,8 @@ fn does_not_lint() {
195196 y = 4;
196197 }
197198
198 // could match with a smarter heuristic to avoid multiple assignments
199199 let x;
200 //~^ needless_late_init
200201 if true {
201202 let mut y = 5;
202203 y = 6;
......@@ -299,3 +300,183 @@ fn issue9895() {
299300 //~^ needless_late_init
300301 (r = 5);
301302}
303
304fn 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
314fn 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 ~ };
276276 |
277277
278278error: unneeded late initialization
279 --> tests/ui/needless_late_init.rs:298:5
279 --> tests/ui/needless_late_init.rs:199:5
280 |
281LL | let x;
282 | ^^^^^^
283 |
284help: move the declaration `x` here and remove the assignments from the branches
285 |
286LL ~
287LL |
288LL ~ let x = if true {
289LL | let mut y = 5;
290LL | y = 6;
291LL ~ y
292LL | } else {
293LL ~ 2
294LL ~ };
295 |
296
297error: unneeded late initialization
298 --> tests/ui/needless_late_init.rs:190:5
299 |
300LL | / if true {
301LL | |
302LL | | x = 1;
303LL | | y = 2;
304... |
305LL | | y = 4;
306LL | | }
307 | |_____^
308 |
309help: move the declarations here and remove the assignments from the branches
310 |
311LL ~
312LL ~
313LL ~ let (x, y) = if true {
314LL |
315LL ~ (1, 2)
316LL | } else {
317LL ~ (3, 4)
318LL ~ };
319 |
320
321error: unneeded late initialization
322 --> tests/ui/needless_late_init.rs:299:5
280323 |
281324LL | let r;
282325 | ^^^^^^ created here
......@@ -291,5 +334,153 @@ LL |
291334LL ~ let r = 5;
292335 |
293336
294error: aborting due to 17 previous errors
337error: unneeded late initialization
338 --> tests/ui/needless_late_init.rs:305:5
339 |
340LL | let z;
341 | ^^^^^^
342 |
343help: move the declaration `z` here and remove the assignments from the branches
344 |
345LL ~
346LL |
347LL ~ let z = if true {
348LL ~ 1
349LL | } else {
350LL ~ 2
351LL ~ };
352 |
353
354error: unneeded late initialization
355 --> tests/ui/needless_late_init.rs:455:5
356 |
357LL | let c;
358 | ^^^^^^
359 |
360help: move the declaration `c` here and remove the assignments from the branches
361 |
362LL ~
363LL |
364LL ~ let c = if true {
365LL | a = 1;
366LL | b = a + 1;
367LL ~ b + 1
368LL | } else {
369LL | a = 4;
370LL | b = a + 2;
371LL ~ b + 2
372LL ~ };
373 |
374
375error: unneeded late initialization
376 --> tests/ui/needless_late_init.rs:318:5
377 |
378LL | / if true {
379LL | |
380LL | | a = 1;
381LL | | b = 2;
382... |
383LL | | b = 4;
384LL | | }
385 | |_____^
386 |
387help: move the declarations here and remove the assignments from the branches
388 |
389LL ~
390LL ~
391LL ~ let (a, b) = if true {
392LL |
393LL ~ (1, 2)
394LL | } else {
395LL ~ (3, 4)
396LL ~ };
397 |
398
399error: unneeded late initialization
400 --> tests/ui/needless_late_init.rs:361:5
401 |
402LL | / match 1 {
403LL | |
404LL | | 1 => {
405LL | | a = 1;
406... |
407LL | | },
408LL | | }
409 | |_____^
410 |
411help: move the declarations here and remove the assignments from the `match` arms
412 |
413LL ~
414LL ~
415LL ~
416LL ~ let (a, b, c) = match 1 {
417LL |
418LL | 1 => {
419LL ~ (1, 2, 3)
420LL | },
421LL | _ if false => {
422LL ~ (4, 5, 6)
423LL | },
424LL | _ => {
425LL ~ (7, 8, 9)
426LL | },
427LL ~ };
428 |
429
430error: unneeded late initialization
431 --> tests/ui/needless_late_init.rs:384:5
432 |
433LL | / if true {
434LL | |
435LL | | a = 1;
436LL | | b = 2;
437... |
438LL | | c = 9;
439LL | | }
440 | |_____^
441 |
442help: move the declarations here and remove the assignments from the branches
443 |
444LL ~
445LL ~
446LL ~
447LL ~ let (a, b, c) = if true {
448LL |
449LL ~ (1, 2, 3)
450LL | } else if false {
451LL ~ (4, 5, 6)
452LL | } else {
453LL ~ (7, 8, 9)
454LL ~ };
455 |
456
457error: unneeded late initialization
458 --> tests/ui/needless_late_init.rs:470:5
459 |
460LL | / if true {
461LL | |
462LL | | a = 1;
463LL | | b = a + 1;
464... |
465LL | | d = 2;
466LL | | }
467 | |_____^
468 |
469help: move the declarations here and remove the assignments from the branches
470 |
471LL ~
472LL ~
473LL ~ let (c, d) = if true {
474LL |
475LL | a = 1;
476LL | b = a + 1;
477LL ~ (b + 1, 1)
478LL | } else {
479LL | a = 4;
480LL | b = a + 2;
481LL ~ (b + 2, 2)
482LL ~ };
483 |
484
485error: aborting due to 25 previous errors
295486
src/tools/clippy/tests/ui/ref_patterns.rs+10
......@@ -19,4 +19,14 @@ fn use_in_binding() {
1919fn use_in_parameter(ref x: i32) {}
2020//~^ ref_patterns
2121
22struct Foo {}
23
24// shouldn't trigger the lint
25#[automatically_derived]
26impl Foo {
27 fn foo() {
28 if let Some(ref x) = Some(1) {}
29 }
30}
31
2232fn main() {}
src/tools/clippy/tests/ui/std_instead_of_core.fixed+20
......@@ -96,3 +96,23 @@ fn issue15579() {
9696
9797 let layout = alloc::Layout::new::<u8>();
9898}
99
100#[warn(clippy::std_instead_of_core)]
101fn 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"]
107fn issue13158_msrv_1_40(_: &dyn std::panic::UnwindSafe) {}
108
109#[clippy::msrv = "1.41"]
110fn issue13158_msrv_1_41(_: &dyn core::panic::UnwindSafe) {}
111//~^ std_instead_of_core
112
113#[clippy::msrv = "1.80"]
114fn issue13158_msrv_1_80(_: &dyn std::error::Error) {}
115
116#[clippy::msrv = "1.81"]
117fn 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() {
9696
9797 let layout = alloc::Layout::new::<u8>();
9898}
99
100#[warn(clippy::std_instead_of_core)]
101fn 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"]
107fn issue13158_msrv_1_40(_: &dyn std::panic::UnwindSafe) {}
108
109#[clippy::msrv = "1.41"]
110fn issue13158_msrv_1_41(_: &dyn std::panic::UnwindSafe) {}
111//~^ std_instead_of_core
112
113#[clippy::msrv = "1.80"]
114fn issue13158_msrv_1_80(_: &dyn std::error::Error) {}
115
116#[clippy::msrv = "1.81"]
117fn 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`
9797LL | fn msrv_1_77(_: std::net::IpAddr) {}
9898 | ^^^ help: consider importing the item from `core`: `core`
9999
100error: aborting due to 15 previous errors
100error: used import from `std` instead of `core`
101 --> tests/ui/std_instead_of_core.rs:110:33
102 |
103LL | fn issue13158_msrv_1_41(_: &dyn std::panic::UnwindSafe) {}
104 | ^^^ help: consider importing the item from `core`: `core`
105
106error: used import from `std` instead of `core`
107 --> tests/ui/std_instead_of_core.rs:117:33
108 |
109LL | fn issue13158_msrv_1_81(_: &dyn std::error::Error) {}
110 | ^^^ help: consider importing the item from `core`: `core`
111
112error: aborting due to 17 previous errors
101113
src/tools/clippy/tests/ui/std_instead_of_core_unfixable.rs+11
......@@ -14,3 +14,14 @@ fn issue15143() {
1414 //~^ std_instead_of_core
1515 //~| std_instead_of_alloc
1616}
17
18#[rustfmt::skip]
19fn 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};
2626 = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings`
2727 = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]`
2828
29error: aborting due to 3 previous errors
29error: used import from `std` instead of `alloc`
30 --> tests/ui/std_instead_of_core_unfixable.rs:21:17
31 |
32LL | borrow::Cow,
33 | ^^^
34 |
35 = help: consider importing the item from `alloc`
36
37error: used import from `std` instead of `alloc`
38 --> tests/ui/std_instead_of_core_unfixable.rs:23:22
39 |
40LL | collections::BTreeSet,
41 | ^^^^^^^^
42 |
43 = help: consider importing the item from `alloc`
44
45error: aborting due to 5 previous errors
3046
src/tools/clippy/tests/ui/uninit_vec.rs+122
......@@ -205,3 +205,125 @@ fn main() {
205205 }
206206 }
207207}
208
209mod 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);
159159 |
160160 = help: initialize the buffer or wrap the content in `MaybeUninit`
161161
162error: aborting due to 15 previous errors
162error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
163 --> tests/ui/uninit_vec.rs:222:9
164 |
165LL | let mut v: Vec<[u8; HUGE]> = Vec::with_capacity(1);
166 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
167LL |
168LL | unsafe { v.set_len(1) };
169 | ^^^^^^^^^^^^
170 |
171 = help: initialize the buffer or wrap the content in `MaybeUninit`
172
173error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
174 --> tests/ui/uninit_vec.rs:240:9
175 |
176LL | let mut v: Vec<HeavyWrapperUnsafe> = Vec::with_capacity(1);
177 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
178LL |
179LL | unsafe { v.set_len(1) };
180 | ^^^^^^^^^^^^
181 |
182 = help: initialize the buffer or wrap the content in `MaybeUninit`
183
184error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
185 --> tests/ui/uninit_vec.rs:251:9
186 |
187LL | let mut v: Vec<HeavyEnum> = Vec::with_capacity(1);
188 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
189LL |
190LL | unsafe { v.set_len(1) };
191 | ^^^^^^^^^^^^
192 |
193 = help: initialize the buffer or wrap the content in `MaybeUninit`
194
195error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
196 --> tests/ui/uninit_vec.rs:274:9
197 |
198LL | let mut v: Vec<OneVariantU8> = Vec::with_capacity(1);
199 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
200LL |
201LL | unsafe { v.set_len(1) };
202 | ^^^^^^^^^^^^
203 |
204 = help: initialize the buffer or wrap the content in `MaybeUninit`
205
206error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
207 --> tests/ui/uninit_vec.rs:288:9
208 |
209LL | let mut v: Vec<T> = Vec::with_capacity(1);
210 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
211LL |
212LL | unsafe { v.set_len(1) };
213 | ^^^^^^^^^^^^
214 |
215 = help: initialize the buffer or wrap the content in `MaybeUninit`
216
217error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
218 --> tests/ui/uninit_vec.rs:302:9
219 |
220LL | let mut v: Vec<<T as Assoc>::Item> = Vec::with_capacity(1);
221 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
222LL |
223LL | unsafe { v.set_len(1) };
224 | ^^^^^^^^^^^^
225 |
226 = help: initialize the buffer or wrap the content in `MaybeUninit`
227
228error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
229 --> tests/ui/uninit_vec.rs:325:9
230 |
231LL | let mut v: Vec<E<u8, (u8, core::convert::Infallible)>> = Vec::with_capacity(1);
232 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
233LL |
234LL | unsafe { v.set_len(1) };
235 | ^^^^^^^^^^^^
236 |
237 = help: initialize the buffer or wrap the content in `MaybeUninit`
238
239error: aborting due to 22 previous errors
163240
src/tools/clippy/tests/ui/unnecessary_box_returns.rs+17
......@@ -71,6 +71,23 @@ impl HasHuge {
7171 }
7272}
7373
74// don't lint (issue #17202): the size of `[T; N]` depends on a const generic parameter
75fn 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
80fn 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)]
86fn generic_vec<T>(value: Box<Vec<T>>) -> Box<Vec<T>> {
87 //~^ unnecessary_box_returns
88 value
89}
90
7491fn main() {
7592 // don't lint: this is a closure
7693 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> {
3232 |
3333 = help: changing this also requires a change to the return expressions in this function
3434
35error: aborting due to 4 previous errors
35error: boxed return of the sized type `std::vec::Vec<T>`
36 --> tests/ui/unnecessary_box_returns.rs:86:42
37 |
38LL | 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
43error: aborting due to 5 previous errors
3644
src/tools/clippy/tests/ui/unnecessary_cast.fixed+24
......@@ -1,7 +1,9 @@
11//@aux-build:extern_fake_libc.rs
2#![feature(const_trait_impl, const_ops)]
23#![warn(clippy::unnecessary_cast)]
34#![allow(
45 clippy::borrow_as_ptr,
6 clippy::identity_op,
57 clippy::multiple_bound_locations,
68 clippy::no_effect,
79 clippy::nonstandard_macro_braces,
......@@ -656,3 +658,25 @@ fn issue16475() -> *const u8 {
656658 //~^ unnecessary_cast
657659 }
658660}
661
662// Make sure that the calculated values aren't changed by the fixes.
663const _: () = {
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 @@
11//@aux-build:extern_fake_libc.rs
2#![feature(const_trait_impl, const_ops)]
23#![warn(clippy::unnecessary_cast)]
34#![allow(
45 clippy::borrow_as_ptr,
6 clippy::identity_op,
57 clippy::multiple_bound_locations,
68 clippy::no_effect,
79 clippy::nonstandard_macro_braces,
......@@ -656,3 +658,25 @@ fn issue16475() -> *const u8 {
656658 //~^ unnecessary_cast
657659 }
658660}
661
662// Make sure that the calculated values aren't changed by the fixes.
663const _: () = {
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 @@
11error: 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
33 |
44LL | ptr as *const T
55 | ^^^^^^^^^^^^^^^ help: try: `ptr`
......@@ -8,388 +8,430 @@ LL | ptr as *const T
88 = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`
99
1010error: casting integer literal to `i32` is unnecessary
11 --> tests/ui/unnecessary_cast.rs:55:5
11 --> tests/ui/unnecessary_cast.rs:57:5
1212 |
1313LL | 1i32 as i32;
1414 | ^^^^^^^^^^^ help: try: `1_i32`
1515
1616error: casting float literal to `f32` is unnecessary
17 --> tests/ui/unnecessary_cast.rs:57:5
17 --> tests/ui/unnecessary_cast.rs:59:5
1818 |
1919LL | 1f32 as f32;
2020 | ^^^^^^^^^^^ help: try: `1_f32`
2121
2222error: 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
2424 |
2525LL | false as bool;
2626 | ^^^^^^^^^^^^^ help: try: `false`
2727
2828error: casting integer literal to `i32` is unnecessary
29 --> tests/ui/unnecessary_cast.rs:63:5
29 --> tests/ui/unnecessary_cast.rs:65:5
3030 |
3131LL | -1_i32 as i32;
3232 | ^^^^^^^^^^^^^ help: try: `-1_i32`
3333
3434error: casting integer literal to `i32` is unnecessary
35 --> tests/ui/unnecessary_cast.rs:65:5
35 --> tests/ui/unnecessary_cast.rs:67:5
3636 |
3737LL | - 1_i32 as i32;
3838 | ^^^^^^^^^^^^^^ help: try: `- 1_i32`
3939
4040error: casting float literal to `f32` is unnecessary
41 --> tests/ui/unnecessary_cast.rs:67:5
41 --> tests/ui/unnecessary_cast.rs:69:5
4242 |
4343LL | -1f32 as f32;
4444 | ^^^^^^^^^^^^ help: try: `-1_f32`
4545
4646error: casting integer literal to `i32` is unnecessary
47 --> tests/ui/unnecessary_cast.rs:69:5
47 --> tests/ui/unnecessary_cast.rs:71:5
4848 |
4949LL | 1_i32 as i32;
5050 | ^^^^^^^^^^^^ help: try: `1_i32`
5151
5252error: casting float literal to `f32` is unnecessary
53 --> tests/ui/unnecessary_cast.rs:71:5
53 --> tests/ui/unnecessary_cast.rs:73:5
5454 |
5555LL | 1_f32 as f32;
5656 | ^^^^^^^^^^^^ help: try: `1_f32`
5757
5858error: 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
6060 |
6161LL | let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8;
6262 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
6363
6464error: 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
6666 |
6767LL | [1u8, 2].as_ptr() as *const u8;
6868 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
6969
7070error: 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
7272 |
7373LL | [1u8, 2].as_mut_ptr() as *mut u8;
7474 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()`
7575
7676error: 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
7878 |
7979LL | owo::<u32>([1u32].as_ptr()) as *const u32;
8080 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::<u32>([1u32].as_ptr())`
8181
8282error: 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
8484 |
8585LL | uwu::<u32, u8>([1u32].as_ptr()) as *const u8;
8686 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u8>([1u32].as_ptr())`
8787
8888error: 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
9090 |
9191LL | uwu::<u32, u32>([1u32].as_ptr()) as *const u32;
9292 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u32>([1u32].as_ptr())`
9393
9494error: 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
9696 |
9797LL | aaa() as u32;
9898 | ^^^^^^^^^^^^ help: try: `aaa()`
9999
100100error: 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
102102 |
103103LL | x as u32;
104104 | ^^^^^^^^ help: try: `x`
105105
106106error: 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
108108 |
109109LL | bbb() as u32;
110110 | ^^^^^^^^^^^^ help: try: `bbb()`
111111
112112error: 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
114114 |
115115LL | x as u32;
116116 | ^^^^^^^^ help: try: `x`
117117
118118error: casting integer literal to `f32` is unnecessary
119 --> tests/ui/unnecessary_cast.rs:174:9
119 --> tests/ui/unnecessary_cast.rs:176:9
120120 |
121121LL | 100 as f32;
122122 | ^^^^^^^^^^ help: try: `100_f32`
123123
124124error: casting integer literal to `f64` is unnecessary
125 --> tests/ui/unnecessary_cast.rs:176:9
125 --> tests/ui/unnecessary_cast.rs:178:9
126126 |
127127LL | 100 as f64;
128128 | ^^^^^^^^^^ help: try: `100_f64`
129129
130130error: casting integer literal to `f64` is unnecessary
131 --> tests/ui/unnecessary_cast.rs:178:9
131 --> tests/ui/unnecessary_cast.rs:180:9
132132 |
133133LL | 100_i32 as f64;
134134 | ^^^^^^^^^^^^^^ help: try: `100_f64`
135135
136136error: casting integer literal to `f32` is unnecessary
137 --> tests/ui/unnecessary_cast.rs:180:17
137 --> tests/ui/unnecessary_cast.rs:182:17
138138 |
139139LL | let _ = -100 as f32;
140140 | ^^^^^^^^^^^ help: try: `-100_f32`
141141
142142error: casting integer literal to `f64` is unnecessary
143 --> tests/ui/unnecessary_cast.rs:182:17
143 --> tests/ui/unnecessary_cast.rs:184:17
144144 |
145145LL | let _ = -100 as f64;
146146 | ^^^^^^^^^^^ help: try: `-100_f64`
147147
148148error: casting integer literal to `f64` is unnecessary
149 --> tests/ui/unnecessary_cast.rs:184:17
149 --> tests/ui/unnecessary_cast.rs:186:17
150150 |
151151LL | let _ = -100_i32 as f64;
152152 | ^^^^^^^^^^^^^^^ help: try: `-100_f64`
153153
154154error: casting float literal to `f32` is unnecessary
155 --> tests/ui/unnecessary_cast.rs:186:9
155 --> tests/ui/unnecessary_cast.rs:188:9
156156 |
157157LL | 100. as f32;
158158 | ^^^^^^^^^^^ help: try: `100_f32`
159159
160160error: casting float literal to `f64` is unnecessary
161 --> tests/ui/unnecessary_cast.rs:188:9
161 --> tests/ui/unnecessary_cast.rs:190:9
162162 |
163163LL | 100. as f64;
164164 | ^^^^^^^^^^^ help: try: `100_f64`
165165
166166error: casting integer literal to `u32` is unnecessary
167 --> tests/ui/unnecessary_cast.rs:201:9
167 --> tests/ui/unnecessary_cast.rs:203:9
168168 |
169169LL | 1 as u32;
170170 | ^^^^^^^^ help: try: `1_u32`
171171
172172error: casting integer literal to `i32` is unnecessary
173 --> tests/ui/unnecessary_cast.rs:203:9
173 --> tests/ui/unnecessary_cast.rs:205:9
174174 |
175175LL | 0x10 as i32;
176176 | ^^^^^^^^^^^ help: try: `0x10_i32`
177177
178178error: casting integer literal to `usize` is unnecessary
179 --> tests/ui/unnecessary_cast.rs:205:9
179 --> tests/ui/unnecessary_cast.rs:207:9
180180 |
181181LL | 0b10 as usize;
182182 | ^^^^^^^^^^^^^ help: try: `0b10_usize`
183183
184184error: casting integer literal to `u16` is unnecessary
185 --> tests/ui/unnecessary_cast.rs:207:9
185 --> tests/ui/unnecessary_cast.rs:209:9
186186 |
187187LL | 0o73 as u16;
188188 | ^^^^^^^^^^^ help: try: `0o73_u16`
189189
190190error: casting integer literal to `u32` is unnecessary
191 --> tests/ui/unnecessary_cast.rs:209:9
191 --> tests/ui/unnecessary_cast.rs:211:9
192192 |
193193LL | 1_000_000_000 as u32;
194194 | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
195195
196196error: casting float literal to `f64` is unnecessary
197 --> tests/ui/unnecessary_cast.rs:212:9
197 --> tests/ui/unnecessary_cast.rs:214:9
198198 |
199199LL | 1.0 as f64;
200200 | ^^^^^^^^^^ help: try: `1.0_f64`
201201
202202error: casting float literal to `f32` is unnecessary
203 --> tests/ui/unnecessary_cast.rs:214:9
203 --> tests/ui/unnecessary_cast.rs:216:9
204204 |
205205LL | 0.5 as f32;
206206 | ^^^^^^^^^^ help: try: `0.5_f32`
207207
208208error: casting integer literal to `i32` is unnecessary
209 --> tests/ui/unnecessary_cast.rs:219:17
209 --> tests/ui/unnecessary_cast.rs:221:17
210210 |
211211LL | let _ = -1 as i32;
212212 | ^^^^^^^^^ help: try: `-1_i32`
213213
214214error: casting float literal to `f32` is unnecessary
215 --> tests/ui/unnecessary_cast.rs:221:17
215 --> tests/ui/unnecessary_cast.rs:223:17
216216 |
217217LL | let _ = -1.0 as f32;
218218 | ^^^^^^^^^^^ help: try: `-1.0_f32`
219219
220220error: 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
222222 |
223223LL | let _ = &(x as i32);
224224 | ^^^^^^^^^^ help: try: `{ x }`
225225
226226error: casting integer literal to `i32` is unnecessary
227 --> tests/ui/unnecessary_cast.rs:235:22
227 --> tests/ui/unnecessary_cast.rs:237:22
228228 |
229229LL | let _: i32 = -(1) as i32;
230230 | ^^^^^^^^^^^ help: try: `-1_i32`
231231
232232error: casting integer literal to `i64` is unnecessary
233 --> tests/ui/unnecessary_cast.rs:238:22
233 --> tests/ui/unnecessary_cast.rs:240:22
234234 |
235235LL | let _: i64 = -(1) as i64;
236236 | ^^^^^^^^^^^ help: try: `-1_i64`
237237
238238error: casting float literal to `f64` is unnecessary
239 --> tests/ui/unnecessary_cast.rs:246:22
239 --> tests/ui/unnecessary_cast.rs:248:22
240240 |
241241LL | let _: f64 = (-8.0 as f64).exp();
242242 | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
243243
244244error: casting float literal to `f64` is unnecessary
245 --> tests/ui/unnecessary_cast.rs:249:23
245 --> tests/ui/unnecessary_cast.rs:251:23
246246 |
247247LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
248248 | ^^^^^^^^^^^^ help: try: `8.0_f64`
249249
250250error: 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
252252 |
253253LL | let _num = foo() as f32;
254254 | ^^^^^^^^^^^^ help: try: `foo()`
255255
256256error: 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
258258 |
259259LL | (*x as usize).pow(2)
260260 | ^^^^^^^^^^^^^ help: try: `(*x)`
261261
262262error: 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
264264 |
265265LL | assert_eq!(vec.len(), x as usize);
266266 | ^^^^^^^^^^ help: try: `x`
267267
268268error: 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
270270 |
271271LL | let _ = (5i32 as i64 as i64).abs();
272272 | ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)`
273273
274274error: 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
276276 |
277277LL | let _ = 5i32 as i64 as i64;
278278 | ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64`
279279
280280error: 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
282282 |
283283LL | id::<Out<f64>>(1.0_f64.pow_like(2) as f64 * &a).view();
284284 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)`
285285
286286error: 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
288288 |
289289LL | s.id::<Out<f64>>(1.0_f64.pow_like(2) as f64 * &a).view();
290290 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)`
291291
292292error: 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
294294 |
295295LL | wrap::<Out<f64>>(1.0_f64.pow_like(2) as f64 * &a).inner.view();
296296 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)`
297297
298298error: 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
300300 |
301301LL | s.wrap::<Out<f64>>(1.0_f64.pow_like(2) as f64 * &a).inner.view();
302302 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)`
303303
304304error: 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
306306 |
307307LL | let _ = receiver.take(1.0_f64.pow_like_single_impl(2) as f64).abs();
308308 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)`
309309
310310error: 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
312312 |
313313LL | let _ = id(1.0_f64.powi(2) as f64).abs();
314314 | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)`
315315
316316error: 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
318318 |
319319LL | let _ = wrap(1.0_f64.powi(2) as f64).inner.abs();
320320 | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)`
321321
322322error: 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
324324 |
325325LL | let _ = s.id(1.0_f64.powi(2) as f64).abs();
326326 | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)`
327327
328328error: 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
330330 |
331331LL | let _ = s.wrap(1.0_f64.powi(2) as f64).inner.abs();
332332 | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)`
333333
334334error: 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
336336 |
337337LL | let _ = id(1.0_f64.powi(2) as f64 * &a);
338338 | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)`
339339
340340error: 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
342342 |
343343LL | let _ = s.id(1.0_f64.powi(2) as f64 * &a);
344344 | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)`
345345
346346error: 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
348348 |
349349LL | let _ = 1.0_f64.pow_like(0.5) as f64;
350350 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(0.5)`
351351
352352error: 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
354354 |
355355LL | let _ = 1.0_f64.pow_like(2) as f64;
356356 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like(2)`
357357
358358error: 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
360360 |
361361LL | let _ = (1.0_f64.powi(2) as f64).abs();
362362 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.powi(2)`
363363
364364error: 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
366366 |
367367LL | let _ = ((Y + 2) as f64).abs();
368368 | ^^^^^^^^^^^^^^^^ help: try: `((Y + 2))`
369369
370370error: 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
372372 |
373373LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + 1.0_f64).abs();
374374 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)`
375375
376376error: 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
378378 |
379379LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + ONE).abs();
380380 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)`
381381
382382error: 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
384384 |
385385LL | let _ = (1.0_f64.pow_like_single_impl(2) as f64 + one).abs();
386386 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1.0_f64.pow_like_single_impl(2)`
387387
388388error: 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
390390 |
391391LL | *(&NONE as *const _ as *const _ as *const *const u8 as *const *const u8)
392392 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&NONE as *const _ as *const _ as *const *const u8)`
393393
394error: aborting due to 65 previous errors
394error: casting integer literal to `u64` is unnecessary
395 --> tests/ui/unnecessary_cast.rs:665:45
396 |
397LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64).overflowing_shr(1_u32).0);
398 | ^^^^^^^^^^^ help: try: `(!0_u64)`
399
400error: casting to the same type is unnecessary (`u64` -> `u64`)
401 --> tests/ui/unnecessary_cast.rs:667:45
402 |
403LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0_u64 as u64).overflowing_shr(1_u32).0);
404 | ^^^^^^^^^^^^^^^ help: try: `(!0_u64)`
405
406error: casting integer literal to `u64` is unnecessary
407 --> tests/ui/unnecessary_cast.rs:670:46
408 |
409LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!0 as u64 + 0).overflowing_shr(1_u32).0);
410 | ^^^^^^^^^ help: try: `!0_u64`
411
412error: casting integer literal to `u64` is unnecessary
413 --> tests/ui/unnecessary_cast.rs:672:48
414 |
415LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!(0 as u64 + 0)).overflowing_shr(1_u32).0);
416 | ^^^^^^^^ help: try: `0_u64`
417
418error: casting integer literal to `u64` is unnecessary
419 --> tests/ui/unnecessary_cast.rs:675:54
420 |
421LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == identity(!0 as u64).overflowing_shr(1_u32).0);
422 | ^^^^^^^^^ help: try: `!0_u64`
423
424error: casting integer literal to `u64` is unnecessary
425 --> tests/ui/unnecessary_cast.rs:678:56
426 |
427LL | assert!(0x7f_ff_ff_ff_ff_ff_ff_ffu64 == (!identity(0 as u64)).overflowing_shr(1_u32).0);
428 | ^^^^^^^^ help: try: `0_u64`
429
430error: casting integer literal to `u64` is unnecessary
431 --> tests/ui/unnecessary_cast.rs:680:54
432 |
433LL | 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
436error: aborting due to 72 previous errors
395437
src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed+12
......@@ -240,6 +240,18 @@ fn main() {
240240 let _: Result<usize, usize> = res.or_else(|err| Ok(err));
241241}
242242
243fn issue11672() {
244 // needs turbofish to disambiguate
245 let _ = true.then_some::<&[u8]>({ &[] });
246 //~^ unnecessary_lazy_evaluations
247}
248
249fn 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
243255#[allow(unused)]
244256fn issue9485() {
245257 // should not lint, is in proc macro
src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs+12
......@@ -240,6 +240,18 @@ fn main() {
240240 let _: Result<usize, usize> = res.or_else(|err| Ok(err));
241241}
242242
243fn issue11672() {
244 // needs turbofish to disambiguate
245 let _ = true.then(|| -> &[u8] { &[] });
246 //~^ unnecessary_lazy_evaluations
247}
248
249fn 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
243255#[allow(unused)]
244256fn issue9485() {
245257 // 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));
484484 |
485485
486486error: 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 |
489LL | let _ = true.then(|| -> &[u8] { &[] });
490 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
491 |
492help: use `then_some` instead
493 |
494LL - let _ = true.then(|| -> &[u8] { &[] });
495LL + let _ = true.then_some::<&[u8]>({ &[] });
496 |
497
498error: unnecessary closure used to substitute value for `Option::None`
499 --> tests/ui/unnecessary_lazy_eval.rs:251:13
500 |
501LL | let _ = None.get_or_insert_with(|| -> &[u8] { &[] });
502 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
503 |
504help: use `get_or_insert` instead
505 |
506LL - let _ = None.get_or_insert_with(|| -> &[u8] { &[] });
507LL + let _ = None.get_or_insert({ &[] } as &[u8]);
508 |
509
510error: unnecessary closure used with `bool::then`
511 --> tests/ui/unnecessary_lazy_eval.rs:271:14
488512 |
489513LL | let _x = false.then(|| i32::MAX + 1);
490514 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -496,7 +520,7 @@ LL + let _x = false.then_some(i32::MAX + 1);
496520 |
497521
498522error: unnecessary closure used with `bool::then`
499 --> tests/ui/unnecessary_lazy_eval.rs:261:14
523 --> tests/ui/unnecessary_lazy_eval.rs:273:14
500524 |
501525LL | let _x = false.then(|| i32::MAX * 2);
502526 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -508,7 +532,7 @@ LL + let _x = false.then_some(i32::MAX * 2);
508532 |
509533
510534error: unnecessary closure used with `bool::then`
511 --> tests/ui/unnecessary_lazy_eval.rs:263:14
535 --> tests/ui/unnecessary_lazy_eval.rs:275:14
512536 |
513537LL | let _x = false.then(|| i32::MAX - 1);
514538 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -520,7 +544,7 @@ LL + let _x = false.then_some(i32::MAX - 1);
520544 |
521545
522546error: unnecessary closure used with `bool::then`
523 --> tests/ui/unnecessary_lazy_eval.rs:265:14
547 --> tests/ui/unnecessary_lazy_eval.rs:277:14
524548 |
525549LL | let _x = false.then(|| i32::MIN - 1);
526550 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -532,7 +556,7 @@ LL + let _x = false.then_some(i32::MIN - 1);
532556 |
533557
534558error: unnecessary closure used with `bool::then`
535 --> tests/ui/unnecessary_lazy_eval.rs:267:14
559 --> tests/ui/unnecessary_lazy_eval.rs:279:14
536560 |
537561LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2);
538562 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -544,7 +568,7 @@ LL + let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2);
544568 |
545569
546570error: unnecessary closure used with `bool::then`
547 --> tests/ui/unnecessary_lazy_eval.rs:269:14
571 --> tests/ui/unnecessary_lazy_eval.rs:281:14
548572 |
549573LL | let _x = false.then(|| 255u8 << 7);
550574 | ^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -556,7 +580,7 @@ LL + let _x = false.then_some(255u8 << 7);
556580 |
557581
558582error: unnecessary closure used with `bool::then`
559 --> tests/ui/unnecessary_lazy_eval.rs:271:14
583 --> tests/ui/unnecessary_lazy_eval.rs:283:14
560584 |
561585LL | let _x = false.then(|| 255u8 << 8);
562586 | ^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -568,7 +592,7 @@ LL + let _x = false.then_some(255u8 << 8);
568592 |
569593
570594error: unnecessary closure used with `bool::then`
571 --> tests/ui/unnecessary_lazy_eval.rs:273:14
595 --> tests/ui/unnecessary_lazy_eval.rs:285:14
572596 |
573597LL | let _x = false.then(|| 255u8 >> 8);
574598 | ^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -580,7 +604,7 @@ LL + let _x = false.then_some(255u8 >> 8);
580604 |
581605
582606error: unnecessary closure used with `bool::then`
583 --> tests/ui/unnecessary_lazy_eval.rs:276:14
607 --> tests/ui/unnecessary_lazy_eval.rs:288:14
584608 |
585609LL | let _x = false.then(|| i32::MAX + -1);
586610 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -592,7 +616,7 @@ LL + let _x = false.then_some(i32::MAX + -1);
592616 |
593617
594618error: unnecessary closure used with `bool::then`
595 --> tests/ui/unnecessary_lazy_eval.rs:278:14
619 --> tests/ui/unnecessary_lazy_eval.rs:290:14
596620 |
597621LL | let _x = false.then(|| -i32::MAX);
598622 | ^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -604,7 +628,7 @@ LL + let _x = false.then_some(-i32::MAX);
604628 |
605629
606630error: unnecessary closure used with `bool::then`
607 --> tests/ui/unnecessary_lazy_eval.rs:280:14
631 --> tests/ui/unnecessary_lazy_eval.rs:292:14
608632 |
609633LL | let _x = false.then(|| -i32::MIN);
610634 | ^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -616,7 +640,7 @@ LL + let _x = false.then_some(-i32::MIN);
616640 |
617641
618642error: unnecessary closure used with `bool::then`
619 --> tests/ui/unnecessary_lazy_eval.rs:283:14
643 --> tests/ui/unnecessary_lazy_eval.rs:295:14
620644 |
621645LL | let _x = false.then(|| 255 >> -7);
622646 | ^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -628,7 +652,7 @@ LL + let _x = false.then_some(255 >> -7);
628652 |
629653
630654error: unnecessary closure used with `bool::then`
631 --> tests/ui/unnecessary_lazy_eval.rs:285:14
655 --> tests/ui/unnecessary_lazy_eval.rs:297:14
632656 |
633657LL | let _x = false.then(|| 255 << -1);
634658 | ^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -640,7 +664,7 @@ LL + let _x = false.then_some(255 << -1);
640664 |
641665
642666error: unnecessary closure used with `bool::then`
643 --> tests/ui/unnecessary_lazy_eval.rs:287:14
667 --> tests/ui/unnecessary_lazy_eval.rs:299:14
644668 |
645669LL | let _x = false.then(|| 1 / 0);
646670 | ^^^^^^^^^^^^^^^^^^^^
......@@ -652,7 +676,7 @@ LL + let _x = false.then_some(1 / 0);
652676 |
653677
654678error: unnecessary closure used with `bool::then`
655 --> tests/ui/unnecessary_lazy_eval.rs:289:14
679 --> tests/ui/unnecessary_lazy_eval.rs:301:14
656680 |
657681LL | let _x = false.then(|| x << -1);
658682 | ^^^^^^^^^^^^^^^^^^^^^^
......@@ -664,7 +688,7 @@ LL + let _x = false.then_some(x << -1);
664688 |
665689
666690error: unnecessary closure used with `bool::then`
667 --> tests/ui/unnecessary_lazy_eval.rs:291:14
691 --> tests/ui/unnecessary_lazy_eval.rs:303:14
668692 |
669693LL | let _x = false.then(|| x << 2);
670694 | ^^^^^^^^^^^^^^^^^^^^^
......@@ -676,7 +700,7 @@ LL + let _x = false.then_some(x << 2);
676700 |
677701
678702error: unnecessary closure used with `bool::then`
679 --> tests/ui/unnecessary_lazy_eval.rs:301:14
703 --> tests/ui/unnecessary_lazy_eval.rs:313:14
680704 |
681705LL | let _x = false.then(|| x / 0);
682706 | ^^^^^^^^^^^^^^^^^^^^
......@@ -688,7 +712,7 @@ LL + let _x = false.then_some(x / 0);
688712 |
689713
690714error: unnecessary closure used with `bool::then`
691 --> tests/ui/unnecessary_lazy_eval.rs:303:14
715 --> tests/ui/unnecessary_lazy_eval.rs:315:14
692716 |
693717LL | let _x = false.then(|| x % 0);
694718 | ^^^^^^^^^^^^^^^^^^^^
......@@ -700,7 +724,7 @@ LL + let _x = false.then_some(x % 0);
700724 |
701725
702726error: unnecessary closure used with `bool::then`
703 --> tests/ui/unnecessary_lazy_eval.rs:306:14
727 --> tests/ui/unnecessary_lazy_eval.rs:318:14
704728 |
705729LL | let _x = false.then(|| 1 / -1);
706730 | ^^^^^^^^^^^^^^^^^^^^^
......@@ -712,7 +736,7 @@ LL + let _x = false.then_some(1 / -1);
712736 |
713737
714738error: unnecessary closure used with `bool::then`
715 --> tests/ui/unnecessary_lazy_eval.rs:308:14
739 --> tests/ui/unnecessary_lazy_eval.rs:320:14
716740 |
717741LL | let _x = false.then(|| i32::MIN / -1);
718742 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -724,7 +748,7 @@ LL + let _x = false.then_some(i32::MIN / -1);
724748 |
725749
726750error: unnecessary closure used with `bool::then`
727 --> tests/ui/unnecessary_lazy_eval.rs:311:14
751 --> tests/ui/unnecessary_lazy_eval.rs:323:14
728752 |
729753LL | let _x = false.then(|| i32::MIN / 0);
730754 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -736,7 +760,7 @@ LL + let _x = false.then_some(i32::MIN / 0);
736760 |
737761
738762error: unnecessary closure used with `bool::then`
739 --> tests/ui/unnecessary_lazy_eval.rs:313:14
763 --> tests/ui/unnecessary_lazy_eval.rs:325:14
740764 |
741765LL | let _x = false.then(|| 4 / 2);
742766 | ^^^^^^^^^^^^^^^^^^^^
......@@ -748,7 +772,7 @@ LL + let _x = false.then_some(4 / 2);
748772 |
749773
750774error: unnecessary closure used with `bool::then`
751 --> tests/ui/unnecessary_lazy_eval.rs:321:14
775 --> tests/ui/unnecessary_lazy_eval.rs:333:14
752776 |
753777LL | let _x = false.then(|| f1 + f2);
754778 | ^^^^^^^^^^^^^^^^^^^^^^
......@@ -759,5 +783,5 @@ LL - let _x = false.then(|| f1 + f2);
759783LL + let _x = false.then_some(f1 + f2);
760784 |
761785
762error: aborting due to 63 previous errors
786error: aborting due to 65 previous errors
763787
src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs+2-6
......@@ -12,6 +12,8 @@ fn main() {
1212 // fix will break type inference
1313 let _ = Ok(1).unwrap_or_else(|()| 2);
1414 //~^ unnecessary_lazy_evaluations
15 let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 });
16 //~^ unnecessary_lazy_evaluations
1517
1618 mod e {
1719 pub struct E;
......@@ -26,9 +28,3 @@ fn main() {
2628 let arr = [(Some(1),)];
2729 Some(&0).and_then(|&i| arr[i].0);
2830}
29
30fn 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);
1313 |
1414
1515error: 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 |
18LL | let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 });
19 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20 |
21help: use `unwrap_or` instead
22 |
23LL - let _ = Ok(1).unwrap_or_else(|()| -> i32 { 2 });
24LL + let _ = Ok(1).unwrap_or({ 2 } as i32);
25 |
26
27error: unnecessary closure used to substitute value for `Result::Err`
28 --> tests/ui/unnecessary_lazy_eval_unfixable.rs:21:13
1729 |
1830LL | let _ = Ok(1).unwrap_or_else(|e::E| 2);
1931 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -25,7 +37,7 @@ LL + let _ = Ok(1).unwrap_or(2);
2537 |
2638
2739error: 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
2941 |
3042LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2);
3143 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -36,17 +48,5 @@ LL - let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2);
3648LL + let _ = Ok(1).unwrap_or(2);
3749 |
3850
39error: unnecessary closure used with `bool::then`
40 --> tests/ui/unnecessary_lazy_eval_unfixable.rs:32:13
41 |
42LL | let _ = true.then(|| -> &[u8] { &[] });
43 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44 |
45help: use `then_some` instead
46 |
47LL - let _ = true.then(|| -> &[u8] { &[] });
48LL + let _ = true.then_some({ &[] });
49 |
50
5151error: aborting due to 4 previous errors
5252
src/tools/clippy/tests/ui/unnecessary_sort_by.fixed+4-4
......@@ -19,9 +19,9 @@ fn unnecessary_sort_by() {
1919 //~^ unnecessary_sort_by
2020 // Reverse examples
2121 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()));
2323 //~^ 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)));
2525 //~^ unnecessary_sort_by
2626 // Negative examples (shouldn't be changed)
2727 let c = &7;
......@@ -99,9 +99,9 @@ mod issue_6001 {
9999 args.sort_unstable_by_key(|a| a.name());
100100 //~^ unnecessary_sort_by
101101 // Reverse
102 args.sort_by_key(|b| std::cmp::Reverse(b.name()));
102 args.sort_by_key(|a| std::cmp::Reverse(a.name()));
103103 //~^ 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()));
105105 //~^ unnecessary_sort_by
106106 }
107107}
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()));
5757help: try
5858 |
5959LL - vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
60LL + vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs()));
60LL + vec.sort_by_key(|a| std::cmp::Reverse((a + 5).abs()));
6161 |
6262
6363error: consider using `sort_unstable_by_key`
......@@ -69,7 +69,7 @@ LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
6969help: try
7070 |
7171LL - vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
72LL + vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b)));
72LL + vec.sort_unstable_by_key(|a| std::cmp::Reverse(id(-a)));
7373 |
7474
7575error: consider using `sort_by_key`
......@@ -129,7 +129,7 @@ LL | args.sort_by(|a, b| b.name().cmp(&a.name()));
129129help: try
130130 |
131131LL - args.sort_by(|a, b| b.name().cmp(&a.name()));
132LL + args.sort_by_key(|b| std::cmp::Reverse(b.name()));
132LL + args.sort_by_key(|a| std::cmp::Reverse(a.name()));
133133 |
134134
135135error: consider using `sort_unstable_by_key`
......@@ -141,7 +141,7 @@ LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
141141help: try
142142 |
143143LL - args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
144LL + args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name()));
144LL + args.sort_unstable_by_key(|a| std::cmp::Reverse(a.name()));
145145 |
146146
147147error: 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> {
1515fn issue_11524_2() -> Vec<i32> {
1616 let mut vec = vec![1, 2, 3];
1717
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));
2020 //~^ unnecessary_sort_by
2121 vec
2222}
src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.rs+1-1
......@@ -15,7 +15,7 @@ fn issue_11524() -> Vec<i32> {
1515fn issue_11524_2() -> Vec<i32> {
1616 let mut vec = vec![1, 2, 3];
1717
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));`
1919 vec.sort_by(|a, b| (b + 1).cmp(&(a + 1)));
2020 //~^ unnecessary_sort_by
2121 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)));
2121help: try
2222 |
2323LL - vec.sort_by(|a, b| (b + 1).cmp(&(a + 1)));
24LL + vec.sort_by_key(|b| core::cmp::Reverse(b + 1));
24LL + vec.sort_by_key(|a| core::cmp::Reverse(a + 1));
2525 |
2626
2727error: aborting due to 2 previous errors
src/tools/clippy/tests/ui/unnecessary_trailing_comma.fixed+1-1
......@@ -26,9 +26,9 @@ fn simple() {
2626 println!{"Foo{{,}}"}; //~ unnecessary_trailing_comma
2727 println!{"Foo(,"}; //~ unnecessary_trailing_comma
2828 println!{"Foo[,"}; //~ unnecessary_trailing_comma
29 println!(concat!("Foo", "=", "{}"), 1); //~ unnecessary_trailing_comma
2930
3031 // This should eventually work, but requires more work
31 println!(concat!("Foo", "=", "{}"), 1,);
3232 println!("No params", /*"a,){ */);
3333 println!("No params" /* "a,){*/, /*"a,){ */);
3434
src/tools/clippy/tests/ui/unnecessary_trailing_comma.rs+1-1
......@@ -26,9 +26,9 @@ fn simple() {
2626 println!{"Foo{{,}}", }; //~ unnecessary_trailing_comma
2727 println!{"Foo(,", }; //~ unnecessary_trailing_comma
2828 println!{"Foo[,", }; //~ unnecessary_trailing_comma
29 println!(concat!("Foo", "=", "{}"), 1,); //~ unnecessary_trailing_comma
2930
3031 // This should eventually work, but requires more work
31 println!(concat!("Foo", "=", "{}"), 1,);
3232 println!("No params", /*"a,){ */);
3333 println!("No params" /* "a,){*/, /*"a,){ */);
3434
src/tools/clippy/tests/ui/unnecessary_trailing_comma.stderr+7-1
......@@ -115,5 +115,11 @@ error: unnecessary trailing comma
115115LL | println!{"Foo[,", };
116116 | ^^ help: remove the trailing comma
117117
118error: aborting due to 19 previous errors
118error: unnecessary trailing comma
119 --> tests/ui/unnecessary_trailing_comma.rs:29:42
120 |
121LL | println!(concat!("Foo", "=", "{}"), 1,);
122 | ^ help: remove the trailing comma
123
124error: aborting due to 20 previous errors
119125
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
5use proc_macros::{external, with_span};
6
7#[rustfmt::skip]
8use unnecessary_unwrap_unchecked_helper::{lol, kek};
9
10mod 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
20fn test_fn() -> Option<u32> {
21 Some(0)
22}
23
24unsafe fn test_fn_unchecked() -> u32 {
25 0
26}
27
28struct A;
29
30impl 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
48struct B;
49
50impl B {
51 fn b(&self) -> Option<u32> {
52 Some(0)
53 }
54}
55
56impl B {
57 unsafe fn b_unchecked(&self) -> u32 {
58 0
59 }
60}
61
62fn 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
5use proc_macros::{external, with_span};
6
7#[rustfmt::skip]
8use unnecessary_unwrap_unchecked_helper::{lol, kek};
9
10mod 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
20fn test_fn() -> Option<u32> {
21 Some(0)
22}
23
24unsafe fn test_fn_unchecked() -> u32 {
25 0
26}
27
28struct A;
29
30impl 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
48struct B;
49
50impl B {
51 fn b(&self) -> Option<u32> {
52 Some(0)
53 }
54}
55
56impl B {
57 unsafe fn b_unchecked(&self) -> u32 {
58 0
59 }
60}
61
62fn 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 @@
1error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists
2 --> tests/ui/unnecessary_unwrap_unchecked.rs:63:33
3 |
4LL | 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)]`
9help: use `std::str::from_utf8_unchecked` instead, and remove the call to `.unwrap_unchecked()`
10 |
11LL - let string_slice = unsafe { std::str::from_utf8(&[]).unwrap_unchecked() };
12LL + let string_slice = unsafe { std::str::from_utf8_unchecked(&[]) };
13 |
14
15error: usage of `unwrap_unchecked` when an `_unchecked` variant of the method exists
16 --> tests/ui/unnecessary_unwrap_unchecked.rs:65:22
17 |
18LL | let a = unsafe { A::a(&A).unwrap_unchecked() };
19 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
20 |
21help: use `A::a_unchecked` instead, and remove the call to `.unwrap_unchecked()`
22 |
23LL - let a = unsafe { A::a(&A).unwrap_unchecked() };
24LL + let a = unsafe { A::a_unchecked(&A) };
25 |
26
27error: usage of `unwrap_unchecked` when an `_unchecked` variant of the method exists
28 --> tests/ui/unnecessary_unwrap_unchecked.rs:69:9
29 |
30LL | a.a().unwrap_unchecked()
31 | ^^^^^^^^^^^^^^^^^^^^^^^^
32 |
33help: use `A::a_unchecked` instead, and remove the call to `.unwrap_unchecked()`
34 |
35LL - a.a().unwrap_unchecked()
36LL + a.a_unchecked()
37 |
38
39error: usage of `unwrap_unchecked` when an `_unchecked` variant of the associated function exists
40 --> tests/ui/unnecessary_unwrap_unchecked.rs:72:32
41 |
42LL | let an_assoc_fn = unsafe { A::an_assoc_fn().unwrap_unchecked() };
43 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44 |
45help: use `A::an_assoc_fn_unchecked` instead, and remove the call to `.unwrap_unchecked()`
46 |
47LL - let an_assoc_fn = unsafe { A::an_assoc_fn().unwrap_unchecked() };
48LL + let an_assoc_fn = unsafe { A::an_assoc_fn_unchecked() };
49 |
50
51error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists
52 --> tests/ui/unnecessary_unwrap_unchecked.rs:74:30
53 |
54LL | let extern_fn = unsafe { lol().unwrap_unchecked() };
55 | ^^^^^^^^^^^^^^^^^^^^^^^^
56 |
57help: use `unnecessary_unwrap_unchecked_helper::lol_unchecked` instead, and remove the call to `.unwrap_unchecked()`
58 |
59LL - let extern_fn = unsafe { lol().unwrap_unchecked() };
60LL + let extern_fn = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() };
61 |
62
63error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists
64 --> tests/ui/unnecessary_unwrap_unchecked.rs:76:40
65 |
66LL | let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol().unwrap_unchecked() };
67 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68 |
69help: use `unnecessary_unwrap_unchecked_helper::lol_unchecked` instead, and remove the call to `.unwrap_unchecked()`
70 |
71LL - let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol().unwrap_unchecked() };
72LL + let extern_fn_qualified = unsafe { unnecessary_unwrap_unchecked_helper::lol_unchecked() };
73 |
74
75error: usage of `unwrap_unchecked` when an `_unchecked` variant of the function exists
76 --> tests/ui/unnecessary_unwrap_unchecked.rs:78:29
77 |
78LL | let local_fn = unsafe { b::test_fn().unwrap_unchecked() };
79 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
80 |
81help: use `b::test_fn_unchecked` instead, and remove the call to `.unwrap_unchecked()`
82 |
83LL - let local_fn = unsafe { b::test_fn().unwrap_unchecked() };
84LL + let local_fn = unsafe { b::test_fn_unchecked() };
85 |
86
87error: aborting due to 7 previous errors
88
src/tools/clippy/triagebot.toml+5
......@@ -60,6 +60,11 @@ labels = ["S-waiting-on-concerns"]
6060[view-all-comments-link]
6161threshold = 20
6262
63# Allows `merge` and `delegate` commands for merging a PR
64# Documentation at: https://forge.rust-lang.org/triagebot/merge.html
65[merge]
66type = "merge-queue"
67
6368[notify-zulip."lint-nominated"]
6469zulip_stream = 577190 # #clippy/fcp
6570topic = "FCP rust-clippy#{number}: {title}"