Skip to content

Commit c57ab0c

Browse files
committed
Fix call site checking FPs
1 parent 5b1986c commit c57ab0c

File tree

2 files changed

+38
-26
lines changed

2 files changed

+38
-26
lines changed

clippy_lints/src/ambiguous_method_calls.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
66
use rustc_hir::intravisit::FnKind;
77
use rustc_hir::{Body, FnDecl};
88
use rustc_lint::{LateContext, LateLintPass};
9+
use rustc_middle::ty::Ty;
910
use rustc_session::{declare_lint_pass, declare_tool_lint};
1011
use rustc_span::def_id::LocalDefId;
1112
use rustc_span::symbol::Ident;
@@ -69,7 +70,7 @@ declare_clippy_lint! {
6970
#[clippy::version = "1.74.0"]
7071
pub AMBIGUOUS_METHOD_CALLS,
7172
pedantic,
72-
"same-named methods in struct impls and trait impls"
73+
"declarations and calls for same-named methods in struct impls and trait impls"
7374
}
7475
declare_lint_pass!(AmbiguousMethodCalls => [AMBIGUOUS_METHOD_CALLS]);
7576

@@ -86,25 +87,27 @@ impl<'tcx> LateLintPass<'tcx> for AmbiguousMethodCalls {
8687
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
8788
let is_trait_impl = is_trait_impl_item(cx, hir_id);
8889

89-
// Check methods in trait impls and struct impls
9090
if let FnKind::Method(ident, _) = kind {
91-
// FIXME: also keep track of the Ty of the struct for call site checking
92-
insert_method(is_trait_impl, ident);
91+
let parent_item = cx.tcx.hir().get_parent_item(hir_id).to_def_id();
92+
let parent_type = cx.tcx.type_of(parent_item).skip_binder();
93+
let parent_ty_str = format!("{parent_type}");
9394

94-
if has_ambiguous_name(ident) {
95+
insert_method(is_trait_impl, parent_type, ident);
96+
97+
if has_ambiguous_name(parent_type, ident) {
9598
let trait_methods = trait_methods().lock().unwrap();
9699
let struct_methods = struct_methods().lock().unwrap();
97100

98101
span_lint(
99102
cx,
100103
AMBIGUOUS_METHOD_CALLS,
101-
trait_methods.get(&ident.name).unwrap().span(),
104+
trait_methods.get(&(parent_ty_str.clone(), ident.name)).unwrap().span(),
102105
"ambiguous trait method name",
103106
);
104107
span_lint_and_help(
105108
cx,
106109
AMBIGUOUS_METHOD_CALLS,
107-
struct_methods.get(&ident.name).unwrap().span(),
110+
struct_methods.get(&(parent_ty_str, ident.name)).unwrap().span(),
108111
"ambiguous struct method name",
109112
None,
110113
"consider renaming the struct impl's method",
@@ -114,10 +117,15 @@ impl<'tcx> LateLintPass<'tcx> for AmbiguousMethodCalls {
114117
}
115118

116119
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'_>) {
117-
if let rustc_hir::ExprKind::MethodCall(path, _receiver, _, call_span) = &expr.kind {
120+
if let rustc_hir::ExprKind::MethodCall(path, receiver, _, call_span) = &expr.kind {
121+
let recv_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
122+
let recv_ty_str = format!("{recv_ty}");
123+
118124
let struct_methods = struct_methods().lock().unwrap();
119-
if struct_methods.contains_key(&path.ident.name) {
120-
// FIXME: only report after checking receiver's Ty
125+
let trait_methods = trait_methods().lock().unwrap();
126+
if struct_methods.contains_key(&(recv_ty_str.clone(), path.ident.name))
127+
&& trait_methods.contains_key(&(recv_ty_str, path.ident.name))
128+
{
121129
span_lint_and_help(
122130
cx,
123131
AMBIGUOUS_METHOD_CALLS,
@@ -131,30 +139,32 @@ impl<'tcx> LateLintPass<'tcx> for AmbiguousMethodCalls {
131139
}
132140
}
133141

134-
fn has_ambiguous_name(ident: Ident) -> bool {
142+
fn has_ambiguous_name<'tcx>(ty: Ty<'tcx>, ident: Ident) -> bool {
143+
let ty_str = format!("{ty}");
135144
let trait_methods = trait_methods().lock().unwrap();
136145
let struct_methods = struct_methods().lock().unwrap();
137146

138-
trait_methods.contains_key(&ident.name) && struct_methods.contains_key(&ident.name)
147+
trait_methods.contains_key(&(ty_str.clone(), ident.name)) && struct_methods.contains_key(&(ty_str, ident.name))
139148
}
140149

141-
fn trait_methods() -> &'static Mutex<FxHashMap<Symbol, SpanData>> {
142-
static NAMES: OnceLock<Mutex<FxHashMap<Symbol, SpanData>>> = OnceLock::new();
150+
fn trait_methods() -> &'static Mutex<FxHashMap<(String, Symbol), SpanData>> {
151+
static NAMES: OnceLock<Mutex<FxHashMap<(String, Symbol), SpanData>>> = OnceLock::new();
143152
NAMES.get_or_init(|| Mutex::new(FxHashMap::default()))
144153
}
145154

146-
fn struct_methods() -> &'static Mutex<FxHashMap<Symbol, SpanData>> {
147-
static NAMES: OnceLock<Mutex<FxHashMap<Symbol, SpanData>>> = OnceLock::new();
155+
fn struct_methods() -> &'static Mutex<FxHashMap<(String, Symbol), SpanData>> {
156+
static NAMES: OnceLock<Mutex<FxHashMap<(String, Symbol), SpanData>>> = OnceLock::new();
148157
NAMES.get_or_init(|| Mutex::new(FxHashMap::default()))
149158
}
150159

151-
fn insert_method(is_trait_impl: bool, ident: Ident) {
160+
fn insert_method<'tcx>(is_trait_impl: bool, ty: Ty<'tcx>, ident: Ident) {
161+
let ty_str = format!("{ty}");
152162
let mut trait_methods = trait_methods().lock().unwrap();
153163
let mut struct_methods = struct_methods().lock().unwrap();
154164

155165
if is_trait_impl {
156-
trait_methods.insert(ident.name, ident.span.data());
166+
trait_methods.insert((ty_str, ident.name), ident.span.data());
157167
} else {
158-
struct_methods.insert(ident.name, ident.span.data());
168+
struct_methods.insert((ty_str, ident.name), ident.span.data());
159169
}
160170
}

tests/ui/ambiguous_method_calls.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33

44
trait MyTrait {
55
fn ambiguous(&self);
6-
fn not_ambiguous(&self);
76
}
87

9-
struct Base {}
8+
struct Base;
109

1110
impl Base {
1211
fn ambiguous(&self) {
@@ -22,14 +21,17 @@ impl MyTrait for Base {
2221
fn ambiguous(&self) {
2322
println!("trait impl");
2423
}
24+
}
25+
26+
struct Other;
2527

26-
fn not_ambiguous(&self) {
27-
println!("not ambiguous trait impl");
28+
impl MyTrait for Other {
29+
fn ambiguous(&self) {
30+
println!("not actually ambiguous")
2831
}
2932
}
3033

3134
fn main() {
32-
let data = Base {};
33-
34-
data.ambiguous();
35+
Base.ambiguous();
36+
Other.ambiguous();
3537
}

0 commit comments

Comments
 (0)