1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use rustc_data_structures:: fx:: FxHashMap ;
3
- use rustc_hir:: def:: Res ;
4
- use rustc_hir:: { Crate , Impl , ItemKind , Path , QPath , TyKind } ;
3
+ use rustc_hir:: def:: { DefKind , Res } ;
4
+ use rustc_hir:: { Crate , Impl , ItemKind , Node , Path , QPath , TraitRef , TyKind } ;
5
5
use rustc_lint:: { LateContext , LateLintPass } ;
6
+ use rustc_middle:: ty:: AssocKind ;
6
7
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
7
8
use rustc_span:: symbol:: SymbolStr ;
8
9
use rustc_span:: Span ;
9
- // use rustc_hir::Node;
10
- // use rustc_hir::TraitRef;
11
- // use rustc_hir::def::DefKind;
12
- // use rustc_middle::ty::AssocKind;
13
- use std:: collections:: BTreeMap ;
10
+ use std:: collections:: { BTreeMap , BTreeSet } ;
14
11
15
12
declare_clippy_lint ! {
16
13
/// ### What it does
@@ -65,39 +62,82 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
65
62
} ) = & item. kind
66
63
{
67
64
if let TyKind :: Path ( QPath :: Resolved ( _, Path { res, .. } ) ) = self_ty. kind {
65
+ if !mp. contains_key ( res) {
66
+ mp. insert (
67
+ * res,
68
+ S {
69
+ impl_methods : BTreeMap :: new ( ) ,
70
+ trait_methods : BTreeMap :: new ( ) ,
71
+ } ,
72
+ ) ;
73
+ }
74
+ let s = mp. get_mut ( res) . unwrap ( ) ;
75
+
68
76
match of_trait {
69
- Some ( _trait_ref) => {
77
+ Some ( trait_ref) => {
78
+ let mut methods_in_trait: BTreeSet < SymbolStr > = if_chain ! {
79
+ if let Some ( Node :: TraitRef ( TraitRef { path, .. } ) ) = cx. tcx. hir( ) . find( trait_ref. hir_ref_id) ;
80
+ if let Res :: Def ( DefKind :: Trait , did) = path. res;
81
+ then{
82
+ // FIXME: if
83
+ // `rustc_middle::ty::assoc::AssocItems::items` is public,
84
+ // we can iterate the keys, it's more
85
+ // efficient
86
+ cx. tcx
87
+ . associated_items( did)
88
+ . in_definition_order( )
89
+ . filter( |assoc_item| {
90
+ matches!( assoc_item. kind, AssocKind :: Fn )
91
+ } )
92
+ . map( |assoc_item| assoc_item. ident. as_str( ) )
93
+ . collect( )
94
+ } else{
95
+ BTreeSet :: new( )
96
+ }
97
+ } ;
98
+
70
99
for impl_item_ref in ( * items) . iter ( ) . filter ( |impl_item_ref| {
71
100
matches ! ( impl_item_ref. kind, rustc_hir:: AssocItemKind :: Fn { .. } )
72
101
} ) {
73
102
let method_name = impl_item_ref. ident . as_str ( ) ;
103
+ methods_in_trait. remove ( & method_name) ;
74
104
let trait_span = impl_item_ref. span ;
75
- if let Some ( s) = mp. get_mut ( res) {
76
- if let Some ( impl_span) = s. impl_methods . get ( & method_name) {
77
- span_lint_and_then (
78
- cx,
79
- SAME_NAME_METHOD ,
80
- * impl_span,
81
- "binding's name is same to an existing binding" ,
82
- |diag| {
83
- diag. span_note ( trait_span, "existing binding defined here" ) ;
84
- } ,
85
- ) ;
86
- }
87
- if let Some ( v) = s. trait_methods . get_mut ( & method_name) {
88
- v. push ( trait_span) ;
89
- } else {
90
- s. trait_methods . insert ( method_name, vec ! [ trait_span] ) ;
91
- }
105
+ if let Some ( impl_span) = s. impl_methods . get ( & method_name) {
106
+ span_lint_and_then (
107
+ cx,
108
+ SAME_NAME_METHOD ,
109
+ * impl_span,
110
+ "binding's name is same to an existing binding" ,
111
+ |diag| {
112
+ diag. span_note ( trait_span, "existing binding defined here" ) ;
113
+ } ,
114
+ ) ;
115
+ }
116
+ if let Some ( v) = s. trait_methods . get_mut ( & method_name) {
117
+ v. push ( trait_span) ;
92
118
} else {
93
- mp. insert (
94
- * res,
95
- S {
96
- impl_methods : BTreeMap :: new ( ) ,
97
- trait_methods : BTreeMap :: from ( [ ( method_name, vec ! [ trait_span] ) ] ) ,
119
+ s. trait_methods . insert ( method_name, vec ! [ trait_span] ) ;
120
+ }
121
+ }
122
+
123
+ let trait_span = item. span ;
124
+ for method_name in methods_in_trait {
125
+ if let Some ( impl_span) = s. impl_methods . get ( & method_name) {
126
+ span_lint_and_then (
127
+ cx,
128
+ SAME_NAME_METHOD ,
129
+ * impl_span,
130
+ "binding's name is same to an existing binding" ,
131
+ |diag| {
132
+ diag. span_note ( trait_span, "existing binding defined here" ) ;
98
133
} ,
99
134
) ;
100
135
}
136
+ if let Some ( v) = s. trait_methods . get_mut ( & method_name) {
137
+ v. push ( trait_span) ;
138
+ } else {
139
+ s. trait_methods . insert ( method_name, vec ! [ trait_span] ) ;
140
+ }
101
141
}
102
142
} ,
103
143
None => {
@@ -106,29 +146,19 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
106
146
} ) {
107
147
let method_name = impl_item_ref. ident . as_str ( ) ;
108
148
let impl_span = impl_item_ref. span ;
109
- if let Some ( s) = mp. get_mut ( res) {
110
- if let Some ( trait_spans) = s. trait_methods . get ( & method_name) {
111
- span_lint_and_then (
112
- cx,
113
- SAME_NAME_METHOD ,
114
- impl_span,
115
- "binding's name is same to an existing binding" ,
116
- |diag| {
117
- // TODO should we `span_note` on every trait?
118
- diag. span_note ( trait_spans[ 0 ] , "existing binding defined here" ) ;
119
- } ,
120
- ) ;
121
- }
122
- s. impl_methods . insert ( method_name, impl_span) ;
123
- } else {
124
- mp. insert (
125
- * res,
126
- S {
127
- impl_methods : BTreeMap :: from ( [ ( method_name, impl_span) ] ) ,
128
- trait_methods : BTreeMap :: new ( ) ,
149
+ if let Some ( trait_spans) = s. trait_methods . get ( & method_name) {
150
+ span_lint_and_then (
151
+ cx,
152
+ SAME_NAME_METHOD ,
153
+ impl_span,
154
+ "binding's name is same to an existing binding" ,
155
+ |diag| {
156
+ // TODO should we `span_note` on every trait?
157
+ diag. span_note ( trait_spans[ 0 ] , "existing binding defined here" ) ;
129
158
} ,
130
159
) ;
131
160
}
161
+ s. impl_methods . insert ( method_name, impl_span) ;
132
162
}
133
163
} ,
134
164
}
0 commit comments