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