From c6692a8b4284a2e033f620b71a2ad6a88833bb05 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 6 Feb 2023 14:21:37 -0500 Subject: [PATCH 01/90] Add configuration to lint missing docs of `pub(crate)` items --- clippy_lints/src/lib.rs | 3 +- clippy_lints/src/missing_doc.rs | 16 ++++++++-- clippy_lints/src/utils/conf.rs | 4 +++ .../pub_crate_missing_docs/clippy.toml | 1 + .../pub_crate_missing_doc.rs | 32 +++++++++++++++++++ .../pub_crate_missing_doc.stderr | 22 +++++++++++++ 6 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 tests/ui-toml/pub_crate_missing_docs/clippy.toml create mode 100644 tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs create mode 100644 tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2f5c4adca9f10..f5c417fffa837 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -665,12 +665,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); + let only_check_missing_docs_in_crate_items = conf.only_check_missing_docs_in_crate_items; store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); store.register_late_pass(|_| Box::new(mem_forget::MemForget)); store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); - store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new())); + store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(only_check_missing_docs_in_crate_items))); store.register_late_pass(|_| Box::new(missing_inline::MissingInline)); store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems)); store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk)); diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 9942e8115b7f8..3bce54bf2e920 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -12,7 +12,7 @@ use if_chain::if_chain; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::DefIdTree; +use rustc_middle::ty::{DefIdTree, Visibility}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Span; @@ -35,6 +35,8 @@ declare_clippy_lint! { } pub struct MissingDoc { + /// FIXME: docs + crate_items_only: bool, /// Stack of whether #[doc(hidden)] is set /// at each level which has lint attributes. doc_hidden_stack: Vec, @@ -43,14 +45,15 @@ pub struct MissingDoc { impl Default for MissingDoc { #[must_use] fn default() -> Self { - Self::new() + Self::new(false) } } impl MissingDoc { #[must_use] - pub fn new() -> Self { + pub fn new(crate_items_only: bool) -> Self { Self { + crate_items_only, doc_hidden_stack: vec![false], } } @@ -128,6 +131,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { + if self.crate_items_only { + let vis = cx.tcx.visibility(it.owner_id.to_def_id()); + if vis != Visibility::Public && vis != Visibility::Restricted(CRATE_DEF_ID.into()) { + return; + } + } + match it.kind { hir::ItemKind::Fn(..) => { // ignore main() diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 1d78c7cfae0df..f81965b64327b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -454,6 +454,10 @@ define_Conf! { /// configuration will cause restriction lints to trigger even /// if no suggestion can be made. (suppress_restriction_lint_in_const: bool = false), + /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. + /// + /// FIXME: docs + (only_check_missing_docs_in_crate_items: bool = false), } /// Search for the configuration file. diff --git a/tests/ui-toml/pub_crate_missing_docs/clippy.toml b/tests/ui-toml/pub_crate_missing_docs/clippy.toml new file mode 100644 index 0000000000000..a2f1fc27da354 --- /dev/null +++ b/tests/ui-toml/pub_crate_missing_docs/clippy.toml @@ -0,0 +1 @@ +only-check-missing-docs-in-crate-items = true diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs new file mode 100644 index 0000000000000..8eef92d20bf37 --- /dev/null +++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs @@ -0,0 +1,32 @@ +//! this is crate +#![warn(clippy::missing_docs_in_private_items)] + +/// this is mod +mod my_mod { + /// some docs + fn priv_with_docs() {} + fn priv_no_docs() {} + /// some docs + pub(crate) fn crate_with_docs() {} + pub(crate) fn crate_no_docs() {} + /// some docs + pub(super) fn super_with_docs() {} + pub(super) fn super_no_docs() {} + + mod my_sub { + /// some docs + fn sub_priv_with_docs() {} + fn sub_priv_no_docs() {} + /// some docs + pub(crate) fn sub_crate_with_docs() {} + pub(crate) fn sub_crate_no_docs() {} + /// some docs + pub(super) fn sub_super_with_docs() {} + pub(super) fn sub_super_no_docs() {} + } +} + +fn main() { + my_mod::crate_with_docs(); + my_mod::crate_no_docs(); +} diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr new file mode 100644 index 0000000000000..954ef2382f7be --- /dev/null +++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr @@ -0,0 +1,22 @@ +error: missing documentation for a function + --> $DIR/pub_crate_missing_doc.rs:11:5 + | +LL | pub(crate) fn crate_no_docs() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` + +error: missing documentation for a function + --> $DIR/pub_crate_missing_doc.rs:14:5 + | +LL | pub(super) fn super_no_docs() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a function + --> $DIR/pub_crate_missing_doc.rs:22:9 + | +LL | pub(crate) fn sub_crate_no_docs() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From 8eac9e359ec84a7621ee009aadeac91bf22c75b2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 6 Feb 2023 15:19:26 -0500 Subject: [PATCH 02/90] bless tests --- tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index a22c6a5a0607d..f4815df19ca69 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -34,6 +34,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie max-suggested-slice-pattern-length max-trait-bounds msrv + only-check-missing-docs-in-crate-items pass-by-value-size-limit single-char-binding-names-threshold standard-macro-braces From 374c393a937318b2ab6620010a0d252d1339383c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 9 Feb 2023 10:16:00 +0000 Subject: [PATCH 03/90] Introduce `-Zterminal-urls` to use OSC8 for error codes Terminals supporting the OSC8 Hyperlink Extension can support inline anchors where the text is user defineable but clicking on it opens a browser to a specified URLs, just like `` does in HTML. https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda --- clippy_lints/src/doc.rs | 3 ++- src/driver.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 127201b72e275..0b31e20fc87c0 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -11,7 +11,7 @@ use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; -use rustc_errors::{Applicability, Handler, SuggestionStyle}; +use rustc_errors::{Applicability, Handler, SuggestionStyle, TerminalUrl}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Expr}; @@ -717,6 +717,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { None, false, false, + TerminalUrl::No, ); let handler = Handler::with_emitter(false, None, Box::new(emitter)); let sess = ParseSess::with_span_handler(handler, sm); diff --git a/src/driver.rs b/src/driver.rs index d521e8d883983..e45835efe7464 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -220,6 +220,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { None, false, false, + rustc_errors::TerminalUrl::No, )); let handler = rustc_errors::Handler::with_emitter(true, None, emitter); From e2e23c0045d94cc0d509cbb3c915faae74844ea8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 9 Feb 2023 16:41:45 -0500 Subject: [PATCH 04/90] Add docs and update tests --- clippy_lints/src/lib.rs | 4 +-- clippy_lints/src/missing_doc.rs | 30 ++++++++++--------- clippy_lints/src/utils/conf.rs | 4 +-- .../pub_crate_missing_docs/clippy.toml | 2 +- .../pub_crate_missing_doc.rs | 19 ++++++++++++ .../pub_crate_missing_doc.stderr | 26 +++++++++++++++- .../pub_crate_missing_doc.stdout | 0 .../toml_unknown_key/conf_unknown_key.stderr | 2 +- 8 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stdout diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f5c417fffa837..2d04118c69412 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -665,13 +665,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); - let only_check_missing_docs_in_crate_items = conf.only_check_missing_docs_in_crate_items; + let missing_docs_in_crate_items = conf.missing_docs_in_crate_items; store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); store.register_late_pass(|_| Box::new(mem_forget::MemForget)); store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); - store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(only_check_missing_docs_in_crate_items))); + store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(missing_docs_in_crate_items))); store.register_late_pass(|_| Box::new(missing_inline::MissingInline)); store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems)); store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk)); diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 3bce54bf2e920..a5d8a500cca79 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -8,6 +8,7 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; +use hir::def_id::LocalDefId; use if_chain::if_chain; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; @@ -35,7 +36,7 @@ declare_clippy_lint! { } pub struct MissingDoc { - /// FIXME: docs + /// Whether to only check for missing docs in `pub(crate)` items. crate_items_only: bool, /// Stack of whether #[doc(hidden)] is set /// at each level which has lint attributes. @@ -79,6 +80,7 @@ impl MissingDoc { fn check_missing_docs_attrs( &self, cx: &LateContext<'_>, + def_id: LocalDefId, attrs: &[ast::Attribute], sp: Span, article: &'static str, @@ -99,6 +101,13 @@ impl MissingDoc { return; } + if self.crate_items_only && def_id != CRATE_DEF_ID { + let vis = cx.tcx.visibility(def_id); + if vis != Visibility::Public && vis != Visibility::Restricted(CRATE_DEF_ID.into()) { + return; + } + } + let has_doc = attrs .iter() .any(|a| a.doc_str().is_some() || Self::has_include(a.meta())); @@ -127,17 +136,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_crate(&mut self, cx: &LateContext<'tcx>) { let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); - self.check_missing_docs_attrs(cx, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate"); + self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate"); } fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { - if self.crate_items_only { - let vis = cx.tcx.visibility(it.owner_id.to_def_id()); - if vis != Visibility::Public && vis != Visibility::Restricted(CRATE_DEF_ID.into()) { - return; - } - } - match it.kind { hir::ItemKind::Fn(..) => { // ignore main() @@ -170,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let attrs = cx.tcx.hir().attrs(it.hir_id()); if !is_from_proc_macro(cx, it) { - self.check_missing_docs_attrs(cx, attrs, it.span, article, desc); + self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc); } } @@ -179,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let attrs = cx.tcx.hir().attrs(trait_item.hir_id()); if !is_from_proc_macro(cx, trait_item) { - self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc); + self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc); } } @@ -196,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id()); let attrs = cx.tcx.hir().attrs(impl_item.hir_id()); if !is_from_proc_macro(cx, impl_item) { - self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc); + self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc); } } @@ -204,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { if !sf.is_positional() { let attrs = cx.tcx.hir().attrs(sf.hir_id); if !is_from_proc_macro(cx, sf) { - self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field"); + self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field"); } } } @@ -212,7 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { let attrs = cx.tcx.hir().attrs(v.hir_id); if !is_from_proc_macro(cx, v) { - self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant"); + self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant"); } } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index f81965b64327b..86a17a40930f1 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -456,8 +456,8 @@ define_Conf! { (suppress_restriction_lint_in_const: bool = false), /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. /// - /// FIXME: docs - (only_check_missing_docs_in_crate_items: bool = false), + /// Whether to **only** check for missing docmuentation in `pub(crate)` items. + (missing_docs_in_crate_items: bool = false), } /// Search for the configuration file. diff --git a/tests/ui-toml/pub_crate_missing_docs/clippy.toml b/tests/ui-toml/pub_crate_missing_docs/clippy.toml index a2f1fc27da354..ec210a9878305 100644 --- a/tests/ui-toml/pub_crate_missing_docs/clippy.toml +++ b/tests/ui-toml/pub_crate_missing_docs/clippy.toml @@ -1 +1 @@ -only-check-missing-docs-in-crate-items = true +missing-docs-in-crate-items = true diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs index 8eef92d20bf37..f2edb737d59cc 100644 --- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs +++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs @@ -24,6 +24,25 @@ mod my_mod { pub(super) fn sub_super_with_docs() {} pub(super) fn sub_super_no_docs() {} } + + /// some docs + pub(crate) struct CrateStructWithDocs { + /// some docs + pub(crate) crate_field_with_docs: (), + pub(crate) crate_field_no_docs: (), + /// some docs + priv_field_with_docs: (), + priv_field_no_docs: (), + } + + pub(crate) struct CrateStructNoDocs { + /// some docs + pub(crate) crate_field_with_docs: (), + pub(crate) crate_field_no_docs: (), + /// some docs + priv_field_with_docs: (), + priv_field_no_docs: (), + } } fn main() { diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr index 954ef2382f7be..89927abd87bfe 100644 --- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr +++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr @@ -18,5 +18,29 @@ error: missing documentation for a function LL | pub(crate) fn sub_crate_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: missing documentation for a struct field + --> $DIR/pub_crate_missing_doc.rs:32:9 + | +LL | pub(crate) crate_field_no_docs: (), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a struct + --> $DIR/pub_crate_missing_doc.rs:38:5 + | +LL | / pub(crate) struct CrateStructNoDocs { +LL | | /// some docs +LL | | pub(crate) crate_field_with_docs: (), +LL | | pub(crate) crate_field_no_docs: (), +... | +LL | | priv_field_no_docs: (), +LL | | } + | |_____^ + +error: missing documentation for a struct field + --> $DIR/pub_crate_missing_doc.rs:41:9 + | +LL | pub(crate) crate_field_no_docs: (), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stdout b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stdout new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index f4815df19ca69..6a246afac76e0 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -33,8 +33,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie max-struct-bools max-suggested-slice-pattern-length max-trait-bounds + missing-docs-in-crate-items msrv - only-check-missing-docs-in-crate-items pass-by-value-size-limit single-char-binding-names-threshold standard-macro-braces From cc19fbe177eea84aac436a35889788b2ad0f1c6a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 9 Feb 2023 16:53:34 -0500 Subject: [PATCH 05/90] update metadata --- book/src/lint_configuration.md | 9 +++++++++ clippy_lints/src/utils/conf.rs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 32e8e218c4055..46bed62dfc93a 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -53,6 +53,7 @@ Please use that command to update the file and do not edit it by hand. | [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` | | [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` | | [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` | +| [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` | ### arithmetic-side-effects-allowed Suppress checking of the passed type names in all types of operations. @@ -540,4 +541,12 @@ if no suggestion can be made. * [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) +### missing-docs-in-crate-items +Whether to **only** check for missing documentation in `pub(crate)` items. + +**Default Value:** `false` (`bool`) + +* [missing_docs_in_private_items](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) + + diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 86a17a40930f1..ae35ceebc5530 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -456,7 +456,7 @@ define_Conf! { (suppress_restriction_lint_in_const: bool = false), /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. /// - /// Whether to **only** check for missing docmuentation in `pub(crate)` items. + /// Whether to **only** check for missing documentation in `pub(crate)` items. (missing_docs_in_crate_items: bool = false), } From 179c037643fda44f7874816c0030ad83798bdad3 Mon Sep 17 00:00:00 2001 From: DevAccentor Date: Sat, 4 Jun 2022 16:48:35 +0200 Subject: [PATCH 06/90] improve almost swap to look for let statement --- clippy_lints/src/swap.rs | 74 ++++++++++++++++++++++++++++++++++ tests/ui/almost_swapped.rs | 32 +++++++++++++++ tests/ui/almost_swapped.stderr | 30 ++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 tests/ui/almost_swapped.rs create mode 100644 tests/ui/almost_swapped.stderr diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 17e9cc5f6b7c7..5c408a73a55b2 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -172,6 +172,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { } } +#[allow(clippy::too_many_lines)] /// Implementation of the `ALMOST_SWAPPED` lint. fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { for w in block.stmts.windows(2) { @@ -220,6 +221,79 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { }); } } + + let lint_almost_swapped_note = |span, what: String, sugg, lhs, rhs| { + span_lint_and_then( + cx, + ALMOST_SWAPPED, + span, + &format!("this looks like you are trying to swap{}", what), + |diag| { + if !what.is_empty() { + diag.note(&format!( + "maybe you could use `{sugg}::mem::swap({lhs}, {rhs})` or `{sugg}::mem::replace`?" + )); + } + }, + ); + }; + + if let StmtKind::Local(first) = w[0].kind + && let StmtKind::Local(second) = w[1].kind + && first.span.ctxt() == second.span.ctxt() + && let Some(rhs0) = first.init + && let Some(rhs1) = second.init + && let ExprKind::Path(QPath::Resolved(None, path_l)) = rhs0.kind + && let ExprKind::Path(QPath::Resolved(None, path_r)) = rhs1.kind + && let PatKind::Binding(_,_, ident_l,_) = first.pat.kind + && let PatKind::Binding(_,_, ident_r,_) = second.pat.kind + && ident_l.name.as_str() == path_r.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") + && ident_r.name.as_str() == path_l.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") + { + let rhs0 = Sugg::hir_opt(cx, rhs0); + let (what, lhs, rhs) = if let Some(second) = rhs0 { + ( + format!(" `{}` and `{}`", ident_l, second), + format!("&mut {}", ident_l), + second.mut_addr().to_string(), + ) + } else { + (String::new(), String::new(), String::new()) + }; + let span = first.span.to(second.span); + let Some(sugg) = std_or_core(cx) else { return }; + + lint_almost_swapped_note(span, what, sugg, lhs, rhs); + } + + if let StmtKind::Local(first) = w[0].kind + && let StmtKind::Semi(second) = w[1].kind + && first.span.ctxt() == second.span.ctxt() + && let Some(rhs0) = first.init + && let ExprKind::Path(QPath::Resolved(None, path_l)) = rhs0.kind + && let PatKind::Binding(_,_, ident_l,_) = first.pat.kind + && let ExprKind::Assign(lhs1, rhs1, _) = second.kind + && let ExprKind::Path(QPath::Resolved(None, lhs1_path)) = lhs1.kind + && let ExprKind::Path(QPath::Resolved(None, rhs1_path)) = rhs1.kind + && ident_l.name.as_str() == rhs1_path.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") + && path_l.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") == lhs1_path.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") + { + let lhs1 = Sugg::hir_opt(cx, lhs1); + let rhs1 = Sugg::hir_opt(cx, rhs1); + let (what, lhs, rhs) = if let (Some(first),Some(second)) = (lhs1,rhs1) { + ( + format!(" `{}` and `{}`", first, second), + first.mut_addr().to_string(), + second.mut_addr().to_string(), + ) + } else { + (String::new(), String::new(), String::new()) + }; + let span = first.span.to(second.span); + let Some(sugg) = std_or_core(cx) else { return }; + + lint_almost_swapped_note(span, what, sugg, lhs, rhs); + } } } diff --git a/tests/ui/almost_swapped.rs b/tests/ui/almost_swapped.rs new file mode 100644 index 0000000000000..8b0740c320973 --- /dev/null +++ b/tests/ui/almost_swapped.rs @@ -0,0 +1,32 @@ +#![allow(clippy::needless_late_init, clippy::manual_swap)] +#![allow(unused_variables, unused_assignments)] +#![warn(clippy::almost_swapped)] + +fn main() { + let b = 1; + let a = b; + let b = a; + + let mut c = 1; + let mut d = 2; + d = c; + c = d; + + let mut b = 1; + let a = b; + b = a; + + let b = 1; + let a = 2; + + let t = b; + let b = a; + let a = t; + + let mut b = 1; + let mut a = 2; + + let t = b; + b = a; + a = t; +} diff --git a/tests/ui/almost_swapped.stderr b/tests/ui/almost_swapped.stderr new file mode 100644 index 0000000000000..70788d23f1686 --- /dev/null +++ b/tests/ui/almost_swapped.stderr @@ -0,0 +1,30 @@ +error: this looks like you are trying to swap `a` and `b` + --> $DIR/almost_swapped.rs:7:5 + | +LL | / let a = b; +LL | | let b = a; + | |______________^ + | + = note: `-D clippy::almost-swapped` implied by `-D warnings` + = note: maybe you could use `std::mem::swap(&mut a, &mut b)` or `std::mem::replace`? + +error: this looks like you are trying to swap `d` and `c` + --> $DIR/almost_swapped.rs:12:5 + | +LL | / d = c; +LL | | c = d; + | |_________^ help: try: `std::mem::swap(&mut d, &mut c)` + | + = note: or maybe you should use `std::mem::replace`? + +error: this looks like you are trying to swap `b` and `a` + --> $DIR/almost_swapped.rs:16:5 + | +LL | / let a = b; +LL | | b = a; + | |_________^ + | + = note: maybe you could use `std::mem::swap(&mut b, &mut a)` or `std::mem::replace`? + +error: aborting due to 3 previous errors + From e7fe1f9c1446344c9b542f666ac58b116eb58bd6 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 10 Feb 2023 14:01:19 +0100 Subject: [PATCH 07/90] Merge commit '0f7558148c22e53cd4608773b56cdfa50dcdeac3' into clippyup --- CHANGELOG.md | 1 + Cargo.toml | 1 + README.md | 2 +- book/src/README.md | 2 +- book/src/lint_configuration.md | 26 +- clippy_dev/Cargo.toml | 2 +- clippy_dev/src/main.rs | 127 +++-- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/bool_assert_comparison.rs | 53 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/excessive_bools.rs | 2 +- .../src/extra_unused_type_parameters.rs | 178 ++++++ clippy_lints/src/format_args.rs | 2 +- .../src/functions/misnamed_getters.rs | 8 +- .../src/functions/not_unsafe_ptr_arg_deref.rs | 2 +- .../src/iter_not_returning_iterator.rs | 4 +- clippy_lints/src/len_zero.rs | 17 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/lifetimes.rs | 253 ++++---- clippy_lints/src/loops/mod.rs | 3 +- clippy_lints/src/loops/needless_range_loop.rs | 2 +- clippy_lints/src/manual_assert.rs | 97 ++-- clippy_lints/src/matches/match_wild_enum.rs | 13 +- clippy_lints/src/methods/mod.rs | 1 + .../src/methods/suspicious_to_owned.rs | 22 +- .../src/multiple_unsafe_ops_per_block.rs | 3 +- clippy_lints/src/option_if_let_else.rs | 10 +- clippy_lints/src/ptr.rs | 5 +- clippy_lints/src/regex.rs | 89 ++- clippy_lints/src/return_self_not_must_use.rs | 4 +- clippy_lints/src/semicolon_block.rs | 4 +- clippy_lints/src/types/mod.rs | 4 +- clippy_lints/src/unused_io_amount.rs | 2 +- clippy_lints/src/utils/conf.rs | 10 +- clippy_lints/src/utils/dump_hir.rs | 13 + .../internal_lints/lint_without_lint_pass.rs | 15 +- clippy_utils/src/macros.rs | 5 +- clippy_utils/src/sugg.rs | 5 +- clippy_utils/src/visitors.rs | 8 +- lintcheck/Cargo.toml | 4 +- rust-toolchain | 2 +- ...unnecessary_def_path_hardcoded_path.stderr | 16 +- tests/ui/auxiliary/macro_rules.rs | 19 + tests/ui/bool_assert_comparison.fixed | 38 +- tests/ui/bool_assert_comparison.rs | 10 + tests/ui/bool_assert_comparison.stderr | 126 +++- tests/ui/crashes/ice-2774.stderr | 5 + .../needless_lifetimes_impl_trait.stderr | 5 + tests/ui/extra_unused_type_parameters.rs | 69 +++ tests/ui/extra_unused_type_parameters.stderr | 59 ++ tests/ui/len_without_is_empty.rs | 46 ++ tests/ui/manual_assert.edition2018.fixed | 35 +- tests/ui/manual_assert.edition2018.stderr | 67 ++- .../match_wildcard_for_single_variants.fixed | 2 +- .../match_wildcard_for_single_variants.stderr | 8 +- tests/ui/multiple_unsafe_ops_per_block.rs | 9 + tests/ui/multiple_unsafe_ops_per_block.stderr | 40 +- tests/ui/needless_lifetimes.fixed | 538 ++++++++++++++++++ tests/ui/needless_lifetimes.rs | 42 +- tests/ui/needless_lifetimes.stderr | 391 ++++++++++--- tests/ui/needless_range_loop.stderr | 8 +- tests/ui/new_without_default.rs | 7 +- tests/ui/new_without_default.stderr | 14 +- tests/ui/redundant_field_names.fixed | 2 +- tests/ui/redundant_field_names.rs | 2 +- tests/ui/regex.rs | 4 + tests/ui/regex.stderr | 66 ++- .../ui/seek_to_start_instead_of_rewind.fixed | 4 +- tests/ui/seek_to_start_instead_of_rewind.rs | 4 +- tests/ui/suspicious_to_owned.stderr | 43 +- tests/ui/type_repetition_in_bounds.rs | 1 + tests/ui/type_repetition_in_bounds.stderr | 8 +- tests/ui/unused_io_amount.rs | 8 + tests/ui/unused_io_amount.stderr | 44 +- tests/ui/wildcard_enum_match_arm.fixed | 2 +- tests/ui/wildcard_enum_match_arm.stderr | 4 +- 76 files changed, 2192 insertions(+), 560 deletions(-) create mode 100644 clippy_lints/src/extra_unused_type_parameters.rs create mode 100644 tests/ui/extra_unused_type_parameters.rs create mode 100644 tests/ui/extra_unused_type_parameters.stderr create mode 100644 tests/ui/needless_lifetimes.fixed diff --git a/CHANGELOG.md b/CHANGELOG.md index e2cde09776f4c..659e8aebcd579 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4383,6 +4383,7 @@ Released 2018-09-13 [`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice [`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain [`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes +[`extra_unused_type_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_type_parameters [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file diff --git a/Cargo.toml b/Cargo.toml index 2cfb47dd758aa..70d1268090f6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ filetime = "0.2" rustc-workspace-hack = "1.0" # UI test dependencies +clap = { version = "4.1.4", features = ["derive"] } clippy_utils = { path = "clippy_utils" } derive-new = "0.5" if_chain = "1.0" diff --git a/README.md b/README.md index ab44db694835f..95f6d2cc45c83 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/book/src/README.md b/book/src/README.md index 23867df8efe1d..df4a1f2702e47 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index f79dbb50ff490..32e8e218c4055 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -43,6 +43,7 @@ Please use that command to update the file and do not edit it by hand. | [allowed-scripts](#allowed-scripts) | `["Latin"]` | | [enable-raw-pointer-heuristic-for-send](#enable-raw-pointer-heuristic-for-send) | `true` | | [max-suggested-slice-pattern-length](#max-suggested-slice-pattern-length) | `3` | +| [await-holding-invalid-types](#await-holding-invalid-types) | `[]` | | [max-include-file-size](#max-include-file-size) | `1000000` | | [allow-expect-in-tests](#allow-expect-in-tests) | `false` | | [allow-unwrap-in-tests](#allow-unwrap-in-tests) | `false` | @@ -167,6 +168,17 @@ The minimum rust version that the project supports * [manual_clamp](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) * [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) * [unchecked_duration_subtraction](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction) +* [collapsible_str_replace](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) +* [seek_from_current](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) +* [seek_rewind](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) +* [unnecessary_lazy_evaluations](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) +* [transmute_ptr_to_ref](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) +* [almost_complete_range](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) +* [needless_borrow](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) +* [derivable_impls](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) +* [manual_is_ascii_check](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) +* [manual_rem_euclid](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) +* [manual_retain](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) ### cognitive-complexity-threshold @@ -279,7 +291,7 @@ The minimum size (in bytes) to consider a type for passing by reference instead **Default Value:** `256` (`u64`) -* [large_type_pass_by_move](https://rust-lang.github.io/rust-clippy/master/index.html#large_type_pass_by_move) +* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) ### too-many-lines-threshold @@ -442,6 +454,14 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. * [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) +### await-holding-invalid-types + + +**Default Value:** `[]` (`Vec`) + +* [await_holding_invalid_type](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type) + + ### max-include-file-size The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes @@ -497,7 +517,7 @@ for the generic parameters for determining interior mutability **Default Value:** `["bytes::Bytes"]` (`Vec`) -* [mutable_key](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key) +* [mutable_key_type](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) ### allow-mixed-uninlined-format-args @@ -509,7 +529,7 @@ Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar) ### suppress-restriction-lint-in-const -In same +Whether to suppress a restriction lint in constant code. In same cases the restructured operation might not be unavoidable, as the suggested counterparts are unavailable in constant code. This configuration will cause restriction lints to trigger even diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index 510c7e852af6e..c3f8a782d273a 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] aho-corasick = "0.7" -clap = "3.2" +clap = "4.1.4" indoc = "1.0" itertools = "0.10.1" opener = "0.5" diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index d3e036692040f..e2457e5a8a5e9 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -2,7 +2,7 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] -use clap::{Arg, ArgAction, ArgMatches, Command, PossibleValue}; +use clap::{Arg, ArgAction, ArgMatches, Command}; use clippy_dev::{bless, dogfood, fmt, lint, new_lint, serve, setup, update_lints}; use indoc::indoc; @@ -11,22 +11,22 @@ fn main() { match matches.subcommand() { Some(("bless", matches)) => { - bless::bless(matches.contains_id("ignore-timestamp")); + bless::bless(matches.get_flag("ignore-timestamp")); }, Some(("dogfood", matches)) => { dogfood::dogfood( - matches.contains_id("fix"), - matches.contains_id("allow-dirty"), - matches.contains_id("allow-staged"), + matches.get_flag("fix"), + matches.get_flag("allow-dirty"), + matches.get_flag("allow-staged"), ); }, Some(("fmt", matches)) => { - fmt::run(matches.contains_id("check"), matches.contains_id("verbose")); + fmt::run(matches.get_flag("check"), matches.get_flag("verbose")); }, Some(("update_lints", matches)) => { - if matches.contains_id("print-only") { + if matches.get_flag("print-only") { update_lints::print_lints(); - } else if matches.contains_id("check") { + } else if matches.get_flag("check") { update_lints::update(update_lints::UpdateMode::Check); } else { update_lints::update(update_lints::UpdateMode::Change); @@ -38,7 +38,7 @@ fn main() { matches.get_one::("name"), matches.get_one::("category").map(String::as_str), matches.get_one::("type").map(String::as_str), - matches.contains_id("msrv"), + matches.get_flag("msrv"), ) { Ok(_) => update_lints::update(update_lints::UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {e}"), @@ -46,7 +46,7 @@ fn main() { }, Some(("setup", sub_command)) => match sub_command.subcommand() { Some(("intellij", matches)) => { - if matches.contains_id("remove") { + if matches.get_flag("remove") { setup::intellij::remove_rustc_src(); } else { setup::intellij::setup_rustc_src( @@ -57,17 +57,17 @@ fn main() { } }, Some(("git-hook", matches)) => { - if matches.contains_id("remove") { + if matches.get_flag("remove") { setup::git_hook::remove_hook(); } else { - setup::git_hook::install_hook(matches.contains_id("force-override")); + setup::git_hook::install_hook(matches.get_flag("force-override")); } }, Some(("vscode-tasks", matches)) => { - if matches.contains_id("remove") { + if matches.get_flag("remove") { setup::vscode::remove_tasks(); } else { - setup::vscode::install_tasks(matches.contains_id("force-override")); + setup::vscode::install_tasks(matches.get_flag("force-override")); } }, _ => {}, @@ -91,7 +91,7 @@ fn main() { Some(("rename_lint", matches)) => { let old_name = matches.get_one::("old_name").unwrap(); let new_name = matches.get_one::("new_name").unwrap_or(old_name); - let uplift = matches.contains_id("uplift"); + let uplift = matches.get_flag("uplift"); update_lints::rename(old_name, new_name, uplift); }, Some(("deprecate", matches)) => { @@ -110,24 +110,37 @@ fn get_clap_config() -> ArgMatches { Command::new("bless").about("bless the test output changes").arg( Arg::new("ignore-timestamp") .long("ignore-timestamp") + .action(ArgAction::SetTrue) .help("Include files updated before clippy was built"), ), Command::new("dogfood").about("Runs the dogfood test").args([ - Arg::new("fix").long("fix").help("Apply the suggestions when possible"), + Arg::new("fix") + .long("fix") + .action(ArgAction::SetTrue) + .help("Apply the suggestions when possible"), Arg::new("allow-dirty") .long("allow-dirty") + .action(ArgAction::SetTrue) .help("Fix code even if the working directory has changes") .requires("fix"), Arg::new("allow-staged") .long("allow-staged") + .action(ArgAction::SetTrue) .help("Fix code even if the working directory has staged changes") .requires("fix"), ]), Command::new("fmt") .about("Run rustfmt on all projects and tests") .args([ - Arg::new("check").long("check").help("Use the rustfmt --check option"), - Arg::new("verbose").short('v').long("verbose").help("Echo commands run"), + Arg::new("check") + .long("check") + .action(ArgAction::SetTrue) + .help("Use the rustfmt --check option"), + Arg::new("verbose") + .short('v') + .long("verbose") + .action(ArgAction::SetTrue) + .help("Echo commands run"), ]), Command::new("update_lints") .about("Updates lint registration and information from the source code") @@ -140,13 +153,17 @@ fn get_clap_config() -> ArgMatches { * all lints are registered in the lint store", ) .args([ - Arg::new("print-only").long("print-only").help( - "Print a table of lints to STDOUT. \ - This does not include deprecated and internal lints. \ - (Does not modify any files)", - ), + Arg::new("print-only") + .long("print-only") + .action(ArgAction::SetTrue) + .help( + "Print a table of lints to STDOUT. \ + This does not include deprecated and internal lints. \ + (Does not modify any files)", + ), Arg::new("check") .long("check") + .action(ArgAction::SetTrue) .help("Checks that `cargo dev update_lints` has been run. Used on CI."), ]), Command::new("new_lint") @@ -156,15 +173,13 @@ fn get_clap_config() -> ArgMatches { .short('p') .long("pass") .help("Specify whether the lint runs during the early or late pass") - .takes_value(true) - .value_parser([PossibleValue::new("early"), PossibleValue::new("late")]) + .value_parser(["early", "late"]) .conflicts_with("type") .required_unless_present("type"), Arg::new("name") .short('n') .long("name") .help("Name of the new lint in snake case, ex: fn_too_long") - .takes_value(true) .required(true), Arg::new("category") .short('c') @@ -172,25 +187,23 @@ fn get_clap_config() -> ArgMatches { .help("What category the lint belongs to") .default_value("nursery") .value_parser([ - PossibleValue::new("style"), - PossibleValue::new("correctness"), - PossibleValue::new("suspicious"), - PossibleValue::new("complexity"), - PossibleValue::new("perf"), - PossibleValue::new("pedantic"), - PossibleValue::new("restriction"), - PossibleValue::new("cargo"), - PossibleValue::new("nursery"), - PossibleValue::new("internal"), - PossibleValue::new("internal_warn"), - ]) - .takes_value(true), - Arg::new("type") - .long("type") - .help("What directory the lint belongs in") - .takes_value(true) - .required(false), - Arg::new("msrv").long("msrv").help("Add MSRV config code to the lint"), + "style", + "correctness", + "suspicious", + "complexity", + "perf", + "pedantic", + "restriction", + "cargo", + "nursery", + "internal", + "internal_warn", + ]), + Arg::new("type").long("type").help("What directory the lint belongs in"), + Arg::new("msrv") + .long("msrv") + .action(ArgAction::SetTrue) + .help("Add MSRV config code to the lint"), ]), Command::new("setup") .about("Support for setting up your personal development environment") @@ -201,13 +214,12 @@ fn get_clap_config() -> ArgMatches { .args([ Arg::new("remove") .long("remove") - .help("Remove the dependencies added with 'cargo dev setup intellij'") - .required(false), + .action(ArgAction::SetTrue) + .help("Remove the dependencies added with 'cargo dev setup intellij'"), Arg::new("rustc-repo-path") .long("repo-path") .short('r') .help("The path to a rustc repo that will be used for setting the dependencies") - .takes_value(true) .value_name("path") .conflicts_with("remove") .required(true), @@ -217,26 +229,26 @@ fn get_clap_config() -> ArgMatches { .args([ Arg::new("remove") .long("remove") - .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'") - .required(false), + .action(ArgAction::SetTrue) + .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), Arg::new("force-override") .long("force-override") .short('f') - .help("Forces the override of an existing git pre-commit hook") - .required(false), + .action(ArgAction::SetTrue) + .help("Forces the override of an existing git pre-commit hook"), ]), Command::new("vscode-tasks") .about("Add several tasks to vscode for formatting, validation and testing") .args([ Arg::new("remove") .long("remove") - .help("Remove the tasks added with 'cargo dev setup vscode-tasks'") - .required(false), + .action(ArgAction::SetTrue) + .help("Remove the tasks added with 'cargo dev setup vscode-tasks'"), Arg::new("force-override") .long("force-override") .short('f') - .help("Forces the override of existing vscode tasks") - .required(false), + .action(ArgAction::SetTrue) + .help("Forces the override of existing vscode tasks"), ]), ]), Command::new("remove") @@ -295,6 +307,7 @@ fn get_clap_config() -> ArgMatches { .help("The new name of the lint"), Arg::new("uplift") .long("uplift") + .action(ArgAction::SetTrue) .help("This lint will be uplifted into rustc"), ]), Command::new("deprecate").about("Deprecates the given lint").args([ @@ -305,8 +318,6 @@ fn get_clap_config() -> ArgMatches { Arg::new("reason") .long("reason") .short('r') - .required(false) - .takes_value(true) .help("The reason for deprecation"), ]), ]) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 4c40483e3ec94..796f1ff169518 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["clippy", "lint", "plugin"] edition = "2021" [dependencies] -cargo_metadata = "0.14" +cargo_metadata = "0.15.3" clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } if_chain = "1.0" diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 556fa579000c6..1d9096ea64d1c 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_copy}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -34,14 +35,16 @@ declare_clippy_lint! { declare_lint_pass!(BoolAssertComparison => [BOOL_ASSERT_COMPARISON]); -fn is_bool_lit(e: &Expr<'_>) -> bool { - matches!( - e.kind, - ExprKind::Lit(Lit { - node: LitKind::Bool(_), - .. - }) - ) && !e.span.from_expansion() +fn extract_bool_lit(e: &Expr<'_>) -> Option { + if let ExprKind::Lit(Lit { + node: LitKind::Bool(b), .. + }) = e.kind + && !e.span.from_expansion() + { + Some(b) + } else { + None + } } fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { @@ -69,24 +72,23 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; let macro_name = cx.tcx.item_name(macro_call.def_id); - if !matches!( - macro_name.as_str(), - "assert_eq" | "debug_assert_eq" | "assert_ne" | "debug_assert_ne" - ) { - return; - } + let eq_macro = match macro_name.as_str() { + "assert_eq" | "debug_assert_eq" => true, + "assert_ne" | "debug_assert_ne" => false, + _ => return, + }; let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return }; let a_span = a.span.source_callsite(); let b_span = b.span.source_callsite(); - let (lit_span, non_lit_expr) = match (is_bool_lit(a), is_bool_lit(b)) { - // assert_eq!(true, b) - // ^^^^^^ - (true, false) => (a_span.until(b_span), b), - // assert_eq!(a, true) - // ^^^^^^ - (false, true) => (b_span.with_lo(a_span.hi()), a), + let (lit_span, bool_value, non_lit_expr) = match (extract_bool_lit(a), extract_bool_lit(b)) { + // assert_eq!(true/false, b) + // ^^^^^^^^^^^^ + (Some(bool_value), None) => (a_span.until(b_span), bool_value, b), + // assert_eq!(a, true/false) + // ^^^^^^^^^^^^ + (None, Some(bool_value)) => (b_span.with_lo(a_span.hi()), bool_value, a), // If there are two boolean arguments, we definitely don't understand // what's going on, so better leave things as is... // @@ -121,9 +123,16 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { // ^^^^^^^^^ let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); + let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())]; + + if bool_value ^ eq_macro { + let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else { return }; + suggestions.push((non_lit_expr.span, (!sugg).to_string())); + } + diag.multipart_suggestion( format!("replace it with `{non_eq_mac}!(..)`"), - vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())], + suggestions, Applicability::MachineApplicable, ); }, diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 36a366fc97474..457a25826e799 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -156,6 +156,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO, crate::exit::EXIT_INFO, crate::explicit_write::EXPLICIT_WRITE_INFO, + crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO, crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO, crate::float_literal::EXCESSIVE_PRECISION_INFO, crate::float_literal::LOSSY_FLOAT_LITERAL_INFO, diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 9d089fcad70e6..aef2db38583ee 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -4,8 +4,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; +use rustc_span::Span; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs new file mode 100644 index 0000000000000..2fdd8a71466c0 --- /dev/null +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -0,0 +1,178 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::trait_ref_of_method; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::MultiSpan; +use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; +use rustc_hir::{ + GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate, +}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::nested_filter; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{def_id::DefId, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for type parameters in generics that are never used anywhere else. + /// + /// ### Why is this bad? + /// Functions cannot infer the value of unused type parameters; therefore, calling them + /// requires using a turbofish, which serves no purpose but to satisfy the compiler. + /// + /// ### Example + /// ```rust + /// // unused type parameters + /// fn unused_ty(x: u8) { + /// // .. + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn no_unused_ty(x: u8) { + /// // .. + /// } + /// ``` + #[clippy::version = "1.69.0"] + pub EXTRA_UNUSED_TYPE_PARAMETERS, + complexity, + "unused type parameters in function definitions" +} +declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]); + +/// A visitor struct that walks a given function and gathers generic type parameters, plus any +/// trait bounds those parameters have. +struct TypeWalker<'cx, 'tcx> { + cx: &'cx LateContext<'tcx>, + /// Collection of all the type parameters and their spans. + ty_params: FxHashMap, + /// Collection of any (inline) trait bounds corresponding to each type parameter. + bounds: FxHashMap, + /// The entire `Generics` object of the function, useful for querying purposes. + generics: &'tcx Generics<'tcx>, + /// The value of this will remain `true` if *every* parameter: + /// 1. Is a type parameter, and + /// 2. Goes unused in the function. + /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic + /// parameters are present, this will be set to `false`. + all_params_unused: bool, +} + +impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { + fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self { + let mut all_params_unused = true; + let ty_params = generics + .params + .iter() + .filter_map(|param| { + if let GenericParamKind::Type { .. } = param.kind { + Some((param.def_id.into(), param.span)) + } else { + if !param.is_elided_lifetime() { + all_params_unused = false; + } + None + } + }) + .collect(); + Self { + cx, + ty_params, + bounds: FxHashMap::default(), + generics, + all_params_unused, + } + } + + fn emit_lint(&self) { + let (msg, help) = match self.ty_params.len() { + 0 => return, + 1 => ( + "type parameter goes unused in function definition", + "consider removing the parameter", + ), + _ => ( + "type parameters go unused in function definition", + "consider removing the parameters", + ), + }; + + let source_map = self.cx.tcx.sess.source_map(); + let span = if self.all_params_unused { + self.generics.span.into() // Remove the entire list of generics + } else { + MultiSpan::from_spans( + self.ty_params + .iter() + .map(|(def_id, &span)| { + // Extend the span past any trait bounds, and include the comma at the end. + let span_to_extend = self.bounds.get(def_id).copied().map_or(span, Span::shrink_to_hi); + let comma_range = source_map.span_extend_to_next_char(span_to_extend, '>', false); + let comma_span = source_map.span_through_char(comma_range, ','); + span.with_hi(comma_span.hi()) + }) + .collect(), + ) + }; + + span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, span, msg, None, help); + } +} + +impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + + fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { + if let Some((def_id, _)) = t.peel_refs().as_generic_param() { + if self.ty_params.remove(&def_id).is_some() { + self.all_params_unused = false; + } + } else if let TyKind::OpaqueDef(id, _, _) = t.kind { + // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls + // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're + // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked. + let item = self.nested_visit_map().item(id); + walk_item(self, item); + } else { + walk_ty(self, t); + } + } + + fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { + if let WherePredicate::BoundPredicate(predicate) = predicate { + // Collect spans for bounds that appear in the list of generics (not in a where-clause) + // for use in forming the help message + if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() + && let PredicateOrigin::GenericParam = predicate.origin + { + self.bounds.insert(def_id, predicate.span); + } + // Only walk the right-hand side of where-bounds + for bound in predicate.bounds { + walk_param_bound(self, bound); + } + } + } + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } +} + +impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Fn(_, generics, _) = item.kind { + let mut walker = TypeWalker::new(cx, generics); + walk_item(&mut walker, item); + walker.emit_lint(); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { + // Only lint on inherent methods, not trait methods. + if let ImplItemKind::Fn(..) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { + let mut walker = TypeWalker::new(cx, item.generics); + walk_impl_item(&mut walker, item); + walker.emit_lint(); + } + } +} diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index d376ad3bfe399..ea26b96ee0740 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -125,7 +125,7 @@ declare_clippy_lint! { /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`. #[clippy::version = "1.66.0"] pub UNINLINED_FORMAT_ARGS, - style, + pedantic, "using non-inlined variables in `format!` calls" } diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index d6b50537c2e1d..8b53ee68ebdfb 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -10,13 +10,7 @@ use std::iter; use super::MISNAMED_GETTERS; -pub fn check_fn( - cx: &LateContext<'_>, - kind: FnKind<'_>, - decl: &FnDecl<'_>, - body: &Body<'_>, - span: Span, -) { +pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: &Body<'_>, span: Span) { let FnKind::Method(ref ident, sig) = kind else { return; }; diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index a13909a2cdb8f..f2aa7b597a79b 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -25,7 +25,7 @@ pub(super) fn check_fn<'tcx>( intravisit::FnKind::Closure => return, }; - check_raw_ptr(cx, unsafety, decl, body, def_id) + check_raw_ptr(cx, unsafety, decl, body, def_id); } pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 7557a9ce13f11..c924d7361ce3b 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -66,7 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) { if sig.decl.implicit_self.has_implicit_self() { - let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output()); + let ret_ty = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output()); let ret_ty = cx .tcx .try_normalize_erasing_regions(cx.param_env, ret_ty) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 80ed2862a419a..e13bc47973b10 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -135,6 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if item.ident.name == sym::len; if let ImplItemKind::Fn(sig, _) = &item.kind; if sig.decl.implicit_self.has_implicit_self(); + if sig.decl.inputs.len() == 1; if cx.effective_visibilities.is_exported(item.owner_id.def_id); if matches!(sig.decl.output, FnRetTy::Return(_)); if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()); @@ -196,7 +197,15 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool { item.ident.name == name && if let AssocItemKind::Fn { has_self } = item.kind { - has_self && { cx.tcx.fn_sig(item.id.owner_id).skip_binder().inputs().skip_binder().len() == 1 } + has_self && { + cx.tcx + .fn_sig(item.id.owner_id) + .skip_binder() + .inputs() + .skip_binder() + .len() + == 1 + } } else { false } @@ -342,7 +351,11 @@ fn check_for_is_empty<'tcx>( ), Some(is_empty) if !(is_empty.fn_has_self_parameter - && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(), self_kind, output)) => + && check_is_empty_sig( + cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(), + self_kind, + output, + )) => { ( format!( diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d06830397761b..565c5b7af0068 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -121,6 +121,7 @@ mod excessive_bools; mod exhaustive_items; mod exit; mod explicit_write; +mod extra_unused_type_parameters; mod fallible_impl_from; mod float_literal; mod floating_point_arithmetic; @@ -909,6 +910,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef)); store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock)); + store.register_late_pass(|_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 747a94ba5a6ed..43a1a65a43a9d 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,20 +1,21 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::trait_ref_of_method; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::Applicability; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - walk_fn_decl, walk_generic_arg, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor, }; -use rustc_hir::lang_items; use rustc_hir::FnRetTy::Return; use rustc_hir::{ - BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem, - ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, PolyTraitRef, PredicateOrigin, TraitFn, - TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, + lang_items, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, + Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, + PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, }; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter as middle_nested_filter; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -33,8 +34,6 @@ declare_clippy_lint! { /// ### Known problems /// - We bail out if the function has a `where` clause where lifetimes /// are mentioned due to potential false positives. - /// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the - /// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`. /// /// ### Example /// ```rust @@ -92,7 +91,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Fn(ref sig, generics, id) = item.kind { - check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true); + check_fn_inner(cx, sig, Some(id), None, generics, item.span, true); } else if let ItemKind::Impl(impl_) = item.kind { if !item.span.from_expansion() { report_extra_impl_lifetimes(cx, impl_); @@ -105,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none(); check_fn_inner( cx, - sig.decl, + sig, Some(id), None, item.generics, @@ -121,29 +120,21 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { TraitFn::Required(sig) => (None, Some(sig)), TraitFn::Provided(id) => (Some(id), None), }; - check_fn_inner(cx, sig.decl, body, trait_sig, item.generics, item.span, true); + check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true); } } } -/// The lifetime of a &-reference. -#[derive(PartialEq, Eq, Hash, Debug, Clone)] -enum RefLt { - Unnamed, - Static, - Named(LocalDefId), -} - fn check_fn_inner<'tcx>( cx: &LateContext<'tcx>, - decl: &'tcx FnDecl<'_>, + sig: &'tcx FnSig<'_>, body: Option, trait_sig: Option<&[Ident]>, generics: &'tcx Generics<'_>, span: Span, report_extra_lifetimes: bool, ) { - if span.from_expansion() || has_where_lifetimes(cx, generics) { + if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, generics) { return; } @@ -162,7 +153,7 @@ fn check_fn_inner<'tcx>( for bound in pred.bounds { let mut visitor = RefVisitor::new(cx); walk_param_bound(&mut visitor, bound); - if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) { + if visitor.lts.iter().any(|lt| matches!(lt.res, LifetimeName::Param(_))) { return; } if let GenericBound::Trait(ref trait_ref, _) = *bound { @@ -189,12 +180,12 @@ fn check_fn_inner<'tcx>( } } - if let Some(elidable_lts) = could_use_elision(cx, decl, body, trait_sig, generics.params) { + if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) { let lts = elidable_lts .iter() // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a // `Node::GenericParam`. - .filter_map(|&(def_id, _)| cx.tcx.hir().get_by_def_id(def_id).ident()) + .filter_map(|&def_id| cx.tcx.hir().get_by_def_id(def_id).ident()) .map(|ident| ident.to_string()) .collect::>() .join(", "); @@ -202,21 +193,99 @@ fn check_fn_inner<'tcx>( span_lint_and_then( cx, NEEDLESS_LIFETIMES, - span.with_hi(decl.output.span().hi()), + span.with_hi(sig.decl.output.span().hi()), &format!("the following explicit lifetimes could be elided: {lts}"), |diag| { - if let Some(span) = elidable_lts.iter().find_map(|&(_, span)| span) { - diag.span_help(span, "replace with `'_` in generic arguments such as here"); + if sig.header.is_async() { + // async functions have usages whose spans point at the lifetime declaration which messes up + // suggestions + return; + }; + + if let Some(suggestions) = elision_suggestions(cx, generics, &elidable_lts, &usages) { + diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); } }, ); } if report_extra_lifetimes { - self::report_extra_lifetimes(cx, decl, generics); + self::report_extra_lifetimes(cx, sig.decl, generics); } } +fn elision_suggestions( + cx: &LateContext<'_>, + generics: &Generics<'_>, + elidable_lts: &[LocalDefId], + usages: &[Lifetime], +) -> Option> { + let explicit_params = generics + .params + .iter() + .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait()) + .collect::>(); + + let mut suggestions = if elidable_lts.len() == explicit_params.len() { + // if all the params are elided remove the whole generic block + // + // fn x<'a>() {} + // ^^^^ + vec![(generics.span, String::new())] + } else { + elidable_lts + .iter() + .map(|&id| { + let pos = explicit_params.iter().position(|param| param.def_id == id)?; + let param = explicit_params.get(pos)?; + + let span = if let Some(next) = explicit_params.get(pos + 1) { + // fn x<'prev, 'a, 'next>() {} + // ^^^^ + param.span.until(next.span) + } else { + // `pos` should be at least 1 here, because the param in position 0 would either have a `next` + // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch. + let prev = explicit_params.get(pos - 1)?; + + // fn x<'prev, 'a>() {} + // ^^^^ + param.span.with_lo(prev.span.hi()) + }; + + Some((span, String::new())) + }) + .collect::>>()? + }; + + suggestions.extend( + usages + .iter() + .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id))) + .map(|usage| { + match cx.tcx.hir().get_parent(usage.hir_id) { + Node::Ty(Ty { + kind: TyKind::Ref(..), .. + }) => { + // expand `&'a T` to `&'a T` + // ^^ ^^^ + let span = cx + .sess() + .source_map() + .span_extend_while(usage.ident.span, |ch| ch.is_ascii_whitespace()) + .unwrap_or(usage.ident.span); + + (span, String::new()) + }, + // `T<'a>` and `impl Foo + 'a` should be replaced by `'_` + _ => (usage.ident.span, String::from("'_")), + } + }), + ); + + Some(suggestions) +} + // elision doesn't work for explicit self types, see rust-lang/rust#69064 fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option) -> bool { if_chain! { @@ -236,13 +305,20 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: } } +fn named_lifetime(lt: &Lifetime) -> Option { + match lt.res { + LifetimeName::Param(id) if !lt.is_anonymous() => Some(id), + _ => None, + } +} + fn could_use_elision<'tcx>( cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, body: Option, trait_sig: Option<&[Ident]>, named_generics: &'tcx [GenericParam<'_>], -) -> Option)>> { +) -> Option<(Vec, Vec)> { // There are two scenarios where elision works: // * no output references, all input references have different LT // * output references, exactly one input reference with same LT @@ -300,32 +376,24 @@ fn could_use_elision<'tcx>( // check for lifetimes from higher scopes for lt in input_lts.iter().chain(output_lts.iter()) { - if !allowed_lts.contains(lt) { + if let Some(id) = named_lifetime(lt) + && !allowed_lts.contains(&id) + { return None; } } // check for higher-ranked trait bounds if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() { - let allowed_lts: FxHashSet<_> = allowed_lts - .iter() - .filter_map(|lt| match lt { - RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())), - _ => None, - }) - .collect(); + let allowed_lts: FxHashSet<_> = allowed_lts.iter().map(|id| cx.tcx.item_name(id.to_def_id())).collect(); for lt in input_visitor.nested_elision_site_lts { - if let RefLt::Named(def_id) = lt { - if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) { - return None; - } + if allowed_lts.contains(<.ident.name) { + return None; } } for lt in output_visitor.nested_elision_site_lts { - if let RefLt::Named(def_id) = lt { - if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) { - return None; - } + if allowed_lts.contains(<.ident.name) { + return None; } } } @@ -337,15 +405,10 @@ fn could_use_elision<'tcx>( let elidable_lts = named_lifetime_occurrences(&input_lts) .into_iter() .filter_map(|(def_id, occurrences)| { - if occurrences == 1 && (input_lts.len() == 1 || !output_lts.contains(&RefLt::Named(def_id))) { - Some(( - def_id, - input_visitor - .lifetime_generic_arg_spans - .get(&def_id) - .or_else(|| output_visitor.lifetime_generic_arg_spans.get(&def_id)) - .copied(), - )) + if occurrences == 1 + && (input_lts.len() == 1 || !output_lts.iter().any(|lt| named_lifetime(lt) == Some(def_id))) + { + Some(def_id) } else { None } @@ -353,31 +416,34 @@ fn could_use_elision<'tcx>( .collect::>(); if elidable_lts.is_empty() { - None - } else { - Some(elidable_lts) + return None; } + + let usages = itertools::chain(input_lts, output_lts).collect(); + + Some((elidable_lts, usages)) } -fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet { - let mut allowed_lts = FxHashSet::default(); - for par in named_generics.iter() { - if let GenericParamKind::Lifetime { .. } = par.kind { - allowed_lts.insert(RefLt::Named(par.def_id)); - } - } - allowed_lts.insert(RefLt::Unnamed); - allowed_lts.insert(RefLt::Static); - allowed_lts +fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet { + named_generics + .iter() + .filter_map(|par| { + if let GenericParamKind::Lifetime { .. } = par.kind { + Some(par.def_id) + } else { + None + } + }) + .collect() } /// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve /// relative order. #[must_use] -fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> { +fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> { let mut occurrences = Vec::new(); for lt in lts { - if let &RefLt::Named(curr_def_id) = lt { + if let Some(curr_def_id) = named_lifetime(lt) { if let Some(pair) = occurrences .iter_mut() .find(|(prev_def_id, _)| *prev_def_id == curr_def_id) @@ -391,12 +457,10 @@ fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> { occurrences } -/// A visitor usable for `rustc_front::visit::walk_ty()`. struct RefVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - lts: Vec, - lifetime_generic_arg_spans: FxHashMap, - nested_elision_site_lts: Vec, + lts: Vec, + nested_elision_site_lts: Vec, unelided_trait_object_lifetime: bool, } @@ -405,32 +469,16 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { Self { cx, lts: Vec::new(), - lifetime_generic_arg_spans: FxHashMap::default(), nested_elision_site_lts: Vec::new(), unelided_trait_object_lifetime: false, } } - fn record(&mut self, lifetime: &Option) { - if let Some(ref lt) = *lifetime { - if lt.is_static() { - self.lts.push(RefLt::Static); - } else if lt.is_anonymous() { - // Fresh lifetimes generated should be ignored. - self.lts.push(RefLt::Unnamed); - } else if let LifetimeName::Param(def_id) = lt.res { - self.lts.push(RefLt::Named(def_id)); - } - } else { - self.lts.push(RefLt::Unnamed); - } - } - - fn all_lts(&self) -> Vec { + fn all_lts(&self) -> Vec { self.lts .iter() .chain(self.nested_elision_site_lts.iter()) - .cloned() + .copied() .collect::>() } @@ -442,7 +490,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - self.record(&Some(*lifetime)); + self.lts.push(*lifetime); } fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) { @@ -467,11 +515,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { walk_item(self, item); self.lts.truncate(len); self.lts.extend(bounds.iter().filter_map(|bound| match bound { - GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id) = l.res { - RefLt::Named(def_id) - } else { - RefLt::Unnamed - }), + GenericArg::Lifetime(&l) => Some(l), _ => None, })); }, @@ -491,13 +535,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { _ => walk_ty(self, ty), } } - - fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) { - if let GenericArg::Lifetime(l) = generic_arg && let LifetimeName::Param(def_id) = l.res { - self.lifetime_generic_arg_spans.entry(def_id).or_insert(l.ident.span); - } - walk_generic_arg(self, generic_arg); - } } /// Are any lifetimes mentioned in the `where` clause? If so, we don't try to @@ -521,8 +558,12 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ walk_param_bound(&mut visitor, bound); } // and check that all lifetimes are allowed - if visitor.all_lts().iter().any(|it| !allowed_lts.contains(it)) { - return true; + for lt in visitor.all_lts() { + if let Some(id) = named_lifetime(<) + && !allowed_lts.contains(&id) + { + return true; + } } }, WherePredicate::EqPredicate(ref pred) => { diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 8e52cac4323c3..610a0233eee15 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -61,7 +61,8 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// Just iterating the collection itself makes the intent - /// more clear and is probably faster. + /// more clear and is probably faster because it eliminates + /// the bounds check that is done when indexing. /// /// ### Example /// ```rust diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index e6ed4ea7a5db5..25a1a5842f77b 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -149,7 +149,7 @@ pub(super) fn check<'tcx>( |diag| { multispan_sugg( diag, - "consider using an iterator", + "consider using an iterator and enumerate()", vec![ (pat.span, format!("({}, )", ident.name)), ( diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 4277455a3a21c..ce5d657bcf0e3 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -1,7 +1,6 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::{root_macro_call, FormatArgsExpn}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::macros::root_macro_call; use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; @@ -38,57 +37,57 @@ declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]); impl<'tcx> LateLintPass<'tcx> for ManualAssert { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if_chain! { - if let ExprKind::If(cond, then, None) = expr.kind; - if !matches!(cond.kind, ExprKind::Let(_)); - if !expr.span.from_expansion(); - let then = peel_blocks_with_stmt(then); - if let Some(macro_call) = root_macro_call(then.span); - if cx.tcx.item_name(macro_call.def_id) == sym::panic; - if !cx.tcx.sess.source_map().is_multiline(cond.span); - if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn); + if let ExprKind::If(cond, then, None) = expr.kind + && !matches!(cond.kind, ExprKind::Let(_)) + && !expr.span.from_expansion() + && let then = peel_blocks_with_stmt(then) + && let Some(macro_call) = root_macro_call(then.span) + && cx.tcx.item_name(macro_call.def_id) == sym::panic + && !cx.tcx.sess.source_map().is_multiline(cond.span) + && let Ok(panic_snippet) = cx.sess().source_map().span_to_snippet(macro_call.span) + && let Some(panic_snippet) = panic_snippet.strip_suffix(')') + && let Some((_, format_args_snip)) = panic_snippet.split_once('(') // Don't change `else if foo { panic!(..) }` to `else { assert!(foo, ..) }` as it just // shuffles the condition around. // Should this have a config value? - if !is_else_clause(cx.tcx, expr); - then { - let mut applicability = Applicability::MachineApplicable; - let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability); - let cond = cond.peel_drop_temps(); - let mut comments = span_extract_comment(cx.sess().source_map(), expr.span); - if !comments.is_empty() { - comments += "\n"; - } - let (cond, not) = match cond.kind { - ExprKind::Unary(UnOp::Not, e) => (e, ""), - _ => (cond, "!"), - }; - let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); - let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); - // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block - span_lint_and_then( - cx, - MANUAL_ASSERT, - expr.span, - "only a `panic!` in `if`-then statement", - |diag| { - // comments can be noisy, do not show them to the user - if !comments.is_empty() { - diag.tool_only_span_suggestion( - expr.span.shrink_to_lo(), - "add comments back", - comments, - applicability); - } - diag.span_suggestion( - expr.span, - "try instead", - sugg, - applicability); - } - - ); + && !is_else_clause(cx.tcx, expr) + { + let mut applicability = Applicability::MachineApplicable; + let cond = cond.peel_drop_temps(); + let mut comments = span_extract_comment(cx.sess().source_map(), expr.span); + if !comments.is_empty() { + comments += "\n"; } + let (cond, not) = match cond.kind { + ExprKind::Unary(UnOp::Not, e) => (e, ""), + _ => (cond, "!"), + }; + let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); + let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); + // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block + span_lint_and_then( + cx, + MANUAL_ASSERT, + expr.span, + "only a `panic!` in `if`-then statement", + |diag| { + // comments can be noisy, do not show them to the user + if !comments.is_empty() { + diag.tool_only_span_suggestion( + expr.span.shrink_to_lo(), + "add comments back", + comments, + applicability + ); + } + diag.span_suggestion( + expr.span, + "try instead", + sugg, + applicability + ); + } + ); } } } diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index 59de8c0384ba0..3126b590180e6 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -45,8 +45,13 @@ 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 is_external = adt_def.did().as_local().is_none(); + let has_external_hidden = is_external && adt_def.variants().iter().any(|x| is_hidden(cx, x)); + let mut missing_variants: Vec<_> = adt_def + .variants() + .iter() + .filter(|x| !(is_external && is_hidden(cx, x))) + .collect(); let mut path_prefix = CommonPrefixSearcher::None; for arm in arms { @@ -133,7 +138,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { match missing_variants.as_slice() { [] => (), - [x] if !adt_def.is_variant_list_non_exhaustive() && !has_hidden => span_lint_and_sugg( + [x] if !adt_def.is_variant_list_non_exhaustive() && !has_external_hidden => span_lint_and_sugg( cx, MATCH_WILDCARD_FOR_SINGLE_VARIANTS, wildcard_span, @@ -144,7 +149,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { ), variants => { let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect(); - let message = if adt_def.is_variant_list_non_exhaustive() || has_hidden { + let message = if adt_def.is_variant_list_non_exhaustive() || has_external_hidden { suggestions.push("_".into()); "wildcard matches known variants and will also match future added variants" } else { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fb94dfa5980b7..f1e8be7f2b87f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1818,6 +1818,7 @@ declare_clippy_lint! { /// - `or_else` to `or` /// - `get_or_insert_with` to `get_or_insert` /// - `ok_or_else` to `ok_or` + /// - `then` to `then_some` (for msrv >= 1.62.0) /// /// ### Why is this bad? /// Using eager evaluation is shorter and simpler in some cases. diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index fe88fa41fd91e..e818f1892e510 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_diag_trait_item; use clippy_utils::source::snippet_with_context; use if_chain::if_chain; @@ -17,19 +17,31 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - let input_type = cx.typeck_results().expr_ty(expr); if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind(); if cx.tcx.is_diagnostic_item(sym::Cow, adt.did()); + then { let mut app = Applicability::MaybeIncorrect; let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; - span_lint_and_sugg( + span_lint_and_then( cx, SUSPICIOUS_TO_OWNED, expr.span, &with_forced_trimmed_paths!(format!( "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" )), - "consider using, depending on intent", - format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"), - app, + |diag| { + diag.span_suggestion( + expr.span, + "depending on intent, either make the Cow an Owned variant", + format!("{recv_snip}.into_owned()"), + app + ); + diag.span_suggestion( + expr.span, + "or clone the Cow itself", + format!("{recv_snip}.clone()"), + app + ); + } ); return true; } diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 2814c92e67a45..63c575fca30ba 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -10,6 +10,7 @@ use hir::{ use rustc_ast::Mutability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; @@ -66,7 +67,7 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]) impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) { + if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || in_external_macro(cx.tcx.sess, block.span) { return; } let mut unsafe_ops = vec![]; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 472f52380bbf4..c5ea09590d3df 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -25,11 +25,11 @@ declare_clippy_lint! { /// Using the dedicated functions of the `Option` type is clearer and /// more concise than an `if let` expression. /// - /// ### Known problems - /// This lint uses a deliberately conservative metric for checking - /// if the inside of either body contains breaks or continues which will - /// cause it to not suggest a fix if either block contains a loop with - /// continues or breaks contained within the loop. + /// ### Notes + /// This lint uses a deliberately conservative metric for checking if the + /// inside of either body contains loop control expressions `break` or + /// `continue` (which cannot be used within closures). If these are found, + /// this lint will not be raised. /// /// ### Example /// ```rust diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 8afe286fbd5dc..d88409c356e91 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -624,7 +624,10 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: return; }; - match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i].peel_refs().kind() { + match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i] + .peel_refs() + .kind() + { ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => { set_skip_flag(); }, diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 1fda58fa54de1..9e6c6c73d4fe7 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,5 +1,8 @@ +use std::fmt::Display; + use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::source::snippet_opt; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::{LitKind, StrStyle}; @@ -77,13 +80,45 @@ impl<'tcx> LateLintPass<'tcx> for Regex { } } -#[must_use] -fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u8) -> Span { - let offset = u32::from(offset); - let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset); - let start = base.lo() + BytePos(u32::try_from(c.start.offset).expect("offset too large") + offset); - assert!(start <= end); - Span::new(start, end, base.ctxt(), base.parent()) +fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescaped: &str, base: Span, offset: u8) { + let parts: Option<(_, _, &dyn Display)> = match &error { + regex_syntax::Error::Parse(e) => Some((e.span(), e.auxiliary_span(), e.kind())), + regex_syntax::Error::Translate(e) => Some((e.span(), None, e.kind())), + _ => None, + }; + + let convert_span = |regex_span: ®ex_syntax::ast::Span| { + let offset = u32::from(offset); + let start = base.lo() + BytePos(u32::try_from(regex_span.start.offset).expect("offset too large") + offset); + let end = base.lo() + BytePos(u32::try_from(regex_span.end.offset).expect("offset too large") + offset); + + Span::new(start, end, base.ctxt(), base.parent()) + }; + + if let Some((primary, auxiliary, kind)) = parts + && let Some(literal_snippet) = snippet_opt(cx, base) + && let Some(inner) = literal_snippet.get(offset as usize..) + // Only convert to native rustc spans if the parsed regex matches the + // source snippet exactly, to ensure the span offsets are correct + && inner.get(..unescaped.len()) == Some(unescaped) + { + let spans = if let Some(auxiliary) = auxiliary { + vec![convert_span(primary), convert_span(auxiliary)] + } else { + vec![convert_span(primary)] + }; + + span_lint(cx, INVALID_REGEX, spans, &format!("regex syntax error: {kind}")); + } else { + span_lint_and_help( + cx, + INVALID_REGEX, + base, + &error.to_string(), + None, + "consider using a raw string literal: `r\"..\"`", + ); + } } fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option { @@ -155,25 +190,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl); } }, - Err(regex_syntax::Error::Parse(e)) => { - span_lint( - cx, - INVALID_REGEX, - str_span(expr.span, *e.span(), offset), - &format!("regex syntax error: {}", e.kind()), - ); - }, - Err(regex_syntax::Error::Translate(e)) => { - span_lint( - cx, - INVALID_REGEX, - str_span(expr.span, *e.span(), offset), - &format!("regex syntax error: {}", e.kind()), - ); - }, - Err(e) => { - span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}")); - }, + Err(e) => lint_syntax_error(cx, &e, r, expr.span, offset), } } } else if let Some(r) = const_str(cx, expr) { @@ -183,25 +200,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl); } }, - Err(regex_syntax::Error::Parse(e)) => { - span_lint( - cx, - INVALID_REGEX, - expr.span, - &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()), - ); - }, - Err(regex_syntax::Error::Translate(e)) => { - span_lint( - cx, - INVALID_REGEX, - expr.span, - &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()), - ); - }, - Err(e) => { - span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}")); - }, + Err(e) => span_lint(cx, INVALID_REGEX, expr.span, &e.to_string()), } } } diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 8c39b4fc5691b..bccf421e8f3bf 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -78,8 +78,8 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa // We don't want to emit this lint if the `#[must_use]` attribute is already there. if !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use)); if cx.tcx.visibility(fn_def.to_def_id()).is_public(); - let ret_ty = return_ty(cx, owner_id.into()); - let self_arg = nth_arg(cx, owner_id.into(), 0); + let ret_ty = return_ty(cx, owner_id); + let self_arg = nth_arg(cx, owner_id, 0); // If `Self` has the same type as the returned type, then we want to warn. // // For this check, we don't want to remove the reference on the returned type because if diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 8f1d1490e1f08..34a3e5ddf4f6b 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// # let x = 0; /// unsafe { f(x); } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.68.0"] pub SEMICOLON_INSIDE_BLOCK, restriction, "add a semicolon inside the block" @@ -59,7 +59,7 @@ declare_clippy_lint! { /// # let x = 0; /// unsafe { f(x) }; /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.68.0"] pub SEMICOLON_OUTSIDE_BLOCK, restriction, "add a semicolon outside the block" diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 585e2075fa904..c1f228d5f90a9 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -392,9 +392,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { - let is_exported = cx - .effective_visibilities - .is_exported(field.def_id); + let is_exported = cx.effective_visibilities.is_exported(field.def_id); self.check_ty( cx, diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 92053cec59fc8..0e526c216beea 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { } }, hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() { - "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { + "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" | "is_ok" | "is_err" => { check_map_error(cx, arg_0, expr); }, _ => (), diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index f48be27592b7e..1d78c7cfae0df 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -253,7 +253,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN. /// /// The minimum rust version that the project supports (msrv: Option = None), @@ -323,7 +323,7 @@ define_Conf! { /// /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. (trivial_copy_size_limit: Option = None), - /// Lint: LARGE_TYPE_PASS_BY_MOVE. + /// Lint: LARGE_TYPES_PASSED_BY_VALUE. /// /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. (pass_by_value_size_limit: u64 = 256), @@ -411,7 +411,7 @@ define_Conf! { /// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed. /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. (max_suggested_slice_pattern_length: u64 = 3), - /// Lint: AWAIT_HOLDING_INVALID_TYPE + /// Lint: AWAIT_HOLDING_INVALID_TYPE. (await_holding_invalid_types: Vec = Vec::new()), /// Lint: LARGE_INCLUDE_FILE. /// @@ -437,7 +437,7 @@ define_Conf! { /// /// The maximum size of the `Err`-variant in a `Result` returned from a function (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY. + /// Lint: MUTABLE_KEY_TYPE. /// /// A list of paths to types that should be treated like `Arc`, i.e. ignored but /// for the generic parameters for determining interior mutability @@ -446,7 +446,7 @@ define_Conf! { /// /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` (allow_mixed_uninlined_format_args: bool = true), - /// Lint: INDEXING_SLICING + /// Lint: INDEXING_SLICING. /// /// Whether to suppress a restriction lint in constant code. In same /// cases the restructured operation might not be unavoidable, as the diff --git a/clippy_lints/src/utils/dump_hir.rs b/clippy_lints/src/utils/dump_hir.rs index 01efc527a8c3a..092041aecf29c 100644 --- a/clippy_lints/src/utils/dump_hir.rs +++ b/clippy_lints/src/utils/dump_hir.rs @@ -1,4 +1,5 @@ use clippy_utils::get_attr; +use hir::TraitItem; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -47,6 +48,18 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir { println!("{stmt:#?}"); } } + + fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { + if has_attr(cx, item.hir_id()) { + println!("{item:#?}"); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &hir::ImplItem<'_>) { + if has_attr(cx, item.hir_id()) { + println!("{item:#?}"); + } + } } fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 4c3b1b131fd4c..f718207654f44 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -215,14 +215,13 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, }; let body_id = cx.tcx.hir().body_owned_by( - cx.tcx.hir().local_def_id( - impl_item_refs - .iter() - .find(|iiref| iiref.ident.as_str() == "get_lints") - .expect("LintPass needs to implement get_lints") - .id - .hir_id(), - ), + impl_item_refs + .iter() + .find(|iiref| iiref.ident.as_str() == "get_lints") + .expect("LintPass needs to implement get_lints") + .id + .owner_id + .def_id, ); collector.visit_expr(cx.tcx.hir().body(body_id).value); } diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index d7f466c197636..63dccbf697c2d 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -770,10 +770,7 @@ impl<'tcx> FormatSpec<'tcx> { /// Has no other formatting specifiers than setting the format trait. returns true for `{}`, /// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}` pub fn is_default_for_trait(&self) -> bool { - self.width.is_implied() - && self.precision.is_implied() - && self.align == Alignment::AlignUnknown - && self.no_flags + self.width.is_implied() && self.precision.is_implied() && self.align == Alignment::AlignUnknown && self.no_flags } } diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index b8c87aa5e1e42..78fb2e0eb7e68 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -809,7 +809,10 @@ pub struct DerefClosure { /// /// note: this only works on single line immutable closures with exactly one input parameter. pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option { - if let hir::ExprKind::Closure(&Closure { fn_decl, def_id, body, .. }) = closure.kind { + if let hir::ExprKind::Closure(&Closure { + fn_decl, def_id, body, .. + }) = closure.kind + { let closure_body = cx.tcx.hir().body(body); // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`) // a type annotation is present if param `kind` is different from `TyKind::Infer` diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index d18b62d1bf16a..00073bcd82aff 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -392,12 +392,16 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe) => + .map_or(false, |id| { + self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe + }) => { self.is_unsafe = true; }, ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() { - ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => self.is_unsafe = true, + ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => { + self.is_unsafe = true; + }, ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true, _ => walk_expr(self, e), }, diff --git a/lintcheck/Cargo.toml b/lintcheck/Cargo.toml index de31c16b819ef..653121af54dc3 100644 --- a/lintcheck/Cargo.toml +++ b/lintcheck/Cargo.toml @@ -10,8 +10,8 @@ edition = "2021" publish = false [dependencies] -cargo_metadata = "0.14" -clap = "3.2" +cargo_metadata = "0.15.3" +clap = "4.1.4" crossbeam-channel = "0.5.6" flate2 = "1.0" rayon = "1.5.1" diff --git a/rust-toolchain b/rust-toolchain index 4e7fc565a322a..adea8c53df278 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-01-27" +channel = "nightly-2023-02-10" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index 2a240cc249b0c..c1a10ba55ef88 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -1,19 +1,19 @@ error: hardcoded path to a diagnostic item - --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36 + --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 | -LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: convert all references to use `sym::Deref` + = help: convert all references to use `sym::deref_method` = note: `-D clippy::unnecessary-def-path` implied by `-D warnings` error: hardcoded path to a diagnostic item - --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 + --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36 | -LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: convert all references to use `sym::deref_method` + = help: convert all references to use `sym::Deref` error: hardcoded path to a language item --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40 diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 1e5f20e8c39ba..a13af56520389 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -149,3 +149,22 @@ macro_rules! almost_complete_range { let _ = '0'..'9'; }; } + +#[macro_export] +macro_rules! unsafe_macro { + () => { + unsafe { + *core::ptr::null::<()>(); + *core::ptr::null::<()>(); + } + }; +} + +#[macro_export] +macro_rules! needless_lifetime { + () => { + fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + }; +} diff --git a/tests/ui/bool_assert_comparison.fixed b/tests/ui/bool_assert_comparison.fixed index 95f35a61bb289..b8dd92906c8db 100644 --- a/tests/ui/bool_assert_comparison.fixed +++ b/tests/ui/bool_assert_comparison.fixed @@ -86,7 +86,7 @@ fn main() { let b = ImplNotTraitWithBool; assert_eq!("a".len(), 1); - assert!("a".is_empty()); + assert!(!"a".is_empty()); assert!("".is_empty()); assert!("".is_empty()); assert_eq!(a!(), b!()); @@ -97,16 +97,16 @@ fn main() { assert_ne!("a".len(), 1); assert!("a".is_empty()); - assert!("".is_empty()); - assert!("".is_empty()); + assert!(!"".is_empty()); + assert!(!"".is_empty()); assert_ne!(a!(), b!()); assert_ne!(a!(), "".is_empty()); assert_ne!("".is_empty(), b!()); assert_ne!(a, true); - assert!(b); + assert!(!b); debug_assert_eq!("a".len(), 1); - debug_assert!("a".is_empty()); + debug_assert!(!"a".is_empty()); debug_assert!("".is_empty()); debug_assert!("".is_empty()); debug_assert_eq!(a!(), b!()); @@ -117,27 +117,27 @@ fn main() { debug_assert_ne!("a".len(), 1); debug_assert!("a".is_empty()); - debug_assert!("".is_empty()); - debug_assert!("".is_empty()); + debug_assert!(!"".is_empty()); + debug_assert!(!"".is_empty()); debug_assert_ne!(a!(), b!()); debug_assert_ne!(a!(), "".is_empty()); debug_assert_ne!("".is_empty(), b!()); debug_assert_ne!(a, true); - debug_assert!(b); + debug_assert!(!b); // assert with error messages assert_eq!("a".len(), 1, "tadam {}", 1); assert_eq!("a".len(), 1, "tadam {}", true); - assert!("a".is_empty(), "tadam {}", 1); - assert!("a".is_empty(), "tadam {}", true); - assert!("a".is_empty(), "tadam {}", true); + assert!(!"a".is_empty(), "tadam {}", 1); + assert!(!"a".is_empty(), "tadam {}", true); + assert!(!"a".is_empty(), "tadam {}", true); assert_eq!(a, true, "tadam {}", false); debug_assert_eq!("a".len(), 1, "tadam {}", 1); debug_assert_eq!("a".len(), 1, "tadam {}", true); - debug_assert!("a".is_empty(), "tadam {}", 1); - debug_assert!("a".is_empty(), "tadam {}", true); - debug_assert!("a".is_empty(), "tadam {}", true); + debug_assert!(!"a".is_empty(), "tadam {}", 1); + debug_assert!(!"a".is_empty(), "tadam {}", true); + debug_assert!(!"a".is_empty(), "tadam {}", true); debug_assert_eq!(a, true, "tadam {}", false); assert!(a!()); @@ -158,4 +158,14 @@ fn main() { }}; } in_macro!(a); + + assert!("".is_empty()); + assert!("".is_empty()); + assert!(!"requires negation".is_empty()); + assert!(!"requires negation".is_empty()); + + debug_assert!("".is_empty()); + debug_assert!("".is_empty()); + debug_assert!(!"requires negation".is_empty()); + debug_assert!(!"requires negation".is_empty()); } diff --git a/tests/ui/bool_assert_comparison.rs b/tests/ui/bool_assert_comparison.rs index 88e7560b4f984..0a8ad34fda52a 100644 --- a/tests/ui/bool_assert_comparison.rs +++ b/tests/ui/bool_assert_comparison.rs @@ -158,4 +158,14 @@ fn main() { }}; } in_macro!(a); + + assert_eq!("".is_empty(), true); + assert_ne!("".is_empty(), false); + assert_ne!("requires negation".is_empty(), true); + assert_eq!("requires negation".is_empty(), false); + + debug_assert_eq!("".is_empty(), true); + debug_assert_ne!("".is_empty(), false); + debug_assert_ne!("requires negation".is_empty(), true); + debug_assert_eq!("requires negation".is_empty(), false); } diff --git a/tests/ui/bool_assert_comparison.stderr b/tests/ui/bool_assert_comparison.stderr index 3d9f8573e617c..89cefc95a9f69 100644 --- a/tests/ui/bool_assert_comparison.stderr +++ b/tests/ui/bool_assert_comparison.stderr @@ -8,7 +8,7 @@ LL | assert_eq!("a".is_empty(), false); help: replace it with `assert!(..)` | LL - assert_eq!("a".is_empty(), false); -LL + assert!("a".is_empty()); +LL + assert!(!"a".is_empty()); | error: used `assert_eq!` with a literal bool @@ -68,7 +68,7 @@ LL | assert_ne!("".is_empty(), true); help: replace it with `assert!(..)` | LL - assert_ne!("".is_empty(), true); -LL + assert!("".is_empty()); +LL + assert!(!"".is_empty()); | error: used `assert_ne!` with a literal bool @@ -80,7 +80,7 @@ LL | assert_ne!(true, "".is_empty()); help: replace it with `assert!(..)` | LL - assert_ne!(true, "".is_empty()); -LL + assert!("".is_empty()); +LL + assert!(!"".is_empty()); | error: used `assert_ne!` with a literal bool @@ -92,7 +92,7 @@ LL | assert_ne!(b, true); help: replace it with `assert!(..)` | LL - assert_ne!(b, true); -LL + assert!(b); +LL + assert!(!b); | error: used `debug_assert_eq!` with a literal bool @@ -104,7 +104,7 @@ LL | debug_assert_eq!("a".is_empty(), false); help: replace it with `debug_assert!(..)` | LL - debug_assert_eq!("a".is_empty(), false); -LL + debug_assert!("a".is_empty()); +LL + debug_assert!(!"a".is_empty()); | error: used `debug_assert_eq!` with a literal bool @@ -164,7 +164,7 @@ LL | debug_assert_ne!("".is_empty(), true); help: replace it with `debug_assert!(..)` | LL - debug_assert_ne!("".is_empty(), true); -LL + debug_assert!("".is_empty()); +LL + debug_assert!(!"".is_empty()); | error: used `debug_assert_ne!` with a literal bool @@ -176,7 +176,7 @@ LL | debug_assert_ne!(true, "".is_empty()); help: replace it with `debug_assert!(..)` | LL - debug_assert_ne!(true, "".is_empty()); -LL + debug_assert!("".is_empty()); +LL + debug_assert!(!"".is_empty()); | error: used `debug_assert_ne!` with a literal bool @@ -188,7 +188,7 @@ LL | debug_assert_ne!(b, true); help: replace it with `debug_assert!(..)` | LL - debug_assert_ne!(b, true); -LL + debug_assert!(b); +LL + debug_assert!(!b); | error: used `assert_eq!` with a literal bool @@ -200,7 +200,7 @@ LL | assert_eq!("a".is_empty(), false, "tadam {}", 1); help: replace it with `assert!(..)` | LL - assert_eq!("a".is_empty(), false, "tadam {}", 1); -LL + assert!("a".is_empty(), "tadam {}", 1); +LL + assert!(!"a".is_empty(), "tadam {}", 1); | error: used `assert_eq!` with a literal bool @@ -212,7 +212,7 @@ LL | assert_eq!("a".is_empty(), false, "tadam {}", true); help: replace it with `assert!(..)` | LL - assert_eq!("a".is_empty(), false, "tadam {}", true); -LL + assert!("a".is_empty(), "tadam {}", true); +LL + assert!(!"a".is_empty(), "tadam {}", true); | error: used `assert_eq!` with a literal bool @@ -224,7 +224,7 @@ LL | assert_eq!(false, "a".is_empty(), "tadam {}", true); help: replace it with `assert!(..)` | LL - assert_eq!(false, "a".is_empty(), "tadam {}", true); -LL + assert!("a".is_empty(), "tadam {}", true); +LL + assert!(!"a".is_empty(), "tadam {}", true); | error: used `debug_assert_eq!` with a literal bool @@ -236,7 +236,7 @@ LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); help: replace it with `debug_assert!(..)` | LL - debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); -LL + debug_assert!("a".is_empty(), "tadam {}", 1); +LL + debug_assert!(!"a".is_empty(), "tadam {}", 1); | error: used `debug_assert_eq!` with a literal bool @@ -248,7 +248,7 @@ LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true); help: replace it with `debug_assert!(..)` | LL - debug_assert_eq!("a".is_empty(), false, "tadam {}", true); -LL + debug_assert!("a".is_empty(), "tadam {}", true); +LL + debug_assert!(!"a".is_empty(), "tadam {}", true); | error: used `debug_assert_eq!` with a literal bool @@ -260,7 +260,7 @@ LL | debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); help: replace it with `debug_assert!(..)` | LL - debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); -LL + debug_assert!("a".is_empty(), "tadam {}", true); +LL + debug_assert!(!"a".is_empty(), "tadam {}", true); | error: used `assert_eq!` with a literal bool @@ -299,5 +299,101 @@ LL - renamed!(b, true); LL + debug_assert!(b); | -error: aborting due to 25 previous errors +error: used `assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:162:5 + | +LL | assert_eq!("".is_empty(), true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!("".is_empty(), true); +LL + assert!("".is_empty()); + | + +error: used `assert_ne!` with a literal bool + --> $DIR/bool_assert_comparison.rs:163:5 + | +LL | assert_ne!("".is_empty(), false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_ne!("".is_empty(), false); +LL + assert!("".is_empty()); + | + +error: used `assert_ne!` with a literal bool + --> $DIR/bool_assert_comparison.rs:164:5 + | +LL | assert_ne!("requires negation".is_empty(), true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_ne!("requires negation".is_empty(), true); +LL + assert!(!"requires negation".is_empty()); + | + +error: used `assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:165:5 + | +LL | assert_eq!("requires negation".is_empty(), false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!("requires negation".is_empty(), false); +LL + assert!(!"requires negation".is_empty()); + | + +error: used `debug_assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:167:5 + | +LL | debug_assert_eq!("".is_empty(), true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!("".is_empty(), true); +LL + debug_assert!("".is_empty()); + | + +error: used `debug_assert_ne!` with a literal bool + --> $DIR/bool_assert_comparison.rs:168:5 + | +LL | debug_assert_ne!("".is_empty(), false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_ne!("".is_empty(), false); +LL + debug_assert!("".is_empty()); + | + +error: used `debug_assert_ne!` with a literal bool + --> $DIR/bool_assert_comparison.rs:169:5 + | +LL | debug_assert_ne!("requires negation".is_empty(), true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_ne!("requires negation".is_empty(), true); +LL + debug_assert!(!"requires negation".is_empty()); + | + +error: used `debug_assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:170:5 + | +LL | debug_assert_eq!("requires negation".is_empty(), false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!("requires negation".is_empty(), false); +LL + debug_assert!(!"requires negation".is_empty()); + | + +error: aborting due to 33 previous errors diff --git a/tests/ui/crashes/ice-2774.stderr b/tests/ui/crashes/ice-2774.stderr index 1f26c7f4db657..c5ea0b16d1be4 100644 --- a/tests/ui/crashes/ice-2774.stderr +++ b/tests/ui/crashes/ice-2774.stderr @@ -5,6 +5,11 @@ LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` +help: elide the lifetimes + | +LL - pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { +LL + pub fn add_barfoos_to_foos(bars: &HashSet<&Bar>) { + | error: aborting due to previous error diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr index 875d5ab4f21ca..0b0e0ad2684a9 100644 --- a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr +++ b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr @@ -9,6 +9,11 @@ note: the lint level is defined here | LL | #![deny(clippy::needless_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: elide the lifetimes + | +LL - fn baz<'a>(&'a self) -> impl Foo + 'a { +LL + fn baz(&self) -> impl Foo + '_ { + | error: aborting due to previous error diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs new file mode 100644 index 0000000000000..5cb80cb6233f7 --- /dev/null +++ b/tests/ui/extra_unused_type_parameters.rs @@ -0,0 +1,69 @@ +#![allow(unused, clippy::needless_lifetimes)] +#![warn(clippy::extra_unused_type_parameters)] + +fn unused_ty(x: u8) {} + +fn unused_multi(x: u8) {} + +fn unused_with_lt<'a, T>(x: &'a u8) {} + +fn used_ty(x: T, y: u8) {} + +fn used_ref<'a, T>(x: &'a T) {} + +fn used_ret(x: u8) -> T { + T::default() +} + +fn unused_bounded(x: U) {} + +fn unused_where_clause(x: U) +where + T: Default, +{ +} + +fn some_unused, E>(b: B, c: C) {} + +fn used_opaque(iter: impl Iterator) -> usize { + iter.count() +} + +fn used_ret_opaque() -> impl Iterator { + std::iter::empty() +} + +fn used_vec_box(x: Vec>) {} + +fn used_body() -> String { + T::default().to_string() +} + +fn used_closure() -> impl Fn() { + || println!("{}", T::default().to_string()) +} + +struct S; + +impl S { + fn unused_ty_impl(&self) {} +} + +// Don't lint on trait methods +trait Foo { + fn bar(&self); +} + +impl Foo for S { + fn bar(&self) {} +} + +fn skip_index(iter: Iter, index: usize) -> impl Iterator +where + Iter: Iterator, +{ + iter.enumerate() + .filter_map(move |(i, a)| if i == index { None } else { Some(a) }) +} + +fn main() {} diff --git a/tests/ui/extra_unused_type_parameters.stderr b/tests/ui/extra_unused_type_parameters.stderr new file mode 100644 index 0000000000000..1c8dd53e63859 --- /dev/null +++ b/tests/ui/extra_unused_type_parameters.stderr @@ -0,0 +1,59 @@ +error: type parameter goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:4:13 + | +LL | fn unused_ty(x: u8) {} + | ^^^ + | + = help: consider removing the parameter + = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` + +error: type parameters go unused in function definition + --> $DIR/extra_unused_type_parameters.rs:6:16 + | +LL | fn unused_multi(x: u8) {} + | ^^^^^^ + | + = help: consider removing the parameters + +error: type parameter goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:8:23 + | +LL | fn unused_with_lt<'a, T>(x: &'a u8) {} + | ^ + | + = help: consider removing the parameter + +error: type parameter goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:18:19 + | +LL | fn unused_bounded(x: U) {} + | ^^^^^^^^^^^ + | + = help: consider removing the parameter + +error: type parameter goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:20:24 + | +LL | fn unused_where_clause(x: U) + | ^^ + | + = help: consider removing the parameter + +error: type parameters go unused in function definition + --> $DIR/extra_unused_type_parameters.rs:26:16 + | +LL | fn some_unused, E>(b: B, c: C) {} + | ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ + | + = help: consider removing the parameters + +error: type parameter goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:49:22 + | +LL | fn unused_ty_impl(&self) {} + | ^^^ + | + = help: consider removing the parameter + +error: aborting due to 7 previous errors + diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs index 78397c2af346b..b5dec6c46bddd 100644 --- a/tests/ui/len_without_is_empty.rs +++ b/tests/ui/len_without_is_empty.rs @@ -282,4 +282,50 @@ impl AsyncLen { } } +// issue #9520 +pub struct NonStandardLenAndIsEmptySignature; +impl NonStandardLenAndIsEmptySignature { + // don't lint + pub fn len(&self, something: usize) -> usize { + something + } + + pub fn is_empty(&self, something: usize) -> bool { + something == 0 + } +} + +// test case for #9520 with generics in the function signature +pub trait TestResource { + type NonStandardSignatureWithGenerics: Copy; + fn lookup_content(&self, item: Self::NonStandardSignatureWithGenerics) -> Result, String>; +} +pub struct NonStandardSignatureWithGenerics(u32); +impl NonStandardSignatureWithGenerics { + pub fn is_empty(self, resource: &T) -> bool + where + T: TestResource, + U: Copy + From, + { + if let Ok(Some(content)) = resource.lookup_content(self.into()) { + content.is_empty() + } else { + true + } + } + + // test case for #9520 with generics in the function signature + pub fn len(self, resource: &T) -> usize + where + T: TestResource, + U: Copy + From, + { + if let Ok(Some(content)) = resource.lookup_content(self.into()) { + content.len() + } else { + 0_usize + } + } +} + fn main() {} diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index 638320dd6eec4..8c7e919bf62a1 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -29,9 +29,7 @@ fn main() { panic!("qaqaq{:?}", a); } assert!(a.is_empty(), "qaqaq{:?}", a); - if !a.is_empty() { - panic!("qwqwq"); - } + assert!(a.is_empty(), "qwqwq"); if a.len() == 3 { println!("qwq"); println!("qwq"); @@ -46,21 +44,11 @@ fn main() { println!("qwq"); } let b = vec![1, 2, 3]; - if b.is_empty() { - panic!("panic1"); - } - if b.is_empty() && a.is_empty() { - panic!("panic2"); - } - if a.is_empty() && !b.is_empty() { - panic!("panic3"); - } - if b.is_empty() || a.is_empty() { - panic!("panic4"); - } - if a.is_empty() || !b.is_empty() { - panic!("panic5"); - } + assert!(!b.is_empty(), "panic1"); + assert!(!(b.is_empty() && a.is_empty()), "panic2"); + assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + assert!(!(b.is_empty() || a.is_empty()), "panic4"); + assert!(!(a.is_empty() || !b.is_empty()), "panic5"); assert!(!a.is_empty(), "with expansion {}", one!()); if a.is_empty() { let _ = 0; @@ -71,12 +59,11 @@ fn main() { fn issue7730(a: u8) { // Suggestion should preserve comment - if a > 2 { - // comment - /* this is a + // comment +/* this is a multiline comment */ - /// Doc comment - panic!("panic with comment") // comment after `panic!` - } +/// Doc comment +// comment after `panic!` +assert!(!(a > 2), "panic with comment"); } diff --git a/tests/ui/manual_assert.edition2018.stderr b/tests/ui/manual_assert.edition2018.stderr index 1f2e1e3087bd0..3555ac29243a1 100644 --- a/tests/ui/manual_assert.edition2018.stderr +++ b/tests/ui/manual_assert.edition2018.stderr @@ -8,6 +8,54 @@ LL | | } | = note: `-D clippy::manual-assert` implied by `-D warnings` +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:34:5 + | +LL | / if !a.is_empty() { +LL | | panic!("qwqwq"); +LL | | } + | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:51:5 + | +LL | / if b.is_empty() { +LL | | panic!("panic1"); +LL | | } + | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:54:5 + | +LL | / if b.is_empty() && a.is_empty() { +LL | | panic!("panic2"); +LL | | } + | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:57:5 + | +LL | / if a.is_empty() && !b.is_empty() { +LL | | panic!("panic3"); +LL | | } + | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:60:5 + | +LL | / if b.is_empty() || a.is_empty() { +LL | | panic!("panic4"); +LL | | } + | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:63:5 + | +LL | / if a.is_empty() || !b.is_empty() { +LL | | panic!("panic5"); +LL | | } + | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` + error: only a `panic!` in `if`-then statement --> $DIR/manual_assert.rs:66:5 | @@ -16,5 +64,22 @@ LL | | panic!("with expansion {}", one!()) LL | | } | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());` -error: aborting due to 2 previous errors +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:78:5 + | +LL | / if a > 2 { +LL | | // comment +LL | | /* this is a +LL | | multiline +... | +LL | | panic!("panic with comment") // comment after `panic!` +LL | | } + | |_____^ + | +help: try instead + | +LL | assert!(!(a > 2), "panic with comment"); + | + +error: aborting due to 9 previous errors diff --git a/tests/ui/match_wildcard_for_single_variants.fixed b/tests/ui/match_wildcard_for_single_variants.fixed index fc252cdd35294..9fd3739b69c2c 100644 --- a/tests/ui/match_wildcard_for_single_variants.fixed +++ b/tests/ui/match_wildcard_for_single_variants.fixed @@ -123,7 +123,7 @@ fn main() { Enum::A => (), Enum::B => (), Enum::C => (), - _ => (), + Enum::__Private => (), } match Enum::A { Enum::A => (), diff --git a/tests/ui/match_wildcard_for_single_variants.stderr b/tests/ui/match_wildcard_for_single_variants.stderr index 6fa313dc91114..105b4c4b41d1e 100644 --- a/tests/ui/match_wildcard_for_single_variants.stderr +++ b/tests/ui/match_wildcard_for_single_variants.stderr @@ -48,11 +48,17 @@ error: wildcard matches only a single variant and will also match any future add LL | _ => (), | ^ help: try this: `Color::Blue` +error: wildcard matches only a single variant and will also match any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:126:13 + | +LL | _ => (), + | ^ help: try this: `Enum::__Private` + error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:153:13 | LL | _ => 2, | ^ help: try this: `Foo::B` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 41263535df673..4511bc99c3c71 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,9 +1,13 @@ +// aux-build:macro_rules.rs #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::drop_copy)] #![warn(clippy::multiple_unsafe_ops_per_block)] +#[macro_use] +extern crate macro_rules; + use core::arch::asm; fn raw_ptr() -> *const () { @@ -107,4 +111,9 @@ unsafe fn read_char_good(ptr: *const u8) -> char { unsafe { core::char::from_u32_unchecked(int_value) } } +// no lint +fn issue10259() { + unsafe_macro!(); +} + fn main() {} diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index f6b8341795d23..303aeb7aee0c5 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -1,5 +1,5 @@ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:32:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:36:5 | LL | / unsafe { LL | | STATIC += 1; @@ -8,19 +8,19 @@ LL | | } | |_____^ | note: modification of a mutable static occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:33:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:37:9 | LL | STATIC += 1; | ^^^^^^^^^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:34:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:38:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ = note: `-D clippy::multiple-unsafe-ops-per-block` implied by `-D warnings` error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:41:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:45:5 | LL | / unsafe { LL | | drop(u.u); @@ -29,18 +29,18 @@ LL | | } | |_____^ | note: union field access occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:42:14 + --> $DIR/multiple_unsafe_ops_per_block.rs:46:14 | LL | drop(u.u); | ^^^ note: raw pointer dereference occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:43:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:47:9 | LL | *raw_ptr(); | ^^^^^^^^^^ error: this `unsafe` block contains 3 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:48:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:52:5 | LL | / unsafe { LL | | asm!("nop"); @@ -50,23 +50,23 @@ LL | | } | |_____^ | note: inline assembly used here - --> $DIR/multiple_unsafe_ops_per_block.rs:49:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:53:9 | LL | asm!("nop"); | ^^^^^^^^^^^ note: unsafe method call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:50:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:54:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:51:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:55:9 | LL | STATIC = 0; | ^^^^^^^^^^ error: this `unsafe` block contains 6 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:57:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:61:5 | LL | / unsafe { LL | | drop(u.u); @@ -78,49 +78,49 @@ LL | | } | |_____^ | note: union field access occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:58:14 + --> $DIR/multiple_unsafe_ops_per_block.rs:62:14 | LL | drop(u.u); | ^^^ note: access of a mutable static occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:59:14 + --> $DIR/multiple_unsafe_ops_per_block.rs:63:14 | LL | drop(STATIC); | ^^^^^^ note: unsafe method call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:60:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:64:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:61:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:65:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:62:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:66:9 | LL | *raw_ptr(); | ^^^^^^^^^^ note: inline assembly used here - --> $DIR/multiple_unsafe_ops_per_block.rs:63:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:67:9 | LL | asm!("nop"); | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:101:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:105:5 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:101:14 + --> $DIR/multiple_unsafe_ops_per_block.rs:105:14 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:101:39 + --> $DIR/multiple_unsafe_ops_per_block.rs:105:39 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed new file mode 100644 index 0000000000000..d286ef4ba3788 --- /dev/null +++ b/tests/ui/needless_lifetimes.fixed @@ -0,0 +1,538 @@ +// run-rustfix +// aux-build:macro_rules.rs + +#![warn(clippy::needless_lifetimes)] +#![allow( + unused, + clippy::boxed_local, + clippy::extra_unused_type_parameters, + clippy::needless_pass_by_value, + clippy::unnecessary_wraps, + dyn_drop, + clippy::get_first +)] + +#[macro_use] +extern crate macro_rules; + +fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} + +fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {} + +// No error; same lifetime on two params. +fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {} + +// No error; static involved. +fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {} + +fn mut_and_static_input(_x: &mut u8, _y: &'static str) {} + +fn in_and_out(x: &u8, _y: u8) -> &u8 { + x +} + +// No error; multiple input refs. +fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { + x +} + +// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid: +// fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 +// ^^^ +fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 { + x +} + +// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid: +// fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 +// ^^^ +fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 { + y +} + +// No error; multiple input refs +async fn func<'a>(args: &[&'a str]) -> Option<&'a str> { + args.get(0).cloned() +} + +// No error; static involved. +fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { + x +} + +// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid: +// fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> +// ^^^ +fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> { + Ok(x) +} + +// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid: +// fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> +// ^^^ +fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> { + Ok(y) +} + +// No error; two input refs. +fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { + x.unwrap() +} + +fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> { + Ok(x) +} + +// Where-clause, but without lifetimes. +fn where_clause_without_lt(x: &u8, _y: u8) -> Result<&u8, ()> +where + T: Copy, +{ + Ok(x) +} + +type Ref<'r> = &'r u8; + +// No error; same lifetime on two params. +fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {} + +fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} + +// No error; bounded lifetime. +fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {} + +// No error; bounded lifetime. +fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) +where + 'b: 'a, +{ +} + +struct Lt<'a, I: 'static> { + x: &'a I, +} + +// No error; fn bound references `'a`. +fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> +where + F: Fn(Lt<'a, I>) -> Lt<'a, I>, +{ + unreachable!() +} + +fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> +where + for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>, +{ + unreachable!() +} + +// No error; see below. +fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) { + f(x); +} + +fn fn_bound_3_cannot_elide() { + let x = 42; + let p = &x; + let mut q = &x; + // This will fail if we elide lifetimes of `fn_bound_3`. + fn_bound_3(p, |y| q = y); +} + +// No error; multiple input refs. +fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () { + if cond { x } else { f() } +} + +struct X { + x: u8, +} + +impl X { + fn self_and_out(&self) -> &u8 { + &self.x + } + + // Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid: + // fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 + // ^^^ + fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 { + &self.x + } + + // Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid: + // fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 + // ^^^^^ + fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 { + x + } + + fn distinct_self_and_in(&self, _x: &u8) {} + + // No error; same lifetimes on two params. + fn self_and_same_in<'s>(&'s self, _x: &'s u8) {} +} + +struct Foo<'a>(&'a u8); + +impl<'a> Foo<'a> { + // No error; lifetime `'a` not defined in method. + fn self_shared_lifetime(&self, _: &'a u8) {} + // No error; bounds exist. + fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} +} + +fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 { + unimplemented!() +} + +fn struct_with_lt(_foo: Foo<'_>) -> &str { + unimplemented!() +} + +// No warning; two input lifetimes (named on the reference, anonymous on `Foo`). +fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { + unimplemented!() +} + +// No warning; two input lifetimes (anonymous on the reference, named on `Foo`). +fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str { + unimplemented!() +} + +// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is +// valid: +// fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str +// ^^ +fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { + unimplemented!() +} + +// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is +// valid: +// fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str +// ^^^^ +fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str { + unimplemented!() +} + +trait WithLifetime<'a> {} + +type WithLifetimeAlias<'a> = dyn WithLifetime<'a>; + +// Should not warn because it won't build without the lifetime. +fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str { + unimplemented!() +} + +// Should warn because there is no lifetime on `Drop`, so this would be +// unambiguous if we elided the lifetime. +fn trait_obj_elided2(_arg: &dyn Drop) -> &str { + unimplemented!() +} + +type FooAlias<'a> = Foo<'a>; + +fn alias_with_lt(_foo: FooAlias<'_>) -> &str { + unimplemented!() +} + +// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`). +fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { + unimplemented!() +} + +// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`). +fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str { + unimplemented!() +} + +// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is +// valid: +// fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str +// ^^ +fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { + unimplemented!() +} + +// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is +// valid: +// fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str +// ^^^^^^^^^ +fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str { + unimplemented!() +} + +fn named_input_elided_output(_arg: &str) -> &str { + unimplemented!() +} + +fn elided_input_named_output<'a>(_arg: &str) -> &'a str { + unimplemented!() +} + +fn trait_bound_ok>(_: &u8, _: T) { + unimplemented!() +} +fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) { + unimplemented!() +} + +// Don't warn on these; see issue #292. +fn trait_bound_bug<'a, T: WithLifetime<'a>>() { + unimplemented!() +} + +// See issue #740. +struct Test { + vec: Vec, +} + +impl Test { + fn iter<'a>(&'a self) -> Box + 'a> { + unimplemented!() + } +} + +trait LintContext<'a> {} + +fn f<'a, T: LintContext<'a>>(_: &T) {} + +fn test<'a>(x: &'a [u8]) -> u8 { + let y: &'a u8 = &x[5]; + *y +} + +// Issue #3284: give hint regarding lifetime in return type. +struct Cow<'a> { + x: &'a str, +} +fn out_return_type_lts(e: &str) -> Cow<'_> { + unimplemented!() +} + +// Make sure we still warn on implementations +mod issue4291 { + trait BadTrait { + fn needless_lt(x: &u8) {} + } + + impl BadTrait for () { + fn needless_lt(_x: &u8) {} + } +} + +mod issue2944 { + trait Foo {} + struct Bar; + struct Baz<'a> { + bar: &'a Bar, + } + + impl<'a> Foo for Baz<'a> {} + impl Bar { + fn baz(&self) -> impl Foo + '_ { + Baz { bar: self } + } + } +} + +mod nested_elision_sites { + // issue #issue2944 + + // closure trait bounds subject to nested elision + // don't lint because they refer to outer lifetimes + fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 { + move || i + } + fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 { + move || i + } + fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 { + move || i + } + + // don't lint + fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 { + f() + } + fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 { + move || i + } + // lint + fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 { + f(i) + } + fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&i32) -> &i32) -> &i32 { + f(i) + } + + // don't lint + fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 { + f() + } + // lint + fn generics_elidable &i32>(i: &i32, f: T) -> &i32 { + f(i) + } + + // don't lint + fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32 + where + T: Fn() -> &'a i32, + { + f() + } + // lint + fn where_clause_elidadable(i: &i32, f: T) -> &i32 + where + T: Fn(&i32) -> &i32, + { + f(i) + } + + // don't lint + fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 { + f(i) + } + fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 { + |i| i + } + // lint + fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 { + f(i) + } + + // don't lint + fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 { + |f| 42 + } + fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) { + |f| () + } + + // lint + fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 { + |f| 42 + } + fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) { + |f| () + } +} + +mod issue6159 { + use std::ops::Deref; + pub fn apply_deref<'a, T, F, R>(x: &'a T, f: F) -> R + where + T: Deref, + F: FnOnce(&'a T::Target) -> R, + { + f(x.deref()) + } +} + +mod issue7296 { + use std::rc::Rc; + use std::sync::Arc; + + struct Foo; + impl Foo { + fn implicit(&self) -> &() { + &() + } + fn implicit_mut(&mut self) -> &() { + &() + } + + fn explicit<'a>(self: &'a Arc) -> &'a () { + &() + } + fn explicit_mut<'a>(self: &'a mut Rc) -> &'a () { + &() + } + + fn lifetime_elsewhere(self: Box, here: &()) -> &() { + &() + } + } + + trait Bar { + fn implicit(&self) -> &(); + fn implicit_provided(&self) -> &() { + &() + } + + fn explicit<'a>(self: &'a Arc) -> &'a (); + fn explicit_provided<'a>(self: &'a Arc) -> &'a () { + &() + } + + fn lifetime_elsewhere(self: Box, here: &()) -> &(); + fn lifetime_elsewhere_provided(self: Box, here: &()) -> &() { + &() + } + } +} + +mod pr_9743_false_negative_fix { + #![allow(unused)] + + fn foo(x: &u8, y: &'_ u8) {} + + fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {} +} + +mod pr_9743_output_lifetime_checks { + #![allow(unused)] + + // lint: only one input + fn one_input(x: &u8) -> &u8 { + unimplemented!() + } + + // lint: multiple inputs, output would not be elided + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) -> &'b u8 { + unimplemented!() + } + + // don't lint: multiple inputs, output would be elided (which would create an ambiguity) + fn multiple_inputs_output_would_be_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'a u8 { + unimplemented!() + } +} + +mod in_macro { + macro_rules! local_one_input_macro { + () => { + fn one_input(x: &u8) -> &u8 { + unimplemented!() + } + }; + } + + // lint local macro expands to function with needless lifetimes + local_one_input_macro!(); + + // no lint on external macro + macro_rules::needless_lifetime!(); +} + +mod issue5787 { + use std::sync::MutexGuard; + + struct Foo; + + impl Foo { + // doesn't get linted without async + pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { + guard + } + } + + async fn foo<'a>(_x: &i32, y: &'a str) -> &'a str { + y + } +} + +fn main() {} diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 2efc936752ef9..409528b291db1 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,13 +1,20 @@ +// run-rustfix +// aux-build:macro_rules.rs + #![warn(clippy::needless_lifetimes)] #![allow( - dead_code, + unused, clippy::boxed_local, + clippy::extra_unused_type_parameters, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop, clippy::get_first )] +#[macro_use] +extern crate macro_rules; + fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} @@ -495,4 +502,37 @@ mod pr_9743_output_lifetime_checks { } } +mod in_macro { + macro_rules! local_one_input_macro { + () => { + fn one_input<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + }; + } + + // lint local macro expands to function with needless lifetimes + local_one_input_macro!(); + + // no lint on external macro + macro_rules::needless_lifetime!(); +} + +mod issue5787 { + use std::sync::MutexGuard; + + struct Foo; + + impl Foo { + // doesn't get linted without async + pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> { + guard + } + } + + async fn foo<'a>(_x: &i32, y: &'a str) -> &'a str { + y + } +} + fn main() {} diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 5a7cf13c86dde..4e3c8f20d8c52 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -1,316 +1,559 @@ error: the following explicit lifetimes could be elided: 'a, 'b - --> $DIR/needless_lifetimes.rs:11:1 + --> $DIR/needless_lifetimes.rs:18:1 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` +help: elide the lifetimes + | +LL - fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} +LL + fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} + | error: the following explicit lifetimes could be elided: 'a, 'b - --> $DIR/needless_lifetimes.rs:13:1 + --> $DIR/needless_lifetimes.rs:20:1 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} +LL + fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {} + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:23:1 + --> $DIR/needless_lifetimes.rs:30:1 | LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { +LL + fn in_and_out(x: &u8, _y: u8) -> &u8 { + | error: the following explicit lifetimes could be elided: 'b - --> $DIR/needless_lifetimes.rs:35:1 + --> $DIR/needless_lifetimes.rs:42:1 | LL | fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { +LL + fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:42:1 + --> $DIR/needless_lifetimes.rs:49:1 | LL | fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 { +LL + fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 { + | error: the following explicit lifetimes could be elided: 'b - --> $DIR/needless_lifetimes.rs:59:1 + --> $DIR/needless_lifetimes.rs:66:1 | LL | fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { +LL + fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:66:1 + --> $DIR/needless_lifetimes.rs:73:1 | LL | fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> { +LL + fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:75:1 + --> $DIR/needless_lifetimes.rs:82:1 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { +LL + fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:80:1 + --> $DIR/needless_lifetimes.rs:87:1 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> +LL + fn where_clause_without_lt(x: &u8, _y: u8) -> Result<&u8, ()> + | error: the following explicit lifetimes could be elided: 'a, 'b - --> $DIR/needless_lifetimes.rs:92:1 + --> $DIR/needless_lifetimes.rs:99:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace with `'_` in generic arguments such as here - --> $DIR/needless_lifetimes.rs:92:37 +help: elide the lifetimes + | +LL - fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} +LL + fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} | -LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} - | ^^ error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:116:1 + --> $DIR/needless_lifetimes.rs:123:1 | LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace with `'_` in generic arguments such as here - --> $DIR/needless_lifetimes.rs:116:32 +help: elide the lifetimes + | +LL - fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> +LL + fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> | -LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> - | ^^ error: the following explicit lifetimes could be elided: 's - --> $DIR/needless_lifetimes.rs:146:5 + --> $DIR/needless_lifetimes.rs:153:5 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn self_and_out<'s>(&'s self) -> &'s u8 { +LL + fn self_and_out(&self) -> &u8 { + | error: the following explicit lifetimes could be elided: 't - --> $DIR/needless_lifetimes.rs:153:5 + --> $DIR/needless_lifetimes.rs:160:5 | LL | fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { +LL + fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 { + | error: the following explicit lifetimes could be elided: 's - --> $DIR/needless_lifetimes.rs:160:5 + --> $DIR/needless_lifetimes.rs:167:5 | LL | fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 { +LL + fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 { + | error: the following explicit lifetimes could be elided: 's, 't - --> $DIR/needless_lifetimes.rs:164:5 + --> $DIR/needless_lifetimes.rs:171:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} +LL + fn distinct_self_and_in(&self, _x: &u8) {} + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:183:1 + --> $DIR/needless_lifetimes.rs:190:1 | LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace with `'_` in generic arguments such as here - --> $DIR/needless_lifetimes.rs:183:33 +help: elide the lifetimes + | +LL - fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { +LL + fn struct_with_lt(_foo: Foo<'_>) -> &str { | -LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { - | ^^ error: the following explicit lifetimes could be elided: 'b - --> $DIR/needless_lifetimes.rs:201:1 + --> $DIR/needless_lifetimes.rs:208:1 | LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace with `'_` in generic arguments such as here - --> $DIR/needless_lifetimes.rs:201:43 +help: elide the lifetimes + | +LL - fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { +LL + fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { | -LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { - | ^^ error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:209:1 + --> $DIR/needless_lifetimes.rs:216:1 | LL | fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str { +LL + fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:224:1 + --> $DIR/needless_lifetimes.rs:231:1 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { +LL + fn trait_obj_elided2(_arg: &dyn Drop) -> &str { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:230:1 + --> $DIR/needless_lifetimes.rs:237:1 | LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace with `'_` in generic arguments such as here - --> $DIR/needless_lifetimes.rs:230:37 +help: elide the lifetimes + | +LL - fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { +LL + fn alias_with_lt(_foo: FooAlias<'_>) -> &str { | -LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { - | ^^ error: the following explicit lifetimes could be elided: 'b - --> $DIR/needless_lifetimes.rs:248:1 + --> $DIR/needless_lifetimes.rs:255:1 | LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace with `'_` in generic arguments such as here - --> $DIR/needless_lifetimes.rs:248:47 +help: elide the lifetimes + | +LL - fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { +LL + fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { | -LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { - | ^^ error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:256:1 + --> $DIR/needless_lifetimes.rs:263:1 | LL | fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str { +LL + fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:260:1 + --> $DIR/needless_lifetimes.rs:267:1 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn named_input_elided_output<'a>(_arg: &'a str) -> &str { +LL + fn named_input_elided_output(_arg: &str) -> &str { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:268:1 + --> $DIR/needless_lifetimes.rs:275:1 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { +LL + fn trait_bound_ok>(_: &u8, _: T) { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:304:1 + --> $DIR/needless_lifetimes.rs:311:1 | LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace with `'_` in generic arguments such as here - --> $DIR/needless_lifetimes.rs:304:47 +help: elide the lifetimes + | +LL - fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { +LL + fn out_return_type_lts(e: &str) -> Cow<'_> { | -LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { - | ^^ error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:311:9 + --> $DIR/needless_lifetimes.rs:318:9 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn needless_lt<'a>(x: &'a u8) {} +LL + fn needless_lt(x: &u8) {} + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:315:9 + --> $DIR/needless_lifetimes.rs:322:9 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn needless_lt<'a>(_x: &'a u8) {} +LL + fn needless_lt(_x: &u8) {} + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:328:9 + --> $DIR/needless_lifetimes.rs:335:9 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn baz<'a>(&'a self) -> impl Foo + 'a { +LL + fn baz(&self) -> impl Foo + '_ { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:360:5 + --> $DIR/needless_lifetimes.rs:367:5 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { +LL + fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&i32) -> &i32) -> &i32 { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:369:5 + --> $DIR/needless_lifetimes.rs:376:5 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { +LL + fn generics_elidable &i32>(i: &i32, f: T) -> &i32 { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:381:5 + --> $DIR/needless_lifetimes.rs:388:5 | LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 +LL + fn where_clause_elidadable(i: &i32, f: T) -> &i32 + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:396:5 + --> $DIR/needless_lifetimes.rs:403:5 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { +LL + fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:409:5 + --> $DIR/needless_lifetimes.rs:416:5 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { +LL + fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:412:5 + --> $DIR/needless_lifetimes.rs:419:5 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { +LL + fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:434:9 + --> $DIR/needless_lifetimes.rs:441:9 | LL | fn implicit<'a>(&'a self) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn implicit<'a>(&'a self) -> &'a () { +LL + fn implicit(&self) -> &() { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:437:9 + --> $DIR/needless_lifetimes.rs:444:9 | LL | fn implicit_mut<'a>(&'a mut self) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn implicit_mut<'a>(&'a mut self) -> &'a () { +LL + fn implicit_mut(&mut self) -> &() { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:448:9 + --> $DIR/needless_lifetimes.rs:455:9 | LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { +LL + fn lifetime_elsewhere(self: Box, here: &()) -> &() { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:454:9 + --> $DIR/needless_lifetimes.rs:461:9 | LL | fn implicit<'a>(&'a self) -> &'a (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn implicit<'a>(&'a self) -> &'a (); +LL + fn implicit(&self) -> &(); + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:455:9 + --> $DIR/needless_lifetimes.rs:462:9 | LL | fn implicit_provided<'a>(&'a self) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn implicit_provided<'a>(&'a self) -> &'a () { +LL + fn implicit_provided(&self) -> &() { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:464:9 + --> $DIR/needless_lifetimes.rs:471:9 | LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); +LL + fn lifetime_elsewhere(self: Box, here: &()) -> &(); + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:465:9 + --> $DIR/needless_lifetimes.rs:472:9 | LL | fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { +LL + fn lifetime_elsewhere_provided(self: Box, here: &()) -> &() { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:474:5 + --> $DIR/needless_lifetimes.rs:481:5 | LL | fn foo<'a>(x: &'a u8, y: &'_ u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn foo<'a>(x: &'a u8, y: &'_ u8) {} +LL + fn foo(x: &u8, y: &'_ u8) {} + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:476:5 + --> $DIR/needless_lifetimes.rs:483:5 | LL | fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {} +LL + fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {} + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:483:5 + --> $DIR/needless_lifetimes.rs:490:5 | LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { +LL + fn one_input(x: &u8) -> &u8 { + | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:488:5 + --> $DIR/needless_lifetimes.rs:495:5 | LL | fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: elide the lifetimes + | +LL - fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 { +LL + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) -> &'b u8 { + | + +error: the following explicit lifetimes could be elided: 'a + --> $DIR/needless_lifetimes.rs:508:13 + | +LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | local_one_input_macro!(); + | ------------------------ in this macro invocation + | + = note: this error originates in the macro `local_one_input_macro` (in Nightly builds, run with -Z macro-backtrace for more info) +help: elide the lifetimes + | +LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { +LL + fn one_input(x: &u8) -> &u8 { + | -error: aborting due to 45 previous errors +error: aborting due to 46 previous errors diff --git a/tests/ui/needless_range_loop.stderr b/tests/ui/needless_range_loop.stderr index b31544ec334a6..cffa19bec3a66 100644 --- a/tests/ui/needless_range_loop.stderr +++ b/tests/ui/needless_range_loop.stderr @@ -49,7 +49,7 @@ error: the loop variable `i` is used to index `vec` LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ | -help: consider using an iterator +help: consider using an iterator and enumerate() | LL | for (i, ) in vec.iter().enumerate() { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ @@ -126,7 +126,7 @@ error: the loop variable `i` is used to index `vec` LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ | -help: consider using an iterator +help: consider using an iterator and enumerate() | LL | for (i, ) in vec.iter().enumerate().skip(5) { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -137,7 +137,7 @@ error: the loop variable `i` is used to index `vec` LL | for i in 5..10 { | ^^^^^ | -help: consider using an iterator +help: consider using an iterator and enumerate() | LL | for (i, ) in vec.iter().enumerate().take(10).skip(5) { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -148,7 +148,7 @@ error: the loop variable `i` is used to index `vec` LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ | -help: consider using an iterator +help: consider using an iterator and enumerate() | LL | for (i, ) in vec.iter_mut().enumerate() { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index 65809023f8dff..7803418cb047d 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -1,4 +1,9 @@ -#![allow(dead_code, clippy::missing_safety_doc, clippy::extra_unused_lifetimes)] +#![allow( + dead_code, + clippy::missing_safety_doc, + clippy::extra_unused_lifetimes, + clippy::extra_unused_type_parameters +)] #![warn(clippy::new_without_default)] pub struct Foo; diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 212a69ab94e65..583dd327d6a5d 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -1,5 +1,5 @@ error: you should consider adding a `Default` implementation for `Foo` - --> $DIR/new_without_default.rs:7:5 + --> $DIR/new_without_default.rs:12:5 | LL | / pub fn new() -> Foo { LL | | Foo @@ -17,7 +17,7 @@ LL + } | error: you should consider adding a `Default` implementation for `Bar` - --> $DIR/new_without_default.rs:15:5 + --> $DIR/new_without_default.rs:20:5 | LL | / pub fn new() -> Self { LL | | Bar @@ -34,7 +34,7 @@ LL + } | error: you should consider adding a `Default` implementation for `LtKo<'c>` - --> $DIR/new_without_default.rs:79:5 + --> $DIR/new_without_default.rs:84:5 | LL | / pub fn new() -> LtKo<'c> { LL | | unimplemented!() @@ -51,7 +51,7 @@ LL + } | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` - --> $DIR/new_without_default.rs:172:5 + --> $DIR/new_without_default.rs:177: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:180:5 + --> $DIR/new_without_default.rs:185: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:187:5 + --> $DIR/new_without_default.rs:192: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:198:9 + --> $DIR/new_without_default.rs:203:9 | LL | / pub fn new() -> Self { LL | | todo!() diff --git a/tests/ui/redundant_field_names.fixed b/tests/ui/redundant_field_names.fixed index ec7f8ae923a79..276266a2dd803 100644 --- a/tests/ui/redundant_field_names.fixed +++ b/tests/ui/redundant_field_names.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::redundant_field_names)] -#![allow(clippy::no_effect, dead_code, unused_variables)] +#![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] #[macro_use] extern crate derive_new; diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index 73122016cf69e..f674141c138e1 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::redundant_field_names)] -#![allow(clippy::no_effect, dead_code, unused_variables)] +#![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] #[macro_use] extern crate derive_new; diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index f0e1a8128d7c3..ab8ac97a0e707 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -36,6 +36,10 @@ fn syntax_error() { let raw_string_error = Regex::new(r"[...\/...]"); let raw_string_error = Regex::new(r#"[...\/...]"#); + + let escaped_string_span = Regex::new("\\b\\c"); + + let aux_span = Regex::new("(?ixi)"); } fn trivial_regex() { diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index 2424644c6f6b1..c2440f39e0a03 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -29,7 +29,10 @@ error: regex syntax error: invalid character class range, the start must be <= t LL | let some_unicode = Regex::new("[é-è]"); | ^^^ -error: regex syntax error on position 0: unclosed group +error: regex parse error: + ( + ^ + error: unclosed group --> $DIR/regex.rs:18:33 | LL | let some_regex = Regex::new(OPENING_PAREN); @@ -43,25 +46,37 @@ LL | let binary_pipe_in_wrong_position = BRegex::new("|"); | = help: the regex is unlikely to be useful as it is -error: regex syntax error on position 0: unclosed group +error: regex parse error: + ( + ^ + error: unclosed group --> $DIR/regex.rs:21:41 | LL | let some_binary_regex = BRegex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ -error: regex syntax error on position 0: unclosed group +error: regex parse error: + ( + ^ + error: unclosed group --> $DIR/regex.rs:22:56 | LL | let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); | ^^^^^^^^^^^^^ -error: regex syntax error on position 0: unclosed group +error: regex parse error: + ( + ^ + error: unclosed group --> $DIR/regex.rs:34:37 | LL | let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); | ^^^^^^^^^^^^^ -error: regex syntax error on position 0: unclosed group +error: regex parse error: + ( + ^ + error: unclosed group --> $DIR/regex.rs:35:39 | LL | let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); @@ -79,8 +94,25 @@ error: regex syntax error: unrecognized escape sequence LL | let raw_string_error = Regex::new(r#"[...//...]"#); | ^^ +error: regex parse error: + /b/c + ^^ + error: unrecognized escape sequence + --> $DIR/regex.rs:40:42 + | +LL | let escaped_string_span = Regex::new("/b/c"); + | ^^^^^^^^ + | + = help: consider using a raw string literal: `r".."` + +error: regex syntax error: duplicate flag + --> $DIR/regex.rs:42:34 + | +LL | let aux_span = Regex::new("(?ixi)"); + | ^ ^ + error: trivial regex - --> $DIR/regex.rs:42:33 + --> $DIR/regex.rs:46:33 | LL | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ @@ -88,7 +120,7 @@ LL | let trivial_eq = Regex::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:44:48 + --> $DIR/regex.rs:48:48 | LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ @@ -96,7 +128,7 @@ LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:46:42 + --> $DIR/regex.rs:50:42 | LL | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ @@ -104,7 +136,7 @@ LL | let trivial_starts_with = Regex::new("^foobar"); = help: consider using `str::starts_with` error: trivial regex - --> $DIR/regex.rs:48:40 + --> $DIR/regex.rs:52:40 | LL | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ @@ -112,7 +144,7 @@ LL | let trivial_ends_with = Regex::new("foobar$"); = help: consider using `str::ends_with` error: trivial regex - --> $DIR/regex.rs:50:39 + --> $DIR/regex.rs:54:39 | LL | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ @@ -120,7 +152,7 @@ LL | let trivial_contains = Regex::new("foobar"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:52:39 + --> $DIR/regex.rs:56:39 | LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ @@ -128,7 +160,7 @@ LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:54:40 + --> $DIR/regex.rs:58:40 | LL | let trivial_backslash = Regex::new("a/.b"); | ^^^^^^^ @@ -136,7 +168,7 @@ LL | let trivial_backslash = Regex::new("a/.b"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:57:36 + --> $DIR/regex.rs:61:36 | LL | let trivial_empty = Regex::new(""); | ^^ @@ -144,7 +176,7 @@ LL | let trivial_empty = Regex::new(""); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:59:36 + --> $DIR/regex.rs:63:36 | LL | let trivial_empty = Regex::new("^"); | ^^^ @@ -152,7 +184,7 @@ LL | let trivial_empty = Regex::new("^"); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:61:36 + --> $DIR/regex.rs:65:36 | LL | let trivial_empty = Regex::new("^$"); | ^^^^ @@ -160,12 +192,12 @@ LL | let trivial_empty = Regex::new("^$"); = help: consider using `str::is_empty` error: trivial regex - --> $DIR/regex.rs:63:44 + --> $DIR/regex.rs:67:44 | LL | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ | = help: consider using `str::is_empty` -error: aborting due to 23 previous errors +error: aborting due to 25 previous errors diff --git a/tests/ui/seek_to_start_instead_of_rewind.fixed b/tests/ui/seek_to_start_instead_of_rewind.fixed index 713cff604a1d7..dc24d447c6075 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -26,7 +26,7 @@ fn seek_to_start_false_method(t: &mut StructWithSeekMethod) { // This should NOT trigger clippy warning because // StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { +fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { t.seek(SeekFrom::Start(0)); } @@ -38,7 +38,7 @@ fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) { // This should NOT trigger clippy warning because // StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { +fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { t.seek(SeekFrom::Start(0)); } diff --git a/tests/ui/seek_to_start_instead_of_rewind.rs b/tests/ui/seek_to_start_instead_of_rewind.rs index 467003a1a66f6..4adde2c40182d 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/tests/ui/seek_to_start_instead_of_rewind.rs @@ -26,7 +26,7 @@ fn seek_to_start_false_method(t: &mut StructWithSeekMethod) { // This should NOT trigger clippy warning because // StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { +fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) { t.seek(SeekFrom::Start(0)); } @@ -38,7 +38,7 @@ fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) { // This should NOT trigger clippy warning because // StructWithSeekMethod does not implement std::io::Seek; -fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { +fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) { t.seek(SeekFrom::Start(0)); } diff --git a/tests/ui/suspicious_to_owned.stderr b/tests/ui/suspicious_to_owned.stderr index dec3f50d6f1b6..c4ec7aa88a2a3 100644 --- a/tests/ui/suspicious_to_owned.stderr +++ b/tests/ui/suspicious_to_owned.stderr @@ -2,27 +2,62 @@ error: this `to_owned` call clones the Cow<'_, str> itself and does not cause th --> $DIR/suspicious_to_owned.rs:16:13 | LL | let _ = cow.to_owned(); - | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` + | ^^^^^^^^^^^^^^ | = note: `-D clippy::suspicious-to-owned` implied by `-D warnings` +help: depending on intent, either make the Cow an Owned variant + | +LL | let _ = cow.into_owned(); + | ~~~~~~~~~~~~~~~~ +help: or clone the Cow itself + | +LL | let _ = cow.clone(); + | ~~~~~~~~~~~ error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned --> $DIR/suspicious_to_owned.rs:26:13 | LL | let _ = cow.to_owned(); - | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` + | ^^^^^^^^^^^^^^ + | +help: depending on intent, either make the Cow an Owned variant + | +LL | let _ = cow.into_owned(); + | ~~~~~~~~~~~~~~~~ +help: or clone the Cow itself + | +LL | let _ = cow.clone(); + | ~~~~~~~~~~~ error: this `to_owned` call clones the Cow<'_, Vec> itself and does not cause the Cow<'_, Vec> contents to become owned --> $DIR/suspicious_to_owned.rs:36:13 | LL | let _ = cow.to_owned(); - | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` + | ^^^^^^^^^^^^^^ + | +help: depending on intent, either make the Cow an Owned variant + | +LL | let _ = cow.into_owned(); + | ~~~~~~~~~~~~~~~~ +help: or clone the Cow itself + | +LL | let _ = cow.clone(); + | ~~~~~~~~~~~ error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:46:13 | LL | let _ = cow.to_owned(); - | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` + | ^^^^^^^^^^^^^^ + | +help: depending on intent, either make the Cow an Owned variant + | +LL | let _ = cow.into_owned(); + | ~~~~~~~~~~~~~~~~ +help: or clone the Cow itself + | +LL | let _ = cow.clone(); + | ~~~~~~~~~~~ error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type --> $DIR/suspicious_to_owned.rs:60:13 diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs index 2eca1f4701c9f..8b4613b3f6ec7 100644 --- a/tests/ui/type_repetition_in_bounds.rs +++ b/tests/ui/type_repetition_in_bounds.rs @@ -1,4 +1,5 @@ #![deny(clippy::type_repetition_in_bounds)] +#![allow(clippy::extra_unused_type_parameters)] use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr index 70d700c1cc460..a90df03c04ffc 100644 --- a/tests/ui/type_repetition_in_bounds.stderr +++ b/tests/ui/type_repetition_in_bounds.stderr @@ -1,5 +1,5 @@ error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:8:5 + --> $DIR/type_repetition_in_bounds.rs:9:5 | LL | T: Clone, | ^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::type_repetition_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:25:5 + --> $DIR/type_repetition_in_bounds.rs:26:5 | LL | Self: Copy + Default + Ord, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | Self: Copy + Default + Ord, = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:85:5 + --> $DIR/type_repetition_in_bounds.rs:86:5 | LL | T: Clone, | ^^^^^^^^ @@ -28,7 +28,7 @@ LL | T: Clone, = help: consider combining the bounds: `T: ?Sized + Clone` error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:90:5 + --> $DIR/type_repetition_in_bounds.rs:91:5 | LL | T: ?Sized, | ^^^^^^^^^ diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index 4b059558173fb..8d3e094b75967 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -63,6 +63,14 @@ fn combine_or(file: &str) -> Result<(), Error> { Ok(()) } +fn is_ok_err(s: &mut T) { + s.write(b"ok").is_ok(); + s.write(b"err").is_err(); + let mut buf = [0u8; 0]; + s.read(&mut buf).is_ok(); + s.read(&mut buf).is_err(); +} + async fn bad_async_write(w: &mut W) { w.write(b"hello world").await.unwrap(); } diff --git a/tests/ui/unused_io_amount.stderr b/tests/ui/unused_io_amount.stderr index 7ba7e09c0f0df..0865c5213f687 100644 --- a/tests/ui/unused_io_amount.stderr +++ b/tests/ui/unused_io_amount.stderr @@ -82,13 +82,45 @@ LL | | .expect("error"); error: written amount is not handled --> $DIR/unused_io_amount.rs:67:5 | +LL | s.write(b"ok").is_ok(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Write::write_all` instead, or handle partial writes + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:68:5 + | +LL | s.write(b"err").is_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Write::write_all` instead, or handle partial writes + +error: read amount is not handled + --> $DIR/unused_io_amount.rs:70:5 + | +LL | s.read(&mut buf).is_ok(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Read::read_exact` instead, or handle partial reads + +error: read amount is not handled + --> $DIR/unused_io_amount.rs:71:5 + | +LL | s.read(&mut buf).is_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `Read::read_exact` instead, or handle partial reads + +error: written amount is not handled + --> $DIR/unused_io_amount.rs:75:5 + | LL | w.write(b"hello world").await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:72:5 + --> $DIR/unused_io_amount.rs:80:5 | LL | r.read(&mut buf[..]).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +128,7 @@ LL | r.read(&mut buf[..]).await.unwrap(); = help: use `AsyncReadExt::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:85:9 + --> $DIR/unused_io_amount.rs:93:9 | LL | w.write(b"hello world").await?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +136,7 @@ LL | w.write(b"hello world").await?; = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:93:9 + --> $DIR/unused_io_amount.rs:101:9 | LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +144,7 @@ LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?; = help: use `AsyncReadExt::read_exact` instead, or handle partial reads error: written amount is not handled - --> $DIR/unused_io_amount.rs:101:5 + --> $DIR/unused_io_amount.rs:109:5 | LL | w.write(b"hello world").await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,12 +152,12 @@ LL | w.write(b"hello world").await.unwrap(); = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> $DIR/unused_io_amount.rs:106:5 + --> $DIR/unused_io_amount.rs:114:5 | LL | r.read(&mut buf[..]).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `AsyncReadExt::read_exact` instead, or handle partial reads -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index 23607497841e4..293bf75a71762 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -96,7 +96,7 @@ fn main() { } match Enum::A { Enum::A => (), - Enum::B | _ => (), + Enum::B | Enum::__Private => (), } } } diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr index efecc9576cc7b..30d29aa4e77a1 100644 --- a/tests/ui/wildcard_enum_match_arm.stderr +++ b/tests/ui/wildcard_enum_match_arm.stderr @@ -34,11 +34,11 @@ error: wildcard matches known variants and will also match future added variants LL | _ => {}, | ^ help: try this: `ErrorKind::PermissionDenied | _` -error: wildcard matches known variants and will also match future added variants +error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:99:13 | LL | _ => (), - | ^ help: try this: `Enum::B | _` + | ^ help: try this: `Enum::B | Enum::__Private` error: aborting due to 6 previous errors From cd3bcbb8e5fb97a83caab7556175a7d6b3d0632b Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 10 Feb 2023 13:43:29 +0000 Subject: [PATCH 08/90] add `AliasEq` to `PredicateKind` --- clippy_utils/src/qualify_min_const_fn.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 727058780752e..26b1d01974990 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -36,6 +36,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, + ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"), 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:#?}"), From 145e6a94d6bd9aa360fa7d43e52a2e9aad1752ef Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 10 Feb 2023 16:59:04 +0100 Subject: [PATCH 09/90] Add suspicious_command_arg_space lint. --- clippy_lints/src/methods/mod.rs | 30 ++++++++++++++ .../methods/suspicious_command_arg_space.rs | 39 +++++++++++++++++++ clippy_utils/src/paths.rs | 1 + 3 files changed, 70 insertions(+) create mode 100644 clippy_lints/src/methods/suspicious_command_arg_space.rs diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f1e8be7f2b87f..c97f4661cf186 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -80,6 +80,7 @@ mod skip_while_next; mod stable_sort_primitive; mod str_splitn; mod string_extend_chars; +mod suspicious_command_arg_space; mod suspicious_map; mod suspicious_splitn; mod suspicious_to_owned; @@ -3162,6 +3163,32 @@ declare_clippy_lint! { "collecting an iterator when collect is not needed" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for `Command::arg()` invocations that look like they + /// should be multiple arguments instead, such as `arg("-t ext2")`. + /// + /// ### Why is this bad? + /// + /// Arguments are not split by space. An argument like `arg("-t ext2")` + /// will be passed as a single argument to the command, + /// which is likely not what was intended. + /// + /// ### Example + /// ```rust + /// std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); + /// ``` + /// Use instead: + /// ```rust + /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); + /// ``` + #[clippy::version = "1.67.0"] + pub SUSPICIOUS_COMMAND_ARG_SPACE, + suspicious, + "single command line argument that looks like it should be multiple arguments" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3496,6 +3523,9 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, + ("arg", [arg]) => { + suspicious_command_arg_space::check(cx, recv, arg, span); + } ("as_deref" | "as_deref_mut", []) => { needless_option_as_deref::check(cx, expr, recv, name); }, diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs new file mode 100644 index 0000000000000..73632c5a357dd --- /dev/null +++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths; +use clippy_utils::ty::match_type; +use rustc_ast as ast; +use rustc_errors::{Applicability, Diagnostic}; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::SUSPICIOUS_COMMAND_ARG_SPACE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + + if match_type(cx, ty, &paths::STD_PROCESS_COMMAND) + && let hir::ExprKind::Lit(lit) = &arg.kind + && let ast::LitKind::Str(s, _) = &lit.node + && let Some((arg1, arg2)) = s.as_str().split_once(' ') + && arg1.starts_with('-') + && arg1.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-') + { + span_lint_and_then( + cx, + SUSPICIOUS_COMMAND_ARG_SPACE, + arg.span, + "single argument that looks like it should be multiple arguments", + |diag: &mut Diagnostic| { + diag.multipart_suggestion_verbose( + "consider splitting the argument", + vec![ + (span, "args".to_string()), + (arg.span, format!("[{arg1:?}, {arg2:?}]")), + ], + Applicability::MaybeIncorrect, + ); + } + ); + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 95eebab756776..4aae0f7284e4d 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -115,6 +115,7 @@ pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; +pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; From 5fefe8b31738b4adf8329222afa50a264ef97d6a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 10 Feb 2023 17:13:30 +0100 Subject: [PATCH 10/90] Add test. --- tests/ui/suspicious_command_arg_space.rs | 5 ++++ tests/ui/suspicious_command_arg_space.stderr | 25 ++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/ui/suspicious_command_arg_space.rs create mode 100644 tests/ui/suspicious_command_arg_space.stderr diff --git a/tests/ui/suspicious_command_arg_space.rs b/tests/ui/suspicious_command_arg_space.rs new file mode 100644 index 0000000000000..74b230f430bfb --- /dev/null +++ b/tests/ui/suspicious_command_arg_space.rs @@ -0,0 +1,5 @@ +fn main() { + std::process::Command::new("echo").arg("hello world").spawn().unwrap(); + std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); + std::process::Command::new("cat").arg("--number file").spawn().unwrap(); +} diff --git a/tests/ui/suspicious_command_arg_space.stderr b/tests/ui/suspicious_command_arg_space.stderr new file mode 100644 index 0000000000000..9bc0ca93aec9e --- /dev/null +++ b/tests/ui/suspicious_command_arg_space.stderr @@ -0,0 +1,25 @@ +error: single argument that looks like it should be multiple arguments + --> $DIR/suspicious_command_arg_space.rs:3:44 + | +LL | std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); + | ^^^^^^^^^^ + | + = note: `-D clippy::suspicious-command-arg-space` implied by `-D warnings` +help: consider splitting the argument + | +LL | std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); + | ~~~~ ~~~~~~~~~~~~~~~ + +error: single argument that looks like it should be multiple arguments + --> $DIR/suspicious_command_arg_space.rs:4:43 + | +LL | std::process::Command::new("cat").arg("--number file").spawn().unwrap(); + | ^^^^^^^^^^^^^^^ + | +help: consider splitting the argument + | +LL | std::process::Command::new("cat").args(["--number", "file"]).spawn().unwrap(); + | ~~~~ ~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors + From 984c47b9f4e0341bf4d3ed29007f4a51bf8a146d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 10 Feb 2023 18:59:37 +0100 Subject: [PATCH 11/90] Clarify description of suspicious_command_arg_space. Co-authored-by: Manish Goregaokar --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c97f4661cf186..7e34d08ea32c4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3171,7 +3171,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// - /// Arguments are not split by space. An argument like `arg("-t ext2")` + /// `Command::arg()` does not split arguments by space. An argument like `arg("-t ext2")` /// will be passed as a single argument to the command, /// which is likely not what was intended. /// From 8f56767c94a9ccadcd5cb6c495fe7f646e5221a7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 10 Feb 2023 19:03:20 +0100 Subject: [PATCH 12/90] Update lints. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 659e8aebcd579..30727beb8e7ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4764,6 +4764,7 @@ Released 2018-09-13 [`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting +[`suspicious_command_arg_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_command_arg_space [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 457a25826e799..c1feabf05aafd 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -378,6 +378,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::SKIP_WHILE_NEXT_INFO, crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, + crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO, crate::methods::SUSPICIOUS_MAP_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, crate::methods::SUSPICIOUS_TO_OWNED_INFO, From 078f149aa46c198200f54de556a7ba978a619564 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 10 Feb 2023 08:04:24 -0300 Subject: [PATCH 13/90] [significant_drop_tightening] Add MVP --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 3 + .../src/significant_drop_tightening.rs | 381 ++++++++++++++++++ tests/ui/significant_drop_tightening.fixed | 56 +++ tests/ui/significant_drop_tightening.rs | 53 +++ tests/ui/significant_drop_tightening.stderr | 71 ++++ 7 files changed, 566 insertions(+) create mode 100644 clippy_lints/src/significant_drop_tightening.rs create mode 100644 tests/ui/significant_drop_tightening.fixed create mode 100644 tests/ui/significant_drop_tightening.rs create mode 100644 tests/ui/significant_drop_tightening.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 659e8aebcd579..2367524ca7248 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4734,6 +4734,7 @@ Released 2018-09-13 [`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait [`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee +[`significant_drop_tightening`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_tightening [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names [`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str [`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 457a25826e799..bc8ea8a6f2f5b 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -536,6 +536,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::shadow::SHADOW_REUSE_INFO, crate::shadow::SHADOW_SAME_INFO, crate::shadow::SHADOW_UNRELATED_INFO, + crate::significant_drop_tightening::SIGNIFICANT_DROP_TIGHTENING_INFO, crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO, crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO, crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 565c5b7af0068..223e6698b723c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -2,6 +2,7 @@ #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] #![feature(drain_filter)] +#![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(lint_reasons)] @@ -263,6 +264,7 @@ mod semicolon_block; mod semicolon_if_nothing_returned; mod serde_api; mod shadow; +mod significant_drop_tightening; mod single_char_lifetime_names; mod single_component_path_imports; mod size_of_in_element_count; @@ -558,6 +560,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction)); store.register_late_pass(|_| Box::new(mut_mut::MutMut)); store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed)); + store.register_late_pass(|_| Box::>::default()); store.register_late_pass(|_| Box::new(len_zero::LenZero)); store.register_late_pass(|_| Box::new(attrs::Attributes)); store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs new file mode 100644 index 0000000000000..a509592a1a4ec --- /dev/null +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -0,0 +1,381 @@ +use crate::FxHashSet; +use clippy_utils::{ + diagnostics::span_lint_and_then, + get_attr, + source::{indent_of, snippet}, +}; +use rustc_errors::{Applicability, Diagnostic}; +use rustc_hir::{ + self as hir, + intravisit::{walk_expr, Visitor}, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{symbol::Ident, Span, DUMMY_SP}; + +declare_clippy_lint! { + /// ### What it does + /// + /// Searches for elements marked with `#[clippy::significant_drop]` that could be early + /// dropped but are in fact dropped at the end of their scopes. In other words, enforces the + /// "tightening" of their possible lifetimes. + /// + /// ### Why is this bad? + /// + /// Elements marked with `#[clippy::has_significant_drop]` are generally synchronizing + /// primitives that manage shared resources, as such, it is desired to release them as soon as + /// possible to avoid unnecessary resource contention. + /// + /// ### Example + /// + /// ```rust,ignore + /// fn main() { + /// let lock = some_sync_resource.lock(); + /// let owned_rslt = lock.do_stuff_with_resource(); + /// // Only `owned_rslt` is needed but `lock` is still held. + /// do_heavy_computation_that_takes_time(owned_rslt); + /// } + /// ``` + /// + /// Use instead: + /// + /// ```rust,ignore + /// fn main() { + /// let owned_rslt = some_sync_resource.lock().do_stuff_with_resource(); + /// do_heavy_computation_that_takes_time(owned_rslt); + /// } + /// ``` + #[clippy::version = "1.67.0"] + pub SIGNIFICANT_DROP_TIGHTENING, + nursery, + "Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes" +} + +impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); + +#[derive(Default)] +pub struct SignificantDropTightening<'tcx> { + /// Auxiliary structure used to avoid having to verify the same type multiple times. + seen_types: FxHashSet>, +} + +impl<'tcx> SignificantDropTightening<'tcx> { + /// Verifies if the expression is of type `drop(some_lock_path)` to assert that the temporary + /// is already being dropped before the end of its scope. + fn has_drop(expr: &'tcx hir::Expr<'_>, init_bind_ident: Ident) -> bool { + if let hir::ExprKind::Call(fun, args) = expr.kind + && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind + && let [fun_ident, ..] = fun_path.segments + && fun_ident.ident.name == rustc_span::sym::drop + && let [first_arg, ..] = args + && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind + && let [first_arg_ps, .. ] = arg_path.segments + { + first_arg_ps.ident == init_bind_ident + } + else { + false + } + } + + /// Tries to find types marked with `#[has_significant_drop]` of an expression `expr` that is + /// originated from `stmt` and then performs common logic on `sdap`. + fn modify_sdap_if_sig_drop_exists( + &mut self, + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + idx: usize, + sdap: &mut SigDropAuxParams, + stmt: &'tcx hir::Stmt<'_>, + cb: impl Fn(&mut SigDropAuxParams), + ) { + let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types); + sig_drop_finder.visit_expr(expr); + if sig_drop_finder.has_sig_drop { + cb(sdap); + if sdap.number_of_stmts > 0 { + sdap.last_use_stmt_idx = idx; + sdap.last_use_stmt_span = stmt.span; + if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind { + sdap.last_use_method_span = span; + } + } + sdap.number_of_stmts = sdap.number_of_stmts.wrapping_add(1); + } + } + + /// Shows a generic overall message as well as specialized messages depending on the usage. + fn set_suggestions(cx: &LateContext<'tcx>, block_span: Span, diag: &mut Diagnostic, sdap: &SigDropAuxParams) { + match sdap.number_of_stmts { + 0 | 1 => {}, + 2 => { + let indent = " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0)); + let init_method = snippet(cx, sdap.init_method_span, ".."); + let usage_method = snippet(cx, sdap.last_use_method_span, ".."); + let stmt = if let Some(last_use_bind_span) = sdap.last_use_bind_span { + format!( + "\n{indent}let {} = {init_method}.{usage_method};", + snippet(cx, last_use_bind_span, ".."), + ) + } else { + format!("\n{indent}{init_method}.{usage_method};") + }; + diag.span_suggestion_verbose( + sdap.init_stmt_span, + "merge the temporary construction with its single usage", + stmt, + Applicability::MaybeIncorrect, + ); + diag.span_suggestion( + sdap.last_use_stmt_span, + "remove separated single usage", + "", + Applicability::MaybeIncorrect, + ); + }, + _ => { + diag.span_suggestion( + sdap.last_use_stmt_span.shrink_to_hi(), + "drop the temporary after the end of its last usage", + format!( + "\n{}drop({});", + " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0)), + sdap.init_bind_ident + ), + Applicability::MaybeIncorrect, + ); + }, + } + diag.note("this might lead to unnecessary resource contention"); + diag.span_label( + block_span, + format!( + "temporary `{}` is currently being dropped at the end of its contained scope", + sdap.init_bind_ident + ), + ); + } +} + +impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { + let mut sdap = SigDropAuxParams::default(); + for (idx, stmt) in block.stmts.iter().enumerate() { + match stmt.kind { + hir::StmtKind::Expr(expr) => self.modify_sdap_if_sig_drop_exists( + cx, + expr, + idx, + &mut sdap, + stmt, + |_| {} + ), + hir::StmtKind::Local(local) if let Some(expr) = local.init => self.modify_sdap_if_sig_drop_exists( + cx, + expr, + idx, + &mut sdap, + stmt, + |local_sdap| { + if local_sdap.number_of_stmts == 0 { + if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { + local_sdap.init_bind_ident = ident; + } + if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr.kind { + local_sdap.init_method_span = local_expr.span.to(span); + } + local_sdap.init_stmt_span = stmt.span; + } + else if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { + local_sdap.last_use_bind_span = Some(ident.span); + } + } + ), + hir::StmtKind::Semi(expr) => { + if Self::has_drop(expr, sdap.init_bind_ident) { + return; + } + self.modify_sdap_if_sig_drop_exists(cx, expr, idx, &mut sdap, stmt, |_| {}); + }, + _ => continue + }; + } + if sdap.number_of_stmts > 1 && { + let last_stmts_idx = block.stmts.len().wrapping_sub(1); + sdap.last_use_stmt_idx != last_stmts_idx + } { + span_lint_and_then( + cx, + SIGNIFICANT_DROP_TIGHTENING, + sdap.init_bind_ident.span, + "temporary with significant `Drop` can be early dropped", + |diag| { + Self::set_suggestions(cx, block.span, diag, &sdap); + }, + ); + } + } +} + +/// Auxiliary parameters used on each block check. +struct SigDropAuxParams { + /// The binding or variable that references the initial construction of the type marked with + /// `#[has_significant_drop]`. + init_bind_ident: Ident, + /// Similar to `init_bind_ident` but encompasses the right-hand method call. + init_method_span: Span, + /// Similar to `init_bind_ident` but encompasses the whole contained statement. + init_stmt_span: Span, + + /// The last visited binding or variable span within a block that had any referenced inner type + /// marked with `#[has_significant_drop]`. + last_use_bind_span: Option, + /// Index of the last visited statement within a block that had any referenced inner type + /// marked with `#[has_significant_drop]`. + last_use_stmt_idx: usize, + /// Similar to `last_use_bind_span` but encompasses the whole contained statement. + last_use_stmt_span: Span, + /// Similar to `last_use_bind_span` but encompasses the right-hand method call. + last_use_method_span: Span, + + /// Total number of statements within a block that have any referenced inner type marked with + /// `#[has_significant_drop]`. + number_of_stmts: usize, +} + +impl Default for SigDropAuxParams { + fn default() -> Self { + Self { + init_bind_ident: Ident::empty(), + init_method_span: DUMMY_SP, + init_stmt_span: DUMMY_SP, + last_use_bind_span: None, + last_use_method_span: DUMMY_SP, + last_use_stmt_idx: 0, + last_use_stmt_span: DUMMY_SP, + number_of_stmts: 0, + } + } +} + +/// Checks the existence of the `#[has_significant_drop]` attribute +struct SigDropChecker<'cx, 'sdt, 'tcx> { + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet>, +} + +impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { + pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { + seen_types.clear(); + Self { cx, seen_types } + } + + pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + if let Some(adt) = ty.ty_adt_def() { + let iter = get_attr( + self.cx.sess(), + self.cx.tcx.get_attrs_unchecked(adt.did()), + "has_significant_drop", + ); + if iter.count() > 0 { + return true; + } + } + match ty.kind() { + rustc_middle::ty::Adt(a, b) => { + for f in a.all_fields() { + let ty = f.ty(self.cx.tcx, b); + if !self.has_seen_ty(ty) && self.has_sig_drop_attr(ty) { + return true; + } + } + for generic_arg in b.iter() { + if let GenericArgKind::Type(ty) = generic_arg.unpack() { + if self.has_sig_drop_attr(ty) { + return true; + } + } + } + false + }, + rustc_middle::ty::Array(ty, _) + | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. }) + | rustc_middle::ty::Ref(_, ty, _) + | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty), + _ => false, + } + } + + fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool { + !self.seen_types.insert(ty) + } +} + +/// Performs recursive calls to find any inner type marked with `#[has_significant_drop]`. +struct SigDropFinder<'cx, 'sdt, 'tcx> { + cx: &'cx LateContext<'tcx>, + has_sig_drop: bool, + sig_drop_checker: SigDropChecker<'cx, 'sdt, 'tcx>, +} + +impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> { + fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { + Self { + cx, + has_sig_drop: false, + sig_drop_checker: SigDropChecker::new(cx, seen_types), + } + } +} + +impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> { + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'_>) { + if self + .sig_drop_checker + .has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex)) + { + self.has_sig_drop = true; + return; + } + + match ex.kind { + hir::ExprKind::MethodCall(_, expr, ..) => { + self.visit_expr(expr); + }, + hir::ExprKind::Array(..) + | hir::ExprKind::Assign(..) + | hir::ExprKind::AssignOp(..) + | hir::ExprKind::Binary(..) + | hir::ExprKind::Box(..) + | hir::ExprKind::Call(..) + | hir::ExprKind::Field(..) + | hir::ExprKind::If(..) + | hir::ExprKind::Index(..) + | hir::ExprKind::Match(..) + | hir::ExprKind::Repeat(..) + | hir::ExprKind::Ret(..) + | hir::ExprKind::Tup(..) + | hir::ExprKind::Unary(..) + | hir::ExprKind::Yield(..) => { + walk_expr(self, ex); + }, + hir::ExprKind::AddrOf(_, _, _) + | hir::ExprKind::Block(_, _) + | hir::ExprKind::Break(_, _) + | hir::ExprKind::Cast(_, _) + | hir::ExprKind::Closure { .. } + | hir::ExprKind::ConstBlock(_) + | hir::ExprKind::Continue(_) + | hir::ExprKind::DropTemps(_) + | hir::ExprKind::Err + | hir::ExprKind::InlineAsm(_) + | hir::ExprKind::Let(_) + | hir::ExprKind::Lit(_) + | hir::ExprKind::Loop(_, _, _, _) + | hir::ExprKind::Path(_) + | hir::ExprKind::Struct(_, _, _) + | hir::ExprKind::Type(_, _) => {}, + } + } +} diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed new file mode 100644 index 0000000000000..7d56a87053fdb --- /dev/null +++ b/tests/ui/significant_drop_tightening.fixed @@ -0,0 +1,56 @@ +// run-rustfix + +#![warn(clippy::significant_drop_tightening)] + +use std::sync::Mutex; + +pub fn unnecessary_contention_with_multiple_owned_results() { + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let _ = lock.abs(); + let _ = lock.is_positive(); + } + + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let rslt0 = lock.abs(); + let rslt1 = lock.is_positive(); + drop(lock); + do_heavy_computation_that_takes_time((rslt0, rslt1)); + } +} + +pub fn unnecessary_contention_with_single_owned_results() { + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let _ = lock.abs(); + } + { + let mutex = Mutex::new(vec![1i32]); + let mut lock = mutex.lock().unwrap(); + lock.clear(); + } + + { + let mutex = Mutex::new(1i32); + + let rslt0 = mutex.lock().unwrap().abs(); + + do_heavy_computation_that_takes_time(rslt0); + } + { + let mutex = Mutex::new(vec![1i32]); + + mutex.lock().unwrap().clear(); + + do_heavy_computation_that_takes_time(()); + } +} + +// Marker used for illustration purposes. +pub fn do_heavy_computation_that_takes_time(_: T) {} + +fn main() {} diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs new file mode 100644 index 0000000000000..6f3ce328e5d94 --- /dev/null +++ b/tests/ui/significant_drop_tightening.rs @@ -0,0 +1,53 @@ +// run-rustfix + +#![warn(clippy::significant_drop_tightening)] + +use std::sync::Mutex; + +pub fn unnecessary_contention_with_multiple_owned_results() { + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let _ = lock.abs(); + let _ = lock.is_positive(); + } + + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let rslt0 = lock.abs(); + let rslt1 = lock.is_positive(); + do_heavy_computation_that_takes_time((rslt0, rslt1)); + } +} + +pub fn unnecessary_contention_with_single_owned_results() { + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let _ = lock.abs(); + } + { + let mutex = Mutex::new(vec![1i32]); + let mut lock = mutex.lock().unwrap(); + lock.clear(); + } + + { + let mutex = Mutex::new(1i32); + let lock = mutex.lock().unwrap(); + let rslt0 = lock.abs(); + do_heavy_computation_that_takes_time(rslt0); + } + { + let mutex = Mutex::new(vec![1i32]); + let mut lock = mutex.lock().unwrap(); + lock.clear(); + do_heavy_computation_that_takes_time(()); + } +} + +// Marker used for illustration purposes. +pub fn do_heavy_computation_that_takes_time(_: T) {} + +fn main() {} diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr new file mode 100644 index 0000000000000..52754aac78269 --- /dev/null +++ b/tests/ui/significant_drop_tightening.stderr @@ -0,0 +1,71 @@ +error: temporary with significant `Drop` can be early dropped + --> $DIR/significant_drop_tightening.rs:17:13 + | +LL | / { +LL | | let mutex = Mutex::new(1i32); +LL | | let lock = mutex.lock().unwrap(); + | | ^^^^ +LL | | let rslt0 = lock.abs(); +LL | | let rslt1 = lock.is_positive(); +LL | | do_heavy_computation_that_takes_time((rslt0, rslt1)); +LL | | } + | |_____- temporary `lock` is currently being dropped at the end of its contained scope + | + = note: this might lead to unnecessary resource contention + = note: `-D clippy::significant-drop-tightening` implied by `-D warnings` +help: drop the temporary after the end of its last usage + | +LL ~ let rslt1 = lock.is_positive(); +LL + drop(lock); + | + +error: temporary with significant `Drop` can be early dropped + --> $DIR/significant_drop_tightening.rs:38:13 + | +LL | / { +LL | | let mutex = Mutex::new(1i32); +LL | | let lock = mutex.lock().unwrap(); + | | ^^^^ +LL | | let rslt0 = lock.abs(); +LL | | do_heavy_computation_that_takes_time(rslt0); +LL | | } + | |_____- temporary `lock` is currently being dropped at the end of its contained scope + | + = note: this might lead to unnecessary resource contention +help: merge the temporary construction with its single usage + | +LL ~ +LL + let rslt0 = mutex.lock().unwrap().abs(); + | +help: remove separated single usage + | +LL - let rslt0 = lock.abs(); +LL + + | + +error: temporary with significant `Drop` can be early dropped + --> $DIR/significant_drop_tightening.rs:44:17 + | +LL | / { +LL | | let mutex = Mutex::new(vec![1i32]); +LL | | let mut lock = mutex.lock().unwrap(); + | | ^^^^ +LL | | lock.clear(); +LL | | do_heavy_computation_that_takes_time(()); +LL | | } + | |_____- temporary `lock` is currently being dropped at the end of its contained scope + | + = note: this might lead to unnecessary resource contention +help: merge the temporary construction with its single usage + | +LL ~ +LL + mutex.lock().unwrap().clear(); + | +help: remove separated single usage + | +LL - lock.clear(); +LL + + | + +error: aborting due to 3 previous errors + From 805a0ae2df4d85ec88497e32adcd1bb24a8729d1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 10 Feb 2023 22:35:23 +0100 Subject: [PATCH 14/90] Add more test cases for suspicious_command_arg_space. --- tests/ui/suspicious_command_arg_space.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/ui/suspicious_command_arg_space.rs b/tests/ui/suspicious_command_arg_space.rs index 74b230f430bfb..bdc6113a25001 100644 --- a/tests/ui/suspicious_command_arg_space.rs +++ b/tests/ui/suspicious_command_arg_space.rs @@ -1,5 +1,10 @@ fn main() { - std::process::Command::new("echo").arg("hello world").spawn().unwrap(); + // Things it should warn about: std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); std::process::Command::new("cat").arg("--number file").spawn().unwrap(); + + // Things it should not warn about: + std::process::Command::new("echo").arg("hello world").spawn().unwrap(); + std::process::Command::new("a").arg("--fmt=%a %b %c").spawn().unwrap(); + std::process::Command::new("b").arg("-ldflags=-s -w").spawn().unwrap(); } From 8789b37d06e74aef732b5bba1b88a9f4fefdee18 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Sat, 11 Feb 2023 12:22:25 -0500 Subject: [PATCH 15/90] Fix false positives for `extra_unused_type_parameters` --- .../src/extra_unused_type_parameters.rs | 49 +++++++++++++------ tests/ui/extra_unused_type_parameters.rs | 19 ++++++- tests/ui/extra_unused_type_parameters.stderr | 10 ++-- tests/ui/type_repetition_in_bounds.rs | 1 - tests/ui/type_repetition_in_bounds.stderr | 8 +-- 5 files changed, 61 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 2fdd8a71466c0..9e9ad80b3342f 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -4,10 +4,12 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; use rustc_hir::{ - GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate, + BodyId, ExprKind, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, + WherePredicate, }; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{def_id::DefId, Span}; @@ -55,10 +57,13 @@ struct TypeWalker<'cx, 'tcx> { /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic /// parameters are present, this will be set to `false`. all_params_unused: bool, + /// Whether or not the function has an empty body, in which case any bounded type parameters + /// will not be linted. + fn_body_empty: bool, } impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { - fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self { + fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>, body_id: BodyId) -> Self { let mut all_params_unused = true; let ty_params = generics .params @@ -74,12 +79,18 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { } }) .collect(); + + let body = cx.tcx.hir().body(body_id).value; + let fn_body_empty = + matches!(&body.kind, ExprKind::Block(block, None) if block.stmts.is_empty() && block.expr.is_none()); + Self { cx, ty_params, bounds: FxHashMap::default(), generics, all_params_unused, + fn_body_empty, } } @@ -96,7 +107,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { ), }; - let source_map = self.cx.tcx.sess.source_map(); + let source_map = self.cx.sess().source_map(); let span = if self.all_params_unused { self.generics.span.into() // Remove the entire list of generics } else { @@ -139,12 +150,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { if let WherePredicate::BoundPredicate(predicate) = predicate { - // Collect spans for bounds that appear in the list of generics (not in a where-clause) - // for use in forming the help message - if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() - && let PredicateOrigin::GenericParam = predicate.origin - { - self.bounds.insert(def_id, predicate.span); + // Collect spans for any bounds on type parameters. We only keep bounds that appear in + // the list of generics (not in a where-clause). + // + // Also, if the function body is empty, we don't lint the corresponding type parameters + // (See https://github.com/rust-lang/rust-clippy/issues/10319). + if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() { + if self.fn_body_empty { + self.ty_params.remove(&def_id); + } else if let PredicateOrigin::GenericParam = predicate.origin { + self.bounds.insert(def_id, predicate.span); + } } // Only walk the right-hand side of where-bounds for bound in predicate.bounds { @@ -160,8 +176,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Fn(_, generics, _) = item.kind { - let mut walker = TypeWalker::new(cx, generics); + if let ItemKind::Fn(_, generics, body_id) = item.kind + && !in_external_macro(cx.sess(), item.span) + { + let mut walker = TypeWalker::new(cx, generics, body_id); walk_item(&mut walker, item); walker.emit_lint(); } @@ -169,8 +187,11 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { // Only lint on inherent methods, not trait methods. - if let ImplItemKind::Fn(..) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { - let mut walker = TypeWalker::new(cx, item.generics); + if let ImplItemKind::Fn(.., body_id) = item.kind + && trait_ref_of_method(cx, item.owner_id.def_id).is_none() + && !in_external_macro(cx.sess(), item.span) + { + let mut walker = TypeWalker::new(cx, item.generics, body_id); walk_impl_item(&mut walker, item); walker.emit_lint(); } diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs index 5cb80cb6233f7..a1cd8a0d08518 100644 --- a/tests/ui/extra_unused_type_parameters.rs +++ b/tests/ui/extra_unused_type_parameters.rs @@ -15,15 +15,20 @@ fn used_ret(x: u8) -> T { T::default() } -fn unused_bounded(x: U) {} +fn unused_bounded(x: U) { + unimplemented!(); +} fn unused_where_clause(x: U) where T: Default, { + unimplemented!(); } -fn some_unused, E>(b: B, c: C) {} +fn some_unused, E>(b: B, c: C) { + unimplemented!(); +} fn used_opaque(iter: impl Iterator) -> usize { iter.count() @@ -66,4 +71,14 @@ where .filter_map(move |(i, a)| if i == index { None } else { Some(a) }) } +mod issue10319 { + fn assert_send() {} + + fn assert_send_where() + where + T: Send, + { + } +} + fn main() {} diff --git a/tests/ui/extra_unused_type_parameters.stderr b/tests/ui/extra_unused_type_parameters.stderr index 1c8dd53e63859..69a067bd8490f 100644 --- a/tests/ui/extra_unused_type_parameters.stderr +++ b/tests/ui/extra_unused_type_parameters.stderr @@ -26,13 +26,13 @@ LL | fn unused_with_lt<'a, T>(x: &'a u8) {} error: type parameter goes unused in function definition --> $DIR/extra_unused_type_parameters.rs:18:19 | -LL | fn unused_bounded(x: U) {} +LL | fn unused_bounded(x: U) { | ^^^^^^^^^^^ | = help: consider removing the parameter error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:20:24 + --> $DIR/extra_unused_type_parameters.rs:22:24 | LL | fn unused_where_clause(x: U) | ^^ @@ -40,15 +40,15 @@ LL | fn unused_where_clause(x: U) = help: consider removing the parameter error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:26:16 + --> $DIR/extra_unused_type_parameters.rs:29:16 | -LL | fn some_unused, E>(b: B, c: C) {} +LL | fn some_unused, E>(b: B, c: C) { | ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ | = help: consider removing the parameters error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:49:22 + --> $DIR/extra_unused_type_parameters.rs:54:22 | LL | fn unused_ty_impl(&self) {} | ^^^ diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs index 8b4613b3f6ec7..2eca1f4701c9f 100644 --- a/tests/ui/type_repetition_in_bounds.rs +++ b/tests/ui/type_repetition_in_bounds.rs @@ -1,5 +1,4 @@ #![deny(clippy::type_repetition_in_bounds)] -#![allow(clippy::extra_unused_type_parameters)] use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr index a90df03c04ffc..70d700c1cc460 100644 --- a/tests/ui/type_repetition_in_bounds.stderr +++ b/tests/ui/type_repetition_in_bounds.stderr @@ -1,5 +1,5 @@ error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:9:5 + --> $DIR/type_repetition_in_bounds.rs:8:5 | LL | T: Clone, | ^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::type_repetition_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:26:5 + --> $DIR/type_repetition_in_bounds.rs:25:5 | LL | Self: Copy + Default + Ord, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | Self: Copy + Default + Ord, = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:86:5 + --> $DIR/type_repetition_in_bounds.rs:85:5 | LL | T: Clone, | ^^^^^^^^ @@ -28,7 +28,7 @@ LL | T: Clone, = help: consider combining the bounds: `T: ?Sized + Clone` error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:91:5 + --> $DIR/type_repetition_in_bounds.rs:90:5 | LL | T: ?Sized, | ^^^^^^^^^ From d9dc1679f50344e60a69e4e7f93acb8081d009a4 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 12 Feb 2023 08:51:33 +0100 Subject: [PATCH 16/90] cast_possible_truncation: issue proper help message --- .../src/casts/cast_possible_truncation.rs | 2 +- tests/ui/cast.stderr | 36 +++++++++---------- tests/ui/cast_size.stderr | 18 +++++----- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index f3f8b8d87982e..823970e35abbd 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -168,7 +168,7 @@ pub(super) fn check( let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})"); span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| { - diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ..."); + diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ..."); diag.span_suggestion_with_style( expr.span, "... or use `try_from` and handle the error accordingly", diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 4af1de9aa38d3..451078de23b22 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -42,7 +42,7 @@ error: casting `f32` to `i32` may truncate the value LL | 1f32 as i32; | ^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` help: ... or use `try_from` and handle the error accordingly | @@ -55,7 +55,7 @@ error: casting `f32` to `u32` may truncate the value LL | 1f32 as u32; | ^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | u32::try_from(1f32); @@ -75,7 +75,7 @@ error: casting `f64` to `f32` may truncate the value LL | 1f64 as f32; | ^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | f32::try_from(1f64); @@ -87,7 +87,7 @@ error: casting `i32` to `i8` may truncate the value LL | 1i32 as i8; | ^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | i8::try_from(1i32); @@ -99,7 +99,7 @@ error: casting `i32` to `u8` may truncate the value LL | 1i32 as u8; | ^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | u8::try_from(1i32); @@ -111,7 +111,7 @@ error: casting `f64` to `isize` may truncate the value LL | 1f64 as isize; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | isize::try_from(1f64); @@ -123,7 +123,7 @@ error: casting `f64` to `usize` may truncate the value LL | 1f64 as usize; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | usize::try_from(1f64); @@ -141,7 +141,7 @@ error: casting `u32` to `u16` may truncate the value LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | u16::try_from(1f32 as u32); @@ -153,7 +153,7 @@ error: casting `f32` to `u32` may truncate the value LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | u32::try_from(1f32) as u16; @@ -215,7 +215,7 @@ error: casting `i64` to `i8` may truncate the value LL | (-99999999999i64).min(1) as i8; // should be linted because signed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | i8::try_from((-99999999999i64).min(1)); // should be linted because signed @@ -227,7 +227,7 @@ error: casting `u64` to `u8` may truncate the value LL | 999999u64.clamp(0, 256) as u8; // should still be linted | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted @@ -239,7 +239,7 @@ error: casting `main::E2` to `u8` may truncate the value LL | let _ = self as u8; | ^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | let _ = u8::try_from(self); @@ -259,7 +259,7 @@ error: casting `main::E5` to `i8` may truncate the value LL | let _ = self as i8; | ^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | let _ = i8::try_from(self); @@ -277,7 +277,7 @@ error: casting `main::E6` to `i16` may truncate the value LL | let _ = self as i16; | ^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | let _ = i16::try_from(self); @@ -289,7 +289,7 @@ error: casting `main::E7` to `usize` may truncate the value on targets with 32-b LL | let _ = self as usize; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | let _ = usize::try_from(self); @@ -301,7 +301,7 @@ error: casting `main::E10` to `u16` may truncate the value LL | let _ = self as u16; | ^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | let _ = u16::try_from(self); @@ -313,7 +313,7 @@ error: casting `u32` to `u8` may truncate the value LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | let c = u8::try_from((q >> 16)); @@ -325,7 +325,7 @@ error: casting `u32` to `u8` may truncate the value LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | let c = u8::try_from((q / 1000)); diff --git a/tests/ui/cast_size.stderr b/tests/ui/cast_size.stderr index 8acf26049f4d1..6d2d49d9ed208 100644 --- a/tests/ui/cast_size.stderr +++ b/tests/ui/cast_size.stderr @@ -4,7 +4,7 @@ error: casting `isize` to `i8` may truncate the value LL | 1isize as i8; | ^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` help: ... or use `try_from` and handle the error accordingly | @@ -43,7 +43,7 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi LL | 1isize as i32; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | i32::try_from(1isize); @@ -55,7 +55,7 @@ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wi LL | 1isize as u32; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | u32::try_from(1isize); @@ -67,7 +67,7 @@ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wi LL | 1usize as u32; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | u32::try_from(1usize); @@ -79,7 +79,7 @@ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wi LL | 1usize as i32; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | i32::try_from(1usize); @@ -99,7 +99,7 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi LL | 1i64 as isize; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | isize::try_from(1i64); @@ -111,7 +111,7 @@ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wi LL | 1i64 as usize; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | usize::try_from(1i64); @@ -123,7 +123,7 @@ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wi LL | 1u64 as isize; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | isize::try_from(1u64); @@ -141,7 +141,7 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi LL | 1u64 as usize; | ^^^^^^^^^^^^^ | - = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | LL | usize::try_from(1u64); From aeaa1cc342415ae0953a74fc4ac1ee76e48ed2ea Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 12 Feb 2023 14:48:44 +0100 Subject: [PATCH 17/90] lintcheck: fix clap panic --- lintcheck/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lintcheck/src/config.rs b/lintcheck/src/config.rs index b8824024e6c78..e0244ddcecb80 100644 --- a/lintcheck/src/config.rs +++ b/lintcheck/src/config.rs @@ -35,7 +35,7 @@ fn get_clap_config() -> ArgMatches { .long("markdown") .help("Change the reports table to use markdown links"), Arg::new("recursive") - .long("--recursive") + .long("recursive") .help("Run clippy on the dependencies of crates specified in crates-toml") .conflicts_with("threads") .conflicts_with("fix"), From 21433abceaf5b1929e416bfca8fb58473cf95efc Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 12 Feb 2023 15:18:38 +0100 Subject: [PATCH 18/90] book: move warning to the right place --- book/src/development/infrastructure/backport.md | 1 + book/src/development/infrastructure/sync.md | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/development/infrastructure/backport.md b/book/src/development/infrastructure/backport.md index 15f3d1f080604..6920c4e465619 100644 --- a/book/src/development/infrastructure/backport.md +++ b/book/src/development/infrastructure/backport.md @@ -28,6 +28,7 @@ repository. You can do this with: ```bash # Assuming the current directory corresponds to the Rust repository $ git checkout beta +# Make sure to change `your-github-name` to your github name in the following command $ git subtree pull -p src/tools/clippy https://github.com//rust-clippy backport $ ./x.py test src/tools/clippy ``` diff --git a/book/src/development/infrastructure/sync.md b/book/src/development/infrastructure/sync.md index 5a0f7409a2e4c..02cfc11b55acb 100644 --- a/book/src/development/infrastructure/sync.md +++ b/book/src/development/infrastructure/sync.md @@ -79,8 +79,7 @@ to be run inside the `rust` directory): `rustup check`. 3. Sync the changes to the rust-copy of Clippy to your Clippy fork: ```bash - # Make sure to change `your-github-name` to your github name in the following command. Also be - # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand + # Be sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand # because changes cannot be fast forwarded and you have to run this command again. git subtree push -P src/tools/clippy clippy-local sync-from-rust ``` From 09d3097734883a78b69f111a9ecf2154c7da9ce7 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 12 Feb 2023 15:40:06 +0100 Subject: [PATCH 19/90] manual_let_else: do not suggest semantically different replacements --- clippy_lints/src/manual_let_else.rs | 7 +++++++ tests/ui/manual_let_else_match.rs | 29 +++++++++++++++++++++++++-- tests/ui/manual_let_else_match.stderr | 15 +++++++++++--- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 9c6f8b43c078f..9eacb38351407 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -115,6 +115,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse { .enumerate() .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types)); let Some((idx, diverging_arm)) = diverging_arm_opt else { return; }; + // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement. + // However, if it arrives in second position, its pattern may cover some cases already covered + // by the diverging one. + // TODO: accept the non-diverging arm as a second position if patterns are disjointed. + if idx == 0 { + return; + } let pat_arm = &arms[1 - idx]; if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) { return; diff --git a/tests/ui/manual_let_else_match.rs b/tests/ui/manual_let_else_match.rs index 28caed9d79df2..73b7467912597 100644 --- a/tests/ui/manual_let_else_match.rs +++ b/tests/ui/manual_let_else_match.rs @@ -42,13 +42,13 @@ fn fire() { loop { // More complex pattern for the identity arm and diverging arm let v = match h() { - (Some(_), Some(_)) | (None, None) => continue, (Some(v), None) | (None, Some(v)) => v, + (Some(_), Some(_)) | (None, None) => continue, }; // Custom enums are supported as long as the "else" arm is a simple _ let v = match build_enum() { - _ => continue, Variant::Bar(v) | Variant::Baz(v) => v, + _ => continue, }; } @@ -71,6 +71,12 @@ fn fire() { Variant::Bar(_) | Variant::Baz(_) => (), _ => return, }; + + let data = [1_u8, 2, 3, 4, 0, 0, 0, 0]; + let data = match data.as_slice() { + [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data, + _ => return, + }; } fn not_fire() { @@ -125,4 +131,23 @@ fn not_fire() { Ok(v) | Err(Variant::Bar(v) | Variant::Baz(v)) => v, Err(Variant::Foo) => return, }; + + // Issue 10241 + // The non-divergent arm arrives in second position and + // may cover values already matched in the first arm. + let v = match h() { + (Some(_), Some(_)) | (None, None) => return, + (Some(v), _) | (None, Some(v)) => v, + }; + + let v = match build_enum() { + _ => return, + Variant::Bar(v) | Variant::Baz(v) => v, + }; + + let data = [1_u8, 2, 3, 4, 0, 0, 0, 0]; + let data = match data.as_slice() { + [] | [0, 0] => return, + [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data, + }; } diff --git a/tests/ui/manual_let_else_match.stderr b/tests/ui/manual_let_else_match.stderr index cd5e9a9ac39c0..7abaa0b85d23e 100644 --- a/tests/ui/manual_let_else_match.stderr +++ b/tests/ui/manual_let_else_match.stderr @@ -22,8 +22,8 @@ error: this could be rewritten as `let...else` --> $DIR/manual_let_else_match.rs:44:9 | LL | / let v = match h() { -LL | | (Some(_), Some(_)) | (None, None) => continue, LL | | (Some(v), None) | (None, Some(v)) => v, +LL | | (Some(_), Some(_)) | (None, None) => continue, LL | | }; | |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };` @@ -31,8 +31,8 @@ error: this could be rewritten as `let...else` --> $DIR/manual_let_else_match.rs:49:9 | LL | / let v = match build_enum() { -LL | | _ => continue, LL | | Variant::Bar(v) | Variant::Baz(v) => v, +LL | | _ => continue, LL | | }; | |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };` @@ -63,5 +63,14 @@ LL | | _ => return, LL | | }; | |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };` -error: aborting due to 7 previous errors +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else_match.rs:76:5 + | +LL | / let data = match data.as_slice() { +LL | | [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data, +LL | | _ => return, +LL | | }; + | |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };` + +error: aborting due to 8 previous errors From 1b286b128b529d558f92f8dda39ae72759c3fa15 Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 12 Feb 2023 16:17:37 -0300 Subject: [PATCH 20/90] Address comments --- .../src/significant_drop_tightening.rs | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index a509592a1a4ec..4cc85e3856462 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -273,12 +273,12 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { if let Some(adt) = ty.ty_adt_def() { - let iter = get_attr( + let mut iter = get_attr( self.cx.sess(), self.cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop", ); - if iter.count() > 0 { + if iter.next().is_some() { return true; } } @@ -360,22 +360,7 @@ impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> { | hir::ExprKind::Yield(..) => { walk_expr(self, ex); }, - hir::ExprKind::AddrOf(_, _, _) - | hir::ExprKind::Block(_, _) - | hir::ExprKind::Break(_, _) - | hir::ExprKind::Cast(_, _) - | hir::ExprKind::Closure { .. } - | hir::ExprKind::ConstBlock(_) - | hir::ExprKind::Continue(_) - | hir::ExprKind::DropTemps(_) - | hir::ExprKind::Err - | hir::ExprKind::InlineAsm(_) - | hir::ExprKind::Let(_) - | hir::ExprKind::Lit(_) - | hir::ExprKind::Loop(_, _, _, _) - | hir::ExprKind::Path(_) - | hir::ExprKind::Struct(_, _, _) - | hir::ExprKind::Type(_, _) => {}, + _ => {}, } } } From e70a7a68bda5d2f5a53a59f26ff87577eade5839 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 9 Feb 2023 16:46:13 -0300 Subject: [PATCH 21/90] [arithmetic_side_effects] Evaluate integers originated from constant declarations --- .../src/operators/arithmetic_side_effects.rs | 23 +- tests/ui/arithmetic_side_effects.rs | 27 +++ tests/ui/arithmetic_side_effects.stderr | 198 +++++++++--------- 3 files changed, 140 insertions(+), 108 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index d592f6e814c1d..4736c4b802d56 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -1,6 +1,6 @@ use super::ARITHMETIC_SIDE_EFFECTS; use clippy_utils::{ - consts::{constant, constant_simple}, + consts::{constant, constant_simple, Constant}, diagnostics::span_lint, peel_hir_expr_refs, peel_hir_expr_unary, }; @@ -97,17 +97,19 @@ impl ArithmeticSideEffects { self.expr_span = Some(expr.span); } - /// If `expr` is not a literal integer like `1`, returns `None`. + /// Returns the numeric value of a literal integer originated from `expr`, if any. /// - /// Returns the absolute value of the expression, if this is an integer literal. - fn literal_integer(expr: &hir::Expr<'_>) -> Option { + /// Literal integers can be originated from adhoc declarations like `1`, associated constants + /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`, + fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { let actual = peel_hir_expr_unary(expr).0; if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { - Some(n) + return Some(n) } - else { - None + if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) { + return Some(n); } + None } /// Manages when the lint should be triggered. Operations in constant environments, hard coded @@ -143,7 +145,10 @@ impl ArithmeticSideEffects { let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) { let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs); let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); - match (Self::literal_integer(actual_lhs), Self::literal_integer(actual_rhs)) { + match ( + Self::literal_integer(cx, actual_lhs), + Self::literal_integer(cx, actual_rhs), + ) { (None, None) => false, (None, Some(n)) | (Some(n), None) => match (&op.node, n) { (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false, @@ -180,7 +185,7 @@ impl ArithmeticSideEffects { return; } let actual_un_expr = peel_hir_expr_refs(un_expr).0; - if Self::literal_integer(actual_un_expr).is_some() { + if Self::literal_integer(cx, actual_un_expr).is_some() { return; } self.issue_lint(cx, expr); diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index 918cf81c600af..2611e3a785f6f 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -13,6 +13,9 @@ use core::num::{Saturating, Wrapping}; +const ONE: i32 = 1; +const ZERO: i32 = 0; + #[derive(Clone, Copy)] pub struct Custom; @@ -182,6 +185,10 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n += &0; _n -= 0; _n -= &0; + _n += ZERO; + _n += &ZERO; + _n -= ZERO; + _n -= &ZERO; _n /= 99; _n /= &99; _n %= 99; @@ -190,10 +197,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n *= &0; _n *= 1; _n *= &1; + _n *= ZERO; + _n *= &ZERO; + _n *= ONE; + _n *= &ONE; _n += -0; _n += &-0; _n -= -0; _n -= &-0; + _n += -ZERO; + _n += &-ZERO; + _n -= -ZERO; + _n -= &-ZERO; _n /= -99; _n /= &-99; _n %= -99; @@ -208,10 +223,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n = _n + &0; _n = 0 + _n; _n = &0 + _n; + _n = _n + ZERO; + _n = _n + &ZERO; + _n = ZERO + _n; + _n = &ZERO + _n; _n = _n - 0; _n = _n - &0; _n = 0 - _n; _n = &0 - _n; + _n = _n - ZERO; + _n = _n - &ZERO; + _n = ZERO - _n; + _n = &ZERO - _n; _n = _n / 99; _n = _n / &99; _n = _n % 99; @@ -222,6 +245,10 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n = &0 * _n; _n = _n * 1; _n = _n * &1; + _n = ZERO * _n; + _n = &ZERO * _n; + _n = _n * ONE; + _n = _n * &ONE; _n = 1 * _n; _n = &1 * _n; _n = 23 + 85; diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 5e349f6b497cd..17a2448fbfcad 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:243:5 + --> $DIR/arithmetic_side_effects.rs:270:5 | LL | _n += 1; | ^^^^^^^ @@ -7,589 +7,589 @@ LL | _n += 1; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:244:5 + --> $DIR/arithmetic_side_effects.rs:271:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:245:5 + --> $DIR/arithmetic_side_effects.rs:272:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:246:5 + --> $DIR/arithmetic_side_effects.rs:273:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:247:5 + --> $DIR/arithmetic_side_effects.rs:274:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:248:5 + --> $DIR/arithmetic_side_effects.rs:275:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:249:5 + --> $DIR/arithmetic_side_effects.rs:276:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:250:5 + --> $DIR/arithmetic_side_effects.rs:277:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:251:5 + --> $DIR/arithmetic_side_effects.rs:278:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:252:5 + --> $DIR/arithmetic_side_effects.rs:279:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:253:5 + --> $DIR/arithmetic_side_effects.rs:280:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:254:5 + --> $DIR/arithmetic_side_effects.rs:281:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:255:5 + --> $DIR/arithmetic_side_effects.rs:282:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:256:5 + --> $DIR/arithmetic_side_effects.rs:283:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:257:5 + --> $DIR/arithmetic_side_effects.rs:284:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:258:5 + --> $DIR/arithmetic_side_effects.rs:285:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:259:5 + --> $DIR/arithmetic_side_effects.rs:286:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:260:5 + --> $DIR/arithmetic_side_effects.rs:287:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:261:5 + --> $DIR/arithmetic_side_effects.rs:288:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:262:5 + --> $DIR/arithmetic_side_effects.rs:289:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:263:5 + --> $DIR/arithmetic_side_effects.rs:290:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:264:5 + --> $DIR/arithmetic_side_effects.rs:291:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:265:5 + --> $DIR/arithmetic_side_effects.rs:292:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:266:5 + --> $DIR/arithmetic_side_effects.rs:293:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:267:5 + --> $DIR/arithmetic_side_effects.rs:294:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:268:5 + --> $DIR/arithmetic_side_effects.rs:295:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:269:5 + --> $DIR/arithmetic_side_effects.rs:296:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:270:5 + --> $DIR/arithmetic_side_effects.rs:297:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:271:5 + --> $DIR/arithmetic_side_effects.rs:298:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:272:5 + --> $DIR/arithmetic_side_effects.rs:299:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:273:5 + --> $DIR/arithmetic_side_effects.rs:300:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:274:5 + --> $DIR/arithmetic_side_effects.rs:301:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:275:5 + --> $DIR/arithmetic_side_effects.rs:302:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:276:5 + --> $DIR/arithmetic_side_effects.rs:303:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:277:5 + --> $DIR/arithmetic_side_effects.rs:304:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:278:5 + --> $DIR/arithmetic_side_effects.rs:305:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:279:5 + --> $DIR/arithmetic_side_effects.rs:306:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:280:5 + --> $DIR/arithmetic_side_effects.rs:307:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:281:5 + --> $DIR/arithmetic_side_effects.rs:308:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:282:5 + --> $DIR/arithmetic_side_effects.rs:309:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:285:10 + --> $DIR/arithmetic_side_effects.rs:312:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:286:10 + --> $DIR/arithmetic_side_effects.rs:313:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:287:10 + --> $DIR/arithmetic_side_effects.rs:314:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:288:10 + --> $DIR/arithmetic_side_effects.rs:315:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:289:10 + --> $DIR/arithmetic_side_effects.rs:316:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:290:10 + --> $DIR/arithmetic_side_effects.rs:317:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:291:10 + --> $DIR/arithmetic_side_effects.rs:318:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:292:10 + --> $DIR/arithmetic_side_effects.rs:319:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:293:10 + --> $DIR/arithmetic_side_effects.rs:320:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:294:10 + --> $DIR/arithmetic_side_effects.rs:321:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:295:10 + --> $DIR/arithmetic_side_effects.rs:322:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:296:10 + --> $DIR/arithmetic_side_effects.rs:323:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:297:10 + --> $DIR/arithmetic_side_effects.rs:324:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:298:10 + --> $DIR/arithmetic_side_effects.rs:325:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:299:10 + --> $DIR/arithmetic_side_effects.rs:326:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:300:10 + --> $DIR/arithmetic_side_effects.rs:327:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:301:10 + --> $DIR/arithmetic_side_effects.rs:328:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:302:10 + --> $DIR/arithmetic_side_effects.rs:329:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:303:10 + --> $DIR/arithmetic_side_effects.rs:330:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:304:15 + --> $DIR/arithmetic_side_effects.rs:331:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:305:15 + --> $DIR/arithmetic_side_effects.rs:332:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:306:15 + --> $DIR/arithmetic_side_effects.rs:333:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:307:15 + --> $DIR/arithmetic_side_effects.rs:334:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:308:15 + --> $DIR/arithmetic_side_effects.rs:335:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:309:15 + --> $DIR/arithmetic_side_effects.rs:336:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:310:15 + --> $DIR/arithmetic_side_effects.rs:337:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:311:15 + --> $DIR/arithmetic_side_effects.rs:338:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:312:15 + --> $DIR/arithmetic_side_effects.rs:339:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:313:15 + --> $DIR/arithmetic_side_effects.rs:340:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:314:15 + --> $DIR/arithmetic_side_effects.rs:341:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:315:15 + --> $DIR/arithmetic_side_effects.rs:342:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:316:15 + --> $DIR/arithmetic_side_effects.rs:343:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:317:15 + --> $DIR/arithmetic_side_effects.rs:344:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:318:15 + --> $DIR/arithmetic_side_effects.rs:345:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:319:15 + --> $DIR/arithmetic_side_effects.rs:346:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:320:15 + --> $DIR/arithmetic_side_effects.rs:347:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:321:15 + --> $DIR/arithmetic_side_effects.rs:348:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:322:15 + --> $DIR/arithmetic_side_effects.rs:349:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:325:10 + --> $DIR/arithmetic_side_effects.rs:352:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:326:10 + --> $DIR/arithmetic_side_effects.rs:353:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:327:15 + --> $DIR/arithmetic_side_effects.rs:354:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:328:15 + --> $DIR/arithmetic_side_effects.rs:355:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:337:5 + --> $DIR/arithmetic_side_effects.rs:364:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:338:5 + --> $DIR/arithmetic_side_effects.rs:365:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:340:5 + --> $DIR/arithmetic_side_effects.rs:367:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:341:5 + --> $DIR/arithmetic_side_effects.rs:368:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:342:5 + --> $DIR/arithmetic_side_effects.rs:369:5 | LL | i >> 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:343:5 + --> $DIR/arithmetic_side_effects.rs:370:5 | LL | i << 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:352:5 + --> $DIR/arithmetic_side_effects.rs:379:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:353:5 + --> $DIR/arithmetic_side_effects.rs:380:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:354:5 + --> $DIR/arithmetic_side_effects.rs:381:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:356:5 + --> $DIR/arithmetic_side_effects.rs:383:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:358:5 + --> $DIR/arithmetic_side_effects.rs:385:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:359:5 + --> $DIR/arithmetic_side_effects.rs:386:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:361:5 + --> $DIR/arithmetic_side_effects.rs:388:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:363:5 + --> $DIR/arithmetic_side_effects.rs:390:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:364:5 + --> $DIR/arithmetic_side_effects.rs:391:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:365:5 + --> $DIR/arithmetic_side_effects.rs:392:5 | LL | i <<= 3; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:366:5 + --> $DIR/arithmetic_side_effects.rs:393:5 | LL | i >>= 2; | ^^^^^^^ From 1ed8ed3435ab5dca63694d536f91b1d225da868d Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 12 Feb 2023 16:27:30 -0300 Subject: [PATCH 22/90] Address comment --- clippy_lints/src/operators/arithmetic_side_effects.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 4736c4b802d56..87a8a2ed12b2a 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -2,7 +2,7 @@ use super::ARITHMETIC_SIDE_EFFECTS; use clippy_utils::{ consts::{constant, constant_simple, Constant}, diagnostics::span_lint, - peel_hir_expr_refs, peel_hir_expr_unary, + is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary, }; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -191,14 +191,16 @@ impl ArithmeticSideEffects { self.issue_lint(cx, expr); } - fn should_skip_expr(&mut self, expr: &hir::Expr<'_>) -> bool { - self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) + fn should_skip_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) + || self.expr_span.is_some() + || self.const_span.map_or(false, |sp| sp.contains(expr.span)) } } impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) { - if self.should_skip_expr(expr) { + if self.should_skip_expr(cx, expr) { return; } match &expr.kind { From 1f77866991568557e69e2135369ab2a512052a6b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 12 Feb 2023 22:00:13 +0100 Subject: [PATCH 23/90] Add SUSPICIOUS_COMMAND_ARG_SPACE to lint pass. --- clippy_lints/src/methods/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7e34d08ea32c4..d8c018f7591a9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3316,6 +3316,7 @@ impl_lint_pass!(Methods => [ SEEK_FROM_CURRENT, SEEK_TO_START_INSTEAD_OF_REWIND, NEEDLESS_COLLECT, + SUSPICIOUS_COMMAND_ARG_SPACE, ]); /// Extracts a method call name, args, and `Span` of the method name. From ebca1b5d008f87bb0d5712144f68dce18b28c261 Mon Sep 17 00:00:00 2001 From: chansuke Date: Sun, 8 Jan 2023 20:02:50 +0900 Subject: [PATCH 24/90] Refactor `almost_swapped` to lint with `let` statement correctly --- clippy_lints/src/swap.rs | 167 +++++++++++---------------------- tests/ui/almost_swapped.rs | 32 ------- tests/ui/almost_swapped.stderr | 30 ------ tests/ui/swap.fixed | 24 ++++- tests/ui/swap.rs | 29 +++++- tests/ui/swap.stderr | 65 ++++++++++--- 6 files changed, 159 insertions(+), 188 deletions(-) delete mode 100644 tests/ui/almost_swapped.rs delete mode 100644 tests/ui/almost_swapped.stderr diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 5c408a73a55b2..0f062cecf886c 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{sym, symbol::Ident, Span}; declare_clippy_lint! { /// ### What it does @@ -172,129 +172,76 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { } } -#[allow(clippy::too_many_lines)] /// Implementation of the `ALMOST_SWAPPED` lint. fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { - for w in block.stmts.windows(2) { - if_chain! { - if let StmtKind::Semi(first) = w[0].kind; - if let StmtKind::Semi(second) = w[1].kind; - if first.span.ctxt() == second.span.ctxt(); - if let ExprKind::Assign(lhs0, rhs0, _) = first.kind; - if let ExprKind::Assign(lhs1, rhs1, _) = second.kind; - if eq_expr_value(cx, lhs0, rhs1); - if eq_expr_value(cx, lhs1, rhs0); - then { - let lhs0 = Sugg::hir_opt(cx, lhs0); - let rhs0 = Sugg::hir_opt(cx, rhs0); - let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) { - ( - format!(" `{first}` and `{second}`"), - first.mut_addr().to_string(), - second.mut_addr().to_string(), - ) - } else { - (String::new(), String::new(), String::new()) - }; - - let span = first.span.to(second.span); - let Some(sugg) = std_or_core(cx) else { return }; - - span_lint_and_then(cx, - ALMOST_SWAPPED, - span, - &format!("this looks like you are trying to swap{what}"), - |diag| { - if !what.is_empty() { - diag.span_suggestion( - span, - "try", - format!( - "{sugg}::mem::swap({lhs}, {rhs})", - ), - Applicability::MaybeIncorrect, - ); - diag.note( - format!("or maybe you should use `{sugg}::mem::replace`?") - ); - } - }); + for [first, second] in block.stmts.array_windows() { + if let Some((lhs0, rhs0)) = parse(first) + && let Some((lhs1, rhs1)) = parse(second) + && first.span.eq_ctxt(second.span) + && is_same(cx, lhs0, rhs1) + && is_same(cx, lhs1, rhs0) + && let Some(lhs_sugg) = match &lhs0 { + ExprOrIdent::Expr(expr) => Sugg::hir_opt(cx, expr), + ExprOrIdent::Ident(ident) => Some(Sugg::NonParen(ident.as_str().into())), } - } - - let lint_almost_swapped_note = |span, what: String, sugg, lhs, rhs| { + && let Some(rhs_sugg) = Sugg::hir_opt(cx, rhs0) + { + let span = first.span.to(rhs1.span); + let Some(sugg) = std_or_core(cx) else { return }; span_lint_and_then( cx, ALMOST_SWAPPED, span, - &format!("this looks like you are trying to swap{}", what), + &format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"), |diag| { - if !what.is_empty() { - diag.note(&format!( - "maybe you could use `{sugg}::mem::swap({lhs}, {rhs})` or `{sugg}::mem::replace`?" - )); - } + diag.span_suggestion( + span, + "try", + format!("{sugg}::mem::swap({}, {})", lhs_sugg.mut_addr(), rhs_sugg.mut_addr()), + Applicability::MaybeIncorrect, + ); + diag.note(format!("or maybe you should use `{sugg}::mem::replace`?")); }, ); - }; - - if let StmtKind::Local(first) = w[0].kind - && let StmtKind::Local(second) = w[1].kind - && first.span.ctxt() == second.span.ctxt() - && let Some(rhs0) = first.init - && let Some(rhs1) = second.init - && let ExprKind::Path(QPath::Resolved(None, path_l)) = rhs0.kind - && let ExprKind::Path(QPath::Resolved(None, path_r)) = rhs1.kind - && let PatKind::Binding(_,_, ident_l,_) = first.pat.kind - && let PatKind::Binding(_,_, ident_r,_) = second.pat.kind - && ident_l.name.as_str() == path_r.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") - && ident_r.name.as_str() == path_l.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") - { - let rhs0 = Sugg::hir_opt(cx, rhs0); - let (what, lhs, rhs) = if let Some(second) = rhs0 { - ( - format!(" `{}` and `{}`", ident_l, second), - format!("&mut {}", ident_l), - second.mut_addr().to_string(), - ) - } else { - (String::new(), String::new(), String::new()) - }; - let span = first.span.to(second.span); - let Some(sugg) = std_or_core(cx) else { return }; + } + } +} - lint_almost_swapped_note(span, what, sugg, lhs, rhs); - } +fn is_same(cx: &LateContext<'_>, lhs: ExprOrIdent<'_>, rhs: &Expr<'_>) -> bool { + match lhs { + ExprOrIdent::Expr(expr) => eq_expr_value(cx, expr, rhs), + ExprOrIdent::Ident(ident) => { + if let ExprKind::Path(QPath::Resolved(None, path)) = rhs.kind + && let [segment] = &path.segments + && segment.ident == ident + { + true + } else { + false + } + } + } +} - if let StmtKind::Local(first) = w[0].kind - && let StmtKind::Semi(second) = w[1].kind - && first.span.ctxt() == second.span.ctxt() - && let Some(rhs0) = first.init - && let ExprKind::Path(QPath::Resolved(None, path_l)) = rhs0.kind - && let PatKind::Binding(_,_, ident_l,_) = first.pat.kind - && let ExprKind::Assign(lhs1, rhs1, _) = second.kind - && let ExprKind::Path(QPath::Resolved(None, lhs1_path)) = lhs1.kind - && let ExprKind::Path(QPath::Resolved(None, rhs1_path)) = rhs1.kind - && ident_l.name.as_str() == rhs1_path.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") - && path_l.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") == lhs1_path.segments.iter().map(|el| el.ident.to_string()).collect::>().join("::") - { - let lhs1 = Sugg::hir_opt(cx, lhs1); - let rhs1 = Sugg::hir_opt(cx, rhs1); - let (what, lhs, rhs) = if let (Some(first),Some(second)) = (lhs1,rhs1) { - ( - format!(" `{}` and `{}`", first, second), - first.mut_addr().to_string(), - second.mut_addr().to_string(), - ) - } else { - (String::new(), String::new(), String::new()) - }; - let span = first.span.to(second.span); - let Some(sugg) = std_or_core(cx) else { return }; +#[derive(Debug, Clone, Copy)] +enum ExprOrIdent<'a> { + Expr(&'a Expr<'a>), + Ident(Ident), +} - lint_almost_swapped_note(span, what, sugg, lhs, rhs); - } +fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<'hir>)> { + if let StmtKind::Semi(expr) = stmt.kind { + if let ExprKind::Assign(lhs, rhs, _) = expr.kind { + return Some((ExprOrIdent::Expr(lhs), rhs)); + } + } else if let StmtKind::Local(expr) = stmt.kind { + if let Some(rhs) = expr.init { + if let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind { + return Some((ExprOrIdent::Ident(ident_l), rhs)); + } + } } + None } /// Implementation of the xor case for `MANUAL_SWAP` lint. diff --git a/tests/ui/almost_swapped.rs b/tests/ui/almost_swapped.rs deleted file mode 100644 index 8b0740c320973..0000000000000 --- a/tests/ui/almost_swapped.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![allow(clippy::needless_late_init, clippy::manual_swap)] -#![allow(unused_variables, unused_assignments)] -#![warn(clippy::almost_swapped)] - -fn main() { - let b = 1; - let a = b; - let b = a; - - let mut c = 1; - let mut d = 2; - d = c; - c = d; - - let mut b = 1; - let a = b; - b = a; - - let b = 1; - let a = 2; - - let t = b; - let b = a; - let a = t; - - let mut b = 1; - let mut a = 2; - - let t = b; - b = a; - a = t; -} diff --git a/tests/ui/almost_swapped.stderr b/tests/ui/almost_swapped.stderr deleted file mode 100644 index 70788d23f1686..0000000000000 --- a/tests/ui/almost_swapped.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error: this looks like you are trying to swap `a` and `b` - --> $DIR/almost_swapped.rs:7:5 - | -LL | / let a = b; -LL | | let b = a; - | |______________^ - | - = note: `-D clippy::almost-swapped` implied by `-D warnings` - = note: maybe you could use `std::mem::swap(&mut a, &mut b)` or `std::mem::replace`? - -error: this looks like you are trying to swap `d` and `c` - --> $DIR/almost_swapped.rs:12:5 - | -LL | / d = c; -LL | | c = d; - | |_________^ help: try: `std::mem::swap(&mut d, &mut c)` - | - = note: or maybe you should use `std::mem::replace`? - -error: this looks like you are trying to swap `b` and `a` - --> $DIR/almost_swapped.rs:16:5 - | -LL | / let a = b; -LL | | b = a; - | |_________^ - | - = note: maybe you could use `std::mem::swap(&mut b, &mut a)` or `std::mem::replace`? - -error: aborting due to 3 previous errors - diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 805a2ba5a5984..fa89706a815af 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -7,7 +7,8 @@ clippy::redundant_clone, redundant_semicolons, dead_code, - unused_assignments + unused_assignments, + unused_variables )] struct Foo(u32); @@ -121,6 +122,27 @@ fn main() { std::mem::swap(&mut c.0, &mut a); ; std::mem::swap(&mut c.0, &mut a); + + std::mem::swap(&mut a, &mut b); + + let mut c = 1; + let mut d = 2; + std::mem::swap(&mut d, &mut c); + + let mut b = 1; + std::mem::swap(&mut a, &mut b); + + let b = 1; + let a = 2; + + let t = b; + let b = a; + let a = t; + + let mut b = 1; + let mut a = 2; + + std::mem::swap(&mut b, &mut a); } fn issue_8154() { diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index a8c878479523f..ef8a81c8341b1 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -7,7 +7,8 @@ clippy::redundant_clone, redundant_semicolons, dead_code, - unused_assignments + unused_assignments, + unused_variables )] struct Foo(u32); @@ -143,6 +144,32 @@ fn main() { ; let t = c.0; c.0 = a; a = t; + + let a = b; + let b = a; + + let mut c = 1; + let mut d = 2; + d = c; + c = d; + + let mut b = 1; + let a = b; + b = a; + + let b = 1; + let a = 2; + + let t = b; + let b = a; + let a = t; + + let mut b = 1; + let mut a = 2; + + let t = b; + b = a; + a = t; } fn issue_8154() { diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index ee4b7a508a5e3..f0acbfe253f43 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:24:5 + --> $DIR/swap.rs:25:5 | LL | / let temp = bar.a; LL | | bar.a = bar.b; @@ -10,7 +10,7 @@ LL | | bar.b = temp; = note: `-D clippy::manual-swap` implied by `-D warnings` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:36:5 + --> $DIR/swap.rs:37:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -18,7 +18,7 @@ LL | | foo[1] = temp; | |_________________^ help: try: `foo.swap(0, 1)` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:45:5 + --> $DIR/swap.rs:46:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -26,7 +26,7 @@ LL | | foo[1] = temp; | |_________________^ help: try: `foo.swap(0, 1)` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:64:5 + --> $DIR/swap.rs:65:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -34,7 +34,7 @@ LL | | foo[1] = temp; | |_________________^ help: try: `foo.swap(0, 1)` error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:75:5 + --> $DIR/swap.rs:76:5 | LL | / a ^= b; LL | | b ^= a; @@ -42,7 +42,7 @@ LL | | a ^= b; | |___________^ help: try: `std::mem::swap(&mut a, &mut b)` error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:83:5 + --> $DIR/swap.rs:84:5 | LL | / bar.a ^= bar.b; LL | | bar.b ^= bar.a; @@ -50,7 +50,7 @@ LL | | bar.a ^= bar.b; | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:91:5 + --> $DIR/swap.rs:92:5 | LL | / foo[0] ^= foo[1]; LL | | foo[1] ^= foo[0]; @@ -58,7 +58,7 @@ LL | | foo[0] ^= foo[1]; | |_____________________^ help: try: `foo.swap(0, 1)` error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually - --> $DIR/swap.rs:120:5 + --> $DIR/swap.rs:121:5 | LL | / let temp = foo[0][1]; LL | | foo[0][1] = bar[1][0]; @@ -68,7 +68,7 @@ LL | | bar[1][0] = temp; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:134:7 + --> $DIR/swap.rs:135:7 | LL | ; let t = a; | _______^ @@ -79,7 +79,7 @@ LL | | b = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> $DIR/swap.rs:143:7 + --> $DIR/swap.rs:144:7 | LL | ; let t = c.0; | _______^ @@ -89,8 +89,18 @@ LL | | a = t; | = note: or maybe you should use `std::mem::replace`? +error: this looks like you are swapping `b` and `a` manually + --> $DIR/swap.rs:170:5 + | +LL | / let t = b; +LL | | b = a; +LL | | a = t; + | |_________^ help: try: `std::mem::swap(&mut b, &mut a)` + | + = note: or maybe you should use `std::mem::replace`? + error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:131:5 + --> $DIR/swap.rs:132:5 | LL | / a = b; LL | | b = a; @@ -100,7 +110,7 @@ LL | | b = a; = note: `-D clippy::almost-swapped` implied by `-D warnings` error: this looks like you are trying to swap `c.0` and `a` - --> $DIR/swap.rs:140:5 + --> $DIR/swap.rs:141:5 | LL | / c.0 = a; LL | | a = c.0; @@ -108,8 +118,35 @@ LL | | a = c.0; | = note: or maybe you should use `std::mem::replace`? +error: this looks like you are trying to swap `a` and `b` + --> $DIR/swap.rs:148:5 + | +LL | / let a = b; +LL | | let b = a; + | |_____________^ help: try: `std::mem::swap(&mut a, &mut b)` + | + = note: or maybe you should use `std::mem::replace`? + +error: this looks like you are trying to swap `d` and `c` + --> $DIR/swap.rs:153:5 + | +LL | / d = c; +LL | | c = d; + | |_________^ help: try: `std::mem::swap(&mut d, &mut c)` + | + = note: or maybe you should use `std::mem::replace`? + +error: this looks like you are trying to swap `a` and `b` + --> $DIR/swap.rs:157:5 + | +LL | / let a = b; +LL | | b = a; + | |_________^ help: try: `std::mem::swap(&mut a, &mut b)` + | + = note: or maybe you should use `std::mem::replace`? + error: this looks like you are swapping `s.0.x` and `s.0.y` manually - --> $DIR/swap.rs:178:5 + --> $DIR/swap.rs:205:5 | LL | / let t = s.0.x; LL | | s.0.x = s.0.y; @@ -118,5 +155,5 @@ LL | | s.0.y = t; | = note: or maybe you should use `std::mem::replace`? -error: aborting due to 13 previous errors +error: aborting due to 17 previous errors From e8e9c32af94d0d38290f963fe4e8f28faab34dcc Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Thu, 9 Feb 2023 14:02:47 +0000 Subject: [PATCH 25/90] Alias folding/visiting traits instead of re-export --- clippy_utils/src/mir/possible_borrower.rs | 2 +- clippy_utils/src/ty.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index 5836eb73bd94c..fd9c83759a9c2 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_lint::LateContext; use rustc_middle::mir::{self, visit::Visitor as _, Mutability}; -use rustc_middle::ty::{self, visit::TypeVisitor}; +use rustc_middle::ty::{self, visit::ir::TypeVisitor}; use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor}; use std::borrow::Cow; use std::ops::ControlFlow; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index c48d27b05f045..1635b75f718f2 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -17,7 +17,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, - PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, + PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, ir::TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; From 340d9e818a5139c842edf7859cd3aba9361f4e08 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Thu, 9 Feb 2023 19:38:07 +0000 Subject: [PATCH 26/90] Make visiting traits generic over the Interner --- clippy_utils/src/mir/possible_borrower.rs | 4 ++-- clippy_utils/src/ty.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index fd9c83759a9c2..e9dc7351b58ef 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_lint::LateContext; use rustc_middle::mir::{self, visit::Visitor as _, Mutability}; -use rustc_middle::ty::{self, visit::ir::TypeVisitor}; +use rustc_middle::ty::{self, visit::ir::TypeVisitor, TyCtxt}; use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor}; use std::borrow::Cow; use std::ops::ControlFlow; @@ -136,7 +136,7 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, struct ContainsRegion; -impl TypeVisitor<'_> for ContainsRegion { +impl TypeVisitor> for ContainsRegion { type BreakTy = (); fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 1635b75f718f2..c785d89e28012 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -838,7 +838,7 @@ pub fn for_each_top_level_late_bound_region( index: u32, f: F, } - impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow> TypeVisitor<'tcx> for V { + impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow> TypeVisitor> for V { type BreakTy = B; fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { if let RegionKind::ReLateBound(idx, bound) = r.kind() && idx.as_u32() == self.index { From 4b8f112d098790b1140adb455f10aac9412004ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 13 Feb 2023 18:33:44 +0000 Subject: [PATCH 27/90] Use is_str instead of string kind comparison --- clippy_lints/src/methods/expect_fun_call.rs | 4 ++-- clippy_lints/src/methods/search_is_some.rs | 3 +-- clippy_lints/src/methods/single_char_pattern.rs | 2 +- clippy_lints/src/methods/string_extend_chars.rs | 3 +-- clippy_lints/src/strings.rs | 4 ++-- clippy_lints/src/transmute/transmute_ref_to_ref.rs | 3 ++- clippy_utils/src/ty.rs | 2 +- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index aed0ad5d9b5a7..a22285058d48e 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -33,7 +33,7 @@ pub(super) fn check<'tcx>( if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { let arg_type = cx.typeck_results().expr_ty(receiver); let base_type = arg_type.peel_refs(); - *base_type.kind() == ty::Str || is_type_lang_item(cx, base_type, hir::LangItem::String) + base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String) } { receiver } else { @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>( return false; } if let ty::Ref(_, ty, ..) = arg_ty.kind() { - if *ty.kind() == ty::Str && can_be_static_str(cx, arg) { + if ty.is_str() && can_be_static_str(cx, arg) { return false; } }; diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 1c031ad6acbaf..afdb8ce94ac43 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -8,7 +8,6 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_middle::ty; use rustc_span::source_map::Span; use rustc_span::symbol::sym; @@ -108,7 +107,7 @@ pub(super) fn check<'tcx>( if is_type_lang_item(cx, self_ty, hir::LangItem::String) { true } else { - *self_ty.kind() == ty::Str + self_ty.is_str() } }; if_chain! { diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index 4221c52d5cd79..4d704ec39ebb1 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -47,7 +47,7 @@ pub(super) fn check( for &(method, pos) in &PATTERN_METHODS { if_chain! { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind(); - if *ty.kind() == ty::Str; + if ty.is_str(); if method_name.as_str() == method && args.len() > pos; let arg = &args[pos]; let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index f35d81cee8e97..2c20c6d752d70 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -5,7 +5,6 @@ use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty; use super::STRING_EXTEND_CHARS; @@ -17,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if let Some(arglists) = method_chain_args(arg, &["chars"]) { let target = &arglists[0].0; let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); - let ref_str = if *self_ty.kind() == ty::Str { + let ref_str = if self_ty.is_str() { if matches!(target.kind, hir::ExprKind::Index(..)) { "&" } else { diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index bc18cad6d381b..b2f4b310915a6 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { }, ExprKind::Index(target, _idx) => { let e_ty = cx.typeck_results().expr_ty(target).peel_refs(); - if matches!(e_ty.kind(), ty::Str) || is_type_lang_item(cx, e_ty, LangItem::String) { + if e_ty.is_str() || is_type_lang_item(cx, e_ty, LangItem::String) { span_lint( cx, STRING_SLICE, @@ -407,7 +407,7 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { if path.ident.name == sym::to_string; let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, ty, ..) = ty.kind(); - if *ty.kind() == ty::Str; + if ty.is_str(); then { span_lint_and_help( cx, diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index afb7f2e132696..426c7253806e3 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -22,7 +22,8 @@ pub(super) fn check<'tcx>( if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) { if_chain! { - if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind(), &ty_to.kind()); + if let ty::Slice(slice_ty) = *ty_from.kind(); + if ty_to.is_str(); if let ty::Uint(ty::UintTy::U8) = slice_ty.kind(); if from_mutbl == to_mutbl; then { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index c48d27b05f045..f293a7a3baeeb 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -346,7 +346,7 @@ pub fn is_non_aggregate_primitive_type(ty: Ty<'_>) -> bool { pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match *ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, - ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, + ty::Ref(_, inner, _) if inner.is_str() => true, ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type), _ => false, From 89314a08054cea924c807032ebdb62e031453bb3 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 13 Feb 2023 20:50:08 +0100 Subject: [PATCH 28/90] Add question-mark-used lint This lint complains when the question mark operator (try operator) is used. This is a restriction lint that can be useful on local scopes where a custom error handling macro is supposed to be used to augment the error based on local scope data before returning. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/question_mark_used.rs | 47 ++++++++++++++++++++++++++ tests/ui/question_mark_used.rs | 15 ++++++++ tests/ui/question_mark_used.stderr | 11 ++++++ 6 files changed, 77 insertions(+) create mode 100644 clippy_lints/src/question_mark_used.rs create mode 100644 tests/ui/question_mark_used.rs create mode 100644 tests/ui/question_mark_used.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 30727beb8e7ff..077e60af93191 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4675,6 +4675,7 @@ Released 2018-09-13 [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names [`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use [`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark +[`question_mark_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark_used [`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one [`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index c1feabf05aafd..61ce0c5a4699e 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -507,6 +507,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO, crate::pub_use::PUB_USE_INFO, crate::question_mark::QUESTION_MARK_INFO, + crate::question_mark_used::QUESTION_MARK_USED_INFO, crate::ranges::MANUAL_RANGE_CONTAINS_INFO, crate::ranges::RANGE_MINUS_ONE_INFO, crate::ranges::RANGE_PLUS_ONE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 565c5b7af0068..e4926c0ed0815 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -242,6 +242,7 @@ mod ptr; mod ptr_offset_with_cast; mod pub_use; mod question_mark; +mod question_mark_used; mod ranges; mod rc_clone_in_vec_init; mod read_zero_byte_vec; @@ -693,6 +694,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher)); store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom)); store.register_late_pass(|_| Box::new(question_mark::QuestionMark)); + store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed)); store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings)); store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl)); store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit)); diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs new file mode 100644 index 0000000000000..1a103dc35a415 --- /dev/null +++ b/clippy_lints/src/question_mark_used.rs @@ -0,0 +1,47 @@ +use clippy_utils::diagnostics::span_lint_and_help; + +use rustc_hir::{Expr, ExprKind, MatchSource}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions that use the question mark operator and rejects them. + /// + /// ### Why is this bad? + /// Sometimes code wants to avoid the question mark operator because for instance a local + /// block requires a macro to re-throw errors to attach additional information to the + /// error. + /// + /// ### Example + /// ```ignore + /// let result = expr?; + /// ``` + /// + /// Could be written: + /// + /// ```ignore + /// utility_macro!(expr); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub QUESTION_MARK_USED, + restriction, + "complains if the question mark operator is used" +} + +declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]); + +impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind { + span_lint_and_help( + cx, + QUESTION_MARK_USED, + expr.span, + "question mark operator was used", + None, + "consider using a custom macro or match expression", + ); + } + } +} diff --git a/tests/ui/question_mark_used.rs b/tests/ui/question_mark_used.rs new file mode 100644 index 0000000000000..8c3ef789697fc --- /dev/null +++ b/tests/ui/question_mark_used.rs @@ -0,0 +1,15 @@ +// non rustfixable +#![allow(unreachable_code)] +#![allow(dead_code)] +#![warn(clippy::question_mark_used)] + +fn other_function() -> Option { + Some(32) +} + +fn my_function() -> Option { + other_function()?; + None +} + +fn main() {} diff --git a/tests/ui/question_mark_used.stderr b/tests/ui/question_mark_used.stderr new file mode 100644 index 0000000000000..8b5fcbcdbfd6c --- /dev/null +++ b/tests/ui/question_mark_used.stderr @@ -0,0 +1,11 @@ +error: question mark operator was used + --> $DIR/question_mark_used.rs:11:5 + | +LL | other_function()?; + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using a custom macro or match expression + = note: `-D clippy::question-mark-used` implied by `-D warnings` + +error: aborting due to previous error + From c231b4188782c249428a66d70b3f705757390ce5 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 9 Feb 2023 20:32:44 +0100 Subject: [PATCH 29/90] Remove useless call to combine_seq `combine_seq(x, NeverLoopResult::Otherwise)` always returns `x` --- clippy_lints/src/loops/never_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 14f161f510265..5bc0f4226fb26 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -191,7 +191,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H // checks if break targets a block instead of a loop ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e .map_or(NeverLoopResult::Otherwise, |e| { - combine_seq(never_loop_expr(e, ignore_ids, main_loop_id), NeverLoopResult::Otherwise) + never_loop_expr(e, ignore_ids, main_loop_id) }), ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| { combine_seq( From 1fec2927c5cf02de85c08a63dbc8909077661d1b Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 13 Feb 2023 20:36:41 +0100 Subject: [PATCH 30/90] Replace combine_both by combine_seq All evaluations now happen in order. --- clippy_lints/src/loops/never_loop.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 5bc0f4226fb26..9d16949c81f43 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -68,18 +68,6 @@ fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResu } } -// Combine two results where both parts are called but not necessarily in order. -#[must_use] -fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult { - match (left, right) { - (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => { - NeverLoopResult::MayContinueMainLoop - }, - (NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak, - (NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise, - } -} - // Combine two results where only one of the part may have been executed. #[must_use] fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult { @@ -139,7 +127,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H ExprKind::Struct(_, fields, base) => { let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id); if let Some(base) = base { - combine_both(fields, never_loop_expr(base, ignore_ids, main_loop_id)) + combine_seq(fields, never_loop_expr(base, ignore_ids, main_loop_id)) } else { fields } @@ -218,7 +206,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise, }) - .fold(NeverLoopResult::Otherwise, combine_both), + .fold(NeverLoopResult::Otherwise, combine_seq), ExprKind::Yield(_, _) | ExprKind::Closure { .. } | ExprKind::Path(_) @@ -234,7 +222,7 @@ fn never_loop_expr_all<'a, T: Iterator>>( main_loop_id: HirId, ) -> NeverLoopResult { es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id)) - .fold(NeverLoopResult::Otherwise, combine_both) + .fold(NeverLoopResult::Otherwise, combine_seq) } fn never_loop_expr_branch<'a, T: Iterator>>( From 8e96adedd56993eec0609276124ff17d4866b94b Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Tue, 14 Feb 2023 11:31:42 +0800 Subject: [PATCH 31/90] fix [`needless_return`] incorrect suggestion when returning if sequence --- clippy_lints/src/returns.rs | 96 +++++++++++++++++++-------------- tests/ui/needless_return.fixed | 4 ++ tests/ui/needless_return.rs | 4 ++ tests/ui/needless_return.stderr | 10 +++- 4 files changed, 72 insertions(+), 42 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 84a0c6b955853..84bcef856d06c 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -69,31 +69,35 @@ declare_clippy_lint! { "using a return statement like `return expr;` where an expression would suffice" } -#[derive(PartialEq, Eq, Copy, Clone)] +#[derive(PartialEq, Eq, Clone)] enum RetReplacement { Empty, Block, Unit, + IfSequence(String), + Expr(String), } impl RetReplacement { fn sugg_help(self) -> &'static str { match self { - Self::Empty => "remove `return`", + Self::Empty | Self::Expr(_) => "remove `return`", Self::Block => "replace `return` with an empty block", Self::Unit => "replace `return` with a unit value", + Self::IfSequence(_) => "remove `return` and wrap the sequence with parentheses", } } } impl ToString for RetReplacement { fn to_string(&self) -> String { - match *self { - Self::Empty => "", - Self::Block => "{}", - Self::Unit => "()", + match self { + Self::Empty => String::new(), + Self::Block => "{}".to_string(), + Self::Unit => "()".to_string(), + Self::IfSequence(inner) => format!("({inner})"), + Self::Expr(inner) => inner.clone(), } - .to_string() } } @@ -210,13 +214,37 @@ fn check_final_expr<'tcx>( match &peeled_drop_expr.kind { // simple return is always "bad" ExprKind::Ret(ref inner) => { - // if desugar of `do yeet`, don't lint - if let Some(inner_expr) = inner - && let ExprKind::Call(path_expr, _) = inner_expr.kind - && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind - { - return; - } + // check if expr return nothing + let ret_span = if inner.is_none() && replacement == RetReplacement::Empty { + extend_span_to_previous_non_ws(cx, peeled_drop_expr.span) + } else { + peeled_drop_expr.span + }; + + let replacement = if let Some(inner_expr) = inner { + // if desugar of `do yeet`, don't lint + if let ExprKind::Call(path_expr, _) = inner_expr.kind + && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind + { + return; + } + + let (snippet, _) = snippet_with_context( + cx, + inner_expr.span, + ret_span.ctxt(), + "..", + &mut Applicability::MachineApplicable, + ); + if expr_contains_if(inner_expr) { + RetReplacement::IfSequence(snippet.to_string()) + } else { + RetReplacement::Expr(snippet.to_string()) + } + } else { + replacement + }; + if !cx.tcx.hir().attrs(expr.hir_id).is_empty() { return; } @@ -224,14 +252,8 @@ fn check_final_expr<'tcx>( if borrows { return; } - // check if expr return nothing - let ret_span = if inner.is_none() && replacement == RetReplacement::Empty { - extend_span_to_previous_non_ws(cx, peeled_drop_expr.span) - } else { - peeled_drop_expr.span - }; - emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement); + emit_return_lint(cx, ret_span, semi_spans, replacement); }, ExprKind::If(_, then, else_clause_opt) => { check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone()); @@ -253,29 +275,21 @@ fn check_final_expr<'tcx>( } } -fn emit_return_lint( - cx: &LateContext<'_>, - ret_span: Span, - semi_spans: Vec, - inner_span: Option, - replacement: RetReplacement, -) { +fn expr_contains_if<'tcx>(expr: &'tcx Expr<'tcx>) -> bool { + match expr.kind { + ExprKind::If(..) => true, + ExprKind::Binary(_, left, right) => expr_contains_if(left) || expr_contains_if(right), + _ => false, + } +} + +fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec, replacement: RetReplacement) { if ret_span.from_expansion() { return; } - let mut applicability = Applicability::MachineApplicable; - let return_replacement = inner_span.map_or_else( - || replacement.to_string(), - |inner_span| { - let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability); - snippet.to_string() - }, - ); - let sugg_help = if inner_span.is_some() { - "remove `return`" - } else { - replacement.sugg_help() - }; + let applicability = Applicability::MachineApplicable; + let return_replacement = replacement.to_string(); + let sugg_help = replacement.sugg_help(); span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { diag.span_suggestion_hidden(ret_span, sugg_help, return_replacement, applicability); // for each parent statement, we need to remove the semicolon diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 079e3531def1b..c77554fb47b25 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -297,4 +297,8 @@ fn issue10051() -> Result { } } +fn issue10049(b1: bool, b2: bool, b3: bool) -> u32 { + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }) +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index c1c48284f0869..8fed64ac6e3b4 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -307,4 +307,8 @@ fn issue10051() -> Result { } } +fn issue10049(b1: bool, b2: bool, b3: bool) -> u32 { + return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 08b04bfe9d8bf..18edbce2f44ba 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -418,5 +418,13 @@ LL | return Err(format!("err!")); | = help: remove `return` -error: aborting due to 50 previous errors +error: unneeded `return` statement + --> $DIR/needless_return.rs:311:5 + | +LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` and wrap the sequence with parentheses + +error: aborting due to 51 previous errors From e9dffa391085f4b3c84f90e8ab82bdd568d1f17e Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 14 Feb 2023 09:12:51 +0100 Subject: [PATCH 32/90] Fix a bug in never_loop when anonymous blocks are nested in named blocks The following code ``` loop { 'a: { { } break 'a; } } ``` was detected as a never-looping loop. --- clippy_lints/src/loops/never_loop.rs | 4 +++- tests/ui/never_loop.rs | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 9d16949c81f43..3cb5b1ffc7b34 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -163,7 +163,9 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H ignore_ids.push(b.hir_id); } let ret = never_loop_block(b, ignore_ids, main_loop_id); - ignore_ids.pop(); + if l.is_some() { + ignore_ids.pop(); + } ret }, ExprKind::Continue(d) => { diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index 28e8f459d4429..a177d5e06aa62 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -250,6 +250,15 @@ pub fn test20() { } } +pub fn test21() { + loop { + 'a: { + { } + break 'a; + } + } +} + fn main() { test1(); test2(); From e3a739a115f897379f844926ba8f8cfd880641de Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 14 Feb 2023 08:51:19 +0000 Subject: [PATCH 33/90] s/eval_usize/eval_target_usize/ for clarity --- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/loops/explicit_iter_loop.rs | 2 +- clippy_lints/src/loops/needless_range_loop.rs | 2 +- clippy_lints/src/methods/utils.rs | 2 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/trailing_empty_array.rs | 2 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/ty.rs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index eebfb753a0c5d..c384172fbde83 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { if let Some(range) = higher::Range::hir(index) { // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..] if let ty::Array(_, s) = ty.kind() { - let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) { + let size: u128 = if let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env) { size.into() } else { return; diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index b1f2941622abb..151c7f1d5d254 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -68,7 +68,7 @@ fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.kind() { ty::Array(_, n) => n - .try_eval_usize(cx.tcx, cx.param_env) + .try_eval_target_usize(cx.tcx, cx.param_env) .map_or(false, |val| (0..=32).contains(&val)), _ => false, } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 25a1a5842f77b..5c317c2a5bbb6 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -211,7 +211,7 @@ fn is_end_eq_array_len<'tcx>( if let ExprKind::Lit(ref lit) = end.kind; if let ast::LitKind::Int(end_int, _) = lit.node; if let ty::Array(_, arr_len_const) = indexed_ty.kind(); - if let Some(arr_len) = arr_len_const.try_eval_usize(cx.tcx, cx.param_env); + if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env); then { return match limits { ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(), diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index ae6b165fdc366..d50346c166ae0 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -22,7 +22,7 @@ pub(super) fn derefs_to_slice<'tcx>( ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec), - ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(), + ty::Array(_, size) => size.try_eval_target_usize(cx.tcx, cx.param_env).is_some(), ty::Ref(_, inner, _) => may_slice(cx, *inner), _ => false, } diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 5f7aac21e6eb0..3cc765108d7cc 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -166,7 +166,7 @@ impl MutableKeyType { Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty), Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty), Array(inner_ty, size) => { - size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) + size.try_eval_target_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && self.is_interior_mutable_type(cx, inner_ty) }, Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)), diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index de0c5d56e4156..1382c1a40da24 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -62,7 +62,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_ // Then check if that that array zero-sized let length = Const::from_anon_const(cx.tcx, length.def_id); - let length = length.try_eval_usize(cx.tcx, cx.param_env); + let length = length.try_eval_target_usize(cx.tcx, cx.param_env); if let Some(length) = length; then { length == 0 diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index a67bd8d46006b..9d812fbdcc37e 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -335,7 +335,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple), ExprKind::Repeat(value, _) => { let n = match self.typeck_results.expr_ty(e).kind() { - ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?, + ty::Array(_, n) => n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)?, _ => span_bug!(e.span, "typeck error"), }; self.expr(value).map(|v| Constant::Repeat(Box::new(v), n)) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index c785d89e28012..0d763a2c5cf6b 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -949,7 +949,7 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { (Ok(size), _) => size, (Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(), (Err(_), ty::Array(t, n)) => { - n.try_eval_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t) + n.try_eval_target_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t) }, (Err(_), ty::Adt(def, subst)) if def.is_struct() => def .variants() From 657ee48bec2c02ad6885176ea37658bddf6ce59a Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 13 Feb 2023 20:37:36 +0100 Subject: [PATCH 34/90] Ignore instructions following a break from block in never_loop lint It is not sufficient to ignore break from a block inside the loop. Instructions after the break must be ignored, as they are unreachable. This is also true for all instructions in outer blocks and loops until the right block is reached. --- clippy_lints/src/loops/never_loop.rs | 35 +++++++++++++++++++------ tests/ui/never_loop.rs | 38 +++++++++++++++++++++++++++- tests/ui/never_loop.stderr | 15 ++++++++++- 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 3cb5b1ffc7b34..ea7630ce56dd3 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -39,6 +39,7 @@ pub(super) fn check( }); }, NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (), + NeverLoopResult::IgnoreUntilEnd(_) => unreachable!(), } } @@ -48,6 +49,8 @@ enum NeverLoopResult { AlwaysBreak, // A continue may occur for the main loop. MayContinueMainLoop, + // Ignore everything until the end of the block with this id + IgnoreUntilEnd(HirId), Otherwise, } @@ -56,6 +59,7 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult { match arg { NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise, NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop, + NeverLoopResult::IgnoreUntilEnd(id) => NeverLoopResult::IgnoreUntilEnd(id), } } @@ -63,15 +67,26 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult { #[must_use] fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult { match first { - NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop => first, + NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop | NeverLoopResult::IgnoreUntilEnd(_) => { + first + }, NeverLoopResult::Otherwise => second, } } // Combine two results where only one of the part may have been executed. #[must_use] -fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult { +fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirId]) -> NeverLoopResult { match (b1, b2) { + (NeverLoopResult::IgnoreUntilEnd(a), NeverLoopResult::IgnoreUntilEnd(b)) => { + if ignore_ids.iter().find(|&e| e == &a || e == &b).unwrap() == &a { + NeverLoopResult::IgnoreUntilEnd(b) + } else { + NeverLoopResult::IgnoreUntilEnd(a) + } + }, + (i @ NeverLoopResult::IgnoreUntilEnd(_), NeverLoopResult::AlwaysBreak) + | (NeverLoopResult::AlwaysBreak, i @ NeverLoopResult::IgnoreUntilEnd(_)) => i, (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak, (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => { NeverLoopResult::MayContinueMainLoop @@ -91,7 +106,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec, main_loop_id let e = never_loop_expr(e, ignore_ids, main_loop_id); // els is an else block in a let...else binding els.map_or(e, |els| { - combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id)) + combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id), ignore_ids) }) }) .fold(NeverLoopResult::Otherwise, combine_seq) @@ -147,7 +162,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| { never_loop_expr(e, ignore_ids, main_loop_id) }); - combine_seq(e1, combine_branches(e2, e3)) + combine_seq(e1, combine_branches(e2, e3, ignore_ids)) }, ExprKind::Match(e, arms, _) => { let e = never_loop_expr(e, ignore_ids, main_loop_id); @@ -166,7 +181,10 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H if l.is_some() { ignore_ids.pop(); } - ret + match ret { + NeverLoopResult::IgnoreUntilEnd(a) if a == b.hir_id => NeverLoopResult::Otherwise, + _ => ret, + } }, ExprKind::Continue(d) => { let id = d @@ -180,7 +198,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H }, // checks if break targets a block instead of a loop ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e - .map_or(NeverLoopResult::Otherwise, |e| { + .map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| { never_loop_expr(e, ignore_ids, main_loop_id) }), ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| { @@ -232,8 +250,9 @@ fn never_loop_expr_branch<'a, T: Iterator>>( ignore_ids: &mut Vec, main_loop_id: HirId, ) -> NeverLoopResult { - e.map(|e| never_loop_expr(e, ignore_ids, main_loop_id)) - .fold(NeverLoopResult::AlwaysBreak, combine_branches) + e.fold(NeverLoopResult::AlwaysBreak, |a, b| { + combine_branches(a, never_loop_expr(b, ignore_ids, main_loop_id), ignore_ids) + }) } fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String { diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index a177d5e06aa62..29821ff96fc0f 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -253,12 +253,48 @@ pub fn test20() { pub fn test21() { loop { 'a: { - { } + {} break 'a; } } } +// Issue 10304: code after break from block was not considered +// unreachable code and was considered for further analysis of +// whether the loop would ever be executed or not. +pub fn test22() { + for _ in 0..10 { + 'block: { + break 'block; + return; + } + println!("looped"); + } +} + +pub fn test23() { + for _ in 0..10 { + 'block: { + for _ in 0..20 { + break 'block; + } + } + println!("looped"); + } +} + +pub fn test24() { + 'a: for _ in 0..10 { + 'b: { + let x = Some(1); + match x { + None => break 'a, + Some(_) => break 'b, + } + } + } +} + fn main() { test1(); test2(); diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr index b7029bf8bed47..704d448644e28 100644 --- a/tests/ui/never_loop.stderr +++ b/tests/ui/never_loop.stderr @@ -126,5 +126,18 @@ LL | | } LL | | } | |_____^ -error: aborting due to 11 previous errors +error: this loop never actually loops + --> $DIR/never_loop.rs:278:13 + | +LL | / for _ in 0..20 { +LL | | break 'block; +LL | | } + | |_____________^ + | +help: if you need the first element of the iterator, try writing + | +LL | if let Some(_) = (0..20).next() { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 12 previous errors From e4e5924b99b30c693bc87aa95ef51fd2263b6280 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 14 Feb 2023 14:50:08 +0100 Subject: [PATCH 35/90] Do not base map_entry lint suggestion on expanded code --- clippy_lints/src/entry.rs | 4 ++++ tests/ui/entry.fixed | 14 ++++++++++++++ tests/ui/entry.rs | 14 ++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index b44e62435881f..ed9d94cdec3c5 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -65,6 +65,10 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]); impl<'tcx> LateLintPass<'tcx> for HashMapPass { #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if expr.span.from_expansion() { + return; + } + let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else { return }; diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index 79c29c04e0596..dbe09e0ff3c69 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -152,4 +152,18 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa }); } +// Issue 10331 +// do not suggest a bad expansion because the compiler unrolls the first +// occurrence of the loop +pub fn issue_10331() { + let mut m = HashMap::new(); + let mut i = 0; + let mut x = 0; + while !m.contains_key(&x) { + m.insert(x, i); + i += 1; + x += 1; + } +} + fn main() {} diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 2d7985457d8b4..30fed34fc5de2 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -156,4 +156,18 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa } } +// Issue 10331 +// do not suggest a bad expansion because the compiler unrolls the first +// occurrence of the loop +pub fn issue_10331() { + let mut m = HashMap::new(); + let mut i = 0; + let mut x = 0; + while !m.contains_key(&x) { + m.insert(x, i); + i += 1; + x += 1; + } +} + fn main() {} From e41c37316dbd13eaaef8be50422cfa39ea3835a0 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 12 Feb 2023 18:26:47 +0000 Subject: [PATCH 36/90] Add `of_trait` to DefKind::Impl. --- clippy_lints/src/same_name_method.rs | 2 +- clippy_utils/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 17763128cd143..a37e2772d3558 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { let mut map = FxHashMap::::default(); for id in cx.tcx.hir().items() { - if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl) + if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. }) && let item = cx.tcx.hir().item(id) && let ItemKind::Impl(Impl { items, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 26f279f55855f..3b8713e2b108c 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -552,7 +552,7 @@ fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) .filter(|item| item.ident.name == name) .map(|child| child.res.expect_non_local()) .collect(), - DefKind::Impl => tcx + DefKind::Impl { .. } => tcx .associated_item_def_ids(def_id) .iter() .copied() From 17cb2e47e5503494fa506af42be289f38a3a8d73 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 12 Feb 2023 07:12:32 +0000 Subject: [PATCH 37/90] Liberate late-bound regions rather than erasing them in needless_pass_by_value --- clippy_lints/src/needless_pass_by_value.rs | 2 +- .../needless_pass_by_value-w-late-bound.rs | 9 +++++++++ .../needless_pass_by_value-w-late-bound.stderr | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/ui/crashes/needless_pass_by_value-w-late-bound.rs create mode 100644 tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 996ea6ed72316..b403092d5c726 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { }; let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity(); - let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig); + let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig); for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() { // All spans generated from a proc-macro invocation are the same... diff --git a/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs b/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs new file mode 100644 index 0000000000000..dd3d8b8b6d156 --- /dev/null +++ b/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/107147 + +#![warn(clippy::needless_pass_by_value)] + +struct Foo<'a>(&'a [(); 100]); + +fn test(x: Foo<'_>) {} + +fn main() {} diff --git a/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr b/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr new file mode 100644 index 0000000000000..7a0a648974fc7 --- /dev/null +++ b/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr @@ -0,0 +1,15 @@ +error: this argument is passed by value, but not consumed in the function body + --> $DIR/needless_pass_by_value-w-late-bound.rs:7:12 + | +LL | fn test(x: Foo<'_>) {} + | ^^^^^^^ help: consider taking a reference instead: `&Foo<'_>` + | +help: consider marking this type as `Copy` + --> $DIR/needless_pass_by_value-w-late-bound.rs:5:1 + | +LL | struct Foo<'a>(&'a [(); 100]); + | ^^^^^^^^^^^^^^ + = note: `-D clippy::needless-pass-by-value` implied by `-D warnings` + +error: aborting due to previous error + From 7f15a11aa174efded805617f2c5664f31389dcc1 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 12 Feb 2023 09:18:55 +0100 Subject: [PATCH 38/90] manual_let_else: let/else is not divergent by default The divergent `else` block of a `let`/`else` statement does not make the `let`/`else` statement itself divergent. --- clippy_lints/src/manual_let_else.rs | 146 ++++++++++++++++++---------- tests/ui/manual_let_else.rs | 11 +++ 2 files changed, 105 insertions(+), 52 deletions(-) diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 9c6f8b43c078f..5db5c6447364a 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -4,11 +4,12 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::peel_blocks; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, Visitable}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -162,61 +163,102 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: ); } -fn expr_diverges(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { - fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { - if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) { - return ty.is_never(); - } - false +/// Check whether an expression is divergent. May give false negatives. +fn expr_diverges(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + struct V<'cx, 'tcx> { + cx: &'cx LateContext<'tcx>, + res: ControlFlow<(), Descend>, } - // We can't just call is_never on expr and be done, because the type system - // sometimes coerces the ! type to something different before we can get - // our hands on it. So instead, we do a manual search. We do fall back to - // is_never in some places when there is no better alternative. - for_each_expr(expr, |ex| { - match ex.kind { - ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()), - ExprKind::Call(call, _) => { - if is_never(cx, ex) || is_never(cx, call) { - return ControlFlow::Break(()); - } - ControlFlow::Continue(Descend::Yes) - }, - ExprKind::MethodCall(..) => { - if is_never(cx, ex) { - return ControlFlow::Break(()); - } - ControlFlow::Continue(Descend::Yes) - }, - ExprKind::If(if_expr, if_then, if_else) => { - let else_diverges = if_else.map_or(false, |ex| expr_diverges(cx, ex)); - let diverges = expr_diverges(cx, if_expr) || (else_diverges && expr_diverges(cx, if_then)); - if diverges { - return ControlFlow::Break(()); - } - ControlFlow::Continue(Descend::No) - }, - ExprKind::Match(match_expr, match_arms, _) => { - let diverges = expr_diverges(cx, match_expr) - || match_arms.iter().all(|arm| { - let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(cx, g.body())); - guard_diverges || expr_diverges(cx, arm.body) - }); - if diverges { - return ControlFlow::Break(()); + impl<'tcx> Visitor<'tcx> for V<'_, '_> { + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { + if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) { + return ty.is_never(); } - ControlFlow::Continue(Descend::No) - }, + false + } + + if self.res.is_break() { + return; + } - // Don't continue into loops or labeled blocks, as they are breakable, - // and we'd have to start checking labels. - ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No), + // We can't just call is_never on expr and be done, because the type system + // sometimes coerces the ! type to something different before we can get + // our hands on it. So instead, we do a manual search. We do fall back to + // is_never in some places when there is no better alternative. + self.res = match e.kind { + ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()), + ExprKind::Call(call, _) => { + if is_never(self.cx, e) || is_never(self.cx, call) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::Yes) + } + }, + ExprKind::MethodCall(..) => { + if is_never(self.cx, e) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::Yes) + } + }, + ExprKind::If(if_expr, if_then, if_else) => { + let else_diverges = if_else.map_or(false, |ex| expr_diverges(self.cx, ex)); + let diverges = + expr_diverges(self.cx, if_expr) || (else_diverges && expr_diverges(self.cx, if_then)); + if diverges { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::No) + } + }, + ExprKind::Match(match_expr, match_arms, _) => { + let diverges = expr_diverges(self.cx, match_expr) + || match_arms.iter().all(|arm| { + let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(self.cx, g.body())); + guard_diverges || expr_diverges(self.cx, arm.body) + }); + if diverges { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(Descend::No) + } + }, - // Default: descend - _ => ControlFlow::Continue(Descend::Yes), + // Don't continue into loops or labeled blocks, as they are breakable, + // and we'd have to start checking labels. + ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No), + + // Default: descend + _ => ControlFlow::Continue(Descend::Yes), + }; + if let ControlFlow::Continue(Descend::Yes) = self.res { + walk_expr(self, e); + } + } + + fn visit_local(&mut self, local: &'tcx Local<'_>) { + // Don't visit the else block of a let/else statement as it will not make + // the statement divergent even though the else block is divergent. + if let Some(init) = local.init { + self.visit_expr(init); + } } - }) - .is_some() + + // Avoid unnecessary `walk_*` calls. + fn visit_ty(&mut self, _: &'tcx Ty<'tcx>) {} + fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {} + fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {} + // Avoid monomorphising all `visit_*` functions. + fn visit_nested_item(&mut self, _: ItemId) {} + } + + let mut v = V { + cx, + res: ControlFlow::Continue(Descend::Yes), + }; + expr.visit(&mut v); + v.res.is_break() } fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool { diff --git a/tests/ui/manual_let_else.rs b/tests/ui/manual_let_else.rs index 48a162c13602c..d175597a44a63 100644 --- a/tests/ui/manual_let_else.rs +++ b/tests/ui/manual_let_else.rs @@ -248,4 +248,15 @@ fn not_fire() { Some(value) => value, _ => macro_call!(), }; + + // Issue 10296 + // The let/else block in the else part is not divergent despite the presence of return + let _x = if let Some(x) = Some(1) { + x + } else { + let Some(_z) = Some(3) else { + return + }; + 1 + }; } From 8b93eb8a9b31fcaadf22ea0fbacfcea4450a5894 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Wed, 15 Feb 2023 11:26:30 +0800 Subject: [PATCH 39/90] add some adjustment regarding review suggestion --- clippy_lints/src/returns.rs | 60 ++++++++++++++++++--------------- tests/ui/needless_return.fixed | 10 ++++-- tests/ui/needless_return.rs | 10 ++++-- tests/ui/needless_return.stderr | 16 ++++++--- 4 files changed, 61 insertions(+), 35 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 84bcef856d06c..f0d7dd23a6786 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -14,6 +14,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::{BytePos, Pos}; +use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -70,33 +71,39 @@ declare_clippy_lint! { } #[derive(PartialEq, Eq, Clone)] -enum RetReplacement { +enum RetReplacement<'tcx> { Empty, Block, Unit, - IfSequence(String), - Expr(String), + IfSequence(Cow<'tcx, str>, Applicability), + Expr(Cow<'tcx, str>, Applicability), } -impl RetReplacement { +impl<'tcx> RetReplacement<'tcx> { fn sugg_help(self) -> &'static str { match self { - Self::Empty | Self::Expr(_) => "remove `return`", + Self::Empty | Self::Expr(..) => "remove `return`", Self::Block => "replace `return` with an empty block", Self::Unit => "replace `return` with a unit value", - Self::IfSequence(_) => "remove `return` and wrap the sequence with parentheses", + Self::IfSequence(..) => "remove `return` and wrap the sequence with parentheses", + } + } + fn applicability(&self) -> Option { + match self { + Self::Expr(_, ap) | Self::IfSequence(_, ap) => Some(*ap), + _ => None, } } } -impl ToString for RetReplacement { +impl<'tcx> ToString for RetReplacement<'tcx> { fn to_string(&self) -> String { match self { Self::Empty => String::new(), Self::Block => "{}".to_string(), Self::Unit => "()".to_string(), - Self::IfSequence(inner) => format!("({inner})"), - Self::Expr(inner) => inner.clone(), + Self::IfSequence(inner, _) => format!("({inner})"), + Self::Expr(inner, _) => inner.to_string(), } } } @@ -208,7 +215,7 @@ fn check_final_expr<'tcx>( expr: &'tcx Expr<'tcx>, semi_spans: Vec, /* containing all the places where we would need to remove semicolons if finding an * needless return */ - replacement: RetReplacement, + replacement: RetReplacement<'tcx>, ) { let peeled_drop_expr = expr.peel_drop_temps(); match &peeled_drop_expr.kind { @@ -229,17 +236,12 @@ fn check_final_expr<'tcx>( return; } - let (snippet, _) = snippet_with_context( - cx, - inner_expr.span, - ret_span.ctxt(), - "..", - &mut Applicability::MachineApplicable, - ); - if expr_contains_if(inner_expr) { - RetReplacement::IfSequence(snippet.to_string()) + let mut applicability = Applicability::MachineApplicable; + let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability); + if expr_contains_conjunctive_ifs(inner_expr) { + RetReplacement::IfSequence(snippet, applicability) } else { - RetReplacement::Expr(snippet.to_string()) + RetReplacement::Expr(snippet, applicability) } } else { replacement @@ -275,19 +277,23 @@ fn check_final_expr<'tcx>( } } -fn expr_contains_if<'tcx>(expr: &'tcx Expr<'tcx>) -> bool { - match expr.kind { - ExprKind::If(..) => true, - ExprKind::Binary(_, left, right) => expr_contains_if(left) || expr_contains_if(right), - _ => false, +fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool { + fn contains_if(expr: &Expr<'_>, on_if: bool) -> bool { + match expr.kind { + ExprKind::If(..) => on_if, + ExprKind::Binary(_, left, right) => contains_if(left, true) || contains_if(right, true), + _ => false, + } } + + contains_if(expr, false) } -fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec, replacement: RetReplacement) { +fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec, replacement: RetReplacement<'_>) { if ret_span.from_expansion() { return; } - let applicability = Applicability::MachineApplicable; + let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable); let return_replacement = replacement.to_string(); let sugg_help = replacement.sugg_help(); span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index c77554fb47b25..0f525dd294c9b 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -297,8 +297,14 @@ fn issue10051() -> Result { } } -fn issue10049(b1: bool, b2: bool, b3: bool) -> u32 { - (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }) +mod issue10049 { + fn single() -> u32 { + if true { 1 } else { 2 } + } + + fn multiple(b1: bool, b2: bool, b3: bool) -> u32 { + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }) + } } fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 8fed64ac6e3b4..a1db8375d95b9 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -307,8 +307,14 @@ fn issue10051() -> Result { } } -fn issue10049(b1: bool, b2: bool, b3: bool) -> u32 { - return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; +mod issue10049 { + fn single() -> u32 { + return if true { 1 } else { 2 }; + } + + fn multiple(b1: bool, b2: bool, b3: bool) -> u32 { + return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; + } } fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 18edbce2f44ba..87d0cd3e14cfa 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -419,12 +419,20 @@ LL | return Err(format!("err!")); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:311:5 + --> $DIR/needless_return.rs:312:9 | -LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | return if true { 1 } else { 2 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:316:9 + | +LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: remove `return` and wrap the sequence with parentheses -error: aborting due to 51 previous errors +error: aborting due to 52 previous errors From 75aa2b9ec8529a3854a4ebaab1a03438410dc87e Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 13 Feb 2023 20:41:26 +0100 Subject: [PATCH 40/90] uninlined_format_args: do not inline argument with generic parameters --- clippy_lints/src/format_args.rs | 1 + tests/ui/uninlined_format_args.fixed | 4 ++++ tests/ui/uninlined_format_args.rs | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 92238d557e9d2..e7caed65bf28c 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -340,6 +340,7 @@ fn check_one_arg( if matches!(param.kind, Implicit | Starred | Named(_) | Numbered) && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind && let [segment] = path.segments + && segment.args.is_none() && let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id) { let replacement = match param.usage { diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index 9d08e80cf9a55..cbd5cc5fceef5 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -174,3 +174,7 @@ fn _meets_msrv() { let local_i32 = 1; println!("expand='{local_i32}'"); } + +fn _do_not_fire() { + println!("{:?}", None::<()>); +} diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index 35b3677a8968f..cf0ea5be4813f 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -179,3 +179,7 @@ fn _meets_msrv() { let local_i32 = 1; println!("expand='{}'", local_i32); } + +fn _do_not_fire() { + println!("{:?}", None::<()>); +} From cecc45cedcc04ae3a36be8bab321b1eee7b33365 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 14 Feb 2023 14:31:26 +0000 Subject: [PATCH 41/90] Use target instead of machine for mir interpreter integer handling. The naming of `machine` only makes sense from a mir interpreter internals perspective, but outside users talk about the `target` platform --- clippy_lints/src/large_const_arrays.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_utils/src/consts.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index db637dfc068d4..4dc750c03b488 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { let ty = hir_ty_to_ty(cx.tcx, hir_ty); if let ty::Array(element_type, cst) = ty.kind(); if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind(); - if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx); + if let Ok(element_count) = element_count.try_to_target_usize(cx.tcx); if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size); diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 89ae83d48f536..32c6312e06946 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { if let ExprKind::Repeat(_, _) = expr.kind && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx) + && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && !cx.tcx.hir().parent_iter(expr.hir_id) .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. }))) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 9d812fbdcc37e..8b00ce2cc2586 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -640,7 +640,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) - }, mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() { ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match len.kind().try_to_machine_usize(tcx) { + ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) @@ -651,7 +651,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) - .map(Constant::Vec), _ => None, }, - ty::Float(FloatTy::F64) => match len.kind().try_to_machine_usize(tcx) { + ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) From 1ee4651ca1c31b39f106079e7546a47d00a3d945 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Sun, 12 Feb 2023 14:45:44 -0500 Subject: [PATCH 42/90] Ignore synthetic type parameters for `extra_unused_type_parameters` --- clippy_lints/src/extra_unused_type_parameters.rs | 7 +++---- tests/ui/extra_unused_type_parameters.rs | 2 ++ tests/ui/extra_unused_type_parameters.stderr | 10 +++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 9e9ad80b3342f..040473c9ffc62 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -23,7 +23,6 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // unused type parameters /// fn unused_ty(x: u8) { /// // .. /// } @@ -45,7 +44,7 @@ declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]); /// trait bounds those parameters have. struct TypeWalker<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, - /// Collection of all the type parameters and their spans. + /// Collection of all the function's type parameters. ty_params: FxHashMap, /// Collection of any (inline) trait bounds corresponding to each type parameter. bounds: FxHashMap, @@ -69,8 +68,8 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .params .iter() .filter_map(|param| { - if let GenericParamKind::Type { .. } = param.kind { - Some((param.def_id.into(), param.span)) + if let GenericParamKind::Type { synthetic, .. } = param.kind { + (!synthetic).then_some((param.def_id.into(), param.span)) } else { if !param.is_elided_lifetime() { all_params_unused = false; diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs index a1cd8a0d08518..2894fda2f4717 100644 --- a/tests/ui/extra_unused_type_parameters.rs +++ b/tests/ui/extra_unused_type_parameters.rs @@ -71,6 +71,8 @@ where .filter_map(move |(i, a)| if i == index { None } else { Some(a) }) } +fn unused_opaque(dummy: impl Default) {} + mod issue10319 { fn assert_send() {} diff --git a/tests/ui/extra_unused_type_parameters.stderr b/tests/ui/extra_unused_type_parameters.stderr index 69a067bd8490f..aea3ee310f7dd 100644 --- a/tests/ui/extra_unused_type_parameters.stderr +++ b/tests/ui/extra_unused_type_parameters.stderr @@ -55,5 +55,13 @@ LL | fn unused_ty_impl(&self) {} | = help: consider removing the parameter -error: aborting due to 7 previous errors +error: type parameters go unused in function definition + --> $DIR/extra_unused_type_parameters.rs:74:17 + | +LL | fn unused_opaque(dummy: impl Default) {} + | ^^^^^^ + | + = help: consider removing the parameters + +error: aborting due to 8 previous errors From 8ec9543f13ba0fe6af76816441b7c7d54653b854 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 10 Jan 2023 00:18:24 +0100 Subject: [PATCH 43/90] Add `impl_trait_param` lint As this is a lint about "style", and a purely cosmetical choice (using `` over `impl Trait`), a lot of other files needed to be allowed this lint. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../src/functions/impl_trait_param.rs | 88 +++++++++++++++++++ clippy_lints/src/functions/mod.rs | 29 ++++++ clippy_utils/src/ast_utils.rs | 7 +- clippy_utils/src/check_proc_macro.rs | 1 + clippy_utils/src/hir_utils.rs | 1 + clippy_utils/src/macros.rs | 2 +- clippy_utils/src/source.rs | 2 +- tests/ui/borrow_box.rs | 2 +- tests/ui/eta.fixed | 3 +- tests/ui/eta.rs | 3 +- tests/ui/eta.stderr | 52 +++++------ tests/ui/impl_trait_param.rs | 15 ++++ tests/ui/impl_trait_param.stderr | 25 ++++++ tests/ui/trait_duplication_in_bounds.fixed | 1 + tests/ui/trait_duplication_in_bounds.rs | 1 + tests/ui/trait_duplication_in_bounds.stderr | 16 ++-- .../trait_duplication_in_bounds_unfixable.rs | 1 + ...ait_duplication_in_bounds_unfixable.stderr | 16 ++-- 20 files changed, 219 insertions(+), 48 deletions(-) create mode 100644 clippy_lints/src/functions/impl_trait_param.rs create mode 100644 tests/ui/impl_trait_param.rs create mode 100644 tests/ui/impl_trait_param.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 30727beb8e7ff..e2d971b38bcb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4430,6 +4430,7 @@ Released 2018-09-13 [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond +[`impl_trait_param`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_param [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index c1feabf05aafd..41b04f13721bd 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -179,6 +179,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO, crate::from_str_radix_10::FROM_STR_RADIX_10_INFO, crate::functions::DOUBLE_MUST_USE_INFO, + crate::functions::IMPL_TRAIT_PARAM_INFO, crate::functions::MISNAMED_GETTERS_INFO, crate::functions::MUST_USE_CANDIDATE_INFO, crate::functions::MUST_USE_UNIT_INFO, diff --git a/clippy_lints/src/functions/impl_trait_param.rs b/clippy_lints/src/functions/impl_trait_param.rs new file mode 100644 index 0000000000000..1e819dc6c82a2 --- /dev/null +++ b/clippy_lints/src/functions/impl_trait_param.rs @@ -0,0 +1,88 @@ +use clippy_utils::{diagnostics::span_lint_and_then, is_in_test_function}; + +use rustc_hir::{intravisit::FnKind, Body, Generics, HirId}; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::IMPL_TRAIT_PARAM; + +pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { + if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id) + { + if let FnKind::ItemFn(ident, generics, _) = kind { + for param in generics.params { + if param.is_impl_trait() + && !param.name.ident().as_str().contains('<') + && !param.name.ident().as_str().contains('(') + { + // No generics with nested generics, and no generics like FnMut(x) + span_lint_and_then( + cx, + IMPL_TRAIT_PARAM, + param.span, + &format!("'{}' in the function's parameters", param.name.ident().as_str()), + |diag| { + let next_letter = next_valid_letter(generics); + if let Some(gen_span) = generics.span_for_param_suggestion() { + diag.span_suggestion_with_style( + gen_span, + format!( + "create a generic type here and replace that `{}` with `{}`", + param.name.ident().as_str(), + next_letter + ), + ", T: Trait", + rustc_errors::Applicability::MaybeIncorrect, + rustc_errors::SuggestionStyle::ShowAlways, + ); + } else { + // multispan.push_span_label(param.span, format!("Replace this with `{}`", + // next_letter)); + + diag.span_suggestion_with_style( + Span::new( + body.params[0].span.lo() - rustc_span::BytePos(1), + ident.span.hi(), + ident.span.ctxt(), + ident.span.parent(), + ), + format!( + "create a generic type here and replace that '{}' with `{}`", + param.name.ident().as_str(), + next_letter + ), + "", + rustc_errors::Applicability::MaybeIncorrect, + rustc_errors::SuggestionStyle::ShowAlways, + ); + } + }, + ); + } + } + } + } +} + +fn next_valid_letter(generics: &Generics<'_>) -> char { + let mut generics_names = Vec::new(); + + generics.params.iter().for_each(|param| { + generics_names.push(param.name.ident().as_str().to_owned()); + }); + + // If T exists, try with U, then with V, and so on... + let mut current_letter = 84u32; // ASCII code for "T" + while generics_names.contains(&String::from(char::from_u32(current_letter).unwrap())) { + current_letter += 1; + if current_letter == 91 { + // ASCII code for "Z" + current_letter = 65; + } else if current_letter == 83 { + // ASCII "S" + current_letter = 97; // "a" + }; + } + + char::from_u32(current_letter).unwrap() +} diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 4399c68e130f7..cd0df1438df43 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -1,3 +1,4 @@ +mod impl_trait_param; mod misnamed_getters; mod must_use; mod not_unsafe_ptr_arg_deref; @@ -327,6 +328,32 @@ declare_clippy_lint! { "getter method returning the wrong field" } +declare_clippy_lint! { + /// ### What it does + /// Lints when `impl Trait` is being used in a function's paremeters. + /// ### Why is this bad? + /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor. + /// + /// ### Example + /// ```rust + /// trait MyTrait {} + /// fn foo(a: impl MyTrait) { + /// // [...] + /// } + /// ``` + /// Use instead: + /// ```rust + /// trait MyTrait {} + /// fn foo(a: A) { + /// // [...] + /// } + /// ``` + #[clippy::version = "1.68.0"] + pub IMPL_TRAIT_PARAM, + style, + "`impl Trait` is used in the function's parameters" +} + #[derive(Copy, Clone)] pub struct Functions { too_many_arguments_threshold: u64, @@ -354,6 +381,7 @@ impl_lint_pass!(Functions => [ RESULT_UNIT_ERR, RESULT_LARGE_ERR, MISNAMED_GETTERS, + IMPL_TRAIT_PARAM, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -371,6 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold); not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); misnamed_getters::check_fn(cx, kind, decl, body, span); + impl_trait_param::check_fn(cx, &kind, body, hir_id); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 9d0263e93be75..62089320ce35c 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -2,7 +2,12 @@ //! //! - The `eq_foobar` functions test for semantic equality but ignores `NodeId`s and `Span`s. -#![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)] +#![allow( + clippy::similar_names, + clippy::wildcard_imports, + clippy::enum_glob_use, + clippy::impl_trait_param +)] use crate::{both, over}; use rustc_ast::ptr::P; diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 43f0df145f0ec..8650f3c68289a 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -1,3 +1,4 @@ +#![allow(clippy::impl_trait_param)] //! This module handles checking if the span given is from a proc-macro or not. //! //! Proc-macros are capable of setting the span of every token they output to a few possible spans. diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 2bbe1a19b625a..2cd213ed705af 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,3 +1,4 @@ +#![allow(clippy::impl_trait_param)] use crate::consts::constant_simple; use crate::macros::macro_backtrace; use crate::source::snippet_opt; diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 63dccbf697c2d..a85d11f6234c0 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,4 +1,4 @@ -#![allow(clippy::similar_names)] // `expr` and `expn` +#![allow(clippy::similar_names, clippy::impl_trait_param)] // `expr` and `expn` use crate::source::snippet_opt; use crate::visitors::{for_each_expr, Descend}; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index cd5dcfdaca34b..39d00e89551a5 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -1,6 +1,6 @@ //! Utils for extracting, inspecting or transforming source code -#![allow(clippy::module_name_repetitions)] +#![allow(clippy::module_name_repetitions, clippy::impl_trait_param)] use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 3b5b6bf4c9502..e3e5b8464b77d 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,6 +1,6 @@ #![deny(clippy::borrowed_box)] #![allow(dead_code, unused_variables)] -#![allow(clippy::uninlined_format_args, clippy::disallowed_names)] +#![allow(clippy::uninlined_format_args, clippy::disallowed_names, clippy::impl_trait_param)] use std::fmt::Display; diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index dc129591eac4e..8c19143cb2e09 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -7,7 +7,8 @@ clippy::no_effect, clippy::option_map_unit_fn, clippy::redundant_closure_call, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::impl_trait_param )] use std::path::{Path, PathBuf}; diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 025fd6a0b7afd..10d4924c59927 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -7,7 +7,8 @@ clippy::no_effect, clippy::option_map_unit_fn, clippy::redundant_closure_call, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::impl_trait_param )] use std::path::{Path, PathBuf}; diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index a521fb868607a..6ddecc58eaf12 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure - --> $DIR/eta.rs:28:27 + --> $DIR/eta.rs:29:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -7,31 +7,31 @@ LL | let a = Some(1u8).map(|a| foo(a)); = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:32:40 + --> $DIR/eta.rs:33:40 | LL | let _: Option> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> $DIR/eta.rs:33:35 + --> $DIR/eta.rs:34:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: redundant closure - --> $DIR/eta.rs:34:26 + --> $DIR/eta.rs:35:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> $DIR/eta.rs:41:27 + --> $DIR/eta.rs:42:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> $DIR/eta.rs:87:51 + --> $DIR/eta.rs:88:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -39,121 +39,121 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:88:51 + --> $DIR/eta.rs:89:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> $DIR/eta.rs:90:42 + --> $DIR/eta.rs:91:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> $DIR/eta.rs:94:29 + --> $DIR/eta.rs:95:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> $DIR/eta.rs:95:27 + --> $DIR/eta.rs:96:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> $DIR/eta.rs:97:65 + --> $DIR/eta.rs:98:65 | LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> $DIR/eta.rs:160:22 + --> $DIR/eta.rs:161:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> $DIR/eta.rs:167:27 + --> $DIR/eta.rs:168:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> $DIR/eta.rs:172:27 + --> $DIR/eta.rs:173:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> $DIR/eta.rs:204:28 + --> $DIR/eta.rs:205:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:205:28 + --> $DIR/eta.rs:206:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:206:28 + --> $DIR/eta.rs:207:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> $DIR/eta.rs:213:21 + --> $DIR/eta.rs:214:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> $DIR/eta.rs:217:21 + --> $DIR/eta.rs:218:21 | LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` error: redundant closure - --> $DIR/eta.rs:310:18 + --> $DIR/eta.rs:311:18 | LL | takes_fn_mut(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> $DIR/eta.rs:313:19 + --> $DIR/eta.rs:314:19 | LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> $DIR/eta.rs:317:26 + --> $DIR/eta.rs:318:26 | LL | move || takes_fn_mut(|| f_used_once()) | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` error: redundant closure - --> $DIR/eta.rs:329:19 + --> $DIR/eta.rs:330:19 | LL | array_opt.map(|a| a.as_slice()); | ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice` error: redundant closure - --> $DIR/eta.rs:332:19 + --> $DIR/eta.rs:333:19 | LL | slice_opt.map(|s| s.len()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len` error: redundant closure - --> $DIR/eta.rs:335:17 + --> $DIR/eta.rs:336:17 | LL | ptr_opt.map(|p| p.is_null()); | ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null` error: redundant closure - --> $DIR/eta.rs:339:17 + --> $DIR/eta.rs:340:17 | LL | dyn_opt.map(|d| d.method_on_dyn()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `::method_on_dyn` diff --git a/tests/ui/impl_trait_param.rs b/tests/ui/impl_trait_param.rs new file mode 100644 index 0000000000000..3bb9cdbaa0945 --- /dev/null +++ b/tests/ui/impl_trait_param.rs @@ -0,0 +1,15 @@ +#![allow(unused)] +#![warn(clippy::impl_trait_param)] + +pub trait Trait {} + +// Should warn +pub fn a(_: impl Trait) {} +pub fn c(_: C, _: impl Trait) {} + +// Shouldn't warn + +pub fn b(_: B) {} +fn d(_: D, _: impl Trait) {} + +fn main() {} diff --git a/tests/ui/impl_trait_param.stderr b/tests/ui/impl_trait_param.stderr new file mode 100644 index 0000000000000..55dec5d0d99f4 --- /dev/null +++ b/tests/ui/impl_trait_param.stderr @@ -0,0 +1,25 @@ +error: 'impl Trait' in the function's parameters + --> $DIR/impl_trait_param.rs:7:13 + | +LL | pub fn a(_: impl Trait) {} + | ^^^^^^^^^^ + | + = note: `-D clippy::impl-trait-param` implied by `-D warnings` +help: create a generic type here and replace that 'impl Trait' with `T` + | +LL | pub fn a(_: impl Trait) {} + | ++++++++++ + +error: 'impl Trait' in the function's parameters + --> $DIR/impl_trait_param.rs:8:29 + | +LL | pub fn c(_: C, _: impl Trait) {} + | ^^^^^^^^^^ + | +help: create a generic type here and replace that `impl Trait` with `T` + | +LL | pub fn c(_: C, _: impl Trait) {} + | ++++++++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index 4ce5d42178225..a587cc8b456fa 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -1,5 +1,6 @@ // run-rustfix #![deny(clippy::trait_duplication_in_bounds)] +#![allow(clippy::impl_trait_param)] #![allow(unused)] fn bad_foo(arg0: T, argo1: U) { diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index 7f2e96a22e664..beb41ea26d966 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -1,5 +1,6 @@ // run-rustfix #![deny(clippy::trait_duplication_in_bounds)] +#![allow(clippy::impl_trait_param)] #![allow(unused)] fn bad_foo(arg0: T, argo1: U) { diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr index af800ba78880c..5216b2250dbd0 100644 --- a/tests/ui/trait_duplication_in_bounds.stderr +++ b/tests/ui/trait_duplication_in_bounds.stderr @@ -1,5 +1,5 @@ error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:5:15 + --> $DIR/trait_duplication_in_bounds.rs:6:15 | LL | fn bad_foo(arg0: T, argo1: U) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` @@ -11,43 +11,43 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:11:8 + --> $DIR/trait_duplication_in_bounds.rs:12:8 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:39:26 + --> $DIR/trait_duplication_in_bounds.rs:40:26 | LL | trait BadSelfTraitBound: Clone + Clone + Clone { | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:46:15 + --> $DIR/trait_duplication_in_bounds.rs:47:15 | LL | Self: Clone + Clone + Clone; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:60:24 + --> $DIR/trait_duplication_in_bounds.rs:61:24 | LL | trait BadTraitBound { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:67:12 + --> $DIR/trait_duplication_in_bounds.rs:68:12 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:100:19 + --> $DIR/trait_duplication_in_bounds.rs:101:19 | LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:108:22 + --> $DIR/trait_duplication_in_bounds.rs:109:22 | LL | fn qualified_path(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone` diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.rs b/tests/ui/trait_duplication_in_bounds_unfixable.rs index 5630a0345adb1..63ae4493143ee 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.rs +++ b/tests/ui/trait_duplication_in_bounds_unfixable.rs @@ -1,4 +1,5 @@ #![deny(clippy::trait_duplication_in_bounds)] +#![allow(clippy::impl_trait_param)] use std::collections::BTreeMap; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr index 4d56a94646cb6..48091b38fb41b 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.stderr +++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr @@ -1,5 +1,5 @@ error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:7:15 | LL | fn bad_foo(arg0: T, arg1: Z) | ^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:7:23 | LL | fn bad_foo(arg0: T, arg1: Z) | ^^^^^^^ @@ -20,7 +20,7 @@ LL | fn bad_foo(arg0: T, arg1: Z) = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:35:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:36:15 | LL | Self: Default; | ^^^^^^^ @@ -28,7 +28,7 @@ LL | Self: Default; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:49:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:50:15 | LL | Self: Default + Clone; | ^^^^^^^ @@ -36,7 +36,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:56:15 | LL | Self: Default + Clone; | ^^^^^^^ @@ -44,7 +44,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:25 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:56:25 | LL | Self: Default + Clone; | ^^^^^ @@ -52,7 +52,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:58:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:59:15 | LL | Self: Default; | ^^^^^^^ @@ -60,7 +60,7 @@ LL | Self: Default; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:93:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:94:15 | LL | Self: Iterator, | ^^^^^^^^^^^^^^^^^^^^ From ade4c9b2b6e99e0663408318e41139d65a9d0630 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 13 Jan 2023 12:17:30 +0100 Subject: [PATCH 44/90] Rename lint to better fit lint naming conventions --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 2 +- .../{impl_trait_param.rs => impl_trait_in_params.rs} | 4 ++-- clippy_lints/src/functions/mod.rs | 8 ++++---- clippy_utils/src/ast_utils.rs | 2 +- clippy_utils/src/check_proc_macro.rs | 2 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/macros.rs | 2 +- clippy_utils/src/source.rs | 2 +- tests/ui/borrow_box.rs | 2 +- tests/ui/eta.fixed | 2 +- tests/ui/eta.rs | 2 +- tests/ui/{impl_trait_param.rs => impl_trait_in_params.rs} | 2 +- ...mpl_trait_param.stderr => impl_trait_in_params.stderr} | 0 tests/ui/trait_duplication_in_bounds.fixed | 2 +- tests/ui/trait_duplication_in_bounds.rs | 2 +- tests/ui/trait_duplication_in_bounds_unfixable.rs | 2 +- 17 files changed, 20 insertions(+), 19 deletions(-) rename clippy_lints/src/functions/{impl_trait_param.rs => impl_trait_in_params.rs} (98%) rename tests/ui/{impl_trait_param.rs => impl_trait_in_params.rs} (85%) rename tests/ui/{impl_trait_param.stderr => impl_trait_in_params.stderr} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2d971b38bcb7..db2602285c939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4430,6 +4430,7 @@ Released 2018-09-13 [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond +[`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params [`impl_trait_param`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_param [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 41b04f13721bd..9be4f5bf7fc9b 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -179,7 +179,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO, crate::from_str_radix_10::FROM_STR_RADIX_10_INFO, crate::functions::DOUBLE_MUST_USE_INFO, - crate::functions::IMPL_TRAIT_PARAM_INFO, + crate::functions::IMPL_TRAIT_IN_PARAMS_INFO, crate::functions::MISNAMED_GETTERS_INFO, crate::functions::MUST_USE_CANDIDATE_INFO, crate::functions::MUST_USE_UNIT_INFO, diff --git a/clippy_lints/src/functions/impl_trait_param.rs b/clippy_lints/src/functions/impl_trait_in_params.rs similarity index 98% rename from clippy_lints/src/functions/impl_trait_param.rs rename to clippy_lints/src/functions/impl_trait_in_params.rs index 1e819dc6c82a2..f0bfbbf1ea3f8 100644 --- a/clippy_lints/src/functions/impl_trait_param.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -4,7 +4,7 @@ use rustc_hir::{intravisit::FnKind, Body, Generics, HirId}; use rustc_lint::LateContext; use rustc_span::Span; -use super::IMPL_TRAIT_PARAM; +use super::IMPL_TRAIT_IN_PARAMS; pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) { if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id) @@ -18,7 +18,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: // No generics with nested generics, and no generics like FnMut(x) span_lint_and_then( cx, - IMPL_TRAIT_PARAM, + IMPL_TRAIT_IN_PARAMS, param.span, &format!("'{}' in the function's parameters", param.name.ident().as_str()), |diag| { diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index cd0df1438df43..81b7bfe7181bc 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -1,4 +1,4 @@ -mod impl_trait_param; +mod impl_trait_in_params; mod misnamed_getters; mod must_use; mod not_unsafe_ptr_arg_deref; @@ -349,7 +349,7 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.68.0"] - pub IMPL_TRAIT_PARAM, + pub IMPL_TRAIT_IN_PARAMS, style, "`impl Trait` is used in the function's parameters" } @@ -381,7 +381,7 @@ impl_lint_pass!(Functions => [ RESULT_UNIT_ERR, RESULT_LARGE_ERR, MISNAMED_GETTERS, - IMPL_TRAIT_PARAM, + IMPL_TRAIT_IN_PARAMS, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -399,7 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold); not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); misnamed_getters::check_fn(cx, kind, decl, body, span); - impl_trait_param::check_fn(cx, &kind, body, hir_id); + impl_trait_in_params::check_fn(cx, &kind, body, hir_id); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 62089320ce35c..65d287d493b4f 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -6,7 +6,7 @@ clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use, - clippy::impl_trait_param + clippy::impl_trait_in_params )] use crate::{both, over}; diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 8650f3c68289a..353926074b5d0 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -1,4 +1,4 @@ -#![allow(clippy::impl_trait_param)] +#![allow(clippy::impl_trait_in_params)] //! This module handles checking if the span given is from a proc-macro or not. //! //! Proc-macros are capable of setting the span of every token they output to a few possible spans. diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 2cd213ed705af..115d8aafaf77c 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,4 +1,4 @@ -#![allow(clippy::impl_trait_param)] +#![allow(clippy::impl_trait_in_params)] use crate::consts::constant_simple; use crate::macros::macro_backtrace; use crate::source::snippet_opt; diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index a85d11f6234c0..cac29ac9c0153 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,4 +1,4 @@ -#![allow(clippy::similar_names, clippy::impl_trait_param)] // `expr` and `expn` +#![allow(clippy::similar_names, clippy::impl_trait_in_params)] // `expr` and `expn` use crate::source::snippet_opt; use crate::visitors::{for_each_expr, Descend}; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 39d00e89551a5..e802941b5d8a7 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -1,6 +1,6 @@ //! Utils for extracting, inspecting or transforming source code -#![allow(clippy::module_name_repetitions, clippy::impl_trait_param)] +#![allow(clippy::module_name_repetitions, clippy::impl_trait_in_params)] use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index e3e5b8464b77d..3dfd8191adffa 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,6 +1,6 @@ #![deny(clippy::borrowed_box)] #![allow(dead_code, unused_variables)] -#![allow(clippy::uninlined_format_args, clippy::disallowed_names, clippy::impl_trait_param)] +#![allow(clippy::uninlined_format_args, clippy::disallowed_names, clippy::impl_trait_in_params)] use std::fmt::Display; diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index 8c19143cb2e09..c1ad0b66e01b2 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -8,7 +8,7 @@ clippy::option_map_unit_fn, clippy::redundant_closure_call, clippy::uninlined_format_args, - clippy::impl_trait_param + clippy::impl_trait_in_params )] use std::path::{Path, PathBuf}; diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 10d4924c59927..000af653c1521 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -8,7 +8,7 @@ clippy::option_map_unit_fn, clippy::redundant_closure_call, clippy::uninlined_format_args, - clippy::impl_trait_param + clippy::impl_trait_in_params )] use std::path::{Path, PathBuf}; diff --git a/tests/ui/impl_trait_param.rs b/tests/ui/impl_trait_in_params.rs similarity index 85% rename from tests/ui/impl_trait_param.rs rename to tests/ui/impl_trait_in_params.rs index 3bb9cdbaa0945..8402730d31056 100644 --- a/tests/ui/impl_trait_param.rs +++ b/tests/ui/impl_trait_in_params.rs @@ -1,5 +1,5 @@ #![allow(unused)] -#![warn(clippy::impl_trait_param)] +#![warn(clippy::impl_trait_in_params)] pub trait Trait {} diff --git a/tests/ui/impl_trait_param.stderr b/tests/ui/impl_trait_in_params.stderr similarity index 100% rename from tests/ui/impl_trait_param.stderr rename to tests/ui/impl_trait_in_params.stderr diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index a587cc8b456fa..373859a25648e 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -1,6 +1,6 @@ // run-rustfix #![deny(clippy::trait_duplication_in_bounds)] -#![allow(clippy::impl_trait_param)] +#![allow(clippy::impl_trait_in_params)] #![allow(unused)] fn bad_foo(arg0: T, argo1: U) { diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index beb41ea26d966..3afd74aa9b2c3 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -1,6 +1,6 @@ // run-rustfix #![deny(clippy::trait_duplication_in_bounds)] -#![allow(clippy::impl_trait_param)] +#![allow(clippy::impl_trait_in_params)] #![allow(unused)] fn bad_foo(arg0: T, argo1: U) { diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.rs b/tests/ui/trait_duplication_in_bounds_unfixable.rs index 63ae4493143ee..7435a4ba609cb 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.rs +++ b/tests/ui/trait_duplication_in_bounds_unfixable.rs @@ -1,5 +1,5 @@ #![deny(clippy::trait_duplication_in_bounds)] -#![allow(clippy::impl_trait_param)] +#![allow(clippy::impl_trait_in_params)] use std::collections::BTreeMap; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; From 6c9983b936645629d8bf66d2aac9ba5e588f5fb7 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 13 Jan 2023 12:21:17 +0100 Subject: [PATCH 45/90] Exec `cargo dev update_lints` --- CHANGELOG.md | 1 - tests/ui/borrow_box.rs | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db2602285c939..486ffd725c0c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4431,7 +4431,6 @@ Released 2018-09-13 [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params -[`impl_trait_param`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_param [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 3dfd8191adffa..8fe160e8e0f56 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,6 +1,10 @@ #![deny(clippy::borrowed_box)] #![allow(dead_code, unused_variables)] -#![allow(clippy::uninlined_format_args, clippy::disallowed_names, clippy::impl_trait_in_params)] +#![allow( + clippy::uninlined_format_args, + clippy::disallowed_names, + clippy::impl_trait_in_params +)] use std::fmt::Display; From bdf4fd3e82542cea1f9104cef7bd82839ed84213 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 13 Jan 2023 12:54:51 +0100 Subject: [PATCH 46/90] Tests pass --- clippy_lints/src/functions/mod.rs | 2 +- tests/ui/borrow_box.stderr | 20 ++++++++++---------- tests/ui/impl_trait_in_params.rs | 4 +++- tests/ui/impl_trait_in_params.stderr | 6 +++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 81b7bfe7181bc..e7f22f8d778cd 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -344,7 +344,7 @@ declare_clippy_lint! { /// Use instead: /// ```rust /// trait MyTrait {} - /// fn foo(a: A) { + /// fn foo(a: T) { /// // [...] /// } /// ``` diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 99cb60a1ead9b..90e752211ff05 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:20:14 + --> $DIR/borrow_box.rs:24:14 | LL | let foo: &Box; | ^^^^^^^^^^ help: try: `&bool` @@ -11,55 +11,55 @@ LL | #![deny(clippy::borrowed_box)] | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:24:10 + --> $DIR/borrow_box.rs:28:10 | LL | foo: &'a Box, | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:28:17 + --> $DIR/borrow_box.rs:32:17 | LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:94:25 + --> $DIR/borrow_box.rs:98:25 | LL | pub fn test14(_display: &Box) {} | ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:95:25 + --> $DIR/borrow_box.rs:99:25 | LL | pub fn test15(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:96:29 + --> $DIR/borrow_box.rs:100:29 | LL | pub fn test16<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:98:25 + --> $DIR/borrow_box.rs:102:25 | LL | pub fn test17(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:99:25 + --> $DIR/borrow_box.rs:103:25 | LL | pub fn test18(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:100:29 + --> $DIR/borrow_box.rs:104:29 | LL | pub fn test19<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:105:25 + --> $DIR/borrow_box.rs:109:25 | LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` diff --git a/tests/ui/impl_trait_in_params.rs b/tests/ui/impl_trait_in_params.rs index 8402730d31056..07560101a4167 100644 --- a/tests/ui/impl_trait_in_params.rs +++ b/tests/ui/impl_trait_in_params.rs @@ -2,14 +2,16 @@ #![warn(clippy::impl_trait_in_params)] pub trait Trait {} +pub trait AnotherTrait {} // Should warn pub fn a(_: impl Trait) {} pub fn c(_: C, _: impl Trait) {} +fn d(_: impl AnotherTrait) {} // Shouldn't warn pub fn b(_: B) {} -fn d(_: D, _: impl Trait) {} +fn e>(_: T) {} fn main() {} diff --git a/tests/ui/impl_trait_in_params.stderr b/tests/ui/impl_trait_in_params.stderr index 55dec5d0d99f4..a43986017febd 100644 --- a/tests/ui/impl_trait_in_params.stderr +++ b/tests/ui/impl_trait_in_params.stderr @@ -1,17 +1,17 @@ error: 'impl Trait' in the function's parameters - --> $DIR/impl_trait_param.rs:7:13 + --> $DIR/impl_trait_in_params.rs:8:13 | LL | pub fn a(_: impl Trait) {} | ^^^^^^^^^^ | - = note: `-D clippy::impl-trait-param` implied by `-D warnings` + = note: `-D clippy::impl-trait-in-params` implied by `-D warnings` help: create a generic type here and replace that 'impl Trait' with `T` | LL | pub fn a(_: impl Trait) {} | ++++++++++ error: 'impl Trait' in the function's parameters - --> $DIR/impl_trait_param.rs:8:29 + --> $DIR/impl_trait_in_params.rs:9:29 | LL | pub fn c(_: C, _: impl Trait) {} | ^^^^^^^^^^ From 8a2245dcb6ccf8d9491d6fdc7681a4f34739093c Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 13 Jan 2023 19:41:06 +0100 Subject: [PATCH 47/90] Change lint's from `style` to `restriction` --- clippy_lints/src/functions/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index e7f22f8d778cd..d2852b4acad1e 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -350,7 +350,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.68.0"] pub IMPL_TRAIT_IN_PARAMS, - style, + restriction, "`impl Trait` is used in the function's parameters" } From 6aa06b757dde06b43c198d352c51e1eef82bbb1c Mon Sep 17 00:00:00 2001 From: blyxyas Date: Thu, 19 Jan 2023 16:24:47 +0100 Subject: [PATCH 48/90] Remove `#[allow]`s. Apply conversations from @Jarcho --- .../src/functions/impl_trait_in_params.rs | 23 +++----- clippy_utils/src/ast_utils.rs | 7 +-- clippy_utils/src/check_proc_macro.rs | 1 - clippy_utils/src/hir_utils.rs | 1 - clippy_utils/src/macros.rs | 2 +- clippy_utils/src/source.rs | 2 +- tests/ui/borrow_box.rs | 6 +-- tests/ui/borrow_box.stderr | 20 +++---- tests/ui/eta.fixed | 3 +- tests/ui/eta.rs | 3 +- tests/ui/eta.stderr | 52 +++++++++---------- tests/ui/impl_trait_in_params.stderr | 8 +-- tests/ui/trait_duplication_in_bounds.fixed | 1 - tests/ui/trait_duplication_in_bounds.rs | 1 - tests/ui/trait_duplication_in_bounds.stderr | 16 +++--- .../trait_duplication_in_bounds_unfixable.rs | 1 - ...ait_duplication_in_bounds_unfixable.stderr | 16 +++--- 17 files changed, 68 insertions(+), 95 deletions(-) diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index f0bfbbf1ea3f8..ace5932f4e4ae 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -11,27 +11,20 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: { if let FnKind::ItemFn(ident, generics, _) = kind { for param in generics.params { - if param.is_impl_trait() - && !param.name.ident().as_str().contains('<') - && !param.name.ident().as_str().contains('(') - { + if param.is_impl_trait() { // No generics with nested generics, and no generics like FnMut(x) span_lint_and_then( cx, IMPL_TRAIT_IN_PARAMS, param.span, - &format!("'{}' in the function's parameters", param.name.ident().as_str()), + "'`impl Trait` used as a function parameter'", |diag| { let next_letter = next_valid_letter(generics); if let Some(gen_span) = generics.span_for_param_suggestion() { diag.span_suggestion_with_style( gen_span, - format!( - "create a generic type here and replace that `{}` with `{}`", - param.name.ident().as_str(), - next_letter - ), - ", T: Trait", + "add a type paremeter, `{}`: `{}`", + format!(", {next_letter}: {}", ¶m.name.ident().as_str()[5..]), rustc_errors::Applicability::MaybeIncorrect, rustc_errors::SuggestionStyle::ShowAlways, ); @@ -46,12 +39,8 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: ident.span.ctxt(), ident.span.parent(), ), - format!( - "create a generic type here and replace that '{}' with `{}`", - param.name.ident().as_str(), - next_letter - ), - "", + "add a type paremeter", + format!("<{next_letter}: {}>", ¶m.name.ident().as_str()[5..]), rustc_errors::Applicability::MaybeIncorrect, rustc_errors::SuggestionStyle::ShowAlways, ); diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 65d287d493b4f..9d0263e93be75 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -2,12 +2,7 @@ //! //! - The `eq_foobar` functions test for semantic equality but ignores `NodeId`s and `Span`s. -#![allow( - clippy::similar_names, - clippy::wildcard_imports, - clippy::enum_glob_use, - clippy::impl_trait_in_params -)] +#![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)] use crate::{both, over}; use rustc_ast::ptr::P; diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 353926074b5d0..43f0df145f0ec 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -1,4 +1,3 @@ -#![allow(clippy::impl_trait_in_params)] //! This module handles checking if the span given is from a proc-macro or not. //! //! Proc-macros are capable of setting the span of every token they output to a few possible spans. diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 115d8aafaf77c..2bbe1a19b625a 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,4 +1,3 @@ -#![allow(clippy::impl_trait_in_params)] use crate::consts::constant_simple; use crate::macros::macro_backtrace; use crate::source::snippet_opt; diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index cac29ac9c0153..63dccbf697c2d 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,4 +1,4 @@ -#![allow(clippy::similar_names, clippy::impl_trait_in_params)] // `expr` and `expn` +#![allow(clippy::similar_names)] // `expr` and `expn` use crate::source::snippet_opt; use crate::visitors::{for_each_expr, Descend}; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index e802941b5d8a7..cd5dcfdaca34b 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -1,6 +1,6 @@ //! Utils for extracting, inspecting or transforming source code -#![allow(clippy::module_name_repetitions, clippy::impl_trait_in_params)] +#![allow(clippy::module_name_repetitions)] use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 8fe160e8e0f56..3b5b6bf4c9502 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,10 +1,6 @@ #![deny(clippy::borrowed_box)] #![allow(dead_code, unused_variables)] -#![allow( - clippy::uninlined_format_args, - clippy::disallowed_names, - clippy::impl_trait_in_params -)] +#![allow(clippy::uninlined_format_args, clippy::disallowed_names)] use std::fmt::Display; diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 90e752211ff05..99cb60a1ead9b 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:24:14 + --> $DIR/borrow_box.rs:20:14 | LL | let foo: &Box; | ^^^^^^^^^^ help: try: `&bool` @@ -11,55 +11,55 @@ LL | #![deny(clippy::borrowed_box)] | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:28:10 + --> $DIR/borrow_box.rs:24:10 | LL | foo: &'a Box, | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:32:17 + --> $DIR/borrow_box.rs:28:17 | LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:98:25 + --> $DIR/borrow_box.rs:94:25 | LL | pub fn test14(_display: &Box) {} | ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:99:25 + --> $DIR/borrow_box.rs:95:25 | LL | pub fn test15(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:100:29 + --> $DIR/borrow_box.rs:96:29 | LL | pub fn test16<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:102:25 + --> $DIR/borrow_box.rs:98:25 | LL | pub fn test17(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:103:25 + --> $DIR/borrow_box.rs:99:25 | LL | pub fn test18(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:104:29 + --> $DIR/borrow_box.rs:100:29 | LL | pub fn test19<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:109:25 + --> $DIR/borrow_box.rs:105:25 | LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index c1ad0b66e01b2..dc129591eac4e 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -7,8 +7,7 @@ clippy::no_effect, clippy::option_map_unit_fn, clippy::redundant_closure_call, - clippy::uninlined_format_args, - clippy::impl_trait_in_params + clippy::uninlined_format_args )] use std::path::{Path, PathBuf}; diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 000af653c1521..025fd6a0b7afd 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -7,8 +7,7 @@ clippy::no_effect, clippy::option_map_unit_fn, clippy::redundant_closure_call, - clippy::uninlined_format_args, - clippy::impl_trait_in_params + clippy::uninlined_format_args )] use std::path::{Path, PathBuf}; diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index 6ddecc58eaf12..a521fb868607a 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure - --> $DIR/eta.rs:29:27 + --> $DIR/eta.rs:28:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -7,31 +7,31 @@ LL | let a = Some(1u8).map(|a| foo(a)); = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:33:40 + --> $DIR/eta.rs:32:40 | LL | let _: Option> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> $DIR/eta.rs:34:35 + --> $DIR/eta.rs:33:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: redundant closure - --> $DIR/eta.rs:35:26 + --> $DIR/eta.rs:34:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> $DIR/eta.rs:42:27 + --> $DIR/eta.rs:41:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> $DIR/eta.rs:88:51 + --> $DIR/eta.rs:87:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -39,121 +39,121 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:89:51 + --> $DIR/eta.rs:88:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> $DIR/eta.rs:91:42 + --> $DIR/eta.rs:90:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> $DIR/eta.rs:95:29 + --> $DIR/eta.rs:94:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> $DIR/eta.rs:96:27 + --> $DIR/eta.rs:95:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> $DIR/eta.rs:98:65 + --> $DIR/eta.rs:97:65 | LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> $DIR/eta.rs:161:22 + --> $DIR/eta.rs:160:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> $DIR/eta.rs:168:27 + --> $DIR/eta.rs:167:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> $DIR/eta.rs:173:27 + --> $DIR/eta.rs:172:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> $DIR/eta.rs:205:28 + --> $DIR/eta.rs:204:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:206:28 + --> $DIR/eta.rs:205:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:207:28 + --> $DIR/eta.rs:206:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> $DIR/eta.rs:214:21 + --> $DIR/eta.rs:213:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> $DIR/eta.rs:218:21 + --> $DIR/eta.rs:217:21 | LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` error: redundant closure - --> $DIR/eta.rs:311:18 + --> $DIR/eta.rs:310:18 | LL | takes_fn_mut(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> $DIR/eta.rs:314:19 + --> $DIR/eta.rs:313:19 | LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> $DIR/eta.rs:318:26 + --> $DIR/eta.rs:317:26 | LL | move || takes_fn_mut(|| f_used_once()) | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` error: redundant closure - --> $DIR/eta.rs:330:19 + --> $DIR/eta.rs:329:19 | LL | array_opt.map(|a| a.as_slice()); | ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice` error: redundant closure - --> $DIR/eta.rs:333:19 + --> $DIR/eta.rs:332:19 | LL | slice_opt.map(|s| s.len()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len` error: redundant closure - --> $DIR/eta.rs:336:17 + --> $DIR/eta.rs:335:17 | LL | ptr_opt.map(|p| p.is_null()); | ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null` error: redundant closure - --> $DIR/eta.rs:340:17 + --> $DIR/eta.rs:339:17 | LL | dyn_opt.map(|d| d.method_on_dyn()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `::method_on_dyn` diff --git a/tests/ui/impl_trait_in_params.stderr b/tests/ui/impl_trait_in_params.stderr index a43986017febd..62b264f0051cd 100644 --- a/tests/ui/impl_trait_in_params.stderr +++ b/tests/ui/impl_trait_in_params.stderr @@ -1,22 +1,22 @@ -error: 'impl Trait' in the function's parameters +error: '`impl Trait` used as a function parameter' --> $DIR/impl_trait_in_params.rs:8:13 | LL | pub fn a(_: impl Trait) {} | ^^^^^^^^^^ | = note: `-D clippy::impl-trait-in-params` implied by `-D warnings` -help: create a generic type here and replace that 'impl Trait' with `T` +help: add a type paremeter | LL | pub fn a(_: impl Trait) {} | ++++++++++ -error: 'impl Trait' in the function's parameters +error: '`impl Trait` used as a function parameter' --> $DIR/impl_trait_in_params.rs:9:29 | LL | pub fn c(_: C, _: impl Trait) {} | ^^^^^^^^^^ | -help: create a generic type here and replace that `impl Trait` with `T` +help: add a type paremeter, `{}`: `{}` | LL | pub fn c(_: C, _: impl Trait) {} | ++++++++++ diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index 373859a25648e..4ce5d42178225 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -1,6 +1,5 @@ // run-rustfix #![deny(clippy::trait_duplication_in_bounds)] -#![allow(clippy::impl_trait_in_params)] #![allow(unused)] fn bad_foo(arg0: T, argo1: U) { diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index 3afd74aa9b2c3..7f2e96a22e664 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -1,6 +1,5 @@ // run-rustfix #![deny(clippy::trait_duplication_in_bounds)] -#![allow(clippy::impl_trait_in_params)] #![allow(unused)] fn bad_foo(arg0: T, argo1: U) { diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr index 5216b2250dbd0..af800ba78880c 100644 --- a/tests/ui/trait_duplication_in_bounds.stderr +++ b/tests/ui/trait_duplication_in_bounds.stderr @@ -1,5 +1,5 @@ error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:6:15 + --> $DIR/trait_duplication_in_bounds.rs:5:15 | LL | fn bad_foo(arg0: T, argo1: U) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` @@ -11,43 +11,43 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:12:8 + --> $DIR/trait_duplication_in_bounds.rs:11:8 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:40:26 + --> $DIR/trait_duplication_in_bounds.rs:39:26 | LL | trait BadSelfTraitBound: Clone + Clone + Clone { | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:47:15 + --> $DIR/trait_duplication_in_bounds.rs:46:15 | LL | Self: Clone + Clone + Clone; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:61:24 + --> $DIR/trait_duplication_in_bounds.rs:60:24 | LL | trait BadTraitBound { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:68:12 + --> $DIR/trait_duplication_in_bounds.rs:67:12 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:101:19 + --> $DIR/trait_duplication_in_bounds.rs:100:19 | LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:109:22 + --> $DIR/trait_duplication_in_bounds.rs:108:22 | LL | fn qualified_path(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone` diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.rs b/tests/ui/trait_duplication_in_bounds_unfixable.rs index 7435a4ba609cb..5630a0345adb1 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.rs +++ b/tests/ui/trait_duplication_in_bounds_unfixable.rs @@ -1,5 +1,4 @@ #![deny(clippy::trait_duplication_in_bounds)] -#![allow(clippy::impl_trait_in_params)] use std::collections::BTreeMap; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr index 48091b38fb41b..4d56a94646cb6 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.stderr +++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr @@ -1,5 +1,5 @@ error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds_unfixable.rs:7:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15 | LL | fn bad_foo(arg0: T, arg1: Z) | ^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds_unfixable.rs:7:23 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 | LL | fn bad_foo(arg0: T, arg1: Z) | ^^^^^^^ @@ -20,7 +20,7 @@ LL | fn bad_foo(arg0: T, arg1: Z) = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:36:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:35:15 | LL | Self: Default; | ^^^^^^^ @@ -28,7 +28,7 @@ LL | Self: Default; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:50:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:49:15 | LL | Self: Default + Clone; | ^^^^^^^ @@ -36,7 +36,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:56:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:15 | LL | Self: Default + Clone; | ^^^^^^^ @@ -44,7 +44,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:56:25 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:25 | LL | Self: Default + Clone; | ^^^^^ @@ -52,7 +52,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:59:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:58:15 | LL | Self: Default; | ^^^^^^^ @@ -60,7 +60,7 @@ LL | Self: Default; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds_unfixable.rs:94:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:93:15 | LL | Self: Iterator, | ^^^^^^^^^^^^^^^^^^^^ From 4166b7dcfe0384c57dbf24d219b05ccdba30e203 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Wed, 25 Jan 2023 19:19:16 +0100 Subject: [PATCH 49/90] Fix lint message --- clippy_lints/src/functions/impl_trait_in_params.rs | 2 +- tests/ui/impl_trait_in_params.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index ace5932f4e4ae..e4b270db672cb 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -23,7 +23,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: if let Some(gen_span) = generics.span_for_param_suggestion() { diag.span_suggestion_with_style( gen_span, - "add a type paremeter, `{}`: `{}`", + "add a type paremeter", format!(", {next_letter}: {}", ¶m.name.ident().as_str()[5..]), rustc_errors::Applicability::MaybeIncorrect, rustc_errors::SuggestionStyle::ShowAlways, diff --git a/tests/ui/impl_trait_in_params.stderr b/tests/ui/impl_trait_in_params.stderr index 62b264f0051cd..c0bcdfd6d4256 100644 --- a/tests/ui/impl_trait_in_params.stderr +++ b/tests/ui/impl_trait_in_params.stderr @@ -16,7 +16,7 @@ error: '`impl Trait` used as a function parameter' LL | pub fn c(_: C, _: impl Trait) {} | ^^^^^^^^^^ | -help: add a type paremeter, `{}`: `{}` +help: add a type paremeter | LL | pub fn c(_: C, _: impl Trait) {} | ++++++++++ From 6ef34bf009343a398b3d04850c5f0784329ebe99 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 3 Feb 2023 16:46:55 +0100 Subject: [PATCH 50/90] Remove commented code --- clippy_lints/src/functions/impl_trait_in_params.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index e4b270db672cb..1f00e357bfa46 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -29,9 +29,6 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: rustc_errors::SuggestionStyle::ShowAlways, ); } else { - // multispan.push_span_label(param.span, format!("Replace this with `{}`", - // next_letter)); - diag.span_suggestion_with_style( Span::new( body.params[0].span.lo() - rustc_span::BytePos(1), From 27a476839f9fbedbecddf2f42bf40a94c4558ef1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 6 Feb 2023 18:38:52 +0000 Subject: [PATCH 51/90] Rename some region-specific stuff --- clippy_lints/src/ptr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index d88409c356e91..fc550936165e6 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -505,13 +505,13 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio if let FnRetTy::Return(ty) = sig.decl.output && let Some((out, Mutability::Mut, _)) = get_ref_lm(ty) { - let out_region = cx.tcx.named_region(out.hir_id); + let out_region = cx.tcx.named_bound_var(out.hir_id); let args: Option> = sig .decl .inputs .iter() .filter_map(get_ref_lm) - .filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region) + .filter(|&(lt, _, _)| cx.tcx.named_bound_var(lt.hir_id) == out_region) .map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span)) .collect(); if let Some(args) = args From f12b492ee09eb39ba1ec9867a241a4b87c51528c Mon Sep 17 00:00:00 2001 From: Krishna Sundarram Date: Thu, 16 Feb 2023 09:55:39 +0000 Subject: [PATCH 52/90] Change unusual_byte_groupings to require byte groupings of equal size --- clippy_lints/src/literal_representation.rs | 10 +++++++--- tests/ui/large_digit_groups.fixed | 4 ++-- tests/ui/large_digit_groups.stderr | 20 ++++---------------- tests/ui/literals.stderr | 10 ++-------- tests/ui/unreadable_literal.fixed | 2 +- tests/ui/unreadable_literal.stderr | 10 +--------- 6 files changed, 17 insertions(+), 39 deletions(-) diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 3a7b7835c990f..879bcca33a8b7 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -210,7 +210,7 @@ impl WarningType { cx, UNUSUAL_BYTE_GROUPINGS, span, - "digits of hex or binary literal not grouped by four", + "digits of hex, binary or octal literal not in groups of equal size", "consider", suggested_format, Applicability::MachineApplicable, @@ -427,8 +427,12 @@ impl LiteralDigitGrouping { let first = groups.next().expect("At least one group"); - if (radix == Radix::Binary || radix == Radix::Hexadecimal) && groups.any(|i| i != 4 && i != 2) { - return Err(WarningType::UnusualByteGroupings); + if radix == Radix::Binary || radix == Radix::Octal || radix == Radix::Hexadecimal { + if let Some(second_size) = groups.next() { + if !groups.all(|i| i == second_size) || first > second_size { + return Err(WarningType::UnusualByteGroupings); + } + } } if let Some(second) = groups.next() { diff --git a/tests/ui/large_digit_groups.fixed b/tests/ui/large_digit_groups.fixed index 3430c137ec220..ea18dac068336 100644 --- a/tests/ui/large_digit_groups.fixed +++ b/tests/ui/large_digit_groups.fixed @@ -11,7 +11,7 @@ fn main() { let _good = ( 0b1011_i64, 0o1_234_u32, - 0x0123_4567, + 0x1_234_567, 1_2345_6789, 1234_f32, 1_234.12_f32, @@ -19,7 +19,7 @@ fn main() { 1.123_4_f32, ); let _bad = ( - 0b11_0110_i64, + 0b1_10110_i64, 0xdead_beef_usize, 123_456_f32, 123_456.12_f32, diff --git a/tests/ui/large_digit_groups.stderr b/tests/ui/large_digit_groups.stderr index 13d108b56e02e..19c0fae98a645 100644 --- a/tests/ui/large_digit_groups.stderr +++ b/tests/ui/large_digit_groups.stderr @@ -1,22 +1,10 @@ -error: digits of hex or binary literal not grouped by four - --> $DIR/large_digit_groups.rs:14:9 - | -LL | 0x1_234_567, - | ^^^^^^^^^^^ help: consider: `0x0123_4567` - | - = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` - -error: digits of hex or binary literal not grouped by four - --> $DIR/large_digit_groups.rs:22:9 - | -LL | 0b1_10110_i64, - | ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64` - -error: digits of hex or binary literal not grouped by four +error: digits of hex, binary or octal literal not in groups of equal size --> $DIR/large_digit_groups.rs:23:9 | LL | 0xd_e_adbee_f_usize, | ^^^^^^^^^^^^^^^^^^^ help: consider: `0xdead_beef_usize` + | + = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` error: digit groups should be smaller --> $DIR/large_digit_groups.rs:24:9 @@ -44,5 +32,5 @@ error: digit groups should be smaller LL | 1_23456.12345_6_f64, | ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f64` -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/literals.stderr b/tests/ui/literals.stderr index 603d47bacca80..9bc7948c7cc1f 100644 --- a/tests/ui/literals.stderr +++ b/tests/ui/literals.stderr @@ -121,7 +121,7 @@ error: digits grouped inconsistently by underscores LL | let fail23 = 3__16___23; | ^^^^^^^^^^ help: consider: `31_623` -error: digits of hex or binary literal not grouped by four +error: digits of hex, binary or octal literal not in groups of equal size --> $DIR/literals.rs:38:18 | LL | let fail24 = 0xAB_ABC_AB; @@ -129,12 +129,6 @@ LL | let fail24 = 0xAB_ABC_AB; | = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` -error: digits of hex or binary literal not grouped by four - --> $DIR/literals.rs:39:18 - | -LL | let fail25 = 0b01_100_101; - | ^^^^^^^^^^^^ help: consider: `0b0110_0101` - error: this is a decimal constant --> $DIR/literals.rs:46:13 | @@ -168,5 +162,5 @@ help: if you mean to use a decimal constant, remove the `0` to avoid confusion LL | let _ = 89; | ~~ -error: aborting due to 21 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/unreadable_literal.fixed b/tests/ui/unreadable_literal.fixed index a67363b09ea5a..13e5feb19263e 100644 --- a/tests/ui/unreadable_literal.fixed +++ b/tests/ui/unreadable_literal.fixed @@ -23,7 +23,7 @@ fn main() { let _good = ( 0b1011_i64, 0o1_234_u32, - 0x0123_4567, + 0x1_234_567, 65536, 1_2345_6789, 1234_f32, diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index b51130c6a6aba..450121b1c5a92 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -1,11 +1,3 @@ -error: digits of hex or binary literal not grouped by four - --> $DIR/unreadable_literal.rs:26:9 - | -LL | 0x1_234_567, - | ^^^^^^^^^^^ help: consider: `0x0123_4567` - | - = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` - error: long literal lacking separators --> $DIR/unreadable_literal.rs:34:17 | @@ -68,5 +60,5 @@ error: long literal lacking separators LL | let _fail5 = 1.100300400; | ^^^^^^^^^^^ help: consider: `1.100_300_400` -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors From 2d4d39de53ccbada5012e8289625b2a5c2d683b9 Mon Sep 17 00:00:00 2001 From: Jirka Vebr Date: Thu, 16 Feb 2023 13:05:08 +0100 Subject: [PATCH 53/90] Add the `let_underscore_untyped` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/let_underscore.rs | 52 ++++++++++++++++++++++++- tests/ui/let_underscore_untyped.rs | 54 ++++++++++++++++++++++++++ tests/ui/let_underscore_untyped.stderr | 51 ++++++++++++++++++++++++ tests/ui/map_flatten_fixable.fixed | 1 + tests/ui/map_flatten_fixable.rs | 1 + tests/ui/map_flatten_fixable.stderr | 18 ++++----- tests/ui/methods.rs | 1 + tests/ui/methods.stderr | 4 +- 10 files changed, 172 insertions(+), 12 deletions(-) create mode 100644 tests/ui/let_underscore_untyped.rs create mode 100644 tests/ui/let_underscore_untyped.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 30727beb8e7ff..c8165caff4498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4494,6 +4494,7 @@ Released 2018-09-13 [`let_underscore_future`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_future [`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock [`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use +[`let_underscore_untyped`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_untyped [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index c1feabf05aafd..8fa028c62072e 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -224,6 +224,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO, crate::let_underscore::LET_UNDERSCORE_LOCK_INFO, crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO, + crate::let_underscore::LET_UNDERSCORE_UNTYPED_INFO, crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO, crate::lifetimes::NEEDLESS_LIFETIMES_INFO, crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO, diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index f8e3595098088..7600777fab970 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -90,7 +90,45 @@ declare_clippy_lint! { "non-binding `let` on a future" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]); +declare_clippy_lint! { + /// ### What it does + /// Checks for `let _ = ` without a type annotation, and suggests to either provide one, + /// or remove the `let` keyword altogether. + /// + /// ### Why is this bad? + /// The `let _ = ` expression ignores the value of `` but will remain doing so even + /// if the type were to change, thus potentially introducing subtle bugs. By supplying a type + /// annotation, one will be forced to re-visit the decision to ignore the value in such cases. + /// + /// ### Known problems + /// The `_ = ` is not properly supported by some tools (e.g. IntelliJ) and may seem odd + /// to many developers. This lint also partially overlaps with the other `let_underscore_*` + /// lints. + /// + /// ### Example + /// ```rust + /// fn foo() -> Result { + /// Ok(123) + /// } + /// let _ = foo(); + /// ``` + /// Use instead: + /// ```rust + /// fn foo() -> Result { + /// Ok(123) + /// } + /// // Either provide a type annotation: + /// let _: Result = foo(); + /// // …or drop the let keyword: + /// _ = foo(); + /// ``` + #[clippy::version = "1.69.0"] + pub LET_UNDERSCORE_UNTYPED, + pedantic, + "non-binding `let` without a type annotation" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE, LET_UNDERSCORE_UNTYPED]); const SYNC_GUARD_PATHS: [&[&str]; 3] = [ &paths::PARKING_LOT_MUTEX_GUARD, @@ -148,6 +186,18 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "consider explicitly using function result", ); } + + if local.pat.default_binding_modes && local.ty.is_none() { + // When `default_binding_modes` is true, the `let` keyword is present. + span_lint_and_help( + cx, + LET_UNDERSCORE_UNTYPED, + local.span, + "non-binding `let` without a type annotation", + None, + "consider adding a type annotation or removing the `let` keyword", + ); + } } } } diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs new file mode 100644 index 0000000000000..bcb33c5c7e37e --- /dev/null +++ b/tests/ui/let_underscore_untyped.rs @@ -0,0 +1,54 @@ +#![allow(unused)] +#![warn(clippy::let_underscore_untyped)] + +use std::future::Future; +use std::{boxed::Box, fmt::Display}; + +fn a() -> u32 { + 1 +} + +fn b(x: T) -> T { + x +} + +fn c() -> impl Display { + 1 +} + +fn d(x: &u32) -> &u32 { + x +} + +fn e() -> Result { + Ok(1) +} + +fn f() -> Box { + Box::new(1) +} + +fn main() { + let _ = a(); + let _ = b(1); + let _ = c(); + let _ = d(&1); + let _ = e(); + let _ = f(); + + _ = a(); + _ = b(1); + _ = c(); + _ = d(&1); + _ = e(); + _ = f(); + + let _: u32 = a(); + let _: u32 = b(1); + let _: &u32 = d(&1); + let _: Result<_, _> = e(); + let _: Box<_> = f(); + + #[allow(clippy::let_underscore_untyped)] + let _ = a(); +} diff --git a/tests/ui/let_underscore_untyped.stderr b/tests/ui/let_underscore_untyped.stderr new file mode 100644 index 0000000000000..36c3d1214d6b3 --- /dev/null +++ b/tests/ui/let_underscore_untyped.stderr @@ -0,0 +1,51 @@ +error: non-binding `let` without a type annotation + --> $DIR/let_underscore_untyped.rs:32:5 + | +LL | let _ = a(); + | ^^^^^^^^^^^^ + | + = help: consider adding a type annotation or removing the `let` keyword + = note: `-D clippy::let-underscore-untyped` implied by `-D warnings` + +error: non-binding `let` without a type annotation + --> $DIR/let_underscore_untyped.rs:33:5 + | +LL | let _ = b(1); + | ^^^^^^^^^^^^^ + | + = help: consider adding a type annotation or removing the `let` keyword + +error: non-binding `let` without a type annotation + --> $DIR/let_underscore_untyped.rs:34:5 + | +LL | let _ = c(); + | ^^^^^^^^^^^^ + | + = help: consider adding a type annotation or removing the `let` keyword + +error: non-binding `let` without a type annotation + --> $DIR/let_underscore_untyped.rs:35:5 + | +LL | let _ = d(&1); + | ^^^^^^^^^^^^^^ + | + = help: consider adding a type annotation or removing the `let` keyword + +error: non-binding `let` without a type annotation + --> $DIR/let_underscore_untyped.rs:36:5 + | +LL | let _ = e(); + | ^^^^^^^^^^^^ + | + = help: consider adding a type annotation or removing the `let` keyword + +error: non-binding `let` without a type annotation + --> $DIR/let_underscore_untyped.rs:37:5 + | +LL | let _ = f(); + | ^^^^^^^^^^^^ + | + = help: consider adding a type annotation or removing the `let` keyword + +error: aborting due to 6 previous errors + diff --git a/tests/ui/map_flatten_fixable.fixed b/tests/ui/map_flatten_fixable.fixed index 53628ef6531aa..8e2f11389f898 100644 --- a/tests/ui/map_flatten_fixable.fixed +++ b/tests/ui/map_flatten_fixable.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_untyped)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] #![allow(clippy::redundant_closure)] diff --git a/tests/ui/map_flatten_fixable.rs b/tests/ui/map_flatten_fixable.rs index 76016c8ed3cd1..a783a99c4ffd3 100644 --- a/tests/ui/map_flatten_fixable.rs +++ b/tests/ui/map_flatten_fixable.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_untyped)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] #![allow(clippy::redundant_closure)] diff --git a/tests/ui/map_flatten_fixable.stderr b/tests/ui/map_flatten_fixable.stderr index b6b0c4d09c37b..c91f0b9ae94fe 100644 --- a/tests/ui/map_flatten_fixable.stderr +++ b/tests/ui/map_flatten_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on `Iterator` - --> $DIR/map_flatten_fixable.rs:17:47 + --> $DIR/map_flatten_fixable.rs:18:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)` @@ -7,43 +7,43 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = note: `-D clippy::map-flatten` implied by `-D warnings` error: called `map(..).flatten()` on `Iterator` - --> $DIR/map_flatten_fixable.rs:18:47 + --> $DIR/map_flatten_fixable.rs:19:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)` error: called `map(..).flatten()` on `Iterator` - --> $DIR/map_flatten_fixable.rs:19:47 + --> $DIR/map_flatten_fixable.rs:20:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)` error: called `map(..).flatten()` on `Iterator` - --> $DIR/map_flatten_fixable.rs:20:47 + --> $DIR/map_flatten_fixable.rs:21:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on `Iterator` - --> $DIR/map_flatten_fixable.rs:23:47 + --> $DIR/map_flatten_fixable.rs:24:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)` error: called `map(..).flatten()` on `Option` - --> $DIR/map_flatten_fixable.rs:26:40 + --> $DIR/map_flatten_fixable.rs:27:40 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Result` - --> $DIR/map_flatten_fixable.rs:29:42 + --> $DIR/map_flatten_fixable.rs:30:42 | LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Iterator` - --> $DIR/map_flatten_fixable.rs:38:10 + --> $DIR/map_flatten_fixable.rs:39:10 | LL | .map(|n| match n { | __________^ @@ -72,7 +72,7 @@ LL ~ }); | error: called `map(..).flatten()` on `Option` - --> $DIR/map_flatten_fixable.rs:58:10 + --> $DIR/map_flatten_fixable.rs:59:10 | LL | .map(|_| { | __________^ diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 6f22366eab29a..1519e4da9348a 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -4,6 +4,7 @@ #![allow( clippy::disallowed_names, clippy::default_trait_access, + clippy::let_underscore_untyped, clippy::missing_docs_in_private_items, clippy::missing_safety_doc, clippy::non_ascii_literal, diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index b63672dd6fdbb..4643e09e27028 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> $DIR/methods.rs:104:5 + --> $DIR/methods.rs:105:5 | LL | / fn new() -> i32 { LL | | 0 @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> $DIR/methods.rs:125:13 + --> $DIR/methods.rs:126:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ From 09337981b21c7004791260fde7ab7f1e21abf5ca Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 16 Feb 2023 13:21:34 +0100 Subject: [PATCH 54/90] Added check for local spans --- clippy_lints/src/question_mark_used.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index 1a103dc35a415..9b678e8d753c2 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::macros::span_is_local; use rustc_hir::{Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -34,6 +35,10 @@ declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]); impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind { + if !span_is_local(expr.span) { + return; + } + span_lint_and_help( cx, QUESTION_MARK_USED, From 0b1ae20365f4363fdc5462fae3b3a3bd8ee214e6 Mon Sep 17 00:00:00 2001 From: Jirka Vebr Date: Thu, 16 Feb 2023 13:29:38 +0100 Subject: [PATCH 55/90] Fix dogfood tests by adding type annotations --- clippy_dev/src/new_lint.rs | 9 +++++---- clippy_dev/src/update_lints.rs | 6 +++--- clippy_lints/src/entry.rs | 8 ++++---- clippy_lints/src/inconsistent_struct_constructor.rs | 4 ++-- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/module_style.rs | 2 +- clippy_utils/src/numeric_literal.rs | 2 +- clippy_utils/src/sugg.rs | 8 ++++---- lintcheck/src/main.rs | 12 ++++++------ 9 files changed, 27 insertions(+), 26 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index ec7f1dd0d846c..420214d9256d8 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,5 +1,6 @@ use crate::clippy_project_root; use indoc::{formatdoc, writedoc}; +use std::fmt; use std::fmt::Write as _; use std::fs::{self, OpenOptions}; use std::io::prelude::*; @@ -256,7 +257,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ) }); - let _ = write!(result, "{}", get_lint_declaration(&name_upper, category)); + let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category)); result.push_str(&if enable_msrv { formatdoc!( @@ -353,7 +354,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R let mut lint_file_contents = String::new(); if enable_msrv { - let _ = writedoc!( + let _: fmt::Result = writedoc!( lint_file_contents, r#" use clippy_utils::msrvs::{{self, Msrv}}; @@ -373,7 +374,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R name_upper = name_upper, ); } else { - let _ = writedoc!( + let _: fmt::Result = writedoc!( lint_file_contents, r#" use rustc_lint::{{{context_import}, LintContext}}; @@ -521,7 +522,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> .chain(std::iter::once(&*lint_name_upper)) .filter(|s| !s.is_empty()) { - let _ = write!(new_arr_content, "\n {ident},"); + let _: fmt::Result = write!(new_arr_content, "\n {ident},"); } new_arr_content.push('\n'); diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 837618c9294b7..779e4d0e1e308 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; -use std::fmt::Write; +use std::fmt::{self, Write}; use std::fs::{self, OpenOptions}; use std::io::{self, Read, Seek, SeekFrom, Write as _}; use std::ops::Range; @@ -691,7 +691,7 @@ fn gen_deprecated(lints: &[DeprecatedLint]) -> String { let mut output = GENERATED_FILE_COMMENT.to_string(); output.push_str("{\n"); for lint in lints { - let _ = write!( + let _: fmt::Result = write!( output, concat!( " store.register_removed(\n", @@ -726,7 +726,7 @@ fn gen_declared_lints<'a>( if !is_public { output.push_str(" #[cfg(feature = \"internal\")]\n"); } - let _ = writeln!(output, " crate::{module_name}::{lint_name}_INFO,"); + let _: fmt::Result = writeln!(output, " crate::{module_name}::{lint_name}_INFO,"); } output.push_str("];\n"); diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index ed9d94cdec3c5..48a54f60253c8 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -6,7 +6,7 @@ use clippy_utils::{ source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}, SpanlessEq, }; -use core::fmt::Write; +use core::fmt::{self, Write}; use rustc_errors::Applicability; use rustc_hir::{ hir_id::HirIdSet, @@ -536,7 +536,7 @@ impl<'tcx> InsertSearchResults<'tcx> { if is_expr_used_or_unified(cx.tcx, insertion.call) { write_wrapped(&mut res, insertion, ctxt, app); } else { - let _ = write!( + let _: fmt::Result = write!( res, "e.insert({})", snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0 @@ -552,7 +552,7 @@ impl<'tcx> InsertSearchResults<'tcx> { ( self.snippet(cx, span, app, |res, insertion, ctxt, app| { // Insertion into a map would return `Some(&mut value)`, but the entry returns `&mut value` - let _ = write!( + let _: fmt::Result = write!( res, "Some(e.insert({}))", snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0 @@ -566,7 +566,7 @@ impl<'tcx> InsertSearchResults<'tcx> { ( self.snippet(cx, span, app, |res, insertion, ctxt, app| { // Insertion into a map would return `None`, but the entry returns a mutable reference. - let _ = if is_expr_final_block_expr(cx.tcx, insertion.call) { + let _: fmt::Result = if is_expr_final_block_expr(cx.tcx, insertion.call) { write!( res, "e.insert({});\n{}None", diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index e2f2d3d42e695..1ad886f2cf35f 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -7,7 +7,7 @@ use rustc_hir::{self as hir, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; -use std::fmt::Write as _; +use std::fmt::{self, Write as _}; declare_clippy_lint! { /// ### What it does @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { let mut fields_snippet = String::new(); let (last_ident, idents) = ordered_fields.split_last().unwrap(); for ident in idents { - let _ = write!(fields_snippet, "{ident}, "); + let _: fmt::Result = write!(fields_snippet, "{ident}, "); } fields_snippet.push_str(&last_ident.to_string()); diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 3a7b7835c990f..8097627c869ba 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -484,7 +484,7 @@ impl DecimalLiteralRepresentation { then { let hex = format!("{val:#X}"); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); - let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| { + let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| { warning_type.display(num_lit.format(), cx, span); }); } diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 0742943dff2b9..349fcd2274d3e 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -134,7 +134,7 @@ fn process_paths_for_mod_files<'a>( mod_folders: &mut FxHashSet<&'a OsStr>, ) { let mut comp = path.components().rev().peekable(); - let _ = comp.next(); + let _: Option<_> = comp.next(); if path.ends_with("mod.rs") { mod_folders.insert(comp.peek().map(|c| c.as_os_str()).unwrap_or_default()); } diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index 42bdfd4827f10..c225398ad2a8f 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -186,7 +186,7 @@ impl<'a> NumericLiteral<'a> { // The exponent may have a sign, output it early, otherwise it will be // treated as a digit if digits.clone().next() == Some('-') { - let _ = digits.next(); + let _: Option = digits.next(); output.push('-'); } diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 78fb2e0eb7e68..51e270d330c88 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -20,7 +20,7 @@ use rustc_middle::mir::{FakeReadCause, Mutability}; use rustc_middle::ty; use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext}; use std::borrow::Cow; -use std::fmt::{Display, Write as _}; +use std::fmt::{self, Display, Write as _}; use std::ops::{Add, Neg, Not, Sub}; /// A helper type to build suggestion correctly handling parentheses. @@ -932,7 +932,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { if cmt.place.projections.is_empty() { // handle item without any projection, that needs an explicit borrowing // i.e.: suggest `&x` instead of `x` - let _ = write!(self.suggestion_start, "{start_snip}&{ident_str}"); + let _: fmt::Result = write!(self.suggestion_start, "{start_snip}&{ident_str}"); } else { // cases where a parent `Call` or `MethodCall` is using the item // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()` @@ -947,7 +947,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // given expression is the self argument and will be handled completely by the compiler // i.e.: `|x| x.is_something()` ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => { - let _ = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}"); + let _: fmt::Result = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}"); self.next_pos = span.hi(); return; }, @@ -1055,7 +1055,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { } } - let _ = write!(self.suggestion_start, "{start_snip}{replacement_str}"); + let _: fmt::Result = write!(self.suggestion_start, "{start_snip}{replacement_str}"); } self.next_pos = span.hi(); } diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index bd49f09607263..23c8529802759 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -17,9 +17,9 @@ use crate::recursive::LintcheckServer; use std::collections::{HashMap, HashSet}; use std::env; use std::env::consts::EXE_SUFFIX; -use std::fmt::Write as _; +use std::fmt::{self, Write as _}; use std::fs; -use std::io::ErrorKind; +use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -145,8 +145,8 @@ impl ClippyWarning { } let mut output = String::from("| "); - let _ = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line); - let _ = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message); + let _: fmt::Result = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line); + let _: fmt::Result = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message); output.push('\n'); output } else { @@ -632,7 +632,7 @@ fn main() { .unwrap(); let server = config.recursive.then(|| { - let _ = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive"); + let _: io::Result<()> = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive"); LintcheckServer::spawn(recursive_options) }); @@ -689,7 +689,7 @@ fn main() { write!(text, "{}", all_msgs.join("")).unwrap(); text.push_str("\n\n### ICEs:\n"); for (cratename, msg) in &ices { - let _ = write!(text, "{cratename}: '{msg}'"); + let _: fmt::Result = write!(text, "{cratename}: '{msg}'"); } println!("Writing logs to {}", config.lintcheck_results_path.display()); From 9c9dbc24081e569cffe7a1cf83020b4b4907d7be Mon Sep 17 00:00:00 2001 From: Krishna Sundarram Date: Thu, 16 Feb 2023 14:20:40 +0000 Subject: [PATCH 56/90] Fix DOC_MARKDOWN requiring backticks on links to external websites --- clippy_lints/src/doc.rs | 20 +++++++++++--------- tests/ui/doc/doc-fixable.fixed | 2 +- tests/ui/doc/doc-fixable.rs | 4 ++-- tests/ui/doc/doc-fixable.stderr | 24 +----------------------- 4 files changed, 15 insertions(+), 35 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 127201b72e275..5e2811db2f7c0 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -6,6 +6,11 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty}; use if_chain::if_chain; use itertools::Itertools; +use pulldown_cmark::Event::{ + Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, +}; +use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph}; +use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind}; use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; @@ -497,7 +502,6 @@ struct DocHeaders { } fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[Attribute]) -> Option { - use pulldown_cmark::{BrokenLink, CowStr, Options}; /// We don't want the parser to choke on intra doc links. Since we don't /// actually care about rendering them, just pretend that all broken links are /// point to a fake address. @@ -538,8 +542,6 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter(); // Iterate over all `Events` and combine consecutive events into one let events = parser.coalesce(|previous, current| { - use pulldown_cmark::Event::Text; - let previous_range = previous.1; let current_range = current.1; @@ -564,12 +566,6 @@ fn check_doc<'a, Events: Iterator, Range DocHeaders { // true if a safety header was found - use pulldown_cmark::Event::{ - Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, - }; - use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph}; - use pulldown_cmark::{CodeBlockKind, CowStr}; - let mut headers = DocHeaders::default(); let mut in_code = false; let mut in_link = None; @@ -660,6 +656,12 @@ fn check_doc<'a, Events: Iterator, Range $DIR/doc-fixable.rs:78:22 - | -LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: try - | -LL | /// This test has [a `link_with_underscores`][chunked-example] inside it. See #823. - | ~~~~~~~~~~~~~~~~~~~~~~~ - -error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:81:21 - | -LL | /// It can also be [inline_link2]. - | ^^^^^^^^^^^^ - | -help: try - | -LL | /// It can also be [`inline_link2`]. - | ~~~~~~~~~~~~~~ - error: item in documentation is missing backticks --> $DIR/doc-fixable.rs:91:5 | @@ -329,5 +307,5 @@ help: try LL | /// An iterator over `mycrate::Collection`'s values. | ~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 30 previous errors +error: aborting due to 28 previous errors From 6d0df84f6f879feb2211f8f61351a4669d2397e0 Mon Sep 17 00:00:00 2001 From: Jirka Vebr Date: Thu, 16 Feb 2023 16:08:28 +0100 Subject: [PATCH 57/90] Add the `transmute_int_to_non_zero` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/transmute/mod.rs | 28 ++++++++ .../transmute/transmute_int_to_non_zero.rs | 61 ++++++++++++++++++ tests/ui/transmute_int_to_non_zero.rs | 41 ++++++++++++ tests/ui/transmute_int_to_non_zero.stderr | 64 +++++++++++++++++++ 6 files changed, 196 insertions(+) create mode 100644 clippy_lints/src/transmute/transmute_int_to_non_zero.rs create mode 100644 tests/ui/transmute_int_to_non_zero.rs create mode 100644 tests/ui/transmute_int_to_non_zero.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 73ae215ce1b2e..9138a4fb9c58a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4794,6 +4794,7 @@ Released 2018-09-13 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float +[`transmute_int_to_non_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_non_zero [`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn [`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 0dab6b5f3f1c5..2577cdc8c6649 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -577,6 +577,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO, crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO, crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO, + crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO, crate::transmute::TRANSMUTE_NULL_TO_FN_INFO, crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO, crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO, diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index c0d290b5adc42..c01cbe5090f79 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -3,6 +3,7 @@ mod transmute_float_to_int; mod transmute_int_to_bool; mod transmute_int_to_char; mod transmute_int_to_float; +mod transmute_int_to_non_zero; mod transmute_null_to_fn; mod transmute_num_to_bytes; mod transmute_ptr_to_ptr; @@ -253,6 +254,31 @@ declare_clippy_lint! { "transmutes from an integer to a float" } +declare_clippy_lint! { + /// ### What it does + /// Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked` + /// method instead. + /// + /// ### Why is this bad? + /// Transmutes work on any types and thus might cause unsoundness when those types change + /// elsewhere. `new_unchecked` only works for the appropriate types instead. + /// + /// ### Example + /// ```rust + /// # use core::num::NonZeroU32; + /// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) }; + /// ``` + /// Use instead: + /// ```rust + /// # use core::num::NonZeroU32; + /// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) }; + /// ``` + #[clippy::version = "1.69.0"] + pub TRANSMUTE_INT_TO_NON_ZERO, + complexity, + "transmutes from an integer to a non-zero wrapper" +} + declare_clippy_lint! { /// ### What it does /// Checks for transmutes from a float to an integer. @@ -451,6 +477,7 @@ impl_lint_pass!(Transmute => [ TRANSMUTE_BYTES_TO_STR, TRANSMUTE_INT_TO_BOOL, TRANSMUTE_INT_TO_FLOAT, + TRANSMUTE_INT_TO_NON_ZERO, TRANSMUTE_FLOAT_TO_INT, TRANSMUTE_NUM_TO_BYTES, UNSOUND_COLLECTION_TRANSMUTE, @@ -501,6 +528,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context) | ( diff --git a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs new file mode 100644 index 0000000000000..5503653253c55 --- /dev/null +++ b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -0,0 +1,61 @@ +use super::TRANSMUTE_INT_TO_NON_ZERO; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::{ + query::Key, + ty::{self, Ty}, +}; +use rustc_span::symbol::sym; + +/// Checks for `transmute_int_to_non_zero` lint. +/// Returns `true` if it's triggered, otherwise returns `false`. +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, + arg: &'tcx Expr<'_>, +) -> bool { + let (ty::Int(_) | ty::Uint(_), Some(to_ty_id)) = (&from_ty.kind(), to_ty.ty_adt_id()) else { + return false; + }; + let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_id) else { + return false; + }; + + if !matches!( + to_type_sym, + sym::NonZeroU8 + | sym::NonZeroU16 + | sym::NonZeroU32 + | sym::NonZeroU64 + | sym::NonZeroU128 + | sym::NonZeroI8 + | sym::NonZeroI16 + | sym::NonZeroI32 + | sym::NonZeroI64 + | sym::NonZeroI128 + ) { + return false; + } + + span_lint_and_then( + cx, + TRANSMUTE_INT_TO_NON_ZERO, + e.span, + &format!("transmute from a `{from_ty}` to a `{to_type_sym}`"), + |diag| { + let arg = sugg::Sugg::hir(cx, arg, ".."); + diag.span_suggestion( + e.span, + "consider using", + format!("{to_type_sym}::{}({arg})", sym::new_unchecked), + Applicability::Unspecified, + ); + }, + ); + true +} diff --git a/tests/ui/transmute_int_to_non_zero.rs b/tests/ui/transmute_int_to_non_zero.rs new file mode 100644 index 0000000000000..a384067825068 --- /dev/null +++ b/tests/ui/transmute_int_to_non_zero.rs @@ -0,0 +1,41 @@ +#![warn(clippy::transmute_int_to_non_zero)] + +use core::num::*; + +fn main() { + let int_u8: u8 = 1; + let int_u16: u16 = 1; + let int_u32: u32 = 1; + let int_u64: u64 = 1; + let int_u128: u128 = 1; + + let int_i8: i8 = 1; + let int_i16: i16 = 1; + let int_i32: i32 = 1; + let int_i64: i64 = 1; + let int_i128: i128 = 1; + + let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) }; + let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) }; + let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) }; + let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) }; + let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) }; + + let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) }; + let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) }; + let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) }; + let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) }; + let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) }; + + let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) }; + let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) }; + let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) }; + let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) }; + let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) }; + + let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) }; + let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) }; + let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) }; + let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) }; + let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) }; +} diff --git a/tests/ui/transmute_int_to_non_zero.stderr b/tests/ui/transmute_int_to_non_zero.stderr new file mode 100644 index 0000000000000..33f8ce79ea780 --- /dev/null +++ b/tests/ui/transmute_int_to_non_zero.stderr @@ -0,0 +1,64 @@ +error: transmute from a `u8` to a `NonZeroU8` + --> $DIR/transmute_int_to_non_zero.rs:18:33 + | +LL | let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)` + | + = note: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings` + +error: transmute from a `u16` to a `NonZeroU16` + --> $DIR/transmute_int_to_non_zero.rs:19:34 + | +LL | let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU16::new_unchecked(int_u16)` + +error: transmute from a `u32` to a `NonZeroU32` + --> $DIR/transmute_int_to_non_zero.rs:20:34 + | +LL | let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU32::new_unchecked(int_u32)` + +error: transmute from a `u64` to a `NonZeroU64` + --> $DIR/transmute_int_to_non_zero.rs:21:34 + | +LL | let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU64::new_unchecked(int_u64)` + +error: transmute from a `u128` to a `NonZeroU128` + --> $DIR/transmute_int_to_non_zero.rs:22:35 + | +LL | let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU128::new_unchecked(int_u128)` + +error: transmute from a `i8` to a `NonZeroI8` + --> $DIR/transmute_int_to_non_zero.rs:24:33 + | +LL | let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI8::new_unchecked(int_i8)` + +error: transmute from a `i16` to a `NonZeroI16` + --> $DIR/transmute_int_to_non_zero.rs:25:34 + | +LL | let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI16::new_unchecked(int_i16)` + +error: transmute from a `i32` to a `NonZeroI32` + --> $DIR/transmute_int_to_non_zero.rs:26:34 + | +LL | let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI32::new_unchecked(int_i32)` + +error: transmute from a `i64` to a `NonZeroI64` + --> $DIR/transmute_int_to_non_zero.rs:27:34 + | +LL | let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI64::new_unchecked(int_i64)` + +error: transmute from a `i128` to a `NonZeroI128` + --> $DIR/transmute_int_to_non_zero.rs:28:35 + | +LL | let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI128::new_unchecked(int_i128)` + +error: aborting due to 10 previous errors + From 64b8aaf91a558c5b2adaaef93fb5a637b9cbf545 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 16 Feb 2023 11:45:57 -0500 Subject: [PATCH 58/90] remove empty file --- tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stdout | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stdout diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stdout b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stdout deleted file mode 100644 index e69de29bb2d1d..0000000000000 From 7e53e27dfdb5ce4cda44912fcc6c288c34ac7d91 Mon Sep 17 00:00:00 2001 From: Krishna Sundarram Date: Thu, 16 Feb 2023 16:41:04 +0000 Subject: [PATCH 59/90] Stop bytes_nth from suggesting code that does not compile --- clippy_lints/src/methods/bytes_nth.rs | 42 ++++++++++++++++++--------- tests/ui/bytes_nth.fixed | 6 ++-- tests/ui/bytes_nth.rs | 2 +- tests/ui/bytes_nth.stderr | 10 +++---- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index d512cc4eeae12..c5fc145b28908 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -5,6 +5,8 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; +use crate::methods::method_call; + use super::BYTES_NTH; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) { @@ -16,18 +18,32 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E } else { return; }; + let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BYTES_NTH, - expr.span, - &format!("called `.bytes().nth()` on a `{caller_type}`"), - "try", - format!( - "{}.as_bytes().get({})", - snippet_with_applicability(cx, recv.span, "..", &mut applicability), - snippet_with_applicability(cx, n_arg.span, "..", &mut applicability) - ), - applicability, - ); + let receiver = snippet_with_applicability(cx, recv.span, "..", &mut applicability); + let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability); + + if let Some(parent) = clippy_utils::get_parent_expr(cx, expr) + && let Some((name, _, _, _, _)) = method_call(parent) + && name == "unwrap" { + span_lint_and_sugg( + cx, + BYTES_NTH, + parent.span, + &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), + "try", + format!("{receiver}.as_bytes()[{n}]",), + applicability + ); + } else { + span_lint_and_sugg( + cx, + BYTES_NTH, + expr.span, + &format!("called `.bytes().nth()` on a `{caller_type}`"), + "try", + format!("{receiver}.as_bytes().get({n}).copied()"), + applicability + ); + }; } diff --git a/tests/ui/bytes_nth.fixed b/tests/ui/bytes_nth.fixed index b1fb2e16bd584..a35c679afb71f 100644 --- a/tests/ui/bytes_nth.fixed +++ b/tests/ui/bytes_nth.fixed @@ -5,7 +5,7 @@ fn main() { let s = String::from("String"); - let _ = s.as_bytes().get(3); - let _ = &s.as_bytes().get(3); - let _ = s[..].as_bytes().get(3); + let _ = s.as_bytes().get(3).copied(); + let _ = &s.as_bytes()[3]; + let _ = s[..].as_bytes().get(3).copied(); } diff --git a/tests/ui/bytes_nth.rs b/tests/ui/bytes_nth.rs index 034c54e6a4206..1ecffea53035e 100644 --- a/tests/ui/bytes_nth.rs +++ b/tests/ui/bytes_nth.rs @@ -6,6 +6,6 @@ fn main() { let s = String::from("String"); let _ = s.bytes().nth(3); - let _ = &s.bytes().nth(3); + let _ = &s.bytes().nth(3).unwrap(); let _ = s[..].bytes().nth(3); } diff --git a/tests/ui/bytes_nth.stderr b/tests/ui/bytes_nth.stderr index 9851d4791d8db..e8b15027829e3 100644 --- a/tests/ui/bytes_nth.stderr +++ b/tests/ui/bytes_nth.stderr @@ -2,21 +2,21 @@ error: called `.bytes().nth()` on a `String` --> $DIR/bytes_nth.rs:8:13 | LL | let _ = s.bytes().nth(3); - | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` + | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3).copied()` | = note: `-D clippy::bytes-nth` implied by `-D warnings` -error: called `.bytes().nth()` on a `String` +error: called `.bytes().nth().unwrap()` on a `String` --> $DIR/bytes_nth.rs:9:14 | -LL | let _ = &s.bytes().nth(3); - | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` +LL | let _ = &s.bytes().nth(3).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.as_bytes()[3]` error: called `.bytes().nth()` on a `str` --> $DIR/bytes_nth.rs:10:13 | LL | let _ = s[..].bytes().nth(3); - | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3).copied()` error: aborting due to 3 previous errors From 747f81ecd00a4b6daceb9d7e53c6790498196863 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 16 Feb 2023 18:34:33 -0300 Subject: [PATCH 60/90] [significant_drop_tightening] Ignore inexpensive statements --- .../src/significant_drop_tightening.rs | 24 +++++++++++++++---- tests/ui/significant_drop_tightening.fixed | 8 +++++++ tests/ui/significant_drop_tightening.rs | 8 +++++++ tests/ui/significant_drop_tightening.stderr | 6 ++--- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 4cc85e3856462..367466b7d8206 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -61,6 +61,18 @@ pub struct SignificantDropTightening<'tcx> { } impl<'tcx> SignificantDropTightening<'tcx> { + /// Searches for at least one statement that could slow down the release of a significant drop. + fn at_least_one_stmt_is_expensive(stmts: &[hir::Stmt<'_>]) -> bool { + for stmt in stmts { + match stmt.kind { + hir::StmtKind::Local(local) if let Some(expr) = local.init + && let hir::ExprKind::Path(_) = expr.kind => {}, + _ => return true + }; + } + false + } + /// Verifies if the expression is of type `drop(some_lock_path)` to assert that the temporary /// is already being dropped before the end of its scope. fn has_drop(expr: &'tcx hir::Expr<'_>, init_bind_ident: Ident) -> bool { @@ -198,13 +210,15 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { } self.modify_sdap_if_sig_drop_exists(cx, expr, idx, &mut sdap, stmt, |_| {}); }, - _ => continue + _ => {} }; } - if sdap.number_of_stmts > 1 && { - let last_stmts_idx = block.stmts.len().wrapping_sub(1); - sdap.last_use_stmt_idx != last_stmts_idx - } { + let stmts_after_last_use = sdap + .last_use_stmt_idx + .checked_add(1) + .and_then(|idx| block.stmts.get(idx..)) + .unwrap_or_default(); + if sdap.number_of_stmts > 1 && Self::at_least_one_stmt_is_expensive(stmts_after_last_use) { span_lint_and_then( cx, SIGNIFICANT_DROP_TIGHTENING, diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed index 7d56a87053fdb..5d176d2a92726 100644 --- a/tests/ui/significant_drop_tightening.fixed +++ b/tests/ui/significant_drop_tightening.fixed @@ -4,6 +4,14 @@ use std::sync::Mutex; +pub fn post_bindings_can_be_ignored() { + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let rslt = *lock; + let another = rslt; + let _ = another; +} + pub fn unnecessary_contention_with_multiple_owned_results() { { let mutex = Mutex::new(1i32); diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index 6f3ce328e5d94..be9c0774275d6 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -4,6 +4,14 @@ use std::sync::Mutex; +pub fn post_bindings_can_be_ignored() { + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let rslt = *lock; + let another = rslt; + let _ = another; +} + pub fn unnecessary_contention_with_multiple_owned_results() { { let mutex = Mutex::new(1i32); diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr index 52754aac78269..0ec9b1acb5951 100644 --- a/tests/ui/significant_drop_tightening.stderr +++ b/tests/ui/significant_drop_tightening.stderr @@ -1,5 +1,5 @@ error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:17:13 + --> $DIR/significant_drop_tightening.rs:25:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -20,7 +20,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:38:13 + --> $DIR/significant_drop_tightening.rs:46:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -44,7 +44,7 @@ LL + | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:44:17 + --> $DIR/significant_drop_tightening.rs:52:17 | LL | / { LL | | let mutex = Mutex::new(vec![1i32]); From f0565c939e2f271f57b853a4b7ee21dea0541d0b Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Mon, 6 Feb 2023 17:48:12 -0700 Subject: [PATCH 61/90] change usages of type_of to bound_type_of --- clippy_lints/src/casts/cast_ptr_alignment.rs | 2 +- clippy_lints/src/copy_iterator.rs | 2 +- clippy_lints/src/default.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/derive.rs | 4 ++-- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/eta_reduction.rs | 4 ++-- clippy_lints/src/functions/misnamed_getters.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 4 ++-- clippy_lints/src/inherent_impl.rs | 3 ++- clippy_lints/src/large_enum_variant.rs | 2 +- .../src/matches/rest_pat_in_fully_bound_struct.rs | 2 +- clippy_lints/src/methods/bytes_count_to_len.rs | 2 +- .../methods/case_sensitive_file_extension_comparisons.rs | 2 +- clippy_lints/src/methods/get_first.rs | 2 +- clippy_lints/src/methods/implicit_clone.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/map_err_ignore.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/mut_mutex_lock.rs | 2 +- clippy_lints/src/methods/open_options.rs | 2 +- clippy_lints/src/methods/path_buf_push_overwrite.rs | 2 +- clippy_lints/src/methods/stable_sort_primitive.rs | 2 +- clippy_lints/src/methods/suspicious_splitn.rs | 2 +- clippy_lints/src/methods/unnecessary_sort_by.rs | 2 +- clippy_lints/src/methods/utils.rs | 2 +- clippy_lints/src/methods/vec_resize_to_zero.rs | 2 +- clippy_lints/src/new_without_default.rs | 8 +++++--- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/self_named_constructors.rs | 2 +- clippy_lints/src/use_self.rs | 6 +++--- .../src/utils/internal_lints/interning_defined_symbol.rs | 2 +- clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs | 3 ++- .../src/utils/internal_lints/unnecessary_def_path.rs | 4 ++-- clippy_utils/src/eager_or_lazy.rs | 4 ++-- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/ty.rs | 4 ++-- 41 files changed, 57 insertions(+), 53 deletions(-) diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 97054a0d10154..58d4cfff06f50 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -66,7 +66,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned") && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && let Some(def_id) = cx.tcx.impl_of_method(def_id) - && cx.tcx.type_of(def_id).is_unsafe_ptr() + && cx.tcx.bound_type_of(def_id).subst_identity().is_unsafe_ptr() { true } else { diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index e38f772685301..023f9e64deb92 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyIterator { of_trait: Some(ref trait_ref), .. }) = item.kind; - let ty = cx.tcx.type_of(item.owner_id); + let ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); if is_copy(cx, ty); if let Some(trait_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id); diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index a04693f4637ab..b6b7eaae0686b 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { .fields .iter() .all(|field| { - is_copy(cx, cx.tcx.type_of(field.did)) + is_copy(cx, cx.tcx.bound_type_of(field.did).subst_identity()) }); if !has_drop(cx, binding_type) || all_fields_are_copy; then { diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index f806ba238c7c6..e368efe944cff 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -167,7 +167,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { .iter() .find_map(|f_def| { if f_def.ident(self.cx.tcx) == field.ident - { Some(self.cx.tcx.type_of(f_def.did)) } + { Some(self.cx.tcx.bound_type_of(f_def.did).subst_identity()) } else { None } }); self.ty_bounds.push(bound.into()); diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 6c333afacc648..4c9f4f7f8ccac 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -735,7 +735,7 @@ fn walk_parents<'tcx>( span, .. }) if span.ctxt() == ctxt => { - let ty = cx.tcx.type_of(owner_id.def_id); + let ty = cx.tcx.bound_type_of(owner_id.def_id).subst_identity(); Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx)) }, @@ -771,7 +771,7 @@ fn walk_parents<'tcx>( }) => variant_of_res(cx, cx.qpath_res(path, *hir_id)) .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name)) .map(|field_def| { - ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did), precedence).position_for_arg() + ty_auto_deref_stability(cx, cx.tcx.bound_type_of(field_def.did).subst_identity(), precedence).position_for_arg() }), _ => None, }, diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index bc18e2e5ed5fd..f1d2db4487189 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir); if let ImplItemKind::Fn(_, b) = &impl_item.kind; if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b); - if let Some(adt_def) = cx.tcx.type_of(item.owner_id).ty_adt_def(); + if let Some(adt_def) = cx.tcx.bound_type_of(item.owner_id).subst_identity().ty_adt_def(); if let attrs = cx.tcx.hir().attrs(item.hir_id()); if !attrs.iter().any(|attr| attr.doc_str().is_some()); if let child_attrs = cx.tcx.hir().attrs(impl_item_hir); diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index f8fc726d603f8..0181b164f057e 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -211,7 +211,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { .. }) = item.kind { - let ty = cx.tcx.type_of(item.owner_id); + let ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); @@ -347,7 +347,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h 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.bound_type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did())) }); if !has_copy_impl { return; diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 0570c2a101389..8c0112ca4a1cb 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum { } if let ItemKind::Enum(..) = item.kind { - let ty = cx.tcx.type_of(item.owner_id); + let ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); if adt.variants().is_empty() { span_lint_and_help( diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index da67888827d19..e5289c177f3e9 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { for var in def.variants { if let Some(anon_const) = &var.disr_expr { let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body); - let mut ty = cx.tcx.type_of(def_id.to_def_id()); + let mut ty = cx.tcx.bound_type_of(def_id.to_def_id()).subst_identity(); let constant = cx .tcx .const_eval_poly(def_id.to_def_id()) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 3543910c3b55b..a41ad735fb810 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if check_inputs(cx, body.params, None, args); let callee_ty = cx.typeck_results().expr_ty_adjusted(callee); let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id) - .map_or(callee_ty, |id| cx.tcx.type_of(id)); + .map_or(callee_ty, |id| cx.tcx.bound_type_of(id).subst_identity()); if check_sig(cx, closure_ty, call_ty); let substs = cx.typeck_results().node_substs(callee.hir_id); // This fixes some false positives that I don't entirely understand @@ -233,7 +233,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs match assoc_item.container { ty::TraitContainer => cx.tcx.def_path_str(def_id), ty::ImplContainer => { - let ty = cx.tcx.type_of(def_id); + let ty = cx.tcx.bound_type_of(def_id).skip_binder(); match ty.kind() { ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()), ty::Array(..) diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index 8b53ee68ebdfb..1405316c9bc07 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -101,7 +101,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: return; }; - if cx.tcx.type_of(used_field.did) == cx.tcx.type_of(correct_field.did) { + if cx.tcx.bound_type_of(used_field.did) == cx.tcx.bound_type_of(correct_field.did) { let left_span = block_expr.span.until(used_ident.span); let snippet = snippet(cx, left_span, ".."); let sugg = format!("{snippet}{name}"); diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 29d59c26d92c4..bff3cd4e3a19b 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(const_id); if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl - if cx.tcx.type_of(impl_id).is_integral(); + if cx.tcx.bound_type_of(impl_id).subst_identity().is_integral(); then { print_lint_and_sugg(cx, var_name, expr) } @@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(func_id); if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl - if cx.tcx.type_of(impl_id).is_integral(); + if cx.tcx.bound_type_of(impl_id).subst_identity().is_integral(); then { print_lint_and_sugg(cx, var_name, expr) } diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index e9b2e31a769ad..1a959809073e5 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -66,7 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { ) }) { for impl_id in impl_ids.iter().map(|id| id.expect_local()) { - match type_map.entry(cx.tcx.type_of(impl_id)) { + let impl_ty = cx.tcx.bound_type_of(impl_id).subst_identity(); + match type_map.entry(impl_ty) { Entry::Vacant(e) => { // Store the id for the first impl block of this type. The span is retrieved lazily. e.insert(IdOrSpan::Id(impl_id)); diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index b8d4abdbb781a..a7c526692bb73 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { return; } if let ItemKind::Enum(ref def, _) = item.kind { - let ty = cx.tcx.type_of(item.owner_id); + let ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); let Adt(adt, subst) = ty.kind() else { panic!("already checked whether this is an enum") }; diff --git a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index 0aadb482acdda..e3e4c9a5bbe85 100644 --- a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -10,7 +10,7 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { if !pat.span.from_expansion(); if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind; if let Some(def_id) = path.res.opt_def_id(); - let ty = cx.tcx.type_of(def_id); + let ty = cx.tcx.bound_type_of(def_id).subst_identity(); if let ty::Adt(def, _) = ty.kind(); if def.is_struct() || def.is_union(); if fields.len() == def.non_enum_variant().fields.len(); diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs index 89aaad359d4ac..5b27145ac2266 100644 --- a/clippy_lints/src/methods/bytes_count_to_len.rs +++ b/clippy_lints/src/methods/bytes_count_to_len.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id); - if cx.tcx.type_of(impl_id).is_str(); + if cx.tcx.bound_type_of(impl_id).subst_identity().is_str(); let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs(); if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String); then { diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 0b3bf22743fae..052f2097899f7 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.type_of(impl_id).is_str(); + if cx.tcx.bound_type_of(impl_id).subst_identity().is_str(); if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind; if (2..=6).contains(&ext_literal.as_str().len()); let ext_str = ext_literal.as_str(); diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index cb17af608a3f0..a29c008e3d038 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.type_of(impl_id).is_slice(); + if cx.tcx.bound_type_of(impl_id).subst_identity().is_slice(); if let Some(_) = is_slice_of_primitives(cx, recv); if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; then { diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 06ecbce4e70e9..0065806ba2da8 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -53,7 +53,7 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir "to_vec" => cx .tcx .impl_of_method(method_def_id) - .filter(|&impl_did| cx.tcx.type_of(impl_did).is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()) + .filter(|&impl_did| cx.tcx.bound_type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()) .is_some(), _ => false, } diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index 5b758f1e6547c..b780a66374e9a 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option); + if is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::Option); if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind; if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr); if is_ok_wrapping(cx, map_expr); diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 52cc1e0464bf3..57004b4aea479 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id); if cx.tcx.impl_of_method(method_id) - .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id), sym::Option)) + .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.bound_type_of(id).subst_identity(), sym::Option)) || is_diag_trait_item(cx, method_id, sym::Iterator); if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind; then { diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs index b773b3e423f40..71fc5341b702a 100644 --- a/clippy_lints/src/methods/map_err_ignore.rs +++ b/clippy_lints/src/methods/map_err_ignore.rs @@ -9,7 +9,7 @@ use super::MAP_ERR_IGNORE; pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result) + && is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::Result) && let ExprKind::Closure(&Closure { capture_clause: CaptureBy::Ref, body, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f1e8be7f2b87f..a665f48c151d3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3349,7 +3349,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let name = impl_item.ident.name.as_str(); let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(parent); - let self_ty = cx.tcx.type_of(item.owner_id); + let self_ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind { diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index b9593b3687d9c..aa1a4c8075b8c 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &' if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Mutex); + if is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::Mutex); then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index 597af853dc681..e77bc6af47347 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -11,7 +11,7 @@ use super::NONSENSICAL_OPEN_OPTIONS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && match_type(cx, cx.tcx.type_of(impl_id), &paths::OPEN_OPTIONS) + && match_type(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), &paths::OPEN_OPTIONS) { let mut options = Vec::new(); get_open_options(cx, recv, &mut options); diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs index 0cc28c0dcb3d0..4522bf4539025 100644 --- a/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::PathBuf); + if is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::PathBuf); if let ExprKind::Lit(ref lit) = arg.kind; if let LitKind::Str(ref path_lit, _) = lit.node; if let pushed_path = Path::new(path_lit.as_str()); diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs index 09c8ca4cbe44c..6a0bf1560c33c 100644 --- a/clippy_lints/src/methods/stable_sort_primitive.rs +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -10,7 +10,7 @@ use super::STABLE_SORT_PRIMITIVE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && cx.tcx.type_of(impl_id).is_slice() + && cx.tcx.bound_type_of(impl_id).subst_identity().is_slice() && let Some(slice_type) = is_slice_of_primitives(cx, recv) { span_lint_and_then( diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index 219a9edd65768..17f422d0e6994 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(call_id); if cx.tcx.impl_trait_ref(impl_id).is_none(); - let self_ty = cx.tcx.type_of(impl_id); + let self_ty = cx.tcx.bound_type_of(impl_id).subst_identity(); if self_ty.is_slice() || self_ty.is_str(); then { // Ignore empty slice and string literals when used with a literal count. diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index ed5a75b0f3ce5..436e637201a0d 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -122,7 +122,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.type_of(impl_id).is_slice(); + if cx.tcx.bound_type_of(impl_id).subst_identity().is_slice(); if let ExprKind::Closure(&Closure { body, .. }) = arg.kind; if let closure_body = cx.tcx.hir().body(body); if let &[ diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index d50346c166ae0..5959fdb6625fd 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -143,7 +143,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { if_chain! { if args.iter().all(|arg| !self.is_binding(arg)); if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id); - let method_ty = self.cx.tcx.type_of(method_def_id); + let method_ty = self.cx.tcx.bound_type_of(method_def_id).subst_identity(); let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder(); if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not)); then { diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs index 02d8364cb2959..8c461b2629d70 100644 --- a/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -20,7 +20,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Vec); + if is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::Vec); if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind; if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind; then { diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index faf9ec61ec504..47dc4b276a271 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -98,14 +98,15 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { if name == sym::new; if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id); let self_def_id = cx.tcx.hir().get_parent_item(id.into()); - let self_ty = cx.tcx.type_of(self_def_id); + let self_ty = cx.tcx.bound_type_of(self_def_id).subst_identity(); if self_ty == return_ty(cx, id); if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); then { if self.impling_types.is_none() { 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() { + let ty = cx.tcx.bound_type_of(d).subst_identity(); + if let Some(ty_def) = ty.ty_adt_def() { 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)); } @@ -118,7 +119,8 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // generics 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(); + let self_def = cx.tcx.bound_type_of(self_def_id).subst_identity(); + if let Some(self_def) = self_def.ty_adt_def(); 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); diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 07fd321d69fce..a076bed50d1b7 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -313,7 +313,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // and, in that case, the definition is *not* generic. cx.tcx.normalize_erasing_regions( cx.tcx.param_env(of_trait_def_id), - cx.tcx.type_of(of_assoc_item), + cx.tcx.bound_type_of(of_assoc_item).subst_identity(), ), )) .is_err(); diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index 3ce030cd721a7..df834962673d3 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(parent); - let self_ty = cx.tcx.type_of(item.owner_id); + let self_ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); let ret_ty = return_ty(cx, impl_item.owner_id); // Do not check trait impls diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 3cd35838961f6..a50b38c54dca4 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } else { hir_ty_to_ty(cx.tcx, hir_ty) }; - if same_type_and_consts(ty, cx.tcx.type_of(impl_id)); + if same_type_and_consts(ty, cx.tcx.bound_type_of(impl_id).subst_identity()); then { span_lint(cx, hir_ty.span); } @@ -230,7 +230,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if !expr.span.from_expansion(); if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); - if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id); + if cx.typeck_results().expr_ty(expr) == cx.tcx.bound_type_of(impl_id).subst_identity(); then {} else { return; } } match expr.kind { @@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if let PatKind::Path(QPath::Resolved(_, path)) | PatKind::TupleStruct(QPath::Resolved(_, path), _, _) | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind; - if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id); + if cx.typeck_results().pat_ty(pat) == cx.tcx.bound_type_of(impl_id).subst_identity(); then { check_path(cx, path); } diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index 4b33d492a0e47..f62bfa4f22170 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { for item in cx.tcx.module_children(def_id).iter() { if_chain! { if let Res::Def(DefKind::Const, item_def_id) = item.res; - let ty = cx.tcx.type_of(item_def_id); + let ty = cx.tcx.bound_type_of(item_def_id).subst_identity(); if match_type(cx, ty, &paths::SYMBOL); if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id); if let Ok(value) = value.to_u32(); diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 9876a8a765ccb..3249b8633914a 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -38,7 +38,8 @@ impl LateLintPass<'_> for MsrvAttrImpl { if self_ty_def.is_struct(); if self_ty_def.all_fields().any(|f| { cx.tcx - .type_of(f.did) + .bound_type_of(f.did) + .subst_identity() .walk() .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV)) diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 7144363637a04..3f08566dbcc75 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -229,11 +229,11 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option read_mir_alloc_def_path( cx, cx.tcx.eval_static_initializer(def_id).ok()?.inner(), - cx.tcx.type_of(def_id), + cx.tcx.bound_type_of(def_id).subst_identity(), ), Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? { ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => { - read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id)) + read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.bound_type_of(def_id).subst_identity()) }, _ => None, }, diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 5c89dd3e49f41..97b2cc382b0d6 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -50,7 +50,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: let name = name.as_str(); let ty = match cx.tcx.impl_of_method(fn_id) { - Some(id) => cx.tcx.type_of(id), + Some(id) => cx.tcx.bound_type_of(id).subst_identity(), None => return Lazy, }; @@ -71,7 +71,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: .variants() .iter() .flat_map(|v| v.fields.iter()) - .any(|x| matches!(cx.tcx.type_of(x.did).peel_refs().kind(), ty::Param(_))) + .any(|x| matches!(cx.tcx.bound_type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_))) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { PredicateKind::Clause(ty::Clause::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, _ => true, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 3b8713e2b108c..168055657755f 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -317,7 +317,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) /// Checks if a method is defined in an impl of a diagnostic item 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() { + if let Some(adt) = cx.tcx.bound_type_of(impl_did).subst_identity().ty_adt_def() { return cx.tcx.is_diagnostic_item(diag_item, adt.did()); } } @@ -812,7 +812,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< if let QPath::TypeRelative(_, method) = path { if method.ident.name == sym::new { 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() { + if let Some(adt) = cx.tcx.bound_type_of(impl_did).subst_identity().ty_adt_def() { return std_types_symbols.iter().any(|&symbol| { cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string() }); diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index d6af7a948a5c5..6987d1d2d65a7 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -780,7 +780,7 @@ impl core::ops::Add for EnumValue { #[expect(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() { + match tcx.bound_type_of(id).subst_identity().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), @@ -903,7 +903,7 @@ pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx Va let var_id = cx.tcx.parent(id); Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) }, - Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()), + Res::SelfCtor(id) => Some(cx.tcx.bound_type_of(id).subst_identity().ty_adt_def().unwrap().non_enum_variant()), _ => None, } } From 98c4a49db8c305c468646715b773fa9b6ec7049a Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Tue, 7 Feb 2023 01:29:48 -0700 Subject: [PATCH 62/90] remove bound_type_of query; make type_of return EarlyBinder; change type_of in metadata --- clippy_lints/src/casts/cast_ptr_alignment.rs | 2 +- clippy_lints/src/copy_iterator.rs | 2 +- clippy_lints/src/default.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/derive.rs | 4 ++-- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/eta_reduction.rs | 6 +++--- clippy_lints/src/functions/misnamed_getters.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 4 ++-- clippy_lints/src/inherent_impl.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs | 2 +- clippy_lints/src/methods/bytes_count_to_len.rs | 2 +- .../methods/case_sensitive_file_extension_comparisons.rs | 2 +- clippy_lints/src/methods/get_first.rs | 2 +- clippy_lints/src/methods/implicit_clone.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/map_err_ignore.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/mut_mutex_lock.rs | 2 +- clippy_lints/src/methods/open_options.rs | 2 +- clippy_lints/src/methods/path_buf_push_overwrite.rs | 2 +- clippy_lints/src/methods/stable_sort_primitive.rs | 2 +- clippy_lints/src/methods/suspicious_splitn.rs | 2 +- clippy_lints/src/methods/unnecessary_sort_by.rs | 2 +- clippy_lints/src/methods/utils.rs | 2 +- clippy_lints/src/methods/vec_resize_to_zero.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/new_without_default.rs | 6 +++--- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/self_named_constructors.rs | 2 +- clippy_lints/src/transmute/transmute_undefined_repr.rs | 2 +- clippy_lints/src/use_self.rs | 6 +++--- .../src/utils/internal_lints/interning_defined_symbol.rs | 2 +- clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs | 2 +- .../src/utils/internal_lints/unnecessary_def_path.rs | 4 ++-- clippy_utils/src/eager_or_lazy.rs | 4 ++-- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/ty.rs | 4 ++-- 43 files changed, 56 insertions(+), 56 deletions(-) diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 58d4cfff06f50..6c8ee296c7510 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -66,7 +66,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned") && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && let Some(def_id) = cx.tcx.impl_of_method(def_id) - && cx.tcx.bound_type_of(def_id).subst_identity().is_unsafe_ptr() + && cx.tcx.type_of(def_id).subst_identity().is_unsafe_ptr() { true } else { diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 023f9e64deb92..0fc11523298f1 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyIterator { of_trait: Some(ref trait_ref), .. }) = item.kind; - let ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); + let ty = cx.tcx.type_of(item.owner_id).subst_identity(); if is_copy(cx, ty); if let Some(trait_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id); diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index b6b7eaae0686b..080d44e6398c1 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { .fields .iter() .all(|field| { - is_copy(cx, cx.tcx.bound_type_of(field.did).subst_identity()) + is_copy(cx, cx.tcx.type_of(field.did).subst_identity()) }); if !has_drop(cx, binding_type) || all_fields_are_copy; then { diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index e368efe944cff..4e1a6cd4d7355 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -167,7 +167,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { .iter() .find_map(|f_def| { if f_def.ident(self.cx.tcx) == field.ident - { Some(self.cx.tcx.bound_type_of(f_def.did).subst_identity()) } + { Some(self.cx.tcx.type_of(f_def.did).subst_identity()) } else { None } }); self.ty_bounds.push(bound.into()); diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 4c9f4f7f8ccac..b4543aa2544f8 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -735,7 +735,7 @@ fn walk_parents<'tcx>( span, .. }) if span.ctxt() == ctxt => { - let ty = cx.tcx.bound_type_of(owner_id.def_id).subst_identity(); + let ty = cx.tcx.type_of(owner_id.def_id).subst_identity(); Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx)) }, @@ -771,7 +771,7 @@ fn walk_parents<'tcx>( }) => variant_of_res(cx, cx.qpath_res(path, *hir_id)) .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name)) .map(|field_def| { - ty_auto_deref_stability(cx, cx.tcx.bound_type_of(field_def.did).subst_identity(), precedence).position_for_arg() + ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did).subst_identity(), precedence).position_for_arg() }), _ => None, }, diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index f1d2db4487189..f95b8ccf067b4 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir); if let ImplItemKind::Fn(_, b) = &impl_item.kind; if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b); - if let Some(adt_def) = cx.tcx.bound_type_of(item.owner_id).subst_identity().ty_adt_def(); + if let Some(adt_def) = cx.tcx.type_of(item.owner_id).subst_identity().ty_adt_def(); if let attrs = cx.tcx.hir().attrs(item.hir_id()); if !attrs.iter().any(|attr| attr.doc_str().is_some()); if let child_attrs = cx.tcx.hir().attrs(impl_item_hir); diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 0181b164f057e..1cdcccd5f146c 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -211,7 +211,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { .. }) = item.kind { - let ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); + let ty = cx.tcx.type_of(item.owner_id).subst_identity(); let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); @@ -347,7 +347,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { impls .iter() - .any(|&id| matches!(cx.tcx.bound_type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did())) + .any(|&id| matches!(cx.tcx.type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did())) }); if !has_copy_impl { return; diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 8c0112ca4a1cb..d94664daa5619 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum { } if let ItemKind::Enum(..) = item.kind { - let ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); + let ty = cx.tcx.type_of(item.owner_id).subst_identity(); let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); if adt.variants().is_empty() { span_lint_and_help( diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index e5289c177f3e9..e275efaba25fb 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { for var in def.variants { if let Some(anon_const) = &var.disr_expr { let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body); - let mut ty = cx.tcx.bound_type_of(def_id.to_def_id()).subst_identity(); + let mut ty = cx.tcx.type_of(def_id.to_def_id()).subst_identity(); let constant = cx .tcx .const_eval_poly(def_id.to_def_id()) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index a41ad735fb810..ddade65c515c6 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if check_inputs(cx, body.params, None, args); let callee_ty = cx.typeck_results().expr_ty_adjusted(callee); let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id) - .map_or(callee_ty, |id| cx.tcx.bound_type_of(id).subst_identity()); + .map_or(callee_ty, |id| cx.tcx.type_of(id).subst_identity()); if check_sig(cx, closure_ty, call_ty); let substs = cx.typeck_results().node_substs(callee.hir_id); // This fixes some false positives that I don't entirely understand @@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if check_inputs(cx, body.params, Some(receiver), args); let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(body.value.hir_id); - let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs); + let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs); if check_sig(cx, closure_ty, call_ty); then { span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| { @@ -233,7 +233,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs match assoc_item.container { ty::TraitContainer => cx.tcx.def_path_str(def_id), ty::ImplContainer => { - let ty = cx.tcx.bound_type_of(def_id).skip_binder(); + let ty = cx.tcx.type_of(def_id).skip_binder(); match ty.kind() { ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()), ty::Array(..) diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index 1405316c9bc07..8b53ee68ebdfb 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -101,7 +101,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: return; }; - if cx.tcx.bound_type_of(used_field.did) == cx.tcx.bound_type_of(correct_field.did) { + if cx.tcx.type_of(used_field.did) == cx.tcx.type_of(correct_field.did) { let left_span = block_expr.span.until(used_ident.span); let snippet = snippet(cx, left_span, ".."); let sugg = format!("{snippet}{name}"); diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index bff3cd4e3a19b..0c7aea6da8fee 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(const_id); if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl - if cx.tcx.bound_type_of(impl_id).subst_identity().is_integral(); + if cx.tcx.type_of(impl_id).subst_identity().is_integral(); then { print_lint_and_sugg(cx, var_name, expr) } @@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(func_id); if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl - if cx.tcx.bound_type_of(impl_id).subst_identity().is_integral(); + if cx.tcx.type_of(impl_id).subst_identity().is_integral(); then { print_lint_and_sugg(cx, var_name, expr) } diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 1a959809073e5..7c41699f307aa 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { ) }) { for impl_id in impl_ids.iter().map(|id| id.expect_local()) { - let impl_ty = cx.tcx.bound_type_of(impl_id).subst_identity(); + let impl_ty = cx.tcx.type_of(impl_id).subst_identity(); match type_map.entry(impl_ty) { Entry::Vacant(e) => { // Store the id for the first impl block of this type. The span is retrieved lazily. diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index a7c526692bb73..1c99bd2f3d02e 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { return; } if let ItemKind::Enum(ref def, _) = item.kind { - let ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); + let ty = cx.tcx.type_of(item.owner_id).subst_identity(); let Adt(adt, subst) = ty.kind() else { panic!("already checked whether this is an enum") }; diff --git a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index e3e4c9a5bbe85..d06bcdaa27f0a 100644 --- a/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -10,7 +10,7 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { if !pat.span.from_expansion(); if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind; if let Some(def_id) = path.res.opt_def_id(); - let ty = cx.tcx.bound_type_of(def_id).subst_identity(); + let ty = cx.tcx.type_of(def_id).subst_identity(); if let ty::Adt(def, _) = ty.kind(); if def.is_struct() || def.is_union(); if fields.len() == def.non_enum_variant().fields.len(); diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs index 5b27145ac2266..46a20ad412baf 100644 --- a/clippy_lints/src/methods/bytes_count_to_len.rs +++ b/clippy_lints/src/methods/bytes_count_to_len.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id); - if cx.tcx.bound_type_of(impl_id).subst_identity().is_str(); + if cx.tcx.type_of(impl_id).subst_identity().is_str(); let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs(); if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String); then { diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 052f2097899f7..7711aa78b2391 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.bound_type_of(impl_id).subst_identity().is_str(); + if cx.tcx.type_of(impl_id).subst_identity().is_str(); if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind; if (2..=6).contains(&ext_literal.as_str().len()); let ext_str = ext_literal.as_str(); diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index a29c008e3d038..945bbf53bcf35 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.bound_type_of(impl_id).subst_identity().is_slice(); + if cx.tcx.type_of(impl_id).subst_identity().is_slice(); if let Some(_) = is_slice_of_primitives(cx, recv); if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; then { diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 0065806ba2da8..374eb29fc527b 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -53,7 +53,7 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir "to_vec" => cx .tcx .impl_of_method(method_def_id) - .filter(|&impl_did| cx.tcx.bound_type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()) + .filter(|&impl_did| cx.tcx.type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()) .is_some(), _ => false, } diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index b780a66374e9a..b9a0ec779961e 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::Option); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Option); if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind; if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr); if is_ok_wrapping(cx, map_expr); diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 57004b4aea479..2b26ef0141096 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id); if cx.tcx.impl_of_method(method_id) - .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.bound_type_of(id).subst_identity(), sym::Option)) + .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id).subst_identity(), sym::Option)) || is_diag_trait_item(cx, method_id, sym::Iterator); if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind; then { diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs index 71fc5341b702a..a5beb291f3263 100644 --- a/clippy_lints/src/methods/map_err_ignore.rs +++ b/clippy_lints/src/methods/map_err_ignore.rs @@ -9,7 +9,7 @@ use super::MAP_ERR_IGNORE; pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::Result) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Result) && let ExprKind::Closure(&Closure { capture_clause: CaptureBy::Ref, body, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a665f48c151d3..6301b3ded20dc 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3349,7 +3349,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let name = impl_item.ident.name.as_str(); let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(parent); - let self_ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); + let self_ty = cx.tcx.type_of(item.owner_id).subst_identity(); let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind { diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index aa1a4c8075b8c..d0aa39d06275a 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &' if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::Mutex); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Mutex); then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index e77bc6af47347..c6a27cdd6fac0 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -11,7 +11,7 @@ use super::NONSENSICAL_OPEN_OPTIONS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && match_type(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), &paths::OPEN_OPTIONS) + && match_type(cx, cx.tcx.type_of(impl_id).subst_identity(), &paths::OPEN_OPTIONS) { let mut options = Vec::new(); get_open_options(cx, recv, &mut options); diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs index 4522bf4539025..e3f2de3cd4669 100644 --- a/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::PathBuf); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf); if let ExprKind::Lit(ref lit) = arg.kind; if let LitKind::Str(ref path_lit, _) = lit.node; if let pushed_path = Path::new(path_lit.as_str()); diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs index 6a0bf1560c33c..b5fd0ad8ce524 100644 --- a/clippy_lints/src/methods/stable_sort_primitive.rs +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -10,7 +10,7 @@ use super::STABLE_SORT_PRIMITIVE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && cx.tcx.bound_type_of(impl_id).subst_identity().is_slice() + && cx.tcx.type_of(impl_id).subst_identity().is_slice() && let Some(slice_type) = is_slice_of_primitives(cx, recv) { span_lint_and_then( diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index 17f422d0e6994..90ca66bd70c50 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(call_id); if cx.tcx.impl_trait_ref(impl_id).is_none(); - let self_ty = cx.tcx.bound_type_of(impl_id).subst_identity(); + let self_ty = cx.tcx.type_of(impl_id).subst_identity(); if self_ty.is_slice() || self_ty.is_str(); then { // Ignore empty slice and string literals when used with a literal count. diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 436e637201a0d..5201da52bbf1d 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -122,7 +122,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if cx.tcx.bound_type_of(impl_id).subst_identity().is_slice(); + if cx.tcx.type_of(impl_id).subst_identity().is_slice(); if let ExprKind::Closure(&Closure { body, .. }) = arg.kind; if let closure_body = cx.tcx.hir().body(body); if let &[ diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 5959fdb6625fd..c96d69226972f 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -143,7 +143,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { if_chain! { if args.iter().all(|arg| !self.is_binding(arg)); if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id); - let method_ty = self.cx.tcx.bound_type_of(method_def_id).subst_identity(); + let method_ty = self.cx.tcx.type_of(method_def_id).subst_identity(); let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder(); if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not)); then { diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs index 8c461b2629d70..b0cfc163fd08b 100644 --- a/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -20,7 +20,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); - if is_type_diagnostic_item(cx, cx.tcx.bound_type_of(impl_id).subst_identity(), sym::Vec); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Vec); if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind; if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind; then { diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 4547ed7eafc86..e91aac41bc485 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { ExprKind::MethodCall(path, receiver, arguments, _) => { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); - let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs); + let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); check_arguments( cx, std::iter::once(receiver).chain(arguments.iter()).collect(), diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 47dc4b276a271..653b1a8a05f66 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -98,14 +98,14 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { if name == sym::new; if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id); let self_def_id = cx.tcx.hir().get_parent_item(id.into()); - let self_ty = cx.tcx.bound_type_of(self_def_id).subst_identity(); + let self_ty = cx.tcx.type_of(self_def_id).subst_identity(); if self_ty == return_ty(cx, id); if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); then { if self.impling_types.is_none() { let mut impls = HirIdSet::default(); cx.tcx.for_each_impl(default_trait_id, |d| { - let ty = cx.tcx.bound_type_of(d).subst_identity(); + let ty = cx.tcx.type_of(d).subst_identity(); if let Some(ty_def) = ty.ty_adt_def() { 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)); @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // generics if_chain! { if let Some(ref impling_types) = self.impling_types; - let self_def = cx.tcx.bound_type_of(self_def_id).subst_identity(); + let self_def = cx.tcx.type_of(self_def_id).subst_identity(); if let Some(self_def) = self_def.ty_adt_def(); 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); diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index a076bed50d1b7..0bedab05eec61 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -313,7 +313,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { // and, in that case, the definition is *not* generic. cx.tcx.normalize_erasing_regions( cx.tcx.param_env(of_trait_def_id), - cx.tcx.bound_type_of(of_assoc_item).subst_identity(), + cx.tcx.type_of(of_assoc_item).subst_identity(), ), )) .is_err(); diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index df834962673d3..beca203c868d8 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(parent); - let self_ty = cx.tcx.bound_type_of(item.owner_id).subst_identity(); + let self_ty = cx.tcx.type_of(item.owner_id).subst_identity(); let ret_ty = return_ty(cx, impl_item.owner_id); // Do not check trait impls diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index af0242348ac29..5e24213d07fd2 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -273,7 +273,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> .non_enum_variant() .fields .iter() - .map(|f| cx.tcx.bound_type_of(f.did).subst(cx.tcx, substs)); + .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::TypeErasure { raw_ptr_only: false }; }; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index a50b38c54dca4..e7c54000684ab 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } else { hir_ty_to_ty(cx.tcx, hir_ty) }; - if same_type_and_consts(ty, cx.tcx.bound_type_of(impl_id).subst_identity()); + if same_type_and_consts(ty, cx.tcx.type_of(impl_id).subst_identity()); then { span_lint(cx, hir_ty.span); } @@ -230,7 +230,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if !expr.span.from_expansion(); if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); - if cx.typeck_results().expr_ty(expr) == cx.tcx.bound_type_of(impl_id).subst_identity(); + if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).subst_identity(); then {} else { return; } } match expr.kind { @@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if let PatKind::Path(QPath::Resolved(_, path)) | PatKind::TupleStruct(QPath::Resolved(_, path), _, _) | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind; - if cx.typeck_results().pat_ty(pat) == cx.tcx.bound_type_of(impl_id).subst_identity(); + if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).subst_identity(); then { check_path(cx, path); } diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index f62bfa4f22170..688a8b865f329 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { for item in cx.tcx.module_children(def_id).iter() { if_chain! { if let Res::Def(DefKind::Const, item_def_id) = item.res; - let ty = cx.tcx.bound_type_of(item_def_id).subst_identity(); + let ty = cx.tcx.type_of(item_def_id).subst_identity(); if match_type(cx, ty, &paths::SYMBOL); if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id); if let Ok(value) = value.to_u32(); diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 3249b8633914a..09f0f0d0adb6f 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -38,7 +38,7 @@ impl LateLintPass<'_> for MsrvAttrImpl { if self_ty_def.is_struct(); if self_ty_def.all_fields().any(|f| { cx.tcx - .bound_type_of(f.did) + .type_of(f.did) .subst_identity() .walk() .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 3f08566dbcc75..ee5e42bae0f10 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -229,11 +229,11 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option read_mir_alloc_def_path( cx, cx.tcx.eval_static_initializer(def_id).ok()?.inner(), - cx.tcx.bound_type_of(def_id).subst_identity(), + cx.tcx.type_of(def_id).subst_identity(), ), Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? { ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => { - read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.bound_type_of(def_id).subst_identity()) + read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).subst_identity()) }, _ => None, }, diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 97b2cc382b0d6..6ff7728374f83 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -50,7 +50,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: let name = name.as_str(); let ty = match cx.tcx.impl_of_method(fn_id) { - Some(id) => cx.tcx.bound_type_of(id).subst_identity(), + Some(id) => cx.tcx.type_of(id).subst_identity(), None => return Lazy, }; @@ -71,7 +71,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: .variants() .iter() .flat_map(|v| v.fields.iter()) - .any(|x| matches!(cx.tcx.bound_type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_))) + .any(|x| matches!(cx.tcx.type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_))) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { PredicateKind::Clause(ty::Clause::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, _ => true, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 168055657755f..b2edd1bbfef43 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -317,7 +317,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) /// Checks if a method is defined in an impl of a diagnostic item 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.bound_type_of(impl_did).subst_identity().ty_adt_def() { + if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() { return cx.tcx.is_diagnostic_item(diag_item, adt.did()); } } @@ -812,7 +812,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< if let QPath::TypeRelative(_, method) = path { if method.ident.name == sym::new { if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { - if let Some(adt) = cx.tcx.bound_type_of(impl_did).subst_identity().ty_adt_def() { + if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() { return std_types_symbols.iter().any(|&symbol| { cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string() }); diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 6987d1d2d65a7..2ed301fcc2291 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -780,7 +780,7 @@ impl core::ops::Add for EnumValue { #[expect(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.bound_type_of(id).subst_identity().kind() { + match tcx.type_of(id).subst_identity().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), @@ -903,7 +903,7 @@ pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx Va let var_id = cx.tcx.parent(id); Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) }, - Res::SelfCtor(id) => Some(cx.tcx.bound_type_of(id).subst_identity().ty_adt_def().unwrap().non_enum_variant()), + Res::SelfCtor(id) => Some(cx.tcx.type_of(id).subst_identity().ty_adt_def().unwrap().non_enum_variant()), _ => None, } } From 8a66a6816b6344af9bd44fac39da589984087723 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 16 Feb 2023 11:55:58 +0000 Subject: [PATCH 63/90] Add `Clause::ConstArgHasType` variant --- clippy_utils/src/qualify_min_const_fn.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 26b1d01974990..1a35fe05067fc 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -30,7 +30,8 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) ty::Clause::RegionOutlives(_) | ty::Clause::TypeOutlives(_) | ty::Clause::Projection(_) - | ty::Clause::Trait(..), + | ty::Clause::Trait(..) + | ty::Clause::ConstArgHasType(..), ) | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::ConstEvaluatable(..) From ae12b7238ebb2a0400cee54f91cc9109696dfb30 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 16 Feb 2023 11:47:50 +1100 Subject: [PATCH 64/90] Replace `mk_foo` calls with `infer_foo` where possible. There are several `mk_foo`/`intern_foo` pairs, where the former takes an iterator and the latter takes a slice. (This naming convention is bad, but that's a fix for another PR.) This commit changes several `mk_foo` occurrences into `intern_foo`, avoiding the need for some `.iter()`/`.into_iter()` calls. Affected cases: - mk_type_list - mk_tup - mk_substs - mk_const_list --- clippy_lints/src/methods/needless_collect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 82d3b830d4f39..8ddbacc3d7ad4 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -173,7 +173,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let Some(iter_item) = cx.tcx .associated_items(iter_trait) .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait) - && let substs = cx.tcx.mk_substs([GenericArg::from(typeck.expr_ty_adjusted(iter_expr))].into_iter()) + && let substs = cx.tcx.intern_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { From a3837c6bd8476828f92a71366f422f9833ef65a7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 16 Feb 2023 16:27:05 +1100 Subject: [PATCH 65/90] Replace more `mk_foo` calls with `infer_foo`. --- clippy_lints/src/redundant_slicing.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 245a02ea26e61..398329e455bfa 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -11,8 +11,6 @@ use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::subst::GenericArg; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use std::iter; - declare_clippy_lint! { /// ### What it does /// Checks for redundant slicing expressions which use the full range, and @@ -136,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { } 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(iter::once(GenericArg::from(indexed_ty)))), + cx.tcx.mk_projection(target_id, cx.tcx.intern_substs(&[GenericArg::from(indexed_ty)])), ) { if deref_ty == expr_ty { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; From c29e767ef1f2afc534c175f16fce5d671943fe4b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 17 Feb 2023 09:09:44 -0500 Subject: [PATCH 66/90] Address review comments --- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/utils/conf.rs | 3 ++- .../pub_crate_missing_doc.rs | 8 ++++++++ .../pub_crate_missing_doc.stderr | 20 ++++++++++++------- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index a5d8a500cca79..74592918bfc75 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -103,7 +103,7 @@ impl MissingDoc { if self.crate_items_only && def_id != CRATE_DEF_ID { let vis = cx.tcx.visibility(def_id); - if vis != Visibility::Public && vis != Visibility::Restricted(CRATE_DEF_ID.into()) { + if vis == Visibility::Public || vis != Visibility::Restricted(CRATE_DEF_ID.into()) { return; } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index ae35ceebc5530..c3c73ac6e378e 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -456,7 +456,8 @@ define_Conf! { (suppress_restriction_lint_in_const: bool = false), /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. /// - /// Whether to **only** check for missing documentation in `pub(crate)` items. + /// Whether to **only** check for missing documentation in items visible within the current + /// crate. For example, `pub(crate)` items. (missing_docs_in_crate_items: bool = false), } diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs index f2edb737d59cc..830d71f61dd50 100644 --- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs +++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs @@ -1,4 +1,5 @@ //! this is crate +#![allow(missing_docs)] #![warn(clippy::missing_docs_in_private_items)] /// this is mod @@ -45,6 +46,13 @@ mod my_mod { } } +/// some docs +type CrateTypedefWithDocs = String; +type CrateTypedefNoDocs = String; +/// some docs +pub type PubTypedefWithDocs = String; +pub type PubTypedefNoDocs = String; + fn main() { my_mod::crate_with_docs(); my_mod::crate_no_docs(); diff --git a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr index 89927abd87bfe..a474187050c17 100644 --- a/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr +++ b/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a function - --> $DIR/pub_crate_missing_doc.rs:11:5 + --> $DIR/pub_crate_missing_doc.rs:12:5 | LL | pub(crate) fn crate_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | pub(crate) fn crate_no_docs() {} = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a function - --> $DIR/pub_crate_missing_doc.rs:14:5 + --> $DIR/pub_crate_missing_doc.rs:15:5 | LL | pub(super) fn super_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/pub_crate_missing_doc.rs:22:9 + --> $DIR/pub_crate_missing_doc.rs:23:9 | LL | pub(crate) fn sub_crate_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/pub_crate_missing_doc.rs:32:9 + --> $DIR/pub_crate_missing_doc.rs:33:9 | LL | pub(crate) crate_field_no_docs: (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct - --> $DIR/pub_crate_missing_doc.rs:38:5 + --> $DIR/pub_crate_missing_doc.rs:39:5 | LL | / pub(crate) struct CrateStructNoDocs { LL | | /// some docs @@ -37,10 +37,16 @@ LL | | } | |_____^ error: missing documentation for a struct field - --> $DIR/pub_crate_missing_doc.rs:41:9 + --> $DIR/pub_crate_missing_doc.rs:42:9 | LL | pub(crate) crate_field_no_docs: (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: missing documentation for a type alias + --> $DIR/pub_crate_missing_doc.rs:51:1 + | +LL | type CrateTypedefNoDocs = String; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors From 75189695011c0c047db3d2eacfbfeb7fb0836aa2 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 18 Feb 2023 09:14:41 -0300 Subject: [PATCH 67/90] Evaluate the return expression of a block --- .../src/significant_drop_tightening.rs | 37 ++++++++++++++----- tests/ui/significant_drop_tightening.fixed | 20 ++++++++++ tests/ui/significant_drop_tightening.rs | 19 ++++++++++ tests/ui/significant_drop_tightening.stderr | 33 ++++++++++++++--- 4 files changed, 95 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 367466b7d8206..e2d90edec5a4c 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -61,10 +61,26 @@ pub struct SignificantDropTightening<'tcx> { } impl<'tcx> SignificantDropTightening<'tcx> { + /// Unifies the statements of a block with its return expression. + fn all_block_stmts<'ret, 'rslt, 'stmts>( + block_stmts: &'stmts [hir::Stmt<'tcx>], + dummy_ret_stmt: Option<&'ret hir::Stmt<'tcx>>, + ) -> impl Iterator> + where + 'ret: 'rslt, + 'stmts: 'rslt, + { + block_stmts.iter().chain(dummy_ret_stmt) + } + /// Searches for at least one statement that could slow down the release of a significant drop. - fn at_least_one_stmt_is_expensive(stmts: &[hir::Stmt<'_>]) -> bool { + fn at_least_one_stmt_is_expensive<'stmt>(stmts: impl Iterator>) -> bool + where + 'tcx: 'stmt, + { for stmt in stmts { match stmt.kind { + hir::StmtKind::Expr(expr) if let hir::ExprKind::Path(_) = expr.kind => {} hir::StmtKind::Local(local) if let Some(expr) = local.init && let hir::ExprKind::Path(_) = expr.kind => {}, _ => return true @@ -99,7 +115,7 @@ impl<'tcx> SignificantDropTightening<'tcx> { expr: &'tcx hir::Expr<'_>, idx: usize, sdap: &mut SigDropAuxParams, - stmt: &'tcx hir::Stmt<'_>, + stmt: &hir::Stmt<'_>, cb: impl Fn(&mut SigDropAuxParams), ) { let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types); @@ -117,7 +133,7 @@ impl<'tcx> SignificantDropTightening<'tcx> { } } - /// Shows a generic overall message as well as specialized messages depending on the usage. + /// Shows generic overall messages as well as specialized messages depending on the usage. fn set_suggestions(cx: &LateContext<'tcx>, block_span: Span, diag: &mut Diagnostic, sdap: &SigDropAuxParams) { match sdap.number_of_stmts { 0 | 1 => {}, @@ -172,8 +188,13 @@ impl<'tcx> SignificantDropTightening<'tcx> { impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { + let dummy_ret_stmt = block.expr.map(|expr| hir::Stmt { + hir_id: hir::HirId::INVALID, + kind: hir::StmtKind::Expr(expr), + span: DUMMY_SP, + }); let mut sdap = SigDropAuxParams::default(); - for (idx, stmt) in block.stmts.iter().enumerate() { + for (idx, stmt) in Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).enumerate() { match stmt.kind { hir::StmtKind::Expr(expr) => self.modify_sdap_if_sig_drop_exists( cx, @@ -213,11 +234,9 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { _ => {} }; } - let stmts_after_last_use = sdap - .last_use_stmt_idx - .checked_add(1) - .and_then(|idx| block.stmts.get(idx..)) - .unwrap_or_default(); + + let idx = sdap.last_use_stmt_idx.wrapping_add(1); + let stmts_after_last_use = Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).skip(idx); if sdap.number_of_stmts > 1 && Self::at_least_one_stmt_is_expensive(stmts_after_last_use) { span_lint_and_then( cx, diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed index 5d176d2a92726..da998c610bd29 100644 --- a/tests/ui/significant_drop_tightening.fixed +++ b/tests/ui/significant_drop_tightening.fixed @@ -4,6 +4,26 @@ use std::sync::Mutex; +pub fn complex_return_triggers_the_lint() -> i32 { + fn foo() -> i32 { + 1 + } + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let _ = *lock; + let _ = *lock; + drop(lock); + foo() +} + +pub fn path_return_can_be_ignored() -> i32 { + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let rslt = *lock; + let _ = *lock; + rslt +} + pub fn post_bindings_can_be_ignored() { let mutex = Mutex::new(1); let lock = mutex.lock().unwrap(); diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index be9c0774275d6..83823f95f68ac 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -4,6 +4,25 @@ use std::sync::Mutex; +pub fn complex_return_triggers_the_lint() -> i32 { + fn foo() -> i32 { + 1 + } + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let _ = *lock; + let _ = *lock; + foo() +} + +pub fn path_return_can_be_ignored() -> i32 { + let mutex = Mutex::new(1); + let lock = mutex.lock().unwrap(); + let rslt = *lock; + let _ = *lock; + rslt +} + pub fn post_bindings_can_be_ignored() { let mutex = Mutex::new(1); let lock = mutex.lock().unwrap(); diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr index 0ec9b1acb5951..ab8ce356ec7b5 100644 --- a/tests/ui/significant_drop_tightening.stderr +++ b/tests/ui/significant_drop_tightening.stderr @@ -1,5 +1,29 @@ error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:25:13 + --> $DIR/significant_drop_tightening.rs:12:9 + | +LL | pub fn complex_return_triggers_the_lint() -> i32 { + | __________________________________________________- +LL | | fn foo() -> i32 { +LL | | 1 +LL | | } +LL | | let mutex = Mutex::new(1); +LL | | let lock = mutex.lock().unwrap(); + | | ^^^^ +... | +LL | | foo() +LL | | } + | |_- temporary `lock` is currently being dropped at the end of its contained scope + | + = note: this might lead to unnecessary resource contention + = note: `-D clippy::significant-drop-tightening` implied by `-D warnings` +help: drop the temporary after the end of its last usage + | +LL ~ let _ = *lock; +LL + drop(lock); + | + +error: temporary with significant `Drop` can be early dropped + --> $DIR/significant_drop_tightening.rs:44:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -12,7 +36,6 @@ LL | | } | |_____- temporary `lock` is currently being dropped at the end of its contained scope | = note: this might lead to unnecessary resource contention - = note: `-D clippy::significant-drop-tightening` implied by `-D warnings` help: drop the temporary after the end of its last usage | LL ~ let rslt1 = lock.is_positive(); @@ -20,7 +43,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:46:13 + --> $DIR/significant_drop_tightening.rs:65:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -44,7 +67,7 @@ LL + | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:52:17 + --> $DIR/significant_drop_tightening.rs:71:17 | LL | / { LL | | let mutex = Mutex::new(vec![1i32]); @@ -67,5 +90,5 @@ LL - lock.clear(); LL + | -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From 89fde4abf2c689c0ad5a09cc423a0a7be475d6ee Mon Sep 17 00:00:00 2001 From: blyxyas Date: Sat, 18 Feb 2023 20:05:30 +0100 Subject: [PATCH 68/90] Add placeholders, remove name suggesting --- .../src/functions/impl_trait_in_params.rs | 34 +++---------------- tests/ui/impl_trait_in_params.stderr | 8 ++--- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index 1f00e357bfa46..2811a73f6c189 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,6 +1,6 @@ use clippy_utils::{diagnostics::span_lint_and_then, is_in_test_function}; -use rustc_hir::{intravisit::FnKind, Body, Generics, HirId}; +use rustc_hir::{intravisit::FnKind, Body, HirId}; use rustc_lint::LateContext; use rustc_span::Span; @@ -19,13 +19,12 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: param.span, "'`impl Trait` used as a function parameter'", |diag| { - let next_letter = next_valid_letter(generics); if let Some(gen_span) = generics.span_for_param_suggestion() { diag.span_suggestion_with_style( gen_span, "add a type paremeter", - format!(", {next_letter}: {}", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::MaybeIncorrect, + format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]), + rustc_errors::Applicability::HasPlaceholders, rustc_errors::SuggestionStyle::ShowAlways, ); } else { @@ -37,8 +36,8 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: ident.span.parent(), ), "add a type paremeter", - format!("<{next_letter}: {}>", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::MaybeIncorrect, + format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]), + rustc_errors::Applicability::HasPlaceholders, rustc_errors::SuggestionStyle::ShowAlways, ); } @@ -49,26 +48,3 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: } } } - -fn next_valid_letter(generics: &Generics<'_>) -> char { - let mut generics_names = Vec::new(); - - generics.params.iter().for_each(|param| { - generics_names.push(param.name.ident().as_str().to_owned()); - }); - - // If T exists, try with U, then with V, and so on... - let mut current_letter = 84u32; // ASCII code for "T" - while generics_names.contains(&String::from(char::from_u32(current_letter).unwrap())) { - current_letter += 1; - if current_letter == 91 { - // ASCII code for "Z" - current_letter = 65; - } else if current_letter == 83 { - // ASCII "S" - current_letter = 97; // "a" - }; - } - - char::from_u32(current_letter).unwrap() -} diff --git a/tests/ui/impl_trait_in_params.stderr b/tests/ui/impl_trait_in_params.stderr index c0bcdfd6d4256..acfcc21445ebc 100644 --- a/tests/ui/impl_trait_in_params.stderr +++ b/tests/ui/impl_trait_in_params.stderr @@ -7,8 +7,8 @@ LL | pub fn a(_: impl Trait) {} = note: `-D clippy::impl-trait-in-params` implied by `-D warnings` help: add a type paremeter | -LL | pub fn a(_: impl Trait) {} - | ++++++++++ +LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {} + | +++++++++++++++++++++++++++++++ error: '`impl Trait` used as a function parameter' --> $DIR/impl_trait_in_params.rs:9:29 @@ -18,8 +18,8 @@ LL | pub fn c(_: C, _: impl Trait) {} | help: add a type paremeter | -LL | pub fn c(_: C, _: impl Trait) {} - | ++++++++++ +LL | pub fn c(_: C, _: impl Trait) {} + | +++++++++++++++++++++++++++++++ error: aborting due to 2 previous errors From 09058388dec7b62680fd3d33df4b416d84975884 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 20 Feb 2023 09:47:05 +0000 Subject: [PATCH 69/90] Ignore lifetimes from differing contexts in `needless_lifetimes` --- clippy_lints/src/lifetimes.rs | 8 ++++++++ tests/ui/needless_lifetimes.fixed | 10 ++++++++++ tests/ui/needless_lifetimes.rs | 10 ++++++++++ 3 files changed, 28 insertions(+) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 43a1a65a43a9d..986ffcad883db 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -144,6 +144,10 @@ fn check_fn_inner<'tcx>( .filter(|param| matches!(param.kind, GenericParamKind::Type { .. })); for typ in types { + if !typ.span.eq_ctxt(span) { + return; + } + for pred in generics.bounds_for_param(typ.def_id) { if pred.origin == PredicateOrigin::WhereClause { // has_where_lifetimes checked that this predicate contains no lifetime. @@ -181,6 +185,10 @@ fn check_fn_inner<'tcx>( } if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) { + if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) { + return; + } + let lts = elidable_lts .iter() // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index d286ef4ba3788..f0f1f9298ac65 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -516,6 +516,16 @@ mod in_macro { // no lint on external macro macro_rules::needless_lifetime!(); + + macro_rules! expanded_lifetime { + ($l:lifetime) => { + fn f<$l>(arg: &$l str) -> &$l str { + arg + } + } + } + + expanded_lifetime!('a); } mod issue5787 { diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 409528b291db1..ddfd10430038e 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -516,6 +516,16 @@ mod in_macro { // no lint on external macro macro_rules::needless_lifetime!(); + + macro_rules! expanded_lifetime { + ($l:lifetime) => { + fn f<$l>(arg: &$l str) -> &$l str { + arg + } + } + } + + expanded_lifetime!('a); } mod issue5787 { From 92c403c9b01e213ad9b5a003d9c3c289abc653f1 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 19 Feb 2023 19:25:53 +0100 Subject: [PATCH 70/90] Box::default(): do not omit the type of the removed trait object Within a larger expression, when the type of `Box::new(T::default())` is `Box`, the concrete type `T` cannot be omitted in the proposed replacement `Box::::default()`. --- clippy_lints/src/box_default.rs | 3 ++- tests/ui/box_default.fixed | 18 ++++++++++++++++++ tests/ui/box_default.rs | 18 ++++++++++++++++++ tests/ui/box_default.stderr | 14 ++++++++++---- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 9d98a6bab7107..dfa949d1af2f4 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -117,7 +117,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { ) => { if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && let Some(sig) = expr_sig(cx, path) && - let Some(input) = sig.input(index) + let Some(input) = sig.input(index) && + !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait() { input.no_bound_vars().is_some() } else { diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed index 7e9f074fdcabd..59c0baf8718aa 100644 --- a/tests/ui/box_default.fixed +++ b/tests/ui/box_default.fixed @@ -33,6 +33,7 @@ fn main() { let _vec4: Box<_> = Box::>::default(); let _more = ret_ty_fn(); call_ty_fn(Box::default()); + issue_10381(); } fn ret_ty_fn() -> Box { @@ -65,3 +66,20 @@ fn issue_10089() { let _ = Box::::default(); }; } + +fn issue_10381() { + #[derive(Default)] + pub struct Foo {} + pub trait Bar {} + impl Bar for Foo {} + + fn maybe_get_bar(i: u32) -> Option> { + if i % 2 == 0 { + Some(Box::::default()) + } else { + None + } + } + + assert!(maybe_get_bar(2).is_some()); +} diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs index 5c8d0b8354ccc..f7d832193a3a1 100644 --- a/tests/ui/box_default.rs +++ b/tests/ui/box_default.rs @@ -33,6 +33,7 @@ fn main() { let _vec4: Box<_> = Box::new(Vec::from([false; 0])); let _more = ret_ty_fn(); call_ty_fn(Box::new(u8::default())); + issue_10381(); } fn ret_ty_fn() -> Box { @@ -65,3 +66,20 @@ fn issue_10089() { let _ = Box::new(WeirdPathed::default()); }; } + +fn issue_10381() { + #[derive(Default)] + pub struct Foo {} + pub trait Bar {} + impl Bar for Foo {} + + fn maybe_get_bar(i: u32) -> Option> { + if i % 2 == 0 { + Some(Box::new(Foo::default())) + } else { + None + } + } + + assert!(maybe_get_bar(2).is_some()); +} diff --git a/tests/ui/box_default.stderr b/tests/ui/box_default.stderr index 249eb340f96cb..78e17b9f0359c 100644 --- a/tests/ui/box_default.stderr +++ b/tests/ui/box_default.stderr @@ -73,22 +73,28 @@ LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:39:5 + --> $DIR/box_default.rs:40:5 | LL | Box::new(bool::default()) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:56:28 + --> $DIR/box_default.rs:57:28 | LL | let _: Box = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:65:17 + --> $DIR/box_default.rs:66:17 | LL | let _ = Box::new(WeirdPathed::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` -error: aborting due to 15 previous errors +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:78:18 + | +LL | Some(Box::new(Foo::default())) + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` + +error: aborting due to 16 previous errors From 790f28b1533cbc1aec7ee343b98ea5d570f9928e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 20 Feb 2023 09:34:49 -0500 Subject: [PATCH 71/90] Update documentation --- book/src/lint_configuration.md | 3 ++- clippy_lints/src/missing_doc.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 46bed62dfc93a..f74431bee82d7 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -542,7 +542,8 @@ if no suggestion can be made. ### missing-docs-in-crate-items -Whether to **only** check for missing documentation in `pub(crate)` items. +Whether to **only** check for missing documentation in items visible within the current +crate. For example, `pub(crate)` items. **Default Value:** `false` (`bool`) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 74592918bfc75..9659ca8ced2ef 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -36,7 +36,8 @@ declare_clippy_lint! { } pub struct MissingDoc { - /// Whether to only check for missing docs in `pub(crate)` items. + /// Whether to **only** check for missing documentation in items visible within the current + /// crate. For example, `pub(crate)` items. crate_items_only: bool, /// Stack of whether #[doc(hidden)] is set /// at each level which has lint attributes. From 71b8646854d00ce03320038f98aa6442f1ca2c1e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 23 Nov 2022 11:55:16 +1100 Subject: [PATCH 72/90] Use `ThinVec` in various AST types. This commit changes the sequence parsers to produce `ThinVec`, which triggers numerous conversions. --- clippy_lints/src/lib.rs | 1 + clippy_lints/src/unnested_or_patterns.rs | 50 ++++++++++++++++-------- clippy_utils/src/ast_utils.rs | 3 +- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 565c5b7af0068..9011f0896a057 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -42,6 +42,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; extern crate rustc_trait_selection; +extern crate thin_vec; #[macro_use] extern crate clippy_utils; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 7355260ae4af3..06d248204c1f4 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -12,9 +12,9 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::DUMMY_SP; - use std::cell::Cell; use std::mem; +use thin_vec::{thin_vec, ThinVec}; declare_clippy_lint! { /// ### What it does @@ -214,7 +214,7 @@ macro_rules! always_pat { /// Focus on `focus_idx` in `alternatives`, /// attempting to extend it with elements of the same constructor `C` /// in `alternatives[focus_idx + 1..]`. -fn transform_with_focus_on_idx(alternatives: &mut Vec>, focus_idx: usize) -> bool { +fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: usize) -> bool { // Extract the kind; we'll need to make some changes in it. let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, PatKind::Wild); // We'll focus on `alternatives[focus_idx]`, @@ -296,7 +296,7 @@ fn extend_with_struct_pat( fps1: &mut [ast::PatField], rest1: bool, start: usize, - alternatives: &mut Vec>, + alternatives: &mut ThinVec>, ) -> bool { (0..fps1.len()).any(|idx| { let pos_in_2 = Cell::new(None); // The element `k`. @@ -336,9 +336,9 @@ fn extend_with_struct_pat( fn extend_with_matching_product( targets: &mut [P], start: usize, - alternatives: &mut Vec>, + alternatives: &mut ThinVec>, predicate: impl Fn(&PatKind, &[P], usize) -> bool, - extract: impl Fn(PatKind) -> Vec>, + extract: impl Fn(PatKind) -> ThinVec>, ) -> bool { (0..targets.len()).any(|idx| { let tail_or = drain_matching( @@ -365,14 +365,14 @@ fn take_pat(from: &mut Pat) -> Pat { /// Extend `target` as an or-pattern with the alternatives /// in `tail_or` if there are any and return if there were. -fn extend_with_tail_or(target: &mut Pat, tail_or: Vec>) -> bool { - fn extend(target: &mut Pat, mut tail_or: Vec>) { +fn extend_with_tail_or(target: &mut Pat, tail_or: ThinVec>) -> bool { + fn extend(target: &mut Pat, mut tail_or: ThinVec>) { match target { // On an existing or-pattern in the target, append to it. Pat { kind: Or(ps), .. } => ps.append(&mut tail_or), // Otherwise convert the target to an or-pattern. target => { - let mut init_or = vec![P(take_pat(target))]; + let mut init_or = thin_vec![P(take_pat(target))]; init_or.append(&mut tail_or); target.kind = Or(init_or); }, @@ -391,26 +391,42 @@ fn extend_with_tail_or(target: &mut Pat, tail_or: Vec>) -> bool { // Only elements beginning with `start` are considered for extraction. fn drain_matching( start: usize, - alternatives: &mut Vec>, + alternatives: &mut ThinVec>, predicate: impl Fn(&PatKind) -> bool, extract: impl Fn(PatKind) -> P, -) -> Vec> { - let mut tail_or = vec![]; +) -> ThinVec> { + let mut tail_or = ThinVec::new(); let mut idx = 0; - for pat in alternatives.drain_filter(|p| { - // Check if we should extract, but only if `idx >= start`. + + // If `ThinVec` had the `drain_filter` method, this loop could be rewritten + // like so: + // + // for pat in alternatives.drain_filter(|p| { + // // Check if we should extract, but only if `idx >= start`. + // idx += 1; + // idx > start && predicate(&p.kind) + // }) { + // tail_or.push(extract(pat.into_inner().kind)); + // } + let mut i = 0; + while i < alternatives.len() { idx += 1; - idx > start && predicate(&p.kind) - }) { - tail_or.push(extract(pat.into_inner().kind)); + // Check if we should extract, but only if `idx >= start`. + if idx > start && predicate(&alternatives[i].kind) { + let pat = alternatives.remove(i); + tail_or.push(extract(pat.into_inner().kind)); + } else { + i += 1; + } } + tail_or } fn extend_with_matching( target: &mut Pat, start: usize, - alternatives: &mut Vec>, + alternatives: &mut ThinVec>, predicate: impl Fn(&PatKind) -> bool, extract: impl Fn(PatKind) -> P, ) -> bool { diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 9d0263e93be75..d82098523e3be 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -144,7 +144,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (_, Paren(r)) => eq_expr(l, r), (Err, Err) => true, (Box(l), Box(r)) | (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r), - (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), + (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), + (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value), (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)), ( From 0aad34e43fc3c16d880790f521a2aabce0a62121 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 21 Feb 2023 15:47:24 -0500 Subject: [PATCH 73/90] Normalize projections types when checking `explicit_auto_deref` --- clippy_lints/src/dereference.rs | 78 +++++++++++++++++++++--------- clippy_utils/src/ty.rs | 25 +++++++--- tests/ui/explicit_auto_deref.fixed | 14 ++++++ tests/ui/explicit_auto_deref.rs | 14 ++++++ 4 files changed, 102 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 6c333afacc648..b2ed81219942b 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -3,7 +3,7 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res}; +use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig}; use clippy_utils::{ fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage, }; @@ -26,8 +26,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{ - self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, - ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, + self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy, + PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, }; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span, Symbol}; @@ -736,7 +736,7 @@ fn walk_parents<'tcx>( .. }) if span.ctxt() == ctxt => { let ty = cx.tcx.type_of(owner_id.def_id); - Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx)) + Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx)) }, Node::Item(&Item { @@ -760,7 +760,7 @@ fn walk_parents<'tcx>( let output = cx .tcx .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output()); - Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)) + Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)) }, Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) { @@ -768,10 +768,23 @@ fn walk_parents<'tcx>( hir_id, kind: ExprKind::Struct(path, ..), .. - }) => variant_of_res(cx, cx.qpath_res(path, *hir_id)) - .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name)) - .map(|field_def| { - ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did), precedence).position_for_arg() + }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id)) + .and_then(|(adt, variant)| { + variant + .fields + .iter() + .find(|f| f.name == field.ident.name) + .map(|f| (adt, f)) + }) + .map(|(adt, field_def)| { + ty_auto_deref_stability( + cx.tcx, + // Use the param_env of the target type. + cx.tcx.param_env(adt.did()), + cx.tcx.type_of(field_def.did), + precedence, + ) + .position_for_arg() }), _ => None, }, @@ -792,7 +805,7 @@ fn walk_parents<'tcx>( let output = cx .tcx .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output()); - ty_auto_deref_stability(cx, output, precedence).position_for_result(cx) + ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx) }, ) }, @@ -835,15 +848,20 @@ fn walk_parents<'tcx>( msrv, ) } else { - ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) - .position_for_arg() + ty_auto_deref_stability( + cx.tcx, + // Use the param_env of the target function. + sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)), + cx.tcx.erase_late_bound_regions(ty), + precedence + ).position_for_arg() } }, } }) }), ExprKind::MethodCall(method, receiver, args, _) => { - let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); + let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); if receiver.hir_id == child_id { // Check for calls to trait methods where the trait is implemented on a reference. // Two cases need to be handled: @@ -852,13 +870,17 @@ fn walk_parents<'tcx>( // priority. if e.hir_id != child_id { return Some(Position::ReborrowStable(precedence)) - } else if let Some(trait_id) = cx.tcx.trait_of_item(id) + } else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id) && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() && let subs = cx .typeck_results() .node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default() - && let impl_ty = if cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[0].is_ref() { + && let impl_ty = if cx.tcx.fn_sig(fn_id) + .subst_identity() + .skip_binder() + .inputs()[0].is_ref() + { // Trait methods taking `&self` sub_ty } else { @@ -879,10 +901,13 @@ fn walk_parents<'tcx>( return Some(Position::MethodReceiver); } args.iter().position(|arg| arg.hir_id == child_id).map(|i| { - let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i + 1]; + let ty = cx.tcx.fn_sig(fn_id).subst_identity().input(i + 1); // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739 // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782 - if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() { + if e.hir_id == child_id + && method.args.is_none() + && let ty::Param(param_ty) = ty.skip_binder().kind() + { needless_borrow_impl_arg_position( cx, possible_borrowers, @@ -895,8 +920,10 @@ fn walk_parents<'tcx>( ) } else { ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().input(i + 1)), + cx.tcx, + // Use the param_env of the target function. + cx.tcx.param_env(fn_id), + cx.tcx.erase_late_bound_regions(ty), precedence, ) .position_for_arg() @@ -1378,11 +1405,18 @@ impl<'tcx> TyPosition<'tcx> { } // Checks whether a type is stable when switching to auto dereferencing, -fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> { +fn ty_auto_deref_stability<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ty: Ty<'tcx>, + precedence: i8, +) -> TyPosition<'tcx> { let ty::Ref(_, mut ty, _) = *ty.kind() else { return Position::Other(precedence).into(); }; + ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + loop { break match *ty.kind() { ty::Ref(_, ref_ty, _) => { @@ -1423,9 +1457,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc | ty::Closure(..) | ty::Never | ty::Tuple(_) - | ty::Alias(ty::Projection, _) => { - Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into() - }, + | ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(), }; } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index c48d27b05f045..99ebfa8febc46 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -894,16 +894,29 @@ impl AdtVariantInfo { } /// Gets the struct or enum variant from the given `Res` -pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> { +pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<(AdtDef<'tcx>, &'tcx VariantDef)> { match res { - Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()), - Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)), - Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()), + Res::Def(DefKind::Struct, id) => { + let adt = cx.tcx.adt_def(id); + Some((adt, adt.non_enum_variant())) + }, + Res::Def(DefKind::Variant, id) => { + let adt = cx.tcx.adt_def(cx.tcx.parent(id)); + Some((adt, adt.variant_with_id(id))) + }, + Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => { + let adt = cx.tcx.adt_def(cx.tcx.parent(id)); + Some((adt, adt.non_enum_variant())) + }, Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => { let var_id = cx.tcx.parent(id); - Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) + let adt = cx.tcx.adt_def(cx.tcx.parent(var_id)); + Some((adt, adt.variant_with_id(var_id))) + }, + Res::SelfCtor(id) => { + let adt = cx.tcx.type_of(id).ty_adt_def().unwrap(); + Some((adt, adt.non_enum_variant())) }, - Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()), _ => None, } } diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 475fae5e823b3..5d40c850424ff 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -269,6 +269,9 @@ fn main() { trait WithAssoc { type Assoc: ?Sized; + fn to_assoc(&self) -> &Self::Assoc { + panic!() + } } impl WithAssoc for String { type Assoc = str; @@ -281,4 +284,15 @@ fn main() { // Issue #9901 fn takes_ref(_: &i32) {} takes_ref(*Box::new(&0i32)); + + // Issue #10384 + impl<'a> WithAssoc for &'a u32 { + type Assoc = dyn core::fmt::Display; + fn to_assoc(&self) -> &Self::Assoc { + *self + } + } + fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc { + *x + } } diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index c1894258f4d84..79e03f4d76c17 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -269,6 +269,9 @@ fn main() { trait WithAssoc { type Assoc: ?Sized; + fn to_assoc(&self) -> &Self::Assoc { + panic!() + } } impl WithAssoc for String { type Assoc = str; @@ -281,4 +284,15 @@ fn main() { // Issue #9901 fn takes_ref(_: &i32) {} takes_ref(*Box::new(&0i32)); + + // Issue #10384 + impl<'a> WithAssoc for &'a u32 { + type Assoc = dyn core::fmt::Display; + fn to_assoc(&self) -> &Self::Assoc { + *self + } + } + fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc { + *x + } } From bf7c20962051098150967d2c0616723f4abafa26 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 21 Feb 2023 11:01:00 -0500 Subject: [PATCH 74/90] Update readme description of `restriction` lints to dissuade casual use. --- README.md | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 95f6d2cc45c83..3e7379ace7ea5 100644 --- a/README.md +++ b/README.md @@ -19,21 +19,35 @@ You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the | `clippy::complexity` | code that does something simple but in a complex way | **warn** | | `clippy::perf` | code that can be written to run faster | **warn** | | `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow | +| `clippy::restriction` | lints which prevent the use of language and library features[^restrict] | allow | | `clippy::nursery` | new lints that are still under development | allow | | `clippy::cargo` | lints for the cargo manifest | allow | More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas! -The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are -for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used -very selectively, if at all. +The `restriction` category should, *emphatically*, not be enabled as a whole. The contained +lints may lint against perfectly reasonable code, may not have an alternative suggestion, +and may contradict any other lints (including other categories). Lints should be considered +on a case-by-case basis before enabling. + +[^restrict]: Some use cases for `restriction` lints include: + - Strict coding styles (e.g. [`clippy::else_if_without_else`]). + - Additional restrictions on CI (e.g. [`clippy::todo`]). + - Preventing panicking in certain functions (e.g. [`clippy::unwrap_used`]). + - Running a lint only on a subset of code (e.g. `#[forbid(clippy::float_arithmetic)]` on a module). + +[`clippy::else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else +[`clippy::todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo +[`clippy::unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used + +--- Table of contents: -* [Usage instructions](#usage) -* [Configuration](#configuration) -* [Contributing](#contributing) -* [License](#license) +* [Usage instructions](#usage) +* [Configuration](#configuration) +* [Contributing](#contributing) +* [License](#license) ## Usage @@ -64,6 +78,7 @@ Once you have rustup and the latest stable release (at least Rust 1.29) installe ```terminal rustup component add clippy ``` + If it says that it can't find the `clippy` component, please run `rustup self update`. #### Step 3: Run Clippy @@ -143,16 +158,16 @@ line. (You can swap `clippy::all` with the specific lint category you are target You can add options to your code to `allow`/`warn`/`deny` Clippy lints: -* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`). +* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`). Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html). -* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`, +* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`, `#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive lints prone to false positives. -* only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.) +* only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.) -* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc. +* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc. Note: `allow` means to suppress the lint for your code. With `warn` the lint will only emit a warning, while with `deny` the lint will emit an error, when @@ -176,12 +191,14 @@ cargo clippy -- -W clippy::lint_name This also works with lint groups. For example, you can run Clippy with warnings for all lints enabled: + ```terminal cargo clippy -- -W clippy::pedantic ``` If you care only about a single lint, you can allow all others and then explicitly warn on the lint(s) you are interested in: + ```terminal cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... ``` From aa0e543ba0a2760112a3e6cfd69437f59100909a Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 13 Oct 2022 10:13:02 +0100 Subject: [PATCH 75/90] errors: generate typed identifiers in each crate Instead of loading the Fluent resources for every crate in `rustc_error_messages`, each crate generates typed identifiers for its own diagnostics and creates a static which are pulled together in the `rustc_driver` crate and provided to the diagnostic emitter. Signed-off-by: David Wood --- clippy_lints/src/doc.rs | 2 +- src/driver.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 0b31e20fc87c0..660dd8391a30a 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -705,7 +705,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); + rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES, false); let emitter = EmitterWriter::new( Box::new(io::sink()), None, diff --git a/src/driver.rs b/src/driver.rs index e45835efe7464..45209fb8519e9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -209,7 +209,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // Separate the output with an empty line eprintln!(); - let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); + let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES, false); let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( rustc_errors::ColorConfig::Auto, None, From ab69a2a57b54f1581d2b4e5f097b95f8078740fc Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 17 Oct 2022 14:11:26 +0100 Subject: [PATCH 76/90] various: translation resources from cg backend Extend `CodegenBackend` trait with a function returning the translation resources from the codegen backend, which can be added to the complete list of resources provided to the emitter. Signed-off-by: David Wood --- clippy_lints/src/doc.rs | 6 ++++-- src/driver.rs | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 660dd8391a30a..6fdb7de25ccc0 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -704,8 +704,10 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { let filename = FileName::anon_source_code(&code); let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES, false); + let fallback_bundle = rustc_errors::fallback_fluent_bundle( + rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), + false + ); let emitter = EmitterWriter::new( Box::new(io::sink()), None, diff --git a/src/driver.rs b/src/driver.rs index 45209fb8519e9..9ac849aecf1a7 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -209,7 +209,10 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // Separate the output with an empty line eprintln!(); - let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES, false); + let fallback_bundle = rustc_errors::fallback_fluent_bundle( + rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), + false + ); let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( rustc_errors::ColorConfig::Auto, None, From 72e773f6a8bca1a4aaec6866ed995eaa0fd05cb2 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Wed, 22 Feb 2023 21:30:42 +0800 Subject: [PATCH 77/90] Fix test function checker in [unwrap_used], [expect_used] --- clippy_lints/src/methods/expect_used.rs | 4 ++-- clippy_lints/src/methods/unwrap_used.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index cce8f797e98c6..9e370de0a0540 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_in_cfg_test; +use clippy_utils::{is_in_cfg_test, is_in_test_function}; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; @@ -27,7 +27,7 @@ pub(super) fn check( let method = if is_err { "expect_err" } else { "expect" }; - if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) { + if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { return; } diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 90983f249cd59..5e4c3daee6447 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_in_cfg_test, is_lint_allowed}; +use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; @@ -27,7 +27,7 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; - if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) { + if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) { return; } From b9c617a1b79eefb63916b64b2942138aa08d6e30 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Wed, 22 Feb 2023 21:36:16 +0800 Subject: [PATCH 78/90] correct comments --- clippy_lints/src/utils/conf.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index c3c73ac6e378e..5f74de5a28867 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -419,19 +419,19 @@ define_Conf! { (max_include_file_size: u64 = 1_000_000), /// Lint: EXPECT_USED. /// - /// Whether `expect` should be allowed within `#[cfg(test)]` + /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` (allow_expect_in_tests: bool = false), /// Lint: UNWRAP_USED. /// - /// Whether `unwrap` should be allowed in test cfg + /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` (allow_unwrap_in_tests: bool = false), /// Lint: DBG_MACRO. /// - /// Whether `dbg!` should be allowed in test functions + /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` (allow_dbg_in_tests: bool = false), /// Lint: PRINT_STDOUT, PRINT_STDERR. /// - /// Whether print macros (ex. `println!`) should be allowed in test functions + /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` (allow_print_in_tests: bool = false), /// Lint: RESULT_LARGE_ERR. /// From 1a474d9179d301ae5c8ec8c13ba674e0702d8856 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Wed, 22 Feb 2023 21:36:30 +0800 Subject: [PATCH 79/90] Recover tests --- tests/ui-toml/expect_used/expect_used.rs | 12 ++++++++++++ tests/ui-toml/unwrap_used/unwrap_used.rs | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/tests/ui-toml/expect_used/expect_used.rs b/tests/ui-toml/expect_used/expect_used.rs index bff97d97df77a..89f142a150d95 100644 --- a/tests/ui-toml/expect_used/expect_used.rs +++ b/tests/ui-toml/expect_used/expect_used.rs @@ -16,6 +16,18 @@ fn main() { expect_result(); } +#[test] +fn test_expect_option() { + let opt = Some(0); + let _ = opt.expect(""); +} + +#[test] +fn test_expect_result() { + let res: Result = Ok(0); + let _ = res.expect(""); +} + #[cfg(test)] mod issue9612 { // should not lint in `#[cfg(test)]` modules diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs index bc8e8c1f0703a..6525ea5bfc3fc 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -66,6 +66,12 @@ fn main() { } } +#[test] +fn test() { + let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); + let _ = boxed_slice.get(1).unwrap(); +} + #[cfg(test)] mod issue9612 { // should not lint in `#[cfg(test)]` modules From a5acb926c1c7042980b95a4fd75eaed278bb5d14 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Wed, 22 Feb 2023 21:44:56 +0800 Subject: [PATCH 80/90] fix fmt --- clippy_lints/src/methods/expect_used.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 9e370de0a0540..614610335a134 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{is_in_cfg_test, is_in_test_function}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; From 79a90248c3c852efac91829da46e3ec53695e6d3 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Wed, 22 Feb 2023 21:49:26 +0800 Subject: [PATCH 81/90] bless --- tests/ui-toml/unwrap_used/unwrap_used.stderr | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index 94b5ef663add9..8a32750e3c92d 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -188,10 +188,16 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:84:17 + --> $DIR/unwrap_used.rs:72:13 + | +LL | let _ = boxed_slice.get(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` + +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/unwrap_used.rs:90:17 | LL | let _ = Box::new([0]).get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]` -error: aborting due to 27 previous errors +error: aborting due to 28 previous errors From d254516be1aa62a33a4d336278d0e79b509bc1cf Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 21 Feb 2023 14:12:02 -0700 Subject: [PATCH 82/90] clippy: update clippy to use new `TyCtxt::def_descr` --- tests/ui/missing_doc_impl.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/missing_doc_impl.stderr b/tests/ui/missing_doc_impl.stderr index f22fa19dbcabc..b410f56e1671a 100644 --- a/tests/ui/missing_doc_impl.stderr +++ b/tests/ui/missing_doc_impl.stderr @@ -51,13 +51,13 @@ LL | | fn foo_with_impl(&self) {} LL | | } | |_^ -error: missing documentation for an associated function +error: missing documentation for a method --> $DIR/missing_doc_impl.rs:44:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ -error: missing documentation for an associated function +error: missing documentation for a method --> $DIR/missing_doc_impl.rs:45:5 | LL | fn foo_with_impl(&self) {} From 430c4ab7ff73f1fee286848754694de974fcf039 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Wed, 22 Feb 2023 02:18:40 +0000 Subject: [PATCH 83/90] Remove type-traversal trait aliases --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/transmute/transmute_ptr_to_ref.rs | 2 +- clippy_lints/src/transmute/useless_transmute.rs | 2 +- clippy_lints/src/types/redundant_allocation.rs | 2 +- clippy_lints/src/types/vec_box.rs | 2 +- clippy_lints/src/zero_sized_map_values.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/mir/possible_borrower.rs | 2 +- clippy_utils/src/ty.rs | 6 +++--- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index b4543aa2544f8..ef46e23123b92 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -27,7 +27,7 @@ use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{ self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, - ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, + ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults, }; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span, Symbol}; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index ddade65c515c6..b2071f4dcb1e2 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -11,7 +11,7 @@ use rustc_hir::{Closure, 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::{self, EarlyBinder, SubstsRef, Ty, TypeVisitable}; +use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TypeVisitableExt}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 3cc765108d7cc..5a533261cad8c 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -3,7 +3,7 @@ use clippy_utils::{def_path_def_ids, trait_ref_of_method}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 996ea6ed72316..da3b6fa9899df 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -18,7 +18,7 @@ use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::{self, TypeVisitable}; +use rustc_middle::ty::{self, TypeVisitableExt}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 54ac04df1c12a..6bdb9aa5a26d2 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -6,7 +6,7 @@ use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; /// Checks for `transmute_ptr_to_ref` lint. /// Returns `true` if it's triggered, otherwise returns `false`. diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 871c3fadbba71..56207fe767c57 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -4,7 +4,7 @@ use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; /// Checks for `useless_transmute` lint. /// Returns `true` if it's triggered, otherwise returns `false`. diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index f9b9a66b5fa46..f7adc9d35558b 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::LateContext; -use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::TypeVisitableExt; use rustc_span::symbol::sym; use super::{utils, REDUNDANT_ALLOCATION}; diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 7a3c7cd8a99fc..d3062f3d2e360 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -7,7 +7,7 @@ use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::TypeVisitableExt; use rustc_span::symbol::sym; use super::VEC_BOX; diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 6cf2a955fd5c6..93e4b023c5c79 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -5,7 +5,7 @@ use rustc_hir::{self as hir, HirId, ItemKind, Node}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_middle::ty::{Adt, Ty, TypeVisitable}; +use rustc_middle::ty::{Adt, Ty, TypeVisitableExt}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b2edd1bbfef43..f02f8ecb43d72 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -104,7 +104,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType::{ PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType, }; use rustc_middle::ty::{ - layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture, + layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UpvarCapture, }; use rustc_middle::ty::{FloatTy, IntTy, UintTy}; use rustc_span::hygiene::{ExpnKind, MacroKind}; diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index e9dc7351b58ef..920ce8e655be0 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_lint::LateContext; use rustc_middle::mir::{self, visit::Visitor as _, Mutability}; -use rustc_middle::ty::{self, visit::ir::TypeVisitor, TyCtxt}; +use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt}; use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor}; use std::borrow::Cow; use std::ops::ControlFlow; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 2ed301fcc2291..34b9bb5994efa 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -17,8 +17,8 @@ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, - PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, ir::TypeVisitor, UintTy, - VariantDef, VariantDiscr, + PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, + VariantDef, VariantDiscr, TypeVisitableExt, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::Ident; @@ -847,7 +847,7 @@ pub fn for_each_top_level_late_bound_region( ControlFlow::Continue(()) } } - fn visit_binder>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow { + fn visit_binder>>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow { self.index += 1; let res = t.super_visit_with(self); self.index -= 1; From 528bb639d4a72310b625b947874aad27b5ee5088 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Wed, 22 Feb 2023 10:36:39 -0500 Subject: [PATCH 84/90] Fix more false positives for `extra_unused_type_parameters` --- .../src/extra_unused_type_parameters.rs | 83 +++++++++++++------ clippy_lints/src/lib.rs | 6 +- tests/ui/extra_unused_type_parameters.rs | 34 ++++++-- tests/ui/extra_unused_type_parameters.stderr | 34 +++++--- tests/ui/new_without_default.rs | 7 +- tests/ui/new_without_default.stderr | 14 ++-- tests/ui/redundant_field_names.fixed | 2 +- tests/ui/redundant_field_names.rs | 2 +- 8 files changed, 122 insertions(+), 60 deletions(-) diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 040473c9ffc62..20565e1d232ee 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -4,14 +4,17 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; use rustc_hir::{ - BodyId, ExprKind, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, - WherePredicate, + BodyId, ExprKind, GenericBound, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, + PredicateOrigin, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{def_id::DefId, Span}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{ + def_id::{DefId, LocalDefId}, + Span, +}; declare_clippy_lint! { /// ### What it does @@ -38,7 +41,29 @@ declare_clippy_lint! { complexity, "unused type parameters in function definitions" } -declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]); + +pub struct ExtraUnusedTypeParameters { + avoid_breaking_exported_api: bool, +} + +impl ExtraUnusedTypeParameters { + pub fn new(avoid_breaking_exported_api: bool) -> Self { + Self { + avoid_breaking_exported_api, + } + } + + /// Don't lint external macros or functions with empty bodies. Also, don't lint public items if + /// the `avoid_breaking_exported_api` config option is set. + fn check_false_positive(&self, cx: &LateContext<'_>, span: Span, def_id: LocalDefId, body_id: BodyId) -> bool { + let body = cx.tcx.hir().body(body_id).value; + let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none()); + let is_exported = cx.effective_visibilities.is_exported(def_id); + in_external_macro(cx.sess(), span) || (self.avoid_breaking_exported_api && is_exported) || fn_empty + } +} + +impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]); /// A visitor struct that walks a given function and gathers generic type parameters, plus any /// trait bounds those parameters have. @@ -56,13 +81,10 @@ struct TypeWalker<'cx, 'tcx> { /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic /// parameters are present, this will be set to `false`. all_params_unused: bool, - /// Whether or not the function has an empty body, in which case any bounded type parameters - /// will not be linted. - fn_body_empty: bool, } impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { - fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>, body_id: BodyId) -> Self { + fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self { let mut all_params_unused = true; let ty_params = generics .params @@ -79,17 +101,18 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { }) .collect(); - let body = cx.tcx.hir().body(body_id).value; - let fn_body_empty = - matches!(&body.kind, ExprKind::Block(block, None) if block.stmts.is_empty() && block.expr.is_none()); - Self { cx, ty_params, bounds: FxHashMap::default(), generics, all_params_unused, - fn_body_empty, + } + } + + fn mark_param_used(&mut self, def_id: DefId) { + if self.ty_params.remove(&def_id).is_some() { + self.all_params_unused = false; } } @@ -128,14 +151,18 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { } } +/// Given a generic bound, if the bound is for a trait that's not a `LangItem`, return the +/// `LocalDefId` for that trait. +fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option { + bound.trait_ref()?.trait_def_id()?.as_local() +} + impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { if let Some((def_id, _)) = t.peel_refs().as_generic_param() { - if self.ty_params.remove(&def_id).is_some() { - self.all_params_unused = false; - } + self.mark_param_used(def_id); } else if let TyKind::OpaqueDef(id, _, _) = t.kind { // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're @@ -151,12 +178,16 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { if let WherePredicate::BoundPredicate(predicate) = predicate { // Collect spans for any bounds on type parameters. We only keep bounds that appear in // the list of generics (not in a where-clause). - // - // Also, if the function body is empty, we don't lint the corresponding type parameters - // (See https://github.com/rust-lang/rust-clippy/issues/10319). if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() { - if self.fn_body_empty { - self.ty_params.remove(&def_id); + // If the bound contains non-public traits, err on the safe side and don't lint the + // corresponding parameter. + if !predicate + .bounds + .iter() + .filter_map(bound_to_trait_def_id) + .all(|id| self.cx.effective_visibilities.is_exported(id)) + { + self.mark_param_used(def_id); } else if let PredicateOrigin::GenericParam = predicate.origin { self.bounds.insert(def_id, predicate.span); } @@ -176,9 +207,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Fn(_, generics, body_id) = item.kind - && !in_external_macro(cx.sess(), item.span) + && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id) { - let mut walker = TypeWalker::new(cx, generics, body_id); + let mut walker = TypeWalker::new(cx, generics); walk_item(&mut walker, item); walker.emit_lint(); } @@ -188,9 +219,9 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { // Only lint on inherent methods, not trait methods. if let ImplItemKind::Fn(.., body_id) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - && !in_external_macro(cx.sess(), item.span) + && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id) { - let mut walker = TypeWalker::new(cx, item.generics, body_id); + let mut walker = TypeWalker::new(cx, item.generics); walk_impl_item(&mut walker, item); walker.emit_lint(); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7336fa19b1261..b63cb4df48fe4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -916,7 +916,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef)); store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock)); - store.register_late_pass(|_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters)); + store.register_late_pass(move |_| { + Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new( + avoid_breaking_exported_api, + )) + }); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs index 2894fda2f4717..4801743427657 100644 --- a/tests/ui/extra_unused_type_parameters.rs +++ b/tests/ui/extra_unused_type_parameters.rs @@ -1,11 +1,17 @@ #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] -fn unused_ty(x: u8) {} +fn unused_ty(x: u8) { + unimplemented!() +} -fn unused_multi(x: u8) {} +fn unused_multi(x: u8) { + unimplemented!() +} -fn unused_with_lt<'a, T>(x: &'a u8) {} +fn unused_with_lt<'a, T>(x: &'a u8) { + unimplemented!() +} fn used_ty(x: T, y: u8) {} @@ -51,7 +57,9 @@ fn used_closure() -> impl Fn() { struct S; impl S { - fn unused_ty_impl(&self) {} + fn unused_ty_impl(&self) { + unimplemented!() + } } // Don't lint on trait methods @@ -71,7 +79,23 @@ where .filter_map(move |(i, a)| if i == index { None } else { Some(a) }) } -fn unused_opaque(dummy: impl Default) {} +fn unused_opaque(dummy: impl Default) { + unimplemented!() +} + +mod unexported_trait_bounds { + mod private { + pub trait Private {} + } + + fn priv_trait_bound() { + unimplemented!(); + } + + fn unused_with_priv_trait_bound() { + unimplemented!(); + } +} mod issue10319 { fn assert_send() {} diff --git a/tests/ui/extra_unused_type_parameters.stderr b/tests/ui/extra_unused_type_parameters.stderr index aea3ee310f7dd..86c88fc9bf006 100644 --- a/tests/ui/extra_unused_type_parameters.stderr +++ b/tests/ui/extra_unused_type_parameters.stderr @@ -1,30 +1,30 @@ error: type parameter goes unused in function definition --> $DIR/extra_unused_type_parameters.rs:4:13 | -LL | fn unused_ty(x: u8) {} +LL | fn unused_ty(x: u8) { | ^^^ | = help: consider removing the parameter = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:6:16 + --> $DIR/extra_unused_type_parameters.rs:8:16 | -LL | fn unused_multi(x: u8) {} +LL | fn unused_multi(x: u8) { | ^^^^^^ | = help: consider removing the parameters error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:8:23 + --> $DIR/extra_unused_type_parameters.rs:12:23 | -LL | fn unused_with_lt<'a, T>(x: &'a u8) {} +LL | fn unused_with_lt<'a, T>(x: &'a u8) { | ^ | = help: consider removing the parameter error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:18:19 + --> $DIR/extra_unused_type_parameters.rs:24:19 | LL | fn unused_bounded(x: U) { | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | fn unused_bounded(x: U) { = help: consider removing the parameter error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:22:24 + --> $DIR/extra_unused_type_parameters.rs:28:24 | LL | fn unused_where_clause(x: U) | ^^ @@ -40,7 +40,7 @@ LL | fn unused_where_clause(x: U) = help: consider removing the parameter error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:29:16 + --> $DIR/extra_unused_type_parameters.rs:35:16 | LL | fn some_unused, E>(b: B, c: C) { | ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ @@ -48,20 +48,28 @@ LL | fn some_unused, E>(b: B, c: C) { = help: consider removing the parameters error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:54:22 + --> $DIR/extra_unused_type_parameters.rs:60:22 | -LL | fn unused_ty_impl(&self) {} +LL | fn unused_ty_impl(&self) { | ^^^ | = help: consider removing the parameter error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:74:17 + --> $DIR/extra_unused_type_parameters.rs:82:17 | -LL | fn unused_opaque(dummy: impl Default) {} +LL | fn unused_opaque(dummy: impl Default) { | ^^^^^^ | = help: consider removing the parameters -error: aborting due to 8 previous errors +error: type parameter goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:95:58 + | +LL | fn unused_with_priv_trait_bound() { + | ^ + | + = help: consider removing the parameter + +error: aborting due to 9 previous errors diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index 7803418cb047d..65809023f8dff 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -1,9 +1,4 @@ -#![allow( - dead_code, - clippy::missing_safety_doc, - clippy::extra_unused_lifetimes, - clippy::extra_unused_type_parameters -)] +#![allow(dead_code, clippy::missing_safety_doc, clippy::extra_unused_lifetimes)] #![warn(clippy::new_without_default)] pub struct Foo; diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 583dd327d6a5d..212a69ab94e65 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -1,5 +1,5 @@ error: you should consider adding a `Default` implementation for `Foo` - --> $DIR/new_without_default.rs:12:5 + --> $DIR/new_without_default.rs:7:5 | LL | / pub fn new() -> Foo { LL | | Foo @@ -17,7 +17,7 @@ LL + } | error: you should consider adding a `Default` implementation for `Bar` - --> $DIR/new_without_default.rs:20:5 + --> $DIR/new_without_default.rs:15:5 | LL | / pub fn new() -> Self { LL | | Bar @@ -34,7 +34,7 @@ LL + } | error: you should consider adding a `Default` implementation for `LtKo<'c>` - --> $DIR/new_without_default.rs:84:5 + --> $DIR/new_without_default.rs:79:5 | LL | / pub fn new() -> LtKo<'c> { LL | | unimplemented!() @@ -51,7 +51,7 @@ LL + } | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` - --> $DIR/new_without_default.rs:177: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:185: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:192: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:203:9 + --> $DIR/new_without_default.rs:198:9 | LL | / pub fn new() -> Self { LL | | todo!() diff --git a/tests/ui/redundant_field_names.fixed b/tests/ui/redundant_field_names.fixed index 276266a2dd803..ec7f8ae923a79 100644 --- a/tests/ui/redundant_field_names.fixed +++ b/tests/ui/redundant_field_names.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::redundant_field_names)] -#![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] +#![allow(clippy::no_effect, dead_code, unused_variables)] #[macro_use] extern crate derive_new; diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index f674141c138e1..73122016cf69e 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::redundant_field_names)] -#![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] +#![allow(clippy::no_effect, dead_code, unused_variables)] #[macro_use] extern crate derive_new; From 00c294ad0599968ce81bdb8763aefb88a2d2faa0 Mon Sep 17 00:00:00 2001 From: Krishna Sundarram Date: Sat, 18 Feb 2023 16:47:27 +0000 Subject: [PATCH 85/90] Add new lint no_mangle_with_rust_abi --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/no_mangle_with_rust_abi.rs | 65 +++++++++++++++++++++ tests/ui/must_use_candidates.fixed | 2 +- tests/ui/must_use_candidates.rs | 2 +- tests/ui/no_mangle_with_rust_abi.fixed | 48 +++++++++++++++ tests/ui/no_mangle_with_rust_abi.rs | 48 +++++++++++++++ tests/ui/no_mangle_with_rust_abi.stderr | 45 ++++++++++++++ 9 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/no_mangle_with_rust_abi.rs create mode 100644 tests/ui/no_mangle_with_rust_abi.fixed create mode 100644 tests/ui/no_mangle_with_rust_abi.rs create mode 100644 tests/ui/no_mangle_with_rust_abi.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ed61f9978039..765826ed867d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4622,6 +4622,7 @@ Released 2018-09-13 [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect [`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding +[`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index d05f22c231c60..cd5dd7a570653 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -450,6 +450,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::no_effect::NO_EFFECT_INFO, crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO, crate::no_effect::UNNECESSARY_OPERATION_INFO, + crate::no_mangle_with_rust_abi::NO_MANGLE_WITH_RUST_ABI_INFO, crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO, crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO, crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b63cb4df48fe4..8c33bae17b52c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -219,6 +219,7 @@ mod neg_cmp_op_on_partial_ord; mod neg_multiply; mod new_without_default; mod no_effect; +mod no_mangle_with_rust_abi; mod non_copy_const; mod non_expressive_names; mod non_octal_unix_permissions; @@ -921,6 +922,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: avoid_breaking_exported_api, )) }); + store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs new file mode 100644 index 0000000000000..bc64ccb295cb6 --- /dev/null +++ b/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -0,0 +1,65 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::{Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_target::spec::abi::Abi; + +declare_clippy_lint! { + /// ### What it does + /// Checks for Rust ABI functions with the `#[no_mangle]` attribute. + /// + /// ### Why is this bad? + /// The Rust ABI is not stable, but in many simple cases matches + /// enough with the C ABI that it is possible to forget to add + /// `extern "C"` to a function called from C. Changes to the + /// Rust ABI can break this at any point. + /// + /// ### Example + /// ```rust + /// #[no_mangle] + /// fn example(arg_one: u32, arg_two: usize) {} + /// ``` + /// + /// Use instead: + /// ```rust + /// #[no_mangle] + /// extern "C" fn example(arg_one: u32, arg_two: usize) {} + /// ``` + #[clippy::version = "1.69.0"] + pub NO_MANGLE_WITH_RUST_ABI, + pedantic, + "convert Rust ABI functions to C ABI" +} +declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]); + +impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Fn(fn_sig, _, _) = &item.kind { + let attrs = cx.tcx.hir().attrs(item.hir_id()); + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut applicability); + for attr in attrs { + if let Some(ident) = attr.ident() + && ident.name == rustc_span::sym::no_mangle + && fn_sig.header.abi == Abi::Rust + && !snippet.contains("extern") { + + let suggestion = snippet.split_once("fn") + .map_or(String::new(), |(first, second)| format!(r#"{first}extern "C" fn{second}"#)); + + span_lint_and_sugg( + cx, + NO_MANGLE_WITH_RUST_ABI, + fn_sig.span, + "attribute #[no_mangle] set on a Rust ABI function", + "try", + suggestion, + applicability + ); + } + } + } + } +} diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index 04a74a009e092..bbbb3cf621e41 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -84,7 +84,7 @@ pub unsafe fn mutates_static() -> usize { } #[no_mangle] -pub fn unmangled(i: bool) -> bool { +pub extern "C" fn unmangled(i: bool) -> bool { !i } diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index f04122f4eeab6..94d3c83bdb93a 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -84,7 +84,7 @@ pub unsafe fn mutates_static() -> usize { } #[no_mangle] -pub fn unmangled(i: bool) -> bool { +pub extern "C" fn unmangled(i: bool) -> bool { !i } diff --git a/tests/ui/no_mangle_with_rust_abi.fixed b/tests/ui/no_mangle_with_rust_abi.fixed new file mode 100644 index 0000000000000..d18dec22a8bbe --- /dev/null +++ b/tests/ui/no_mangle_with_rust_abi.fixed @@ -0,0 +1,48 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::no_mangle_with_rust_abi)] + +#[no_mangle] +extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + +#[no_mangle] +pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + +/// # Safety +/// This function shouldn't be called unless the horsemen are ready +#[no_mangle] +pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + +/// # Safety +/// This function shouldn't be called unless the horsemen are ready +#[no_mangle] +unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + +#[no_mangle] +extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( + arg_one: u32, + arg_two: usize, +) -> u32 { + 0 +} + +// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"` +#[no_mangle] +#[rustfmt::skip] +extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {} + +fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {} + +#[no_mangle] +extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {} + +extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {} + +extern "C" { + fn c_abi_in_block(arg_one: u32, arg_two: usize); +} + +fn main() { + // test code goes here +} diff --git a/tests/ui/no_mangle_with_rust_abi.rs b/tests/ui/no_mangle_with_rust_abi.rs new file mode 100644 index 0000000000000..481e1b6d96197 --- /dev/null +++ b/tests/ui/no_mangle_with_rust_abi.rs @@ -0,0 +1,48 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::no_mangle_with_rust_abi)] + +#[no_mangle] +fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + +#[no_mangle] +pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + +/// # Safety +/// This function shouldn't be called unless the horsemen are ready +#[no_mangle] +pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + +/// # Safety +/// This function shouldn't be called unless the horsemen are ready +#[no_mangle] +unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + +#[no_mangle] +fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( + arg_one: u32, + arg_two: usize, +) -> u32 { + 0 +} + +// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"` +#[no_mangle] +#[rustfmt::skip] +extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {} + +fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {} + +#[no_mangle] +extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {} + +extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {} + +extern "C" { + fn c_abi_in_block(arg_one: u32, arg_two: usize); +} + +fn main() { + // test code goes here +} diff --git a/tests/ui/no_mangle_with_rust_abi.stderr b/tests/ui/no_mangle_with_rust_abi.stderr new file mode 100644 index 0000000000000..71517d318095e --- /dev/null +++ b/tests/ui/no_mangle_with_rust_abi.stderr @@ -0,0 +1,45 @@ +error: attribute #[no_mangle] set on a Rust ABI function + --> $DIR/no_mangle_with_rust_abi.rs:7:1 + | +LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize)` + | + = note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings` + +error: attribute #[no_mangle] set on a Rust ABI function + --> $DIR/no_mangle_with_rust_abi.rs:10:1 + | +LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize)` + +error: attribute #[no_mangle] set on a Rust ABI function + --> $DIR/no_mangle_with_rust_abi.rs:15:1 + | +LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize)` + +error: attribute #[no_mangle] set on a Rust ABI function + --> $DIR/no_mangle_with_rust_abi.rs:20:1 + | +LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize)` + +error: attribute #[no_mangle] set on a Rust ABI function + --> $DIR/no_mangle_with_rust_abi.rs:23:1 + | +LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( +LL | | arg_one: u32, +LL | | arg_two: usize, +LL | | ) -> u32 { + | |________^ + | +help: try + | +LL + extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( +LL + arg_one: u32, +LL + arg_two: usize, +LL ~ ) -> u32 { + | + +error: aborting due to 5 previous errors + From 84ceca852eee1bcfcc987fc6d98e22e7395b4c69 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Fri, 24 Feb 2023 05:53:58 +0800 Subject: [PATCH 86/90] run cargo collect-metadata --- book/src/lint_configuration.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index f74431bee82d7..33f2b5c1de99c 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -472,7 +472,7 @@ The maximum size of a file included via `include_bytes!()` or `include_str!()`, ### allow-expect-in-tests -Whether `expect` should be allowed within `#[cfg(test)]` +Whether `expect` should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` (`bool`) @@ -480,7 +480,7 @@ Whether `expect` should be allowed within `#[cfg(test)]` ### allow-unwrap-in-tests -Whether `unwrap` should be allowed in test cfg +Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` (`bool`) @@ -488,7 +488,7 @@ Whether `unwrap` should be allowed in test cfg ### allow-dbg-in-tests -Whether `dbg!` should be allowed in test functions +Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` (`bool`) @@ -496,7 +496,7 @@ Whether `dbg!` should be allowed in test functions ### allow-print-in-tests -Whether print macros (ex. `println!`) should be allowed in test functions +Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` (`bool`) From 5552f4a6b505797d8692bd4b2b025509b474d95c Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 25 Feb 2023 17:44:05 -0500 Subject: [PATCH 87/90] Bump nightly version -> 2023-02-25 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index adea8c53df278..cfe845ec78f0a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-02-10" +channel = "nightly-2023-02-25" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From 64775f30c22e8e828a8dec13057e927d363701ac Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 25 Feb 2023 23:39:15 +0100 Subject: [PATCH 88/90] Do not panic when analyzing the malformed origin of a format string --- clippy_utils/src/macros.rs | 9 ++++++++- tests/ui/format.fixed | 6 ++++++ tests/ui/format.rs | 6 ++++++ tests/ui/format.stderr | 30 +++++++++++++++--------------- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 63dccbf697c2d..be6133d320241 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -391,11 +391,18 @@ impl FormatString { }; let mut unescaped = String::with_capacity(inner.len()); + // Sometimes the original string comes from a macro which accepts a malformed string, such as in a + // #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the + // string from the span will not be possible, so we will just return None here. + let mut unparsable = false; unescape_literal(inner, mode, &mut |_, ch| match ch { Ok(ch) => unescaped.push(ch), Err(e) if !e.is_fatal() => (), - Err(e) => panic!("{e:?}"), + Err(_) => unparsable = true, }); + if unparsable { + return None; + } let mut parts = Vec::new(); let _: Option = for_each_expr(pieces, |expr| { diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index beedf2c1db292..cd2f70ee8b029 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, @@ -9,6 +10,8 @@ clippy::uninlined_format_args )] +extern crate proc_macro_with_span; + struct Foo(pub String); macro_rules! foo { @@ -87,4 +90,7 @@ fn main() { let _ = abc.to_string(); let xx = "xx"; let _ = xx.to_string(); + + // Issue #10148 + println!(proc_macro_with_span::with_span!(""something "")); } diff --git a/tests/ui/format.rs b/tests/ui/format.rs index e805f18188989..c22345a79d432 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, @@ -9,6 +10,8 @@ clippy::uninlined_format_args )] +extern crate proc_macro_with_span; + struct Foo(pub String); macro_rules! foo { @@ -89,4 +92,7 @@ fn main() { let _ = format!("{abc}"); let xx = "xx"; let _ = format!("{xx}"); + + // Issue #10148 + println!(proc_macro_with_span::with_span!(""something "")); } diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 0ef0ac655d394..a0e5d5c8ad21f 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -1,5 +1,5 @@ error: useless use of `format!` - --> $DIR/format.rs:19:5 + --> $DIR/format.rs:22:5 | LL | format!("foo"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` @@ -7,19 +7,19 @@ LL | format!("foo"); = note: `-D clippy::useless-format` implied by `-D warnings` error: useless use of `format!` - --> $DIR/format.rs:20:5 + --> $DIR/format.rs:23:5 | LL | format!("{{}}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()` error: useless use of `format!` - --> $DIR/format.rs:21:5 + --> $DIR/format.rs:24:5 | LL | format!("{{}} abc {{}}"); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()` error: useless use of `format!` - --> $DIR/format.rs:22:5 + --> $DIR/format.rs:25:5 | LL | / format!( LL | | r##"foo {{}} @@ -34,67 +34,67 @@ LL ~ " bar"##.to_string(); | error: useless use of `format!` - --> $DIR/format.rs:27:13 + --> $DIR/format.rs:30:13 | LL | let _ = format!(""); | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()` error: useless use of `format!` - --> $DIR/format.rs:29:5 + --> $DIR/format.rs:32:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:37:5 + --> $DIR/format.rs:40:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:67:5 + --> $DIR/format.rs:70:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> $DIR/format.rs:69:5 + --> $DIR/format.rs:72:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> $DIR/format.rs:73:18 + --> $DIR/format.rs:76:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> $DIR/format.rs:77:22 + --> $DIR/format.rs:80:22 | LL | let _s: String = format!("{}", &*v.join("/n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()` error: useless use of `format!` - --> $DIR/format.rs:83:13 + --> $DIR/format.rs:86:13 | LL | let _ = format!("{x}"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:85:13 + --> $DIR/format.rs:88:13 | LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:89:13 + --> $DIR/format.rs:92:13 | LL | let _ = format!("{abc}"); | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` error: useless use of `format!` - --> $DIR/format.rs:91:13 + --> $DIR/format.rs:94:13 | LL | let _ = format!("{xx}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` From e825adf637db15bc264117825b3262f8f9ad27b7 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 25 Feb 2023 18:08:51 -0500 Subject: [PATCH 89/90] Fix normalization of `custom_ice_message` test. --- tests/ui-internal/custom_ice_message.rs | 3 ++- tests/ui-internal/custom_ice_message.stderr | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/ui-internal/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs index 4be04f77f5bdc..837811bdf1eff 100644 --- a/tests/ui-internal/custom_ice_message.rs +++ b/tests/ui-internal/custom_ice_message.rs @@ -1,8 +1,9 @@ // rustc-env:RUST_BACKTRACE=0 // normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo" -// normalize-stderr-test: "internal_lints.rs:\d*:\d*" -> "internal_lints.rs" +// normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" // normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" // normalize-stderr-test: "'rustc'" -> "''" +// normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index 2ba5890660fc9..7ed0ef0274fa3 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -1,4 +1,4 @@ -thread '' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs:28:9 +thread '' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: internal compiler error: unexpected panic @@ -9,5 +9,3 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo -query stack during panic: -end of query stack From 69c4ff6df8605f5f0b293fcf2a597f42510d2fd3 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 25 Feb 2023 18:09:24 -0500 Subject: [PATCH 90/90] Emit `unnecessary_def_path` in source order. --- .../internal_lints/unnecessary_def_path.rs | 4 ++-- .../unnecessary_def_path_hardcoded_path.stderr | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index ee5e42bae0f10..b59ef4086cd8b 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs}; use if_chain::if_chain; use rustc_ast::ast::LitKind; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -44,7 +44,7 @@ impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]); #[derive(Default)] pub struct UnnecessaryDefPath { - array_def_ids: FxHashSet<(DefId, Span)>, + array_def_ids: FxIndexSet<(DefId, Span)>, linted_def_ids: FxHashSet, } diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index c1a10ba55ef88..3ca45404e44bb 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -1,12 +1,3 @@ -error: hardcoded path to a diagnostic item - --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 - | -LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: convert all references to use `sym::deref_method` - = note: `-D clippy::unnecessary-def-path` implied by `-D warnings` - error: hardcoded path to a diagnostic item --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36 | @@ -14,6 +5,7 @@ LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: convert all references to use `sym::Deref` + = note: `-D clippy::unnecessary-def-path` implied by `-D warnings` error: hardcoded path to a language item --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40 @@ -23,5 +15,13 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"] | = help: convert all references to use `LangItem::DerefMut` +error: hardcoded path to a diagnostic item + --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 + | +LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: convert all references to use `sym::deref_method` + error: aborting due to 3 previous errors