Skip to content

Commit

Permalink
Auto merge of rust-lang#12976 - tesuji:fix-explicit_auto_deref, r=xFr…
Browse files Browse the repository at this point in the history
…ednet

Fix some false-positive cases of `explicit_auto_deref`

changelog: [`explicit_auto_deref`] Fix some false-positive cases

Fix part of rust-lang#9841
Fix  rust-lang#12969

r? xFrednet
  • Loading branch information
bors committed Jul 3, 2024
2 parents 918ae1b + c4c41d1 commit 0f4035f
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 12 deletions.
37 changes: 26 additions & 11 deletions clippy_lints/src/dereference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs};
use clippy_utils::{
expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy,
ExprUseNode,
};
use core::mem;
use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
Expand Down Expand Up @@ -175,13 +176,15 @@ struct StateData<'tcx> {
adjusted_ty: Ty<'tcx>,
}

#[derive(Debug)]
struct DerefedBorrow {
count: usize,
msg: &'static str,
stability: TyCoercionStability,
for_field_access: Option<Symbol>,
}

#[derive(Debug)]
enum State {
// Any number of deref method calls.
DerefMethod {
Expand Down Expand Up @@ -744,7 +747,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo
}
}

#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
enum TyCoercionStability {
Deref,
Reborrow,
Expand Down Expand Up @@ -1042,16 +1045,28 @@ fn report<'tcx>(
return;
}

let (prefix, precedence) = if let Some(mutability) = mutability
&& !typeck.expr_ty(expr).is_ref()
let ty = typeck.expr_ty(expr);

// `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst).
if let ty::Ref(_, dst, _) = data.adjusted_ty.kind()
&& dst.is_slice()
{
let prefix = match mutability {
Mutability::Not => "&",
Mutability::Mut => "&mut ",
};
(prefix, PREC_PREFIX)
} else {
("", 0)
let (src, n_src_refs) = peel_middle_ty_refs(ty);
if n_src_refs >= 2 && src.is_array() {
return;
}
}

let (prefix, precedence) = match mutability {
Some(mutability) if !ty.is_ref() => {
let prefix = match mutability {
Mutability::Not => "&",
Mutability::Mut => "&mut ",
};
(prefix, PREC_PREFIX)
},
None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0),
_ => ("", 0),
};
span_lint_hir_and_then(
cx,
Expand Down
11 changes: 11 additions & 0 deletions clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2492,6 +2492,17 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)
}
}

/// Peels off all references on the type. Returns the underlying type and the number of references
/// removed.
pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
let mut count = 0;
while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
ty = *dest_ty;
count += 1;
}
(ty, count)
}

/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
Expand Down
36 changes: 36 additions & 0 deletions tests/ui/explicit_auto_deref.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,39 @@ fn main() {
let _ = &mut ({ *x.u }).x;
}
}

mod issue_12969 {
use std::ops::Deref;

struct Wrapper<T>(T);

impl<T> Deref for Wrapper<T> {
type Target = T;

fn deref(&self) -> &T {
&self.0
}
}

fn foo(_bar: &str) {}

fn bar() {
let wrapped_bar = Wrapper("");

foo(&wrapped_bar);
}
}

mod issue_9841 {
fn takes_array_ref<T, const N: usize>(array: &&[T; N]) {
takes_slice(*array)
}

fn takes_array_ref_ref<T, const N: usize>(array: &&&[T; N]) {
takes_slice(**array)
}

fn takes_slice<T>(slice: &[T]) {
todo!()
}
}
36 changes: 36 additions & 0 deletions tests/ui/explicit_auto_deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,39 @@ fn main() {
let _ = &mut ({ *x.u }).x;
}
}

mod issue_12969 {
use std::ops::Deref;

struct Wrapper<T>(T);

impl<T> Deref for Wrapper<T> {
type Target = T;

fn deref(&self) -> &T {
&self.0
}
}

fn foo(_bar: &str) {}

fn bar() {
let wrapped_bar = Wrapper("");

foo(&*wrapped_bar);
}
}

mod issue_9841 {
fn takes_array_ref<T, const N: usize>(array: &&[T; N]) {
takes_slice(*array)
}

fn takes_array_ref_ref<T, const N: usize>(array: &&&[T; N]) {
takes_slice(**array)
}

fn takes_slice<T>(slice: &[T]) {
todo!()
}
}
8 changes: 7 additions & 1 deletion tests/ui/explicit_auto_deref.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -271,5 +271,11 @@ error: deref which would be done by auto-deref
LL | let _ = &mut (*{ x.u }).x;
| ^^^^^^^^^^ help: try: `{ x.u }`

error: aborting due to 45 previous errors
error: deref which would be done by auto-deref
--> tests/ui/explicit_auto_deref.rs:367:13
|
LL | foo(&*wrapped_bar);
| ^^^^^^^^^^^^^ help: try: `&wrapped_bar`

error: aborting due to 46 previous errors

0 comments on commit 0f4035f

Please sign in to comment.