1414
1515use rustc_ast:: ast:: { IntTy , LitIntType , LitKind , StrStyle , UintTy } ;
1616use 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 ,
1820} ;
1921use rustc_lint:: { LateContext , LintContext } ;
2022use rustc_middle:: ty:: TyCtxt ;
2123use rustc_session:: Session ;
2224use rustc_span:: { Span , Symbol } ;
25+ use rustc_target:: spec:: abi:: Abi ;
2326
2427#[ derive( Clone , Copy ) ]
25- enum Pat {
28+ pub enum Pat {
2629 Str ( & ' static str ) ,
30+ MultiStr ( & ' static [ & ' static str ] ) ,
2731 Sym ( Symbol ) ,
2832 Num ,
2933}
@@ -42,10 +46,12 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
4246 let end_str = s. trim_end_matches ( |c : char | c. is_whitespace ( ) || c == ')' || c == ',' ) ;
4347 ( match start_pat {
4448 Pat :: Str ( text) => start_str. starts_with ( text) ,
49+ Pat :: MultiStr ( texts) => texts. iter ( ) . any ( |s| start_str. starts_with ( s) ) ,
4550 Pat :: Sym ( sym) => start_str. starts_with ( sym. as_str ( ) ) ,
4651 Pat :: Num => start_str. as_bytes ( ) . first ( ) . map_or ( false , u8:: is_ascii_digit) ,
4752 } && match end_pat {
4853 Pat :: Str ( text) => end_str. ends_with ( text) ,
54+ Pat :: MultiStr ( texts) => texts. iter ( ) . any ( |s| start_str. ends_with ( s) ) ,
4955 Pat :: Sym ( sym) => end_str. ends_with ( sym. as_str ( ) ) ,
5056 Pat :: Num => end_str. as_bytes ( ) . last ( ) . map_or ( false , u8:: is_ascii_hexdigit) ,
5157 } )
@@ -154,10 +160,121 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
154160 }
155161}
156162
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)
161278}
162279
163280/// Checks if the span actually refers to a match expression
0 commit comments