]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #5980 - matsujika:create-dir, r=flip1995
authorbors <bors@rust-lang.org>
Thu, 10 Sep 2020 14:34:22 +0000 (14:34 +0000)
committerbors <bors@rust-lang.org>
Thu, 10 Sep 2020 14:34:22 +0000 (14:34 +0000)
Add a lint to prevent `create_dir` from being used

This closes #5950
changelog: none

103 files changed:
CHANGELOG.md
clippy_lints/src/async_yields_async.rs [new file with mode: 0644]
clippy_lints/src/atomic_ordering.rs
clippy_lints/src/attrs.rs
clippy_lints/src/await_holding_lock.rs
clippy_lints/src/bytecount.rs
clippy_lints/src/consts.rs
clippy_lints/src/default_trait_access.rs
clippy_lints/src/derive.rs
clippy_lints/src/doc.rs
clippy_lints/src/drop_forget_ref.rs
clippy_lints/src/enum_clike.rs
clippy_lints/src/eta_reduction.rs
clippy_lints/src/eval_order_dependence.rs
clippy_lints/src/float_equality_without_abs.rs
clippy_lints/src/float_literal.rs
clippy_lints/src/floating_point_arithmetic.rs
clippy_lints/src/format.rs
clippy_lints/src/functions.rs
clippy_lints/src/future_not_send.rs
clippy_lints/src/identity_op.rs
clippy_lints/src/indexing_slicing.rs
clippy_lints/src/large_const_arrays.rs
clippy_lints/src/large_stack_arrays.rs
clippy_lints/src/len_zero.rs
clippy_lints/src/lib.rs
clippy_lints/src/loops.rs
clippy_lints/src/map_clone.rs
clippy_lints/src/map_unit_fn.rs
clippy_lints/src/matches.rs
clippy_lints/src/methods/inefficient_to_string.rs
clippy_lints/src/methods/mod.rs
clippy_lints/src/misc.rs
clippy_lints/src/modulo_arithmetic.rs
clippy_lints/src/mut_key.rs
clippy_lints/src/mut_mut.rs
clippy_lints/src/mut_reference.rs
clippy_lints/src/mutable_debug_assertion.rs
clippy_lints/src/mutex_atomic.rs
clippy_lints/src/needless_borrow.rs
clippy_lints/src/needless_pass_by_value.rs
clippy_lints/src/needless_update.rs
clippy_lints/src/non_copy_const.rs
clippy_lints/src/pattern_type_mismatch.rs
clippy_lints/src/ptr.rs
clippy_lints/src/ranges.rs
clippy_lints/src/redundant_clone.rs
clippy_lints/src/shadow.rs
clippy_lints/src/swap.rs
clippy_lints/src/temporary_assignment.rs
clippy_lints/src/to_digit_is_some.rs
clippy_lints/src/transmute.rs
clippy_lints/src/trivially_copy_pass_by_ref.rs
clippy_lints/src/try_err.rs
clippy_lints/src/types.rs
clippy_lints/src/unit_return_expecting_ord.rs
clippy_lints/src/unnamed_address.rs
clippy_lints/src/unnecessary_sort_by.rs
clippy_lints/src/useless_conversion.rs
clippy_lints/src/utils/ast_utils.rs
clippy_lints/src/utils/conf.rs
clippy_lints/src/utils/mod.rs
clippy_lints/src/utils/sugg.rs
clippy_lints/src/vec.rs
src/lintlist/mod.rs
tests/ui-toml/functions_maxlines/test.stderr
tests/ui/async_yields_async.fixed [new file with mode: 0644]
tests/ui/async_yields_async.rs [new file with mode: 0644]
tests/ui/async_yields_async.stderr [new file with mode: 0644]
tests/ui/borrow_interior_mutable_const.rs
tests/ui/borrow_interior_mutable_const.stderr
tests/ui/collapsible_if.fixed
tests/ui/collapsible_if.rs
tests/ui/collapsible_if.stderr
tests/ui/default_trait_access.fixed [new file with mode: 0644]
tests/ui/default_trait_access.rs
tests/ui/default_trait_access.stderr
tests/ui/doc.rs
tests/ui/doc.stderr
tests/ui/functions_maxlines.stderr
tests/ui/issue-3145.rs
tests/ui/issue-3145.stderr
tests/ui/new_ret_no_self.rs
tests/ui/new_ret_no_self.stderr
tests/ui/option_map_unit_fn_fixable.stderr
tests/ui/or_fun_call.fixed
tests/ui/or_fun_call.rs
tests/ui/or_fun_call.stderr
tests/ui/result_map_unit_fn_fixable.stderr
tests/ui/result_map_unit_fn_unfixable.stderr
tests/ui/same_item_push.rs
tests/ui/same_item_push.stderr
tests/ui/temporary_assignment.rs
tests/ui/temporary_assignment.stderr
tests/ui/transmute_ptr_to_ptr.rs
tests/ui/unit_arg.rs
tests/ui/unit_arg.stderr
tests/ui/unit_arg_empty_blocks.stderr
tests/ui/unnecessary_sort_by.fixed
tests/ui/unnecessary_sort_by.rs
tests/ui/useless_attribute.fixed
tests/ui/useless_attribute.rs
tests/ui/useless_attribute.stderr

index b37273af44d2226c5bb01bbbc33fadf9d8c7b60e..64f9379b303cda15d6cd5919d4208718149b8348 100644 (file)
@@ -6,11 +6,113 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...master)
+[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master)
+
+## Rust 1.47
+
+Current beta, release 2020-10-08
+
+[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
+
+### New lints
+
+* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848)
+* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852)
+* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694)
+* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737)
+* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841)
+* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773)
+* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825)
+* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869)
+* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769)
+* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809)
+* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750)
+* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301)
+
+### Moves and Deprecations
+
+* Deprecate [`regex_macro`] lint
+  [#5760](https://github.com/rust-lang/rust-clippy/pull/5760)
+* Move [`range_minus_one`] to `pedantic`
+  [#5752](https://github.com/rust-lang/rust-clippy/pull/5752)
+
+### Enhancements
+
+* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls
+  [#5837](https://github.com/rust-lang/rust-clippy/pull/5837)
+* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting
+  [#5811](https://github.com/rust-lang/rust-clippy/pull/5811)
+* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`]
+  [#5443](https://github.com/rust-lang/rust-clippy/pull/5443)
+* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`]
+  [#5701](https://github.com/rust-lang/rust-clippy/pull/5701)
+* Make it possible to allow [`unsafe_derive_deserialize`]
+  [#5870](https://github.com/rust-lang/rust-clippy/pull/5870)
+* Catch `ord.min(a).max(b)` where a < b in [`min_max`]
+  [#5871](https://github.com/rust-lang/rust-clippy/pull/5871)
+* Make [`clone_on_copy`] suggestion machine applicable
+  [#5745](https://github.com/rust-lang/rust-clippy/pull/5745)
+* Enable [`len_zero`] on ranges now that `is_empty` is stable on them
+  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
+
+### False Positive Fixes
+
+* Avoid triggering [`or_fun_call`] with const fns that take no arguments
+  [#5889](https://github.com/rust-lang/rust-clippy/pull/5889)
+* Fix [`redundant_closure_call`] false positive for closures that have multiple calls
+  [#5800](https://github.com/rust-lang/rust-clippy/pull/5800)
+* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`]
+  [#5824](https://github.com/rust-lang/rust-clippy/pull/5824)
+* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`]
+  [#5771](https://github.com/rust-lang/rust-clippy/pull/5771)
+* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled
+  [#5758](https://github.com/rust-lang/rust-clippy/pull/5758)
+* Avoid linting if key borrows in [`unnecessary_sort_by`]
+  [#5756](https://github.com/rust-lang/rust-clippy/pull/5756)
+* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`]
+  [#5857](https://github.com/rust-lang/rust-clippy/pull/5857)
+* Take input lifetimes into account in `manual_async_fn`
+  [#5859](https://github.com/rust-lang/rust-clippy/pull/5859)
+* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option
+  [#5761](https://github.com/rust-lang/rust-clippy/pull/5761)
+* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation
+  [#5820](https://github.com/rust-lang/rust-clippy/pull/5820)
+
+### Suggestion Fixes/Improvements
+
+* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet
+  [#5788](https://github.com/rust-lang/rust-clippy/pull/5788)
+* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`]
+  [#5846](https://github.com/rust-lang/rust-clippy/pull/5846)
+* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`]
+  [#5793](https://github.com/rust-lang/rust-clippy/pull/5793)
+* Drop borrow operator in suggestions of [`redundant_pattern_matching`]
+  [#5815](https://github.com/rust-lang/rust-clippy/pull/5815)
+* Add suggestion for [`iter_skip_next`]
+  [#5843](https://github.com/rust-lang/rust-clippy/pull/5843)
+* Improve [`collapsible_if`] fix suggestion
+  [#5732](https://github.com/rust-lang/rust-clippy/pull/5732)
+
+### ICE Fixes
+
+* Fix ICE caused by [`needless_collect`]
+  [#5877](https://github.com/rust-lang/rust-clippy/pull/5877)
+* Fix ICE caused by [`unnested_or_patterns`]
+  [#5784](https://github.com/rust-lang/rust-clippy/pull/5784)
+
+### Documentation Improvements
+
+* Fix grammar of [`await_holding_lock`] documentation
+  [#5748](https://github.com/rust-lang/rust-clippy/pull/5748)
+
+### Others
+
+* Make lints adhere to the rustc dev guide
+  [#5888](https://github.com/rust-lang/rust-clippy/pull/5888)
 
 ## Rust 1.46
 
-Current beta, release 2020-08-27
+Current stable, released 2020-08-27
 
 [7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 
@@ -72,7 +174,7 @@ Current beta, release 2020-08-27
 
 ## Rust 1.45
 
-Current stable, released 2020-07-16
+Released 2020-07-16
 
 [891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
 
@@ -1410,6 +1512,7 @@ Released 2018-09-13
 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
 [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
 [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops
+[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async
 [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock
 [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
 [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs
new file mode 100644 (file)
index 0000000..88d9d3b
--- /dev/null
@@ -0,0 +1,86 @@
+use crate::utils::{implements_trait, snippet, span_lint_and_then};
+use rustc_errors::Applicability;
+use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for async blocks that yield values of types
+    /// that can themselves be awaited.
+    ///
+    /// **Why is this bad?** An await is likely missing.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// async fn foo() {}
+    ///
+    /// fn bar() {
+    ///   let x = async {
+    ///     foo()
+    ///   };
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// async fn foo() {}
+    ///
+    /// fn bar() {
+    ///   let x = async {
+    ///     foo().await
+    ///   };
+    /// }
+    /// ```
+    pub ASYNC_YIELDS_ASYNC,
+    correctness,
+    "async blocks that return a type that can be awaited"
+}
+
+declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
+
+impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
+    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+        use AsyncGeneratorKind::{Block, Closure};
+        // For functions, with explicitly defined types, don't warn.
+        // XXXkhuey maybe we should?
+        if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind {
+            if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
+                let body_id = BodyId {
+                    hir_id: body.value.hir_id,
+                };
+                let def_id = cx.tcx.hir().body_owner_def_id(body_id);
+                let typeck_results = cx.tcx.typeck(def_id);
+                let expr_ty = typeck_results.expr_ty(&body.value);
+
+                if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
+                    let return_expr_span = match &body.value.kind {
+                        // XXXkhuey there has to be a better way.
+                        ExprKind::Block(block, _) => block.expr.map(|e| e.span),
+                        ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span),
+                        _ => None,
+                    };
+                    if let Some(return_expr_span) = return_expr_span {
+                        span_lint_and_then(
+                            cx,
+                            ASYNC_YIELDS_ASYNC,
+                            return_expr_span,
+                            "an async construct yields a type which is itself awaitable",
+                            |db| {
+                                db.span_label(body.value.span, "outer async construct");
+                                db.span_label(return_expr_span, "awaitable value not awaited");
+                                db.span_suggestion(
+                                    return_expr_span,
+                                    "consider awaiting this value",
+                                    format!("{}.await", snippet(cx, return_expr_span, "..")),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            },
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
index 277fe350055ec357a81f6a4a0f0a95f03e74fca6..2d964ac2b9f64c7cae2f4a0bc511cfbb23ff5355 100644 (file)
@@ -53,7 +53,7 @@
 ];
 
 fn type_is_atomic(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.typeck_results().expr_ty(expr).kind {
+    if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.typeck_results().expr_ty(expr).kind() {
         ATOMIC_TYPES
             .iter()
             .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty]))
index cfcc1b3c5f356948df9bb333ccc292dd7a12e06e..c8f153e7201cb12988e0030f928446f7490bcda2 100644 (file)
@@ -71,8 +71,9 @@
     /// **What it does:** Checks for `extern crate` and `use` items annotated with
     /// lint attributes.
     ///
-    /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]` and
-    /// `#[allow(unreachable_pub)]` on `use` items and `#[allow(unused_imports)]` on
+    /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`,
+    /// `#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and
+    /// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on
     /// `extern crate` items with a `#[macro_use]` attribute.
     ///
     /// **Why is this bad?** Lint attributes have no effect on crate imports. Most
@@ -318,7 +319,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                         if let Some(ident) = attr.ident() {
                             match &*ident.as_str() {
                                 "allow" | "warn" | "deny" | "forbid" => {
-                                    // permit `unused_imports`, `deprecated` and `unreachable_pub` for `use` items
+                                    // permit `unused_imports`, `deprecated`, `unreachable_pub`,
+                                    // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items
                                     // and `unused_imports` for `extern crate` items with `macro_use`
                                     for lint in lint_list {
                                         match item.kind {
@@ -327,6 +329,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                                                     || is_word(lint, sym!(deprecated))
                                                     || is_word(lint, sym!(unreachable_pub))
                                                     || is_word(lint, sym!(unused))
+                                                    || extract_clippy_lint(lint)
+                                                        .map_or(false, |s| s == "wildcard_imports")
+                                                    || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use")
                                                 {
                                                     return;
                                                 }
@@ -387,24 +392,25 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
     }
 }
 
-fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
-    fn extract_name(lint: &NestedMetaItem) -> Option<SymbolStr> {
-        if_chain! {
-            if let Some(meta_item) = lint.meta_item();
-            if meta_item.path.segments.len() > 1;
-            if let tool_name = meta_item.path.segments[0].ident;
-            if tool_name.as_str() == "clippy";
-            let lint_name = meta_item.path.segments.last().unwrap().ident.name;
-            then {
-                return Some(lint_name.as_str());
-            }
+/// Returns the lint name if it is clippy lint.
+fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<SymbolStr> {
+    if_chain! {
+        if let Some(meta_item) = lint.meta_item();
+        if meta_item.path.segments.len() > 1;
+        if let tool_name = meta_item.path.segments[0].ident;
+        if tool_name.as_str() == "clippy";
+        let lint_name = meta_item.path.segments.last().unwrap().ident.name;
+        then {
+            return Some(lint_name.as_str());
         }
-        None
     }
+    None
+}
 
+fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
     let lint_store = cx.lints();
     for lint in items {
-        if let Some(lint_name) = extract_name(lint) {
+        if let Some(lint_name) = extract_clippy_lint(lint) {
             if let CheckLintNameResult::Tool(Err((None, _))) =
                 lint_store.check_lint_name(&lint_name, Some(sym!(clippy)))
             {
index b10b1e0a65ab94e0b3ea232fdad304ba689ab776..f18e7e5d99755d425d75ec2eab98574c409cb7a0 100644 (file)
@@ -67,7 +67,7 @@ fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
 
 fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
     for ty_cause in ty_causes {
-        if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind {
+        if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
             if is_mutex_guard(cx, adt.did) {
                 span_lint_and_note(
                     cx,
index cdb49d777d8dae2aeee008054b61dee8c293f092..189c07427ae99c82583ebab999557ebee40844f0 100644 (file)
@@ -63,7 +63,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                                 _ => { return; }
                             }
                         };
-                        if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind {
+                        if ty::Uint(UintTy::U8) != *walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind() {
                             return;
                         }
                         let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =
index c77b80bc23733e1b4495e07f78c1210eafd388c4..3ee022e4e68a0e5d20357b081eedcb5225b47525 100644 (file)
@@ -123,7 +123,7 @@ pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self)
             (&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
             (&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
             (&Self::Int(l), &Self::Int(r)) => {
-                if let ty::Int(int_ty) = cmp_type.kind {
+                if let ty::Int(int_ty) = *cmp_type.kind() {
                     Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
                 } else {
                     Some(l.cmp(&r))
@@ -162,7 +162,7 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
             FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
             FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
         },
-        LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind {
+        LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
             ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
             ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
             _ => bug!(),
@@ -230,7 +230,7 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
             ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
             ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
             ExprKind::Repeat(ref value, _) => {
-                let n = match self.typeck_results.expr_ty(e).kind {
+                let n = match self.typeck_results.expr_ty(e).kind() {
                     ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
                     _ => span_bug!(e.span, "typeck error"),
                 };
@@ -281,7 +281,7 @@ fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
             Bool(b) => Some(Bool(!b)),
             Int(value) => {
                 let value = !value;
-                match ty.kind {
+                match *ty.kind() {
                     ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
                     ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
                     _ => None,
@@ -295,7 +295,7 @@ fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
         use self::Constant::{Int, F32, F64};
         match *o {
             Int(value) => {
-                let ity = match ty.kind {
+                let ity = match *ty.kind() {
                     ty::Int(ity) => ity,
                     _ => return None,
                 };
@@ -402,7 +402,7 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
         let l = self.expr(left)?;
         let r = self.expr(right);
         match (l, r) {
-            (Constant::Int(l), Some(Constant::Int(r))) => match self.typeck_results.expr_ty_opt(left)?.kind {
+            (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
                 ty::Int(ity) => {
                     let l = sext(self.lcx.tcx, l, ity);
                     let r = sext(self.lcx.tcx, r, ity);
@@ -495,7 +495,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
     use rustc_middle::mir::interpret::{ConstValue, Scalar};
     match result.val {
         ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => {
-            match result.ty.kind {
+            match result.ty.kind() {
                 ty::Bool => Some(Constant::Bool(d == 1)),
                 ty::Uint(_) | ty::Int(_) => Some(Constant::Int(d)),
                 ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
@@ -505,7 +505,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
                     d.try_into().expect("invalid f64 bit representation"),
                 ))),
                 ty::RawPtr(type_and_mut) => {
-                    if let ty::Uint(_) = type_and_mut.ty.kind {
+                    if let ty::Uint(_) = type_and_mut.ty.kind() {
                         return Some(Constant::RawPtr(d));
                     }
                     None
@@ -514,8 +514,8 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
                 _ => None,
             }
         },
-        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind {
-            ty::Ref(_, tam, _) => match tam.kind {
+        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() {
+            ty::Ref(_, tam, _) => match tam.kind() {
                 ty::Str => String::from_utf8(
                     data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
                         .to_owned(),
@@ -526,8 +526,8 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
             },
             _ => None,
         },
-        ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind {
-            ty::Array(sub_type, len) => match sub_type.kind {
+        ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() {
+            ty::Array(sub_type, len) => match sub_type.kind() {
                 ty::Float(FloatTy::F32) => match miri_to_const(len) {
                     Some(Constant::Int(len)) => alloc
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
index 067ea903bdd96bf77f06820625449835d287f01d..3048436d9a7b5f30d066fc7374fd2db090d9e2db 100644 (file)
@@ -38,37 +38,23 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Path(ref qpath) = path.kind;
             if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+            // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
+            if let QPath::Resolved(None, _path) = qpath;
             then {
-                match qpath {
-                    QPath::Resolved(..) => {
-                        if_chain! {
-                            // Detect and ignore <Foo as Default>::default() because these calls do
-                            // explicitly name the type.
-                            if let ExprKind::Call(ref method, ref _args) = expr.kind;
-                            if let ExprKind::Path(ref p) = method.kind;
-                            if let QPath::Resolved(Some(_ty), _path) = p;
-                            then {
-                                return;
-                            }
-                        }
-
-                        // TODO: Work out a way to put "whatever the imported way of referencing
-                        // this type in this file" rather than a fully-qualified type.
-                        let expr_ty = cx.typeck_results().expr_ty(expr);
-                        if let ty::Adt(..) = expr_ty.kind {
-                            let replacement = format!("{}::default()", expr_ty);
-                            span_lint_and_sugg(
-                                cx,
-                                DEFAULT_TRAIT_ACCESS,
-                                expr.span,
-                                &format!("calling `{}` is more clear than this expression", replacement),
-                                "try",
-                                replacement,
-                                Applicability::Unspecified, // First resolve the TODO above
-                            );
-                         }
-                    },
-                    QPath::TypeRelative(..) | QPath::LangItem(..) => {},
+                let expr_ty = cx.typeck_results().expr_ty(expr);
+                if let ty::Adt(def, ..) = expr_ty.kind() {
+                    // TODO: Work out a way to put "whatever the imported way of referencing
+                    // this type in this file" rather than a fully-qualified type.
+                    let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
+                    span_lint_and_sugg(
+                        cx,
+                        DEFAULT_TRAIT_ACCESS,
+                        expr.span,
+                        &format!("calling `{}` is more clear than this expression", replacement),
+                        "try",
+                        replacement,
+                        Applicability::Unspecified, // First resolve the TODO above
+                    );
                 }
             }
         }
index 58b0704294b566622dd6028c290066e5dd605f7b..bf8e030cc294b25d57699644c8cec428906dcb0e 100644 (file)
@@ -299,20 +299,20 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T
             return;
         }
 
-        match ty.kind {
+        match *ty.kind() {
             ty::Adt(def, _) if def.is_union() => return,
 
             // Some types are not Clone by default but could be cloned “by hand” if necessary
             ty::Adt(def, substs) => {
                 for variant in &def.variants {
                     for field in &variant.fields {
-                        if let ty::FnDef(..) = field.ty(cx.tcx, substs).kind {
+                        if let ty::FnDef(..) = field.ty(cx.tcx, substs).kind() {
                             return;
                         }
                     }
                     for subst in substs {
                         if let ty::subst::GenericArgKind::Type(subst) = subst.unpack() {
-                            if let ty::Param(_) = subst.kind {
+                            if let ty::Param(_) = subst.kind() {
                                 return;
                             }
                         }
@@ -353,7 +353,7 @@ fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
 
     if_chain! {
         if match_path(&trait_ref.path, &paths::SERDE_DESERIALIZE);
-        if let ty::Adt(def, _) = ty.kind;
+        if let ty::Adt(def, _) = ty.kind();
         if let Some(local_def_id) = def.did.as_local();
         let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
         if !is_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
index 9555459e240e9f874ba29132cb32eb47fe531161..50121a054c79830676aac61494779ce2445b1e66 100644 (file)
@@ -239,9 +239,9 @@ fn lint_for_missing_headers<'tcx>(
                 let mir = cx.tcx.optimized_mir(def_id.to_def_id());
                 let ret_ty = mir.return_ty();
                 if implements_trait(cx, ret_ty, future, &[]);
-                if let ty::Opaque(_, subs) = ret_ty.kind;
+                if let ty::Opaque(_, subs) = ret_ty.kind();
                 if let Some(gen) = subs.types().next();
-                if let ty::Generator(_, subs, _) = gen.kind;
+                if let ty::Generator(_, subs, _) = gen.kind();
                 if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym!(result_type));
                 then {
                     span_lint(
index 57ff569f14b0f7bb18d54817b5a38742172254f2..cf528d189b4b14220833a1eac46f54c58e666c14 100644 (file)
@@ -121,7 +121,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 let arg = &args[0];
                 let arg_ty = cx.typeck_results().expr_ty(arg);
 
-                if let ty::Ref(..) = arg_ty.kind {
+                if let ty::Ref(..) = arg_ty.kind() {
                     if match_def_path(cx, def_id, &paths::DROP) {
                         lint = DROP_REF;
                         msg = DROP_REF_SUMMARY.to_string();
index 48caf48dbdb2cab0e80f0e2f4ee70e631c225a62..fb80f48a9ccf361bbb36bf55ce421bfde402a008 100644 (file)
@@ -53,12 +53,12 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                         .ok()
                         .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty));
                     if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) {
-                        if let ty::Adt(adt, _) = ty.kind {
+                        if let ty::Adt(adt, _) = ty.kind() {
                             if adt.is_enum() {
                                 ty = adt.repr.discr_type().to_ty(cx.tcx);
                             }
                         }
-                        match ty.kind {
+                        match ty.kind() {
                             ty::Int(IntTy::Isize) => {
                                 let val = ((val as i128) << 64) >> 64;
                                 if i32::try_from(val).is_ok() {
index 87254c1dbc490a9fac3706194fa35d9759f4d4cc..53df3abbf543744ef1300c6b80ddaef834a2afdb 100644 (file)
@@ -99,7 +99,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
             let fn_ty = cx.typeck_results().expr_ty(caller);
 
-            if matches!(fn_ty.kind, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));
+            if matches!(fn_ty.kind(), ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));
 
             if !type_is_unsafe_function(cx, fn_ty);
 
@@ -173,14 +173,14 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
 }
 
 fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
-    match (&lhs.kind, &rhs.kind) {
+    match (&lhs.kind(), &rhs.kind()) {
         (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2),
         (l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))),
     }
 }
 
 fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
-    match (&lhs.kind, &rhs.kind) {
+    match (&lhs.kind(), &rhs.kind()) {
         (ty::Bool, ty::Bool)
         | (ty::Char, ty::Char)
         | (ty::Int(_), ty::Int(_))
@@ -194,7 +194,7 @@ fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
 }
 
 fn get_type_name(cx: &LateContext<'_>, ty: Ty<'_>) -> String {
-    match ty.kind {
+    match ty.kind() {
         ty::Adt(t, _) => cx.tcx.def_path_str(t.did),
         ty::Ref(_, r, _) => get_type_name(cx, &r),
         _ => ty.to_string(),
index c00638ecc0c1d26619ef188f3b66da2f1e6a5bc4..4240147f498db43a2742f0eb69171043f1ccd970 100644 (file)
@@ -138,10 +138,10 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
             ExprKind::Call(ref func, _) => {
                 let typ = self.cx.typeck_results().expr_ty(func);
-                match typ.kind {
+                match typ.kind() {
                     ty::FnDef(..) | ty::FnPtr(_) => {
                         let sig = typ.fn_sig(self.cx.tcx);
-                        if let ty::Never = self.cx.tcx.erase_late_bound_regions(&sig).output().kind {
+                        if let ty::Never = self.cx.tcx.erase_late_bound_regions(&sig).output().kind() {
                             self.report_diverging_sub_expr(e);
                         }
                     },
index 9ac5a45eb4590c6b65c9e8f29ee74647ebc2a896..69818b4d3c642e1e5c29853c3713aee959473c2e 100644 (file)
@@ -81,8 +81,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             // values of the substractions on the left hand side are of the type float
             let t_val_l = cx.typeck_results().expr_ty(val_l);
             let t_val_r = cx.typeck_results().expr_ty(val_r);
-            if let ty::Float(_) = t_val_l.kind;
-            if let ty::Float(_) = t_val_r.kind;
+            if let ty::Float(_) = t_val_l.kind();
+            if let ty::Float(_) = t_val_r.kind();
 
             then {
                 let sug_l = sugg::Sugg::hir(cx, &val_l, "..");
index 358b9f6dcd0a5eb3cd66c092c3d238c1ee1376a9..1fe4461533b36840a3330ed09f72e8a46d3fdda3 100644 (file)
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
             let ty = cx.typeck_results().expr_ty(expr);
-            if let ty::Float(fty) = ty.kind;
+            if let ty::Float(fty) = *ty.kind();
             if let hir::ExprKind::Lit(ref lit) = expr.kind;
             if let LitKind::Float(sym, lit_float_ty) = lit.node;
             then {
index 1b02cee126d03b71af78ed69cba56e3cddbd9905..18fea8b34bfd46514e559bbf5437e292e0033f85 100644 (file)
@@ -136,7 +136,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
     if_chain! {
         // if the expression is a float literal and it is unsuffixed then
         // add a suffix so the suggestion is valid and unambiguous
-        if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind;
+        if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind();
         if let ExprKind::Lit(lit) = &expr.kind;
         if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
         then {
index 572c839502f4f20acc62d6a6182e918706421622..8bd85af87682a3027c0b5e7eb3efee27952aca8c 100644 (file)
@@ -91,7 +91,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &
         if pats.len() == 1;
         then {
             let ty = walk_ptrs_ty(cx.typeck_results().pat_ty(&pats[0]));
-            if ty.kind != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
+            if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
                 return None;
             }
             if let ExprKind::Lit(ref lit) = format_args.kind {
index ac1c7aa9bbbe998977c3484eef37d1d8893572c4..50b39cf4ea7c07109680bab252029431dc613017 100644 (file)
@@ -374,7 +374,12 @@ fn check_line_number(self, cx: &LateContext<'_>, span: Span, body: &'tcx hir::Bo
         }
 
         if line_count > self.max_lines {
-            span_lint(cx, TOO_MANY_LINES, span, "this function has a large number of lines")
+            span_lint(
+                cx,
+                TOO_MANY_LINES,
+                span,
+                &format!("this function has too many lines ({}/{})", line_count, self.max_lines),
+            )
         }
     }
 
@@ -505,7 +510,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut FxHashSet<
 static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]];
 
 fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut FxHashSet<DefId>) -> bool {
-    match ty.kind {
+    match *ty.kind() {
         // primitive types are never mutable
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
         ty::Adt(ref adt, ref substs) => {
index 0fdb5b8c2a48e9a6217c96f58dec7808be398e1b..2ab257ca88e3bdedc0794f4ea18ea1c617e0a8ef 100644 (file)
@@ -61,7 +61,7 @@ fn check_fn(
             return;
         }
         let ret_ty = utils::return_ty(cx, hir_id);
-        if let Opaque(id, subst) = ret_ty.kind {
+        if let Opaque(id, subst) = *ret_ty.kind() {
             let preds = cx.tcx.predicates_of(id).instantiate(cx.tcx, subst);
             let mut is_future = false;
             for p in preds.predicates {
index 4c62637858cde2b64cd942f9a45741772c9ee7fb..8501d34770201b1a80d77210dcb6999bbda9d7be 100644 (file)
@@ -75,7 +75,7 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_
 #[allow(clippy::cast_possible_wrap)]
 fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
     if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) {
-        let check = match cx.typeck_results().expr_ty(e).kind {
+        let check = match *cx.typeck_results().expr_ty(e).kind() {
             ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
             ty::Uint(uty) => clip(cx.tcx, !0, uty),
             _ => return,
index 90b1a529be79dc310e7cd3a35f1129a944e5168e..a28eda8be15a4ec8a129bb44a9aa172fb10cc247 100644 (file)
@@ -91,7 +91,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             let ty = cx.typeck_results().expr_ty(array);
             if let Some(range) = higher::range(index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
-                if let ty::Array(_, s) = ty.kind {
+                if let ty::Array(_, s) = ty.kind() {
                     let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
                         size.into()
                     } else {
@@ -141,7 +141,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic.", None, help_msg);
             } else {
                 // Catchall non-range index, i.e., [n] or [n << m]
-                if let ty::Array(..) = ty.kind {
+                if let ty::Array(..) = ty.kind() {
                     // Index is a constant uint.
                     if let Some(..) = constant(cx, cx.typeck_results(), index) {
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
index c6cc174a8c97b28b6203a684e729d7dfd599aa42..025ff86da39d8cc9fd6b117fce951e37f400ebcd 100644 (file)
@@ -51,7 +51,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if !item.span.from_expansion();
             if let ItemKind::Const(hir_ty, _) = &item.kind;
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
-            if let ty::Array(element_type, cst) = ty.kind;
+            if let ty::Array(element_type, cst) = ty.kind();
             if let ConstKind::Value(val) = cst.val;
             if let ConstValue::Scalar(element_count) = val;
             if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
index a7c715879232b980b078c1e00399e0cb2ec8017b..9fd3780e14e04023423491d9c94cac1994de5b3a 100644 (file)
@@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
             if let ExprKind::Repeat(_, _) = expr.kind;
-            if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind;
+            if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind();
             if let ConstKind::Value(val) = cst.val;
             if let ConstValue::Scalar(element_count) = val;
             if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
index b691d363d2f2165ca03be278f0706a82f018e0bb..42a98dc963d2084cfe93eca9ac759608bcbfd5d4 100644 (file)
@@ -286,7 +286,7 @@ fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
     }
 
     let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr));
-    match ty.kind {
+    match ty.kind() {
         ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| {
             cx.tcx
                 .associated_items(principal.def_id())
index 7943be34c6238a79d6bad25124f0975508887779..2020ef78509b0c24f80f01f4105da0652462ebf9 100644 (file)
@@ -154,6 +154,7 @@ macro_rules! declare_clippy_lint {
 mod as_conversions;
 mod assertions_on_constants;
 mod assign_ops;
+mod async_yields_async;
 mod atomic_ordering;
 mod attrs;
 mod await_holding_lock;
@@ -484,6 +485,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
         &assign_ops::ASSIGN_OP_PATTERN,
         &assign_ops::MISREFACTORED_ASSIGN_OP,
+        &async_yields_async::ASYNC_YIELDS_ASYNC,
         &atomic_ordering::INVALID_ATOMIC_ORDERING,
         &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
         &attrs::DEPRECATED_CFG_ATTR,
@@ -1102,6 +1104,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
     store.register_late_pass(|| box self_assignment::SelfAssignment);
     store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
+    store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1236,6 +1239,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
         LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
         LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
+        LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC),
         LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
         LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
         LintId::of(&attrs::DEPRECATED_CFG_ATTR),
@@ -1679,6 +1683,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
 
     store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
         LintId::of(&approx_const::APPROX_CONSTANT),
+        LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC),
         LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
         LintId::of(&attrs::DEPRECATED_SEMVER),
         LintId::of(&attrs::MISMATCHED_TARGET_OS),
index c95e43a9430446b2470aac5c782c10418b23ac57..6c54c07869ad1a6a2b7f1814fef1ed6ee20718d6 100644 (file)
@@ -826,7 +826,7 @@ struct FixedOffsetVar<'hir> {
 }
 
 fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool {
-    let is_slice = match ty.kind {
+    let is_slice = match ty.kind() {
         ty::Ref(_, subty, _) => is_slice_like(cx, subty),
         ty::Slice(..) | ty::Array(..) => true,
         _ => false,
@@ -1131,6 +1131,27 @@ fn detect_same_item_push<'tcx>(
     body: &'tcx Expr<'_>,
     _: &'tcx Expr<'_>,
 ) {
+    fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) {
+        let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
+        let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
+
+        span_lint_and_help(
+            cx,
+            SAME_ITEM_PUSH,
+            vec.span,
+            "it looks like the same item is being pushed into this Vec",
+            None,
+            &format!(
+                "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
+                item_str, vec_str, item_str
+            ),
+        )
+    }
+
+    if !matches!(pat.kind, PatKind::Wild) {
+        return;
+    }
+
     // Determine whether it is safe to lint the body
     let mut same_item_push_visitor = SameItemPushVisitor {
         should_lint: true,
@@ -1140,43 +1161,50 @@ fn detect_same_item_push<'tcx>(
     walk_expr(&mut same_item_push_visitor, body);
     if same_item_push_visitor.should_lint {
         if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push {
-            // Make sure that the push does not involve possibly mutating values
-            if let PatKind::Wild = pat.kind {
-                let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
-                let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
-                if let ExprKind::Path(ref qpath) = pushed_item.kind {
-                    if_chain! {
-                        if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id);
-                        let node = cx.tcx.hir().get(hir_id);
-                        if let Node::Binding(pat) = node;
-                        if let PatKind::Binding(bind_ann, ..) = pat.kind;
-                        if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
-                        then {
-                            span_lint_and_help(
-                                cx,
-                                SAME_ITEM_PUSH,
-                                vec.span,
-                                "it looks like the same item is being pushed into this Vec",
-                                None,
-                                &format!(
-                                    "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
-                                    item_str, vec_str, item_str
-                                ),
-                            )
+            let vec_ty = cx.typeck_results().expr_ty(vec);
+            let ty = vec_ty.walk().nth(1).unwrap().expect_ty();
+            if cx
+                .tcx
+                .lang_items()
+                .clone_trait()
+                .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+            {
+                // Make sure that the push does not involve possibly mutating values
+                match pushed_item.kind {
+                    ExprKind::Path(ref qpath) => {
+                        match qpath_res(cx, qpath, pushed_item.hir_id) {
+                            // immutable bindings that are initialized with literal or constant
+                            Res::Local(hir_id) => {
+                                if_chain! {
+                                    let node = cx.tcx.hir().get(hir_id);
+                                    if let Node::Binding(pat) = node;
+                                    if let PatKind::Binding(bind_ann, ..) = pat.kind;
+                                    if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
+                                    let parent_node = cx.tcx.hir().get_parent_node(hir_id);
+                                    if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
+                                    if let Some(init) = parent_let_expr.init;
+                                    then {
+                                        match init.kind {
+                                            // immutable bindings that are initialized with literal
+                                            ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
+                                            // immutable bindings that are initialized with constant
+                                            ExprKind::Path(ref path) => {
+                                                if let Res::Def(DefKind::Const, ..) = qpath_res(cx, path, init.hir_id) {
+                                                    emit_lint(cx, vec, pushed_item);
+                                                }
+                                            }
+                                            _ => {},
+                                        }
+                                    }
+                                }
+                            },
+                            // constant
+                            Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item),
+                            _ => {},
                         }
-                    }
-                } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
-                    span_lint_and_help(
-                        cx,
-                        SAME_ITEM_PUSH,
-                        vec.span,
-                        "it looks like the same item is being pushed into this Vec",
-                        None,
-                        &format!(
-                            "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
-                            item_str, vec_str, item_str
-                        ),
-                    )
+                    },
+                    ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
+                    _ => {},
                 }
             }
         }
@@ -1375,7 +1403,7 @@ fn is_end_eq_array_len<'tcx>(
     if_chain! {
         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 ty::Array(_, arr_len_const) = indexed_ty.kind();
         if let Some(arr_len) = arr_len_const.try_eval_usize(cx.tcx, cx.param_env);
         then {
             return match limits {
@@ -1612,7 +1640,7 @@ fn check_for_loop_over_map_kv<'tcx>(
     if let PatKind::Tuple(ref pat, _) = pat.kind {
         if pat.len() == 2 {
             let arg_span = arg.span;
-            let (new_pat_span, kind, ty, mutbl) = match cx.typeck_results().expr_ty(arg).kind {
+            let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() {
                 ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
                     (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl),
                     (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not),
@@ -1940,7 +1968,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 for expr in args {
                     let ty = self.cx.typeck_results().expr_ty_adjusted(expr);
                     self.prefer_mutable = false;
-                    if let ty::Ref(_, _, mutbl) = ty.kind {
+                    if let ty::Ref(_, _, mutbl) = *ty.kind() {
                         if mutbl == Mutability::Mut {
                             self.prefer_mutable = true;
                         }
@@ -1952,7 +1980,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
                 for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) {
                     self.prefer_mutable = false;
-                    if let ty::Ref(_, _, mutbl) = ty.kind {
+                    if let ty::Ref(_, _, mutbl) = *ty.kind() {
                         if mutbl == Mutability::Mut {
                             self.prefer_mutable = true;
                         }
@@ -2050,7 +2078,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 
 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 {
+    match ty.kind() {
         ty::Array(_, n) => n
             .try_eval_usize(cx.tcx, cx.param_env)
             .map_or(false, |val| (0..=32).contains(&val)),
index 1cd5b2012922f72ac65772a64de3af1f3d38c2e8..6d1c2ffbfbdd21a21ee450473b3ebfadffda323c 100644 (file)
@@ -70,7 +70,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
                         match closure_expr.kind {
                             hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => {
                                 if ident_eq(name, inner) {
-                                    if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind {
+                                    if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
                                         lint(cx, e.span, args[0].span, true);
                                     }
                                 }
@@ -80,7 +80,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
                                     && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
 
                                     let obj_ty = cx.typeck_results().expr_ty(&obj[0]);
-                                    if let ty::Ref(_, ty, _) = obj_ty.kind {
+                                    if let ty::Ref(_, ty, _) = obj_ty.kind() {
                                         let copy = is_copy(cx, ty);
                                         lint(cx, e.span, args[0].span, copy);
                                     } else {
index 198251c58ddc50dde677ebcc7397924f1981b26f..076ef235b8bd80cc7d0cbada94d2b2d217ad3a10 100644 (file)
@@ -9,7 +9,7 @@
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `option.map(f)` where f is a function
-    /// or closure that returns the unit type.
+    /// or closure that returns the unit type `()`.
     ///
     /// **Why is this bad?** Readability, this can be written more clearly with
     /// an if let statement
@@ -51,7 +51,7 @@
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `result.map(f)` where f is a function
-    /// or closure that returns the unit type.
+    /// or closure that returns the unit type `()`.
     ///
     /// **Why is this bad?** Readability, this can be written more clearly with
     /// an if let statement
@@ -93,7 +93,7 @@
 declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]);
 
 fn is_unit_type(ty: Ty<'_>) -> bool {
-    match ty.kind {
+    match ty.kind() {
         ty::Tuple(slice) => slice.is_empty(),
         ty::Never => true,
         _ => false,
@@ -103,7 +103,7 @@ fn is_unit_type(ty: Ty<'_>) -> bool {
 fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
 
-    if let ty::FnDef(id, _) = ty.kind {
+    if let ty::FnDef(id, _) = *ty.kind() {
         if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
             return is_unit_type(fn_type.output());
         }
@@ -197,7 +197,7 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String {
 #[must_use]
 fn suggestion_msg(function_type: &str, map_type: &str) -> String {
     format!(
-        "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type",
+        "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`",
         map_type, function_type
     )
 }
index be879dfe28d7038999be8b2be4f0314eb0457d02..7ba7397c29cb66797e5fdb8668e133c7825448b6 100644 (file)
@@ -573,7 +573,7 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
             if let QPath::Resolved(_, ref path) = qpath;
             if let Some(def_id) = path.res.opt_def_id();
             let ty = cx.tcx.type_of(def_id);
-            if let ty::Adt(def, _) = ty.kind;
+            if let ty::Adt(def, _) = ty.kind();
             if def.is_struct() || def.is_union();
             if fields.len() == def.non_enum_variant().fields.len();
 
@@ -621,7 +621,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
         };
 
         let ty = cx.typeck_results().expr_ty(ex);
-        if ty.kind != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) {
+        if *ty.kind() != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) {
             check_single_match_single_pattern(cx, ex, arms, expr, els);
             check_single_match_opt_like(cx, ex, arms, expr, ty, els);
         }
@@ -712,7 +712,7 @@ fn check_single_match_opt_like(
 
 fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     // Type of expression is `bool`.
-    if cx.typeck_results().expr_ty(ex).kind == ty::Bool {
+    if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
         span_lint_and_then(
             cx,
             MATCH_BOOL,
@@ -860,7 +860,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
         // already covered.
 
         let mut missing_variants = vec![];
-        if let ty::Adt(def, _) = ty.kind {
+        if let ty::Adt(def, _) = ty.kind() {
             for variant in &def.variants {
                 missing_variants.push(variant);
             }
@@ -914,7 +914,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
 
         let mut message = "wildcard match will miss any future added variants";
 
-        if let ty::Adt(def, _) = ty.kind {
+        if let ty::Adt(def, _) = ty.kind() {
             if def.is_variant_list_non_exhaustive() {
                 message = "match on non-exhaustive enum doesn't explicitly match all known variants";
                 suggestion.push(String::from("_"));
@@ -1014,11 +1014,11 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
             let input_ty = cx.typeck_results().expr_ty(ex);
 
             let cast = if_chain! {
-                if let ty::Adt(_, substs) = input_ty.kind;
+                if let ty::Adt(_, substs) = input_ty.kind();
                 let input_ty = substs.type_at(0);
-                if let ty::Adt(_, substs) = output_ty.kind;
+                if let ty::Adt(_, substs) = output_ty.kind();
                 let output_ty = substs.type_at(0);
-                if let ty::Ref(_, output_ty, _) = output_ty.kind;
+                if let ty::Ref(_, output_ty, _) = *output_ty.kind();
                 if input_ty != output_ty;
                 then {
                     ".map(|x| x as _)"
index e5f815772eba946fe32d5221d39c8620e83d553d..5dae7efad9763da38ff5e6ce4215715db489e2bc 100644 (file)
@@ -46,7 +46,7 @@ pub fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<
 /// Returns whether `ty` specializes `ToString`.
 /// Currently, these are `str`, `String`, and `Cow<'_, str>`.
 fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    if let ty::Str = ty.kind {
+    if let ty::Str = ty.kind() {
         return true;
     }
 
@@ -54,7 +54,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
         return true;
     }
 
-    if let ty::Adt(adt, substs) = ty.kind {
+    if let ty::Adt(adt, substs) = ty.kind() {
         match_def_path(cx, adt.did, &paths::COW) && substs.type_at(1).is_str()
     } else {
         false
index 1ef54d285f68a3c9219203f56e8698f07b608dba..ba69c8266b1182be338a48dfb85571a9acb83ba8 100644 (file)
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Ty, TyS};
+use rustc_middle::ty::{self, TraitRef, Ty, TyS};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{sym, SymbolStr};
 use crate::consts::{constant, Constant};
 use crate::utils::usage::mutated_variables;
 use crate::utils::{
-    get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy,
-    is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment,
-    match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths,
-    remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite,
-    span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty,
-    walk_ptrs_ty_depth, SpanlessEq,
+    contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
+    is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats,
+    last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls,
+    method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability,
+    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
+    span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
 };
 
 declare_clippy_lint! {
     /// **Known problems:** None.
     ///
     /// **Example:**
+    /// In an impl block:
     /// ```rust
     /// # struct Foo;
     /// # struct NotAFoo;
     ///
     /// ```rust
     /// # struct Foo;
-    /// # struct FooError;
+    /// struct Bar(Foo);
     /// impl Foo {
-    ///     // Good. Return type contains `Self`
-    ///     fn new() -> Result<Foo, FooError> {
-    ///         # Ok(Foo)
+    ///     // Bad. The type name must contain `Self`
+    ///     fn new() -> Bar {
+    /// # Bar(Foo)
     ///     }
     /// }
     /// ```
     ///
     /// ```rust
     /// # struct Foo;
-    /// struct Bar(Foo);
+    /// # struct FooError;
     /// impl Foo {
-    ///     // Bad. The type name must contain `Self`.
-    ///     fn new() -> Bar {
-    ///         # Bar(Foo)
+    ///     // Good. Return type contains `Self`
+    ///     fn new() -> Result<Foo, FooError> {
+    /// # Ok(Foo)
     ///     }
     /// }
     /// ```
+    ///
+    /// Or in a trait definition:
+    /// ```rust
+    /// pub trait Trait {
+    ///     // Bad. The type name must contain `Self`
+    ///     fn new();
+    /// }
+    /// ```
+    ///
+    /// ```rust
+    /// pub trait Trait {
+    ///     // Good. Return type contains `Self`
+    ///     fn new() -> Self;
+    /// }
+    /// ```
     pub NEW_RET_NO_SELF,
     style,
     "not returning type containing `Self` in a `new` method"
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Warns when using push_str with a single-character string literal,
-    /// and push with a char would work fine.
+    /// **What it does:** Warns when using `push_str` with a single-character string literal,
+    /// and `push` with a `char` would work fine.
     ///
-    /// **Why is this bad?** It's less clear that we are pushing a single character
+    /// **Why is this bad?** It's less clear that we are pushing a single character.
     ///
     /// **Known problems:** None
     ///
     /// **Example:**
-    /// ```
+    /// ```rust
     /// let mut string = String::new();
     /// string.push_str("R");
     /// ```
     /// Could be written as
-    /// ```
+    /// ```rust
     /// let mut string = String::new();
     /// string.push('R');
     /// ```
@@ -1518,8 +1534,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                     }
                 }
 
-                match self_ty.kind {
-                    ty::Ref(_, ty, _) if ty.kind == ty::Str => {
+                match self_ty.kind() {
+                    ty::Ref(_, ty, _) if *ty.kind() == ty::Str => {
                         for &(method, pos) in &PATTERN_METHODS {
                             if method_call.ident.name.as_str() == method && args.len() > pos {
                                 lint_single_char_pattern(cx, expr, &args[pos]);
@@ -1631,29 +1647,26 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
             }
         }
 
+        // if this impl block implements a trait, lint in trait definition instead
+        if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
+            return;
+        }
+
         if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
             let ret_ty = return_ty(cx, impl_item.hir_id);
 
-            let contains_self_ty = |ty: Ty<'tcx>| {
-                ty.walk().any(|inner| match inner.unpack() {
-                    GenericArgKind::Type(inner_ty) => TyS::same_type(self_ty, inner_ty),
-
-                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
-                })
-            };
-
             // walk the return type and check for Self (this does not check associated types)
-            if contains_self_ty(ret_ty) {
+            if contains_ty(ret_ty, self_ty) {
                 return;
             }
 
             // if return type is impl trait, check the associated types
-            if let ty::Opaque(def_id, _) = ret_ty.kind {
+            if let ty::Opaque(def_id, _) = *ret_ty.kind() {
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.predicates_of(def_id).predicates {
                     if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
                         // walk the associated type and check for Self
-                        if contains_self_ty(projection_predicate.ty) {
+                        if contains_ty(projection_predicate.ty, self_ty) {
                             return;
                         }
                     }
@@ -1670,6 +1683,26 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
             }
         }
     }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
+        if_chain! {
+            if !in_external_macro(cx.tcx.sess, item.span);
+            if item.ident.name == sym!(new);
+            if let TraitItemKind::Fn(_, _) = item.kind;
+            let ret_ty = return_ty(cx, item.hir_id);
+            let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty();
+            if !contains_ty(ret_ty, self_ty);
+
+            then {
+                span_lint(
+                    cx,
+                    NEW_RET_NO_SELF,
+                    item.span,
+                    "methods called `new` usually return `Self`",
+                );
+            }
+        }
+    }
 }
 
 /// Checks for the `OR_FUN_CALL` lint.
@@ -1770,7 +1803,7 @@ fn check_general_case<'tcx>(
             if path.ident.as_str() == "len" {
                 let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
 
-                match ty.kind {
+                match ty.kind() {
                     ty::Slice(_) | ty::Array(_, _) => return,
                     _ => (),
                 }
@@ -1877,7 +1910,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Ex
                         && {
                             let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
                             let base_type = walk_ptrs_ty(arg_type);
-                            base_type.kind == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
+                            *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
                         }
                     {
                         &call_args[0]
@@ -1898,8 +1931,8 @@ fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
         if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) {
             return false;
         }
-        if let ty::Ref(_, ty, ..) = arg_ty.kind {
-            if ty.kind == ty::Str && can_be_static_str(cx, arg) {
+        if let ty::Ref(_, ty, ..) = arg_ty.kind() {
+            if *ty.kind() == ty::Str && can_be_static_str(cx, arg) {
                 return false;
             }
         };
@@ -1915,7 +1948,7 @@ fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                 if let hir::ExprKind::Path(ref p) = fun.kind {
                     match cx.qpath_res(p, fun.hir_id) {
                         hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
-                            cx.tcx.fn_sig(def_id).output().skip_binder().kind,
+                            cx.tcx.fn_sig(def_id).output().skip_binder().kind(),
                             ty::Ref(ty::ReStatic, ..)
                         ),
                         _ => false,
@@ -1929,7 +1962,7 @@ fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                     .type_dependent_def_id(arg.hir_id)
                     .map_or(false, |method_id| {
                         matches!(
-                            cx.tcx.fn_sig(method_id).output().skip_binder().kind,
+                            cx.tcx.fn_sig(method_id).output().skip_binder().kind(),
                             ty::Ref(ty::ReStatic, ..)
                         )
                     })
@@ -2048,8 +2081,8 @@ fn is_call(node: &hir::ExprKind<'_>) -> bool {
 /// Checks for the `CLONE_ON_COPY` lint.
 fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
     let ty = cx.typeck_results().expr_ty(expr);
-    if let ty::Ref(_, inner, _) = arg_ty.kind {
-        if let ty::Ref(_, innermost, _) = inner.kind {
+    if let ty::Ref(_, inner, _) = arg_ty.kind() {
+        if let ty::Ref(_, innermost, _) = inner.kind() {
             span_lint_and_then(
                 cx,
                 CLONE_DOUBLE_REF,
@@ -2060,7 +2093,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
                     if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
                         let mut ty = innermost;
                         let mut n = 0;
-                        while let ty::Ref(_, inner, _) = ty.kind {
+                        while let ty::Ref(_, inner, _) = ty.kind() {
                             ty = inner;
                             n += 1;
                         }
@@ -2139,7 +2172,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
 fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg));
 
-    if let ty::Adt(_, subst) = obj_ty.kind {
+    if let ty::Adt(_, subst) = obj_ty.kind() {
         let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
             "Rc"
         } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) {
@@ -2169,7 +2202,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
         let target = &arglists[0][0];
         let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target));
-        let ref_str = if self_ty.kind == ty::Str {
+        let ref_str = if *self_ty.kind() == ty::Str {
             ""
         } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
             "&"
@@ -2205,7 +2238,7 @@ fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>
 fn lint_cstring_as_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, source: &hir::Expr<'_>, unwrap: &hir::Expr<'_>) {
     if_chain! {
         let source_type = cx.typeck_results().expr_ty(source);
-        if let ty::Adt(def, substs) = source_type.kind;
+        if let ty::Adt(def, substs) = source_type.kind();
         if cx.tcx.is_diagnostic_item(sym!(result_type), def.did);
         if match_type(cx, substs.type_at(0), &paths::CSTRING);
         then {
@@ -2379,7 +2412,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
         }
     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type))
         || matches!(
-            &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind,
+            &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind(),
             ty::Array(_, _)
         )
     {
@@ -2546,7 +2579,7 @@ fn derefs_to_slice<'tcx>(
     ty: Ty<'tcx>,
 ) -> Option<&'tcx hir::Expr<'tcx>> {
     fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
-        match ty.kind {
+        match ty.kind() {
             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_type)),
@@ -2565,7 +2598,7 @@ fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
             None
         }
     } else {
-        match ty.kind {
+        match ty.kind() {
             ty::Slice(_) => Some(expr),
             ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
             ty::Ref(_, inner, _) => {
@@ -2659,9 +2692,9 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
     // lint if caller of `.map().flatten()` is an Iterator
     if match_trait_method(cx, expr, &paths::ITERATOR) {
         let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]);
-        let is_map_to_option = match map_closure_ty.kind {
+        let is_map_to_option = match map_closure_ty.kind() {
             ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
-                let map_closure_sig = match map_closure_ty.kind {
+                let map_closure_sig = match map_closure_ty.kind() {
                     ty::Closure(_, substs) => substs.as_closure().sig(),
                     _ => map_closure_ty.fn_sig(cx.tcx),
                 };
@@ -3131,7 +3164,7 @@ fn lint_chars_cmp(
             let mut applicability = Applicability::MachineApplicable;
             let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0]));
 
-            if self_ty.kind != ty::Str {
+            if *self_ty.kind() != ty::Str {
                 return false;
             }
 
@@ -3319,7 +3352,7 @@ fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_re
 
 fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(&'static str, &'static str)> {
     has_iter_method(cx, self_ref_ty).map(|ty_name| {
-        let mutbl = match self_ref_ty.kind {
+        let mutbl = match self_ref_ty.kind() {
             ty::Ref(_, _, mutbl) => mutbl,
             _ => unreachable!(),
         };
@@ -3371,7 +3404,7 @@ fn lint_maybe_uninit(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Ex
 }
 
 fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    match ty.kind {
+    match ty.kind() {
         ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component),
         ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
         ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
@@ -3498,7 +3531,7 @@ fn lint_option_as_ref_deref<'tcx>(
 
 /// Given a `Result<T, E>` type, return its error type (`E`).
 fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
-    match ty.kind {
+    match ty.kind() {
         ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1),
         _ => None,
     }
@@ -3652,7 +3685,7 @@ fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'_>, ty: Ty<'_>) -> boo
             } else if ty.is_box() {
                 ty.boxed_ty() == parent_ty
             } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
-                if let ty::Adt(_, substs) = ty.kind {
+                if let ty::Adt(_, substs) = ty.kind() {
                     substs.types().next().map_or(false, |t| t == parent_ty)
                 } else {
                     false
@@ -3663,7 +3696,7 @@ fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'_>, ty: Ty<'_>) -> boo
         }
 
         fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
-            if let ty::Ref(_, t, m) = ty.kind {
+            if let ty::Ref(_, t, m) = *ty.kind() {
                 return m == mutability && t == parent_ty;
             }
 
@@ -3780,7 +3813,7 @@ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     if_chain! {
         if args.len() == 2;
-        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind;
+        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind();
         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
         if layout.is_zst();
         then {
index 06f367a8b775f99ee7ae9fc610cc315c1170c4e5..d4a50dd9013f01a8e8862399fc57c67a8275d900 100644 (file)
@@ -561,17 +561,17 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind;
+    let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind();
 
     if let ty::Array(arr_ty, _) = value {
-        return matches!(arr_ty.kind, ty::Float(_));
+        return matches!(arr_ty.kind(), ty::Float(_));
     };
 
     matches!(value, ty::Float(_))
 }
 
 fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind, ty::Array(_, _))
+    matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind(), ty::Array(_, _))
 }
 
 fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
index b1d788b5c683f4587cebc071623e2326e001160a..da3ae1d652f6c515862ebb2c74016b4c7e69c4f0 100644 (file)
@@ -38,7 +38,7 @@ struct OperandInfo {
 
 fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> {
     match constant(cx, cx.typeck_results(), operand) {
-        Some((Constant::Int(v), _)) => match cx.typeck_results().expr_ty(expr).kind {
+        Some((Constant::Int(v), _)) => match *cx.typeck_results().expr_ty(expr).kind() {
             ty::Int(ity) => {
                 let value = sext(cx.tcx, v, ity);
                 return Some(OperandInfo {
index 9f8f401cc0f67d4e869fb002e914d4bfa18f1d7d..7423107e8f9453fb48906f151988894411a58c83 100644 (file)
@@ -97,7 +97,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::
 // generics (because the compiler cannot ensure immutability for unknown types).
 fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
     let ty = walk_ptrs_ty(ty);
-    if let Adt(def, substs) = ty.kind {
+    if let Adt(def, substs) = ty.kind() {
         if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET]
             .iter()
             .any(|path| match_def_path(cx, def.did, &**path))
@@ -109,7 +109,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
 }
 
 fn is_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
-    match ty.kind {
+    match *ty.kind() {
         RawPtr(TypeAndMut { ty: inner_ty, mutbl }) | Ref(_, inner_ty, mutbl) => {
             mutbl == hir::Mutability::Mut || is_mutable_type(cx, inner_ty, span)
         },
index b02e86bca27195c2a39a7639176adee31fbf2368..2f3cdb894f01c666de9fb75cec810b97594deca6 100644 (file)
@@ -69,7 +69,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
                     expr.span,
                     "generally you want to avoid `&mut &mut _` if possible",
                 );
-            } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind {
+            } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
                 span_lint(
                     self.cx,
                     MUT_MUT,
index c506440ed7987e48c7733262abbc12ac78805826..3f0b765df1561dc9543984506ea475dca498299a 100644 (file)
@@ -61,11 +61,11 @@ fn check_arguments<'tcx>(
     name: &str,
     fn_kind: &str,
 ) {
-    match type_definition.kind {
+    match type_definition.kind() {
         ty::FnDef(..) | ty::FnPtr(_) => {
             let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
             for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
-                match parameter.kind {
+                match parameter.kind() {
                     ty::Ref(_, _, Mutability::Not)
                     | ty::RawPtr(ty::TypeAndMut {
                         mutbl: Mutability::Not, ..
index 7f529f0404c00af727db852f1725efe0e3647569..cc635c2a202f6d4da3000d1ee1603a59b253bbe5 100644 (file)
@@ -138,7 +138,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
                     if adj
                         .iter()
-                        .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut)))
+                        .any(|a| matches!(a.target.kind(), ty::Ref(_, _, Mutability::Mut)))
                     {
                         self.found = true;
                         return;
index 21efee71269862484f60ca618249bb067dd363e5..ea986874291e020f54c9751689383e1d4551ef3c 100644 (file)
@@ -67,7 +67,7 @@
 impl<'tcx> LateLintPass<'tcx> for Mutex {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let ty = cx.typeck_results().expr_ty(expr);
-        if let ty::Adt(_, subst) = ty.kind {
+        if let ty::Adt(_, subst) = ty.kind() {
             if is_type_diagnostic_item(cx, ty, sym!(mutex_type)) {
                 let mutex_param = subst.type_at(0);
                 if let Some(atomic_name) = get_atomic_name(mutex_param) {
@@ -76,7 +76,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                          behavior and not the internal type, consider using `Mutex<()>`",
                         atomic_name
                     );
-                    match mutex_param.kind {
+                    match *mutex_param.kind() {
                         ty::Uint(t) if t != ast::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
                         ty::Int(t) if t != ast::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
                         _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg),
@@ -88,7 +88,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 }
 
 fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
-    match ty.kind {
+    match ty.kind() {
         ty::Bool => Some("AtomicBool"),
         ty::Uint(_) => Some("AtomicUsize"),
         ty::Int(_) => Some("AtomicIsize"),
index 9391049c6e8f95d6513b0c8444bdcd94b5d3224a..b71d5496a37a3e27b610ac5da97cf01279f0fe13 100644 (file)
@@ -46,7 +46,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             return;
         }
         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
-            if let ty::Ref(..) = cx.typeck_results().expr_ty(inner).kind {
+            if let ty::Ref(..) = cx.typeck_results().expr_ty(inner).kind() {
                 for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
                     if let [Adjustment {
                         kind: Adjust::Deref(_), ..
@@ -85,9 +85,9 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
         }
         if_chain! {
             if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
-            if let ty::Ref(_, tam, mutbl) = cx.typeck_results().pat_ty(pat).kind;
+            if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
             if mutbl == Mutability::Not;
-            if let ty::Ref(_, _, mutbl) = tam.kind;
+            if let ty::Ref(_, _, mutbl) = *tam.kind();
             // only lint immutable refs, because borrowed `&mut T` cannot be moved out
             if mutbl == Mutability::Not;
             then {
index 047a78b087841b7224c83536bfbb4eaa488f7908..7e933c674dd781a7093df9eb6c77e7457f6d56c3 100644 (file)
@@ -194,7 +194,7 @@ fn check_fn(
 
                     // Dereference suggestion
                     let sugg = |diag: &mut DiagnosticBuilder<'_>| {
-                        if let ty::Adt(def, ..) = ty.kind {
+                        if let ty::Adt(def, ..) = ty.kind() {
                             if let Some(span) = cx.tcx.hir().span_if_local(def.did) {
                                 if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() {
                                     diag.span_help(span, "consider marking this type as `Copy`");
index ce3f066eff5e7d5d6c8227563c818a826fc98ff1..98e9078094a225b0f9acaee37eb4e32c3c231163 100644 (file)
@@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind {
             let ty = cx.typeck_results().expr_ty(expr);
-            if let ty::Adt(def, _) = ty.kind {
+            if let ty::Adt(def, _) = ty.kind() {
                 if fields.len() == def.non_enum_variant().fields.len() {
                     span_lint(
                         cx,
index f1df634701dd25d5c7a8e5dfcaa31abaad210426..73eabd4207e773cbc80a0c003b11e1cc3e204cf5 100644 (file)
@@ -128,7 +128,7 @@ fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
                 diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)");
             },
             Source::Assoc { ty: ty_span, .. } => {
-                if ty.flags.intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) {
+                if ty.flags().intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) {
                     diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
                 }
             },
index ef26fc667b22591f7b0cba87600407a8081b2848..5539331d0460be96f00928833e1eb1300f5f3935 100644 (file)
@@ -187,19 +187,19 @@ fn find_first_mismatch<'tcx>(
     level: Level,
 ) -> Option<(Span, Mutability, Level)> {
     if let PatKind::Ref(ref sub_pat, _) = pat.kind {
-        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
+        if let TyKind::Ref(_, sub_ty, _) = ty.kind() {
             return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
         }
     }
 
-    if let TyKind::Ref(_, _, mutability) = ty.kind {
+    if let TyKind::Ref(_, _, mutability) = *ty.kind() {
         if is_non_ref_pattern(&pat.kind) {
             return Some((pat.span, mutability, level));
         }
     }
 
     if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
-        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
+        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind() {
             if let Some(variant) = get_variant(adt_def, qpath) {
                 let field_defs = &variant.fields;
                 return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
@@ -208,7 +208,7 @@ fn find_first_mismatch<'tcx>(
     }
 
     if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
-        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
+        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind() {
             if let Some(variant) = get_variant(adt_def, qpath) {
                 let field_defs = &variant.fields;
                 let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
@@ -218,7 +218,7 @@ fn find_first_mismatch<'tcx>(
     }
 
     if let PatKind::Tuple(ref pats, _) = pat.kind {
-        if let TyKind::Tuple(..) = ty.kind {
+        if let TyKind::Tuple(..) = ty.kind() {
             return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
         }
     }
index 7dafb1555dc6e7e187f62e44c1977de7dd2fd81d..6b1c848a9467b2693334d12d6dad98f224128478 100644 (file)
@@ -180,7 +180,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
             }
         }
 
-        if let ty::Ref(_, ty, Mutability::Not) = ty.kind {
+        if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
             if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
                 let mut ty_snippet = None;
                 if_chain! {
index 7a75fc125d0ad0eb42f3c4b8f5f154466eabf41d..cc492917b9dafdd96b4cc89afa26ddfde4f4b635 100644 (file)
@@ -281,7 +281,7 @@ fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool {
     if_chain! {
         if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(expr);
         let ty = cx.typeck_results().expr_ty(start);
-        if let ty::Int(_) | ty::Uint(_) = ty.kind;
+        if let ty::Int(_) | ty::Uint(_) = ty.kind();
         if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start);
         if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end);
         if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
index 7932be0d4b1f260a59b3d839002d3747bb1a9ad1..57a45e628db61497c3f605838e75f2e220a8a003 100644 (file)
@@ -14,7 +14,6 @@
     visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
 };
 use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
-use rustc_mir::dataflow::BottomValue;
 use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
@@ -124,7 +123,7 @@ fn check_fn(
                 continue;
             }
 
-            if let ty::Adt(ref def, _) = arg_ty.kind {
+            if let ty::Adt(ref def, _) = arg_ty.kind() {
                 if match_def_path(cx, def.did, &paths::MEM_MANUALLY_DROP) {
                     continue;
                 }
@@ -287,7 +286,7 @@ fn is_call_with_ref_arg<'tcx>(
         if let mir::TerminatorKind::Call { func, args, destination, .. } = kind;
         if args.len() == 1;
         if let mir::Operand::Move(mir::Place { local, .. }) = &args[0];
-        if let ty::FnDef(def_id, _) = func.ty(&*mir, cx.tcx).kind;
+        if let ty::FnDef(def_id, _) = *func.ty(&*mir, cx.tcx).kind();
         if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(&*mir, cx.tcx));
         if !is_copy(cx, inner_ty);
         then {
@@ -411,14 +410,15 @@ fn visit_place(&mut self, place: &mir::Place<'tcx>, ctx: PlaceContext, _: mir::L
 struct MaybeStorageLive;
 
 impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
-    type Idx = mir::Local;
+    type Domain = BitSet<mir::Local>;
     const NAME: &'static str = "maybe_storage_live";
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = dead
+        BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
         for arg in body.args_iter() {
             state.insert(arg);
         }
@@ -426,6 +426,8 @@ fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self
 }
 
 impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
+    type Idx = mir::Local;
+
     fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
         match stmt.kind {
             mir::StatementKind::StorageLive(l) => trans.gen(l),
@@ -454,11 +456,6 @@ fn call_return_effect(
     }
 }
 
-impl BottomValue for MaybeStorageLive {
-    /// bottom = dead
-    const BOTTOM_VALUE: bool = false;
-}
-
 /// Collects the possible borrowers of each local.
 /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
 /// possible borrowers of `a`.
index 2610157763a8b97dcdb9a818c1ee1cfb7417190f..087d50c90e671236b090fa44266aeb3a0cda2e07 100644 (file)
@@ -165,7 +165,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &
 
 fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool {
     let var_ty = cx.typeck_results().node_type_opt(pat_id);
-    var_ty.map_or(false, |var_ty| !matches!(var_ty.kind, ty::Adt(..)))
+    var_ty.map_or(false, |var_ty| !matches!(var_ty.kind(), ty::Adt(..)))
 }
 
 fn check_pat<'tcx>(
index cc39f060fc7f3929a69ed1860ca789a6dfbc6e54..47a73ca9a24cf7eb5b46f6ee03d377700d48ec34 100644 (file)
@@ -196,8 +196,8 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<
             if eq_expr_value(cx, lhs1, lhs2) {
                 let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1));
 
-                if matches!(ty.kind, ty::Slice(_))
-                    || matches!(ty.kind, ty::Array(_, _))
+                if matches!(ty.kind(), ty::Slice(_))
+                    || matches!(ty.kind(), ty::Array(_, _))
                     || is_type_diagnostic_item(cx, ty, sym!(vec_type))
                     || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type))
                 {
index 1aeff1baa362e24a2362263c07a946e412abde46..fb891866364ccbc9730697e739d923681d9b8094 100644 (file)
@@ -1,5 +1,4 @@
 use crate::utils::{is_adjusted, span_lint};
-use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
     "assignments to temporaries"
 }
 
-fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    match &expr.kind {
-        ExprKind::Struct(..) | ExprKind::Tup(..) => true,
-        ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)),
-        _ => false,
-    }
+fn is_temporary(expr: &Expr<'_>) -> bool {
+    matches!(&expr.kind, ExprKind::Struct(..) | ExprKind::Tup(..))
 }
 
 declare_lint_pass!(TemporaryAssignment => [TEMPORARY_ASSIGNMENT]);
@@ -39,7 +34,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.kind {
                 base = f;
             }
-            if is_temporary(cx, base) && !is_adjusted(cx, base) {
+            if is_temporary(base) && !is_adjusted(cx, base) {
                 span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary");
             }
         }
index 6750452941f28a1b15dc11cb02e4ad301ed3b2bd..eeda39bfa20874fc2fd856767de67dd698a2fe39 100644 (file)
@@ -44,7 +44,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                             if let [char_arg, radix_arg] = &**to_digit_args;
                             if to_digits_path.ident.name.as_str() == "to_digit";
                             let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
-                            if char_arg_ty.kind == ty::Char;
+                            if *char_arg_ty.kind() == ty::Char;
                             then {
                                 Some((true, char_arg, radix_arg))
                             } else {
index 50d9c93f9d405f16e956de1c6446fada39ea7b75..c75adb62f2575aedab44e40b1b8163b0522a8f84 100644 (file)
@@ -331,14 +331,15 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::TRANSMUTE);
             then {
-                // Avoid suggesting from/to bits in const contexts.
+                // Avoid suggesting from/to bits and dereferencing raw pointers in const contexts.
                 // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`.
+                // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
                 let const_context = in_constant(cx, e.hir_id);
 
                 let from_ty = cx.typeck_results().expr_ty(&args[0]);
                 let to_ty = cx.typeck_results().expr_ty(e);
 
-                match (&from_ty.kind, &to_ty.kind) {
+                match (&from_ty.kind(), &to_ty.kind()) {
                     _ if from_ty == to_ty => span_lint(
                         cx,
                         USELESS_TRANSMUTE,
@@ -446,7 +447,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             &format!("transmute from a `{}` to a `char`", from_ty),
                             |diag| {
                                 let arg = sugg::Sugg::hir(cx, &args[0], "..");
-                                let arg = if let ty::Int(_) = from_ty.kind {
+                                let arg = if let ty::Int(_) = from_ty.kind() {
                                     arg.as_ty(ast::UintTy::U32.name_str())
                                 } else {
                                     arg
@@ -462,8 +463,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     },
                     (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => {
                         if_chain! {
-                            if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind, &ty_to.kind);
-                            if let ty::Uint(ast::UintTy::U8) = slice_ty.kind;
+                            if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind(), &ty_to.kind());
+                            if let ty::Uint(ast::UintTy::U8) = slice_ty.kind();
                             if from_mutbl == to_mutbl;
                             then {
                                 let postfix = if *from_mutbl == Mutability::Mut {
@@ -486,7 +487,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                                     Applicability::Unspecified,
                                 );
                             } else {
-                                if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) {
+                                if (cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty))
+                                    && !const_context {
                                     span_lint_and_then(
                                         cx,
                                         TRANSMUTE_PTR_TO_PTR,
@@ -555,7 +557,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
                         |diag| {
                             let arg = sugg::Sugg::hir(cx, &args[0], "..");
-                            let arg = if let ty::Int(int_ty) = from_ty.kind {
+                            let arg = if let ty::Int(int_ty) = from_ty.kind() {
                                 arg.as_ty(format!(
                                     "u{}",
                                     int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string())
@@ -601,7 +603,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             arg = sugg::Sugg::NonParen(format!("{}.to_bits()", arg.maybe_par()).into());
 
                             // cast the result of `to_bits` if `to_ty` is signed
-                            arg = if let ty::Int(int_ty) = to_ty.kind {
+                            arg = if let ty::Int(int_ty) = to_ty.kind() {
                                 arg.as_ty(int_ty.name_str().to_string())
                             } else {
                                 arg
index 92f42168a1eabc56dd5df476d1f5b138211dff57..1f06d2dbe9144e0beb56fc0e33a090ac70e3457c 100644 (file)
@@ -83,7 +83,7 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl
         // Use lifetimes to determine if we're returning a reference to the
         // argument. In that case we can't switch to pass-by-value as the
         // argument will not live long enough.
-        let output_lts = match fn_sig.output().kind {
+        let output_lts = match *fn_sig.output().kind() {
             ty::Ref(output_lt, _, _) => vec![output_lt],
             ty::Adt(_, substs) => substs.regions().collect(),
             _ => vec![],
@@ -97,7 +97,7 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl
             }
 
             if_chain! {
-                if let ty::Ref(input_lt, ty, Mutability::Not) = ty.kind;
+                if let ty::Ref(input_lt, ty, Mutability::Not) = ty.kind();
                 if !output_lts.contains(&input_lt);
                 if is_copy(cx, ty);
                 if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
index a4676e505b6f38e946d0e83b5fdf9a6dee9a7030..3e747ec4ad9e25dcdb5b4bdc2fc03c9fb813bf55 100644 (file)
@@ -132,7 +132,7 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O
 /// Extracts the error type from Result<T, E>.
 fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
-        if let ty::Adt(_, subst) = ty.kind;
+        if let ty::Adt(_, subst) = ty.kind();
         if is_type_diagnostic_item(cx, ty, sym!(result_type));
         let err_ty = subst.type_at(1);
         then {
@@ -146,11 +146,11 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
 /// Extracts the error type from Poll<Result<T, E>>.
 fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
-        if let ty::Adt(def, subst) = ty.kind;
+        if let ty::Adt(def, subst) = ty.kind();
         if match_def_path(cx, def.did, &paths::POLL);
         let ready_ty = subst.type_at(0);
 
-        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind;
+        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
         if cx.tcx.is_diagnostic_item(sym!(result_type), ready_def.did);
         let err_ty = ready_subst.type_at(1);
 
@@ -165,15 +165,15 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<
 /// Extracts the error type from Poll<Option<Result<T, E>>>.
 fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
-        if let ty::Adt(def, subst) = ty.kind;
+        if let ty::Adt(def, subst) = ty.kind();
         if match_def_path(cx, def.did, &paths::POLL);
         let ready_ty = subst.type_at(0);
 
-        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind;
+        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
         if cx.tcx.is_diagnostic_item(sym!(option_type), ready_def.did);
         let some_ty = ready_subst.type_at(0);
 
-        if let ty::Adt(some_def, some_subst) = some_ty.kind;
+        if let ty::Adt(some_def, some_subst) = some_ty.kind();
         if cx.tcx.is_diagnostic_item(sym!(result_type), some_def.did);
         let err_ty = some_subst.type_at(1);
 
index 7e9190bef5e78425ac5478cb78e6e2ec24879f12..6c6188d61ad52fc6f492453ec95667fba4e67662 100644 (file)
@@ -11,8 +11,8 @@
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{
     BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
-    ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn,
-    TraitItem, TraitItemKind, TyKind, UnOp,
+    ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind,
+    TraitFn, TraitItem, TraitItemKind, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use crate::utils::{
     clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item,
     last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral,
-    qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability,
-    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
+    qpath_res, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite,
+    span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
 };
 
 declare_clippy_lint! {
     /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
+    /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
     ///
     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
     /// the heap. So if you `Box` it, you just add another level of indirection
@@ -65,6 +66,7 @@
 
 declare_clippy_lint! {
     /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
+    /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
     ///
     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
     /// the heap. So if you `Box` its contents, you just add another level of indirection.
 
 declare_clippy_lint! {
     /// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
+    /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
     ///
     /// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more
     /// general.
@@ -802,6 +805,45 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 }
 
+fn fmt_stmts_and_call(
+    cx: &LateContext<'_>,
+    call_expr: &Expr<'_>,
+    call_snippet: &str,
+    args_snippets: &[impl AsRef<str>],
+    non_empty_block_args_snippets: &[impl AsRef<str>],
+) -> String {
+    let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0);
+    let call_snippet_with_replacements = args_snippets
+        .iter()
+        .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1));
+
+    let mut stmts_and_call = non_empty_block_args_snippets
+        .iter()
+        .map(|it| it.as_ref().to_owned())
+        .collect::<Vec<_>>();
+    stmts_and_call.push(call_snippet_with_replacements);
+    stmts_and_call = stmts_and_call
+        .into_iter()
+        .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned())
+        .collect();
+
+    let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
+    // expr is not in a block statement or result expression position, wrap in a block
+    let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id));
+    if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) {
+        let block_indent = call_expr_indent + 4;
+        stmts_and_call_snippet =
+            reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned();
+        stmts_and_call_snippet = format!(
+            "{{\n{}{}\n{}}}",
+            " ".repeat(block_indent),
+            &stmts_and_call_snippet,
+            " ".repeat(call_expr_indent)
+        );
+    }
+    stmts_and_call_snippet
+}
+
 fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
     let (singular, plural) = if args_to_recover.len() > 1 {
@@ -844,43 +886,52 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
                         Applicability::MaybeIncorrect,
                     );
                     or = "or ";
+                    applicability = Applicability::MaybeIncorrect;
                 });
-            let sugg = args_to_recover
+
+            let arg_snippets: Vec<String> = args_to_recover
+                .iter()
+                .filter_map(|arg| snippet_opt(cx, arg.span))
+                .collect();
+            let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover
                 .iter()
                 .filter(|arg| !is_empty_block(arg))
-                .enumerate()
-                .map(|(i, arg)| {
-                    let indent = if i == 0 {
-                        0
-                    } else {
-                        indent_of(cx, expr.span).unwrap_or(0)
-                    };
-                    format!(
-                        "{}{};",
-                        " ".repeat(indent),
-                        snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability)
-                    )
-                })
-                .collect::<Vec<String>>();
-            let mut and = "";
-            if !sugg.is_empty() {
-                let plural = if sugg.len() > 1 { "s" } else { "" };
-                db.span_suggestion(
-                    expr.span.with_hi(expr.span.lo()),
-                    &format!("{}move the expression{} in front of the call...", or, plural),
-                    format!("{}\n", sugg.join("\n")),
-                    applicability,
+                .filter_map(|arg| snippet_opt(cx, arg.span))
+                .collect();
+
+            if let Some(call_snippet) = snippet_opt(cx, expr.span) {
+                let sugg = fmt_stmts_and_call(
+                    cx,
+                    expr,
+                    &call_snippet,
+                    &arg_snippets,
+                    &arg_snippets_without_empty_blocks,
                 );
-                and = "...and "
+
+                if arg_snippets_without_empty_blocks.is_empty() {
+                    db.multipart_suggestion(
+                        &format!("use {}unit literal{} instead", singular, plural),
+                        args_to_recover
+                            .iter()
+                            .map(|arg| (arg.span, "()".to_string()))
+                            .collect::<Vec<_>>(),
+                        applicability,
+                    );
+                } else {
+                    let plural = arg_snippets_without_empty_blocks.len() > 1;
+                    let empty_or_s = if plural { "s" } else { "" };
+                    let it_or_them = if plural { "them" } else { "it" };
+                    db.span_suggestion(
+                        expr.span,
+                        &format!(
+                            "{}move the expression{} in front of the call and replace {} with the unit literal `()`",
+                            or, empty_or_s, it_or_them
+                        ),
+                        sugg,
+                        applicability,
+                    );
+                }
             }
-            db.multipart_suggestion(
-                &format!("{}use {}unit literal{} instead", and, singular, plural),
-                args_to_recover
-                    .iter()
-                    .map(|arg| (arg.span, "()".to_string()))
-                    .collect::<Vec<_>>(),
-                applicability,
-            );
         },
     );
 }
@@ -907,7 +958,7 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
 }
 
 fn is_unit(ty: Ty<'_>) -> bool {
-    matches!(ty.kind, ty::Tuple(slice) if slice.is_empty())
+    matches!(ty.kind(), ty::Tuple(slice) if slice.is_empty())
 }
 
 fn is_unit_literal(expr: &Expr<'_>) -> bool {
@@ -1134,7 +1185,7 @@ fn is_unit_literal(expr: &Expr<'_>) -> bool {
 /// Returns the size in bits of an integral type.
 /// Will return 0 if the type is not an int or uint variant
 fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
-    match typ.kind {
+    match typ.kind() {
         ty::Int(i) => match i {
             IntTy::Isize => tcx.data_layout.pointer_size.bits(),
             IntTy::I8 => 8,
@@ -1156,7 +1207,7 @@ fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
 }
 
 fn is_isize_or_usize(typ: Ty<'_>) -> bool {
-    matches!(typ.kind, ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
+    matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
 }
 
 fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) {
@@ -1248,7 +1299,7 @@ fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast
     if_chain! {
         if let Some((const_val, _)) = const_val;
         if let Constant::Int(n) = const_val;
-        if let ty::Int(ity) = cast_from.kind;
+        if let ty::Int(ity) = *cast_from.kind();
         if sext(cx.tcx, n, ity) >= 0;
         then {
             return
@@ -1381,7 +1432,7 @@ fn check_lossless(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_fro
 // Check if the given type is either `core::ffi::c_void` or
 // one of the platform specific `libc::<platform>::c_void` of libc.
 fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    if let ty::Adt(adt, _) = ty.kind {
+    if let ty::Adt(adt, _) = ty.kind() {
         let names = cx.get_def_path(adt.did);
 
         if names.is_empty() {
@@ -1397,7 +1448,7 @@ fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
 /// Returns the mantissa bits wide of a fp type.
 /// Will return 0 if the type is not a fp
 fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
-    match typ.kind {
+    match typ.kind() {
         ty::Float(FloatTy::F32) => 23,
         ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
         _ => 0,
@@ -1437,7 +1488,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 match lit.node {
                     LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
                     _ => {
-                        if cast_from.kind == cast_to.kind && !in_external_macro(cx.sess(), expr.span) {
+                        if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
                             span_lint(
                                 cx,
                                 UNNECESSARY_CAST,
@@ -1470,7 +1521,7 @@ fn lint_numeric_casts<'tcx>(
     match (cast_from.is_integral(), cast_to.is_integral()) {
         (true, false) => {
             let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
-            let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind {
+            let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
                 32
             } else {
                 64
@@ -1507,7 +1558,7 @@ fn lint_numeric_casts<'tcx>(
             check_lossless(cx, expr, cast_expr, cast_from, cast_to);
         },
         (false, false) => {
-            if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.kind, &cast_to.kind) {
+            if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.kind(), &cast_to.kind()) {
                 span_lint(
                     cx,
                     CAST_POSSIBLE_TRUNCATION,
@@ -1515,7 +1566,7 @@ fn lint_numeric_casts<'tcx>(
                     "casting `f64` to `f32` may truncate the value",
                 );
             }
-            if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.kind, &cast_to.kind) {
+            if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.kind(), &cast_to.kind()) {
                 span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
             }
         },
@@ -1524,8 +1575,8 @@ fn lint_numeric_casts<'tcx>(
 
 fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) {
     if_chain! {
-        if let ty::RawPtr(from_ptr_ty) = &cast_from.kind;
-        if let ty::RawPtr(to_ptr_ty) = &cast_to.kind;
+        if let ty::RawPtr(from_ptr_ty) = &cast_from.kind();
+        if let ty::RawPtr(to_ptr_ty) = &cast_to.kind();
         if let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty);
         if let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty);
         if from_layout.align.abi < to_layout.align.abi;
@@ -1558,11 +1609,11 @@ fn lint_fn_to_numeric_cast(
     cast_to: Ty<'_>,
 ) {
     // We only want to check casts to `ty::Uint` or `ty::Int`
-    match cast_to.kind {
+    match cast_to.kind() {
         ty::Uint(_) | ty::Int(..) => { /* continue on */ },
         _ => return,
     }
-    match cast_from.kind {
+    match cast_from.kind() {
         ty::FnDef(..) | ty::FnPtr(_) => {
             let mut applicability = Applicability::MaybeIncorrect;
             let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
@@ -1581,7 +1632,7 @@ fn lint_fn_to_numeric_cast(
                     format!("{} as usize", from_snippet),
                     applicability,
                 );
-            } else if cast_to.kind != ty::Uint(UintTy::Usize) {
+            } else if *cast_to.kind() != ty::Uint(UintTy::Usize) {
                 span_lint_and_sugg(
                     cx,
                     FN_TO_NUMERIC_CAST,
@@ -1798,7 +1849,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Cast(e, _) = &expr.kind;
             if let ExprKind::Lit(l) = &e.kind;
             if let LitKind::Char(c) = l.node;
-            if ty::Uint(UintTy::U8) == cx.typeck_results().expr_ty(expr).kind;
+            if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind();
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
@@ -1937,7 +1988,7 @@ fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op
 
     let cv = constant(cx, cx.typeck_results(), expr)?.0;
 
-    let which = match (&ty.kind, cv) {
+    let which = match (ty.kind(), cv) {
         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
         (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
             Minimum
@@ -2055,6 +2106,7 @@ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         })
     }
 }
+
 impl Ord for FullInt {
     #[must_use]
     fn cmp(&self, other: &Self) -> Ordering {
@@ -2071,7 +2123,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) ->
         if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
             return None;
         }
-        match pre_cast_ty.kind {
+        match pre_cast_ty.kind() {
             ty::Int(int_ty) => Some(match int_ty {
                 IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
                 IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
@@ -2098,7 +2150,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) ->
 fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
     let val = constant(cx, cx.typeck_results(), expr)?.0;
     if let Constant::Int(const_int) = val {
-        match cx.typeck_results().expr_ty(expr).kind {
+        match *cx.typeck_results().expr_ty(expr).kind() {
             ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
             ty::Uint(_) => Some(FullInt::U(const_int)),
             _ => None,
@@ -2601,7 +2653,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind;
             if let ExprKind::Cast(e, t) = &e.kind;
             if let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind;
-            if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind;
+            if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind();
             then {
                 span_lint(
                     cx,
index 679aaec9fcd6c4402da0ea5ddff7756f950b4c52..0d5a5017331b78bf0e6a16f6ebe276e19559d24f 100644 (file)
@@ -110,7 +110,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
 fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
     if_chain! {
         if let ExprKind::Closure(_, _fn_decl, body_id, span, _) = arg.kind;
-        if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind;
+        if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind();
         let ret_ty = substs.as_closure().sig().output();
         let ty = cx.tcx.erase_late_bound_regions(&ret_ty);
         if ty.is_unit();
index 28b393b9f11f0b67a952af15e2909a6926e134df..9582c162e77b274734c7e976bc1e17735fde48f5 100644 (file)
@@ -65,14 +65,14 @@ fn is_comparison(binop: BinOpKind) -> bool {
         }
 
         fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-            match cx.typeck_results().expr_ty_adjusted(expr).kind {
+            match cx.typeck_results().expr_ty_adjusted(expr).kind() {
                 ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(),
                 _ => false,
             }
         }
 
         fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-            matches!(cx.typeck_results().expr_ty(expr).kind, ty::FnDef(..))
+            matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..))
         }
 
         if_chain! {
index 59993d25bb4706b9b204729693ff0921cd0b5422..9b6a9075a2954b8e0c7753f63309c86a4aa6a785 100644 (file)
@@ -1,5 +1,4 @@
 use crate::utils;
-use crate::utils::paths;
 use crate::utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -171,12 +170,22 @@ fn mirrored_exprs(
 }
 
 fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
+    // NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162,
+    // (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested
+    // closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more
+    // than one level of references would add some extra complexity as we would have to compensate
+    // in the closure body.
+
     if_chain! {
         if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
         if let name = name_ident.ident.name.to_ident_string();
         if name == "sort_by" || name == "sort_unstable_by";
         if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
-        if utils::match_type(cx, &cx.typeck_results().expr_ty(vec), &paths::VEC);
+        let vec_ty = cx.typeck_results().expr_ty(vec);
+        if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type));
+        let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec<T>
+        if !matches!(&ty.kind(), ty::Ref(..));
+        if utils::is_copy(cx, ty);
         if let closure_body = cx.tcx.hir().body(*closure_body_id);
         if let &[
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
@@ -230,7 +239,7 @@ fn key_returns_borrow(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if let Some(def_id) = utils::fn_def_id(cx, expr) {
         let output = cx.tcx.fn_sig(def_id).output();
         let ty = output.skip_binder();
-        return matches!(ty.kind, ty::Ref(..))
+        return matches!(ty.kind(), ty::Ref(..))
             || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
     }
 
index 4ab2b5e796deb75f7361fc466c9d69306e7c7db4..615440e15f384bca82bff66cdda8796cf7e5266a 100644 (file)
@@ -107,7 +107,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         let a = cx.typeck_results().expr_ty(e);
                         let b = cx.typeck_results().expr_ty(&args[0]);
                         if is_type_diagnostic_item(cx, a, sym!(result_type));
-                        if let ty::Adt(_, substs) = a.kind;
+                        if let ty::Adt(_, substs) = a.kind();
                         if let Some(a_type) = substs.types().next();
                         if TyS::same_type(a_type, b);
 
@@ -137,7 +137,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::TRY_FROM);
                             if is_type_diagnostic_item(cx, a, sym!(result_type));
-                            if let ty::Adt(_, substs) = a.kind;
+                            if let ty::Adt(_, substs) = a.kind();
                             if let Some(a_type) = substs.types().next();
                             if TyS::same_type(a_type, b);
 
index 7b419431c0f51dafe566ad6a29dd46394213ac74..fa8dd210ebadd12bc68a22a794cd339bc84aff74 100644 (file)
@@ -191,7 +191,9 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
         (Item(l), Item(r)) => eq_item(l, r, eq_item_kind),
         (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r),
         (Empty, Empty) => true,
-        (MacCall(l), MacCall(r)) => l.1 == r.1 && eq_mac_call(&l.0, &r.0) && over(&l.2, &r.2, |l, r| eq_attr(l, r)),
+        (MacCall(l), MacCall(r)) => {
+            l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+        },
         _ => false,
     }
 }
index 292dbd7ad6b480babd426aae3dadc51060b419ac..9c5a12ea9c8e1674e7be4e522437555e156b977e 100644 (file)
@@ -122,7 +122,7 @@ fn $config() -> $Ty {
         "IPv4", "IPv6",
         "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
         "NaN", "NaNs",
-        "OAuth",
+        "OAuth", "GraphQL",
         "OCaml",
         "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap",
         "TensorFlow",
index e6be5c4588f0f24d65abb1194eae4ec960e72e87..3ebbfed6456273638409bceffc8f6faa9c572d02 100644 (file)
@@ -19,6 +19,7 @@
 pub mod ptr;
 pub mod sugg;
 pub mod usage;
+
 pub use self::attrs::*;
 pub use self::diagnostics::*;
 pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
@@ -42,7 +43,8 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
+use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
 use rustc_mir::const_eval;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
@@ -107,6 +109,7 @@ pub fn in_macro(span: Span) -> bool {
         false
     }
 }
+
 // If the snippet is empty, it's an attribute that was inserted during macro
 // expansion and we want to ignore those, because they could come from external
 // sources that the user has no control over.
@@ -128,7 +131,7 @@ pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
 
 /// Checks if type is struct, enum or union type with the given def path.
 pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
-    match ty.kind {
+    match ty.kind() {
         ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
         _ => false,
     }
@@ -136,7 +139,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
 
 /// Checks if the type is equal to a diagnostic item
 pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
-    match ty.kind {
+    match ty.kind() {
         ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
         _ => false,
     }
@@ -144,7 +147,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb
 
 /// Checks if the type is equal to a lang item
 pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
-    match ty.kind {
+    match ty.kind() {
         ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did,
         _ => false,
     }
@@ -570,7 +573,7 @@ pub fn snippet_block<'a, T: LintContext>(
 ) -> Cow<'a, str> {
     let snip = snippet(cx, span, default);
     let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
-    trim_multiline(snip, true, indent)
+    reindent_multiline(snip, true, indent)
 }
 
 /// Same as `snippet_block`, but adapts the applicability level by the rules of
@@ -584,7 +587,7 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>(
 ) -> Cow<'a, str> {
     let snip = snippet_with_applicability(cx, span, default, applicability);
     let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
-    trim_multiline(snip, true, indent)
+    reindent_multiline(snip, true, indent)
 }
 
 /// Returns a new Span that extends the original Span to the first non-whitespace char of the first
@@ -660,16 +663,16 @@ pub fn expr_block<'a, T: LintContext>(
     }
 }
 
-/// Trim indentation from a multiline string with possibility of ignoring the
-/// first line.
-fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
-    let s_space = trim_multiline_inner(s, ignore_first, indent, ' ');
-    let s_tab = trim_multiline_inner(s_space, ignore_first, indent, '\t');
-    trim_multiline_inner(s_tab, ignore_first, indent, ' ')
+/// Reindent a multiline string with possibility of ignoring the first line.
+#[allow(clippy::needless_pass_by_value)]
+pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
+    let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' ');
+    let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t');
+    reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into()
 }
 
-fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>, ch: char) -> Cow<'_, str> {
-    let mut x = s
+fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, ch: char) -> String {
+    let x = s
         .lines()
         .skip(ignore_first as usize)
         .filter_map(|l| {
@@ -682,26 +685,20 @@ fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option<usiz
         })
         .min()
         .unwrap_or(0);
-    if let Some(indent) = indent {
-        x = x.saturating_sub(indent);
-    }
-    if x > 0 {
-        Cow::Owned(
-            s.lines()
-                .enumerate()
-                .map(|(i, l)| {
-                    if (ignore_first && i == 0) || l.is_empty() {
-                        l
-                    } else {
-                        l.split_at(x).1
-                    }
-                })
-                .collect::<Vec<_>>()
-                .join("\n"),
-        )
-    } else {
-        s
-    }
+    let indent = indent.unwrap_or(0);
+    s.lines()
+        .enumerate()
+        .map(|(i, l)| {
+            if (ignore_first && i == 0) || l.is_empty() {
+                l.to_owned()
+            } else if x > indent {
+                l.split_at(x - indent).1.to_owned()
+            } else {
+                " ".repeat(indent - x) + l
+            }
+        })
+        .collect::<Vec<String>>()
+        .join("\n")
 }
 
 /// Gets the parent expression, if any –- this is useful to constrain a lint.
@@ -753,7 +750,7 @@ pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
 
 /// Returns the base type for references and raw pointers.
 pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> {
-    match ty.kind {
+    match ty.kind() {
         ty::Ref(_, ty, _) => walk_ptrs_ty(ty),
         _ => ty,
     }
@@ -763,7 +760,7 @@ pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> {
 /// depth.
 pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
     fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
-        match ty.kind {
+        match ty.kind() {
             ty::Ref(_, ty, _) => inner(ty, depth + 1),
             _ => (ty, depth),
         }
@@ -866,9 +863,17 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx>
     cx.tcx.erase_late_bound_regions(&ret_ty)
 }
 
+/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty`
+pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool {
+    ty.walk().any(|inner| match inner.unpack() {
+        GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty),
+        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
+    })
+}
+
 /// Returns `true` if the given type is an `unsafe` function.
 pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    match ty.kind {
+    match ty.kind() {
         ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
         _ => false,
     }
@@ -890,7 +895,7 @@ fn has_no_arguments(cx: &LateContext<'_>, def_id: DefId) -> bool {
             return match res {
                 def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
                 // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210
-                def::Res::Def(DefKind::Fn, def_id) if has_no_arguments(cx, def_id) => {
+                def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => {
                     const_eval::is_const_fn(cx.tcx, def_id)
                 },
                 def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
@@ -933,7 +938,7 @@ fn are_refutable<'a, I: Iterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, mut
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
         PatKind::Slice(ref head, ref middle, ref tail) => {
-            match &cx.typeck_results().node_type(pat.hir_id).kind {
+            match &cx.typeck_results().node_type(pat.hir_id).kind() {
                 ty::Slice(..) => {
                     // [..] is the only irrefutable slice pattern.
                     !head.is_empty() || middle.is_none() || !tail.is_empty()
@@ -1147,12 +1152,12 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<
         &paths::RECEIVER,
     ];
 
-    let ty_to_check = match probably_ref_ty.kind {
+    let ty_to_check = match probably_ref_ty.kind() {
         ty::Ref(_, ty_to_check, _) => ty_to_check,
         _ => probably_ref_ty,
     };
 
-    let def_id = match ty_to_check.kind {
+    let def_id = match ty_to_check.kind() {
         ty::Array(..) => return Some("array"),
         ty::Slice(..) => return Some("slice"),
         ty::Adt(adt, _) => adt.did,
@@ -1268,7 +1273,7 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 
 // Returns whether the type has #[must_use] attribute
 pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    match ty.kind {
+    match ty.kind() {
         ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
         ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
         ty::Slice(ref ty)
@@ -1400,9 +1405,9 @@ pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bo
 /// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point
 /// number type, a str, or an array, slice, or tuple of those types).
 pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
-    match ty.kind {
+    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.kind() == ty::Str => true,
         ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
         ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
         _ => false,
@@ -1414,24 +1419,23 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
 /// `is_recursively_primitive_type` function) and None otherwise.
 pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
     let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
-    let expr_kind = &expr_type.kind;
+    let expr_kind = expr_type.kind();
     let is_primitive = match expr_kind {
-        ty::Slice(ref element_type)
-        | ty::Ref(
-            _,
-            ty::TyS {
-                kind: ty::Slice(ref element_type),
-                ..
-            },
-            _,
-        ) => is_recursively_primitive_type(element_type),
+        ty::Slice(element_type) => is_recursively_primitive_type(element_type),
+        ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &ty::Slice(_)) => {
+            if let ty::Slice(element_type) = inner_ty.kind() {
+                is_recursively_primitive_type(element_type)
+            } else {
+                unreachable!()
+            }
+        },
         _ => false,
     };
 
     if is_primitive {
         // if we have wrappers like Array, Slice or Tuple, print these
         // and get the type enclosed in the slice ref
-        match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind {
+        match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() {
             ty::Slice(..) => return Some("slice".into()),
             ty::Array(..) => return Some("array".into()),
             ty::Tuple(..) => return Some("tuple".into()),
@@ -1466,26 +1470,26 @@ macro_rules! unwrap_cargo_metadata {
 
 #[cfg(test)]
 mod test {
-    use super::{trim_multiline, without_block_comments};
+    use super::{reindent_multiline, without_block_comments};
 
     #[test]
-    fn test_trim_multiline_single_line() {
-        assert_eq!("", trim_multiline("".into(), false, None));
-        assert_eq!("...", trim_multiline("...".into(), false, None));
-        assert_eq!("...", trim_multiline("    ...".into(), false, None));
-        assert_eq!("...", trim_multiline("\t...".into(), false, None));
-        assert_eq!("...", trim_multiline("\t\t...".into(), false, None));
+    fn test_reindent_multiline_single_line() {
+        assert_eq!("", reindent_multiline("".into(), false, None));
+        assert_eq!("...", reindent_multiline("...".into(), false, None));
+        assert_eq!("...", reindent_multiline("    ...".into(), false, None));
+        assert_eq!("...", reindent_multiline("\t...".into(), false, None));
+        assert_eq!("...", reindent_multiline("\t\t...".into(), false, None));
     }
 
     #[test]
     #[rustfmt::skip]
-    fn test_trim_multiline_block() {
+    fn test_reindent_multiline_block() {
         assert_eq!("\
     if x {
         y
     } else {
         z
-    }", trim_multiline("    if x {
+    }", reindent_multiline("    if x {
             y
         } else {
             z
@@ -1495,7 +1499,7 @@ fn test_trim_multiline_block() {
     \ty
     } else {
     \tz
-    }", trim_multiline("    if x {
+    }", reindent_multiline("    if x {
         \ty
         } else {
         \tz
@@ -1504,14 +1508,14 @@ fn test_trim_multiline_block() {
 
     #[test]
     #[rustfmt::skip]
-    fn test_trim_multiline_empty_line() {
+    fn test_reindent_multiline_empty_line() {
         assert_eq!("\
     if x {
         y
 
     } else {
         z
-    }", trim_multiline("    if x {
+    }", reindent_multiline("    if x {
             y
 
         } else {
@@ -1519,6 +1523,22 @@ fn test_trim_multiline_empty_line() {
         }".into(), false, None));
     }
 
+    #[test]
+    #[rustfmt::skip]
+    fn test_reindent_multiline_lines_deeper() {
+        assert_eq!("\
+        if x {
+            y
+        } else {
+            z
+        }", reindent_multiline("\
+    if x {
+        y
+    } else {
+        z
+    }".into(), true, Some(8)));
+    }
+
     #[test]
     fn test_without_block_comments_lines_without_block_comments() {
         let result = without_block_comments(vec!["/*", "", "*/"]);
index 2955f8d8e591984dc4004595aeda7bff29d40a7d..811fde388d15adbaeffbd998ddcf91ea91089f52 100644 (file)
@@ -132,7 +132,11 @@ fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
     pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
         use rustc_ast::ast::RangeLimits;
 
-        let snippet = snippet(cx, expr.span, default);
+        let snippet = if expr.span.from_expansion() {
+            snippet_with_macro_callsite(cx, expr.span, default)
+        } else {
+            snippet(cx, expr.span, default)
+        };
 
         match expr.kind {
             ast::ExprKind::AddrOf(..)
index 84e907d7125de8951f291dc201a4c453d417c74d..149cceb39dd9903cc2625d0ccf1508f8f96f94be 100644 (file)
@@ -44,8 +44,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // search for `&vec![_]` expressions where the adjusted type is `&[_]`
         if_chain! {
-            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind;
-            if let ty::Slice(..) = ty.kind;
+            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
+            if let ty::Slice(..) = ty.kind();
             if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind;
             if let Some(vec_args) = higher::vec_macro(cx, addressee);
             then {
@@ -127,7 +127,7 @@ fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
 
 /// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
 fn vec_type(ty: Ty<'_>) -> Ty<'_> {
-    if let ty::Adt(_, substs) = ty.kind {
+    if let ty::Adt(_, substs) = ty.kind() {
         substs.type_at(0)
     } else {
         panic!("The type of `vec!` is a not a struct?");
index e51345109226c6514403075ea65c9b4d05c0c351..6697835e950d982d1767421d138411d921ee37ba 100644 (file)
         deprecation: None,
         module: "assign_ops",
     },
+    Lint {
+        name: "async_yields_async",
+        group: "correctness",
+        desc: "async blocks that return a type that can be awaited",
+        deprecation: None,
+        module: "async_yields_async",
+    },
     Lint {
         name: "await_holding_lock",
         group: "pedantic",
index fb12257021a1e7e0f0751c65c233392c0d8572fa..a27ce945ca58461cc08fef154aef3ba7c3cc7f23 100644 (file)
@@ -1,4 +1,4 @@
-error: this function has a large number of lines
+error: this function has too many lines (2/1)
   --> $DIR/test.rs:18:1
    |
 LL | / fn too_many_lines() {
@@ -9,7 +9,7 @@ LL | | }
    |
    = note: `-D clippy::too-many-lines` implied by `-D warnings`
 
-error: this function has a large number of lines
+error: this function has too many lines (2/1)
   --> $DIR/test.rs:38:1
    |
 LL | / fn comment_before_code() {
diff --git a/tests/ui/async_yields_async.fixed b/tests/ui/async_yields_async.fixed
new file mode 100644 (file)
index 0000000..9b1a7ac
--- /dev/null
@@ -0,0 +1,68 @@
+// run-rustfix
+// edition:2018
+
+#![feature(async_closure)]
+#![warn(clippy::async_yields_async)]
+
+use core::future::Future;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+struct CustomFutureType;
+
+impl Future for CustomFutureType {
+    type Output = u8;
+
+    fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
+        Poll::Ready(3)
+    }
+}
+
+fn custom_future_type_ctor() -> CustomFutureType {
+    CustomFutureType
+}
+
+async fn f() -> CustomFutureType {
+    // Don't warn for functions since you have to explicitly declare their
+    // return types.
+    CustomFutureType
+}
+
+#[rustfmt::skip]
+fn main() {
+    let _f = {
+        3
+    };
+    let _g = async {
+        3
+    };
+    let _h = async {
+        async {
+            3
+        }.await
+    };
+    let _i = async {
+        CustomFutureType.await
+    };
+    let _i = async || {
+        3
+    };
+    let _j = async || {
+        async {
+            3
+        }.await
+    };
+    let _k = async || {
+        CustomFutureType.await
+    };
+    let _l = async || CustomFutureType.await;
+    let _m = async || {
+        println!("I'm bored");
+        // Some more stuff
+
+        // Finally something to await
+        CustomFutureType.await
+    };
+    let _n = async || custom_future_type_ctor();
+    let _o = async || f();
+}
diff --git a/tests/ui/async_yields_async.rs b/tests/ui/async_yields_async.rs
new file mode 100644 (file)
index 0000000..731c094
--- /dev/null
@@ -0,0 +1,68 @@
+// run-rustfix
+// edition:2018
+
+#![feature(async_closure)]
+#![warn(clippy::async_yields_async)]
+
+use core::future::Future;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+struct CustomFutureType;
+
+impl Future for CustomFutureType {
+    type Output = u8;
+
+    fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
+        Poll::Ready(3)
+    }
+}
+
+fn custom_future_type_ctor() -> CustomFutureType {
+    CustomFutureType
+}
+
+async fn f() -> CustomFutureType {
+    // Don't warn for functions since you have to explicitly declare their
+    // return types.
+    CustomFutureType
+}
+
+#[rustfmt::skip]
+fn main() {
+    let _f = {
+        3
+    };
+    let _g = async {
+        3
+    };
+    let _h = async {
+        async {
+            3
+        }
+    };
+    let _i = async {
+        CustomFutureType
+    };
+    let _i = async || {
+        3
+    };
+    let _j = async || {
+        async {
+            3
+        }
+    };
+    let _k = async || {
+        CustomFutureType
+    };
+    let _l = async || CustomFutureType;
+    let _m = async || {
+        println!("I'm bored");
+        // Some more stuff
+
+        // Finally something to await
+        CustomFutureType
+    };
+    let _n = async || custom_future_type_ctor();
+    let _o = async || f();
+}
diff --git a/tests/ui/async_yields_async.stderr b/tests/ui/async_yields_async.stderr
new file mode 100644 (file)
index 0000000..17d0c37
--- /dev/null
@@ -0,0 +1,96 @@
+error: an async construct yields a type which is itself awaitable
+  --> $DIR/async_yields_async.rs:40:9
+   |
+LL |        let _h = async {
+   |   ____________________-
+LL |  |         async {
+   |  |_________^
+LL | ||             3
+LL | ||         }
+   | ||_________^ awaitable value not awaited
+LL |  |     };
+   |  |_____- outer async construct
+   |
+   = note: `-D clippy::async-yields-async` implied by `-D warnings`
+help: consider awaiting this value
+   |
+LL |         async {
+LL |             3
+LL |         }.await
+   |
+
+error: an async construct yields a type which is itself awaitable
+  --> $DIR/async_yields_async.rs:45:9
+   |
+LL |       let _i = async {
+   |  ____________________-
+LL | |         CustomFutureType
+   | |         ^^^^^^^^^^^^^^^^
+   | |         |
+   | |         awaitable value not awaited
+   | |         help: consider awaiting this value: `CustomFutureType.await`
+LL | |     };
+   | |_____- outer async construct
+
+error: an async construct yields a type which is itself awaitable
+  --> $DIR/async_yields_async.rs:51:9
+   |
+LL |        let _j = async || {
+   |   _______________________-
+LL |  |         async {
+   |  |_________^
+LL | ||             3
+LL | ||         }
+   | ||_________^ awaitable value not awaited
+LL |  |     };
+   |  |_____- outer async construct
+   |
+help: consider awaiting this value
+   |
+LL |         async {
+LL |             3
+LL |         }.await
+   |
+
+error: an async construct yields a type which is itself awaitable
+  --> $DIR/async_yields_async.rs:56:9
+   |
+LL |       let _k = async || {
+   |  _______________________-
+LL | |         CustomFutureType
+   | |         ^^^^^^^^^^^^^^^^
+   | |         |
+   | |         awaitable value not awaited
+   | |         help: consider awaiting this value: `CustomFutureType.await`
+LL | |     };
+   | |_____- outer async construct
+
+error: an async construct yields a type which is itself awaitable
+  --> $DIR/async_yields_async.rs:58:23
+   |
+LL |     let _l = async || CustomFutureType;
+   |                       ^^^^^^^^^^^^^^^^
+   |                       |
+   |                       outer async construct
+   |                       awaitable value not awaited
+   |                       help: consider awaiting this value: `CustomFutureType.await`
+
+error: an async construct yields a type which is itself awaitable
+  --> $DIR/async_yields_async.rs:64:9
+   |
+LL |       let _m = async || {
+   |  _______________________-
+LL | |         println!("I'm bored");
+LL | |         // Some more stuff
+LL | |
+LL | |         // Finally something to await
+LL | |         CustomFutureType
+   | |         ^^^^^^^^^^^^^^^^
+   | |         |
+   | |         awaitable value not awaited
+   | |         help: consider awaiting this value: `CustomFutureType.await`
+LL | |     };
+   | |_____- outer async construct
+
+error: aborting due to 6 previous errors
+
index a414832bcd36200765be6b70ae3fe59588d64586..39f87510548503654c7a610837fed55c9ebc64de 100644 (file)
@@ -1,5 +1,6 @@
 #![warn(clippy::borrow_interior_mutable_const)]
 #![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)]
+#![allow(const_item_mutation)]
 
 use std::borrow::Cow;
 use std::cell::{Cell, UnsafeCell};
index 1e0b3e4d20a5236c6b7c72162f0490bd8eb54345..5800af7e960f4da7247f652d0685bcaf3af32093 100644 (file)
@@ -1,5 +1,5 @@
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:65:5
+  --> $DIR/borrow_interior_mutable_const.rs:66:5
    |
 LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
    |     ^^^^^^
@@ -8,7 +8,7 @@ LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:66:16
+  --> $DIR/borrow_interior_mutable_const.rs:67:16
    |
 LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
    |                ^^^^^^
@@ -16,7 +16,7 @@ LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:69:22
+  --> $DIR/borrow_interior_mutable_const.rs:70:22
    |
 LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
    |                      ^^^^^^^^^
@@ -24,7 +24,7 @@ LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:70:25
+  --> $DIR/borrow_interior_mutable_const.rs:71:25
    |
 LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
    |                         ^^^^^^^^^
@@ -32,7 +32,7 @@ LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:71:27
+  --> $DIR/borrow_interior_mutable_const.rs:72:27
    |
 LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
    |                           ^^^^^^^^^
@@ -40,7 +40,7 @@ LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:72:26
+  --> $DIR/borrow_interior_mutable_const.rs:73:26
    |
 LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
    |                          ^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:83:14
+  --> $DIR/borrow_interior_mutable_const.rs:84:14
    |
 LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:84:14
+  --> $DIR/borrow_interior_mutable_const.rs:85:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:85:19
+  --> $DIR/borrow_interior_mutable_const.rs:86:19
    |
 LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
    |                   ^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:86:14
+  --> $DIR/borrow_interior_mutable_const.rs:87:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -80,7 +80,7 @@ LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:87:13
+  --> $DIR/borrow_interior_mutable_const.rs:88:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
    |             ^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:93:13
+  --> $DIR/borrow_interior_mutable_const.rs:94:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    |             ^^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:98:5
+  --> $DIR/borrow_interior_mutable_const.rs:99:5
    |
 LL |     CELL.set(2); //~ ERROR interior mutability
    |     ^^^^
@@ -104,7 +104,7 @@ LL |     CELL.set(2); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:99:16
+  --> $DIR/borrow_interior_mutable_const.rs:100:16
    |
 LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
    |                ^^^^
@@ -112,7 +112,7 @@ LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:112:5
+  --> $DIR/borrow_interior_mutable_const.rs:113:5
    |
 LL |     u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
    |     ^^^^^^^^^^^
@@ -120,7 +120,7 @@ LL |     u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/borrow_interior_mutable_const.rs:113:16
+  --> $DIR/borrow_interior_mutable_const.rs:114:16
    |
 LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
    |                ^^^^^^^^^^^
index 561283fc8e73de2b839d10dbf3d3fd22068d091c..efd4187947b201221058dbede468a1f1a76f841f 100644 (file)
@@ -135,4 +135,7 @@ fn main() {
             if truth() {}
         }
     }
+
+    // Fix #5962
+    if matches!(true, true) && matches!(true, true) {}
 }
index dc9d9b451c0f9620d9181936ebbc18bd58fa6a4f..657f32d38a32bc1a3714c8de089e6ade5a52c628 100644 (file)
@@ -149,4 +149,9 @@ fn truth() -> bool { true }
             if truth() {}
         }
     }
+
+    // Fix #5962
+    if matches!(true, true) {
+        if matches!(true, true) {}
+    }
 }
index f56dd65b9dd26c77144b24d0763ac472b739c238..acd1ec3f2caeaf6a924529a5f1d9307e8ca9075a 100644 (file)
@@ -118,5 +118,13 @@ LL |         println!("Hello world!");
 LL |     }
    |
 
-error: aborting due to 7 previous errors
+error: this `if` statement can be collapsed
+  --> $DIR/collapsible_if.rs:154:5
+   |
+LL | /     if matches!(true, true) {
+LL | |         if matches!(true, true) {}
+LL | |     }
+   | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed
new file mode 100644 (file)
index 0000000..d05567a
--- /dev/null
@@ -0,0 +1,106 @@
+// run-rustfix
+
+#![allow(unused_imports)]
+#![deny(clippy::default_trait_access)]
+
+use std::default;
+use std::default::Default as D2;
+use std::string;
+
+fn main() {
+    let s1: String = std::string::String::default();
+
+    let s2 = String::default();
+
+    let s3: String = std::string::String::default();
+
+    let s4: String = std::string::String::default();
+
+    let s5 = string::String::default();
+
+    let s6: String = std::string::String::default();
+
+    let s7 = std::string::String::default();
+
+    let s8: String = DefaultFactory::make_t_badly();
+
+    let s9: String = DefaultFactory::make_t_nicely();
+
+    let s10 = DerivedDefault::default();
+
+    let s11: GenericDerivedDefault<String> = GenericDerivedDefault::default();
+
+    let s12 = GenericDerivedDefault::<String>::default();
+
+    let s13 = TupleDerivedDefault::default();
+
+    let s14: TupleDerivedDefault = TupleDerivedDefault::default();
+
+    let s15: ArrayDerivedDefault = ArrayDerivedDefault::default();
+
+    let s16 = ArrayDerivedDefault::default();
+
+    let s17: TupleStructDerivedDefault = TupleStructDerivedDefault::default();
+
+    let s18 = TupleStructDerivedDefault::default();
+
+    let s19 = <DerivedDefault as Default>::default();
+
+    println!(
+        "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]",
+        s1,
+        s2,
+        s3,
+        s4,
+        s5,
+        s6,
+        s7,
+        s8,
+        s9,
+        s10,
+        s11,
+        s12,
+        s13,
+        s14,
+        s15,
+        s16,
+        s17,
+        s18,
+        s19,
+    );
+}
+
+struct DefaultFactory;
+
+impl DefaultFactory {
+    pub fn make_t_badly<T: Default>() -> T {
+        Default::default()
+    }
+
+    pub fn make_t_nicely<T: Default>() -> T {
+        T::default()
+    }
+}
+
+#[derive(Debug, Default)]
+struct DerivedDefault {
+    pub s: String,
+}
+
+#[derive(Debug, Default)]
+struct GenericDerivedDefault<T: Default + std::fmt::Debug> {
+    pub s: T,
+}
+
+#[derive(Debug, Default)]
+struct TupleDerivedDefault {
+    pub s: (String, String),
+}
+
+#[derive(Debug, Default)]
+struct ArrayDerivedDefault {
+    pub s: [String; 10],
+}
+
+#[derive(Debug, Default)]
+struct TupleStructDerivedDefault(String);
index 2f1490a70369e267a340f726fd9227cd3d9fe6b6..447e70c0bbbea74d9fbe5958e3f3aceb9c60a64c 100644 (file)
@@ -1,4 +1,7 @@
-#![warn(clippy::default_trait_access)]
+// run-rustfix
+
+#![allow(unused_imports)]
+#![deny(clippy::default_trait_access)]
 
 use std::default;
 use std::default::Default as D2;
index 26b2057548bd9e46b3dc94c7a6ff6366a30b33ce..df8a5b94ddcf3c81468744a3263fdd0b316964c5 100644 (file)
@@ -1,49 +1,53 @@
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:8:22
+  --> $DIR/default_trait_access.rs:11:22
    |
 LL |     let s1: String = Default::default();
    |                      ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
    |
-   = note: `-D clippy::default-trait-access` implied by `-D warnings`
+note: the lint level is defined here
+  --> $DIR/default_trait_access.rs:4:9
+   |
+LL | #![deny(clippy::default_trait_access)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:12:22
+  --> $DIR/default_trait_access.rs:15:22
    |
 LL |     let s3: String = D2::default();
    |                      ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:14:22
+  --> $DIR/default_trait_access.rs:17:22
    |
 LL |     let s4: String = std::default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:18:22
+  --> $DIR/default_trait_access.rs:21:22
    |
 LL |     let s6: String = default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
-error: calling `GenericDerivedDefault<std::string::String>::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:28:46
+error: calling `GenericDerivedDefault::default()` is more clear than this expression
+  --> $DIR/default_trait_access.rs:31:46
    |
 LL |     let s11: GenericDerivedDefault<String> = Default::default();
-   |                                              ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault<std::string::String>::default()`
+   |                                              ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()`
 
 error: calling `TupleDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:34:36
+  --> $DIR/default_trait_access.rs:37:36
    |
 LL |     let s14: TupleDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
 
 error: calling `ArrayDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:36:36
+  --> $DIR/default_trait_access.rs:39:36
    |
 LL |     let s15: ArrayDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
 
 error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:40:42
+  --> $DIR/default_trait_access.rs:43:42
    |
 LL |     let s17: TupleStructDerivedDefault = Default::default();
    |                                          ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
index 77620c857e66e2ca52e5f40fc0887eba94f0fd1e..68c5d32846f19b69887d21d0b8dcf8c2157d9100 100644 (file)
@@ -49,6 +49,16 @@ fn test_emphasis() {
 fn test_units() {
 }
 
+/// This tests allowed identifiers.
+/// DirectX
+/// ECMAScript
+/// OAuth GraphQL
+/// TeX LaTeX BibTeX BibLaTeX
+/// CamelCase (see also #2395)
+/// be_sure_we_got_to_the_end_of_it
+fn test_allowed() {
+}
+
 /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
 /// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
 /// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
@@ -168,9 +178,6 @@ fn issue_1920() {}
 /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
 fn issue_1832() {}
 
-/// Ok: CamelCase (It should not be surrounded by backticks)
-fn issue_2395() {}
-
 /// An iterator over mycrate::Collection's values.
 /// It should not lint a `'static` lifetime in ticks.
 fn issue_2210() {}
index ae9bb394cb9ac726bcca6129a5e7bb1c3349741d..23fca43590b4f5a11b85c810ee651e88af46fe4a 100644 (file)
@@ -54,131 +54,137 @@ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the doc
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
+  --> $DIR/doc.rs:58:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: you should put `link_with_underscores` between ticks in the documentation
-  --> $DIR/doc.rs:52:22
+  --> $DIR/doc.rs:62:22
    |
 LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
    |                      ^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `inline_link2` between ticks in the documentation
-  --> $DIR/doc.rs:55:21
+  --> $DIR/doc.rs:65:21
    |
 LL | /// It can also be [inline_link2].
    |                     ^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:65:5
+  --> $DIR/doc.rs:75:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `CamelCaseThing` between ticks in the documentation
-  --> $DIR/doc.rs:73:8
+  --> $DIR/doc.rs:83:8
    |
 LL | /// ## CamelCaseThing
    |        ^^^^^^^^^^^^^^
 
 error: you should put `CamelCaseThing` between ticks in the documentation
-  --> $DIR/doc.rs:76:7
+  --> $DIR/doc.rs:86:7
    |
 LL | /// # CamelCaseThing
    |       ^^^^^^^^^^^^^^
 
 error: you should put `CamelCaseThing` between ticks in the documentation
-  --> $DIR/doc.rs:78:22
+  --> $DIR/doc.rs:88:22
    |
 LL | /// Not a title #897 CamelCaseThing
    |                      ^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:79:5
+  --> $DIR/doc.rs:89:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:86:5
+  --> $DIR/doc.rs:96:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:99:5
+  --> $DIR/doc.rs:109:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `FooBar` between ticks in the documentation
-  --> $DIR/doc.rs:110:43
+  --> $DIR/doc.rs:120:43
    |
 LL | /** E.g., serialization of an empty list: FooBar
    |                                           ^^^^^^
 
 error: you should put `BarQuz` between ticks in the documentation
-  --> $DIR/doc.rs:115:5
+  --> $DIR/doc.rs:125:5
    |
 LL | And BarQuz too.
    |     ^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:116:1
+  --> $DIR/doc.rs:126:1
    |
 LL | be_sure_we_got_to_the_end_of_it
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `FooBar` between ticks in the documentation
-  --> $DIR/doc.rs:121:43
+  --> $DIR/doc.rs:131:43
    |
 LL | /** E.g., serialization of an empty list: FooBar
    |                                           ^^^^^^
 
 error: you should put `BarQuz` between ticks in the documentation
-  --> $DIR/doc.rs:126:5
+  --> $DIR/doc.rs:136:5
    |
 LL | And BarQuz too.
    |     ^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:127:1
+  --> $DIR/doc.rs:137:1
    |
 LL | be_sure_we_got_to_the_end_of_it
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:138:5
+  --> $DIR/doc.rs:148:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> $DIR/doc.rs:165:13
+  --> $DIR/doc.rs:175:13
    |
 LL | /// Not ok: http://www.unicode.org
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> $DIR/doc.rs:166:13
+  --> $DIR/doc.rs:176:13
    |
 LL | /// Not ok: https://www.unicode.org
    |             ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> $DIR/doc.rs:167:13
+  --> $DIR/doc.rs:177:13
    |
 LL | /// Not ok: http://www.unicode.org/
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> $DIR/doc.rs:168:13
+  --> $DIR/doc.rs:178:13
    |
 LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `mycrate::Collection` between ticks in the documentation
-  --> $DIR/doc.rs:174:22
+  --> $DIR/doc.rs:181:22
    |
 LL | /// An iterator over mycrate::Collection's values.
    |                      ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 30 previous errors
+error: aborting due to 31 previous errors
 
index c640c82d6d7c991e9df76d297118ea3de576a4cf..dc6c8ba2f154d8cfd52adedb40601973c0bd9de3 100644 (file)
@@ -1,4 +1,4 @@
-error: this function has a large number of lines
+error: this function has too many lines (102/100)
   --> $DIR/functions_maxlines.rs:58:1
    |
 LL | / fn bad_lines() {
index f497d5550af5f9cb9e6fdcafb18557db5a022b2a..586d13647d15eb94fe5cc580eb497794e01bb62a 100644 (file)
@@ -1,3 +1,3 @@
 fn main() {
-    println!("{}" a); //~ERROR expected token: `,`
+    println!("{}" a); //~ERROR expected `,`, found `a`
 }
index cb0d95f5e2643abab2cce9fb77323c2acd0c3778..a35032aa150dc96238b656957921e6688c55cbff 100644 (file)
@@ -1,7 +1,7 @@
-error: expected token: `,`
+error: expected `,`, found `a`
   --> $DIR/issue-3145.rs:2:19
    |
-LL |     println!("{}" a); //~ERROR expected token: `,`
+LL |     println!("{}" a); //~ERROR expected `,`, found `a`
    |                   ^ expected `,`
 
 error: aborting due to previous error
index 2c2d1e275893fae41e3965c9c4568f2afad8c6e8..e82873629a54b0de91ad1068fff7d552001fe81b 100644 (file)
@@ -137,9 +137,9 @@ pub fn new() -> *mut Self {
     }
 }
 
-struct MutPointerReturnerOk2;
+struct ConstPointerReturnerOk2;
 
-impl MutPointerReturnerOk2 {
+impl ConstPointerReturnerOk2 {
     // should not trigger lint
     pub fn new() -> *const Self {
         unimplemented!();
@@ -210,3 +210,133 @@ pub fn new<'b: 'a>(s: &'b str) -> WithLifetime<'b> {
         unimplemented!();
     }
 }
+
+mod issue5435 {
+    struct V;
+
+    pub trait TraitRetSelf {
+        // should not trigger lint
+        fn new() -> Self;
+    }
+
+    pub trait TraitRet {
+        // should trigger lint as we are in trait definition
+        fn new() -> String;
+    }
+    pub struct StructRet;
+    impl TraitRet for StructRet {
+        // should not trigger lint as we are in the impl block
+        fn new() -> String {
+            unimplemented!();
+        }
+    }
+
+    pub trait TraitRet2 {
+        // should trigger lint
+        fn new(_: String) -> String;
+    }
+
+    trait TupleReturnerOk {
+        // should not trigger lint
+        fn new() -> (Self, u32)
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+
+    trait TupleReturnerOk2 {
+        // should not trigger lint (it doesn't matter which element in the tuple is Self)
+        fn new() -> (u32, Self)
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+
+    trait TupleReturnerOk3 {
+        // should not trigger lint (tuple can contain multiple Self)
+        fn new() -> (Self, Self)
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+
+    trait TupleReturnerBad {
+        // should trigger lint
+        fn new() -> (u32, u32) {
+            unimplemented!();
+        }
+    }
+
+    trait MutPointerReturnerOk {
+        // should not trigger lint
+        fn new() -> *mut Self
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+
+    trait ConstPointerReturnerOk2 {
+        // should not trigger lint
+        fn new() -> *const Self
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+
+    trait MutPointerReturnerBad {
+        // should trigger lint
+        fn new() -> *mut V {
+            unimplemented!();
+        }
+    }
+
+    trait GenericReturnerOk {
+        // should not trigger lint
+        fn new() -> Option<Self>
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+
+    trait NestedReturnerOk {
+        // should not trigger lint
+        fn new() -> (Option<Self>, u32)
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+
+    trait NestedReturnerOk2 {
+        // should not trigger lint
+        fn new() -> ((Self, u32), u32)
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+
+    trait NestedReturnerOk3 {
+        // should not trigger lint
+        fn new() -> Option<(Self, u32)>
+        where
+            Self: Sized,
+        {
+            unimplemented!();
+        }
+    }
+}
index dd5a24bcbe7aed4c1ba4b792942ecac8f8cf9ea2..8217bc6187f93aa5cfce1ddbc5ce7ed4788b6173 100644 (file)
@@ -48,5 +48,33 @@ LL | |         unimplemented!();
 LL | |     }
    | |_____^
 
-error: aborting due to 6 previous errors
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:224:9
+   |
+LL |         fn new() -> String;
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:236:9
+   |
+LL |         fn new(_: String) -> String;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:271:9
+   |
+LL | /         fn new() -> (u32, u32) {
+LL | |             unimplemented!();
+LL | |         }
+   | |_________^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:298:9
+   |
+LL | /         fn new() -> *mut V {
+LL | |             unimplemented!();
+LL | |         }
+   | |_________^
+
+error: aborting due to 10 previous errors
 
index 1312c70b6d5929be6678ec97af153c78f7da93e1..d7d45ef9b0b334dd92827e6b92ce32f0e1c864b6 100644 (file)
@@ -1,4 +1,4 @@
-error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:38:5
    |
 LL |     x.field.map(do_nothing);
@@ -8,7 +8,7 @@ LL |     x.field.map(do_nothing);
    |
    = note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
 
-error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:40:5
    |
 LL |     x.field.map(do_nothing);
@@ -16,7 +16,7 @@ LL |     x.field.map(do_nothing);
    |     |
    |     help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
 
-error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:42:5
    |
 LL |     x.field.map(diverge);
@@ -24,7 +24,7 @@ LL |     x.field.map(diverge);
    |     |
    |     help: try this: `if let Some(x_field) = x.field { diverge(x_field) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:48:5
    |
 LL |     x.field.map(|value| x.do_option_nothing(value + captured));
@@ -32,7 +32,7 @@ LL |     x.field.map(|value| x.do_option_nothing(value + captured));
    |     |
    |     help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:50:5
    |
 LL |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
@@ -40,7 +40,7 @@ LL |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:53:5
    |
 LL |     x.field.map(|value| do_nothing(value + captured));
@@ -48,7 +48,7 @@ LL |     x.field.map(|value| do_nothing(value + captured));
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:55:5
    |
 LL |     x.field.map(|value| { do_nothing(value + captured) });
@@ -56,7 +56,7 @@ LL |     x.field.map(|value| { do_nothing(value + captured) });
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:57:5
    |
 LL |     x.field.map(|value| { do_nothing(value + captured); });
@@ -64,7 +64,7 @@ LL |     x.field.map(|value| { do_nothing(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:59:5
    |
 LL |     x.field.map(|value| { { do_nothing(value + captured); } });
@@ -72,7 +72,7 @@ LL |     x.field.map(|value| { { do_nothing(value + captured); } });
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:62:5
    |
 LL |     x.field.map(|value| diverge(value + captured));
@@ -80,7 +80,7 @@ LL |     x.field.map(|value| diverge(value + captured));
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:64:5
    |
 LL |     x.field.map(|value| { diverge(value + captured) });
@@ -88,7 +88,7 @@ LL |     x.field.map(|value| { diverge(value + captured) });
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:66:5
    |
 LL |     x.field.map(|value| { diverge(value + captured); });
@@ -96,7 +96,7 @@ LL |     x.field.map(|value| { diverge(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:68:5
    |
 LL |     x.field.map(|value| { { diverge(value + captured); } });
@@ -104,7 +104,7 @@ LL |     x.field.map(|value| { { diverge(value + captured); } });
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:73:5
    |
 LL |     x.field.map(|value| { let y = plus_one(value + captured); });
@@ -112,7 +112,7 @@ LL |     x.field.map(|value| { let y = plus_one(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:75:5
    |
 LL |     x.field.map(|value| { plus_one(value + captured); });
@@ -120,7 +120,7 @@ LL |     x.field.map(|value| { plus_one(value + captured); });
    |     |
    |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:77:5
    |
 LL |     x.field.map(|value| { { plus_one(value + captured); } });
@@ -128,7 +128,7 @@ LL |     x.field.map(|value| { { plus_one(value + captured); } });
    |     |
    |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
 
-error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:80:5
    |
 LL |     x.field.map(|ref value| { do_nothing(value + captured) });
@@ -136,7 +136,7 @@ LL |     x.field.map(|ref value| { do_nothing(value + captured) });
    |     |
    |     help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
   --> $DIR/option_map_unit_fn_fixable.rs:82:5
    |
 LL |     option().map(do_nothing);}
index 67faa8bd4a0aa1f8b2c5eb2a8f86f43df6fd2798..5fb568672d35638a4fb027c61ad6f8aef687c6d1 100644 (file)
@@ -58,12 +58,6 @@ fn or_fun_call() {
     let without_default = Some(Foo);
     without_default.unwrap_or_else(Foo::new);
 
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert_with(String::new);
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert_with(String::new);
-
     let stringy = Some(String::from(""));
     let _ = stringy.unwrap_or_else(|| "".to_owned());
 
@@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() {
         Some(42)
     }
     let _ = None.or(foo());
+
+    // See issue #5693.
+    let mut map = std::collections::HashMap::new();
+    map.insert(1, vec![1]);
+    map.entry(1).or_insert(vec![]);
+
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert(String::new());
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert(String::new());
 }
 
 fn main() {}
index 9867e2eedcff5253eaa86e20bbb24fabd9a046bd..737b0f7e55bc7a56773f0e9b63e64e2a0626b67e 100644 (file)
@@ -58,12 +58,6 @@ fn make<T>() -> T {
     let without_default = Some(Foo);
     without_default.unwrap_or(Foo::new());
 
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
-
     let stringy = Some(String::from(""));
     let _ = stringy.unwrap_or("".to_owned());
 
@@ -122,6 +116,17 @@ const fn foo() -> Option<i32> {
         Some(42)
     }
     let _ = None.or(foo());
+
+    // See issue #5693.
+    let mut map = std::collections::HashMap::new();
+    map.insert(1, vec![1]);
+    map.entry(1).or_insert(vec![]);
+
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert(String::new());
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert(String::new());
 }
 
 fn main() {}
index bc5978b538f16f69901c7d59576e840a95f95e23..b8a436993f329f3d6f608a228fcee774841b3249 100644 (file)
@@ -60,35 +60,23 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
 
-error: use of `or_insert` followed by a function call
-  --> $DIR/or_fun_call.rs:62:19
-   |
-LL |     map.entry(42).or_insert(String::new());
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
-
-error: use of `or_insert` followed by a function call
-  --> $DIR/or_fun_call.rs:65:21
-   |
-LL |     btree.entry(42).or_insert(String::new());
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
-
 error: use of `unwrap_or` followed by a function call
-  --> $DIR/or_fun_call.rs:68:21
+  --> $DIR/or_fun_call.rs:62:21
    |
 LL |     let _ = stringy.unwrap_or("".to_owned());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
 
 error: use of `or` followed by a function call
-  --> $DIR/or_fun_call.rs:93:35
+  --> $DIR/or_fun_call.rs:87:35
    |
 LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
 
 error: use of `or` followed by a function call
-  --> $DIR/or_fun_call.rs:97:10
+  --> $DIR/or_fun_call.rs:91:10
    |
 LL |         .or(Some(Bar(b, Duration::from_secs(2))));
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
 
-error: aborting due to 15 previous errors
+error: aborting due to 13 previous errors
 
index 467e00263cd3ae58ae9eeed948825e6f8c054da0..4f3a8c6b7923986359d770df58bdc6e530410983 100644 (file)
@@ -1,4 +1,4 @@
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:35:5
    |
 LL |     x.field.map(do_nothing);
@@ -8,7 +8,7 @@ LL |     x.field.map(do_nothing);
    |
    = note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
 
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:37:5
    |
 LL |     x.field.map(do_nothing);
@@ -16,7 +16,7 @@ LL |     x.field.map(do_nothing);
    |     |
    |     help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
 
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:39:5
    |
 LL |     x.field.map(diverge);
@@ -24,7 +24,7 @@ LL |     x.field.map(diverge);
    |     |
    |     help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:45:5
    |
 LL |     x.field.map(|value| x.do_result_nothing(value + captured));
@@ -32,7 +32,7 @@ LL |     x.field.map(|value| x.do_result_nothing(value + captured));
    |     |
    |     help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:47:5
    |
 LL |     x.field.map(|value| { x.do_result_plus_one(value + captured); });
@@ -40,7 +40,7 @@ LL |     x.field.map(|value| { x.do_result_plus_one(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:50:5
    |
 LL |     x.field.map(|value| do_nothing(value + captured));
@@ -48,7 +48,7 @@ LL |     x.field.map(|value| do_nothing(value + captured));
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:52:5
    |
 LL |     x.field.map(|value| { do_nothing(value + captured) });
@@ -56,7 +56,7 @@ LL |     x.field.map(|value| { do_nothing(value + captured) });
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:54:5
    |
 LL |     x.field.map(|value| { do_nothing(value + captured); });
@@ -64,7 +64,7 @@ LL |     x.field.map(|value| { do_nothing(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:56:5
    |
 LL |     x.field.map(|value| { { do_nothing(value + captured); } });
@@ -72,7 +72,7 @@ LL |     x.field.map(|value| { { do_nothing(value + captured); } });
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:59:5
    |
 LL |     x.field.map(|value| diverge(value + captured));
@@ -80,7 +80,7 @@ LL |     x.field.map(|value| diverge(value + captured));
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:61:5
    |
 LL |     x.field.map(|value| { diverge(value + captured) });
@@ -88,7 +88,7 @@ LL |     x.field.map(|value| { diverge(value + captured) });
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:63:5
    |
 LL |     x.field.map(|value| { diverge(value + captured); });
@@ -96,7 +96,7 @@ LL |     x.field.map(|value| { diverge(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:65:5
    |
 LL |     x.field.map(|value| { { diverge(value + captured); } });
@@ -104,7 +104,7 @@ LL |     x.field.map(|value| { { diverge(value + captured); } });
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:70:5
    |
 LL |     x.field.map(|value| { let y = plus_one(value + captured); });
@@ -112,7 +112,7 @@ LL |     x.field.map(|value| { let y = plus_one(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:72:5
    |
 LL |     x.field.map(|value| { plus_one(value + captured); });
@@ -120,7 +120,7 @@ LL |     x.field.map(|value| { plus_one(value + captured); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:74:5
    |
 LL |     x.field.map(|value| { { plus_one(value + captured); } });
@@ -128,7 +128,7 @@ LL |     x.field.map(|value| { { plus_one(value + captured); } });
    |     |
    |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_fixable.rs:77:5
    |
 LL |     x.field.map(|ref value| { do_nothing(value + captured) });
index b23cc608621d0fa3880ac27766d86d6349c5a76d..88e4efdb0f054dcf372f31e207f3ae3122ed8f2b 100644 (file)
@@ -1,4 +1,4 @@
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:23:5
    |
 LL |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
@@ -8,7 +8,7 @@ LL |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
    |
    = note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:25:5
    |
 LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
@@ -16,7 +16,7 @@ LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value)
    |     |
    |     help: try this: `if let Ok(value) = x.field { ... }`
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:29:5
    |
 LL |        x.field.map(|value| {
@@ -30,7 +30,7 @@ LL | ||     });
    | |_______|
    | 
 
-error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:33:5
    |
 LL |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
@@ -38,7 +38,7 @@ LL |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
    |     |
    |     help: try this: `if let Ok(value) = x.field { ... }`
 
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:37:5
    |
 LL |     "12".parse::<i32>().map(diverge);
@@ -46,7 +46,7 @@ LL |     "12".parse::<i32>().map(diverge);
    |     |
    |     help: try this: `if let Ok(a) = "12".parse::<i32>() { diverge(a) }`
 
-error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type
+error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
   --> $DIR/result_map_unit_fn_unfixable.rs:43:5
    |
 LL |     y.map(do_nothing);
index bfe27e020445c77b83c4ddfb14f773eb4ee36b85..a37c8782ec3300c58f887df041a048abf143159f 100644 (file)
@@ -1,5 +1,7 @@
 #![warn(clippy::same_item_push)]
 
+const VALUE: u8 = 7;
+
 fn mutate_increment(x: &mut u8) -> u8 {
     *x += 1;
     *x
@@ -9,65 +11,81 @@ fn increment(x: u8) -> u8 {
     x + 1
 }
 
-fn main() {
-    // Test for basic case
-    let mut spaces = Vec::with_capacity(10);
-    for _ in 0..10 {
-        spaces.push(vec![b' ']);
-    }
+fn fun() -> usize {
+    42
+}
 
-    let mut vec2: Vec<u8> = Vec::new();
+fn main() {
+    // ** linted cases **
+    let mut vec: Vec<u8> = Vec::new();
     let item = 2;
     for _ in 5..=20 {
-        vec2.push(item);
+        vec.push(item);
     }
 
-    let mut vec3: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for _ in 0..15 {
         let item = 2;
-        vec3.push(item);
+        vec.push(item);
     }
 
-    let mut vec4: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for _ in 0..15 {
-        vec4.push(13);
+        vec.push(13);
+    }
+
+    let mut vec = Vec::new();
+    for _ in 0..20 {
+        vec.push(VALUE);
+    }
+
+    let mut vec = Vec::new();
+    let item = VALUE;
+    for _ in 0..20 {
+        vec.push(item);
+    }
+
+    // ** non-linted cases **
+    let mut spaces = Vec::with_capacity(10);
+    for _ in 0..10 {
+        spaces.push(vec![b' ']);
     }
 
     // Suggestion should not be given as pushed variable can mutate
-    let mut vec5: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     let mut item: u8 = 2;
     for _ in 0..30 {
-        vec5.push(mutate_increment(&mut item));
+        vec.push(mutate_increment(&mut item));
     }
 
-    let mut vec6: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     let mut item: u8 = 2;
     let mut item2 = &mut mutate_increment(&mut item);
     for _ in 0..30 {
-        vec6.push(mutate_increment(item2));
+        vec.push(mutate_increment(item2));
     }
 
-    let mut vec7: Vec<usize> = Vec::new();
+    let mut vec: Vec<usize> = Vec::new();
     for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() {
-        vec7.push(a);
+        vec.push(a);
     }
 
-    let mut vec8: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for i in 0..30 {
-        vec8.push(increment(i));
+        vec.push(increment(i));
     }
 
-    let mut vec9: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for i in 0..30 {
-        vec9.push(i + i * i);
+        vec.push(i + i * i);
     }
 
     // Suggestion should not be given as there are multiple pushes that are not the same
-    let mut vec10: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     let item: u8 = 2;
     for _ in 0..30 {
-        vec10.push(item);
-        vec10.push(item * 2);
+        vec.push(item);
+        vec.push(item * 2);
     }
 
     // Suggestion should not be given as Vec is not involved
@@ -82,16 +100,52 @@ struct A {
     for i in 0..30 {
         vec_a.push(A { kind: i });
     }
-    let mut vec12: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     for a in vec_a {
-        vec12.push(2u8.pow(a.kind));
+        vec.push(2u8.pow(a.kind));
     }
 
     // Fix #5902
-    let mut vec13: Vec<u8> = Vec::new();
+    let mut vec: Vec<u8> = Vec::new();
     let mut item = 0;
     for _ in 0..10 {
-        vec13.push(item);
+        vec.push(item);
         item += 10;
     }
+
+    // Fix #5979
+    let mut vec: Vec<std::fs::File> = Vec::new();
+    for _ in 0..10 {
+        vec.push(std::fs::File::open("foobar").unwrap());
+    }
+    // Fix #5979
+    #[derive(Clone)]
+    struct S {}
+
+    trait T {}
+    impl T for S {}
+
+    let mut vec: Vec<Box<dyn T>> = Vec::new();
+    for _ in 0..10 {
+        vec.push(Box::new(S {}));
+    }
+
+    // Fix #5985
+    let mut vec = Vec::new();
+    let item = 42;
+    let item = fun();
+    for _ in 0..20 {
+        vec.push(item);
+    }
+
+    // Fix #5985
+    let mut vec = Vec::new();
+    let key = 1;
+    for _ in 0..20 {
+        let item = match key {
+            1 => 10,
+            _ => 0,
+        };
+        vec.push(item);
+    }
 }
index ddc5d48cd41357471b770872e2e4d05b33af3ab6..d9ffa15780ad004b17609a48ef8e241af1992c7e 100644 (file)
@@ -1,35 +1,43 @@
 error: it looks like the same item is being pushed into this Vec
-  --> $DIR/same_item_push.rs:16:9
+  --> $DIR/same_item_push.rs:23:9
    |
-LL |         spaces.push(vec![b' ']);
-   |         ^^^^^^
+LL |         vec.push(item);
+   |         ^^^
    |
    = note: `-D clippy::same-item-push` implied by `-D warnings`
-   = help: try using vec![vec![b' '];SIZE] or spaces.resize(NEW_SIZE, vec![b' '])
+   = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
 
 error: it looks like the same item is being pushed into this Vec
-  --> $DIR/same_item_push.rs:22:9
+  --> $DIR/same_item_push.rs:29:9
    |
-LL |         vec2.push(item);
-   |         ^^^^
+LL |         vec.push(item);
+   |         ^^^
    |
-   = help: try using vec![item;SIZE] or vec2.resize(NEW_SIZE, item)
+   = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
 
 error: it looks like the same item is being pushed into this Vec
-  --> $DIR/same_item_push.rs:28:9
+  --> $DIR/same_item_push.rs:34:9
    |
-LL |         vec3.push(item);
-   |         ^^^^
+LL |         vec.push(13);
+   |         ^^^
    |
-   = help: try using vec![item;SIZE] or vec3.resize(NEW_SIZE, item)
+   = help: try using vec![13;SIZE] or vec.resize(NEW_SIZE, 13)
 
 error: it looks like the same item is being pushed into this Vec
-  --> $DIR/same_item_push.rs:33:9
+  --> $DIR/same_item_push.rs:39:9
    |
-LL |         vec4.push(13);
-   |         ^^^^
+LL |         vec.push(VALUE);
+   |         ^^^
    |
-   = help: try using vec![13;SIZE] or vec4.resize(NEW_SIZE, 13)
+   = help: try using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE)
 
-error: aborting due to 4 previous errors
+error: it looks like the same item is being pushed into this Vec
+  --> $DIR/same_item_push.rs:45:9
+   |
+LL |         vec.push(item);
+   |         ^^^
+   |
+   = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
+
+error: aborting due to 5 previous errors
 
index c6c315d5fab5d359aa7378719722fdb9a8ead38c..ac4c1bc65979fb5f38661d3f8ac37487ef802e89 100644 (file)
@@ -53,11 +53,6 @@ fn main() {
     ArrayStruct { array: [0] }.array[0] = 1;
     (0, 0).0 = 1;
 
-    A.0 = 2;
-    B.field = 2;
-    C.structure.field = 2;
-    D.array[0] = 2;
-
     // no error
     s.field = 1;
     t.0 = 1;
index 4efe2d4bb6713625bd6b02fb299670e32e135155..7d79901a28d1be70a17f22f33806278c09b0e340 100644 (file)
@@ -28,29 +28,5 @@ error: assignment to temporary
 LL |     (0, 0).0 = 1;
    |     ^^^^^^^^^^^^
 
-error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:56:5
-   |
-LL |     A.0 = 2;
-   |     ^^^^^^^
-
-error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:57:5
-   |
-LL |     B.field = 2;
-   |     ^^^^^^^^^^^
-
-error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:58:5
-   |
-LL |     C.structure.field = 2;
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:59:5
-   |
-LL |     D.array[0] = 2;
-   |     ^^^^^^^^^^^^^^
-
-error: aborting due to 8 previous errors
+error: aborting due to 4 previous errors
 
index 0d8a322f2b2b0b7fa31f410c4af644409b1e0310..26b03bdc74055665d927efde9bbd8ae50ccd6f71 100644 (file)
@@ -51,4 +51,12 @@ fn transmute_ptr_to_ptr() {
     let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) };
 }
 
+// dereferencing raw pointers in const contexts, should not lint as it's unstable (issue 5959)
+const _: &() = {
+    struct ZST;
+    let zst = &ZST;
+
+    unsafe { std::mem::transmute::<&'static ZST, &'static ()>(zst) }
+};
+
 fn main() {}
index 2992abae775b8ffb438f5ae4e645899698a1302e..fec115ff29d6699cd82adafbf5d34dbcc1e25d3a 100644 (file)
@@ -1,5 +1,11 @@
 #![warn(clippy::unit_arg)]
-#![allow(clippy::no_effect, unused_must_use, unused_variables)]
+#![allow(
+    clippy::no_effect,
+    unused_must_use,
+    unused_variables,
+    clippy::unused_unit,
+    clippy::or_fun_call
+)]
 
 use std::fmt::Debug;
 
@@ -47,6 +53,11 @@ fn bad() {
             foo(3);
         },
     );
+    // here Some(foo(2)) isn't the top level statement expression, wrap the suggestion in a block
+    None.or(Some(foo(2)));
+    // in this case, the suggestion can be inlined, no need for a surrounding block
+    // foo(()); foo(()) instead of { foo(()); foo(()) }
+    foo(foo(()))
 }
 
 fn ok() {
index 56f6a855dfa554d725aa29f6cb3ba12cf5d58175..90fee3aab23b0c96cd3b8cff521f208ad8cff55d 100644 (file)
@@ -1,5 +1,5 @@
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:23:5
+  --> $DIR/unit_arg.rs:29:5
    |
 LL | /     foo({
 LL | |         1;
@@ -11,34 +11,28 @@ help: remove the semicolon from the last statement in the block
    |
 LL |         1
    |
-help: or move the expression in front of the call...
+help: or move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     {
 LL |         1;
 LL |     };
-   |
-help: ...and use a unit literal instead
-   |
 LL |     foo(());
-   |         ^^
+   |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:26:5
+  --> $DIR/unit_arg.rs:32:5
    |
 LL |     foo(foo(1));
    |     ^^^^^^^^^^^
    |
-help: move the expression in front of the call...
+help: move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     foo(1);
-   |
-help: ...and use a unit literal instead
-   |
 LL |     foo(());
-   |         ^^
+   |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:27:5
+  --> $DIR/unit_arg.rs:33:5
    |
 LL | /     foo({
 LL | |         foo(1);
@@ -50,20 +44,17 @@ help: remove the semicolon from the last statement in the block
    |
 LL |         foo(2)
    |
-help: or move the expression in front of the call...
+help: or move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     {
 LL |         foo(1);
 LL |         foo(2);
 LL |     };
-   |
-help: ...and use a unit literal instead
-   |
 LL |     foo(());
-   |         ^^
+   |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:32:5
+  --> $DIR/unit_arg.rs:38:5
    |
 LL | /     b.bar({
 LL | |         1;
@@ -74,35 +65,29 @@ help: remove the semicolon from the last statement in the block
    |
 LL |         1
    |
-help: or move the expression in front of the call...
+help: or move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     {
 LL |         1;
 LL |     };
-   |
-help: ...and use a unit literal instead
-   |
 LL |     b.bar(());
-   |           ^^
+   |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:35:5
+  --> $DIR/unit_arg.rs:41:5
    |
 LL |     taking_multiple_units(foo(0), foo(1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: move the expressions in front of the call...
+help: move the expressions in front of the call and replace them with the unit literal `()`
    |
 LL |     foo(0);
 LL |     foo(1);
-   |
-help: ...and use unit literals instead
-   |
 LL |     taking_multiple_units((), ());
-   |                           ^^  ^^
+   |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:36:5
+  --> $DIR/unit_arg.rs:42:5
    |
 LL | /     taking_multiple_units(foo(0), {
 LL | |         foo(1);
@@ -114,21 +99,18 @@ help: remove the semicolon from the last statement in the block
    |
 LL |         foo(2)
    |
-help: or move the expressions in front of the call...
+help: or move the expressions in front of the call and replace them with the unit literal `()`
    |
 LL |     foo(0);
 LL |     {
 LL |         foo(1);
 LL |         foo(2);
 LL |     };
-   |
-help: ...and use unit literals instead
-   |
 LL |     taking_multiple_units((), ());
-   |                           ^^  ^^
+   |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:40:5
+  --> $DIR/unit_arg.rs:46:5
    |
 LL | /     taking_multiple_units(
 LL | |         {
@@ -147,7 +129,7 @@ help: remove the semicolon from the last statement in the block
    |
 LL |             foo(3)
    |
-help: or move the expressions in front of the call...
+help: or move the expressions in front of the call and replace them with the unit literal `()`
    |
 LL |     {
 LL |         foo(0);
@@ -156,26 +138,44 @@ LL |     };
 LL |     {
 LL |         foo(2);
  ...
-help: ...and use unit literals instead
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:57:13
+   |
+LL |     None.or(Some(foo(2)));
+   |             ^^^^^^^^^^^^
    |
-LL |         (),
-LL |         (),
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL |     None.or({
+LL |         foo(2);
+LL |         Some(())
+LL |     });
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:82:5
+  --> $DIR/unit_arg.rs:60:5
    |
-LL |     Some(foo(1))
+LL |     foo(foo(()))
    |     ^^^^^^^^^^^^
    |
-help: move the expression in front of the call...
+help: move the expression in front of the call and replace it with the unit literal `()`
    |
-LL |     foo(1);
+LL |     foo(());
+LL |     foo(())
    |
-help: ...and use a unit literal instead
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:93:5
    |
+LL |     Some(foo(1))
+   |     ^^^^^^^^^^^^
+   |
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL |     foo(1);
 LL |     Some(())
-   |          ^^
+   |
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
index bb58483584b3e9bf419df2506de17a6d52c3b0cd..456b12a2c6b1654a7b18b2325603f740593ce8aa 100644 (file)
@@ -22,14 +22,11 @@ error: passing unit values to a function
 LL |     taking_two_units({}, foo(0));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: move the expression in front of the call...
+help: move the expression in front of the call and replace it with the unit literal `()`
    |
 LL |     foo(0);
-   |
-help: ...and use unit literals instead
-   |
 LL |     taking_two_units((), ());
-   |                      ^^  ^^
+   |
 
 error: passing unit values to a function
   --> $DIR/unit_arg_empty_blocks.rs:18:5
@@ -37,15 +34,12 @@ error: passing unit values to a function
 LL |     taking_three_units({}, foo(0), foo(1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: move the expressions in front of the call...
+help: move the expressions in front of the call and replace them with the unit literal `()`
    |
 LL |     foo(0);
 LL |     foo(1);
-   |
-help: ...and use unit literals instead
-   |
 LL |     taking_three_units((), (), ());
-   |                        ^^  ^^  ^^
+   |
 
 error: aborting due to 4 previous errors
 
index 31c2ba0f9c5893a21dcaba76b1675b4577746173..ad0d0387db03cb81b3fe8224beea7cb9b8162678 100644 (file)
@@ -25,17 +25,25 @@ fn unnecessary_sort_by() {
     vec.sort_by(|_, b| b.cmp(&5));
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
+
+    // Ignore vectors of references
+    let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
+    vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_by(|a, b| b.cmp(a));
+    vec.sort_unstable_by(|a, b| b.cmp(a));
 }
 
-// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162
+// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
 mod issue_5754 {
-    struct Test(String);
+    #[derive(Clone, Copy)]
+    struct Test(usize);
 
     #[derive(PartialOrd, Ord, PartialEq, Eq)]
-    struct Wrapper<'a>(&'a str);
+    struct Wrapper<'a>(&'a usize);
 
     impl Test {
-        fn name(&self) -> &str {
+        fn name(&self) -> &usize {
             &self.0
         }
 
@@ -60,7 +68,33 @@ mod issue_5754 {
     }
 }
 
+// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
+// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
+// not linted.
+mod issue_6001 {
+    struct Test(String);
+
+    impl Test {
+        // Return an owned type so that we don't hit the fix for 5754
+        fn name(&self) -> String {
+            self.0.clone()
+        }
+    }
+
+    pub fn test() {
+        let mut args: Vec<Test> = vec![];
+
+        // Forward
+        args.sort_by(|a, b| a.name().cmp(&b.name()));
+        args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
+        // Reverse
+        args.sort_by(|a, b| b.name().cmp(&a.name()));
+        args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
+    }
+}
+
 fn main() {
     unnecessary_sort_by();
     issue_5754::test();
+    issue_6001::test();
 }
index a3c8ae468ede73d15a42f79c61141b60aac38e46..9746f6e6849ddb46c632e498783c73f633418169 100644 (file)
@@ -25,17 +25,25 @@ fn id(x: isize) -> isize {
     vec.sort_by(|_, b| b.cmp(&5));
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
+
+    // Ignore vectors of references
+    let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
+    vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_by(|a, b| b.cmp(a));
+    vec.sort_unstable_by(|a, b| b.cmp(a));
 }
 
-// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162
+// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
 mod issue_5754 {
-    struct Test(String);
+    #[derive(Clone, Copy)]
+    struct Test(usize);
 
     #[derive(PartialOrd, Ord, PartialEq, Eq)]
-    struct Wrapper<'a>(&'a str);
+    struct Wrapper<'a>(&'a usize);
 
     impl Test {
-        fn name(&self) -> &str {
+        fn name(&self) -> &usize {
             &self.0
         }
 
@@ -60,7 +68,33 @@ pub fn test() {
     }
 }
 
+// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
+// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
+// not linted.
+mod issue_6001 {
+    struct Test(String);
+
+    impl Test {
+        // Return an owned type so that we don't hit the fix for 5754
+        fn name(&self) -> String {
+            self.0.clone()
+        }
+    }
+
+    pub fn test() {
+        let mut args: Vec<Test> = vec![];
+
+        // Forward
+        args.sort_by(|a, b| a.name().cmp(&b.name()));
+        args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
+        // Reverse
+        args.sort_by(|a, b| b.name().cmp(&a.name()));
+        args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
+    }
+}
+
 fn main() {
     unnecessary_sort_by();
     issue_5754::test();
+    issue_6001::test();
 }
index b222e2f7976d5a0b953fbeee44669608efff24ff..a5fcde768f18344ed7684116e0ce5f9aeeb52ee5 100644 (file)
@@ -49,6 +49,14 @@ mod a {
     pub use self::b::C;
 }
 
+// don't lint on clippy::wildcard_imports for `use` items
+#[allow(clippy::wildcard_imports)]
+pub use std::io::prelude::*;
+
+// don't lint on clippy::enum_glob_use for `use` items
+#[allow(clippy::enum_glob_use)]
+pub use std::cmp::Ordering::*;
+
 fn test_indented_attr() {
     #![allow(clippy::almost_swapped)]
     use std::collections::HashSet;
index 3422eace4ab97d81613ab2d27a3082fb174cd2ea..0396d39e3d54eff2151a4d43964c70cac8d86051 100644 (file)
@@ -49,6 +49,14 @@ pub struct C {}
     pub use self::b::C;
 }
 
+// don't lint on clippy::wildcard_imports for `use` items
+#[allow(clippy::wildcard_imports)]
+pub use std::io::prelude::*;
+
+// don't lint on clippy::enum_glob_use for `use` items
+#[allow(clippy::enum_glob_use)]
+pub use std::cmp::Ordering::*;
+
 fn test_indented_attr() {
     #[allow(clippy::almost_swapped)]
     use std::collections::HashSet;
index 57ba976730c172f2e2e06fb55decfb36ca8d9d01..d0194e4bbbe5b0a3133c130a8ccd30a80402fd59 100644 (file)
@@ -13,7 +13,7 @@ LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)`
 
 error: useless lint attribute
-  --> $DIR/useless_attribute.rs:53:5
+  --> $DIR/useless_attribute.rs:61:5
    |
 LL |     #[allow(clippy::almost_swapped)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(clippy::almost_swapped)]`