1
1
use clippy_config:: types:: DisallowedPath ;
2
2
use clippy_utils:: diagnostics:: span_lint_and_then;
3
3
use clippy_utils:: { fn_def_id, get_parent_expr, path_def_id} ;
4
- use rustc_hir:: def_id:: DefIdMap ;
5
- use rustc_hir:: { Expr , ExprKind } ;
4
+ use itertools:: Itertools as _;
5
+ use rustc_data_structures:: unord:: UnordMap ;
6
+ use rustc_hir:: def:: Res ;
7
+ use rustc_hir:: def_id:: { DefId , DefIdMap } ;
8
+ use rustc_hir:: { Expr , ExprKind , PrimTy } ;
6
9
use rustc_lint:: { LateContext , LateLintPass } ;
10
+ use rustc_middle:: ty:: { self , AdtKind } ;
7
11
use rustc_session:: impl_lint_pass;
8
12
9
13
declare_clippy_lint ! {
@@ -59,13 +63,16 @@ declare_clippy_lint! {
59
63
pub struct DisallowedMethods {
60
64
conf_disallowed : Vec < DisallowedPath > ,
61
65
disallowed : DefIdMap < usize > ,
66
+ // (Self, TraitMethod)
67
+ disallowed_qualified_trait : UnordMap < ( Res , DefId ) , usize > ,
62
68
}
63
69
64
70
impl DisallowedMethods {
65
71
pub fn new ( conf_disallowed : Vec < DisallowedPath > ) -> Self {
66
72
Self {
67
73
conf_disallowed,
68
74
disallowed : DefIdMap :: default ( ) ,
75
+ disallowed_qualified_trait : UnordMap :: default ( ) ,
69
76
}
70
77
}
71
78
}
@@ -75,9 +82,31 @@ impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
75
82
impl < ' tcx > LateLintPass < ' tcx > for DisallowedMethods {
76
83
fn check_crate ( & mut self , cx : & LateContext < ' _ > ) {
77
84
for ( index, conf) in self . conf_disallowed . iter ( ) . enumerate ( ) {
78
- let segs: Vec < _ > = conf. path ( ) . split ( "::" ) . collect ( ) ;
79
- for id in clippy_utils:: def_path_def_ids ( cx, & segs) {
80
- self . disallowed . insert ( id, index) ;
85
+ let path = conf. path ( ) ;
86
+ if let Some ( path) = path. strip_prefix ( '<' ) {
87
+ // a qualified associated item
88
+ let Some ( ( tr, method) ) = path. split_once ( ">::" ) else {
89
+ continue ;
90
+ } ;
91
+ let Some ( ( self_ty, _as, trait_path) ) = tr. split_whitespace ( ) . next_tuple ( ) else {
92
+ continue ;
93
+ } ;
94
+ let self_segs: Vec < _ > = self_ty. split ( "::" ) . collect ( ) ;
95
+ let self_ress: Vec < _ > = clippy_utils:: def_path_res ( cx, & self_segs) ;
96
+ let mut method_segs: Vec < _ > = trait_path. split ( "::" ) . collect ( ) ;
97
+ method_segs. push ( method) ;
98
+ let method_id: Vec < _ > = clippy_utils:: def_path_def_ids ( cx, & method_segs) . collect ( ) ;
99
+ for self_res in & self_ress {
100
+ for method_id in & method_id {
101
+ self . disallowed_qualified_trait . insert ( ( * self_res, * method_id) , index) ;
102
+ }
103
+ }
104
+ } else {
105
+ // simple path
106
+ let segs: Vec < _ > = path. split ( "::" ) . collect ( ) ;
107
+ for id in clippy_utils:: def_path_def_ids ( cx, & segs) {
108
+ self . disallowed . insert ( id, index) ;
109
+ }
81
110
}
82
111
}
83
112
}
@@ -96,7 +125,35 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
96
125
} ;
97
126
let conf = match self . disallowed . get ( & def_id) {
98
127
Some ( & index) => & self . conf_disallowed [ index] ,
99
- None => return ,
128
+ None => match expr. kind {
129
+ ExprKind :: MethodCall ( _, self_arg, _, _) if !self . disallowed_qualified_trait . is_empty ( ) => {
130
+ let typeck = cx. typeck_results ( ) ;
131
+ let trait_method_def_id = typeck. type_dependent_def_id ( expr. hir_id ) . unwrap ( ) ;
132
+ let self_ty = typeck. expr_ty ( self_arg) ;
133
+ let self_res: Res < rustc_hir:: HirId > = match self_ty. kind ( ) {
134
+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) => {
135
+ Res :: PrimTy ( PrimTy :: from_name ( self_ty. primitive_symbol ( ) . unwrap ( ) ) . unwrap ( ) )
136
+ } ,
137
+ ty:: Str => Res :: PrimTy ( PrimTy :: Str ) ,
138
+ ty:: Adt ( adt, _) => Res :: Def (
139
+ match adt. adt_kind ( ) {
140
+ AdtKind :: Struct => rustc_hir:: def:: DefKind :: Struct ,
141
+ AdtKind :: Union => rustc_hir:: def:: DefKind :: Union ,
142
+ AdtKind :: Enum => rustc_hir:: def:: DefKind :: Enum ,
143
+ } ,
144
+ adt. did ( ) ,
145
+ ) ,
146
+ // FIXME: these other kinds are not currently supported by disallowed_methods due to how
147
+ // def_path_ref is implemented
148
+ _ => return ,
149
+ } ;
150
+ match self . disallowed_qualified_trait . get ( & ( self_res, trait_method_def_id) ) {
151
+ Some ( & index) => & self . conf_disallowed [ index] ,
152
+ None => return ,
153
+ }
154
+ } ,
155
+ _ => return ,
156
+ } ,
100
157
} ;
101
158
let msg = format ! ( "use of a disallowed method `{}`" , conf. path( ) ) ;
102
159
span_lint_and_then ( cx, DISALLOWED_METHODS , expr. span , & msg, |diag| {
0 commit comments