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