@@ -6,6 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
6
6
use rustc_hir:: intravisit:: FnKind ;
7
7
use rustc_hir:: { Body , FnDecl } ;
8
8
use rustc_lint:: { LateContext , LateLintPass } ;
9
+ use rustc_middle:: ty:: Ty ;
9
10
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10
11
use rustc_span:: def_id:: LocalDefId ;
11
12
use rustc_span:: symbol:: Ident ;
@@ -69,7 +70,7 @@ declare_clippy_lint! {
69
70
#[ clippy:: version = "1.74.0" ]
70
71
pub AMBIGUOUS_METHOD_CALLS ,
71
72
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"
73
74
}
74
75
declare_lint_pass ! ( AmbiguousMethodCalls => [ AMBIGUOUS_METHOD_CALLS ] ) ;
75
76
@@ -86,25 +87,27 @@ impl<'tcx> LateLintPass<'tcx> for AmbiguousMethodCalls {
86
87
let hir_id = cx. tcx . hir ( ) . local_def_id_to_hir_id ( def_id) ;
87
88
let is_trait_impl = is_trait_impl_item ( cx, hir_id) ;
88
89
89
- // Check methods in trait impls and struct impls
90
90
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}" ) ;
93
94
94
- if has_ambiguous_name ( ident) {
95
+ insert_method ( is_trait_impl, parent_type, ident) ;
96
+
97
+ if has_ambiguous_name ( parent_type, ident) {
95
98
let trait_methods = trait_methods ( ) . lock ( ) . unwrap ( ) ;
96
99
let struct_methods = struct_methods ( ) . lock ( ) . unwrap ( ) ;
97
100
98
101
span_lint (
99
102
cx,
100
103
AMBIGUOUS_METHOD_CALLS ,
101
- trait_methods. get ( & ident. name ) . unwrap ( ) . span ( ) ,
104
+ trait_methods. get ( & ( parent_ty_str . clone ( ) , ident. name ) ) . unwrap ( ) . span ( ) ,
102
105
"ambiguous trait method name" ,
103
106
) ;
104
107
span_lint_and_help (
105
108
cx,
106
109
AMBIGUOUS_METHOD_CALLS ,
107
- struct_methods. get ( & ident. name ) . unwrap ( ) . span ( ) ,
110
+ struct_methods. get ( & ( parent_ty_str , ident. name ) ) . unwrap ( ) . span ( ) ,
108
111
"ambiguous struct method name" ,
109
112
None ,
110
113
"consider renaming the struct impl's method" ,
@@ -114,10 +117,15 @@ impl<'tcx> LateLintPass<'tcx> for AmbiguousMethodCalls {
114
117
}
115
118
116
119
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
+
118
124
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
+ {
121
129
span_lint_and_help (
122
130
cx,
123
131
AMBIGUOUS_METHOD_CALLS ,
@@ -131,30 +139,32 @@ impl<'tcx> LateLintPass<'tcx> for AmbiguousMethodCalls {
131
139
}
132
140
}
133
141
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}" ) ;
135
144
let trait_methods = trait_methods ( ) . lock ( ) . unwrap ( ) ;
136
145
let struct_methods = struct_methods ( ) . lock ( ) . unwrap ( ) ;
137
146
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 ) )
139
148
}
140
149
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 ( ) ;
143
152
NAMES . get_or_init ( || Mutex :: new ( FxHashMap :: default ( ) ) )
144
153
}
145
154
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 ( ) ;
148
157
NAMES . get_or_init ( || Mutex :: new ( FxHashMap :: default ( ) ) )
149
158
}
150
159
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}" ) ;
152
162
let mut trait_methods = trait_methods ( ) . lock ( ) . unwrap ( ) ;
153
163
let mut struct_methods = struct_methods ( ) . lock ( ) . unwrap ( ) ;
154
164
155
165
if is_trait_impl {
156
- trait_methods. insert ( ident. name , ident. span . data ( ) ) ;
166
+ trait_methods. insert ( ( ty_str , ident. name ) , ident. span . data ( ) ) ;
157
167
} else {
158
- struct_methods. insert ( ident. name , ident. span . data ( ) ) ;
168
+ struct_methods. insert ( ( ty_str , ident. name ) , ident. span . data ( ) ) ;
159
169
}
160
170
}
0 commit comments