@@ -69,11 +69,13 @@ use rustc_hir::def::{DefKind, Res};
6969use rustc_hir:: def_id:: DefId ;
7070use rustc_hir:: hir_id:: { HirIdMap , HirIdSet } ;
7171use rustc_hir:: intravisit:: { self , walk_expr, ErasedMap , FnKind , NestedVisitorMap , Visitor } ;
72+ use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
7273use rustc_hir:: LangItem :: { OptionNone , ResultErr , ResultOk } ;
7374use rustc_hir:: {
74- def, Arm , BindingAnnotation , Block , Body , Constness , Destination , Expr , ExprKind , FnDecl , GenericArgs , HirId , Impl ,
75- ImplItem , ImplItemKind , IsAsync , Item , ItemKind , LangItem , Local , MatchSource , Mutability , Node , Param , Pat ,
76- PatKind , Path , PathSegment , PrimTy , QPath , Stmt , StmtKind , TraitItem , TraitItemKind , TraitRef , TyKind , UnOp ,
75+ def, Arm , BindingAnnotation , Block , Body , Constness , Destination , Expr , ExprKind , FnDecl , ForeignItem , GenericArgs ,
76+ HirId , Impl , ImplItem , ImplItemKind , IsAsync , Item , ItemKind , LangItem , Local , MatchSource , Mutability , Node ,
77+ Param , Pat , PatKind , Path , PathSegment , PrimTy , QPath , Stmt , StmtKind , TraitItem , TraitItemKind , TraitRef , TyKind ,
78+ UnOp ,
7779} ;
7880use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
7981use rustc_middle:: hir:: exports:: Export ;
@@ -2064,16 +2066,72 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
20642066 false
20652067}
20662068
2067- /// Checks whether item either has `test` attribute applied, or
2068- /// is a module with `test` in its name.
2069- pub fn is_test_module_or_function ( tcx : TyCtxt < ' _ > , item : & Item < ' _ > ) -> bool {
2070- if let Some ( def_id) = tcx. hir ( ) . opt_local_def_id ( item. hir_id ( ) ) {
2071- if tcx. has_attr ( def_id. to_def_id ( ) , sym:: test) {
2072- return true ;
2069+ struct VisitConstTestStruct < ' tcx > {
2070+ tcx : TyCtxt < ' tcx > ,
2071+ names : Vec < Symbol > ,
2072+ found : bool ,
2073+ }
2074+ impl < ' hir > ItemLikeVisitor < ' hir > for VisitConstTestStruct < ' hir > {
2075+ fn visit_item ( & mut self , item : & Item < ' _ > ) {
2076+ if let ItemKind :: Const ( ty, _body) = item. kind {
2077+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = ty. kind {
2078+ // We could also check for the type name `test::TestDescAndFn`
2079+ // and the `#[rustc_test_marker]` attribute?
2080+ if let Res :: Def ( DefKind :: Struct , _) = path. res {
2081+ let has_test_marker = self
2082+ . tcx
2083+ . hir ( )
2084+ . attrs ( item. hir_id ( ) )
2085+ . iter ( )
2086+ . any ( |a| a. has_name ( sym:: rustc_test_marker) ) ;
2087+ if has_test_marker && self . names . contains ( & item. ident . name ) {
2088+ self . found = true ;
2089+ }
2090+ }
2091+ }
20732092 }
20742093 }
2094+ fn visit_trait_item ( & mut self , _: & TraitItem < ' _ > ) { }
2095+ fn visit_impl_item ( & mut self , _: & ImplItem < ' _ > ) { }
2096+ fn visit_foreign_item ( & mut self , _: & ForeignItem < ' _ > ) { }
2097+ }
20752098
2076- matches ! ( item. kind, ItemKind :: Mod ( ..) ) && item. ident . name . as_str ( ) . split ( '_' ) . any ( |a| a == "test" || a == "tests" )
2099+ /// Checks if the function containing the given `HirId` is a `#[test]` function
2100+ ///
2101+ /// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
2102+ pub fn is_in_test_function ( tcx : TyCtxt < ' _ > , id : hir:: HirId ) -> bool {
2103+ let names: Vec < _ > = tcx
2104+ . hir ( )
2105+ . parent_iter ( id)
2106+ // Since you can nest functions we need to collect all until we leave
2107+ // function scope
2108+ . filter_map ( |( _id, node) | {
2109+ if let Node :: Item ( item) = node {
2110+ if let ItemKind :: Fn ( _, _, _) = item. kind {
2111+ return Some ( item. ident . name ) ;
2112+ }
2113+ }
2114+ None
2115+ } )
2116+ . collect ( ) ;
2117+ let parent_mod = tcx. parent_module ( id) ;
2118+ let mut vis = VisitConstTestStruct {
2119+ tcx,
2120+ names,
2121+ found : false ,
2122+ } ;
2123+ tcx. hir ( ) . visit_item_likes_in_module ( parent_mod, & mut vis) ;
2124+ vis. found
2125+ }
2126+
2127+ /// Checks whether item either has `test` attribute appelied, or
2128+ /// is a module with `test` in its name.
2129+ ///
2130+ /// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
2131+ pub fn is_test_module_or_function ( tcx : TyCtxt < ' _ > , item : & Item < ' _ > ) -> bool {
2132+ is_in_test_function ( tcx, item. hir_id ( ) )
2133+ || matches ! ( item. kind, ItemKind :: Mod ( ..) )
2134+ && item. ident . name . as_str ( ) . split ( '_' ) . any ( |a| a == "test" || a == "tests" )
20772135}
20782136
20792137macro_rules! op_utils {
0 commit comments