11use clippy_config:: types:: DisallowedPath ;
2- use clippy_utils:: diagnostics:: span_lint_and_then;
2+ use clippy_utils:: diagnostics:: { span_lint_and_then, span_lint_hir_and_then } ;
33use clippy_utils:: macros:: macro_backtrace;
44use rustc_ast:: Attribute ;
55use rustc_data_structures:: fx:: FxHashSet ;
6+ use rustc_errors:: Diagnostic ;
67use rustc_hir:: def_id:: DefIdMap ;
7- use rustc_hir:: { Expr , ExprKind , ForeignItem , HirId , ImplItem , Item , Pat , Path , Stmt , TraitItem , Ty } ;
8+ use rustc_hir:: {
9+ Expr , ExprKind , ForeignItem , HirId , ImplItem , Item , ItemKind , OwnerId , Pat , Path , Stmt , TraitItem , Ty ,
10+ } ;
811use rustc_lint:: { LateContext , LateLintPass } ;
912use rustc_session:: impl_lint_pass;
10- use rustc_span:: { ExpnId , Span } ;
13+ use rustc_span:: { ExpnId , MacroKind , Span } ;
1114
1215declare_clippy_lint ! {
1316 /// ### What it does
@@ -57,6 +60,10 @@ pub struct DisallowedMacros {
5760 conf_disallowed : Vec < DisallowedPath > ,
5861 disallowed : DefIdMap < usize > ,
5962 seen : FxHashSet < ExpnId > ,
63+
64+ // Track the most recently seen node that can have a `derive` attribute.
65+ // Needed to use the correct lint level.
66+ derive_src : Option < OwnerId > ,
6067}
6168
6269impl DisallowedMacros {
@@ -65,10 +72,11 @@ impl DisallowedMacros {
6572 conf_disallowed,
6673 disallowed : DefIdMap :: default ( ) ,
6774 seen : FxHashSet :: default ( ) ,
75+ derive_src : None ,
6876 }
6977 }
7078
71- fn check ( & mut self , cx : & LateContext < ' _ > , span : Span ) {
79+ fn check ( & mut self , cx : & LateContext < ' _ > , span : Span , derive_src : Option < OwnerId > ) {
7280 if self . conf_disallowed . is_empty ( ) {
7381 return ;
7482 }
@@ -80,18 +88,26 @@ impl DisallowedMacros {
8088
8189 if let Some ( & index) = self . disallowed . get ( & mac. def_id ) {
8290 let conf = & self . conf_disallowed [ index] ;
83-
84- span_lint_and_then (
85- cx,
86- DISALLOWED_MACROS ,
87- mac. span ,
88- & format ! ( "use of a disallowed macro `{}`" , conf. path( ) ) ,
89- |diag| {
90- if let Some ( reason) = conf. reason ( ) {
91- diag. note ( reason) ;
92- }
93- } ,
94- ) ;
91+ let msg = format ! ( "use of a disallowed macro `{}`" , conf. path( ) ) ;
92+ let add_note = |diag : & mut Diagnostic | {
93+ if let Some ( reason) = conf. reason ( ) {
94+ diag. note ( reason) ;
95+ }
96+ } ;
97+ if matches ! ( mac. kind, MacroKind :: Derive )
98+ && let Some ( derive_src) = derive_src
99+ {
100+ span_lint_hir_and_then (
101+ cx,
102+ DISALLOWED_MACROS ,
103+ cx. tcx . local_def_id_to_hir_id ( derive_src. def_id ) ,
104+ mac. span ,
105+ & msg,
106+ add_note,
107+ ) ;
108+ } else {
109+ span_lint_and_then ( cx, DISALLOWED_MACROS , mac. span , & msg, add_note) ;
110+ }
95111 }
96112 }
97113 }
@@ -110,49 +126,57 @@ impl LateLintPass<'_> for DisallowedMacros {
110126 }
111127
112128 fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
113- self . check ( cx, expr. span ) ;
129+ self . check ( cx, expr. span , None ) ;
114130 // `$t + $t` can have the context of $t, check also the span of the binary operator
115131 if let ExprKind :: Binary ( op, ..) = expr. kind {
116- self . check ( cx, op. span ) ;
132+ self . check ( cx, op. span , None ) ;
117133 }
118134 }
119135
120136 fn check_stmt ( & mut self , cx : & LateContext < ' _ > , stmt : & Stmt < ' _ > ) {
121- self . check ( cx, stmt. span ) ;
137+ self . check ( cx, stmt. span , None ) ;
122138 }
123139
124140 fn check_ty ( & mut self , cx : & LateContext < ' _ > , ty : & Ty < ' _ > ) {
125- self . check ( cx, ty. span ) ;
141+ self . check ( cx, ty. span , None ) ;
126142 }
127143
128144 fn check_pat ( & mut self , cx : & LateContext < ' _ > , pat : & Pat < ' _ > ) {
129- self . check ( cx, pat. span ) ;
145+ self . check ( cx, pat. span , None ) ;
130146 }
131147
132148 fn check_item ( & mut self , cx : & LateContext < ' _ > , item : & Item < ' _ > ) {
133- self . check ( cx, item. span ) ;
134- self . check ( cx, item. vis_span ) ;
149+ self . check ( cx, item. span , self . derive_src ) ;
150+ self . check ( cx, item. vis_span , None ) ;
151+
152+ if matches ! (
153+ item. kind,
154+ ItemKind :: Struct ( ..) | ItemKind :: Enum ( ..) | ItemKind :: Union ( ..)
155+ ) && macro_backtrace ( item. span ) . all ( |m| !matches ! ( m. kind, MacroKind :: Derive ) )
156+ {
157+ self . derive_src = Some ( item. owner_id ) ;
158+ }
135159 }
136160
137161 fn check_foreign_item ( & mut self , cx : & LateContext < ' _ > , item : & ForeignItem < ' _ > ) {
138- self . check ( cx, item. span ) ;
139- self . check ( cx, item. vis_span ) ;
162+ self . check ( cx, item. span , None ) ;
163+ self . check ( cx, item. vis_span , None ) ;
140164 }
141165
142166 fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , item : & ImplItem < ' _ > ) {
143- self . check ( cx, item. span ) ;
144- self . check ( cx, item. vis_span ) ;
167+ self . check ( cx, item. span , None ) ;
168+ self . check ( cx, item. vis_span , None ) ;
145169 }
146170
147171 fn check_trait_item ( & mut self , cx : & LateContext < ' _ > , item : & TraitItem < ' _ > ) {
148- self . check ( cx, item. span ) ;
172+ self . check ( cx, item. span , None ) ;
149173 }
150174
151175 fn check_path ( & mut self , cx : & LateContext < ' _ > , path : & Path < ' _ > , _: HirId ) {
152- self . check ( cx, path. span ) ;
176+ self . check ( cx, path. span , None ) ;
153177 }
154178
155179 fn check_attribute ( & mut self , cx : & LateContext < ' _ > , attr : & Attribute ) {
156- self . check ( cx, attr. span ) ;
180+ self . check ( cx, attr. span , self . derive_src ) ;
157181 }
158182}
0 commit comments