11use clippy_config:: types:: DisallowedPath ;
22use clippy_utils:: diagnostics:: span_lint_and_then;
33use 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 } ;
69use rustc_lint:: { LateContext , LateLintPass } ;
10+ use rustc_middle:: ty:: { self , AdtKind } ;
711use rustc_session:: impl_lint_pass;
812
913declare_clippy_lint ! {
@@ -59,13 +63,16 @@ declare_clippy_lint! {
5963pub struct DisallowedMethods {
6064 conf_disallowed : Vec < DisallowedPath > ,
6165 disallowed : DefIdMap < usize > ,
66+ // (Self, TraitMethod)
67+ disallowed_qualified_trait : UnordMap < ( Res , DefId ) , usize > ,
6268}
6369
6470impl DisallowedMethods {
6571 pub fn new ( conf_disallowed : Vec < DisallowedPath > ) -> Self {
6672 Self {
6773 conf_disallowed,
6874 disallowed : DefIdMap :: default ( ) ,
75+ disallowed_qualified_trait : UnordMap :: default ( ) ,
6976 }
7077 }
7178}
@@ -75,9 +82,31 @@ impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
7582impl < ' tcx > LateLintPass < ' tcx > for DisallowedMethods {
7683 fn check_crate ( & mut self , cx : & LateContext < ' _ > ) {
7784 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+ }
81110 }
82111 }
83112 }
@@ -96,7 +125,35 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
96125 } ;
97126 let conf = match self . disallowed . get ( & def_id) {
98127 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+ } ,
100157 } ;
101158 let msg = format ! ( "use of a disallowed method `{}`" , conf. path( ) ) ;
102159 span_lint_and_then ( cx, DISALLOWED_METHODS , expr. span , & msg, |diag| {
0 commit comments