Look at adjusted types instead of fn signature types in ptr_arg
This commit is contained in:
parent
2b7d80b80a
commit
15495ebf42
@ -1,11 +1,9 @@
|
|||||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
|
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
|
||||||
use clippy_utils::source::SpanRangeExt;
|
use clippy_utils::source::SpanRangeExt;
|
||||||
use clippy_utils::ty::expr_sig;
|
|
||||||
use clippy_utils::visitors::contains_unsafe_block;
|
use clippy_utils::visitors::contains_unsafe_block;
|
||||||
use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local};
|
use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local};
|
||||||
use hir::LifetimeName;
|
use hir::LifetimeName;
|
||||||
use rustc_errors::{Applicability, MultiSpan};
|
use rustc_errors::{Applicability, MultiSpan};
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
use rustc_hir::hir_id::{HirId, HirIdMap};
|
use rustc_hir::hir_id::{HirId, HirIdMap};
|
||||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
@ -323,7 +321,6 @@ struct PtrArg<'tcx> {
|
|||||||
idx: usize,
|
idx: usize,
|
||||||
emission_id: HirId,
|
emission_id: HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
ty_did: DefId,
|
|
||||||
ty_name: Symbol,
|
ty_name: Symbol,
|
||||||
method_renames: &'static [(&'static str, &'static str)],
|
method_renames: &'static [(&'static str, &'static str)],
|
||||||
ref_prefix: RefPrefix,
|
ref_prefix: RefPrefix,
|
||||||
@ -411,7 +408,6 @@ fn display<'a>(&'a self, cx: &'a LateContext<'tcx>) -> DerefTyDisplay<'a, 'tcx>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::too_many_lines)]
|
|
||||||
fn check_fn_args<'cx, 'tcx: 'cx>(
|
fn check_fn_args<'cx, 'tcx: 'cx>(
|
||||||
cx: &'cx LateContext<'tcx>,
|
cx: &'cx LateContext<'tcx>,
|
||||||
fn_sig: ty::FnSig<'tcx>,
|
fn_sig: ty::FnSig<'tcx>,
|
||||||
@ -514,7 +510,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
|
|||||||
idx: i,
|
idx: i,
|
||||||
emission_id,
|
emission_id,
|
||||||
span: hir_ty.span,
|
span: hir_ty.span,
|
||||||
ty_did: adt.did(),
|
|
||||||
ty_name: name.ident.name,
|
ty_name: name.ident.name,
|
||||||
method_renames,
|
method_renames,
|
||||||
ref_prefix: RefPrefix { lt: *lt, mutability },
|
ref_prefix: RefPrefix { lt: *lt, mutability },
|
||||||
@ -610,65 +605,50 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
|||||||
set_skip_flag();
|
set_skip_flag();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some((Node::Expr(e), child_id)) => match e.kind {
|
Some((Node::Expr(use_expr), child_id)) => {
|
||||||
ExprKind::Call(f, expr_args) => {
|
if let ExprKind::Index(e, ..) = use_expr.kind
|
||||||
let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
|
&& e.hir_id == child_id
|
||||||
if expr_sig(self.cx, f).and_then(|sig| sig.input(i)).map_or(true, |ty| {
|
{
|
||||||
match *ty.skip_binder().peel_refs().kind() {
|
// Indexing works with both owned and its dereferenced type
|
||||||
ty::Dynamic(preds, _, _) => !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds),
|
return;
|
||||||
ty::Param(_) => true,
|
|
||||||
ty::Adt(def, _) => def.did() == args.ty_did,
|
|
||||||
_ => false,
|
|
||||||
}
|
}
|
||||||
}) {
|
|
||||||
// Passed to a function taking the non-dereferenced type.
|
if let ExprKind::MethodCall(name, receiver, ..) = use_expr.kind
|
||||||
set_skip_flag();
|
&& receiver.hir_id == child_id
|
||||||
}
|
{
|
||||||
},
|
|
||||||
ExprKind::MethodCall(name, self_arg, expr_args, _) => {
|
|
||||||
let i = iter::once(self_arg)
|
|
||||||
.chain(expr_args.iter())
|
|
||||||
.position(|arg| arg.hir_id == child_id)
|
|
||||||
.unwrap_or(0);
|
|
||||||
if i == 0 {
|
|
||||||
// Check if the method can be renamed.
|
|
||||||
let name = name.ident.as_str();
|
let name = name.ident.as_str();
|
||||||
|
|
||||||
|
// Check if the method can be renamed.
|
||||||
if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) {
|
if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) {
|
||||||
result.replacements.push(PtrArgReplacement {
|
result.replacements.push(PtrArgReplacement {
|
||||||
expr_span: e.span,
|
expr_span: use_expr.span,
|
||||||
self_span: self_arg.span,
|
self_span: receiver.span,
|
||||||
replacement,
|
replacement,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let Some(id) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) else {
|
// Some methods exist on both `[T]` and `Vec<T>`, such as `len`, where the receiver type
|
||||||
set_skip_flag();
|
// doesn't coerce to a slice and our adjusted type check below isn't enough,
|
||||||
|
// but it would still be valid to call with a slice
|
||||||
|
if is_allowed_vec_method(self.cx, use_expr) {
|
||||||
return;
|
return;
|
||||||
};
|
|
||||||
|
|
||||||
match *self.cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i]
|
|
||||||
.peel_refs()
|
|
||||||
.kind()
|
|
||||||
{
|
|
||||||
ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => {
|
|
||||||
set_skip_flag();
|
|
||||||
},
|
|
||||||
ty::Param(_) => {
|
|
||||||
set_skip_flag();
|
|
||||||
},
|
|
||||||
// If the types match check for methods which exist on both types. e.g. `Vec::len` and
|
|
||||||
// `slice::len`
|
|
||||||
ty::Adt(def, _) if def.did() == args.ty_did && !is_allowed_vec_method(self.cx, e) => {
|
|
||||||
set_skip_flag();
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
// Indexing is fine for currently supported types.
|
|
||||||
ExprKind::Index(e, _, _) if e.hir_id == child_id => (),
|
let deref_ty = args.deref_ty.ty(self.cx);
|
||||||
_ => set_skip_flag(),
|
let adjusted_ty = self.cx.typeck_results().expr_ty_adjusted(e).peel_refs();
|
||||||
|
if adjusted_ty == deref_ty {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ty::Dynamic(preds, ..) = adjusted_ty.kind()
|
||||||
|
&& matches_preds(self.cx, deref_ty, preds)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_skip_flag();
|
||||||
},
|
},
|
||||||
_ => set_skip_flag(),
|
_ => set_skip_flag(),
|
||||||
}
|
}
|
||||||
|
@ -309,3 +309,25 @@ trait T {
|
|||||||
extern "C" fn allowed(_v: &Vec<u32>) {}
|
extern "C" fn allowed(_v: &Vec<u32>) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod issue_13308 {
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
fn repro(source: &str, destination: &mut String) {
|
||||||
|
source.clone_into(destination);
|
||||||
|
}
|
||||||
|
fn repro2(source: &str, destination: &mut String) {
|
||||||
|
ToOwned::clone_into(source, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn h1(_: &<String as Deref>::Target) {}
|
||||||
|
fn h2<T: Deref>(_: T, _: &T::Target) {}
|
||||||
|
|
||||||
|
// Other cases that are still ok to lint and ideally shouldn't regress
|
||||||
|
fn good(v1: &String, v2: &String) {
|
||||||
|
//~^ ERROR: writing `&String` instead of `&str`
|
||||||
|
//~^^ ERROR: writing `&String` instead of `&str`
|
||||||
|
h1(v1);
|
||||||
|
h2(String::new(), v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -221,5 +221,17 @@ error: using a reference to `Cow` is not recommended
|
|||||||
LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
|
LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
|
||||||
| ^^^^^^^^^^^^^^^^ help: change this to: `&str`
|
| ^^^^^^^^^^^^^^^^ help: change this to: `&str`
|
||||||
|
|
||||||
error: aborting due to 25 previous errors
|
error: writing `&String` instead of `&str` involves a new object where a slice will do
|
||||||
|
--> tests/ui/ptr_arg.rs:327:17
|
||||||
|
|
|
||||||
|
LL | fn good(v1: &String, v2: &String) {
|
||||||
|
| ^^^^^^^ help: change this to: `&str`
|
||||||
|
|
||||||
|
error: writing `&String` instead of `&str` involves a new object where a slice will do
|
||||||
|
--> tests/ui/ptr_arg.rs:327:30
|
||||||
|
|
|
||||||
|
LL | fn good(v1: &String, v2: &String) {
|
||||||
|
| ^^^^^^^ help: change this to: `&str`
|
||||||
|
|
||||||
|
error: aborting due to 27 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user