14
14
15
15
use rustc_ast:: ast:: { IntTy , LitIntType , LitKind , StrStyle , UintTy } ;
16
16
use rustc_hir:: {
17
- Block , BlockCheckMode , Destination , Expr , ExprKind , LoopSource , MatchSource , QPath , UnOp , UnsafeSource , YieldSource ,
17
+ Block , BlockCheckMode , Destination , Expr , ExprKind , FieldDef , FnHeader , Impl , ImplItem , ImplItemKind , IsAuto , Item ,
18
+ ItemKind , LoopSource , MatchSource , QPath , TraitItem , TraitItemKind , UnOp , UnsafeSource , Unsafety , Variant ,
19
+ VariantData , VisibilityKind , YieldSource ,
18
20
} ;
19
21
use rustc_lint:: { LateContext , LintContext } ;
20
22
use rustc_middle:: ty:: TyCtxt ;
21
23
use rustc_session:: Session ;
22
24
use rustc_span:: { Span , Symbol } ;
25
+ use rustc_target:: spec:: abi:: Abi ;
23
26
24
27
#[ derive( Clone , Copy ) ]
25
- enum Pat {
28
+ pub enum Pat {
26
29
Str ( & ' static str ) ,
30
+ MultiStr ( & ' static [ & ' static str ] ) ,
27
31
Sym ( Symbol ) ,
28
32
Num ,
29
33
}
@@ -42,10 +46,12 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
42
46
let end_str = s. trim_end_matches ( |c : char | c. is_whitespace ( ) || c == ')' || c == ',' ) ;
43
47
( match start_pat {
44
48
Pat :: Str ( text) => start_str. starts_with ( text) ,
49
+ Pat :: MultiStr ( texts) => texts. iter ( ) . any ( |s| start_str. starts_with ( s) ) ,
45
50
Pat :: Sym ( sym) => start_str. starts_with ( sym. as_str ( ) ) ,
46
51
Pat :: Num => start_str. as_bytes ( ) . first ( ) . map_or ( false , u8:: is_ascii_digit) ,
47
52
} && match end_pat {
48
53
Pat :: Str ( text) => end_str. ends_with ( text) ,
54
+ Pat :: MultiStr ( texts) => texts. iter ( ) . any ( |s| start_str. ends_with ( s) ) ,
49
55
Pat :: Sym ( sym) => end_str. ends_with ( sym. as_str ( ) ) ,
50
56
Pat :: Num => end_str. as_bytes ( ) . last ( ) . map_or ( false , u8:: is_ascii_hexdigit) ,
51
57
} )
@@ -154,10 +160,121 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
154
160
}
155
161
}
156
162
157
- /// Checks if the expression likely came from a proc-macro
158
- pub fn is_expr_from_proc_macro ( cx : & LateContext < ' _ > , e : & Expr < ' _ > ) -> bool {
159
- let ( start_pat, end_pat) = expr_search_pat ( cx. tcx , e) ;
160
- !span_matches_pat ( cx. sess ( ) , e. span , start_pat, end_pat)
163
+ fn fn_header_search_pat ( header : FnHeader ) -> Pat {
164
+ if header. is_async ( ) {
165
+ Pat :: Str ( "async" )
166
+ } else if header. is_const ( ) {
167
+ Pat :: Str ( "const" )
168
+ } else if header. is_unsafe ( ) {
169
+ Pat :: Str ( "unsafe" )
170
+ } else if header. abi != Abi :: Rust {
171
+ Pat :: Str ( "extern" )
172
+ } else {
173
+ Pat :: MultiStr ( & [ "fn" , "extern" ] )
174
+ }
175
+ }
176
+
177
+ fn item_search_pat ( item : & Item < ' _ > ) -> ( Pat , Pat ) {
178
+ let ( start_pat, end_pat) = match & item. kind {
179
+ ItemKind :: ExternCrate ( _) => ( Pat :: Str ( "extern" ) , Pat :: Str ( ";" ) ) ,
180
+ ItemKind :: Static ( ..) => ( Pat :: Str ( "static" ) , Pat :: Str ( ";" ) ) ,
181
+ ItemKind :: Const ( ..) => ( Pat :: Str ( "const" ) , Pat :: Str ( ";" ) ) ,
182
+ ItemKind :: Fn ( sig, ..) => ( fn_header_search_pat ( sig. header ) , Pat :: Str ( "" ) ) ,
183
+ ItemKind :: ForeignMod { .. } => ( Pat :: Str ( "extern" ) , Pat :: Str ( "}" ) ) ,
184
+ ItemKind :: TyAlias ( ..) | ItemKind :: OpaqueTy ( _) => ( Pat :: Str ( "type" ) , Pat :: Str ( ";" ) ) ,
185
+ ItemKind :: Enum ( ..) => ( Pat :: Str ( "enum" ) , Pat :: Str ( "}" ) ) ,
186
+ ItemKind :: Struct ( VariantData :: Struct ( ..) , _) => ( Pat :: Str ( "struct" ) , Pat :: Str ( "}" ) ) ,
187
+ ItemKind :: Struct ( ..) => ( Pat :: Str ( "struct" ) , Pat :: Str ( ";" ) ) ,
188
+ ItemKind :: Union ( ..) => ( Pat :: Str ( "union" ) , Pat :: Str ( "}" ) ) ,
189
+ ItemKind :: Trait ( _, Unsafety :: Unsafe , ..)
190
+ | ItemKind :: Impl ( Impl {
191
+ unsafety : Unsafety :: Unsafe ,
192
+ ..
193
+ } ) => ( Pat :: Str ( "unsafe" ) , Pat :: Str ( "}" ) ) ,
194
+ ItemKind :: Trait ( IsAuto :: Yes , ..) => ( Pat :: Str ( "auto" ) , Pat :: Str ( "}" ) ) ,
195
+ ItemKind :: Trait ( ..) => ( Pat :: Str ( "trait" ) , Pat :: Str ( "}" ) ) ,
196
+ ItemKind :: Impl ( _) => ( Pat :: Str ( "impl" ) , Pat :: Str ( "}" ) ) ,
197
+ _ => return ( Pat :: Str ( "" ) , Pat :: Str ( "" ) ) ,
198
+ } ;
199
+ if matches ! ( item. vis. node, VisibilityKind :: Inherited ) {
200
+ ( start_pat, end_pat)
201
+ } else {
202
+ ( Pat :: Str ( "pub" ) , end_pat)
203
+ }
204
+ }
205
+
206
+ fn trait_item_search_pat ( item : & TraitItem < ' _ > ) -> ( Pat , Pat ) {
207
+ match & item. kind {
208
+ TraitItemKind :: Const ( ..) => ( Pat :: Str ( "const" ) , Pat :: Str ( ";" ) ) ,
209
+ TraitItemKind :: Type ( ..) => ( Pat :: Str ( "type" ) , Pat :: Str ( ";" ) ) ,
210
+ TraitItemKind :: Fn ( sig, ..) => ( fn_header_search_pat ( sig. header ) , Pat :: Str ( "" ) ) ,
211
+ }
212
+ }
213
+
214
+ fn impl_item_search_pat ( item : & ImplItem < ' _ > ) -> ( Pat , Pat ) {
215
+ let ( start_pat, end_pat) = match & item. kind {
216
+ ImplItemKind :: Const ( ..) => ( Pat :: Str ( "const" ) , Pat :: Str ( ";" ) ) ,
217
+ ImplItemKind :: TyAlias ( ..) => ( Pat :: Str ( "type" ) , Pat :: Str ( ";" ) ) ,
218
+ ImplItemKind :: Fn ( sig, ..) => ( fn_header_search_pat ( sig. header ) , Pat :: Str ( "" ) ) ,
219
+ } ;
220
+ if matches ! ( item. vis. node, VisibilityKind :: Inherited ) {
221
+ ( start_pat, end_pat)
222
+ } else {
223
+ ( Pat :: Str ( "pub" ) , end_pat)
224
+ }
225
+ }
226
+
227
+ fn field_def_search_pat ( def : & FieldDef < ' _ > ) -> ( Pat , Pat ) {
228
+ if matches ! ( def. vis. node, VisibilityKind :: Inherited ) {
229
+ if def. is_positional ( ) {
230
+ ( Pat :: Str ( "" ) , Pat :: Str ( "" ) )
231
+ } else {
232
+ ( Pat :: Sym ( def. ident . name ) , Pat :: Str ( "" ) )
233
+ }
234
+ } else {
235
+ ( Pat :: Str ( "pub" ) , Pat :: Str ( "" ) )
236
+ }
237
+ }
238
+
239
+ fn variant_search_pat ( v : & Variant < ' _ > ) -> ( Pat , Pat ) {
240
+ match v. data {
241
+ VariantData :: Struct ( ..) => ( Pat :: Sym ( v. ident . name ) , Pat :: Str ( "}" ) ) ,
242
+ VariantData :: Tuple ( ..) => ( Pat :: Sym ( v. ident . name ) , Pat :: Str ( "" ) ) ,
243
+ VariantData :: Unit ( ..) => ( Pat :: Sym ( v. ident . name ) , Pat :: Sym ( v. ident . name ) ) ,
244
+ }
245
+ }
246
+
247
+ pub trait WithSearchPat {
248
+ type Context : LintContext ;
249
+ fn search_pat ( & self , cx : & Self :: Context ) -> ( Pat , Pat ) ;
250
+ fn span ( & self ) -> Span ;
251
+ }
252
+ macro_rules! impl_with_search_pat {
253
+ ( $cx: ident: $ty: ident with $fn: ident $( ( $tcx: ident) ) ?) => {
254
+ impl <' cx> WithSearchPat for $ty<' cx> {
255
+ type Context = $cx<' cx>;
256
+ #[ allow( unused_variables) ]
257
+ fn search_pat( & self , cx: & Self :: Context ) -> ( Pat , Pat ) {
258
+ $( let $tcx = cx. tcx; ) ?
259
+ $fn( $( $tcx, ) ? self )
260
+ }
261
+ fn span( & self ) -> Span {
262
+ self . span
263
+ }
264
+ }
265
+ } ;
266
+ }
267
+ impl_with_search_pat ! ( LateContext : Expr with expr_search_pat( tcx) ) ;
268
+ impl_with_search_pat ! ( LateContext : Item with item_search_pat) ;
269
+ impl_with_search_pat ! ( LateContext : TraitItem with trait_item_search_pat) ;
270
+ impl_with_search_pat ! ( LateContext : ImplItem with impl_item_search_pat) ;
271
+ impl_with_search_pat ! ( LateContext : FieldDef with field_def_search_pat) ;
272
+ impl_with_search_pat ! ( LateContext : Variant with variant_search_pat) ;
273
+
274
+ /// Checks if the item likely came from a proc-macro
275
+ pub fn is_from_proc_macro < T : WithSearchPat > ( cx : & T :: Context , item : & T ) -> bool {
276
+ let ( start_pat, end_pat) = item. search_pat ( cx) ;
277
+ !span_matches_pat ( cx. sess ( ) , item. span ( ) , start_pat, end_pat)
161
278
}
162
279
163
280
/// Checks if the span actually refers to a match expression
0 commit comments