From 88483bd4b7b525b5550ccaf0c5623732f5a13b7c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 23 Jan 2022 20:41:46 +0000 Subject: [PATCH 01/19] Replace `&mut DiagnosticBuilder`, in signatures, with `&mut Diagnostic`. --- clippy_lints/src/copies.rs | 4 ++-- clippy_lints/src/implicit_hasher.rs | 4 ++-- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 4 ++-- clippy_lints/src/new_without_default.rs | 2 +- clippy_utils/src/diagnostics.rs | 12 ++++++------ clippy_utils/src/sugg.rs | 6 +++--- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 8b79f1600aeb..a20aa12c9ff4 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -6,7 +6,7 @@ use clippy_utils::{ }; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -489,7 +489,7 @@ fn emit_branches_sharing_code_lint( add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit(); } - let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| { + let add_optional_msgs = |diag: &mut Diagnostic| { if add_expr_note { diag.note("The end suggestion probably needs some adjustments to use the expression result correctly"); } diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 5e4cde553b52..d5430a8c9175 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::collections::BTreeMap; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { fn suggestion<'tcx>( cx: &LateContext<'tcx>, - diag: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, generics_span: Span, generics_suggestion_span: Span, target: &ImplicitHasherType<'_>, diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index df69d3dcc516..dd7177e0131c 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -1,7 +1,7 @@ //! checks for `#[inline]` on trait methods without bodies use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::sugg::DiagnosticBuilderExt; +use clippy_utils::sugg::DiagnosticExt; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index ebd4fb0bf51c..91d7274f5f5a 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -6,7 +6,7 @@ use clippy_utils::{get_trait_def_id, is_self, paths}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::FnKind; use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind}; use rustc_hir::{HirIdMap, HirIdSet}; @@ -196,7 +196,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } // Dereference suggestion - let sugg = |diag: &mut DiagnosticBuilder<'_>| { + let sugg = |diag: &mut Diagnostic| { if let ty::Adt(def, ..) = ty.kind() { if let Some(span) = cx.tcx.hir().span_if_local(def.did) { if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() { diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index f86af7a7bb6e..4cb79648ae36 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::return_ty; use clippy_utils::source::snippet; -use clippy_utils::sugg::DiagnosticBuilderExt; +use clippy_utils::sugg::DiagnosticExt; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index ca222c3d6699..a927788e6a44 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -8,13 +8,13 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::source_map::{MultiSpan, Span}; use std::env; -fn docs_link(diag: &mut DiagnosticBuilder<'_>, lint: &'static Lint) { +fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() { if let Some(lint) = lint.name_lower().strip_prefix("clippy::") { diag.help(&format!( @@ -145,7 +145,7 @@ pub fn span_lint_and_then(cx: &C, lint: &'static Lint, sp: S, msg: &str where C: LintContext, S: Into, - F: FnOnce(&mut DiagnosticBuilder<'_>), + F: FnOnce(&mut Diagnostic), { cx.struct_span_lint(lint, sp, |diag| { let mut diag = diag.build(msg); @@ -169,7 +169,7 @@ pub fn span_lint_hir_and_then( hir_id: HirId, sp: impl Into, msg: &str, - f: impl FnOnce(&mut DiagnosticBuilder<'_>), + f: impl FnOnce(&mut Diagnostic), ) { cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| { let mut diag = diag.build(msg); @@ -219,7 +219,7 @@ pub fn span_lint_and_sugg<'a, T: LintContext>( /// appear once per /// replacement. In human-readable format though, it only appears once before /// the whole suggestion. -pub fn multispan_sugg(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: I) +pub fn multispan_sugg(diag: &mut Diagnostic, help_msg: &str, sugg: I) where I: IntoIterator, { @@ -232,7 +232,7 @@ where /// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141). /// Suggestions with multiple spans will be silently ignored. pub fn multispan_sugg_with_applicability( - diag: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, help_msg: &str, applicability: Applicability, sugg: I, diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index fa63ddff253c..63c442e70085 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -673,8 +673,8 @@ fn indentation(cx: &T, span: Span) -> Option { }) } -/// Convenience extension trait for `DiagnosticBuilder`. -pub trait DiagnosticBuilderExt { +/// Convenience extension trait for `Diagnostic`. +pub trait DiagnosticExt { /// Suggests to add an attribute to an item. /// /// Correctly handles indentation of the attribute and item. @@ -721,7 +721,7 @@ pub trait DiagnosticBuilderExt { fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability); } -impl DiagnosticBuilderExt for rustc_errors::DiagnosticBuilder<'_> { +impl DiagnosticExt for rustc_errors::Diagnostic { fn suggest_item_with_attr( &mut self, cx: &T, From 881b8cb704c20b8ac550329b980c241a246cbd50 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 26 Jan 2022 03:39:14 +0000 Subject: [PATCH 02/19] rustc_errors: take `self` by value in `DiagnosticBuilder::cancel`. --- clippy_lints/src/doc.rs | 6 ++---- clippy_lints/src/write.rs | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index a00361e6062a..16173580fd46 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -628,9 +628,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, Err(errs) => { - for mut err in errs { - err.cancel(); - } + drop(errs); return false; }, }; @@ -668,7 +666,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { _ => {}, }, Ok(None) => break, - Err(mut e) => { + Err(e) => { e.cancel(); return false; }, diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 1fa6301ebd73..a328ddda5ae7 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -534,7 +534,7 @@ impl Write { match parser .parse_expr() .map(rustc_ast::ptr::P::into_inner) - .map_err(|mut e| e.cancel()) + .map_err(|e| e.cancel()) { // write!(e, ...) Ok(p) if parser.eat(&token::Comma) => Some(p), @@ -563,7 +563,7 @@ impl Write { } let comma_span = parser.prev_token.span; - let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|mut err| err.cancel()) { + let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|err| err.cancel()) { expr } else { return (Some(fmtstr), None); From 676943a9f9a2e0b5978e9783130c7dc6a9ffb5cf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Feb 2022 13:03:28 -0800 Subject: [PATCH 03/19] better ObligationCause for normalization errors in can_type_implement_copy --- clippy_lints/src/needless_pass_by_value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index ebd4fb0bf51c..d27e1383d012 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let sugg = |diag: &mut DiagnosticBuilder<'_>| { if let ty::Adt(def, ..) = ty.kind() { if let Some(span) = cx.tcx.hir().span_if_local(def.did) { - if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() { + if can_type_implement_copy(cx.tcx, cx.param_env, ty, traits::ObligationCause::dummy_with_span(span)).is_ok() { diag.span_help(span, "consider marking this type as `Copy`"); } } From 83d32701f2f1571d76c34e992009aa73d062666a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Dec 2021 19:52:23 +0800 Subject: [PATCH 04/19] resolve: Fix incorrect results of `opt_def_kind` query for some built-in macros Previously it always returned `MacroKind::Bang` while some of those macros are actually attributes and derives --- clippy_lints/src/utils/inspector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 869114831370..dc48ea3f4f99 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -373,7 +373,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { let item_ty = cx.tcx.type_of(did); println!("function of type {:#?}", item_ty); }, - hir::ItemKind::Macro(ref macro_def) => { + hir::ItemKind::Macro(ref macro_def, _) => { if macro_def.macro_rules { println!("macro introduced by `macro_rules!`"); } else { From a30eba2c7e066da9e35f3404d547f535fd5581cd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 5 Feb 2022 10:07:13 +0800 Subject: [PATCH 05/19] Update clippy tests --- tests/ui/macro_use_imports.fixed | 2 +- tests/ui/macro_use_imports.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index 306ea50258da..a83c8ba0b642 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -15,7 +15,7 @@ extern crate macro_use_helper as mac; extern crate proc_macro_derive as mini_mac; mod a { - use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro}; + use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro}; use mac; use mini_mac::ClippyMiniMacroTest; use mini_mac; diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr index f8c86c8d9179..9028a636e7f7 100644 --- a/tests/ui/macro_use_imports.stderr +++ b/tests/ui/macro_use_imports.stderr @@ -2,7 +2,7 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:18:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro};` | = note: `-D clippy::macro-use-imports` implied by `-D warnings` From 307966fbb2742d2542a62d9dd869d10086b56f01 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 23 Feb 2022 08:06:22 -0500 Subject: [PATCH 06/19] Switch bootstrap cfgs --- clippy_lints/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5c45012ef068..85256ff0e995 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -18,7 +18,7 @@ // warn on rustc internal lints #![warn(rustc::internal)] // Disable this rustc lint for now, as it was also done in rustc -#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] +#![allow(rustc::potential_query_instability)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) From 35020280a05d82117c6796db8c63debbb8a76837 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sat, 26 Feb 2022 14:26:21 +0100 Subject: [PATCH 07/19] Merge commit 'e329249b6a3a98830d860c74c8234a8dd9407436' into clippyup --- CHANGELOG.md | 9 +- Cargo.toml | 3 +- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/await_holding_invalid.rs | 119 +++++-- clippy_lints/src/cargo/common_metadata.rs | 54 +++ clippy_lints/src/cargo/feature_name.rs | 92 +++++ clippy_lints/src/cargo/mod.rs | 221 ++++++++++++ .../src/cargo/multiple_crate_versions.rs | 63 ++++ .../src/cargo/wildcard_dependencies.rs | 27 ++ clippy_lints/src/cargo_common_metadata.rs | 118 ------- .../src/casts/cast_possible_truncation.rs | 68 +++- clippy_lints/src/casts/cast_ptr_alignment.rs | 18 +- clippy_lints/src/casts/mod.rs | 28 +- clippy_lints/src/casts/utils.rs | 52 ++- clippy_lints/src/dbg_macro.rs | 97 +++--- clippy_lints/src/default.rs | 16 +- clippy_lints/src/derive.rs | 7 +- clippy_lints/src/drop_forget_ref.rs | 38 ++- clippy_lints/src/duration_subsec.rs | 11 +- clippy_lints/src/eq_op.rs | 10 +- clippy_lints/src/eta_reduction.rs | 7 + clippy_lints/src/feature_name.rs | 166 --------- clippy_lints/src/format_args.rs | 26 +- clippy_lints/src/format_impl.rs | 253 ++++++++++++++ clippy_lints/src/infinite_iter.rs | 11 +- clippy_lints/src/large_enum_variant.rs | 50 ++- clippy_lints/src/lib.register_all.rs | 7 +- clippy_lints/src/lib.register_cargo.rs | 10 +- clippy_lints/src/lib.register_correctness.rs | 3 +- clippy_lints/src/lib.register_lints.rs | 15 +- clippy_lints/src/lib.register_nursery.rs | 1 - clippy_lints/src/lib.register_pedantic.rs | 2 - clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 4 + clippy_lints/src/lib.rs | 25 +- clippy_lints/src/manual_bits.rs | 5 +- .../src/matches/match_like_matches.rs | 45 +-- clippy_lints/src/matches/match_same_arms.rs | 152 ++++----- .../src/matches/match_single_binding.rs | 19 +- clippy_lints/src/matches/mod.rs | 144 ++++++-- .../src/matches/redundant_pattern_match.rs | 14 +- clippy_lints/src/mem_forget.rs | 4 +- clippy_lints/src/mem_replace.rs | 4 +- .../src/methods/uninit_assumed_init.rs | 5 +- clippy_lints/src/minmax.rs | 15 +- clippy_lints/src/multiple_crate_versions.rs | 101 ------ clippy_lints/src/new_without_default.rs | 14 +- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 124 +++++-- clippy_lints/src/size_of_in_element_count.rs | 4 +- clippy_lints/src/to_string_in_display.rs | 123 ------- clippy_lints/src/trait_bounds.rs | 5 +- clippy_lints/src/transmute/mod.rs | 5 +- .../src/transmute/transmute_undefined_repr.rs | 134 +++++--- clippy_lints/src/types/borrowed_box.rs | 4 +- clippy_lints/src/undropped_manually_drops.rs | 12 +- clippy_lints/src/utils/internal_lints.rs | 2 +- clippy_lints/src/wildcard_dependencies.rs | 57 ---- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/lib.rs | 19 +- clippy_utils/src/macros.rs | 27 ++ clippy_utils/src/paths.rs | 46 +-- clippy_utils/src/ty.rs | 73 +++- rust-toolchain | 2 +- tests/compile-test.rs | 5 + tests/ui/auxiliary/macro_rules.rs | 7 + tests/ui/await_holding_lock.rs | 206 ++++++++--- tests/ui/await_holding_lock.stderr | 215 ++++++++++-- tests/ui/await_holding_refcell_ref.stderr | 30 +- tests/ui/cast.rs | 136 ++++++++ tests/ui/cast.stderr | 94 +++-- tests/ui/dbg_macro.rs | 23 ++ tests/ui/dbg_macro.stderr | 35 +- tests/ui/default_trait_access.fixed | 15 +- tests/ui/default_trait_access.rs | 15 +- tests/ui/deref_by_slicing.fixed | 29 ++ tests/ui/deref_by_slicing.rs | 29 ++ tests/ui/deref_by_slicing.stderr | 58 ++++ tests/ui/eta.fixed | 19 ++ tests/ui/eta.rs | 19 ++ tests/ui/large_enum_variant.rs | 24 ++ tests/ui/large_enum_variant.stderr | 18 +- tests/ui/match_as_ref.fixed | 10 +- tests/ui/match_as_ref.rs | 10 +- tests/ui/match_bool.rs | 8 + tests/ui/match_expr_like_matches_macro.fixed | 15 + tests/ui/match_expr_like_matches_macro.rs | 15 + tests/ui/match_same_arms2.rs | 10 +- tests/ui/match_single_binding.fixed | 8 +- tests/ui/match_single_binding.rs | 3 +- tests/ui/match_single_binding.stderr | 11 +- tests/ui/new_without_default.rs | 26 ++ tests/ui/new_without_default.stderr | 8 +- tests/ui/print_in_format_impl.rs | 58 ++++ tests/ui/print_in_format_impl.stderr | 46 +++ tests/ui/ptr_arg.rs | 8 + tests/ui/ptr_as_ptr.fixed | 15 + tests/ui/ptr_as_ptr.rs | 15 + tests/ui/ptr_as_ptr.stderr | 27 +- tests/ui/recursive_format_impl.rs | 321 ++++++++++++++++++ tests/ui/recursive_format_impl.stderr | 91 +++++ tests/ui/redundant_slicing.fixed | 46 +++ tests/ui/redundant_slicing.rs | 28 +- tests/ui/redundant_slicing.stderr | 26 +- tests/ui/rename.fixed | 2 + tests/ui/rename.rs | 2 + tests/ui/rename.stderr | 74 ++-- tests/ui/single_match.rs | 8 + tests/ui/to_string_in_display.rs | 69 ---- tests/ui/to_string_in_display.stderr | 19 -- tests/ui/transmute_undefined_repr.rs | 85 +++-- tests/ui/transmute_undefined_repr.stderr | 62 ++-- 113 files changed, 3461 insertions(+), 1441 deletions(-) create mode 100644 clippy_lints/src/cargo/common_metadata.rs create mode 100644 clippy_lints/src/cargo/feature_name.rs create mode 100644 clippy_lints/src/cargo/mod.rs create mode 100644 clippy_lints/src/cargo/multiple_crate_versions.rs create mode 100644 clippy_lints/src/cargo/wildcard_dependencies.rs delete mode 100644 clippy_lints/src/cargo_common_metadata.rs delete mode 100644 clippy_lints/src/feature_name.rs create mode 100644 clippy_lints/src/format_impl.rs delete mode 100644 clippy_lints/src/multiple_crate_versions.rs delete mode 100644 clippy_lints/src/to_string_in_display.rs delete mode 100644 clippy_lints/src/wildcard_dependencies.rs create mode 100644 tests/ui/deref_by_slicing.fixed create mode 100644 tests/ui/deref_by_slicing.rs create mode 100644 tests/ui/deref_by_slicing.stderr create mode 100644 tests/ui/print_in_format_impl.rs create mode 100644 tests/ui/print_in_format_impl.stderr create mode 100644 tests/ui/recursive_format_impl.rs create mode 100644 tests/ui/recursive_format_impl.stderr create mode 100644 tests/ui/redundant_slicing.fixed delete mode 100644 tests/ui/to_string_in_display.rs delete mode 100644 tests/ui/to_string_in_display.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index c9adf77c0d63..35983b7fb506 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1438,7 +1438,7 @@ Released 2020-11-19 * [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038) * [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998) * [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044) -* [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831) +* `to_string_in_display` [#5831](https://github.com/rust-lang/rust-clippy/pull/5831) * `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881) ### Moves and Deprecations @@ -1481,7 +1481,7 @@ Released 2020-11-19 [#5949](https://github.com/rust-lang/rust-clippy/pull/5949) * [`doc_markdown`]: allow using "GraphQL" without backticks [#5996](https://github.com/rust-lang/rust-clippy/pull/5996) -* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` +* `to_string_in_display`: avoid linting when calling `to_string()` on anything that is not `self` [#5971](https://github.com/rust-lang/rust-clippy/pull/5971) * [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays [#6034](https://github.com/rust-lang/rust-clippy/pull/6034) @@ -3068,6 +3068,7 @@ Released 2018-09-13 [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata [`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons +[`cast_enum_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_truncation [`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless [`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation [`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap @@ -3105,6 +3106,7 @@ Released 2018-09-13 [`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr [`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof +[`deref_by_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_by_slicing [`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord @@ -3368,6 +3370,7 @@ Released 2018-09-13 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence +[`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal [`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr [`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout @@ -3385,6 +3388,7 @@ Released 2018-09-13 [`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len [`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex +[`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation [`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure @@ -3459,7 +3463,6 @@ Released 2018-09-13 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some -[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments diff --git a/Cargo.toml b/Cargo.toml index e445889a58f7..5cc5530f874d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.60" +version = "0.1.61" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -50,6 +50,7 @@ syn = { version = "1.0", features = ["full"] } futures = "0.3" parking_lot = "0.11.2" tokio = { version = "1", features = ["io-util"] } +num_cpus = "1.13" [build-dependencies] rustc_tools_util = { version = "0.2", path = "rustc_tools_util" } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 2053ca64ba23..40d7dd702628 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.60" +version = "0.1.61" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 1cc3418d4748..f0979840ff8d 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_hir::def_id::DefId; use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind}; @@ -9,8 +9,7 @@ use rustc_span::Span; declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a - /// non-async-aware MutexGuard. + /// Checks for calls to await while holding a non-async-aware MutexGuard. /// /// ### Why is this bad? /// The Mutex types found in std::sync and parking_lot @@ -22,41 +21,57 @@ declare_clippy_lint! { /// either by introducing a scope or an explicit call to Drop::drop. /// /// ### Known problems - /// Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). + /// Will report false positive for explicitly dropped guards + /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is + /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard. /// /// ### Example - /// ```rust,ignore - /// use std::sync::Mutex; - /// + /// ```rust + /// # use std::sync::Mutex; + /// # async fn baz() {} /// async fn foo(x: &Mutex) { - /// let guard = x.lock().unwrap(); + /// let mut guard = x.lock().unwrap(); /// *guard += 1; - /// bar.await; + /// baz().await; + /// } + /// + /// async fn bar(x: &Mutex) { + /// let mut guard = x.lock().unwrap(); + /// *guard += 1; + /// drop(guard); // explicit drop + /// baz().await; /// } /// ``` /// /// Use instead: - /// ```rust,ignore - /// use std::sync::Mutex; - /// + /// ```rust + /// # use std::sync::Mutex; + /// # async fn baz() {} /// async fn foo(x: &Mutex) { /// { - /// let guard = x.lock().unwrap(); + /// let mut guard = x.lock().unwrap(); /// *guard += 1; /// } - /// bar.await; + /// baz().await; + /// } + /// + /// async fn bar(x: &Mutex) { + /// { + /// let mut guard = x.lock().unwrap(); + /// *guard += 1; + /// } // guard dropped here at end of scope + /// baz().await; /// } /// ``` #[clippy::version = "1.45.0"] pub AWAIT_HOLDING_LOCK, - pedantic, - "Inside an async function, holding a MutexGuard while calling await" + suspicious, + "inside an async function, holding a `MutexGuard` while calling `await`" } declare_clippy_lint! { /// ### What it does - /// Checks for calls to await while holding a - /// `RefCell` `Ref` or `RefMut`. + /// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`. /// /// ### Why is this bad? /// `RefCell` refs only check for exclusive mutable access @@ -64,35 +79,52 @@ declare_clippy_lint! { /// risks panics from a mutable ref shared while other refs are outstanding. /// /// ### Known problems - /// Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). + /// Will report false positive for explicitly dropped refs + /// ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is + /// to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref. /// /// ### Example - /// ```rust,ignore - /// use std::cell::RefCell; - /// + /// ```rust + /// # use std::cell::RefCell; + /// # async fn baz() {} /// async fn foo(x: &RefCell) { /// let mut y = x.borrow_mut(); /// *y += 1; - /// bar.await; + /// baz().await; + /// } + /// + /// async fn bar(x: &RefCell) { + /// let mut y = x.borrow_mut(); + /// *y += 1; + /// drop(y); // explicit drop + /// baz().await; /// } /// ``` /// /// Use instead: - /// ```rust,ignore - /// use std::cell::RefCell; - /// + /// ```rust + /// # use std::cell::RefCell; + /// # async fn baz() {} /// async fn foo(x: &RefCell) { /// { /// let mut y = x.borrow_mut(); /// *y += 1; /// } - /// bar.await; + /// baz().await; + /// } + /// + /// async fn bar(x: &RefCell) { + /// { + /// let mut y = x.borrow_mut(); + /// *y += 1; + /// } // y dropped here at end of scope + /// baz().await; /// } /// ``` #[clippy::version = "1.49.0"] pub AWAIT_HOLDING_REFCELL_REF, - pedantic, - "Inside an async function, holding a RefCell ref while calling await" + suspicious, + "inside an async function, holding a `RefCell` ref while calling `await`" } declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]); @@ -118,23 +150,36 @@ fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorType for ty_cause in ty_causes { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { if is_mutex_guard(cx, adt.did) { - span_lint_and_note( + span_lint_and_then( cx, AWAIT_HOLDING_LOCK, ty_cause.span, - "this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await", - ty_cause.scope_span.or(Some(span)), - "these are all the await points this lock is held through", + "this `MutexGuard` is held across an `await` point", + |diag| { + diag.help( + "consider using an async-aware `Mutex` type or ensuring the \ + `MutexGuard` is dropped before calling await", + ); + diag.span_note( + ty_cause.scope_span.unwrap_or(span), + "these are all the `await` points this lock is held through", + ); + }, ); } if is_refcell_ref(cx, adt.did) { - span_lint_and_note( + span_lint_and_then( cx, AWAIT_HOLDING_REFCELL_REF, ty_cause.span, - "this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await", - ty_cause.scope_span.or(Some(span)), - "these are all the await points this ref is held through", + "this `RefCell` reference is held across an `await` point", + |diag| { + diag.help("ensure the reference is dropped before calling `await`"); + diag.span_note( + ty_cause.scope_span.unwrap_or(span), + "these are all the `await` points this reference is held through", + ); + }, ); } } diff --git a/clippy_lints/src/cargo/common_metadata.rs b/clippy_lints/src/cargo/common_metadata.rs new file mode 100644 index 000000000000..e0442dda479d --- /dev/null +++ b/clippy_lints/src/cargo/common_metadata.rs @@ -0,0 +1,54 @@ +//! lint on missing cargo common metadata + +use cargo_metadata::Metadata; +use clippy_utils::diagnostics::span_lint; +use rustc_lint::LateContext; +use rustc_span::source_map::DUMMY_SP; + +use super::CARGO_COMMON_METADATA; + +pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: bool) { + for package in &metadata.packages { + // only run the lint if publish is `None` (`publish = true` or skipped entirely) + // or if the vector isn't empty (`publish = ["something"]`) + if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || ignore_publish { + if is_empty_str(&package.description) { + missing_warning(cx, package, "package.description"); + } + + if is_empty_str(&package.license) && is_empty_str(&package.license_file) { + missing_warning(cx, package, "either package.license or package.license_file"); + } + + if is_empty_str(&package.repository) { + missing_warning(cx, package, "package.repository"); + } + + if is_empty_str(&package.readme) { + missing_warning(cx, package, "package.readme"); + } + + if is_empty_vec(&package.keywords) { + missing_warning(cx, package, "package.keywords"); + } + + if is_empty_vec(&package.categories) { + missing_warning(cx, package, "package.categories"); + } + } + } +} + +fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { + let message = format!("package `{}` is missing `{}` metadata", package.name, field); + span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); +} + +fn is_empty_str>(value: &Option) -> bool { + value.as_ref().map_or(true, |s| s.as_ref().is_empty()) +} + +fn is_empty_vec(value: &[String]) -> bool { + // This works because empty iterators return true + value.iter().all(String::is_empty) +} diff --git a/clippy_lints/src/cargo/feature_name.rs b/clippy_lints/src/cargo/feature_name.rs new file mode 100644 index 000000000000..79a469a4258b --- /dev/null +++ b/clippy_lints/src/cargo/feature_name.rs @@ -0,0 +1,92 @@ +use cargo_metadata::Metadata; +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_lint::LateContext; +use rustc_span::source_map::DUMMY_SP; + +use super::{NEGATIVE_FEATURE_NAMES, REDUNDANT_FEATURE_NAMES}; + +static PREFIXES: [&str; 8] = ["no-", "no_", "not-", "not_", "use-", "use_", "with-", "with_"]; +static SUFFIXES: [&str; 2] = ["-support", "_support"]; + +pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { + for package in &metadata.packages { + let mut features: Vec<&String> = package.features.keys().collect(); + features.sort(); + for feature in features { + let prefix_opt = { + let i = PREFIXES.partition_point(|prefix| prefix < &feature.as_str()); + if i > 0 && feature.starts_with(PREFIXES[i - 1]) { + Some(PREFIXES[i - 1]) + } else { + None + } + }; + if let Some(prefix) = prefix_opt { + lint(cx, feature, prefix, true); + } + + let suffix_opt: Option<&str> = { + let i = SUFFIXES.partition_point(|suffix| { + suffix.bytes().rev().cmp(feature.bytes().rev()) == std::cmp::Ordering::Less + }); + if i > 0 && feature.ends_with(SUFFIXES[i - 1]) { + Some(SUFFIXES[i - 1]) + } else { + None + } + }; + if let Some(suffix) = suffix_opt { + lint(cx, feature, suffix, false); + } + } + } +} + +fn is_negative_prefix(s: &str) -> bool { + s.starts_with("no") +} + +fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) { + let is_negative = is_prefix && is_negative_prefix(substring); + span_lint_and_help( + cx, + if is_negative { + NEGATIVE_FEATURE_NAMES + } else { + REDUNDANT_FEATURE_NAMES + }, + DUMMY_SP, + &format!( + "the \"{}\" {} in the feature name \"{}\" is {}", + substring, + if is_prefix { "prefix" } else { "suffix" }, + feature, + if is_negative { "negative" } else { "redundant" } + ), + None, + &format!( + "consider renaming the feature to \"{}\"{}", + if is_prefix { + feature.strip_prefix(substring) + } else { + feature.strip_suffix(substring) + } + .unwrap(), + if is_negative { + ", but make sure the feature adds functionality" + } else { + "" + } + ), + ); +} + +#[test] +fn test_prefixes_sorted() { + let mut sorted_prefixes = PREFIXES; + sorted_prefixes.sort_unstable(); + assert_eq!(PREFIXES, sorted_prefixes); + let mut sorted_suffixes = SUFFIXES; + sorted_suffixes.sort_by(|a, b| a.bytes().rev().cmp(b.bytes().rev())); + assert_eq!(SUFFIXES, sorted_suffixes); +} diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs new file mode 100644 index 000000000000..abe95c6663f7 --- /dev/null +++ b/clippy_lints/src/cargo/mod.rs @@ -0,0 +1,221 @@ +use cargo_metadata::MetadataCommand; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_lint_allowed; +use rustc_hir::hir_id::CRATE_HIR_ID; +use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::DUMMY_SP; + +mod common_metadata; +mod feature_name; +mod multiple_crate_versions; +mod wildcard_dependencies; + +declare_clippy_lint! { + /// ### What it does + /// Checks to see if all common metadata is defined in + /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata + /// + /// ### Why is this bad? + /// It will be more difficult for users to discover the + /// purpose of the crate, and key information related to it. + /// + /// ### Example + /// ```toml + /// # This `Cargo.toml` is missing a description field: + /// [package] + /// name = "clippy" + /// version = "0.0.212" + /// repository = "https://github.com/rust-lang/rust-clippy" + /// readme = "README.md" + /// license = "MIT OR Apache-2.0" + /// keywords = ["clippy", "lint", "plugin"] + /// categories = ["development-tools", "development-tools::cargo-plugins"] + /// ``` + /// + /// Should include a description field like: + /// + /// ```toml + /// # This `Cargo.toml` includes all common metadata + /// [package] + /// name = "clippy" + /// version = "0.0.212" + /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" + /// repository = "https://github.com/rust-lang/rust-clippy" + /// readme = "README.md" + /// license = "MIT OR Apache-2.0" + /// keywords = ["clippy", "lint", "plugin"] + /// categories = ["development-tools", "development-tools::cargo-plugins"] + /// ``` + #[clippy::version = "1.32.0"] + pub CARGO_COMMON_METADATA, + cargo, + "common metadata is defined in `Cargo.toml`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for feature names with prefix `use-`, `with-` or suffix `-support` + /// + /// ### Why is this bad? + /// These prefixes and suffixes have no significant meaning. + /// + /// ### Example + /// ```toml + /// # The `Cargo.toml` with feature name redundancy + /// [features] + /// default = ["use-abc", "with-def", "ghi-support"] + /// use-abc = [] // redundant + /// with-def = [] // redundant + /// ghi-support = [] // redundant + /// ``` + /// + /// Use instead: + /// ```toml + /// [features] + /// default = ["abc", "def", "ghi"] + /// abc = [] + /// def = [] + /// ghi = [] + /// ``` + /// + #[clippy::version = "1.57.0"] + pub REDUNDANT_FEATURE_NAMES, + cargo, + "usage of a redundant feature name" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for negative feature names with prefix `no-` or `not-` + /// + /// ### Why is this bad? + /// Features are supposed to be additive, and negatively-named features violate it. + /// + /// ### Example + /// ```toml + /// # The `Cargo.toml` with negative feature names + /// [features] + /// default = [] + /// no-abc = [] + /// not-def = [] + /// + /// ``` + /// Use instead: + /// ```toml + /// [features] + /// default = ["abc", "def"] + /// abc = [] + /// def = [] + /// + /// ``` + #[clippy::version = "1.57.0"] + pub NEGATIVE_FEATURE_NAMES, + cargo, + "usage of a negative feature name" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks to see if multiple versions of a crate are being + /// used. + /// + /// ### Why is this bad? + /// This bloats the size of targets, and can lead to + /// confusing error messages when structs or traits are used interchangeably + /// between different versions of a crate. + /// + /// ### Known problems + /// Because this can be caused purely by the dependencies + /// themselves, it's not always possible to fix this issue. + /// + /// ### Example + /// ```toml + /// # This will pull in both winapi v0.3.x and v0.2.x, triggering a warning. + /// [dependencies] + /// ctrlc = "=3.1.0" + /// ansi_term = "=0.11.0" + /// ``` + #[clippy::version = "pre 1.29.0"] + pub MULTIPLE_CRATE_VERSIONS, + cargo, + "multiple versions of the same crate being used" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for wildcard dependencies in the `Cargo.toml`. + /// + /// ### Why is this bad? + /// [As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html), + /// it is highly unlikely that you work with any possible version of your dependency, + /// and wildcard dependencies would cause unnecessary breakage in the ecosystem. + /// + /// ### Example + /// ```toml + /// [dependencies] + /// regex = "*" + /// ``` + #[clippy::version = "1.32.0"] + pub WILDCARD_DEPENDENCIES, + cargo, + "wildcard dependencies being used" +} + +pub struct Cargo { + pub ignore_publish: bool, +} + +impl_lint_pass!(Cargo => [ + CARGO_COMMON_METADATA, + REDUNDANT_FEATURE_NAMES, + NEGATIVE_FEATURE_NAMES, + MULTIPLE_CRATE_VERSIONS, + WILDCARD_DEPENDENCIES +]); + +impl LateLintPass<'_> for Cargo { + fn check_crate(&mut self, cx: &LateContext<'_>) { + static NO_DEPS_LINTS: &[&Lint] = &[ + CARGO_COMMON_METADATA, + REDUNDANT_FEATURE_NAMES, + NEGATIVE_FEATURE_NAMES, + WILDCARD_DEPENDENCIES, + ]; + static WITH_DEPS_LINTS: &[&Lint] = &[MULTIPLE_CRATE_VERSIONS]; + + if !NO_DEPS_LINTS + .iter() + .all(|&lint| is_lint_allowed(cx, lint, CRATE_HIR_ID)) + { + match MetadataCommand::new().no_deps().exec() { + Ok(metadata) => { + common_metadata::check(cx, &metadata, self.ignore_publish); + feature_name::check(cx, &metadata); + wildcard_dependencies::check(cx, &metadata); + }, + Err(e) => { + for lint in NO_DEPS_LINTS { + span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e)); + } + }, + } + } + + if !WITH_DEPS_LINTS + .iter() + .all(|&lint| is_lint_allowed(cx, lint, CRATE_HIR_ID)) + { + match MetadataCommand::new().exec() { + Ok(metadata) => { + multiple_crate_versions::check(cx, &metadata); + }, + Err(e) => { + for lint in WITH_DEPS_LINTS { + span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e)); + } + }, + } + } + } +} diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs new file mode 100644 index 000000000000..76fd0819a39a --- /dev/null +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -0,0 +1,63 @@ +//! lint on multiple versions of a crate being used + +use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId}; +use clippy_utils::diagnostics::span_lint; +use if_chain::if_chain; +use itertools::Itertools; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_lint::LateContext; +use rustc_span::source_map::DUMMY_SP; + +use super::MULTIPLE_CRATE_VERSIONS; + +pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { + let local_name = cx.tcx.crate_name(LOCAL_CRATE); + let mut packages = metadata.packages.clone(); + packages.sort_by(|a, b| a.name.cmp(&b.name)); + + if_chain! { + if let Some(resolve) = &metadata.resolve; + if let Some(local_id) = packages + .iter() + .find_map(|p| if p.name == local_name.as_str() { Some(&p.id) } else { None }); + then { + for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { + let group: Vec<&Package> = group.collect(); + + if group.len() <= 1 { + continue; + } + + if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) { + let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect(); + versions.sort(); + let versions = versions.iter().join(", "); + + span_lint( + cx, + MULTIPLE_CRATE_VERSIONS, + DUMMY_SP, + &format!("multiple versions for dependency `{}`: {}", name, versions), + ); + } + } + } + } +} + +fn is_normal_dep(nodes: &[Node], local_id: &PackageId, dep_id: &PackageId) -> bool { + fn depends_on(node: &Node, dep_id: &PackageId) -> bool { + node.deps.iter().any(|dep| { + dep.pkg == *dep_id + && dep + .dep_kinds + .iter() + .any(|info| matches!(info.kind, DependencyKind::Normal)) + }) + } + + nodes + .iter() + .filter(|node| depends_on(node, dep_id)) + .any(|node| node.id == *local_id || is_normal_dep(nodes, local_id, &node.id)) +} diff --git a/clippy_lints/src/cargo/wildcard_dependencies.rs b/clippy_lints/src/cargo/wildcard_dependencies.rs new file mode 100644 index 000000000000..7fa6acbf557b --- /dev/null +++ b/clippy_lints/src/cargo/wildcard_dependencies.rs @@ -0,0 +1,27 @@ +use cargo_metadata::Metadata; +use clippy_utils::diagnostics::span_lint; +use if_chain::if_chain; +use rustc_lint::LateContext; +use rustc_span::source_map::DUMMY_SP; + +use super::WILDCARD_DEPENDENCIES; + +pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { + for dep in &metadata.packages[0].dependencies { + // VersionReq::any() does not work + if_chain! { + if let Ok(wildcard_ver) = semver::VersionReq::parse("*"); + if let Some(ref source) = dep.source; + if !source.starts_with("git"); + if dep.req == wildcard_ver; + then { + span_lint( + cx, + WILDCARD_DEPENDENCIES, + DUMMY_SP, + &format!("wildcard dependency for `{}`", dep.name), + ); + } + } + } +} diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs deleted file mode 100644 index 23f79fdc6823..000000000000 --- a/clippy_lints/src/cargo_common_metadata.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! lint on missing cargo common metadata - -use clippy_utils::{diagnostics::span_lint, is_lint_allowed}; -use rustc_hir::hir_id::CRATE_HIR_ID; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::DUMMY_SP; - -declare_clippy_lint! { - /// ### What it does - /// Checks to see if all common metadata is defined in - /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata - /// - /// ### Why is this bad? - /// It will be more difficult for users to discover the - /// purpose of the crate, and key information related to it. - /// - /// ### Example - /// ```toml - /// # This `Cargo.toml` is missing a description field: - /// [package] - /// name = "clippy" - /// version = "0.0.212" - /// repository = "https://github.com/rust-lang/rust-clippy" - /// readme = "README.md" - /// license = "MIT OR Apache-2.0" - /// keywords = ["clippy", "lint", "plugin"] - /// categories = ["development-tools", "development-tools::cargo-plugins"] - /// ``` - /// - /// Should include a description field like: - /// - /// ```toml - /// # This `Cargo.toml` includes all common metadata - /// [package] - /// name = "clippy" - /// version = "0.0.212" - /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" - /// repository = "https://github.com/rust-lang/rust-clippy" - /// readme = "README.md" - /// license = "MIT OR Apache-2.0" - /// keywords = ["clippy", "lint", "plugin"] - /// categories = ["development-tools", "development-tools::cargo-plugins"] - /// ``` - #[clippy::version = "1.32.0"] - pub CARGO_COMMON_METADATA, - cargo, - "common metadata is defined in `Cargo.toml`" -} - -#[derive(Copy, Clone, Debug)] -pub struct CargoCommonMetadata { - ignore_publish: bool, -} - -impl CargoCommonMetadata { - pub fn new(ignore_publish: bool) -> Self { - Self { ignore_publish } - } -} - -impl_lint_pass!(CargoCommonMetadata => [ - CARGO_COMMON_METADATA -]); - -fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { - let message = format!("package `{}` is missing `{}` metadata", package.name, field); - span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); -} - -fn is_empty_str>(value: &Option) -> bool { - value.as_ref().map_or(true, |s| s.as_ref().is_empty()) -} - -fn is_empty_vec(value: &[String]) -> bool { - // This works because empty iterators return true - value.iter().all(String::is_empty) -} - -impl LateLintPass<'_> for CargoCommonMetadata { - fn check_crate(&mut self, cx: &LateContext<'_>) { - if is_lint_allowed(cx, CARGO_COMMON_METADATA, CRATE_HIR_ID) { - return; - } - - let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false); - - for package in metadata.packages { - // only run the lint if publish is `None` (`publish = true` or skipped entirely) - // or if the vector isn't empty (`publish = ["something"]`) - if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || self.ignore_publish { - if is_empty_str(&package.description) { - missing_warning(cx, &package, "package.description"); - } - - if is_empty_str(&package.license) && is_empty_str(&package.license_file) { - missing_warning(cx, &package, "either package.license or package.license_file"); - } - - if is_empty_str(&package.repository) { - missing_warning(cx, &package, "package.repository"); - } - - if is_empty_str(&package.readme) { - missing_warning(cx, &package, "package.readme"); - } - - if is_empty_vec(&package.keywords) { - missing_warning(cx, &package, "package.keywords"); - } - - if is_empty_vec(&package.categories) { - missing_warning(cx, &package, "package.categories"); - } - } - } - } -} diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index ea74d5acbda0..9b189ea1ef8f 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,12 +1,15 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::expr_or_init; -use clippy_utils::ty::is_isize_or_usize; +use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; +use rustc_ast::ast; +use rustc_attr::IntType; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use super::{utils, CAST_POSSIBLE_TRUNCATION}; +use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) { @@ -75,8 +78,8 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b } pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { - let msg = match (cast_from.is_integral(), cast_to.is_integral()) { - (true, true) => { + let msg = match (cast_from.kind(), cast_to.is_integral()) { + (ty::Int(_) | ty::Uint(_), true) => { let from_nbits = apply_reductions( cx, utils::int_ty_to_nbits(cast_from, cx.tcx), @@ -108,19 +111,60 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, ) }, - (false, true) => { - format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to) - }, - - (_, _) => { - if matches!(cast_from.kind(), &ty::Float(FloatTy::F64)) - && matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) + (ty::Adt(def, _), true) if def.is_enum() => { + let (from_nbits, variant) = if let ExprKind::Path(p) = &cast_expr.kind + && let Res::Def(DefKind::Ctor(..), id) = cx.qpath_res(p, cast_expr.hir_id) { - "casting `f64` to `f32` may truncate the value".to_string() + let i = def.variant_index_with_ctor_id(id); + let variant = &def.variants[i]; + let nbits = utils::enum_value_nbits(get_discriminant_value(cx.tcx, def, i)); + (nbits, Some(variant)) } else { + (utils::enum_ty_to_nbits(def, cx.tcx), None) + }; + let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); + + let cast_from_ptr_size = def.repr.int.map_or(true, |ty| { + matches!( + ty, + IntType::SignedInt(ast::IntTy::Isize) | IntType::UnsignedInt(ast::UintTy::Usize) + ) + }); + let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) { + (false, false) if from_nbits > to_nbits => "", + (true, false) if from_nbits > to_nbits => "", + (false, true) if from_nbits > 64 => "", + (false, true) if from_nbits > 32 => " on targets with 32-bit wide pointers", + _ => return, + }; + + if let Some(variant) = variant { + span_lint( + cx, + CAST_ENUM_TRUNCATION, + expr.span, + &format!( + "casting `{}::{}` to `{}` will truncate the value{}", + cast_from, variant.name, cast_to, suffix, + ), + ); return; } + format!( + "casting `{}` to `{}` may truncate the value{}", + cast_from, cast_to, suffix, + ) }, + + (ty::Float(_), true) => { + format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to) + }, + + (ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { + "casting `f64` to `f32` may truncate the value".to_string() + }, + + _ => return, }; span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg); diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 079b7ff0675b..a4ef1344ab95 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_hir_ty_cfg_dependant; +use clippy_utils::ty::is_c_void; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::sym; use super::CAST_PTR_ALIGNMENT; @@ -62,19 +62,3 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f } } } - -/// Check if the given type is either `core::ffi::c_void` or -/// one of the platform specific `libc::::c_void` of libc. -fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - if let ty::Adt(adt, _) = ty.kind() { - let names = cx.get_def_path(adt.did); - - if names.is_empty() { - return false; - } - if names[0] == sym::libc || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) { - return true; - } - } - false -} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index aee1e50b94a2..f2077c569c04 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -390,6 +390,25 @@ declare_clippy_lint! { "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for casts from an enum type to an integral type which will definitely truncate the + /// value. + /// + /// ### Why is this bad? + /// The resulting integral value will not match the value of the variant it came from. + /// + /// ### Example + /// ```rust + /// enum E { X = 256 }; + /// let _ = E::X as u8; + /// ``` + #[clippy::version = "1.60.0"] + pub CAST_ENUM_TRUNCATION, + suspicious, + "casts from an enum type to an integral type which will truncate the value" +} + pub struct Casts { msrv: Option, } @@ -415,10 +434,15 @@ impl_lint_pass!(Casts => [ FN_TO_NUMERIC_CAST_WITH_TRUNCATION, CHAR_LIT_AS_U8, PTR_AS_PTR, + CAST_ENUM_TRUNCATION, ]); impl<'tcx> LateLintPass<'tcx> for Casts { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !in_external_macro(cx.sess(), expr.span) { + ptr_as_ptr::check(cx, expr, &self.msrv); + } + if expr.span.from_expansion() { return; } @@ -441,13 +465,12 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { + cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); if cast_from.is_numeric() { - cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); } - cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); } } @@ -455,7 +478,6 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_ref_to_mut::check(cx, expr); cast_ptr_alignment::check(cx, expr); char_lit_as_u8::check(cx, expr); - ptr_as_ptr::check(cx, expr, &self.msrv); } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs index 00fd0b3473b4..bbed766c47a8 100644 --- a/clippy_lints/src/casts/utils.rs +++ b/clippy_lints/src/casts/utils.rs @@ -1,4 +1,5 @@ -use rustc_middle::ty::{self, IntTy, Ty, TyCtxt, UintTy}; +use clippy_utils::ty::{read_explicit_enum_value, EnumValue}; +use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr}; /// Returns the size in bits of an integral type. /// Will return 0 if the type is not an int or uint variant @@ -23,3 +24,52 @@ pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { _ => 0, } } + +pub(super) fn enum_value_nbits(value: EnumValue) -> u64 { + match value { + EnumValue::Unsigned(x) => 128 - x.leading_zeros(), + EnumValue::Signed(x) if x < 0 => 128 - (-(x + 1)).leading_zeros() + 1, + EnumValue::Signed(x) => 128 - x.leading_zeros(), + } + .into() +} + +pub(super) fn enum_ty_to_nbits(adt: &AdtDef, tcx: TyCtxt<'_>) -> u64 { + let mut explicit = 0i128; + let (start, end) = adt + .variants + .iter() + .fold((0, i128::MIN), |(start, end), variant| match variant.discr { + VariantDiscr::Relative(x) => match explicit.checked_add(i128::from(x)) { + Some(x) => (start, end.max(x)), + None => (i128::MIN, end), + }, + VariantDiscr::Explicit(id) => match read_explicit_enum_value(tcx, id) { + Some(EnumValue::Signed(x)) => { + explicit = x; + (start.min(x), end.max(x)) + }, + Some(EnumValue::Unsigned(x)) => match i128::try_from(x) { + Ok(x) => { + explicit = x; + (start, end.max(x)) + }, + Err(_) => (i128::MIN, end), + }, + None => (start, end), + }, + }); + + if start > end { + // No variants. + 0 + } else { + let neg_bits = if start < 0 { + 128 - (-(start + 1)).leading_zeros() + 1 + } else { + 0 + }; + let pos_bits = if end > 0 { 128 - end.leading_zeros() } else { 0 }; + neg_bits.max(pos_bits).into() + } +} diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 5a0b60fdfbc0..df1a4128af35 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,11 +1,11 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::snippet_opt; -use rustc_ast::ast; -use rustc_ast::tokenstream::TokenStream; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -15,14 +15,6 @@ declare_clippy_lint! { /// `dbg!` macro is intended as a debugging tool. It /// should not be in version control. /// - /// ### Known problems - /// * The lint level is unaffected by crate attributes. The level can still - /// be set for functions, modules and other items. To change the level for - /// the entire crate, please use command line flags. More information and a - /// configuration example can be found in [clippy#6610]. - /// - /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 - /// /// ### Example /// ```rust,ignore /// // Bad @@ -39,37 +31,52 @@ declare_clippy_lint! { declare_lint_pass!(DbgMacro => [DBG_MACRO]); -impl EarlyLintPass for DbgMacro { - fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { - if mac.path == sym!(dbg) { - if let Some(sugg) = tts_span(mac.args.inner_tokens()).and_then(|span| snippet_opt(cx, span)) { - span_lint_and_sugg( - cx, - DBG_MACRO, - mac.span(), - "`dbg!` macro is intended as a debugging tool", - "ensure to avoid having uses of it in version control", - sugg, - Applicability::MaybeIncorrect, - ); - } else { - span_lint_and_help( - cx, - DBG_MACRO, - mac.span(), - "`dbg!` macro is intended as a debugging tool", - None, - "ensure to avoid having uses of it in version control", - ); - } +impl LateLintPass<'_> for DbgMacro { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) { + let mut applicability = Applicability::MachineApplicable; + let suggestion = match expr.peel_drop_temps().kind { + // dbg!() + ExprKind::Block(_, _) => String::new(), + // dbg!(1) + ExprKind::Match(val, ..) => { + snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string() + }, + // dbg!(2, 3) + ExprKind::Tup( + [ + Expr { + kind: ExprKind::Match(first, ..), + .. + }, + .., + Expr { + kind: ExprKind::Match(last, ..), + .. + }, + ], + ) => { + let snippet = snippet_with_applicability( + cx, + first.span.source_callsite().to(last.span.source_callsite()), + "..", + &mut applicability, + ); + format!("({snippet})") + }, + _ => return, + }; + + span_lint_and_sugg( + cx, + DBG_MACRO, + macro_call.span, + "`dbg!` macro is intended as a debugging tool", + "ensure to avoid having uses of it in version control", + suggestion, + applicability, + ); } } } - -// Get span enclosing entire the token stream. -fn tts_span(tts: TokenStream) -> Option { - let mut cursor = tts.into_trees(); - let first = cursor.next()?.span(); - let span = cursor.last().map_or(first, |tree| first.to(tree.span())); - Some(span) -} diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 3070588483c2..06e6bf986c2a 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths}; +use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -88,6 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + if !is_update_syntax_base(cx, expr); // Detect and ignore ::default() because these calls do explicitly name the type. if let QPath::Resolved(None, _path) = qpath; let expr_ty = cx.typeck_results().expr_ty(expr); @@ -290,3 +291,16 @@ fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Op } } } + +/// Returns whether `expr` is the update syntax base: `Foo { a: 1, .. base }` +fn is_update_syntax_base<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + if_chain! { + if let Some(parent) = get_parent_expr(cx, expr); + if let ExprKind::Struct(_, _, Some(base)) = parent.kind; + then { + base.hir_id == expr.hir_id + } else { + false + } + } +} diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 6d3df260ca25..7277e4080c5c 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then}; use clippy_utils::paths; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{get_trait_def_id, is_automatically_derived, is_lint_allowed, match_def_path}; +use clippy_utils::{is_automatically_derived, is_lint_allowed, match_def_path}; use if_chain::if_chain; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; use rustc_hir::{ @@ -12,6 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -196,7 +197,7 @@ fn check_hash_peq<'tcx>( if_chain! { if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait(); if let Some(def_id) = trait_ref.trait_def_id(); - if match_def_path(cx, def_id, &paths::HASH); + if cx.tcx.is_diagnostic_item(sym::Hash, def_id); then { // Look for the PartialEq implementations for `ty` cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { @@ -247,7 +248,7 @@ fn check_ord_partial_ord<'tcx>( ord_is_automatically_derived: bool, ) { if_chain! { - if let Some(ord_trait_def_id) = get_trait_def_id(cx, &paths::ORD); + if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord); if let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait(); if let Some(def_id) = &trait_ref.trait_def_id(); if *def_id == ord_trait_def_id; diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index a8f8e3d8a42c..5c4b35fd4b9d 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::ty::is_copy; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -128,14 +128,16 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let arg_ty = cx.typeck_results().expr_ty(arg); if let ty::Ref(..) = arg_ty.kind() { - if match_def_path(cx, def_id, &paths::DROP) { - lint = DROP_REF; - msg = DROP_REF_SUMMARY.to_string(); - } else if match_def_path(cx, def_id, &paths::MEM_FORGET) { - lint = FORGET_REF; - msg = FORGET_REF_SUMMARY.to_string(); - } else { - return; + match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::mem_drop) => { + lint = DROP_REF; + msg = DROP_REF_SUMMARY.to_string(); + }, + Some(sym::mem_forget) => { + lint = FORGET_REF; + msg = FORGET_REF_SUMMARY.to_string(); + }, + _ => return, } span_lint_and_note(cx, lint, @@ -144,14 +146,16 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { Some(arg.span), &format!("argument has type `{}`", arg_ty)); } else if is_copy(cx, arg_ty) { - if match_def_path(cx, def_id, &paths::DROP) { - lint = DROP_COPY; - msg = DROP_COPY_SUMMARY.to_string(); - } else if match_def_path(cx, def_id, &paths::MEM_FORGET) { - lint = FORGET_COPY; - msg = FORGET_COPY_SUMMARY.to_string(); - } else { - return; + match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::mem_drop) => { + lint = DROP_COPY; + msg = DROP_COPY_SUMMARY.to_string(); + }, + Some(sym::mem_forget) => { + lint = FORGET_COPY; + msg = FORGET_COPY_SUMMARY.to_string(); + }, + _ => return, } span_lint_and_note(cx, lint, diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 24e32c09f44b..09318f74527c 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -1,15 +1,14 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; - -use clippy_utils::consts::{constant, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -46,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for DurationSubsec { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, left, right) = expr.kind; if let ExprKind::MethodCall(method_path, args, _) = left.kind; - if match_type(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::DURATION); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::Duration); if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right); then { let suggested_fn = match (method_path.ident.as_str(), divisor) { diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index ea547793b1ea..6490231fed8a 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -6,9 +6,7 @@ use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{ - def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind, -}; +use rustc_hir::{def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -279,7 +277,11 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } } -fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> { +fn in_impl<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + bin_op: DefId, +) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> { if_chain! { if let Some(block) = get_enclosing_block(cx, e.hir_id); if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id()); diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 263bff4873ca..d23c0c225e19 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -10,6 +10,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; +use rustc_middle::ty::binding::BindingMode; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -169,11 +170,17 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_ if params.len() != call_args.len() { return false; } + let binding_modes = cx.typeck_results().pat_binding_modes(); std::iter::zip(params, call_args).all(|(param, arg)| { match param.pat.kind { PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {}, _ => return false, } + // checks that parameters are not bound as `ref` or `ref mut` + if let Some(BindingMode::BindByReference(_)) = binding_modes.get(param.pat.hir_id) { + return false; + } + match *cx.typeck_results().expr_adjustments(arg) { [] => true, [ diff --git a/clippy_lints/src/feature_name.rs b/clippy_lints/src/feature_name.rs deleted file mode 100644 index dc6bef52ddd9..000000000000 --- a/clippy_lints/src/feature_name.rs +++ /dev/null @@ -1,166 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{diagnostics::span_lint, is_lint_allowed}; -use rustc_hir::CRATE_HIR_ID; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::DUMMY_SP; - -declare_clippy_lint! { - /// ### What it does - /// Checks for feature names with prefix `use-`, `with-` or suffix `-support` - /// - /// ### Why is this bad? - /// These prefixes and suffixes have no significant meaning. - /// - /// ### Example - /// ```toml - /// # The `Cargo.toml` with feature name redundancy - /// [features] - /// default = ["use-abc", "with-def", "ghi-support"] - /// use-abc = [] // redundant - /// with-def = [] // redundant - /// ghi-support = [] // redundant - /// ``` - /// - /// Use instead: - /// ```toml - /// [features] - /// default = ["abc", "def", "ghi"] - /// abc = [] - /// def = [] - /// ghi = [] - /// ``` - /// - #[clippy::version = "1.57.0"] - pub REDUNDANT_FEATURE_NAMES, - cargo, - "usage of a redundant feature name" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for negative feature names with prefix `no-` or `not-` - /// - /// ### Why is this bad? - /// Features are supposed to be additive, and negatively-named features violate it. - /// - /// ### Example - /// ```toml - /// # The `Cargo.toml` with negative feature names - /// [features] - /// default = [] - /// no-abc = [] - /// not-def = [] - /// - /// ``` - /// Use instead: - /// ```toml - /// [features] - /// default = ["abc", "def"] - /// abc = [] - /// def = [] - /// - /// ``` - #[clippy::version = "1.57.0"] - pub NEGATIVE_FEATURE_NAMES, - cargo, - "usage of a negative feature name" -} - -declare_lint_pass!(FeatureName => [REDUNDANT_FEATURE_NAMES, NEGATIVE_FEATURE_NAMES]); - -static PREFIXES: [&str; 8] = ["no-", "no_", "not-", "not_", "use-", "use_", "with-", "with_"]; -static SUFFIXES: [&str; 2] = ["-support", "_support"]; - -fn is_negative_prefix(s: &str) -> bool { - s.starts_with("no") -} - -fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) { - let is_negative = is_prefix && is_negative_prefix(substring); - span_lint_and_help( - cx, - if is_negative { - NEGATIVE_FEATURE_NAMES - } else { - REDUNDANT_FEATURE_NAMES - }, - DUMMY_SP, - &format!( - "the \"{}\" {} in the feature name \"{}\" is {}", - substring, - if is_prefix { "prefix" } else { "suffix" }, - feature, - if is_negative { "negative" } else { "redundant" } - ), - None, - &format!( - "consider renaming the feature to \"{}\"{}", - if is_prefix { - feature.strip_prefix(substring) - } else { - feature.strip_suffix(substring) - } - .unwrap(), - if is_negative { - ", but make sure the feature adds functionality" - } else { - "" - } - ), - ); -} - -impl LateLintPass<'_> for FeatureName { - fn check_crate(&mut self, cx: &LateContext<'_>) { - if is_lint_allowed(cx, REDUNDANT_FEATURE_NAMES, CRATE_HIR_ID) - && is_lint_allowed(cx, NEGATIVE_FEATURE_NAMES, CRATE_HIR_ID) - { - return; - } - - let metadata = unwrap_cargo_metadata!(cx, REDUNDANT_FEATURE_NAMES, false); - - for package in metadata.packages { - let mut features: Vec<&String> = package.features.keys().collect(); - features.sort(); - for feature in features { - let prefix_opt = { - let i = PREFIXES.partition_point(|prefix| prefix < &feature.as_str()); - if i > 0 && feature.starts_with(PREFIXES[i - 1]) { - Some(PREFIXES[i - 1]) - } else { - None - } - }; - if let Some(prefix) = prefix_opt { - lint(cx, feature, prefix, true); - } - - let suffix_opt: Option<&str> = { - let i = SUFFIXES.partition_point(|suffix| { - suffix.bytes().rev().cmp(feature.bytes().rev()) == std::cmp::Ordering::Less - }); - if i > 0 && feature.ends_with(SUFFIXES[i - 1]) { - Some(SUFFIXES[i - 1]) - } else { - None - } - }; - if let Some(suffix) = suffix_opt { - lint(cx, feature, suffix, false); - } - } - } - } -} - -#[test] -fn test_prefixes_sorted() { - let mut sorted_prefixes = PREFIXES; - sorted_prefixes.sort_unstable(); - assert_eq!(PREFIXES, sorted_prefixes); - let mut sorted_suffixes = SUFFIXES; - sorted_suffixes.sort_by(|a, b| a.bytes().rev().cmp(b.bytes().rev())); - assert_eq!(SUFFIXES, sorted_suffixes); -} diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 503aac8ccd02..1e6feaac26c3 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::macros::{FormatArgsArg, FormatArgsExpn}; +use clippy_utils::is_diag_trait_item; +use clippy_utils::macros::{is_format_macro, FormatArgsArg, FormatArgsExpn}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_diag_trait_item, match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -65,21 +65,6 @@ declare_clippy_lint! { declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]); -const FORMAT_MACRO_PATHS: &[&[&str]] = &[ - &paths::FORMAT_ARGS_MACRO, - &paths::ASSERT_EQ_MACRO, - &paths::ASSERT_MACRO, - &paths::ASSERT_NE_MACRO, - &paths::EPRINT_MACRO, - &paths::EPRINTLN_MACRO, - &paths::PRINT_MACRO, - &paths::PRINTLN_MACRO, - &paths::WRITE_MACRO, - &paths::WRITELN_MACRO, -]; - -const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_macro]; - impl<'tcx> LateLintPass<'tcx> for FormatArgs { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { @@ -87,12 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { let expr_expn_data = expr.span.ctxt().outer_expn_data(); let outermost_expn_data = outermost_expn_data(expr_expn_data); if let Some(macro_def_id) = outermost_expn_data.macro_def_id; - if FORMAT_MACRO_PATHS - .iter() - .any(|path| match_def_path(cx, macro_def_id, path)) - || FORMAT_MACRO_DIAG_ITEMS - .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, macro_def_id)); + if is_format_macro(cx, macro_def_id); if let ExpnKind::Macro(_, name) = outermost_expn_data.kind; if let Some(args) = format_args.args(); then { diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs new file mode 100644 index 000000000000..ef8be9e878f6 --- /dev/null +++ b/clippy_lints/src/format_impl.rs @@ -0,0 +1,253 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArgsArg, FormatArgsExpn}; +use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{sym, symbol::kw, Symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for format trait implementations (e.g. `Display`) with a recursive call to itself + /// which uses `self` as a parameter. + /// This is typically done indirectly with the `write!` macro or with `to_string()`. + /// + /// ### Why is this bad? + /// This will lead to infinite recursion and a stack overflow. + /// + /// ### Example + /// + /// ```rust + /// use std::fmt; + /// + /// struct Structure(i32); + /// impl fmt::Display for Structure { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "{}", self.to_string()) + /// } + /// } + /// + /// ``` + /// Use instead: + /// ```rust + /// use std::fmt; + /// + /// struct Structure(i32); + /// impl fmt::Display for Structure { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "{}", self.0) + /// } + /// } + /// ``` + #[clippy::version = "1.48.0"] + pub RECURSIVE_FORMAT_IMPL, + correctness, + "Format trait method called while implementing the same Format trait" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for use of `println`, `print`, `eprintln` or `eprint` in an + /// implementation of a formatting trait. + /// + /// ### Why is this bad? + /// Using a print macro is likely unintentional since formatting traits + /// should write to the `Formatter`, not stdout/stderr. + /// + /// ### Example + /// ```rust + /// use std::fmt::{Display, Error, Formatter}; + /// + /// struct S; + /// impl Display for S { + /// fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + /// println!("S"); + /// + /// Ok(()) + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::fmt::{Display, Error, Formatter}; + /// + /// struct S; + /// impl Display for S { + /// fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + /// writeln!(f, "S"); + /// + /// Ok(()) + /// } + /// } + /// ``` + #[clippy::version = "1.61.0"] + pub PRINT_IN_FORMAT_IMPL, + suspicious, + "use of a print macro in a formatting trait impl" +} + +#[derive(Clone, Copy)] +struct FormatTrait { + /// e.g. `sym::Display` + name: Symbol, + /// `f` in `fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {}` + formatter_name: Option, +} + +#[derive(Default)] +pub struct FormatImpl { + // Whether we are inside Display or Debug trait impl - None for neither + format_trait_impl: Option, +} + +impl FormatImpl { + pub fn new() -> Self { + Self { + format_trait_impl: None, + } + } +} + +impl_lint_pass!(FormatImpl => [RECURSIVE_FORMAT_IMPL, PRINT_IN_FORMAT_IMPL]); + +impl<'tcx> LateLintPass<'tcx> for FormatImpl { + fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + self.format_trait_impl = is_format_trait_impl(cx, impl_item); + } + + fn check_impl_item_post(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + // Assume no nested Impl of Debug and Display within eachother + if is_format_trait_impl(cx, impl_item).is_some() { + self.format_trait_impl = None; + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let Some(format_trait_impl) = self.format_trait_impl else { return }; + + if format_trait_impl.name == sym::Display { + check_to_string_in_display(cx, expr); + } + + check_self_in_format_args(cx, expr, format_trait_impl); + check_print_in_format_impl(cx, expr, format_trait_impl); + } +} + +fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + // Get the hir_id of the object we are calling the method on + if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind; + // Is the method to_string() ? + if path.ident.name == sym!(to_string); + // Is the method a part of the ToString trait? (i.e. not to_string() implemented + // separately) + if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if is_diag_trait_item(cx, expr_def_id, sym::ToString); + // Is the method is called on self + if let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind; + if let [segment] = path.segments; + if segment.ident.name == kw::SelfLower; + then { + span_lint( + cx, + RECURSIVE_FORMAT_IMPL, + expr.span, + "using `self.to_string` in `fmt::Display` implementation will cause infinite recursion", + ); + } + } +} + +fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTrait) { + // Check each arg in format calls - do we ever use Display on self (directly or via deref)? + if_chain! { + if let Some(outer_macro) = root_macro_call_first_node(cx, expr); + if let macro_def_id = outer_macro.def_id; + if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn); + if is_format_macro(cx, macro_def_id); + if let Some(args) = format_args.args(); + then { + for arg in args { + if arg.format_trait != impl_trait.name { + continue; + } + check_format_arg_self(cx, expr, &arg, impl_trait); + } + } + } +} + +fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArgsArg<'_>, impl_trait: FormatTrait) { + // Handle multiple dereferencing of references e.g. &&self + // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) + // Since the argument to fmt is itself a reference: &self + let reference = peel_ref_operators(cx, arg.value); + let map = cx.tcx.hir(); + // Is the reference self? + if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { + let FormatTrait { name, .. } = impl_trait; + span_lint( + cx, + RECURSIVE_FORMAT_IMPL, + expr.span, + &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), + ); + } +} + +fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTrait) { + if_chain! { + if let Some(macro_call) = root_macro_call_first_node(cx, expr); + if let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id); + then { + let replacement = match name { + sym::print_macro | sym::eprint_macro => "write", + sym::println_macro | sym::eprintln_macro => "writeln", + _ => return, + }; + + let name = name.as_str().strip_suffix("_macro").unwrap(); + + span_lint_and_sugg( + cx, + PRINT_IN_FORMAT_IMPL, + macro_call.span, + &format!("use of `{}!` in `{}` impl", name, impl_trait.name), + "replace with", + if let Some(formatter_name) = impl_trait.formatter_name { + format!("{}!({}, ..)", replacement, formatter_name) + } else { + format!("{}!(..)", replacement) + }, + Applicability::HasPlaceholders, + ); + } + } +} + +fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { + if_chain! { + if impl_item.ident.name == sym::fmt; + if let ImplItemKind::Fn(_, body_id) = impl_item.kind; + if let Some(Impl { of_trait: Some(trait_ref),..}) = get_parent_as_impl(cx.tcx, impl_item.hir_id()); + if let Some(did) = trait_ref.trait_def_id(); + if let Some(name) = cx.tcx.get_diagnostic_name(did); + if matches!(name, sym::Debug | sym::Display); + then { + let body = cx.tcx.hir().body(body_id); + let formatter_name = body.params.get(1) + .and_then(|param| param.pat.simple_ident()) + .map(|ident| ident.name); + + Some(FormatTrait { + name, + formatter_name, + }) + } else { + None + } + } +} diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index b6badef02f58..b2b9889f5dc7 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{get_trait_def_id, higher, match_def_path, path_def_id, paths}; +use clippy_utils::{higher, match_def_path, path_def_id, paths}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -229,9 +229,12 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } } if method.ident.name == sym!(last) && args.len() == 1 { - let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR).map_or(false, |id| { - !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[]) - }); + let not_double_ended = cx + .tcx + .get_diagnostic_item(sym::DoubleEndedIterator) + .map_or(false, |id| { + !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[]) + }); if not_double_ended { return is_infinite(cx, &args[0]); } diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 0191713f60d3..d1dc6b775c56 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -84,34 +84,30 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { if adt.variants.len() <= 1 { return; } - let mut variants_size: Vec = adt - .variants - .iter() - .enumerate() - .map(|(i, variant)| { - let mut fields_size = Vec::new(); - let size: u64 = variant - .fields - .iter() - .enumerate() - .filter_map(|(i, f)| { - let ty = cx.tcx.type_of(f.did); - // don't count generics by filtering out everything - // that does not have a layout - cx.layout_of(ty).ok().map(|l| { - let size = l.size.bytes(); - fields_size.push(FieldInfo { ind: i, size }); - size - }) - }) - .sum(); - VariantInfo { - ind: i, - size, - fields_size, + let mut variants_size: Vec = Vec::new(); + for (i, variant) in adt.variants.iter().enumerate() { + let mut fields_size = Vec::new(); + for (i, f) in variant.fields.iter().enumerate() { + let ty = cx.tcx.type_of(f.did); + // don't lint variants which have a field of generic type. + match cx.layout_of(ty) { + Ok(l) => { + let fsize = l.size.bytes(); + fields_size.push(FieldInfo { ind: i, size: fsize }); + }, + Err(_) => { + return; + }, } - }) - .collect(); + } + let size: u64 = fields_size.iter().map(|info| info.size).sum(); + + variants_size.push(VariantInfo { + ind: i, + size, + fields_size, + }); + } variants_size.sort_by(|a, b| (b.size.cmp(&a.size))); diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 4721b7f2b472..f6d467941e3e 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -14,6 +14,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(attrs::DEPRECATED_SEMVER), LintId::of(attrs::MISMATCHED_TARGET_OS), LintId::of(attrs::USELESS_ATTRIBUTE), + LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), + LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(bit_mask::BAD_BIT_MASK), LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(blacklisted_name::BLACKLISTED_NAME), @@ -21,6 +23,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), LintId::of(booleans::LOGIC_BUG), LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(casts::CAST_ENUM_TRUNCATION), LintId::of(casts::CAST_REF_TO_MUT), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::FN_TO_NUMERIC_CAST), @@ -65,6 +68,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(format::USELESS_FORMAT), LintId::of(format_args::FORMAT_IN_FORMAT_ARGS), LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS), + LintId::of(format_impl::PRINT_IN_FORMAT_IMPL), + LintId::of(format_impl::RECURSIVE_FORMAT_IMPL), LintId::of(formatting::POSSIBLE_MISSING_COMMA), LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), @@ -267,7 +272,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), - LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), LintId::of(transmute::CROSSPOINTER_TRANSMUTE), LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), @@ -277,6 +281,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES), LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), LintId::of(transmuting_null::TRANSMUTING_NULL), diff --git a/clippy_lints/src/lib.register_cargo.rs b/clippy_lints/src/lib.register_cargo.rs index 1809f2cc7d46..c890523fe5ae 100644 --- a/clippy_lints/src/lib.register_cargo.rs +++ b/clippy_lints/src/lib.register_cargo.rs @@ -3,9 +3,9 @@ // Manual edits will be overwritten. store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![ - LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA), - LintId::of(feature_name::NEGATIVE_FEATURE_NAMES), - LintId::of(feature_name::REDUNDANT_FEATURE_NAMES), - LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS), - LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES), + LintId::of(cargo::CARGO_COMMON_METADATA), + LintId::of(cargo::MULTIPLE_CRATE_VERSIONS), + LintId::of(cargo::NEGATIVE_FEATURE_NAMES), + LintId::of(cargo::REDUNDANT_FEATURE_NAMES), + LintId::of(cargo::WILDCARD_DEPENDENCIES), ]) diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 4217fd3a3ea7..35b1e644a8a7 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -24,6 +24,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), LintId::of(eq_op::EQ_OP), LintId::of(erasing_op::ERASING_OP), + LintId::of(format_impl::RECURSIVE_FORMAT_IMPL), LintId::of(formatting::POSSIBLE_MISSING_COMMA), LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(if_let_mutex::IF_LET_MUTEX), @@ -57,7 +58,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(swap::ALMOST_SWAPPED), - LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), + LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), LintId::of(transmuting_null::TRANSMUTING_NULL), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index a80320a578f0..686482671b48 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -61,8 +61,13 @@ store.register_lints(&[ booleans::NONMINIMAL_BOOL, borrow_as_ptr::BORROW_AS_PTR, bytecount::NAIVE_BYTECOUNT, - cargo_common_metadata::CARGO_COMMON_METADATA, + cargo::CARGO_COMMON_METADATA, + cargo::MULTIPLE_CRATE_VERSIONS, + cargo::NEGATIVE_FEATURE_NAMES, + cargo::REDUNDANT_FEATURE_NAMES, + cargo::WILDCARD_DEPENDENCIES, case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + casts::CAST_ENUM_TRUNCATION, casts::CAST_LOSSLESS, casts::CAST_POSSIBLE_TRUNCATION, casts::CAST_POSSIBLE_WRAP, @@ -139,8 +144,6 @@ store.register_lints(&[ exit::EXIT, explicit_write::EXPLICIT_WRITE, fallible_impl_from::FALLIBLE_IMPL_FROM, - feature_name::NEGATIVE_FEATURE_NAMES, - feature_name::REDUNDANT_FEATURE_NAMES, float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, float_literal::EXCESSIVE_PRECISION, float_literal::LOSSY_FLOAT_LITERAL, @@ -149,6 +152,8 @@ store.register_lints(&[ format::USELESS_FORMAT, format_args::FORMAT_IN_FORMAT_ARGS, format_args::TO_STRING_IN_FORMAT_ARGS, + format_impl::PRINT_IN_FORMAT_IMPL, + format_impl::RECURSIVE_FORMAT_IMPL, formatting::POSSIBLE_MISSING_COMMA, formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, @@ -353,7 +358,6 @@ store.register_lints(&[ module_style::MOD_MODULE_FILES, module_style::SELF_NAMED_MODULE_FILES, modulo_arithmetic::MODULO_ARITHMETIC, - multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, mut_key::MUTABLE_KEY_TYPE, mut_mut::MUT_MUT, mut_mutex_lock::MUT_MUTEX_LOCK, @@ -420,6 +424,7 @@ store.register_lints(&[ redundant_else::REDUNDANT_ELSE, redundant_field_names::REDUNDANT_FIELD_NAMES, redundant_pub_crate::REDUNDANT_PUB_CRATE, + redundant_slicing::DEREF_BY_SLICING, redundant_slicing::REDUNDANT_SLICING, redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, ref_option_ref::REF_OPTION_REF, @@ -459,7 +464,6 @@ store.register_lints(&[ tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, temporary_assignment::TEMPORARY_ASSIGNMENT, to_digit_is_some::TO_DIGIT_IS_SOME, - to_string_in_display::TO_STRING_IN_DISPLAY, trailing_empty_array::TRAILING_EMPTY_ARRAY, trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, trait_bounds::TYPE_REPETITION_IN_BOUNDS, @@ -520,7 +524,6 @@ store.register_lints(&[ vec_init_then_push::VEC_INIT_THEN_PUSH, vec_resize_to_zero::VEC_RESIZE_TO_ZERO, verbose_file_reads::VERBOSE_FILE_READS, - wildcard_dependencies::WILDCARD_DEPENDENCIES, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, write::PRINTLN_EMPTY_STRING, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 8d4dde42bbec..a73537901002 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -26,7 +26,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(strings::STRING_LIT_AS_BYTES), LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY), - LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(use_self::USE_SELF), ]) diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 1292675f4a96..00d305131810 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -4,8 +4,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(attrs::INLINE_ALWAYS), - LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(bit_mask::VERBOSE_BIT_MASK), LintId::of(borrow_as_ptr::BORROW_AS_PTR), LintId::of(bytecount::NAIVE_BYTECOUNT), diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 5a89fdb05a99..f89f35b885c1 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -51,6 +51,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(panic_unimplemented::UNIMPLEMENTED), LintId::of(panic_unimplemented::UNREACHABLE), LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH), + LintId::of(redundant_slicing::DEREF_BY_SLICING), LintId::of(same_name_method::SAME_NAME_METHOD), LintId::of(shadow::SHADOW_REUSE), LintId::of(shadow::SHADOW_SAME), diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 10f8ae4b7f7f..465baa825817 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -5,8 +5,12 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![ LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), + LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), + LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), + LintId::of(casts::CAST_ENUM_TRUNCATION), LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(format_impl::PRINT_IN_FORMAT_IMPL), LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 85256ff0e995..230e2b2ccdfb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -5,6 +5,7 @@ #![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(iter_intersperse)] +#![feature(let_chains)] #![feature(let_else)] #![feature(once_cell)] #![feature(rustc_private)] @@ -24,6 +25,7 @@ // (Currently there is no way to opt into sysroot crates without `extern crate`.) extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; @@ -177,7 +179,7 @@ mod bool_assert_comparison; mod booleans; mod borrow_as_ptr; mod bytecount; -mod cargo_common_metadata; +mod cargo; mod case_sensitive_file_extension_comparisons; mod casts; mod checked_conversions; @@ -219,12 +221,12 @@ mod exhaustive_items; mod exit; mod explicit_write; mod fallible_impl_from; -mod feature_name; mod float_equality_without_abs; mod float_literal; mod floating_point_arithmetic; mod format; mod format_args; +mod format_impl; mod formatting; mod from_over_into; mod from_str_radix_10; @@ -289,7 +291,6 @@ mod missing_enforced_import_rename; mod missing_inline; mod module_style; mod modulo_arithmetic; -mod multiple_crate_versions; mod mut_key; mod mut_mut; mod mut_mutex_lock; @@ -365,7 +366,6 @@ mod swap; mod tabs_in_doc_comments; mod temporary_assignment; mod to_digit_is_some; -mod to_string_in_display; mod trailing_empty_array; mod trait_bounds; mod transmute; @@ -398,7 +398,6 @@ mod vec; mod vec_init_then_push; mod vec_resize_to_zero; mod verbose_file_reads; -mod wildcard_dependencies; mod wildcard_imports; mod write; mod zero_div_zero; @@ -431,7 +430,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se store.register_pre_expansion_pass(|| Box::new(write::Write::default())); store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv })); - store.register_pre_expansion_pass(|| Box::new(dbg_macro::DbgMacro)); } #[doc(hidden)] @@ -707,7 +705,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic)); store.register_early_pass(|| Box::new(reference::DerefAddrOf)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); - store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new())); + store.register_late_pass(|| Box::new(format_impl::FormatImpl::new())); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); @@ -724,10 +722,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(redundant_else::RedundantElse)); store.register_late_pass(|| Box::new(create_dir::CreateDir)); store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType)); - let cargo_ignore_publish = conf.cargo_ignore_publish; - store.register_late_pass(move || Box::new(cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish))); - store.register_late_pass(|| Box::new(multiple_crate_versions::MultipleCrateVersions)); - store.register_late_pass(|| Box::new(wildcard_dependencies::WildcardDependencies)); let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; store.register_early_pass(move || { Box::new(literal_representation::LiteralDigitGrouping::new( @@ -842,7 +836,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts))); store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings)); store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors)); - store.register_late_pass(move || Box::new(feature_name::FeatureName)); store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator)); store.register_late_pass(move || Box::new(manual_assert::ManualAssert)); let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; @@ -863,6 +856,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv))); store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); + store.register_late_pass(|| Box::new(dbg_macro::DbgMacro)); + let cargo_ignore_publish = conf.cargo_ignore_publish; + store.register_late_pass(move || { + Box::new(cargo::Cargo { + ignore_publish: cargo_ignore_publish, + }) + }); // add lints here, do not remove this comment, it's used in `new_lint` } @@ -939,6 +939,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) { ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types"); ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods"); ls.register_renamed("clippy::ref_in_deref", "clippy::needless_borrow"); + ls.register_renamed("clippy::to_string_in_display", "clippy::recursive_format_impl"); // uplifted lints ls.register_renamed("clippy::invalid_ref", "invalid_value"); diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 809aa168a7a0..dcf44303cf44 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::{match_def_path, meets_msrv, msrvs, paths}; +use clippy_utils::{meets_msrv, msrvs}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; @@ -8,6 +8,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -99,7 +100,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< if let Some(GenericArg::Type(real_ty)) = args.args.get(0); if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::MEM_SIZE_OF); + if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id); then { cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (real_ty, resolved_ty)) } else { diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index d605b6d73c09..2e1f7646eb40 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::{higher, is_wild}; use rustc_ast::{Attribute, LitKind}; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Guard, MatchSource, Pat}; +use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::source_map::Spanned; @@ -11,7 +11,7 @@ use rustc_span::source_map::Spanned; use super::MATCH_LIKE_MATCHES_MACRO; /// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!` -pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { +pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::IfLet { let_pat, let_expr, @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool if_else: Some(if_else), }) = higher::IfLet::hir(cx, expr) { - return find_matches_sugg( + find_matches_sugg( cx, let_expr, IntoIterator::into_iter([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]), @@ -27,25 +27,28 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool true, ); } +} - if let ExprKind::Match(scrut, arms, MatchSource::Normal) = expr.kind { - return find_matches_sugg( - cx, - scrut, - arms.iter().map(|arm| { - ( - cx.tcx.hir().attrs(arm.hir_id), - Some(arm.pat), - arm.body, - arm.guard.as_ref(), - ) - }), - expr, - false, - ); - } - - false +pub(super) fn check_match<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + scrutinee: &'tcx Expr<'_>, + arms: &'tcx [Arm<'tcx>], +) -> bool { + find_matches_sugg( + cx, + scrutinee, + arms.iter().map(|arm| { + ( + cx.tcx.hir().attrs(arm.hir_id), + Some(arm.pat), + arm.body, + arm.guard.as_ref(), + ) + }), + e, + false, + ) } /// Lint a `match` or `if let` for replacement by `matches!` diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 271a38685955..d11dda57e6fd 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,96 +1,94 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::{path_to_local, search_same, SpanlessEq, SpanlessHash}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdSet, MatchSource, Pat, PatKind}; +use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdSet, Pat, PatKind}; use rustc_lint::LateContext; use std::collections::hash_map::Entry; use super::MATCH_SAME_ARMS; -pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) { - if let ExprKind::Match(_, arms, MatchSource::Normal) = expr.kind { - let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 { - let mut h = SpanlessHash::new(cx); - h.hash_expr(arm.body); - h.finish() - }; +pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { + let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 { + let mut h = SpanlessHash::new(cx); + h.hash_expr(arm.body); + h.finish() + }; - let eq = |&(lindex, lhs): &(usize, &Arm<'_>), &(rindex, rhs): &(usize, &Arm<'_>)| -> bool { - let min_index = usize::min(lindex, rindex); - let max_index = usize::max(lindex, rindex); + let eq = |&(lindex, lhs): &(usize, &Arm<'_>), &(rindex, rhs): &(usize, &Arm<'_>)| -> bool { + let min_index = usize::min(lindex, rindex); + let max_index = usize::max(lindex, rindex); - let mut local_map: HirIdMap = HirIdMap::default(); - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { - if_chain! { - if let Some(a_id) = path_to_local(a); - if let Some(b_id) = path_to_local(b); - let entry = match local_map.entry(a_id) { - Entry::Vacant(entry) => entry, - // check if using the same bindings as before - Entry::Occupied(entry) => return *entry.get() == b_id, - }; - // the names technically don't have to match; this makes the lint more conservative - if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id); - if cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b); - if pat_contains_local(lhs.pat, a_id); - if pat_contains_local(rhs.pat, b_id); - then { - entry.insert(b_id); - true - } else { - false - } + let mut local_map: HirIdMap = HirIdMap::default(); + let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + if_chain! { + if let Some(a_id) = path_to_local(a); + if let Some(b_id) = path_to_local(b); + let entry = match local_map.entry(a_id) { + Entry::Vacant(entry) => entry, + // check if using the same bindings as before + Entry::Occupied(entry) => return *entry.get() == b_id, + }; + // the names technically don't have to match; this makes the lint more conservative + if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id); + if cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b); + if pat_contains_local(lhs.pat, a_id); + if pat_contains_local(rhs.pat, b_id); + then { + entry.insert(b_id); + true + } else { + false } - }; - // Arms with a guard are ignored, those can’t always be merged together - // This is also the case for arms in-between each there is an arm with a guard - (min_index..=max_index).all(|index| arms[index].guard.is_none()) - && SpanlessEq::new(cx) - .expr_fallback(eq_fallback) - .eq_expr(lhs.body, rhs.body) - // these checks could be removed to allow unused bindings - && bindings_eq(lhs.pat, local_map.keys().copied().collect()) - && bindings_eq(rhs.pat, local_map.values().copied().collect()) + } }; + // Arms with a guard are ignored, those can’t always be merged together + // This is also the case for arms in-between each there is an arm with a guard + (min_index..=max_index).all(|index| arms[index].guard.is_none()) + && SpanlessEq::new(cx) + .expr_fallback(eq_fallback) + .eq_expr(lhs.body, rhs.body) + // these checks could be removed to allow unused bindings + && bindings_eq(lhs.pat, local_map.keys().copied().collect()) + && bindings_eq(rhs.pat, local_map.values().copied().collect()) + }; - let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); - for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) { - span_lint_and_then( - cx, - MATCH_SAME_ARMS, - j.body.span, - "this `match` has identical arm bodies", - |diag| { - diag.span_note(i.body.span, "same as this"); + let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); + for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) { + span_lint_and_then( + cx, + MATCH_SAME_ARMS, + j.body.span, + "this `match` has identical arm bodies", + |diag| { + diag.span_note(i.body.span, "same as this"); - // Note: this does not use `span_suggestion` on purpose: - // there is no clean way - // to remove the other arm. Building a span and suggest to replace it to "" - // makes an even more confusing error message. Also in order not to make up a - // span for the whole pattern, the suggestion is only shown when there is only - // one pattern. The user should know about `|` if they are already using it… + // Note: this does not use `span_suggestion` on purpose: + // there is no clean way + // to remove the other arm. Building a span and suggest to replace it to "" + // makes an even more confusing error message. Also in order not to make up a + // span for the whole pattern, the suggestion is only shown when there is only + // one pattern. The user should know about `|` if they are already using it… - let lhs = snippet(cx, i.pat.span, ""); - let rhs = snippet(cx, j.pat.span, ""); + let lhs = snippet(cx, i.pat.span, ""); + let rhs = snippet(cx, j.pat.span, ""); - if let PatKind::Wild = j.pat.kind { - // if the last arm is _, then i could be integrated into _ - // note that i.pat cannot be _, because that would mean that we're - // hiding all the subsequent arms, and rust won't compile - diag.span_note( - i.body.span, - &format!( - "`{}` has the same arm body as the `_` wildcard, consider removing it", - lhs - ), - ); - } else { - diag.span_help(i.pat.span, &format!("consider refactoring into `{} | {}`", lhs, rhs,)) - .help("...or consider changing the match arm bodies"); - } - }, - ); - } + if let PatKind::Wild = j.pat.kind { + // if the last arm is _, then i could be integrated into _ + // note that i.pat cannot be _, because that would mean that we're + // hiding all the subsequent arms, and rust won't compile + diag.span_note( + i.body.span, + &format!( + "`{}` has the same arm body as the `_` wildcard, consider removing it", + lhs + ), + ); + } else { + diag.span_help(i.pat.span, &format!("consider refactoring into `{} | {}`", lhs, rhs,)) + .help("...or consider changing the match arm bodies"); + } + }, + ); } } diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 8ae19e03f1a6..39fe54648fbc 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, snippet_block, snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{indent_of, snippet_block, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; use rustc_errors::Applicability; @@ -14,23 +14,6 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e return; } - // HACK: - // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here - // to prevent false positives as there is currently no better way to detect if code was excluded by - // a macro. See PR #6435 - if_chain! { - if let Some(match_snippet) = snippet_opt(cx, expr.span); - if let Some(arm_snippet) = snippet_opt(cx, arms[0].span); - if let Some(ex_snippet) = snippet_opt(cx, ex.span); - let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, ""); - if rest_snippet.contains("=>"); - then { - // The code it self contains another thick arrow "=>" - // -> Either another arm or a comment - return; - } - } - let matched_vars = ex.span; let bind_names = arms[0].pat.span; let match_body = peel_blocks(arms[0].body); diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index b5ee4561f06e..92179eb6f0e6 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1,8 +1,11 @@ +use clippy_utils::source::{snippet_opt, walk_span_to_context}; use clippy_utils::{meets_msrv, msrvs}; -use rustc_hir::{Expr, ExprKind, Local, MatchSource, Pat}; +use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; +use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{Span, SpanData, SyntaxContext}; mod infalliable_detructuring_match; mod match_as_ref; @@ -604,33 +607,39 @@ impl<'tcx> LateLintPass<'tcx> for Matches { return; } - redundant_pattern_match::check(cx, expr); + if let ExprKind::Match(ex, arms, source) = expr.kind { + if !contains_cfg_arm(cx, expr, ex, arms) { + if source == MatchSource::Normal { + if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) + && match_like_matches::check_match(cx, expr, ex, arms)) + { + match_same_arms::check(cx, arms); + } - if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) { - if !match_like_matches::check(cx, expr) { - match_same_arms::check(cx, expr); + redundant_pattern_match::check_match(cx, expr, ex, arms); + single_match::check(cx, ex, arms, expr); + match_bool::check(cx, ex, arms, expr); + overlapping_arms::check(cx, ex, arms); + match_wild_enum::check(cx, ex, arms); + match_as_ref::check(cx, ex, arms, expr); + + if self.infallible_destructuring_match_linted { + self.infallible_destructuring_match_linted = false; + } else { + match_single_binding::check(cx, ex, arms, expr); + } + } + match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr); } - } else { - match_same_arms::check(cx, expr); - } - if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { - single_match::check(cx, ex, arms, expr); - match_bool::check(cx, ex, arms, expr); - overlapping_arms::check(cx, ex, arms); + // These don't depend on a relationship between multiple arms match_wild_err_arm::check(cx, ex, arms); - match_wild_enum::check(cx, ex, arms); - match_as_ref::check(cx, ex, arms, expr); wild_in_or_pats::check(cx, arms); - - if self.infallible_destructuring_match_linted { - self.infallible_destructuring_match_linted = false; - } else { - match_single_binding::check(cx, ex, arms, expr); + } else { + if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) { + match_like_matches::check(cx, expr); } - } - if let ExprKind::Match(ex, arms, _) = expr.kind { - match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr); + redundant_pattern_match::check(cx, expr); } } @@ -644,3 +653,94 @@ impl<'tcx> LateLintPass<'tcx> for Matches { extract_msrv_attr!(LateContext); } + +/// Checks if there are any arms with a `#[cfg(..)]` attribute. +fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]) -> bool { + let Some(scrutinee_span) = walk_span_to_context(scrutinee.span, SyntaxContext::root()) else { + // Shouldn't happen, but treat this as though a `cfg` attribute were found + return true; + }; + + let start = scrutinee_span.hi(); + let mut arm_spans = arms.iter().map(|arm| { + let data = arm.span.data(); + (data.ctxt == SyntaxContext::root()).then(|| (data.lo, data.hi)) + }); + let end = e.span.hi(); + + // Walk through all the non-code space before each match arm. The space trailing the final arm is + // handled after the `try_fold` e.g. + // + // match foo { + // _________^- everything between the scrutinee and arm1 + //| arm1 => (), + //|---^___________^ everything before arm2 + //| #[cfg(feature = "enabled")] + //| arm2 => some_code(), + //|---^____________________^ everything before arm3 + //| // some comment about arm3 + //| arm3 => some_code(), + //|---^____________________^ everything after arm3 + //| #[cfg(feature = "disabled")] + //| arm4 = some_code(), + //|}; + //|^ + let found = arm_spans.try_fold(start, |start, range| { + let Some((end, next_start)) = range else { + // Shouldn't happen as macros can't expand to match arms, but treat this as though a `cfg` attribute were + // found. + return Err(()); + }; + let span = SpanData { + lo: start, + hi: end, + ctxt: SyntaxContext::root(), + parent: None, + } + .span(); + (!span_contains_cfg(cx, span)).then(|| next_start).ok_or(()) + }); + match found { + Ok(start) => { + let span = SpanData { + lo: start, + hi: end, + ctxt: SyntaxContext::root(), + parent: None, + } + .span(); + span_contains_cfg(cx, span) + }, + Err(()) => true, + } +} + +/// Checks if the given span contains a `#[cfg(..)]` attribute +fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { + let Some(snip) = snippet_opt(cx, s) else { + // Assume true. This would require either an invalid span, or one which crosses file boundaries. + return true; + }; + let mut pos = 0usize; + let mut iter = tokenize(&snip).map(|t| { + let start = pos; + pos += t.len; + (t.kind, start..pos) + }); + + // Search for the token sequence [`#`, `[`, `cfg`] + while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, _)| { + matches!( + t, + TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } + ) + }); + if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) + && matches!(iter.next(), Some((TokenKind::Ident, range)) if &snip[range.clone()] == "cfg") + { + return true; + } + } + false +} diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 677b8cdf2ba0..777ec9b75bc2 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -12,13 +12,13 @@ use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, PollPending}; use rustc_hir::{ intravisit::{walk_expr, Visitor}, - Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp, + Arm, Block, Expr, ExprKind, LangItem, Node, Pat, PatKind, QPath, UnOp, }; use rustc_lint::LateContext; use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty}; use rustc_span::sym; -pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::IfLet { if_else, let_pat, @@ -27,11 +27,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { }) = higher::IfLet::hir(cx, expr) { find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some()); - } - if let ExprKind::Match(op, arms, MatchSource::Normal) = &expr.kind { - find_sugg_for_match(cx, expr, op, arms); - } - if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { + } else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) { find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false); } } @@ -59,7 +55,7 @@ fn type_needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, see // Check if any component type has any. match ty.kind() { ty::Tuple(fields) => fields.iter().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)), - &ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, ty, seen), + ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, *ty, seen), ty::Adt(adt, subs) => adt .all_fields() .map(|f| f.ty(cx.tcx, subs)) @@ -304,7 +300,7 @@ fn find_sugg_for_if_let<'tcx>( ); } -fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { +pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { if arms.len() == 2 { let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index 5ffcfd4d2641..d6c235b5a693 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_def_path, paths}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -32,7 +32,7 @@ impl<'tcx> LateLintPass<'tcx> for MemForget { if let ExprKind::Call(path_expr, [ref first_arg, ..]) = e.kind { if let ExprKind::Path(ref qpath) = path_expr.kind { if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() { - if match_def_path(cx, def_id, &paths::MEM_FORGET) { + if cx.tcx.is_diagnostic_item(sym::mem_forget, def_id) { let forgot_ty = cx.typeck_results().expr_ty(first_arg); if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) { diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index a184806d021b..054937e3e36b 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths}; +use clippy_utils::{is_default_equivalent, is_lang_ctor, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; @@ -249,7 +249,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { if let ExprKind::Call(func, func_args) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::MEM_REPLACE); + if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id); if let [dest, src] = func_args; then { check_replace_option_with_none(cx, src, dest, expr.span); diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index ce89189bce97..77d21f1d3730 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,8 +1,9 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_path_def_path, paths, ty::is_uninit_value_valid_for_ty}; +use clippy_utils::{is_expr_diagnostic_item, ty::is_uninit_value_valid_for_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::UNINIT_ASSUMED_INIT; @@ -11,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if_chain! { if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); - if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT); + if is_expr_diagnostic_item(cx, callee, sym::maybe_uninit_uninit); if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index cf9770f5c1fd..65d1f440b763 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,10 +1,11 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_def_path, match_trait_method, paths}; +use clippy_utils::{match_trait_method, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use std::cmp::Ordering; declare_clippy_lint! { @@ -73,14 +74,10 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons cx.typeck_results() .qpath_res(qpath, path.hir_id) .opt_def_id() - .and_then(|def_id| { - if match_def_path(cx, def_id, &paths::CMP_MIN) { - fetch_const(cx, args, MinMax::Min) - } else if match_def_path(cx, def_id, &paths::CMP_MAX) { - fetch_const(cx, args, MinMax::Max) - } else { - None - } + .and_then(|def_id| match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::cmp_min) => fetch_const(cx, args, MinMax::Min), + Some(sym::cmp_max) => fetch_const(cx, args, MinMax::Max), + _ => None, }) } else { None diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs deleted file mode 100644 index 1f9db39cf8ca..000000000000 --- a/clippy_lints/src/multiple_crate_versions.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! lint on multiple versions of a crate being used - -use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_lint_allowed; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::CRATE_HIR_ID; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::DUMMY_SP; - -use cargo_metadata::{DependencyKind, Node, Package, PackageId}; -use if_chain::if_chain; -use itertools::Itertools; - -declare_clippy_lint! { - /// ### What it does - /// Checks to see if multiple versions of a crate are being - /// used. - /// - /// ### Why is this bad? - /// This bloats the size of targets, and can lead to - /// confusing error messages when structs or traits are used interchangeably - /// between different versions of a crate. - /// - /// ### Known problems - /// Because this can be caused purely by the dependencies - /// themselves, it's not always possible to fix this issue. - /// - /// ### Example - /// ```toml - /// # This will pull in both winapi v0.3.x and v0.2.x, triggering a warning. - /// [dependencies] - /// ctrlc = "=3.1.0" - /// ansi_term = "=0.11.0" - /// ``` - #[clippy::version = "pre 1.29.0"] - pub MULTIPLE_CRATE_VERSIONS, - cargo, - "multiple versions of the same crate being used" -} - -declare_lint_pass!(MultipleCrateVersions => [MULTIPLE_CRATE_VERSIONS]); - -impl LateLintPass<'_> for MultipleCrateVersions { - fn check_crate(&mut self, cx: &LateContext<'_>) { - if is_lint_allowed(cx, MULTIPLE_CRATE_VERSIONS, CRATE_HIR_ID) { - return; - } - - let metadata = unwrap_cargo_metadata!(cx, MULTIPLE_CRATE_VERSIONS, true); - let local_name = cx.tcx.crate_name(LOCAL_CRATE); - let mut packages = metadata.packages; - packages.sort_by(|a, b| a.name.cmp(&b.name)); - - if_chain! { - if let Some(resolve) = &metadata.resolve; - if let Some(local_id) = packages - .iter() - .find_map(|p| if p.name == local_name.as_str() { Some(&p.id) } else { None }); - then { - for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { - let group: Vec<&Package> = group.collect(); - - if group.len() <= 1 { - continue; - } - - if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) { - let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect(); - versions.sort(); - let versions = versions.iter().join(", "); - - span_lint( - cx, - MULTIPLE_CRATE_VERSIONS, - DUMMY_SP, - &format!("multiple versions for dependency `{}`: {}", name, versions), - ); - } - } - } - } - } -} - -fn is_normal_dep(nodes: &[Node], local_id: &PackageId, dep_id: &PackageId) -> bool { - fn depends_on(node: &Node, dep_id: &PackageId) -> bool { - node.deps.iter().any(|dep| { - dep.pkg == *dep_id - && dep - .dep_kinds - .iter() - .any(|info| matches!(info.kind, DependencyKind::Normal)) - }) - } - - nodes - .iter() - .filter(|node| depends_on(node, dep_id)) - .any(|node| node.id == *local_id || is_normal_dep(nodes, local_id, &node.id)) -} diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 4cb79648ae36..6c68c1bc48df 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -13,7 +13,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for types with a `fn new() -> Self` method and no + /// Checks for public types with a `pub fn new() -> Self` method and no /// implementation of /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html). /// @@ -24,10 +24,10 @@ declare_clippy_lint! { /// /// ### Example /// ```ignore - /// struct Foo(Bar); + /// pub struct Foo(Bar); /// /// impl Foo { - /// fn new() -> Self { + /// pub fn new() -> Self { /// Foo(Bar::new()) /// } /// } @@ -36,7 +36,7 @@ declare_clippy_lint! { /// To fix the lint, add a `Default` implementation that delegates to `new`: /// /// ```ignore - /// struct Foo(Bar); + /// pub struct Foo(Bar); /// /// impl Default for Foo { /// fn default() -> Self { @@ -47,7 +47,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub NEW_WITHOUT_DEFAULT, style, - "`fn new() -> Self` method without `Default` implementation" + "`pub fn new() -> Self` method without `Default` implementation" } #[derive(Clone, Default)] @@ -85,6 +85,10 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // can't be implemented for unsafe new return; } + if clippy_utils::is_doc_hidden(cx.tcx.hir().attrs(id)) { + // shouldn't be implemented when it is hidden in docs + return; + } if impl_item .generics .params diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index e0ce1b7db003..2c328195f24e 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -547,7 +547,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: // Helper function to handle early returns. let mut set_skip_flag = || { - if result.skip { + if !result.skip { self.skip_count += 1; } result.skip = true; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 3e0e32857f1d..b3988973256c 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { } if let ty::Adt(def, _) = arg_ty.kind() { - if match_def_path(cx, def.did, &paths::MEM_MANUALLY_DROP) { + if def.is_manually_drop() { continue; } } diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index cd3aee556553..25a9072ef6e0 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -1,11 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::is_type_lang_item; +use clippy_utils::ty::{is_type_lang_item, peel_mid_ty_refs}; use if_chain::if_chain; +use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; +use rustc_middle::ty::subst::GenericArg; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -39,7 +42,34 @@ declare_clippy_lint! { "redundant slicing of the whole range of a type" } -declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]); +declare_clippy_lint! { + /// ### What it does + /// Checks for slicing expressions which are equivalent to dereferencing the + /// value. + /// + /// ### Why is this bad? + /// Some people may prefer to dereference rather than slice. + /// + /// ### Example + /// ```rust + /// let vec = vec![1, 2, 3]; + /// let slice = &vec[..]; + /// ``` + /// Use instead: + /// ```rust + /// let vec = vec![1, 2, 3]; + /// let slice = &*vec; + /// ``` + #[clippy::version = "1.60.0"] + pub DEREF_BY_SLICING, + restriction, + "slicing instead of dereferencing" +} + +declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING, DEREF_BY_SLICING]); + +static REDUNDANT_SLICING_LINT: (&Lint, &str) = (REDUNDANT_SLICING, "redundant slicing of the whole range"); +static DEREF_BY_SLICING_LINT: (&Lint, &str) = (DEREF_BY_SLICING, "slicing when dereferencing would work"); impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -53,34 +83,84 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { if addressee.span.ctxt() == ctxt; if let ExprKind::Index(indexed, range) = addressee.kind; if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull); - if cx.typeck_results().expr_ty(expr) == cx.typeck_results().expr_ty(indexed); then { + let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr)); + let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed)); + let parent_expr = get_parent_expr(cx, expr); + let needs_parens_for_prefix = parent_expr.map_or(false, |parent| { + parent.precedence().order() > PREC_PREFIX + }); let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; - let (reborrow_str, help_str) = if mutability == Mutability::Mut { - // The slice was used to reborrow the mutable reference. - ("&mut *", "reborrow the original value instead") - } else if matches!( - get_parent_expr(cx, expr), - Some(Expr { - kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _), - .. - }) - ) { - // The slice was used to make a temporary reference. - ("&*", "reborrow the original value instead") + let ((lint, msg), help, sugg) = if expr_ty == indexed_ty { + if expr_ref_count > indexed_ref_count { + // Indexing takes self by reference and can't return a reference to that + // reference as it's a local variable. The only way this could happen is if + // `self` contains a reference to the `Self` type. If this occurs then the + // lint no longer applies as it's essentially a field access, which is not + // redundant. + return; + } + let deref_count = indexed_ref_count - expr_ref_count; + + let (lint, reborrow_str, help_str) = if mutability == Mutability::Mut { + // The slice was used to reborrow the mutable reference. + (DEREF_BY_SLICING_LINT, "&mut *", "reborrow the original value instead") + } else if matches!( + parent_expr, + Some(Expr { + kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _), + .. + }) + ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| { + matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. }))) + }) { + // The slice was used to make a temporary reference. + (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead") + } else if deref_count != 0 { + (DEREF_BY_SLICING_LINT, "", "dereference the original value instead") + } else { + (REDUNDANT_SLICING_LINT, "", "use the original value instead") + }; + + let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; + let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix { + format!("({}{}{})", reborrow_str, "*".repeat(deref_count), snip) + } else { + format!("{}{}{}", reborrow_str, "*".repeat(deref_count), snip) + }; + + (lint, help_str, sugg) + } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { + if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( + cx.param_env, + cx.tcx.mk_projection(target_id, cx.tcx.mk_substs([GenericArg::from(indexed_ty)].into_iter())), + ) { + if deref_ty == expr_ty { + let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; + let sugg = if needs_parens_for_prefix { + format!("(&{}{}*{})", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip) + } else { + format!("&{}{}*{}", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip) + }; + (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg) + } else { + return; + } + } else { + return; + } } else { - ("", "use the original value instead") + return; }; span_lint_and_sugg( cx, - REDUNDANT_SLICING, + lint, expr.span, - "redundant slicing of the whole range", - help_str, - format!("{}{}", reborrow_str, snip), + msg, + help, + sugg, app, ); } diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index f3515ea3c2dd..3d7dc49b406a 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -9,6 +9,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -44,8 +45,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: if !inverted; if let ExprKind::Path(ref count_func_qpath) = count_func.kind; if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::MEM_SIZE_OF) - || match_def_path(cx, def_id, &paths::MEM_SIZE_OF_VAL); + if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::mem_size_of | sym::mem_size_of_val)); then { cx.typeck_results().node_substs(count_func.hir_id).types().next() } else { diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs deleted file mode 100644 index 03060d78fc5a..000000000000 --- a/clippy_lints/src/to_string_in_display.rs +++ /dev/null @@ -1,123 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_diag_trait_item, match_def_path, path_to_local_id, paths}; -use if_chain::if_chain; -use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for uses of `to_string()` in `Display` traits. - /// - /// ### Why is this bad? - /// Usually `to_string` is implemented indirectly - /// via `Display`. Hence using it while implementing `Display` would - /// lead to infinite recursion. - /// - /// ### Example - /// - /// ```rust - /// use std::fmt; - /// - /// struct Structure(i32); - /// impl fmt::Display for Structure { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - /// write!(f, "{}", self.to_string()) - /// } - /// } - /// - /// ``` - /// Use instead: - /// ```rust - /// use std::fmt; - /// - /// struct Structure(i32); - /// impl fmt::Display for Structure { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - /// write!(f, "{}", self.0) - /// } - /// } - /// ``` - #[clippy::version = "1.48.0"] - pub TO_STRING_IN_DISPLAY, - correctness, - "`to_string` method used while implementing `Display` trait" -} - -#[derive(Default)] -pub struct ToStringInDisplay { - in_display_impl: bool, - self_hir_id: Option, -} - -impl ToStringInDisplay { - pub fn new() -> Self { - Self { - in_display_impl: false, - self_hir_id: None, - } - } -} - -impl_lint_pass!(ToStringInDisplay => [TO_STRING_IN_DISPLAY]); - -impl LateLintPass<'_> for ToStringInDisplay { - fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_display_impl(cx, item) { - self.in_display_impl = true; - } - } - - fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if is_display_impl(cx, item) { - self.in_display_impl = false; - self.self_hir_id = None; - } - } - - fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { - if_chain! { - if self.in_display_impl; - if let ImplItemKind::Fn(.., body_id) = &impl_item.kind; - let body = cx.tcx.hir().body(*body_id); - if !body.params.is_empty(); - then { - let self_param = &body.params[0]; - self.self_hir_id = Some(self_param.pat.hir_id); - } - } - } - - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if self.in_display_impl; - if let Some(self_hir_id) = self.self_hir_id; - if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind; - if path.ident.name == sym!(to_string); - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_diag_trait_item(cx, expr_def_id, sym::ToString); - if path_to_local_id(self_arg, self_hir_id); - then { - span_lint( - cx, - TO_STRING_IN_DISPLAY, - expr.span, - "using `to_string` in `fmt::Display` implementation might lead to infinite recursion", - ); - } - } - } -} - -fn is_display_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if_chain! { - if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind; - if let Some(did) = trait_ref.trait_def_id(); - then { - match_def_path(cx, did, &paths::DISPLAY_TRAIT) - } else { - false - } - } -} diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index bca95b7f2563..be9d538c3626 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -98,8 +98,9 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; if !bound_predicate.span.from_expansion(); if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; - if let Some(PathSegment { res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), .. }) = segments.first(); - + if let Some(PathSegment { + res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), .. + }) = segments.first(); if let Some( Node::Item( Item { diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 5e94ab6d0482..22a8c53a5852 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -358,7 +358,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for transmutes either to or from a type which does not have a defined representation. + /// Checks for transmutes between types which do not have a representation defined relative to + /// each other. /// /// ### Why is this bad? /// The results of such a transmute are not defined. @@ -376,7 +377,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.60.0"] pub TRANSMUTE_UNDEFINED_REPR, - nursery, + correctness, "transmute to or from a type with an undefined representation" } diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index a57c819cb225..05eadab3e6cc 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -1,5 +1,6 @@ use super::TRANSMUTE_UNDEFINED_REPR; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_c_void; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::subst::Subst; @@ -18,33 +19,55 @@ pub(super) fn check<'tcx>( while from_ty != to_ty { match reduce_refs(cx, e.span, from_ty, to_ty) { - ReducedTys::FromFatPtr { unsized_ty, .. } => { - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!("transmute from `{}` which has an undefined layout", from_ty_orig), - |diag| { - if from_ty_orig.peel_refs() != unsized_ty { - diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty)); - } - }, - ); - return true; + ReducedTys::FromFatPtr { + unsized_ty, + to_ty: to_sub_ty, + } => match reduce_ty(cx, to_sub_ty) { + ReducedTy::IntArray | ReducedTy::TypeErasure => break, + ReducedTy::Ref(to_sub_ty) => { + from_ty = unsized_ty; + to_ty = to_sub_ty; + continue; + }, + _ => { + span_lint_and_then( + cx, + TRANSMUTE_UNDEFINED_REPR, + e.span, + &format!("transmute from `{}` which has an undefined layout", from_ty_orig), + |diag| { + if from_ty_orig.peel_refs() != unsized_ty { + diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty)); + } + }, + ); + return true; + }, }, - ReducedTys::ToFatPtr { unsized_ty, .. } => { - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!("transmute to `{}` which has an undefined layout", to_ty_orig), - |diag| { - if to_ty_orig.peel_refs() != unsized_ty { - diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty)); - } - }, - ); - return true; + ReducedTys::ToFatPtr { + unsized_ty, + from_ty: from_sub_ty, + } => match reduce_ty(cx, from_sub_ty) { + ReducedTy::IntArray | ReducedTy::TypeErasure => break, + ReducedTy::Ref(from_sub_ty) => { + from_ty = from_sub_ty; + to_ty = unsized_ty; + continue; + }, + _ => { + span_lint_and_then( + cx, + TRANSMUTE_UNDEFINED_REPR, + e.span, + &format!("transmute to `{}` which has an undefined layout", to_ty_orig), + |diag| { + if to_ty_orig.peel_refs() != unsized_ty { + diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty)); + } + }, + ); + return true; + }, }, ReducedTys::ToPtr { from_ty: from_sub_ty, @@ -100,7 +123,8 @@ pub(super) fn check<'tcx>( from_ty: from_sub_ty, to_ty: to_sub_ty, } => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) { - (ReducedTy::IntArray, _) | (_, ReducedTy::IntArray) => return false, + (ReducedTy::IntArray | ReducedTy::TypeErasure, _) + | (_, ReducedTy::IntArray | ReducedTy::TypeErasure) => return false, (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => { span_lint_and_then( cx, @@ -184,13 +208,14 @@ pub(super) fn check<'tcx>( } enum ReducedTys<'tcx> { - FromFatPtr { unsized_ty: Ty<'tcx> }, - ToFatPtr { unsized_ty: Ty<'tcx> }, + FromFatPtr { unsized_ty: Ty<'tcx>, to_ty: Ty<'tcx> }, + ToFatPtr { unsized_ty: Ty<'tcx>, from_ty: Ty<'tcx> }, ToPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }, FromPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }, Other { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }, } +/// Remove references so long as both types are references. fn reduce_refs<'tcx>( cx: &LateContext<'tcx>, span: Span, @@ -200,27 +225,27 @@ fn reduce_refs<'tcx>( loop { return match (from_ty.kind(), to_ty.kind()) { ( - &ty::Ref(_, from_sub_ty, _) | &ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. }), - &ty::Ref(_, to_sub_ty, _) | &ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. }), + &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })), + &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })), ) => { from_ty = from_sub_ty; to_ty = to_sub_ty; continue; }, - (&ty::Ref(_, unsized_ty, _) | &ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }), _) + (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _) if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) => { - ReducedTys::FromFatPtr { unsized_ty } + ReducedTys::FromFatPtr { unsized_ty, to_ty } }, - (_, &ty::Ref(_, unsized_ty, _) | &ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })) + (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }))) if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) => { - ReducedTys::ToFatPtr { unsized_ty } + ReducedTys::ToFatPtr { unsized_ty, from_ty } }, - (&ty::Ref(_, from_ty, _) | &ty::RawPtr(TypeAndMut { ty: from_ty, .. }), _) => { + (&(ty::Ref(_, from_ty, _) | ty::RawPtr(TypeAndMut { ty: from_ty, .. })), _) => { ReducedTys::FromPtr { from_ty, to_ty } }, - (_, &ty::Ref(_, to_ty, _) | &ty::RawPtr(TypeAndMut { ty: to_ty, .. })) => { + (_, &(ty::Ref(_, to_ty, _) | ty::RawPtr(TypeAndMut { ty: to_ty, .. }))) => { ReducedTys::ToPtr { from_ty, to_ty } }, _ => ReducedTys::Other { from_ty, to_ty }, @@ -229,13 +254,23 @@ fn reduce_refs<'tcx>( } enum ReducedTy<'tcx> { + /// The type can be used for type erasure. + TypeErasure, + /// The type is a struct containing either zero non-zero sized fields, or multiple non-zero + /// sized fields with a defined order. OrderedFields(Ty<'tcx>), + /// The type is a struct containing multiple non-zero sized fields with no defined order. UnorderedFields(Ty<'tcx>), + /// The type is a reference to the contained type. Ref(Ty<'tcx>), - Other(Ty<'tcx>), + /// The type is an array of a primitive integer type. These can be used as storage for a value + /// of another type. IntArray, + /// Any other type. + Other(Ty<'tcx>), } +/// Reduce structs containing a single non-zero sized field to it's contained type. fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> { loop { ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty); @@ -245,8 +280,9 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> ty = sub_ty; continue; }, + ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure, ty::Tuple(args) => { - let Some(sized_ty) = args.iter().find(|&ty| !is_zero_sized_ty(cx, ty)) else { + let Some(sized_ty) = args.iter().find(|&ty| !is_zero_sized_ty(cx, ty)) else { return ReducedTy::OrderedFields(ty); }; if args.iter().all(|ty| is_zero_sized_ty(cx, ty)) { @@ -256,24 +292,30 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> ReducedTy::UnorderedFields(ty) }, ty::Adt(def, substs) if def.is_struct() => { - if def.repr.inhibit_struct_field_reordering_opt() { - return ReducedTy::OrderedFields(ty); - } let mut iter = def .non_enum_variant() .fields .iter() .map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs)); - let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, *ty)) else { - return ReducedTy::OrderedFields(ty); + let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else { + return ReducedTy::TypeErasure; }; if iter.all(|ty| is_zero_sized_ty(cx, ty)) { ty = sized_ty; continue; } - ReducedTy::UnorderedFields(ty) + if def.repr.inhibit_struct_field_reordering_opt() { + ReducedTy::OrderedFields(ty) + } else { + ReducedTy::UnorderedFields(ty) + } + }, + ty::Adt(def, _) if def.is_enum() && (def.variants.is_empty() || is_c_void(cx, ty)) => { + ReducedTy::TypeErasure }, - ty::Ref(..) | ty::RawPtr(_) => ReducedTy::Ref(ty), + ty::Foreign(_) => ReducedTy::TypeErasure, + ty::Ref(_, ty, _) => ReducedTy::Ref(ty), + ty::RawPtr(ty) => ReducedTy::Ref(ty.ty), _ => ReducedTy::Other(ty), }; } diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 63ad65b8afd9..7c06906293b1 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{self as hir, GenericArg, GenericBounds, GenericParamKind}; use rustc_hir::{HirId, Lifetime, MutTy, Mutability, Node, QPath, TyKind}; use rustc_lint::LateContext; +use rustc_span::sym; use super::BORROWED_BOX; @@ -89,7 +89,7 @@ fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool { if let Some(trait_did) = traits[0].trait_ref.trait_def_id(); // Only Send/Sync can be used as additional traits, so it is enough to // check only the first trait. - if match_def_path(cx, trait_did, &paths::ANY_TRAIT); + if cx.tcx.is_diagnostic_item(sym::Any, trait_did); then { return true; } diff --git a/clippy_lints/src/undropped_manually_drops.rs b/clippy_lints/src/undropped_manually_drops.rs index 7557e14d11f5..db652766705c 100644 --- a/clippy_lints/src/undropped_manually_drops.rs +++ b/clippy_lints/src/undropped_manually_drops.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::path_res; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{match_function_call, paths}; -use rustc_hir::{lang_items, Expr}; +use rustc_hir::{lang_items, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -38,9 +39,12 @@ declare_lint_pass!(UndroppedManuallyDrops => [UNDROPPED_MANUALLY_DROPS]); impl<'tcx> LateLintPass<'tcx> for UndroppedManuallyDrops { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some([arg_0, ..]) = match_function_call(cx, expr, &paths::DROP) { + if_chain! { + if let ExprKind::Call(fun, [arg_0, ..]) = expr.kind; + if path_res(cx, fun).opt_def_id() == cx.tcx.get_diagnostic_item(sym::mem_drop); let ty = cx.typeck_results().expr_ty(arg_0); - if is_type_lang_item(cx, ty, lang_items::LangItem::ManuallyDrop) { + if is_type_lang_item(cx, ty, lang_items::LangItem::ManuallyDrop); + then { span_lint_and_help( cx, UNDROPPED_MANUALLY_DROPS, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index dc0f515bfe5c..4433d5f5bf14 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1305,7 +1305,7 @@ fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: S } span.adjust(if_chain_span.ctxt().outer_expn()); let sm = cx.sess().source_map(); - let span = sm.span_extend_to_prev_str(span, "let", false); + let span = sm.span_extend_to_prev_str(span, "let", false, true).unwrap_or(span); let span = sm.span_extend_to_next_char(span, ';', false); Span::new( span.lo() - BytePos(3), diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs deleted file mode 100644 index 80d7b8a1b6df..000000000000 --- a/clippy_lints/src/wildcard_dependencies.rs +++ /dev/null @@ -1,57 +0,0 @@ -use clippy_utils::{diagnostics::span_lint, is_lint_allowed}; -use rustc_hir::hir_id::CRATE_HIR_ID; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::DUMMY_SP; - -use if_chain::if_chain; - -declare_clippy_lint! { - /// ### What it does - /// Checks for wildcard dependencies in the `Cargo.toml`. - /// - /// ### Why is this bad? - /// [As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html), - /// it is highly unlikely that you work with any possible version of your dependency, - /// and wildcard dependencies would cause unnecessary breakage in the ecosystem. - /// - /// ### Example - /// ```toml - /// [dependencies] - /// regex = "*" - /// ``` - #[clippy::version = "1.32.0"] - pub WILDCARD_DEPENDENCIES, - cargo, - "wildcard dependencies being used" -} - -declare_lint_pass!(WildcardDependencies => [WILDCARD_DEPENDENCIES]); - -impl LateLintPass<'_> for WildcardDependencies { - fn check_crate(&mut self, cx: &LateContext<'_>) { - if is_lint_allowed(cx, WILDCARD_DEPENDENCIES, CRATE_HIR_ID) { - return; - } - - let metadata = unwrap_cargo_metadata!(cx, WILDCARD_DEPENDENCIES, false); - - for dep in &metadata.packages[0].dependencies { - // VersionReq::any() does not work - if_chain! { - if let Ok(wildcard_ver) = semver::VersionReq::parse("*"); - if let Some(ref source) = dep.source; - if !source.starts_with("git"); - if dep.req == wildcard_ver; - then { - span_lint( - cx, - WILDCARD_DEPENDENCIES, - DUMMY_SP, - &format!("wildcard dependency for `{}`", dep.name), - ); - } - } - } - } -} diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index afff6491aba6..d3ed8da4499f 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.60" +version = "0.1.61" edition = "2021" publish = false diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 4bb401273c40..397783e309e8 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1,6 +1,7 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_else)] +#![feature(let_chains)] #![feature(once_cell)] #![feature(rustc_private)] #![recursion_limit = "512"] @@ -2042,24 +2043,6 @@ pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir> expr } -#[macro_export] -macro_rules! unwrap_cargo_metadata { - ($cx: ident, $lint: ident, $deps: expr) => {{ - let mut command = cargo_metadata::MetadataCommand::new(); - if !$deps { - command.no_deps(); - } - - match command.exec() { - Ok(metadata) => metadata, - Err(err) => { - span_lint($cx, $lint, DUMMY_SP, &format!("could not read cargo metadata: {}", err)); - return; - }, - } - }}; -} - pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { if let Res::Def(_, def_id) = path.res { diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 5a76ac23332d..e7d4c5a49521 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -13,6 +13,33 @@ use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; use rustc_span::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol}; use std::ops::ControlFlow; +const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ + sym::assert_eq_macro, + sym::assert_macro, + sym::assert_ne_macro, + sym::debug_assert_eq_macro, + sym::debug_assert_macro, + sym::debug_assert_ne_macro, + sym::eprint_macro, + sym::eprintln_macro, + sym::format_args_macro, + sym::format_macro, + sym::print_macro, + sym::println_macro, + sym::std_panic_macro, + sym::write_macro, + sym::writeln_macro, +]; + +/// Returns true if a given Macro `DefId` is a format macro (e.g. `println!`) +pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool { + if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) { + FORMAT_MACRO_DIAG_ITEMS.contains(&name) + } else { + false + } +} + /// A macro call, like `vec![1, 2, 3]`. /// /// Use `tcx.item_name(macro_call.def_id)` to get the macro name. diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 288c56e9fd73..2778e30388e2 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -4,7 +4,6 @@ //! Whenever possible, please consider diagnostic items over hardcoded paths. //! See for more information. -pub const ANY_TRAIT: [&str; 3] = ["core", "any", "Any"]; #[cfg(feature = "internal")] pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"]; #[cfg(feature = "internal")] @@ -17,23 +16,12 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ #[cfg(feature = "internal")] pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"]; pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const ASSERT_EQ_MACRO: [&str; 3] = ["core", "macros", "assert_eq"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const ASSERT_MACRO: [&str; 4] = ["core", "macros", "builtin", "assert"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const ASSERT_NE_MACRO: [&str; 3] = ["core", "macros", "assert_ne"]; pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; -/// Preferably use the diagnostic item `sym::Borrow` where possible -pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"]; -pub const BORROW_MUT_TRAIT: [&str; 3] = ["core", "borrow", "BorrowMut"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"]; pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; -pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"]; -pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; @@ -42,24 +30,14 @@ pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"]; pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; -pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"]; -pub const DROP: [&str; 3] = ["core", "mem", "drop"]; -pub const DURATION: [&str; 3] = ["core", "time", "Duration"]; #[cfg(feature = "internal")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const EPRINT_MACRO: [&str; 3] = ["std", "macros", "eprint"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const EPRINTLN_MACRO: [&str; 3] = ["std", "macros", "eprintln"]; pub const EXIT: [&str; 3] = ["std", "process", "exit"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; pub const FILE: [&str; 3] = ["std", "fs", "File"]; pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const FORMAT_ARGS_MACRO: [&str; 4] = ["core", "macros", "builtin", "format_args"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; -pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"]; pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; @@ -67,7 +45,6 @@ pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator" pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[allow(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"]; -pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"]; pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"]; @@ -91,17 +68,8 @@ pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; #[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; -pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"]; -pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"]; -pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"]; -pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"]; -pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]; -pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"]; -pub const MEM_SIZE_OF: [&str; 3] = ["core", "mem", "size_of"]; -pub const MEM_SIZE_OF_VAL: [&str; 3] = ["core", "mem", "size_of_val"]; pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; -pub const OPS_MODULE: [&str; 2] = ["core", "ops"]; /// Preferably use the diagnostic item `sym::Option` where possible pub const OPTION: [&str; 3] = ["core", "option", "Option"]; pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"]; @@ -111,9 +79,9 @@ pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_RAWMUTEX: [&str; 3] = ["parking_lot", "raw_mutex", "RawMutex"]; pub const PARKING_LOT_RAWRWLOCK: [&str; 3] = ["parking_lot", "raw_rwlock", "RawRwLock"]; -pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"]; -pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"]; -pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"]; +pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; +pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; +pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"]; @@ -122,10 +90,6 @@ pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "Permis pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"]; pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"]; pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const PRINT_MACRO: [&str; 3] = ["std", "macros", "print"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const PRINTLN_MACRO: [&str; 3] = ["std", "macros", "println"]; pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"]; pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; @@ -206,8 +170,4 @@ pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const WRITE_MACRO: [&str; 3] = ["core", "macros", "write"]; -#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros -pub const WRITELN_MACRO: [&str; 3] = ["core", "macros", "writeln"]; pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 0d39226d9703..0646d1524a76 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -10,12 +10,14 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; +use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, + self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_target::abi::{Size, VariantIdx}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; use std::iter; @@ -515,3 +517,72 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option for EnumValue { + type Output = Self; + fn add(self, n: u32) -> Self::Output { + match self { + Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)), + Self::Signed(x) => Self::Signed(x + i128::from(n)), + } + } +} + +/// Attempts to read the given constant as though it were an an enum value. +#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] +pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option { + if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) { + match tcx.type_of(id).kind() { + ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() { + 1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8), + 2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16), + 4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32), + 8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64), + 16 => value.assert_bits(Size::from_bytes(16)) as i128, + _ => return None, + })), + ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() { + 1 => value.assert_bits(Size::from_bytes(1)), + 2 => value.assert_bits(Size::from_bytes(2)), + 4 => value.assert_bits(Size::from_bytes(4)), + 8 => value.assert_bits(Size::from_bytes(8)), + 16 => value.assert_bits(Size::from_bytes(16)), + _ => return None, + })), + _ => None, + } + } else { + None + } +} + +/// Gets the value of the given variant. +pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -> EnumValue { + let variant = &adt.variants[i]; + match variant.discr { + VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap(), + VariantDiscr::Relative(x) => match adt.variants[(i.as_usize() - x as usize).into()].discr { + VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap() + x, + VariantDiscr::Relative(_) => EnumValue::Unsigned(x.into()), + }, + } +} + +/// Check if the given type is either `core::ffi::c_void`, `std::os::raw::c_void`, or one of the +/// platform specific `libc::::c_void` types in libc. +pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + if let ty::Adt(adt, _) = ty.kind() + && let &[krate, .., name] = &*cx.get_def_path(adt.did) + && let sym::libc | sym::core | sym::std = krate + && name.as_str() == "c_void" + { + true + } else { + false + } +} diff --git a/rust-toolchain b/rust-toolchain index f065f0bffc7b..4d2c57619912 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-02-10" +channel = "nightly-2022-02-24" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/compile-test.rs b/tests/compile-test.rs index a82ff1828393..6bc74bc1e9aa 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -162,6 +162,11 @@ fn run_ui() { let config = base_config("ui"); // use tests/clippy.toml let _g = VarGuard::set("CARGO_MANIFEST_DIR", fs::canonicalize("tests").unwrap()); + let _threads = VarGuard::set( + "RUST_TEST_THREADS", + // if RUST_TEST_THREADS is set, adhere to it, otherwise override it + env::var("RUST_TEST_THREADS").unwrap_or_else(|_| num_cpus::get().to_string()), + ); compiletest::run_tests(&config); } diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 0251fada9e85..9f283337c7e1 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -120,3 +120,10 @@ macro_rules! mut_mut { let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32; }; } + +#[macro_export] +macro_rules! ptr_as_ptr_cast { + ($ptr: ident) => { + $ptr as *const i32 + }; +} diff --git a/tests/ui/await_holding_lock.rs b/tests/ui/await_holding_lock.rs index dd6640a387a2..57e5b55045b9 100644 --- a/tests/ui/await_holding_lock.rs +++ b/tests/ui/await_holding_lock.rs @@ -1,64 +1,192 @@ #![warn(clippy::await_holding_lock)] -use std::sync::Mutex; +// When adding or modifying a test, please do the same for parking_lot::Mutex. +mod std_mutex { + use super::baz; + use std::sync::{Mutex, RwLock}; -async fn bad(x: &Mutex) -> u32 { - let guard = x.lock().unwrap(); - baz().await -} + pub async fn bad(x: &Mutex) -> u32 { + let guard = x.lock().unwrap(); + baz().await + } -async fn good(x: &Mutex) -> u32 { - { + pub async fn good(x: &Mutex) -> u32 { + { + let guard = x.lock().unwrap(); + let y = *guard + 1; + } + baz().await; let guard = x.lock().unwrap(); - let y = *guard + 1; + 47 } - baz().await; - let guard = x.lock().unwrap(); - 47 -} -async fn baz() -> u32 { - 42 -} + pub async fn bad_rw(x: &RwLock) -> u32 { + let guard = x.read().unwrap(); + baz().await + } -async fn also_bad(x: &Mutex) -> u32 { - let first = baz().await; + pub async fn bad_rw_write(x: &RwLock) -> u32 { + let mut guard = x.write().unwrap(); + baz().await + } - let guard = x.lock().unwrap(); + pub async fn good_rw(x: &RwLock) -> u32 { + { + let guard = x.read().unwrap(); + let y = *guard + 1; + } + { + let mut guard = x.write().unwrap(); + *guard += 1; + } + baz().await; + let guard = x.read().unwrap(); + 47 + } - let second = baz().await; + pub async fn also_bad(x: &Mutex) -> u32 { + let first = baz().await; - let third = baz().await; + let guard = x.lock().unwrap(); - first + second + third + let second = baz().await; + + let third = baz().await; + + first + second + third + } + + pub async fn not_good(x: &Mutex) -> u32 { + let first = baz().await; + + let second = { + let guard = x.lock().unwrap(); + baz().await + }; + + let third = baz().await; + + first + second + third + } + + #[allow(clippy::manual_async_fn)] + pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { + async move { + let guard = x.lock().unwrap(); + baz().await + } + } } -async fn not_good(x: &Mutex) -> u32 { - let first = baz().await; +// When adding or modifying a test, please do the same for std::Mutex. +mod parking_lot_mutex { + use super::baz; + use parking_lot::{Mutex, RwLock}; - let second = { - let guard = x.lock().unwrap(); + pub async fn bad(x: &Mutex) -> u32 { + let guard = x.lock(); baz().await - }; + } - let third = baz().await; + pub async fn good(x: &Mutex) -> u32 { + { + let guard = x.lock(); + let y = *guard + 1; + } + baz().await; + let guard = x.lock(); + 47 + } - first + second + third -} + pub async fn bad_rw(x: &RwLock) -> u32 { + let guard = x.read(); + baz().await + } -#[allow(clippy::manual_async_fn)] -fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { - async move { - let guard = x.lock().unwrap(); + pub async fn bad_rw_write(x: &RwLock) -> u32 { + let mut guard = x.write(); baz().await } + + pub async fn good_rw(x: &RwLock) -> u32 { + { + let guard = x.read(); + let y = *guard + 1; + } + { + let mut guard = x.write(); + *guard += 1; + } + baz().await; + let guard = x.read(); + 47 + } + + pub async fn also_bad(x: &Mutex) -> u32 { + let first = baz().await; + + let guard = x.lock(); + + let second = baz().await; + + let third = baz().await; + + first + second + third + } + + pub async fn not_good(x: &Mutex) -> u32 { + let first = baz().await; + + let second = { + let guard = x.lock(); + baz().await + }; + + let third = baz().await; + + first + second + third + } + + #[allow(clippy::manual_async_fn)] + pub fn block_bad(x: &Mutex) -> impl std::future::Future + '_ { + async move { + let guard = x.lock(); + baz().await + } + } +} + +async fn baz() -> u32 { + 42 +} + +async fn no_await(x: std::sync::Mutex) { + let mut guard = x.lock().unwrap(); + *guard += 1; +} + +// FIXME: FP, because the `MutexGuard` is dropped before crossing the await point. This is +// something the needs to be fixed in rustc. There's already drop-tracking, but this is currently +// disabled, see rust-lang/rust#93751. This case isn't picked up by drop-tracking though. If the +// `*guard += 1` is removed it is picked up. +async fn dropped_before_await(x: std::sync::Mutex) { + let mut guard = x.lock().unwrap(); + *guard += 1; + drop(guard); + baz().await; } fn main() { - let m = Mutex::new(100); - good(&m); - bad(&m); - also_bad(&m); - not_good(&m); - block_bad(&m); + let m = std::sync::Mutex::new(100); + std_mutex::good(&m); + std_mutex::bad(&m); + std_mutex::also_bad(&m); + std_mutex::not_good(&m); + std_mutex::block_bad(&m); + + let m = parking_lot::Mutex::new(100); + parking_lot_mutex::good(&m); + parking_lot_mutex::bad(&m); + parking_lot_mutex::also_bad(&m); + parking_lot_mutex::not_good(&m); } diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr index ddfb104cdfbd..976da8d92424 100644 --- a/tests/ui/await_holding_lock.stderr +++ b/tests/ui/await_holding_lock.stderr @@ -1,63 +1,208 @@ -error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:6:9 +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:9:13 | -LL | let guard = x.lock().unwrap(); - | ^^^^^ +LL | let guard = x.lock().unwrap(); + | ^^^^^ | = note: `-D clippy::await-holding-lock` implied by `-D warnings` -note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:6:5 + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:9:9 | -LL | / let guard = x.lock().unwrap(); -LL | | baz().await -LL | | } - | |_^ +LL | / let guard = x.lock().unwrap(); +LL | | baz().await +LL | | } + | |_____^ -error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:27:9 +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:24:13 | -LL | let guard = x.lock().unwrap(); - | ^^^^^ +LL | let guard = x.read().unwrap(); + | ^^^^^ | -note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:27:5 + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:24:9 | -LL | / let guard = x.lock().unwrap(); +LL | / let guard = x.read().unwrap(); +LL | | baz().await +LL | | } + | |_____^ + +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:29:13 + | +LL | let mut guard = x.write().unwrap(); + | ^^^^^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:29:9 + | +LL | / let mut guard = x.write().unwrap(); +LL | | baz().await +LL | | } + | |_____^ + +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:50:13 + | +LL | let guard = x.lock().unwrap(); + | ^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:50:9 + | +LL | / let guard = x.lock().unwrap(); LL | | -LL | | let second = baz().await; +LL | | let second = baz().await; LL | | ... | -LL | | first + second + third -LL | | } - | |_^ +LL | | first + second + third +LL | | } + | |_____^ -error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:40:13 +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:63:17 | -LL | let guard = x.lock().unwrap(); +LL | let guard = x.lock().unwrap(); + | ^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:63:13 + | +LL | / let guard = x.lock().unwrap(); +LL | | baz().await +LL | | }; + | |_________^ + +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:75:17 + | +LL | let guard = x.lock().unwrap(); + | ^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:75:13 + | +LL | / let guard = x.lock().unwrap(); +LL | | baz().await +LL | | } + | |_________^ + +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:87:13 + | +LL | let guard = x.lock(); | ^^^^^ | -note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:40:9 + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:87:9 | -LL | / let guard = x.lock().unwrap(); +LL | / let guard = x.lock(); LL | | baz().await -LL | | }; +LL | | } | |_____^ -error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:52:13 +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:102:13 | -LL | let guard = x.lock().unwrap(); +LL | let guard = x.read(); | ^^^^^ | -note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:52:9 + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:102:9 | -LL | / let guard = x.lock().unwrap(); +LL | / let guard = x.read(); LL | | baz().await LL | | } | |_____^ -error: aborting due to 4 previous errors +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:107:13 + | +LL | let mut guard = x.write(); + | ^^^^^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:107:9 + | +LL | / let mut guard = x.write(); +LL | | baz().await +LL | | } + | |_____^ + +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:128:13 + | +LL | let guard = x.lock(); + | ^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:128:9 + | +LL | / let guard = x.lock(); +LL | | +LL | | let second = baz().await; +LL | | +... | +LL | | first + second + third +LL | | } + | |_____^ + +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:141:17 + | +LL | let guard = x.lock(); + | ^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:141:13 + | +LL | / let guard = x.lock(); +LL | | baz().await +LL | | }; + | |_________^ + +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:153:17 + | +LL | let guard = x.lock(); + | ^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:153:13 + | +LL | / let guard = x.lock(); +LL | | baz().await +LL | | } + | |_________^ + +error: this `MutexGuard` is held across an `await` point + --> $DIR/await_holding_lock.rs:173:9 + | +LL | let mut guard = x.lock().unwrap(); + | ^^^^^^^^^ + | + = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await +note: these are all the `await` points this lock is held through + --> $DIR/await_holding_lock.rs:173:5 + | +LL | / let mut guard = x.lock().unwrap(); +LL | | *guard += 1; +LL | | drop(guard); +LL | | baz().await; +LL | | } + | |_^ + +error: aborting due to 13 previous errors diff --git a/tests/ui/await_holding_refcell_ref.stderr b/tests/ui/await_holding_refcell_ref.stderr index 67cc0032be2f..4339fca735dd 100644 --- a/tests/ui/await_holding_refcell_ref.stderr +++ b/tests/ui/await_holding_refcell_ref.stderr @@ -1,11 +1,12 @@ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await +error: this `RefCell` reference is held across an `await` point --> $DIR/await_holding_refcell_ref.rs:6:9 | LL | let b = x.borrow(); | ^ | = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` -note: these are all the await points this ref is held through + = help: ensure the reference is dropped before calling `await` +note: these are all the `await` points this reference is held through --> $DIR/await_holding_refcell_ref.rs:6:5 | LL | / let b = x.borrow(); @@ -13,13 +14,14 @@ LL | | baz().await LL | | } | |_^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await +error: this `RefCell` reference is held across an `await` point --> $DIR/await_holding_refcell_ref.rs:11:9 | LL | let b = x.borrow_mut(); | ^ | -note: these are all the await points this ref is held through + = help: ensure the reference is dropped before calling `await` +note: these are all the `await` points this reference is held through --> $DIR/await_holding_refcell_ref.rs:11:5 | LL | / let b = x.borrow_mut(); @@ -27,13 +29,14 @@ LL | | baz().await LL | | } | |_^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await +error: this `RefCell` reference is held across an `await` point --> $DIR/await_holding_refcell_ref.rs:32:9 | LL | let b = x.borrow_mut(); | ^ | -note: these are all the await points this ref is held through + = help: ensure the reference is dropped before calling `await` +note: these are all the `await` points this reference is held through --> $DIR/await_holding_refcell_ref.rs:32:5 | LL | / let b = x.borrow_mut(); @@ -45,13 +48,14 @@ LL | | first + second + third LL | | } | |_^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await +error: this `RefCell` reference is held across an `await` point --> $DIR/await_holding_refcell_ref.rs:44:9 | LL | let b = x.borrow_mut(); | ^ | -note: these are all the await points this ref is held through + = help: ensure the reference is dropped before calling `await` +note: these are all the `await` points this reference is held through --> $DIR/await_holding_refcell_ref.rs:44:5 | LL | / let b = x.borrow_mut(); @@ -63,13 +67,14 @@ LL | | first + second + third LL | | } | |_^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await +error: this `RefCell` reference is held across an `await` point --> $DIR/await_holding_refcell_ref.rs:59:13 | LL | let b = x.borrow_mut(); | ^ | -note: these are all the await points this ref is held through + = help: ensure the reference is dropped before calling `await` +note: these are all the `await` points this reference is held through --> $DIR/await_holding_refcell_ref.rs:59:9 | LL | / let b = x.borrow_mut(); @@ -77,13 +82,14 @@ LL | | baz().await LL | | }; | |_____^ -error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await +error: this `RefCell` reference is held across an `await` point --> $DIR/await_holding_refcell_ref.rs:71:13 | LL | let b = x.borrow_mut(); | ^ | -note: these are all the await points this ref is held through + = help: ensure the reference is dropped before calling `await` +note: these are all the `await` points this reference is held through --> $DIR/await_holding_refcell_ref.rs:71:9 | LL | / let b = x.borrow_mut(); diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index ebc1ed5587fe..2e31ad3172ee 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,3 +1,6 @@ +#![feature(repr128)] +#![allow(incomplete_features)] + #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, @@ -115,4 +118,137 @@ fn main() { }) as u8; 999999u64.clamp(0, 255) as u8; 999999u64.clamp(0, 256) as u8; // should still be linted + + #[derive(Clone, Copy)] + enum E1 { + A, + B, + C, + } + impl E1 { + fn test(self) { + let _ = self as u8; // Don't lint. `0..=2` fits in u8 + } + } + + #[derive(Clone, Copy)] + enum E2 { + A = 255, + B, + } + impl E2 { + fn test(self) { + let _ = self as u8; + let _ = Self::B as u8; + let _ = self as i16; // Don't lint. `255..=256` fits in i16 + let _ = Self::A as u8; // Don't lint. + } + } + + #[derive(Clone, Copy)] + enum E3 { + A = -1, + B, + C = 50, + } + impl E3 { + fn test(self) { + let _ = self as i8; // Don't lint. `-1..=50` fits in i8 + } + } + + #[derive(Clone, Copy)] + enum E4 { + A = -128, + B, + } + impl E4 { + fn test(self) { + let _ = self as i8; // Don't lint. `-128..=-127` fits in i8 + } + } + + #[derive(Clone, Copy)] + enum E5 { + A = -129, + B = 127, + } + impl E5 { + fn test(self) { + let _ = self as i8; + let _ = Self::A as i8; + let _ = self as i16; // Don't lint. `-129..=127` fits in i16 + let _ = Self::B as u8; // Don't lint. + } + } + + #[derive(Clone, Copy)] + #[repr(u32)] + enum E6 { + A = u16::MAX as u32, + B, + } + impl E6 { + fn test(self) { + let _ = self as i16; + let _ = Self::A as u16; // Don't lint. `2^16-1` fits in u16 + let _ = self as u32; // Don't lint. `2^16-1..=2^16` fits in u32 + let _ = Self::A as u16; // Don't lint. + } + } + + #[derive(Clone, Copy)] + #[repr(u64)] + enum E7 { + A = u32::MAX as u64, + B, + } + impl E7 { + fn test(self) { + let _ = self as usize; + let _ = Self::A as usize; // Don't lint. + let _ = self as u64; // Don't lint. `2^32-1..=2^32` fits in u64 + } + } + + #[derive(Clone, Copy)] + #[repr(i128)] + enum E8 { + A = i128::MIN, + B, + C = 0, + D = i128::MAX, + } + impl E8 { + fn test(self) { + let _ = self as i128; // Don't lint. `-(2^127)..=2^127-1` fits it i128 + } + } + + #[derive(Clone, Copy)] + #[repr(u128)] + enum E9 { + A, + B = u128::MAX, + } + impl E9 { + fn test(self) { + let _ = Self::A as u8; // Don't lint. + let _ = self as u128; // Don't lint. `0..=2^128-1` fits in u128 + } + } + + #[derive(Clone, Copy)] + #[repr(usize)] + enum E10 { + A, + B = u32::MAX as usize, + } + impl E10 { + fn test(self) { + let _ = self as u16; + let _ = Self::B as u32; // Don't lint. + let _ = self as u64; // Don't lint. + } + } } diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index edf8790cf33d..7a68c0984f14 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:11:5 + --> $DIR/cast.rs:14:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -7,37 +7,37 @@ LL | x0 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:13:5 + --> $DIR/cast.rs:16:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> $DIR/cast.rs:14:5 + --> $DIR/cast.rs:17:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:16:5 + --> $DIR/cast.rs:19:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:18:5 + --> $DIR/cast.rs:21:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> $DIR/cast.rs:19:5 + --> $DIR/cast.rs:22:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> $DIR/cast.rs:21:5 + --> $DIR/cast.rs:24:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -45,13 +45,13 @@ LL | 1f32 as i32; = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` error: casting `f32` to `u32` may truncate the value - --> $DIR/cast.rs:22:5 + --> $DIR/cast.rs:25:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ error: casting `f32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:22:5 + --> $DIR/cast.rs:25:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -59,43 +59,43 @@ LL | 1f32 as u32; = note: `-D clippy::cast-sign-loss` implied by `-D warnings` error: casting `f64` to `f32` may truncate the value - --> $DIR/cast.rs:23:5 + --> $DIR/cast.rs:26:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> $DIR/cast.rs:24:5 + --> $DIR/cast.rs:27:5 | LL | 1i32 as i8; | ^^^^^^^^^^ error: casting `i32` to `u8` may truncate the value - --> $DIR/cast.rs:25:5 + --> $DIR/cast.rs:28:5 | LL | 1i32 as u8; | ^^^^^^^^^^ error: casting `f64` to `isize` may truncate the value - --> $DIR/cast.rs:26:5 + --> $DIR/cast.rs:29:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ error: casting `f64` to `usize` may truncate the value - --> $DIR/cast.rs:27:5 + --> $DIR/cast.rs:30:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `f64` to `usize` may lose the sign of the value - --> $DIR/cast.rs:27:5 + --> $DIR/cast.rs:30:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> $DIR/cast.rs:29:5 + --> $DIR/cast.rs:32:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -103,52 +103,96 @@ LL | 1u8 as i8; = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting `u16` to `i16` may wrap around the value - --> $DIR/cast.rs:30:5 + --> $DIR/cast.rs:33:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> $DIR/cast.rs:31:5 + --> $DIR/cast.rs:34:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> $DIR/cast.rs:32:5 + --> $DIR/cast.rs:35:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:36:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:36:5 + --> $DIR/cast.rs:39:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> $DIR/cast.rs:38:5 + --> $DIR/cast.rs:41:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> $DIR/cast.rs:105:5 + --> $DIR/cast.rs:108:5 | LL | (-99999999999i64).min(1) as i8; // should be linted because signed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> $DIR/cast.rs:117:5 + --> $DIR/cast.rs:120:5 | LL | 999999u64.clamp(0, 256) as u8; // should still be linted | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 24 previous errors +error: casting `main::E2` to `u8` may truncate the value + --> $DIR/cast.rs:141:21 + | +LL | let _ = self as u8; + | ^^^^^^^^^^ + +error: casting `main::E2::B` to `u8` will truncate the value + --> $DIR/cast.rs:142:21 + | +LL | let _ = Self::B as u8; + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::cast-enum-truncation` implied by `-D warnings` + +error: casting `main::E5` to `i8` may truncate the value + --> $DIR/cast.rs:178:21 + | +LL | let _ = self as i8; + | ^^^^^^^^^^ + +error: casting `main::E5::A` to `i8` will truncate the value + --> $DIR/cast.rs:179:21 + | +LL | let _ = Self::A as i8; + | ^^^^^^^^^^^^^ + +error: casting `main::E6` to `i16` may truncate the value + --> $DIR/cast.rs:193:21 + | +LL | let _ = self as i16; + | ^^^^^^^^^^^ + +error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers + --> $DIR/cast.rs:208:21 + | +LL | let _ = self as usize; + | ^^^^^^^^^^^^^ + +error: casting `main::E10` to `u16` may truncate the value + --> $DIR/cast.rs:249:21 + | +LL | let _ = self as u16; + | ^^^^^^^^^^^ + +error: aborting due to 31 previous errors diff --git a/tests/ui/dbg_macro.rs b/tests/ui/dbg_macro.rs index d74e2611ee1f..9b03c9b47832 100644 --- a/tests/ui/dbg_macro.rs +++ b/tests/ui/dbg_macro.rs @@ -16,4 +16,27 @@ fn main() { dbg!(42); dbg!(dbg!(dbg!(42))); foo(3) + dbg!(factorial(4)); + dbg!(1, 2, dbg!(3, 4)); + dbg!(1, 2, 3, 4, 5); +} + +mod issue7274 { + trait Thing<'b> { + fn foo(&self); + } + + macro_rules! define_thing { + ($thing:ident, $body:expr) => { + impl<'a> Thing<'a> for $thing { + fn foo<'b>(&self) { + $body + } + } + }; + } + + struct MyThing; + define_thing!(MyThing, { + dbg!(2); + }); } diff --git a/tests/ui/dbg_macro.stderr b/tests/ui/dbg_macro.stderr index 0abe953af261..8ee1b328720d 100644 --- a/tests/ui/dbg_macro.stderr +++ b/tests/ui/dbg_macro.stderr @@ -76,5 +76,38 @@ help: ensure to avoid having uses of it in version control LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ -error: aborting due to 7 previous errors +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:19:5 + | +LL | dbg!(1, 2, dbg!(3, 4)); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | (1, 2, dbg!(3, 4)); + | ~~~~~~~~~~~~~~~~~~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:20:5 + | +LL | dbg!(1, 2, 3, 4, 5); + | ^^^^^^^^^^^^^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | (1, 2, 3, 4, 5); + | ~~~~~~~~~~~~~~~ + +error: `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:40:9 + | +LL | dbg!(2); + | ^^^^^^^ + | +help: ensure to avoid having uses of it in version control + | +LL | 2; + | ~ + +error: aborting due to 10 previous errors diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 9114d8754dcc..264dd4efaeb8 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -46,9 +46,14 @@ fn main() { let s19 = ::default(); + let s20 = UpdateSyntax { + s: "foo", + ..Default::default() + }; + println!( - "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]", - s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, + "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", + s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, ); } @@ -86,3 +91,9 @@ struct ArrayDerivedDefault { #[derive(Debug, Default)] struct TupleStructDerivedDefault(String); + +#[derive(Debug, Default)] +struct UpdateSyntax { + pub s: &'static str, + pub u: u64, +} diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 8a5f0d6a7497..a0930fab8e7c 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -46,9 +46,14 @@ fn main() { let s19 = ::default(); + let s20 = UpdateSyntax { + s: "foo", + ..Default::default() + }; + println!( - "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]", - s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, + "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", + s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, ); } @@ -86,3 +91,9 @@ struct ArrayDerivedDefault { #[derive(Debug, Default)] struct TupleStructDerivedDefault(String); + +#[derive(Debug, Default)] +struct UpdateSyntax { + pub s: &'static str, + pub u: u64, +} diff --git a/tests/ui/deref_by_slicing.fixed b/tests/ui/deref_by_slicing.fixed new file mode 100644 index 000000000000..b26276218b78 --- /dev/null +++ b/tests/ui/deref_by_slicing.fixed @@ -0,0 +1,29 @@ +// run-rustfix + +#![warn(clippy::deref_by_slicing)] + +use std::io::Read; + +fn main() { + let mut vec = vec![0]; + let _ = &*vec; + let _ = &mut *vec; + + let ref_vec = &mut vec; + let _ = &**ref_vec; + let mut_slice = &mut **ref_vec; + let _ = &mut *mut_slice; // Err, re-borrows slice + + let s = String::new(); + let _ = &*s; + + static S: &[u8] = &[0, 1, 2]; + let _ = &mut &*S; // Err, re-borrows slice + + let slice: &[u32] = &[0u32, 1u32]; + let slice_ref = &slice; + let _ = *slice_ref; // Err, derefs slice + + let bytes: &[u8] = &[]; + let _ = (&*bytes).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice +} diff --git a/tests/ui/deref_by_slicing.rs b/tests/ui/deref_by_slicing.rs new file mode 100644 index 000000000000..6aa1408ba176 --- /dev/null +++ b/tests/ui/deref_by_slicing.rs @@ -0,0 +1,29 @@ +// run-rustfix + +#![warn(clippy::deref_by_slicing)] + +use std::io::Read; + +fn main() { + let mut vec = vec![0]; + let _ = &vec[..]; + let _ = &mut vec[..]; + + let ref_vec = &mut vec; + let _ = &ref_vec[..]; + let mut_slice = &mut ref_vec[..]; + let _ = &mut mut_slice[..]; // Err, re-borrows slice + + let s = String::new(); + let _ = &s[..]; + + static S: &[u8] = &[0, 1, 2]; + let _ = &mut &S[..]; // Err, re-borrows slice + + let slice: &[u32] = &[0u32, 1u32]; + let slice_ref = &slice; + let _ = &slice_ref[..]; // Err, derefs slice + + let bytes: &[u8] = &[]; + let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice +} diff --git a/tests/ui/deref_by_slicing.stderr b/tests/ui/deref_by_slicing.stderr new file mode 100644 index 000000000000..ffd76de378df --- /dev/null +++ b/tests/ui/deref_by_slicing.stderr @@ -0,0 +1,58 @@ +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:9:13 + | +LL | let _ = &vec[..]; + | ^^^^^^^^ help: dereference the original value instead: `&*vec` + | + = note: `-D clippy::deref-by-slicing` implied by `-D warnings` + +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:10:13 + | +LL | let _ = &mut vec[..]; + | ^^^^^^^^^^^^ help: dereference the original value instead: `&mut *vec` + +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:13:13 + | +LL | let _ = &ref_vec[..]; + | ^^^^^^^^^^^^ help: dereference the original value instead: `&**ref_vec` + +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:14:21 + | +LL | let mut_slice = &mut ref_vec[..]; + | ^^^^^^^^^^^^^^^^ help: dereference the original value instead: `&mut **ref_vec` + +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:15:13 + | +LL | let _ = &mut mut_slice[..]; // Err, re-borrows slice + | ^^^^^^^^^^^^^^^^^^ help: reborrow the original value instead: `&mut *mut_slice` + +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:18:13 + | +LL | let _ = &s[..]; + | ^^^^^^ help: dereference the original value instead: `&*s` + +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:21:18 + | +LL | let _ = &mut &S[..]; // Err, re-borrows slice + | ^^^^^^ help: reborrow the original value instead: `&*S` + +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:25:13 + | +LL | let _ = &slice_ref[..]; // Err, derefs slice + | ^^^^^^^^^^^^^^ help: dereference the original value instead: `*slice_ref` + +error: slicing when dereferencing would work + --> $DIR/deref_by_slicing.rs:28:13 + | +LL | let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice + | ^^^^^^^^^^^^ help: reborrow the original value instead: `(&*bytes)` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index 618f80cdcf84..5aedbea381f2 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -256,3 +256,22 @@ fn arc_fp() { (0..5).map(|n| arc(n)); Some(4).map(|n| ref_arc(n)); } + +// #8460 Don't replace closures with params bounded as `ref` +mod bind_by_ref { + struct A; + struct B; + + impl From<&A> for B { + fn from(A: &A) -> Self { + B + } + } + + fn test() { + // should not lint + Some(A).map(|a| B::from(&a)); + // should not lint + Some(A).map(|ref a| B::from(a)); + } +} diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index a759e6eb514b..5fdf7fb97716 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -256,3 +256,22 @@ fn arc_fp() { (0..5).map(|n| arc(n)); Some(4).map(|n| ref_arc(n)); } + +// #8460 Don't replace closures with params bounded as `ref` +mod bind_by_ref { + struct A; + struct B; + + impl From<&A> for B { + fn from(A: &A) -> Self { + B + } + } + + fn test() { + // should not lint + Some(A).map(|a| B::from(&a)); + // should not lint + Some(A).map(|ref a| B::from(a)); + } +} diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index b45cc849eaec..cee9e2372c22 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -74,6 +74,30 @@ enum LargeEnum8 { ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), } +enum LargeEnum9 { + A(Struct<()>), + B(Struct2), +} + +enum LargeEnumOk2 { + A(T), + B(Struct2), +} + +enum LargeEnumOk3 { + A(Struct), + B(Struct2), +} + +struct Struct { + a: i32, + t: T, +} + +struct Struct2 { + a: [i32; 8000], +} + fn main() { large_enum_variant!(); } diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index 899f97ce2e1e..cbf2ac972e2b 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -111,5 +111,21 @@ help: consider boxing the large fields to reduce the total size of the enum LL | ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ -error: aborting due to 7 previous errors +error: large size difference between variants + --> $DIR/large_enum_variant.rs:79:5 + | +LL | B(Struct2), + | ^^^^^^^^^^ this variant is 32000 bytes + | +note: and the second-largest variant is 4 bytes: + --> $DIR/large_enum_variant.rs:78:5 + | +LL | A(Struct<()>), + | ^^^^^^^^^^^^^ +help: consider boxing the large fields to reduce the total size of the enum + | +LL | B(Box), + | ~~~~~~~~~~~~ + +error: aborting due to 8 previous errors diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index c61eb9216643..ddfa1e741ada 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -32,4 +32,12 @@ mod issue4437 { } } -fn main() {} +fn main() { + // Don't lint + let _ = match Some(0) { + #[cfg(feature = "foo")] + Some(ref x) if *x > 50 => None, + Some(ref x) => Some(x), + None => None, + }; +} diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 2fbd0b255faa..025d475ae13d 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -41,4 +41,12 @@ mod issue4437 { } } -fn main() {} +fn main() { + // Don't lint + let _ = match Some(0) { + #[cfg(feature = "foo")] + Some(ref x) if *x > 50 => None, + Some(ref x) => Some(x), + None => None, + }; +} diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs index 9ed55ca7ae7f..bcc999a49428 100644 --- a/tests/ui/match_bool.rs +++ b/tests/ui/match_bool.rs @@ -50,6 +50,14 @@ fn match_bool() { 11..=20 => 2, _ => 3, }; + + // Don't lint + let _ = match test { + #[cfg(feature = "foo")] + true if option == 5 => 10, + true => 0, + false => 1, + }; } fn main() {} diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed index c611f76bf960..36f233f33460 100644 --- a/tests/ui/match_expr_like_matches_macro.fixed +++ b/tests/ui/match_expr_like_matches_macro.fixed @@ -146,4 +146,19 @@ fn main() { let _res = matches!(&val, &Some(ref _a)); fun(val); } + + { + enum E { + A, + B, + C, + } + + let _ = match E::A { + E::B => true, + #[cfg(feature = "foo")] + E::A => true, + _ => false, + }; + } } diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs index 2deeb84e7413..750f69fa5088 100644 --- a/tests/ui/match_expr_like_matches_macro.rs +++ b/tests/ui/match_expr_like_matches_macro.rs @@ -181,4 +181,19 @@ fn main() { }; fun(val); } + + { + enum E { + A, + B, + C, + } + + let _ = match E::A { + E::B => true, + #[cfg(feature = "foo")] + E::A => true, + _ => false, + }; + } } diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index da4e3020d5b8..67e1d518483c 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -166,4 +166,12 @@ fn match_expr_like_matches_macro_priority() { }; } -fn main() {} +fn main() { + let _ = match Some(0) { + Some(0) => 0, + Some(1) => 1, + #[cfg(feature = "foo")] + Some(2) => 2, + _ => 1, + }; +} diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index b4ec525ada09..b8dc8179f7d7 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -106,10 +106,8 @@ fn main() { 0 => println!("Array index start"), _ => println!("Not an array index start"), } - // False negative + + // Lint let x = 1; - match x { - // => - _ => println!("Not an array index start"), - } + println!("Not an array index start"); } diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index e04c4018b98d..fe63dcd63f2b 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -118,7 +118,8 @@ fn main() { 0 => println!("Array index start"), _ => println!("Not an array index start"), } - // False negative + + // Lint let x = 1; match x { // => diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 291fa77dc2ee..d939291f53c4 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -167,5 +167,14 @@ LL + unwrapped LL ~ }) | -error: aborting due to 11 previous errors +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:124:5 + | +LL | / match x { +LL | | // => +LL | | _ => println!("Not an array index start"), +LL | | } + | |_____^ help: consider using the match body instead: `println!("Not an array index start");` + +error: aborting due to 12 previous errors diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index 4b2e7444dcf6..e94f99c95f48 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -90,6 +90,22 @@ impl Private { } // We don't lint private items } +struct PrivateStruct; + +impl PrivateStruct { + pub fn new() -> PrivateStruct { + unimplemented!() + } // We don't lint public items on private structs +} + +pub struct PrivateItem; + +impl PrivateItem { + fn new() -> PrivateItem { + unimplemented!() + } // We don't lint private items on public structs +} + struct Const; impl Const { @@ -185,4 +201,14 @@ pub mod issue7220 { } } +// see issue #8152 +// This should not create any lints +pub struct DocHidden; +impl DocHidden { + #[doc(hidden)] + pub fn new() -> Self { + DocHidden + } +} + fn main() {} diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 14ddb66f2324..19572dfe8b07 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -51,7 +51,7 @@ LL + } | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` - --> $DIR/new_without_default.rs:156:5 + --> $DIR/new_without_default.rs:172:5 | LL | / pub fn new() -> Self { LL | | NewNotEqualToDerive { foo: 1 } @@ -68,7 +68,7 @@ LL + } | error: you should consider adding a `Default` implementation for `FooGenerics` - --> $DIR/new_without_default.rs:164:5 + --> $DIR/new_without_default.rs:180:5 | LL | / pub fn new() -> Self { LL | | Self(Default::default()) @@ -85,7 +85,7 @@ LL + } | error: you should consider adding a `Default` implementation for `BarGenerics` - --> $DIR/new_without_default.rs:171:5 + --> $DIR/new_without_default.rs:187:5 | LL | / pub fn new() -> Self { LL | | Self(Default::default()) @@ -102,7 +102,7 @@ LL + } | error: you should consider adding a `Default` implementation for `Foo` - --> $DIR/new_without_default.rs:182:9 + --> $DIR/new_without_default.rs:198:9 | LL | / pub fn new() -> Self { LL | | todo!() diff --git a/tests/ui/print_in_format_impl.rs b/tests/ui/print_in_format_impl.rs new file mode 100644 index 000000000000..64e886866098 --- /dev/null +++ b/tests/ui/print_in_format_impl.rs @@ -0,0 +1,58 @@ +#![allow(unused, clippy::print_literal, clippy::write_literal)] +#![warn(clippy::print_in_format_impl)] +use std::fmt::{Debug, Display, Error, Formatter}; + +macro_rules! indirect { + () => {{ println!() }}; +} + +macro_rules! nested { + ($($tt:tt)*) => { + $($tt)* + }; +} + +struct Foo; +impl Debug for Foo { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + static WORKS_WITH_NESTED_ITEMS: bool = true; + + print!("{}", 1); + println!("{}", 2); + eprint!("{}", 3); + eprintln!("{}", 4); + nested! { + println!("nested"); + }; + + write!(f, "{}", 5); + writeln!(f, "{}", 6); + indirect!(); + + Ok(()) + } +} + +impl Display for Foo { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + print!("Display"); + write!(f, "Display"); + + Ok(()) + } +} + +struct UnnamedFormatter; +impl Debug for UnnamedFormatter { + fn fmt(&self, _: &mut Formatter) -> Result<(), Error> { + println!("UnnamedFormatter"); + Ok(()) + } +} + +fn main() { + print!("outside fmt"); + println!("outside fmt"); + eprint!("outside fmt"); + eprintln!("outside fmt"); +} diff --git a/tests/ui/print_in_format_impl.stderr b/tests/ui/print_in_format_impl.stderr new file mode 100644 index 000000000000..63b7179bca7d --- /dev/null +++ b/tests/ui/print_in_format_impl.stderr @@ -0,0 +1,46 @@ +error: use of `print!` in `Debug` impl + --> $DIR/print_in_format_impl.rs:20:9 + | +LL | print!("{}", 1); + | ^^^^^^^^^^^^^^^ help: replace with: `write!(f, ..)` + | + = note: `-D clippy::print-in-format-impl` implied by `-D warnings` + +error: use of `println!` in `Debug` impl + --> $DIR/print_in_format_impl.rs:21:9 + | +LL | println!("{}", 2); + | ^^^^^^^^^^^^^^^^^ help: replace with: `writeln!(f, ..)` + +error: use of `eprint!` in `Debug` impl + --> $DIR/print_in_format_impl.rs:22:9 + | +LL | eprint!("{}", 3); + | ^^^^^^^^^^^^^^^^ help: replace with: `write!(f, ..)` + +error: use of `eprintln!` in `Debug` impl + --> $DIR/print_in_format_impl.rs:23:9 + | +LL | eprintln!("{}", 4); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `writeln!(f, ..)` + +error: use of `println!` in `Debug` impl + --> $DIR/print_in_format_impl.rs:25:13 + | +LL | println!("nested"); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `writeln!(f, ..)` + +error: use of `print!` in `Display` impl + --> $DIR/print_in_format_impl.rs:38:9 + | +LL | print!("Display"); + | ^^^^^^^^^^^^^^^^^ help: replace with: `write!(f, ..)` + +error: use of `println!` in `Debug` impl + --> $DIR/print_in_format_impl.rs:48:9 + | +LL | println!("UnnamedFormatter"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `writeln!(..)` + +error: aborting due to 7 previous errors + diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 00b99da2631c..97990fedd51f 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -186,3 +186,11 @@ pub trait Trait { fn f(v: &mut Vec); fn f2(v: &mut Vec) {} } + +// Issue #8463 +fn two_vecs(a: &mut Vec, b: &mut Vec) { + a.push(0); + a.push(0); + a.push(0); + b.push(1); +} diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index 8346a9454f4e..bea6be66a8e0 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,8 +1,17 @@ // run-rustfix +// aux-build:macro_rules.rs #![warn(clippy::ptr_as_ptr)] #![feature(custom_inner_attributes)] +extern crate macro_rules; + +macro_rules! cast_it { + ($ptr: ident) => { + $ptr.cast::() + }; +} + fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; @@ -28,6 +37,12 @@ fn main() { // Ensure the lint doesn't produce unnecessary turbofish for inferred types. let _: *const i32 = ptr.cast(); let _: *mut i32 = mut_ptr.cast(); + + // Make sure the lint is triggered inside a macro + let _ = cast_it!(ptr); + + // Do not lint inside macros from external crates + let _ = macro_rules::ptr_as_ptr_cast!(ptr); } fn _msrv_1_37() { diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index b68d4bc0aaca..ca2616b0069a 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,8 +1,17 @@ // run-rustfix +// aux-build:macro_rules.rs #![warn(clippy::ptr_as_ptr)] #![feature(custom_inner_attributes)] +extern crate macro_rules; + +macro_rules! cast_it { + ($ptr: ident) => { + $ptr as *const i32 + }; +} + fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; @@ -28,6 +37,12 @@ fn main() { // Ensure the lint doesn't produce unnecessary turbofish for inferred types. let _: *const i32 = ptr as *const _; let _: *mut i32 = mut_ptr as _; + + // Make sure the lint is triggered inside a macro + let _ = cast_it!(ptr); + + // Do not lint inside macros from external crates + let _ = macro_rules::ptr_as_ptr_cast!(ptr); } fn _msrv_1_37() { diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index 854906dc111d..c58c55cfd83a 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,5 +1,5 @@ error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:10:13 + --> $DIR/ptr_as_ptr.rs:19:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` @@ -7,40 +7,51 @@ LL | let _ = ptr as *const i32; = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:11:13 + --> $DIR/ptr_as_ptr.rs:20:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:16:17 + --> $DIR/ptr_as_ptr.rs:25:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:29:25 + --> $DIR/ptr_as_ptr.rs:38:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:30:23 + --> $DIR/ptr_as_ptr.rs:39:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:48:13 + --> $DIR/ptr_as_ptr.rs:11:9 + | +LL | $ptr as *const i32 + | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` +... +LL | let _ = cast_it!(ptr); + | ------------- in this macro invocation + | + = note: this error originates in the macro `cast_it` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:63:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:49:13 + --> $DIR/ptr_as_ptr.rs:64:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/recursive_format_impl.rs b/tests/ui/recursive_format_impl.rs new file mode 100644 index 000000000000..9241bf7ed740 --- /dev/null +++ b/tests/ui/recursive_format_impl.rs @@ -0,0 +1,321 @@ +#![warn(clippy::recursive_format_impl)] +#![allow( + clippy::inherent_to_string_shadow_display, + clippy::to_string_in_format_args, + clippy::deref_addrof +)] + +use std::fmt; + +struct A; +impl A { + fn fmt(&self) { + self.to_string(); + } +} + +trait B { + fn fmt(&self) {} +} + +impl B for A { + fn fmt(&self) { + self.to_string(); + } +} + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_string()) + } +} + +fn fmt(a: A) { + a.to_string(); +} + +struct C; + +impl C { + // Doesn't trigger if to_string defined separately + // i.e. not using ToString trait (from Display) + fn to_string(&self) -> String { + String::from("I am C") + } +} + +impl fmt::Display for C { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_string()) + } +} + +enum D { + E(String), + F, +} + +impl std::fmt::Display for D { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + Self::E(string) => write!(f, "E {}", string.to_string()), + Self::F => write!(f, "F"), + } + } +} + +// Check for use of self as Display, in Display impl +// Triggers on direct use of self +struct G {} + +impl std::fmt::Display for G { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self) + } +} + +// Triggers on reference to self +struct H {} + +impl std::fmt::Display for H { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", &self) + } +} + +impl std::fmt::Debug for H { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", &self) + } +} + +// Triggers on multiple reference to self +struct H2 {} + +impl std::fmt::Display for H2 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", &&&self) + } +} + +// Doesn't trigger on correct deref +struct I {} + +impl std::ops::Deref for I { + type Target = str; + + fn deref(&self) -> &Self::Target { + "test" + } +} + +impl std::fmt::Display for I { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", &**self) + } +} + +impl std::fmt::Debug for I { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", &**self) + } +} + +// Doesn't trigger on multiple correct deref +struct I2 {} + +impl std::ops::Deref for I2 { + type Target = str; + + fn deref(&self) -> &Self::Target { + "test" + } +} + +impl std::fmt::Display for I2 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", **&&&**self) + } +} + +// Doesn't trigger on multiple correct deref +struct I3 {} + +impl std::ops::Deref for I3 { + type Target = str; + + fn deref(&self) -> &Self::Target { + "test" + } +} + +impl std::fmt::Display for I3 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", &&**&&&**self) + } +} + +// Does trigger when deref resolves to self +struct J {} + +impl std::ops::Deref for J { + type Target = str; + + fn deref(&self) -> &Self::Target { + "test" + } +} + +impl std::fmt::Display for J { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", &*self) + } +} + +impl std::fmt::Debug for J { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", &*self) + } +} + +struct J2 {} + +impl std::ops::Deref for J2 { + type Target = str; + + fn deref(&self) -> &Self::Target { + "test" + } +} + +impl std::fmt::Display for J2 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", *self) + } +} + +struct J3 {} + +impl std::ops::Deref for J3 { + type Target = str; + + fn deref(&self) -> &Self::Target { + "test" + } +} + +impl std::fmt::Display for J3 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", **&&*self) + } +} + +struct J4 {} + +impl std::ops::Deref for J4 { + type Target = str; + + fn deref(&self) -> &Self::Target { + "test" + } +} + +impl std::fmt::Display for J4 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", &&**&&*self) + } +} + +// Doesn't trigger on Debug from Display +struct K {} + +impl std::fmt::Debug for K { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "test") + } +} + +impl std::fmt::Display for K { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +// Doesn't trigger on Display from Debug +struct K2 {} + +impl std::fmt::Debug for K2 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self) + } +} + +impl std::fmt::Display for K2 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "test") + } +} + +// Doesn't trigger on struct fields +struct L { + field1: u32, + field2: i32, +} + +impl std::fmt::Display for L { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{},{}", self.field1, self.field2) + } +} + +impl std::fmt::Debug for L { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?},{:?}", self.field1, self.field2) + } +} + +// Doesn't trigger on nested enum matching +enum Tree { + Leaf, + Node(Vec), +} + +impl std::fmt::Display for Tree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Tree::Leaf => write!(f, "*"), + Tree::Node(children) => { + write!(f, "(")?; + for child in children.iter() { + write!(f, "{},", child)?; + } + write!(f, ")") + }, + } + } +} + +impl std::fmt::Debug for Tree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Tree::Leaf => write!(f, "*"), + Tree::Node(children) => { + write!(f, "(")?; + for child in children.iter() { + write!(f, "{:?},", child)?; + } + write!(f, ")") + }, + } + } +} + +fn main() { + let a = A; + a.to_string(); + a.fmt(); + fmt(a); + + let c = C; + c.to_string(); +} diff --git a/tests/ui/recursive_format_impl.stderr b/tests/ui/recursive_format_impl.stderr new file mode 100644 index 000000000000..6171696ed69d --- /dev/null +++ b/tests/ui/recursive_format_impl.stderr @@ -0,0 +1,91 @@ +error: using `self.to_string` in `fmt::Display` implementation will cause infinite recursion + --> $DIR/recursive_format_impl.rs:29:25 + | +LL | write!(f, "{}", self.to_string()) + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::recursive-format-impl` implied by `-D warnings` + +error: unnecessary use of `to_string` + --> $DIR/recursive_format_impl.rs:61:50 + | +LL | Self::E(string) => write!(f, "E {}", string.to_string()), + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` + = note: this error originates in the macro `$crate::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Display` in `impl Display` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:73:9 + | +LL | write!(f, "{}", self) + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Display` in `impl Display` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:82:9 + | +LL | write!(f, "{}", &self) + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Debug` in `impl Debug` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:88:9 + | +LL | write!(f, "{:?}", &self) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Display` in `impl Display` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:97:9 + | +LL | write!(f, "{}", &&&self) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Display` in `impl Display` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:171:9 + | +LL | write!(f, "{}", &*self) + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Debug` in `impl Debug` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:177:9 + | +LL | write!(f, "{:?}", &*self) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Display` in `impl Display` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:193:9 + | +LL | write!(f, "{}", *self) + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Display` in `impl Display` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:209:9 + | +LL | write!(f, "{}", **&&*self) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: using `self` as `Display` in `impl Display` will cause infinite recursion + --> $DIR/recursive_format_impl.rs:225:9 + | +LL | write!(f, "{}", &&**&&*self) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 11 previous errors + diff --git a/tests/ui/redundant_slicing.fixed b/tests/ui/redundant_slicing.fixed new file mode 100644 index 000000000000..8dd8d3092378 --- /dev/null +++ b/tests/ui/redundant_slicing.fixed @@ -0,0 +1,46 @@ +// run-rustfix + +#![allow(unused, clippy::deref_by_slicing)] +#![warn(clippy::redundant_slicing)] + +use std::io::Read; + +fn main() { + let slice: &[u32] = &[0]; + let _ = slice; // Redundant slice + + let v = vec![0]; + let _ = &v[..]; // Ok, results in `&[_]` + let _ = (&*v); // Outer borrow is redundant + + static S: &[u8] = &[0, 1, 2]; + let _ = &mut &S[..]; // Ok, re-borrows slice + + let mut vec = vec![0]; + let mut_slice = &mut vec[..]; // Ok, results in `&mut [_]` + let _ = &mut mut_slice[..]; // Ok, re-borrows slice + + let ref_vec = &vec; + let _ = &ref_vec[..]; // Ok, results in `&[_]` + + macro_rules! m { + ($e:expr) => { + $e + }; + } + let _ = slice; + + macro_rules! m2 { + ($e:expr) => { + &$e[..] + }; + } + let _ = m2!(slice); // Don't lint in a macro + + let slice_ref = &slice; + let _ = &slice_ref[..]; // Ok, derefs slice + + // Issue #7972 + let bytes: &[u8] = &[]; + let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Ok, re-borrows slice +} diff --git a/tests/ui/redundant_slicing.rs b/tests/ui/redundant_slicing.rs index 554b6ba36ae0..51c16dd8d65a 100644 --- a/tests/ui/redundant_slicing.rs +++ b/tests/ui/redundant_slicing.rs @@ -1,20 +1,27 @@ -#![allow(unused)] +// run-rustfix + +#![allow(unused, clippy::deref_by_slicing)] #![warn(clippy::redundant_slicing)] +use std::io::Read; + fn main() { let slice: &[u32] = &[0]; - let _ = &slice[..]; + let _ = &slice[..]; // Redundant slice let v = vec![0]; - let _ = &v[..]; // Changes the type - let _ = &(&v[..])[..]; // Outer borrow is redundant + let _ = &v[..]; // Ok, results in `&[_]` + let _ = &(&*v)[..]; // Outer borrow is redundant static S: &[u8] = &[0, 1, 2]; - let err = &mut &S[..]; // Should reborrow instead of slice + let _ = &mut &S[..]; // Ok, re-borrows slice let mut vec = vec![0]; - let mut_slice = &mut *vec; - let _ = &mut mut_slice[..]; // Should reborrow instead of slice + let mut_slice = &mut vec[..]; // Ok, results in `&mut [_]` + let _ = &mut mut_slice[..]; // Ok, re-borrows slice + + let ref_vec = &vec; + let _ = &ref_vec[..]; // Ok, results in `&[_]` macro_rules! m { ($e:expr) => { @@ -29,4 +36,11 @@ fn main() { }; } let _ = m2!(slice); // Don't lint in a macro + + let slice_ref = &slice; + let _ = &slice_ref[..]; // Ok, derefs slice + + // Issue #7972 + let bytes: &[u8] = &[]; + let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Ok, re-borrows slice } diff --git a/tests/ui/redundant_slicing.stderr b/tests/ui/redundant_slicing.stderr index bbd10eafbbe7..82367143c07f 100644 --- a/tests/ui/redundant_slicing.stderr +++ b/tests/ui/redundant_slicing.stderr @@ -1,34 +1,22 @@ error: redundant slicing of the whole range - --> $DIR/redundant_slicing.rs:6:13 + --> $DIR/redundant_slicing.rs:10:13 | -LL | let _ = &slice[..]; +LL | let _ = &slice[..]; // Redundant slice | ^^^^^^^^^^ help: use the original value instead: `slice` | = note: `-D clippy::redundant-slicing` implied by `-D warnings` error: redundant slicing of the whole range - --> $DIR/redundant_slicing.rs:10:13 - | -LL | let _ = &(&v[..])[..]; // Outer borrow is redundant - | ^^^^^^^^^^^^^ help: use the original value instead: `(&v[..])` - -error: redundant slicing of the whole range - --> $DIR/redundant_slicing.rs:13:20 - | -LL | let err = &mut &S[..]; // Should reborrow instead of slice - | ^^^^^^ help: reborrow the original value instead: `&*S` - -error: redundant slicing of the whole range - --> $DIR/redundant_slicing.rs:17:13 + --> $DIR/redundant_slicing.rs:14:13 | -LL | let _ = &mut mut_slice[..]; // Should reborrow instead of slice - | ^^^^^^^^^^^^^^^^^^ help: reborrow the original value instead: `&mut *mut_slice` +LL | let _ = &(&*v)[..]; // Outer borrow is redundant + | ^^^^^^^^^^ help: use the original value instead: `(&*v)` error: redundant slicing of the whole range - --> $DIR/redundant_slicing.rs:24:13 + --> $DIR/redundant_slicing.rs:31:13 | LL | let _ = &m!(slice)[..]; | ^^^^^^^^^^^^^^ help: use the original value instead: `slice` -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 8bddec576ed1..24a0c8122919 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -20,6 +20,7 @@ #![allow(clippy::match_result_ok)] #![allow(clippy::disallowed_types)] #![allow(clippy::disallowed_methods)] +#![allow(clippy::recursive_format_impl)] // uplifted lints #![allow(invalid_value)] #![allow(array_into_iter)] @@ -55,6 +56,7 @@ #![warn(clippy::disallowed_types)] #![warn(clippy::disallowed_methods)] #![warn(clippy::needless_borrow)] +#![warn(clippy::recursive_format_impl)] // uplifted lints #![warn(invalid_value)] #![warn(array_into_iter)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index d2010d71d2c1..ea64234c680d 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -20,6 +20,7 @@ #![allow(clippy::match_result_ok)] #![allow(clippy::disallowed_types)] #![allow(clippy::disallowed_methods)] +#![allow(clippy::recursive_format_impl)] // uplifted lints #![allow(invalid_value)] #![allow(array_into_iter)] @@ -55,6 +56,7 @@ #![warn(clippy::disallowed_type)] #![warn(clippy::disallowed_method)] #![warn(clippy::ref_in_deref)] +#![warn(clippy::to_string_in_display)] // uplifted lints #![warn(clippy::invalid_ref)] #![warn(clippy::into_iter_on_array)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 45cb8b786f5f..8b132a783847 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:34:9 + --> $DIR/rename.rs:35:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` @@ -7,196 +7,202 @@ LL | #![warn(clippy::stutter)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:35:9 + --> $DIR/rename.rs:36:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:36:9 + --> $DIR/rename.rs:37:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:37:9 + --> $DIR/rename.rs:38:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:39:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:40:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` -error: lint `clippy::invalid_ref` has been renamed to `invalid_value` +error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` --> $DIR/rename.rs:59:9 | +LL | #![warn(clippy::to_string_in_display)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` + +error: lint `clippy::invalid_ref` has been renamed to `invalid_value` + --> $DIR/rename.rs:61:9 + | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` -error: aborting due to 33 previous errors +error: aborting due to 34 previous errors diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index bd3718880463..dd148edf5292 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -234,4 +234,12 @@ macro_rules! single_match { fn main() { single_match!(5); + + // Don't lint + let _ = match Some(0) { + #[cfg(feature = "foo")] + Some(10) => 11, + Some(x) => x, + _ => 0, + }; } diff --git a/tests/ui/to_string_in_display.rs b/tests/ui/to_string_in_display.rs deleted file mode 100644 index 3ccdcd1117b5..000000000000 --- a/tests/ui/to_string_in_display.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![warn(clippy::to_string_in_display)] -#![allow(clippy::inherent_to_string_shadow_display, clippy::to_string_in_format_args)] - -use std::fmt; - -struct A; -impl A { - fn fmt(&self) { - self.to_string(); - } -} - -trait B { - fn fmt(&self) {} -} - -impl B for A { - fn fmt(&self) { - self.to_string(); - } -} - -impl fmt::Display for A { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_string()) - } -} - -fn fmt(a: A) { - a.to_string(); -} - -struct C; - -impl C { - fn to_string(&self) -> String { - String::from("I am C") - } -} - -impl fmt::Display for C { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_string()) - } -} - -enum D { - E(String), - F, -} - -impl std::fmt::Display for D { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self { - Self::E(string) => write!(f, "E {}", string.to_string()), - Self::F => write!(f, "F"), - } - } -} - -fn main() { - let a = A; - a.to_string(); - a.fmt(); - fmt(a); - - let c = C; - c.to_string(); -} diff --git a/tests/ui/to_string_in_display.stderr b/tests/ui/to_string_in_display.stderr deleted file mode 100644 index 80189ca1f0ae..000000000000 --- a/tests/ui/to_string_in_display.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: using `to_string` in `fmt::Display` implementation might lead to infinite recursion - --> $DIR/to_string_in_display.rs:25:25 - | -LL | write!(f, "{}", self.to_string()) - | ^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::to-string-in-display` implied by `-D warnings` - -error: unnecessary use of `to_string` - --> $DIR/to_string_in_display.rs:55:50 - | -LL | Self::E(string) => write!(f, "E {}", string.to_string()), - | ^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings` - = note: this error originates in the macro `$crate::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 2 previous errors - diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs index 71539940fbf2..b163d6056343 100644 --- a/tests/ui/transmute_undefined_repr.rs +++ b/tests/ui/transmute_undefined_repr.rs @@ -1,5 +1,8 @@ #![warn(clippy::transmute_undefined_repr)] -#![allow(clippy::unit_arg)] +#![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref)] + +use core::ffi::c_void; +use core::mem::{size_of, transmute}; fn value() -> T { unimplemented!() @@ -14,31 +17,75 @@ struct Ty2C(T, U); fn main() { unsafe { - let _: () = core::mem::transmute(value::()); - let _: Empty = core::mem::transmute(value::<()>()); + let _: () = transmute(value::()); + let _: Empty = transmute(value::<()>()); + + let _: Ty = transmute(value::()); + let _: Ty = transmute(value::()); + + let _: Ty2C = transmute(value::>()); // Lint, Ty2 is unordered + let _: Ty2 = transmute(value::>()); // Lint, Ty2 is unordered + + let _: Ty2 = transmute(value::>>()); // Ok, Ty2 types are the same + let _: Ty> = transmute(value::>()); // Ok, Ty2 types are the same + + let _: Ty2 = transmute(value::>>()); // Lint, different Ty2 instances + let _: Ty> = transmute(value::>()); // Lint, different Ty2 instances + + let _: Ty<&()> = transmute(value::<&()>()); + let _: &() = transmute(value::>()); + + let _: &Ty2 = transmute(value::>>()); // Lint, different Ty2 instances + let _: Ty<&Ty2> = transmute(value::<&Ty2>()); // Lint, different Ty2 instances + + let _: Ty = transmute(value::<&Ty2>()); // Ok, pointer to usize conversion + let _: &Ty2 = transmute(value::>()); // Ok, pointer to usize conversion + + let _: Ty<[u8; 8]> = transmute(value::>()); // Ok, transmute to byte array + let _: Ty2 = transmute(value::>()); // Ok, transmute from byte array + + // issue #8417 + let _: Ty2C, ()> = transmute(value::>()); // Ok, Ty2 types are the same + let _: Ty2 = transmute(value::, ()>>()); // Ok, Ty2 types are the same + + let _: &'static mut Ty2 = transmute(value::>>()); // Ok, Ty2 types are the same + let _: Box> = transmute(value::<&'static mut Ty2>()); // Ok, Ty2 types are the same + let _: *mut Ty2 = transmute(value::>>()); // Ok, Ty2 types are the same + let _: Box> = transmute(value::<*mut Ty2>()); // Ok, Ty2 types are the same + + let _: &'static mut Ty2 = transmute(value::>>()); // Lint, different Ty2 instances + let _: Box> = transmute(value::<&'static mut Ty2>()); // Lint, different Ty2 instances + + let _: *const () = transmute(value::>>()); // Ok, type erasure + let _: Ty<&Ty2> = transmute(value::<*const ()>()); // Ok, reverse type erasure - let _: Ty = core::mem::transmute(value::()); - let _: Ty = core::mem::transmute(value::()); + let _: *const c_void = transmute(value::>>()); // Ok, type erasure + let _: Ty<&Ty2> = transmute(value::<*const c_void>()); // Ok, reverse type erasure - let _: Ty2C = core::mem::transmute(value::>()); // Lint, Ty2 is unordered - let _: Ty2 = core::mem::transmute(value::>()); // Lint, Ty2 is unordered + enum Erase {} + let _: *const Erase = transmute(value::>>()); // Ok, type erasure + let _: Ty<&Ty2> = transmute(value::<*const Erase>()); // Ok, reverse type erasure - let _: Ty2 = core::mem::transmute(value::>>()); // Ok, Ty2 types are the same - let _: Ty> = core::mem::transmute(value::>()); // Ok, Ty2 types are the same + struct Erase2( + [u8; 0], + core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, + ); + let _: *const Erase2 = transmute(value::>>()); // Ok, type erasure + let _: Ty<&Ty2> = transmute(value::<*const Erase2>()); // Ok, reverse type erasure - let _: Ty2 = core::mem::transmute(value::>>()); // Lint, different Ty2 instances - let _: Ty> = core::mem::transmute(value::>()); // Lint, different Ty2 instances + let _: *const () = transmute(value::<&&[u8]>()); // Ok, type erasure + let _: &&[u8] = transmute(value::<*const ()>()); // Ok, reverse type erasure - let _: Ty<&()> = core::mem::transmute(value::<&()>()); - let _: &() = core::mem::transmute(value::>()); + let _: *mut c_void = transmute(value::<&mut &[u8]>()); // Ok, type erasure + let _: &mut &[u8] = transmute(value::<*mut c_void>()); // Ok, reverse type erasure - let _: &Ty2 = core::mem::transmute(value::>>()); // Lint, different Ty2 instances - let _: Ty<&Ty2> = core::mem::transmute(value::<&Ty2>()); // Lint, different Ty2 instances + let _: [u8; size_of::<&[u8]>()] = transmute(value::<&[u8]>()); // Ok, transmute to byte array + let _: &[u8] = transmute(value::<[u8; size_of::<&[u8]>()]>()); // Ok, transmute from byte array - let _: Ty = core::mem::transmute(value::<&Ty2>()); // Ok, pointer to usize conversion - let _: &Ty2 = core::mem::transmute(value::>()); // Ok, pointer to usize conversion + let _: [usize; 2] = transmute(value::<&[u8]>()); // Ok, transmute to int array + let _: &[u8] = transmute(value::<[usize; 2]>()); // Ok, transmute from int array - let _: Ty<[u8; 8]> = core::mem::transmute(value::>()); // Ok, transmute to byte array - let _: Ty2 = core::mem::transmute(value::>()); // Ok, transmute from byte array + let _: *const [u8] = transmute(value::>()); // Ok + let _: Box<[u8]> = transmute(value::<*mut [u8]>()); // Ok } } diff --git a/tests/ui/transmute_undefined_repr.stderr b/tests/ui/transmute_undefined_repr.stderr index 040c63c7afa6..42d544fc954c 100644 --- a/tests/ui/transmute_undefined_repr.stderr +++ b/tests/ui/transmute_undefined_repr.stderr @@ -1,44 +1,64 @@ error: transmute from `Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:23:33 + --> $DIR/transmute_undefined_repr.rs:26:33 | -LL | let _: Ty2C = core::mem::transmute(value::>()); // Lint, Ty2 is unordered - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Ty2C = transmute(value::>()); // Lint, Ty2 is unordered + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::transmute-undefined-repr` implied by `-D warnings` error: transmute into `Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:24:32 + --> $DIR/transmute_undefined_repr.rs:27:32 | -LL | let _: Ty2 = core::mem::transmute(value::>()); // Lint, Ty2 is unordered - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Ty2 = transmute(value::>()); // Lint, Ty2 is unordered + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `Ty>` to `Ty2`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:29:32 + --> $DIR/transmute_undefined_repr.rs:32:32 | -LL | let _: Ty2 = core::mem::transmute(value::>>()); // Lint, different Ty2 instances - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Ty2 = transmute(value::>>()); // Lint, different Ty2 instances + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty2` to `Ty>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:30:36 + --> $DIR/transmute_undefined_repr.rs:33:36 | -LL | let _: Ty> = core::mem::transmute(value::>()); // Lint, different Ty2 instances - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Ty> = transmute(value::>()); // Lint, different Ty2 instances + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: two instances of the same generic type (`Ty2`) may have different layouts -error: transmute to `&Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:35:33 +error: transmute from `Ty<&Ty2>` to `&Ty2`, both of which have an undefined layout + --> $DIR/transmute_undefined_repr.rs:38:33 | -LL | let _: &Ty2 = core::mem::transmute(value::>>()); // Lint, different Ty2 instances - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: &Ty2 = transmute(value::>>()); // Lint, different Ty2 instances + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: two instances of the same generic type (`Ty2`) may have different layouts + +error: transmute from `&Ty2` to `Ty<&Ty2>`, both of which have an undefined layout + --> $DIR/transmute_undefined_repr.rs:39:37 + | +LL | let _: Ty<&Ty2> = transmute(value::<&Ty2>()); // Lint, different Ty2 instances + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: two instances of the same generic type (`Ty2`) may have different layouts -error: transmute from `&Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:36:37 +error: transmute from `std::boxed::Box>` to `&mut Ty2`, both of which have an undefined layout + --> $DIR/transmute_undefined_repr.rs:56:45 | -LL | let _: Ty<&Ty2> = core::mem::transmute(value::<&Ty2>()); // Lint, different Ty2 instances - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: &'static mut Ty2 = transmute(value::>>()); // Lint, different Ty2 instances + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: two instances of the same generic type (`Ty2`) may have different layouts + +error: transmute from `&mut Ty2` to `std::boxed::Box>`, both of which have an undefined layout + --> $DIR/transmute_undefined_repr.rs:57:37 + | +LL | let _: Box> = transmute(value::<&'static mut Ty2>()); // Lint, different Ty2 instances + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: two instances of the same generic type (`Ty2`) may have different layouts -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors From 7f44a753ce21ad8be1f77bbfb1e21b14d1bb8194 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 15 Feb 2022 10:54:38 +0100 Subject: [PATCH 08/19] Move transmute_undefined_repr back to nursery There's still open discussion if this lint is ready to be enabled by default. We want to give us more time to figure this out and prevent this lint from getting to stable as an enabled-by-default lint. --- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_correctness.rs | 1 - clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/transmute/mod.rs | 2 +- 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index f6d467941e3e..abfb46035376 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -281,7 +281,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES), LintId::of(transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), LintId::of(transmuting_null::TRANSMUTING_NULL), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 35b1e644a8a7..d7bf91eb6921 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -58,7 +58,6 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(swap::ALMOST_SWAPPED), - LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), LintId::of(transmuting_null::TRANSMUTING_NULL), diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index a73537901002..8d4dde42bbec 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -26,6 +26,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(strings::STRING_LIT_AS_BYTES), LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY), + LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(use_self::USE_SELF), ]) diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 22a8c53a5852..1da3b7659048 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -377,7 +377,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.60.0"] pub TRANSMUTE_UNDEFINED_REPR, - correctness, + nursery, "transmute to or from a type with an undefined representation" } From c45a42a3327baeb6bfd05a0d95e795a9e65a88b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Mar 2022 19:20:27 -0500 Subject: [PATCH 09/19] bless clippy --- tests/ui/modulo_one.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr index 34f762bbb923..03f460897fce 100644 --- a/tests/ui/modulo_one.stderr +++ b/tests/ui/modulo_one.stderr @@ -1,18 +1,18 @@ -error: this arithmetic operation will overflow +error: this operation will panic at runtime --> $DIR/modulo_one.rs:11:5 | LL | i32::MIN % (-1); // also caught by rustc | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow | - = note: `#[deny(arithmetic_overflow)]` on by default + = note: `#[deny(unconditional_panic)]` on by default -error: this arithmetic operation will overflow +error: this operation will panic at runtime --> $DIR/modulo_one.rs:21:5 | LL | INT_MIN % NEG_ONE; // also caught by rustc | ^^^^^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow -error: this arithmetic operation will overflow +error: this operation will panic at runtime --> $DIR/modulo_one.rs:22:5 | LL | INT_MIN % STATIC_NEG_ONE; // ONLY caught by rustc From c8d6a55f6afe21f02f5e38f0c66e9950db779a3b Mon Sep 17 00:00:00 2001 From: pierwill Date: Fri, 4 Mar 2022 11:54:28 -0600 Subject: [PATCH 10/19] Update `itertools` Update to 0.10.1 --- Cargo.toml | 2 +- clippy_dev/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5cc5530f874d..d4ca9480bec6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ rustc-workspace-hack = "1.0" clippy_utils = { path = "clippy_utils" } derive-new = "0.5" if_chain = "1.0" -itertools = "0.10" +itertools = "0.10.1" quote = "1.0" serde = { version = "1.0", features = ["derive"] } syn = { version = "1.0", features = ["full"] } diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index d350d9a00182..d133e8cddabc 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" bytecount = "0.6" clap = "2.33" indoc = "1.0" -itertools = "0.10" +itertools = "0.10.1" opener = "0.5" regex = "1.5" shell-escape = "0.1" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 40d7dd702628..66e61660d313 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" cargo_metadata = "0.14" clippy_utils = { path = "../clippy_utils" } if_chain = "1.0" -itertools = "0.10" +itertools = "0.10.1" pulldown-cmark = { version = "0.9", default-features = false } quine-mc_cluskey = "0.2" regex-syntax = "0.6" From 90da7cdd41e1952e30981ad1047c1e493458e92d Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 21 Jan 2022 00:15:39 +0000 Subject: [PATCH 11/19] Do not point at whole file missing `fn main` Only point at the end of the crate. We could try making it point at the beginning of the crate, but that is confused with `DUMMY_SP`, causing the output to be *worse*. This change will make it so that VSCode will *not* underline the whole file when `main` is missing, so other errors will be visible. --- tests/ui/crashes/ice-6250.stderr | 12 +++--------- tests/ui/crashes/ice-6251.stderr | 8 +++----- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/tests/ui/crashes/ice-6250.stderr b/tests/ui/crashes/ice-6250.stderr index 7ffbd7a64b34..878897c410cf 100644 --- a/tests/ui/crashes/ice-6250.stderr +++ b/tests/ui/crashes/ice-6250.stderr @@ -1,14 +1,8 @@ error[E0601]: `main` function not found in crate `ice_6250` - --> $DIR/ice-6250.rs:4:1 + --> $DIR/ice-6250.rs:16:2 | -LL | / pub struct Cache { -LL | | data: Vec, -LL | | } -LL | | -... | -LL | | } -LL | | } - | |_^ consider adding a `main` function to `$DIR/ice-6250.rs` +LL | } + | ^ consider adding a `main` function to `$DIR/ice-6250.rs` error[E0308]: mismatched types --> $DIR/ice-6250.rs:12:14 diff --git a/tests/ui/crashes/ice-6251.stderr b/tests/ui/crashes/ice-6251.stderr index 14c71e884b6e..77a3c2ba4ad0 100644 --- a/tests/ui/crashes/ice-6251.stderr +++ b/tests/ui/crashes/ice-6251.stderr @@ -1,10 +1,8 @@ error[E0601]: `main` function not found in crate `ice_6251` - --> $DIR/ice-6251.rs:4:1 + --> $DIR/ice-6251.rs:6:2 | -LL | / fn bug() -> impl Iterator { -LL | | std::iter::empty() -LL | | } - | |_^ consider adding a `main` function to `$DIR/ice-6251.rs` +LL | } + | ^ consider adding a `main` function to `$DIR/ice-6251.rs` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/ice-6251.rs:4:45 From 9bee01eb91764d1c54ec6979178b885e0b577773 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Tue, 19 Oct 2021 18:45:48 -0400 Subject: [PATCH 12/19] Change syntax for TyAlias where clauses --- clippy_utils/src/ast_utils.rs | 48 +++++------------------------------ 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 3f4043ad052a..3a47845ec82c 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -279,20 +279,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { (ForeignMod(l), ForeignMod(r)) => { both(&l.abi, &r.abi, eq_str_lit) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind)) }, - ( - TyAlias(box ast::TyAlias { - defaultness: ld, - generics: lg, - bounds: lb, - ty: lt, - }), - TyAlias(box ast::TyAlias { - defaultness: rd, - generics: rg, - bounds: rb, - ty: rt, - }), - ) => { + (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt, .. }), + TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt, .. })) => { eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) @@ -382,20 +370,8 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { ) => { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r)) }, - ( - TyAlias(box ast::TyAlias { - defaultness: ld, - generics: lg, - bounds: lb, - ty: lt, - }), - TyAlias(box ast::TyAlias { - defaultness: rd, - generics: rg, - bounds: rb, - ty: rt, - }), - ) => { + (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt, .. }), + TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt, .. })) => { eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) @@ -426,20 +402,8 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ) => { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r)) }, - ( - TyAlias(box ast::TyAlias { - defaultness: ld, - generics: lg, - bounds: lb, - ty: lt, - }), - TyAlias(box ast::TyAlias { - defaultness: rd, - generics: rg, - bounds: rb, - ty: rt, - }), - ) => { + (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt, .. }), + TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt, .. })) => { eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) From 96eb1168d177a8e37fb4866051e665e3f1988c25 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Mar 2022 07:15:04 +1100 Subject: [PATCH 13/19] Introduce `ConstAllocation`. Currently some `Allocation`s are interned, some are not, and it's very hard to tell at a use point which is which. This commit introduces `ConstAllocation` for the known-interned ones, which makes the division much clearer. `ConstAllocation::inner()` is used to get the underlying `Allocation`. In some places it's natural to use an `Allocation`, in some it's natural to use a `ConstAllocation`, and in some places there's no clear choice. I've tried to make things look as nice as possible, while generally favouring `ConstAllocation`, which is the type that embodies more information. This does require quite a few calls to `inner()`. The commit also tweaks how `PartialOrd` works for `Interned`. The previous code was too clever by half, building on `T: Ord` to make the code shorter. That caused problems with deriving `PartialOrd` and `Ord` for `ConstAllocation`, so I changed it to build on `T: PartialOrd`, which is slightly more verbose but much more standard and avoided the problems. --- clippy_utils/src/consts.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index d40583c47dd7..42b9e692d3ff 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -593,7 +593,7 @@ pub fn miri_to_const(result: ty::Const<'_>) -> Option { ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty().kind() { ty::Ref(_, tam, _) => match tam.kind() { ty::Str => String::from_utf8( - data.inspect_with_uninit_and_ptr_outside_interpreter(start..end) + data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end) .to_owned(), ) .ok() @@ -605,7 +605,7 @@ pub fn miri_to_const(result: ty::Const<'_>) -> Option { ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty().kind() { ty::Array(sub_type, len) => match sub_type.kind() { ty::Float(FloatTy::F32) => match miri_to_const(*len) { - Some(Constant::Int(len)) => alloc + Some(Constant::Int(len)) => alloc.inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize)) .to_owned() .chunks(4) @@ -619,7 +619,7 @@ pub fn miri_to_const(result: ty::Const<'_>) -> Option { _ => None, }, ty::Float(FloatTy::F64) => match miri_to_const(*len) { - Some(Constant::Int(len)) => alloc + Some(Constant::Int(len)) => alloc.inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize)) .to_owned() .chunks(8) From b36924b4ac73c4eab2fd9e4cc2486d5fa1b6bf41 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Mar 2022 13:46:56 +1100 Subject: [PATCH 14/19] Clarify `Layout` interning. `Layout` is another type that is sometimes interned, sometimes not, and we always use references to refer to it so we can't take any advantage of the uniqueness properties for hashing or equality checks. This commit renames `Layout` as `LayoutS`, and then introduces a new `Layout` that is a newtype around an `Interned`. It also interns more layouts than before. Previously layouts within layouts (via the `variants` field) were never interned, but now they are. Hence the lifetime on the new `Layout` type. Unlike other interned types, these ones are in `rustc_target` instead of `rustc_middle`. This reflects the existing structure of the code, which does layout-specific stuff in `rustc_target` while `TyAndLayout` is generic over the `Ty`, allowing the type-specific stuff to occur in `rustc_middle`. The commit also adds a `HashStable` impl for `Interned`, which was needed. It hashes the contents, unlike the `Hash` impl which hashes the pointer. --- clippy_lints/src/transmute/transmute_undefined_repr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 05eadab3e6cc..81076776ed3d 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -326,7 +326,7 @@ fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty); if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); then { - layout.layout.size.bytes() == 0 + layout.layout.size().bytes() == 0 } else { false } From b86620da377102a1a5e84a96910b70c9c957b810 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 8 Feb 2022 16:33:15 -0800 Subject: [PATCH 15/19] Stabilize const_fn_fn_ptr_basics and const_fn_trait_bound --- clippy_utils/src/qualify_min_const_fn.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index c039fec955db..891531951c1a 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -32,32 +32,12 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: | ty::PredicateKind::Projection(_) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Trait(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate), - ty::PredicateKind::Trait(pred) => { - if Some(pred.def_id()) == tcx.lang_items().sized_trait() { - continue; - } - match pred.self_ty().kind() { - ty::Param(ref p) => { - let generics = tcx.generics_of(current); - let def = generics.type_param(p, tcx); - let span = tcx.def_span(def.def_id); - return Err(( - span, - "trait bounds other than `Sized` \ - on const fn parameters are unstable" - .into(), - )); - }, - // other kinds of bounds are either tautologies - // or cause errors in other passes - _ => continue, - } - }, } } match predicates.parent { From 43ce0a94af2539f28463197010a5f4147e33a0e0 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 10 Feb 2022 19:23:43 -0800 Subject: [PATCH 16/19] Update and fix clippy tests --- clippy_lints/src/missing_const_for_fn.rs | 13 +++++++++++++ tests/ui/missing_const_for_fn/could_be_const.rs | 2 -- .../ui/missing_const_for_fn/could_be_const.stderr | 14 +++++++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index bad9e0be82e6..ecc9acf4445d 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -3,6 +3,7 @@ use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method}; use rustc_hir as hir; +use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; @@ -131,6 +132,18 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Closure => return, } + // Const fns are not allowed as methods in a trait. + { + let parent = cx.tcx.hir().get_parent_item(hir_id); + if parent != CRATE_DEF_ID { + if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) { + if let hir::ItemKind::Trait(..) = &item.kind { + return; + } + } + } + } + let mir = cx.tcx.optimized_mir(def_id); if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) { diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index baa7eec05462..88f6935d224a 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -49,8 +49,6 @@ fn sub(x: u32) -> usize { unsafe { transmute(&x) } } -// NOTE: This is currently not yet allowed to be const -// Once implemented, Clippy should be able to suggest this as const, too. fn generic_arr(t: [T; 1]) -> T { t[0] } diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index b89cc6451bb5..3eb52b682747 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -58,7 +58,15 @@ LL | | } | |_^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:67:9 + --> $DIR/could_be_const.rs:52:1 + | +LL | / fn generic_arr(t: [T; 1]) -> T { +LL | | t[0] +LL | | } + | |_^ + +error: this could be a `const fn` + --> $DIR/could_be_const.rs:65:9 | LL | / pub fn b(self, a: &A) -> B { LL | | B @@ -66,12 +74,12 @@ LL | | } | |_________^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:77:5 + --> $DIR/could_be_const.rs:75:5 | LL | / fn const_fn_stabilized_before_msrv(byte: u8) { LL | | byte.is_ascii_digit(); LL | | } | |_____^ -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors From a4d6c61bdc05b17f85dfb5b73c6f13a838f88e7f Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 8 Mar 2022 15:39:52 +0100 Subject: [PATCH 17/19] add `#[rustc_pass_by_value]` to more types --- clippy_lints/src/redundant_clone.rs | 8 ++++---- clippy_utils/src/lib.rs | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index b3988973256c..1f134be2cbc8 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -543,10 +543,10 @@ impl<'a, 'tcx> PossibleBorrowerVisitor<'a, 'tcx> { continue; } - let borrowers = self.possible_borrower.reachable_from(&row); + let borrowers = self.possible_borrower.reachable_from(row); if !borrowers.is_empty() { let mut bs = HybridBitSet::new_empty(self.body.local_decls.len()); - for &c in borrowers { + for c in borrowers { if c != mir::Local::from_usize(0) { bs.insert(c); } @@ -663,10 +663,10 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> { continue; } - let borrowers = self.possible_origin.reachable_from(&row); + let borrowers = self.possible_origin.reachable_from(row); if !borrowers.is_empty() { let mut bs = HybridBitSet::new_empty(self.body.local_decls.len()); - for &c in borrowers { + for c in borrowers { if c != mir::Local::from_usize(0) { bs.insert(c); } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 397783e309e8..8c14f0dd761a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -489,7 +489,8 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option { tcx.crates(()) .iter() - .find(|&&num| tcx.crate_name(num).as_str() == name) + .copied() + .find(|&num| tcx.crate_name(num).as_str() == name) .map(CrateNum::as_def_id) } From e1102312608f7d41160a37a3f7e60f88f87c046f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 5 Mar 2022 07:28:41 +1100 Subject: [PATCH 18/19] Improve `AdtDef` interning. This commit makes `AdtDef` use `Interned`. Much the commit is tedious changes to introduce getter functions. The interesting changes are in `compiler/rustc_middle/src/ty/adt.rs`. --- clippy_lints/src/await_holding_invalid.rs | 4 +-- ...se_sensitive_file_extension_comparisons.rs | 3 ++- .../src/casts/cast_possible_truncation.rs | 8 +++--- clippy_lints/src/casts/utils.rs | 4 +-- clippy_lints/src/default.rs | 6 ++--- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/derive.rs | 6 ++--- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/eq_op.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/functions/must_use.rs | 4 +-- .../src/inconsistent_struct_constructor.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 4 +-- clippy_lints/src/len_zero.rs | 14 +++++----- clippy_lints/src/loops/manual_memcpy.rs | 2 +- clippy_lints/src/matches/match_wild_enum.rs | 6 ++--- .../src/methods/bind_instead_of_map.rs | 2 +- .../src/methods/cloned_instead_of_copied.rs | 2 +- clippy_lints/src/methods/filter_map.rs | 4 +-- clippy_lints/src/methods/implicit_clone.rs | 2 +- .../src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/map_flatten.rs | 4 +-- clippy_lints/src/methods/str_splitn.rs | 2 +- .../src/methods/unnecessary_filter_map.rs | 2 +- clippy_lints/src/mut_key.rs | 6 ++--- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/new_without_default.rs | 4 +-- clippy_lints/src/non_copy_const.rs | 2 +- .../src/non_send_fields_in_send_ty.rs | 4 +-- clippy_lints/src/ptr.rs | 10 +++---- clippy_lints/src/self_named_constructors.rs | 2 +- .../src/transmute/transmute_undefined_repr.rs | 6 ++--- .../transmute/unsound_collection_transmute.rs | 4 +-- clippy_lints/src/try_err.rs | 10 +++---- clippy_lints/src/unnecessary_wraps.rs | 4 +-- clippy_utils/src/eager_or_lazy.rs | 2 +- clippy_utils/src/lib.rs | 4 +-- clippy_utils/src/ty.rs | 26 +++++++++---------- 42 files changed, 93 insertions(+), 92 deletions(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index f0979840ff8d..4592ca727488 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -149,7 +149,7 @@ impl LateLintPass<'_> for AwaitHolding { fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) { for ty_cause in ty_causes { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { - if is_mutex_guard(cx, adt.did) { + if is_mutex_guard(cx, adt.did()) { span_lint_and_then( cx, AWAIT_HOLDING_LOCK, @@ -167,7 +167,7 @@ fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorType }, ); } - if is_refcell_ref(cx, adt.did) { + if is_refcell_ref(cx, adt.did()) { span_lint_and_then( cx, AWAIT_HOLDING_REFCELL_REF, diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index 7637666d059e..df780747a0c7 100644 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_ast::ast::LitKind; +use rustc_data_structures::intern::Interned; use rustc_hir::{Expr, ExprKind, PathSegment}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -55,7 +56,7 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: & ty::Str => { return Some(span); }, - ty::Adt(&ty::AdtDef { did, .. }, _) => { + ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) => { if ctx.tcx.is_diagnostic_item(sym::String, did) { return Some(span); } diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 9b189ea1ef8f..421bd6f53f71 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -116,15 +116,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, && let Res::Def(DefKind::Ctor(..), id) = cx.qpath_res(p, cast_expr.hir_id) { let i = def.variant_index_with_ctor_id(id); - let variant = &def.variants[i]; - let nbits = utils::enum_value_nbits(get_discriminant_value(cx.tcx, def, i)); + let variant = def.variant(i); + let nbits = utils::enum_value_nbits(get_discriminant_value(cx.tcx, *def, i)); (nbits, Some(variant)) } else { - (utils::enum_ty_to_nbits(def, cx.tcx), None) + (utils::enum_ty_to_nbits(*def, cx.tcx), None) }; let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); - let cast_from_ptr_size = def.repr.int.map_or(true, |ty| { + let cast_from_ptr_size = def.repr().int.map_or(true, |ty| { matches!( ty, IntType::SignedInt(ast::IntTy::Isize) | IntType::UnsignedInt(ast::UintTy::Usize) diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs index bbed766c47a8..5a4f20f09906 100644 --- a/clippy_lints/src/casts/utils.rs +++ b/clippy_lints/src/casts/utils.rs @@ -34,10 +34,10 @@ pub(super) fn enum_value_nbits(value: EnumValue) -> u64 { .into() } -pub(super) fn enum_ty_to_nbits(adt: &AdtDef, tcx: TyCtxt<'_>) -> u64 { +pub(super) fn enum_ty_to_nbits(adt: AdtDef<'_>, tcx: TyCtxt<'_>) -> u64 { let mut explicit = 0i128; let (start, end) = adt - .variants + .variants() .iter() .fold((0, i128::MIN), |(start, end), variant| match variant.discr { VariantDiscr::Relative(x) => match explicit.checked_add(i128::from(x)) { diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 06e6bf986c2a..f7e4bc24321c 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { then { // TODO: Work out a way to put "whatever the imported way of referencing // this type in this file" rather than a fully-qualified type. - let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); + let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did())); span_lint_and_sugg( cx, DEFAULT_TRAIT_ACCESS, @@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let Some(adt) = binding_type.ty_adt_def(); if adt.is_struct(); let variant = adt.non_enum_variant(); - if adt.did.is_local() || !variant.is_field_list_non_exhaustive(); + if adt.did().is_local() || !variant.is_field_list_non_exhaustive(); let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id(); if variant .fields @@ -216,7 +216,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let ty::Adt(adt_def, substs) = binding_type.kind(); if !substs.is_empty(); then { - let adt_def_ty_name = cx.tcx.item_name(adt_def.did); + let adt_def_ty_name = cx.tcx.item_name(adt_def.did()); let generic_args = substs.iter().collect::>(); let tys_str = generic_args .iter() diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index b80d55dd192a..f3996e5b44d7 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -148,7 +148,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { if_chain! { if let Some(adt_def) = ty.ty_adt_def(); if adt_def.is_struct(); - if let Some(variant) = adt_def.variants.iter().next(); + if let Some(variant) = adt_def.variants().iter().next(); then { let fields_def = &variant.fields; diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index eccb18982f30..14098340745b 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { _ => false, }; if should_emit { - let path_string = cx.tcx.def_path_str(adt_def.did); + let path_string = cx.tcx.def_path_str(adt_def.did()); span_lint_and_help( cx, DERIVABLE_IMPLS, diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 7277e4080c5c..557e101494e3 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -315,7 +315,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { impls .iter() - .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did)) + .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did())) }); if !has_copy_impl { return; @@ -357,10 +357,10 @@ fn check_unsafe_derive_deserialize<'tcx>( if let Some(trait_def_id) = trait_ref.trait_def_id(); if match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE); if let ty::Adt(def, _) = ty.kind(); - if let Some(local_def_id) = def.did.as_local(); + if let Some(local_def_id) = def.did().as_local(); let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id); - if cx.tcx.inherent_impls(def.did) + if cx.tcx.inherent_impls(def.did()) .iter() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)); diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index af9e65e63613..b5d6b3c7524b 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum { if let ItemKind::Enum(..) = item.kind { let ty = cx.tcx.type_of(item.def_id); let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); - if adt.variants.is_empty() { + if adt.variants().is_empty() { span_lint_and_help( cx, EMPTY_ENUM, diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 3b6661c817be..e2a5430da08c 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) { if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { - ty = adt.repr.discr_type().to_ty(cx.tcx); + ty = adt.repr().discr_type().to_ty(cx.tcx); } } match ty.kind() { diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 6490231fed8a..51c811b304ca 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -306,7 +306,7 @@ fn in_impl<'tcx>( fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool { if_chain! { if let ty::Adt(adt_def, _) = middle_ty.kind(); - if let Some(local_did) = adt_def.did.as_local(); + if let Some(local_did) = adt_def.did().as_local(); let item = cx.tcx.hir().expect_item(local_did); let middle_ty_id = item.def_id.to_def_id(); if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index d23c0c225e19..845863bd209c 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -224,7 +224,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String { ty::ImplContainer(def_id) => { let ty = cx.tcx.type_of(def_id); match ty.kind() { - ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did), + ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()), _ => ty.to_string(), } }, diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 395c920c9974..64c41b565878 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { if_chain! { if format_args.format_string_parts == [kw::Empty]; if match cx.typeck_results().expr_ty(value).peel_refs().kind() { - ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did), + ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()), ty::Str => true, _ => false, }; diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index ea9b68d1a40e..0709580c8adf 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -189,8 +189,8 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m // primitive types are never mutable ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, ty::Adt(adt, substs) => { - tys.insert(adt.did) && !ty.is_freeze(cx.tcx.at(span), cx.param_env) - || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path)) + tys.insert(adt.did()) && !ty.is_freeze(cx.tcx.at(span), cx.param_env) + || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did(), path)) && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)) }, ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, span, tys)), diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 3d44a669d8f0..c8ec2f451370 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { let ty = cx.typeck_results().expr_ty(expr); if let Some(adt_def) = ty.ty_adt_def(); if adt_def.is_struct(); - if let Some(variant) = adt_def.variants.iter().next(); + if let Some(variant) = adt_def.variants().iter().next(); if fields.iter().all(|f| f.is_shorthand); then { let mut def_order_map = FxHashMap::default(); diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index d1dc6b775c56..0f3889a29361 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -81,11 +81,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { if let ItemKind::Enum(ref def, _) = item.kind { let ty = cx.tcx.type_of(item.def_id); let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); - if adt.variants.len() <= 1 { + if adt.variants().len() <= 1 { return; } let mut variants_size: Vec = Vec::new(); - for (i, variant) in adt.variants.iter().enumerate() { + for (i, variant) in adt.variants().iter().enumerate() { let mut fields_size = Vec::new(); for (i, f) in variant.fields.iter().enumerate() { let ty = cx.tcx.type_of(f.did); diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 35d10d53112e..dabbb8375f0a 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -248,13 +248,13 @@ enum LenOutput<'tcx> { fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option> { match *sig.output().kind() { ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral), - ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => { - subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did)) + ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) => { + subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did())) }, - ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did) => subs + ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => subs .type_at(0) .is_integral() - .then(|| LenOutput::Result(adt.did, subs.type_at(1))), + .then(|| LenOutput::Result(adt.did(), subs.type_at(1))), _ => None, } } @@ -263,8 +263,8 @@ impl LenOutput<'_> { fn matches_is_empty_output(self, ty: Ty<'_>) -> bool { match (self, ty.kind()) { (_, &ty::Bool) => true, - (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did => subs.type_at(0).is_bool(), - (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did => { + (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(), + (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did() => { subs.type_at(0).is_bool() && subs.type_at(1) == err_ty }, _ => false, @@ -488,7 +488,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { .any(|item| is_is_empty(cx, item)) }), ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id), - ty::Adt(id, _) => has_is_empty_impl(cx, id.did), + ty::Adt(id, _) => has_is_empty_impl(cx, id.did()), ty::Array(..) | ty::Slice(..) | ty::Str => true, _ => false, } diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index f6ef87264c0a..b31015d195b5 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -334,7 +334,7 @@ struct Start<'hir> { fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { match ty.kind() { - ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did) => Some(subs.type_at(0)), + ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did()) => Some(subs.type_at(0)), ty::Ref(_, subty, _) => get_slice_like_element_ty(cx, *subty), ty::Slice(ty) | ty::Array(ty, _) => Some(*ty), _ => None, diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index 3515286d5b4a..93bf0dc62e07 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -45,8 +45,8 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { // Accumulate the variants which should be put in place of the wildcard because they're not // already covered. - let has_hidden = adt_def.variants.iter().any(|x| is_hidden(cx, x)); - let mut missing_variants: Vec<_> = adt_def.variants.iter().filter(|x| !is_hidden(cx, x)).collect(); + let has_hidden = adt_def.variants().iter().any(|x| is_hidden(cx, x)); + let mut missing_variants: Vec<_> = adt_def.variants().iter().filter(|x| !is_hidden(cx, x)).collect(); let mut path_prefix = CommonPrefixSearcher::None; for arm in arms { @@ -118,7 +118,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { } s } else { - let mut s = cx.tcx.def_path_str(adt_def.did); + let mut s = cx.tcx.def_path_str(adt_def.did()); s.push_str("::"); s }, diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index ce958b8ac9f5..eec232e6d098 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -145,7 +145,7 @@ pub(crate) trait BindInsteadOfMap { if_chain! { if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def(); if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM); - if Some(adt.did) == cx.tcx.parent(vid); + if Some(adt.did()) == cx.tcx.parent(vid); then {} else { return false; } } diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index 67a585edc255..6d30bb5a278b 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -15,7 +15,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, let inner_ty = match recv_ty.kind() { // `Option` -> `T` ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => + if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => { subst.type_at(0) }, diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 30c68186b3ae..558cb6bd64e7 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -119,9 +119,9 @@ pub(super) fn check<'tcx>( if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind; if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def(); - if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did) { + if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { Some(false) - } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did) { + } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { Some(true) } else { None diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 7a255baffd74..6e64e7f62220 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -17,7 +17,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv let return_type = cx.typeck_results().expr_ty(expr); let input_type = cx.typeck_results().expr_ty(recv); let (input_type, ref_count) = peel_mid_ty_refs(input_type); - if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did)); + if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did())); if return_type == input_type; then { let mut app = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index c0f66feb48ae..06ead144afa2 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -60,7 +60,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } if let ty::Adt(adt, substs) = ty.kind() { - match_def_path(cx, adt.did, &paths::COW) && substs.type_at(1).is_str() + match_def_path(cx, adt.did(), &paths::COW) && substs.type_at(1).is_str() } else { false } diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 6782f64f2ca4..e1212c31cfb0 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -55,9 +55,9 @@ pub(super) fn check<'tcx>( // lint if caller of `.map().flatten()` is an Option or Result let caller_type = match cx.typeck_results().expr_ty(recv).kind() { ty::Adt(adt, _) => { - if cx.tcx.is_diagnostic_item(sym::Option, adt.did) { + if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) { "Option" - } else if cx.tcx.is_diagnostic_item(sym::Result, adt.did) { + } else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) { "Result" } else { return; diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 926c25b4b40a..8125930b3046 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -152,7 +152,7 @@ fn parse_iter_usage<'tcx>( return if_chain! { if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE); if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind(); - if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did); + if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()); if let ty::Tuple(subs) = subs.type_at(0).kind(); if subs.len() == 2; then { diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 12ad3d8d6903..a307e33875eb 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< } else if !found_mapping && !mutates_arg { let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); match cx.typeck_results().expr_ty(&body.value).kind() { - ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && in_ty == subst.type_at(0) => { + ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) => { "filter" }, _ => return, diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index ce9ca15430e4..cba54e14212d 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -125,7 +125,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { if let Adt(def, substs) = ty.kind() { let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did)); + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did())); if is_keyed_type && is_interior_mutable_type(cx, substs.type_at(0), span) { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); } @@ -159,8 +159,8 @@ fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Sp sym::Arc, ] .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did)); - let is_box = Some(def.did) == cx.tcx.lang_items().owned_box(); + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did())); + let is_box = Some(def.did()) == cx.tcx.lang_items().owned_box(); if is_std_collection || is_box { // The type is mutable if any of its type parameters are substs.types().any(|ty| is_interior_mutable_type(cx, ty, span)) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index ebfd908a6fb7..a57dc2b27986 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -198,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { // Dereference suggestion let sugg = |diag: &mut Diagnostic| { if let ty::Adt(def, ..) = ty.kind() { - if let Some(span) = cx.tcx.hir().span_if_local(def.did) { + if let Some(span) = cx.tcx.hir().span_if_local(def.did()) { if can_type_implement_copy(cx.tcx, cx.param_env, ty, traits::ObligationCause::dummy_with_span(span)).is_ok() { diag.span_help(span, "consider marking this type as `Copy`"); } diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index ed315efaa2fa..c87c174ef732 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate { let ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(def, _) = ty.kind() { if fields.len() == def.non_enum_variant().fields.len() - && !def.variants[0_usize.into()].is_field_list_non_exhaustive() + && !def.variant(0_usize.into()).is_field_list_non_exhaustive() { span_lint( cx, diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 6c68c1bc48df..9419056be143 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { let mut impls = HirIdSet::default(); cx.tcx.for_each_impl(default_trait_id, |d| { if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() { - if let Some(local_def_id) = ty_def.did.as_local() { + if let Some(local_def_id) = ty_def.did().as_local() { impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id)); } } @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { if_chain! { if let Some(ref impling_types) = self.impling_types; if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def(); - if let Some(self_local_did) = self_def.did.as_local(); + if let Some(self_local_did) = self_def.did().as_local(); let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); if impling_types.contains(&self_id); then { diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 3ba99403f06d..8db41ba6ee29 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -140,7 +140,7 @@ fn is_value_unfrozen_raw<'tcx>( match val.ty().kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. - ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true, + ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { let val = cx.tcx.destructure_const(cx.param_env.and(val)); val.fields.iter().any(|field| inner(cx, *field)) diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 5168ca67b6ab..ddef7352de88 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { let mut non_send_fields = Vec::new(); let hir_map = cx.tcx.hir(); - for variant in &adt_def.variants { + for variant in adt_def.variants() { for field in &variant.fields { if_chain! { if let Some(field_hir_id) = field @@ -233,7 +233,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b return true; }, ty::Adt(adt_def, _) => { - if match_def_path(cx, adt_def.did, &paths::PTR_NON_NULL) { + if match_def_path(cx, adt_def.did(), &paths::PTR_NON_NULL) { return true; } }, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 2c328195f24e..9c776437d7fe 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -405,13 +405,13 @@ fn check_fn_args<'cx, 'tcx: 'cx>( // Check that the name as typed matches the actual name of the type. // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec` if let [.., name] = path.segments; - if cx.tcx.item_name(adt.did) == name.ident.name; + if cx.tcx.item_name(adt.did()) == name.ident.name; if !is_lint_allowed(cx, PTR_ARG, hir_ty.hir_id); if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id)); then { - let (method_renames, deref_ty, deref_impl_id) = match cx.tcx.get_diagnostic_name(adt.did) { + let (method_renames, deref_ty, deref_impl_id) = match cx.tcx.get_diagnostic_name(adt.did()) { Some(sym::Vec) => ( [("clone", ".to_owned()")].as_slice(), DerefTy::Slice( @@ -462,7 +462,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( return Some(PtrArg { idx: i, span: hir_ty.span, - ty_did: adt.did, + ty_did: adt.did(), ty_name: name.ident.name, method_renames, ref_prefix: RefPrefix { @@ -570,7 +570,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: .map(|sig| sig.input(i).skip_binder().peel_refs()) .map_or(true, |ty| match *ty.kind() { ty::Param(_) => true, - ty::Adt(def, _) => def.did == args.ty_did, + ty::Adt(def, _) => def.did() == args.ty_did, _ => false, }) { @@ -607,7 +607,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: // If the types match check for methods which exist on both types. e.g. `Vec::len` and // `slice::len` ty::Adt(def, _) - if def.did == args.ty_did + if def.did() == args.ty_did && (i != 0 || self.cx.tcx.trait_of_item(id).is_some() || !args.deref_assoc_items.map_or(false, |(id, items)| { diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index 123d0ad0457d..d07c26d7c897 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { if_chain! { if let Some(self_def) = self_ty.ty_adt_def(); - if let Some(self_local_did) = self_def.did.as_local(); + if let Some(self_local_did) = self_def.did().as_local(); let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id); let type_name = x.ident.name.as_str().to_lowercase(); diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 81076776ed3d..6edff2240920 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -141,7 +141,7 @@ pub(super) fn check<'tcx>( then { diag.note(&format!( "two instances of the same generic type (`{}`) may have different layouts", - cx.tcx.item_name(from_def.did) + cx.tcx.item_name(from_def.did()) )); } else { if from_ty_orig.peel_refs() != from_ty { @@ -304,13 +304,13 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> ty = sized_ty; continue; } - if def.repr.inhibit_struct_field_reordering_opt() { + if def.repr().inhibit_struct_field_reordering_opt() { ReducedTy::OrderedFields(ty) } else { ReducedTy::UnorderedFields(ty) } }, - ty::Adt(def, _) if def.is_enum() && (def.variants.is_empty() || is_c_void(cx, ty)) => { + ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => { ReducedTy::TypeErasure }, ty::Foreign(_) => ReducedTy::TypeErasure, diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 2d67401a15f2..831b0d450d20 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -11,11 +11,11 @@ use rustc_span::symbol::sym; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => { - if from_adt.did != to_adt.did { + if from_adt.did() != to_adt.did() { return false; } if !matches!( - cx.tcx.get_diagnostic_name(to_adt.did), + cx.tcx.get_diagnostic_name(to_adt.did()), Some( sym::BTreeMap | sym::BTreeSet diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 4da32c52e750..80d6f3c63367 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -151,11 +151,11 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if_chain! { if let ty::Adt(def, subst) = ty.kind(); - if match_def_path(cx, def.did, &paths::POLL); + if match_def_path(cx, def.did(), &paths::POLL); let ready_ty = subst.type_at(0); if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did); + if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did()); then { Some(ready_subst.type_at(1)) } else { @@ -168,15 +168,15 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option< fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if_chain! { if let ty::Adt(def, subst) = ty.kind(); - if match_def_path(cx, def.did, &paths::POLL); + if match_def_path(cx, def.did(), &paths::POLL); let ready_ty = subst.type_at(0); if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did); + if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did()); let some_ty = ready_subst.type_at(0); if let ty::Adt(some_def, some_subst) = some_ty.kind(); - if cx.tcx.is_diagnostic_item(sym::Result, some_def.did); + if cx.tcx.is_diagnostic_item(sym::Result, some_def.did()); then { Some(some_subst.type_at(1)) } else { diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 1728533f18b8..f4f5a4336a39 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -102,9 +102,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { // Get the wrapper and inner types, if can't, abort. let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() { - if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did) { + if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) { ("Option", OptionSome, subst.type_at(0)) - } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did) { + } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) { ("Result", ResultOk, subst.type_at(0)) } else { return; diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index eb9efec3f161..a6ef6d79fc02 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -73,7 +73,7 @@ fn fn_eagerness<'tcx>( // than marker traits. // Due to the limited operations on these types functions should be fairly cheap. if def - .variants + .variants() .iter() .flat_map(|v| v.fields.iter()) .any(|x| matches!(cx.tcx.type_of(x.did).peel_refs().kind(), ty::Param(_))) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8c14f0dd761a..cd20abd94ed2 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -268,7 +268,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() { - return cx.tcx.is_diagnostic_item(diag_item, adt.did); + return cx.tcx.is_diagnostic_item(diag_item, adt.did()); } } false @@ -657,7 +657,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() { return std_types_symbols .iter() - .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did)); + .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did())); } } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 0646d1524a76..3645a9a5228c 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -51,7 +51,7 @@ pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool { /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt /// constructor. -pub fn contains_adt_constructor(ty: Ty<'_>, adt: &AdtDef) -> bool { +pub fn contains_adt_constructor(ty: Ty<'_>, adt: AdtDef<'_>) -> bool { ty.walk().any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, @@ -112,7 +112,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option< let def_id = match ty_to_check.kind() { ty::Array(..) => return Some(sym::array), ty::Slice(..) => return Some(sym::slice), - ty::Adt(adt, _) => adt.did, + ty::Adt(adt, _) => adt.did(), _ => return None, }; @@ -164,7 +164,7 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // Returns whether the type has #[must_use] attribute pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { - ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(), + ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did())).is_some(), ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(), ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case @@ -220,7 +220,7 @@ fn is_normalizable_helper<'tcx>( let cause = rustc_middle::traits::ObligationCause::dummy(); if infcx.at(&cause, param_env).normalize(ty).is_ok() { match ty.kind() { - ty::Adt(def, substs) => def.variants.iter().all(|variant| { + ty::Adt(def, substs) => def.variants().iter().all(|variant| { variant .fields .iter() @@ -264,7 +264,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { match ty.kind() { ty::Ref(_, ref_ty, _) => match ref_ty.kind() { - ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), + ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()), _ => false, }, _ => false, @@ -284,7 +284,7 @@ pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_ite /// [Diagnostic Items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { match ty.kind() { - ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did), + ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()), _ => false, } } @@ -294,7 +294,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Returns `false` if the `LangItem` is not defined. pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { match ty.kind() { - ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did), + ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did()), _ => false, } } @@ -310,7 +310,7 @@ pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { /// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem` pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { match ty.kind() { - ty::Adt(adt, _) => match_def_path(cx, adt.did, path), + ty::Adt(adt, _) => match_def_path(cx, adt.did(), path), _ => false, } } @@ -398,7 +398,7 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { match *ty.kind() { ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), - ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did), + ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()), _ => false, } } @@ -562,11 +562,11 @@ pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option } /// Gets the value of the given variant. -pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -> EnumValue { - let variant = &adt.variants[i]; +pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: AdtDef<'_>, i: VariantIdx) -> EnumValue { + let variant = &adt.variant(i); match variant.discr { VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap(), - VariantDiscr::Relative(x) => match adt.variants[(i.as_usize() - x as usize).into()].discr { + VariantDiscr::Relative(x) => match adt.variant((i.as_usize() - x as usize).into()).discr { VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap() + x, VariantDiscr::Relative(_) => EnumValue::Unsigned(x.into()), }, @@ -577,7 +577,7 @@ pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) - /// platform specific `libc::::c_void` types in libc. pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { if let ty::Adt(adt, _) = ty.kind() - && let &[krate, .., name] = &*cx.get_def_path(adt.did) + && let &[krate, .., name] = &*cx.get_def_path(adt.did()) && let sym::libc | sym::core | sym::std = krate && name.as_str() == "c_void" { From 2ebd0b20b03d06b7e6b8d153711c0327bce5ae5e Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 14 Mar 2022 11:29:39 +0100 Subject: [PATCH 19/19] Bump nightly version -> 2022-03-14 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 4d2c57619912..9d5da4ed68f8 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-02-24" +channel = "nightly-2022-03-14" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]