@@ -16,7 +16,8 @@ use rustc_abi::ExternAbi;
1616use rustc_ast as ast;
1717use rustc_ast:: AttrStyle ;
1818use rustc_ast:: ast:: {
19- AttrKind , Attribute , GenericArgs , IntTy , LitIntType , LitKind , StrStyle , TraitObjectSyntax , UintTy ,
19+ AttrKind , Attribute , GenericArgs , IntTy , LitIntType , LitKind , RangeLimits , StrStyle , StructExpr , TraitObjectSyntax ,
20+ UintTy ,
2021} ;
2122use rustc_ast:: token:: CommentKind ;
2223use rustc_hir:: intravisit:: FnKind ;
@@ -419,6 +420,22 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
419420 }
420421}
421422
423+ fn ast_path_search_pat ( path : & ast:: Path ) -> ( Pat , Pat ) {
424+ let ( head, tail) = match & * path. segments {
425+ [ ] => return ( Pat :: Str ( "" ) , Pat :: Str ( "" ) ) ,
426+ [ p] => ( Pat :: Sym ( p. ident . name ) , p) ,
427+ [ p, .., tail] => ( Pat :: Sym ( p. ident . name ) , tail) ,
428+ } ;
429+ (
430+ head,
431+ if tail. args . is_some ( ) {
432+ Pat :: Str ( ">" )
433+ } else {
434+ Pat :: Sym ( tail. ident . name )
435+ } ,
436+ )
437+ }
438+
422439fn ast_ty_search_pat ( ty : & ast:: Ty ) -> ( Pat , Pat ) {
423440 use ast:: { Extern , FnRetTy , MutTy , Safety , TraitObjectSyntax , TyKind } ;
424441
@@ -537,6 +554,167 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
537554 }
538555}
539556
557+ /// Get the search patterns to use for the given literal
558+ fn token_lit_search_pat ( lit : & ast:: token:: Lit ) -> ( Pat , Pat ) {
559+ use ast:: token:: LitKind ;
560+
561+ match lit. kind {
562+ LitKind :: Bool => ( Pat :: MultiStr ( & [ "true" , "false" ] ) , Pat :: MultiStr ( & [ "true" , "false" ] ) ) ,
563+ LitKind :: Byte => ( Pat :: Str ( "b'" ) , Pat :: Str ( "'" ) ) ,
564+ LitKind :: ByteStr => ( Pat :: Str ( "b\" " ) , Pat :: Str ( "\" " ) ) ,
565+ LitKind :: ByteStrRaw ( 0 ) => ( Pat :: Str ( "br\" " ) , Pat :: Str ( "\" " ) ) ,
566+ LitKind :: ByteStrRaw ( _) => ( Pat :: Str ( "br#" ) , Pat :: Str ( "#" ) ) ,
567+ LitKind :: CStr => ( Pat :: Str ( "c\" " ) , Pat :: Str ( "\" " ) ) ,
568+ LitKind :: CStrRaw ( 0 ) => ( Pat :: Str ( "cr\" " ) , Pat :: Str ( "\" " ) ) ,
569+ LitKind :: CStrRaw ( _) => ( Pat :: Str ( "cr#" ) , Pat :: Str ( "#" ) ) ,
570+ LitKind :: Char => ( Pat :: Str ( "'" ) , Pat :: Str ( "'" ) ) ,
571+ LitKind :: Float | LitKind :: Integer => ( Pat :: Sym ( lit. symbol ) , Pat :: Sym ( lit. suffix . unwrap_or ( lit. symbol ) ) ) ,
572+ LitKind :: Str => ( Pat :: Str ( "\" " ) , Pat :: Str ( "\" " ) ) ,
573+ LitKind :: StrRaw ( 0 ) => ( Pat :: Str ( "r" ) , Pat :: Str ( "\" " ) ) ,
574+ LitKind :: StrRaw ( _) => ( Pat :: Str ( "r#" ) , Pat :: Str ( "#" ) ) ,
575+ LitKind :: Err ( _) => ( Pat :: Str ( "" ) , Pat :: Str ( "" ) ) ,
576+ }
577+ }
578+
579+ /// Get the search patterns to use for the given expression
580+ #[ expect( clippy:: too_many_lines, reason = "just a big `match`" ) ]
581+ fn ast_expr_search_pat ( e : & ast:: Expr ) -> ( Pat , Pat ) {
582+ #[ expect( clippy:: too_many_lines, reason = "just a big `match`" ) ]
583+ fn inner ( e : & ast:: Expr , outer_span : Span ) -> ( Pat , Pat ) {
584+ use ast:: {
585+ Block , BlockCheckMode , CaptureBy , Closure , ExprKind , GenBlockKind , MatchKind , MethodCall , UnsafeSource ,
586+ YieldKind ,
587+ } ;
588+
589+ // The expression can have subexpressions in different contexts, in which case
590+ // building up a search pattern from the macro expansion would lead to false positives;
591+ // e.g. `return format!(..)` would be considered to be from a proc macro
592+ // if we build up a pattern for the macro expansion and compare it to the invocation `format!()`.
593+ // So instead we return an empty pattern such that `span_matches_pat` always returns true.
594+ if !e. span . eq_ctxt ( outer_span) {
595+ return ( Pat :: Str ( "" ) , Pat :: Str ( "" ) ) ;
596+ }
597+
598+ match & e. kind {
599+ ExprKind :: Underscore => ( Pat :: Str ( "_" ) , Pat :: Str ( "_" ) ) ,
600+ ExprKind :: ConstBlock ( _) => ( Pat :: Str ( "const" ) , Pat :: Str ( "}" ) ) ,
601+ ExprKind :: Unary ( UnOp :: Deref , e) => ( Pat :: Str ( "*" ) , inner ( e, outer_span) . 1 ) ,
602+ ExprKind :: Unary ( UnOp :: Not , e) => ( Pat :: Str ( "!" ) , inner ( e, outer_span) . 1 ) ,
603+ ExprKind :: Unary ( UnOp :: Neg , e) => ( Pat :: Str ( "-" ) , inner ( e, outer_span) . 1 ) ,
604+ ExprKind :: Lit ( lit) => token_lit_search_pat ( lit) ,
605+ // Parentheses are trimmed from the text before the search patterns are matched.
606+ // See: `span_matches_pat`
607+ ExprKind :: Paren ( e) => inner ( e, outer_span) ,
608+ ExprKind :: Array ( _) | ExprKind :: Repeat ( ..) => ( Pat :: Str ( "[" ) , Pat :: Str ( "]" ) ) ,
609+ ExprKind :: Range ( None , None , lims) => range_limits_search_pat ( * lims) ,
610+ ExprKind :: Range ( None , Some ( end) , lims) => ( range_limits_search_pat ( * lims) . 0 , inner ( end, outer_span) . 1 ) ,
611+ ExprKind :: Range ( Some ( start) , None , lims) => ( inner ( start, outer_span) . 0 , range_limits_search_pat ( * lims) . 1 ) ,
612+ ExprKind :: Call ( e, args)
613+ | ExprKind :: MethodCall ( box MethodCall {
614+ seg : _,
615+ receiver : e,
616+ args,
617+ span : _,
618+ } ) => (
619+ inner ( e, outer_span) . 0 ,
620+ // Parenthesis are trimmed from the text before the search patterns are matched.
621+ // See: `span_matches_pat`
622+ match & * * args {
623+ [ ] => Pat :: Str ( "(" ) ,
624+ [ .., last] => inner ( last, outer_span) . 1 ,
625+ } ,
626+ ) ,
627+ ExprKind :: Binary ( _, first, last)
628+ | ExprKind :: Assign ( first, last, _)
629+ | ExprKind :: AssignOp ( _, first, last)
630+ | ExprKind :: Range ( Some ( first) , Some ( last) , _) => {
631+ ( inner ( first, outer_span) . 0 , inner ( last, outer_span) . 1 )
632+ } ,
633+ ExprKind :: Tup ( tup) => {
634+ match & * * tup {
635+ // Parentheses are trimmed from the text before the search patterns are matched.
636+ // See: `span_matches_pat`
637+ [ ] => ( Pat :: Str ( ")" ) , Pat :: Str ( "(" ) ) ,
638+ [ e] => inner ( e, outer_span) ,
639+ [ first, .., last] => ( inner ( first, outer_span) . 0 , inner ( last, outer_span) . 1 ) ,
640+ }
641+ } ,
642+ ExprKind :: Cast ( e, _) | ExprKind :: Type ( e, _) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "" ) ) ,
643+ ExprKind :: Let ( _, init, _, _) => ( Pat :: Str ( "let" ) , inner ( init, outer_span) . 1 ) ,
644+ ExprKind :: If ( ..) => ( Pat :: Str ( "if" ) , Pat :: Str ( "}" ) ) ,
645+ ExprKind :: Loop ( _, Some ( _) , _)
646+ | ExprKind :: While ( _, _, Some ( _) )
647+ | ExprKind :: ForLoop { label : Some ( _) , .. }
648+ | ExprKind :: Block ( _, Some ( _) ) => ( Pat :: Str ( "'" ) , Pat :: Str ( "}" ) ) ,
649+ ExprKind :: Loop ( _, None , _) => ( Pat :: Str ( "loop" ) , Pat :: Str ( "}" ) ) ,
650+ ExprKind :: While ( _, _, None ) => ( Pat :: Str ( "while" ) , Pat :: Str ( "}" ) ) ,
651+ ExprKind :: ForLoop { label : None , .. } => ( Pat :: Str ( "for" ) , Pat :: Str ( "}" ) ) ,
652+ ExprKind :: Match ( _, _, MatchKind :: Prefix ) => ( Pat :: Str ( "match" ) , Pat :: Str ( "}" ) ) ,
653+ ExprKind :: Match ( e, _, MatchKind :: Postfix ) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "}" ) ) ,
654+ ExprKind :: Try ( e) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "?" ) ) ,
655+ ExprKind :: TryBlock ( _) => ( Pat :: Str ( "try" ) , Pat :: Str ( "}" ) ) ,
656+ ExprKind :: Await ( e, _) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "await" ) ) ,
657+ ExprKind :: Closure ( box Closure {
658+ capture_clause, body, ..
659+ } ) => {
660+ let start = match capture_clause {
661+ CaptureBy :: Value { .. } => "move" ,
662+ CaptureBy :: Use { .. } => "use" ,
663+ CaptureBy :: Ref => "|" ,
664+ } ;
665+ ( Pat :: Str ( start) , inner ( body, outer_span) . 1 )
666+ } ,
667+ ExprKind :: Gen ( _, _, GenBlockKind :: Async | GenBlockKind :: AsyncGen , _) => ( Pat :: Str ( "async" ) , Pat :: Str ( "" ) ) ,
668+ ExprKind :: Gen ( _, _, GenBlockKind :: Gen , _) => ( Pat :: Str ( "gen" ) , Pat :: Str ( "" ) ) ,
669+ ExprKind :: Block (
670+ box Block {
671+ rules : BlockCheckMode :: Unsafe ( UnsafeSource :: UserProvided ) ,
672+ ..
673+ } ,
674+ None ,
675+ ) => ( Pat :: Str ( "unsafe" ) , Pat :: Str ( "}" ) ) ,
676+ ExprKind :: Block ( _, None ) => ( Pat :: Str ( "{" ) , Pat :: Str ( "}" ) ) ,
677+ ExprKind :: Field ( e, name) => ( inner ( e, outer_span) . 0 , Pat :: Sym ( name. name ) ) ,
678+ ExprKind :: Index ( e, _, _) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "]" ) ) ,
679+ ExprKind :: Path ( None , path) => ast_path_search_pat ( path) ,
680+ ExprKind :: Path ( Some ( _) , path) => ( Pat :: Str ( "<" ) , ast_path_search_pat ( path) . 1 ) ,
681+ ExprKind :: AddrOf ( _, _, e) => ( Pat :: Str ( "&" ) , inner ( e, outer_span) . 1 ) ,
682+ ExprKind :: Break ( None , None ) => ( Pat :: Str ( "break" ) , Pat :: Str ( "break" ) ) ,
683+ ExprKind :: Break ( Some ( name) , None ) => ( Pat :: Str ( "break" ) , Pat :: Sym ( name. ident . name ) ) ,
684+ ExprKind :: Break ( _, Some ( e) ) => ( Pat :: Str ( "break" ) , inner ( e, outer_span) . 1 ) ,
685+ ExprKind :: Continue ( None ) => ( Pat :: Str ( "continue" ) , Pat :: Str ( "continue" ) ) ,
686+ ExprKind :: Continue ( Some ( name) ) => ( Pat :: Str ( "continue" ) , Pat :: Sym ( name. ident . name ) ) ,
687+ ExprKind :: Ret ( None ) => ( Pat :: Str ( "return" ) , Pat :: Str ( "return" ) ) ,
688+ ExprKind :: Ret ( Some ( e) ) => ( Pat :: Str ( "return" ) , inner ( e, outer_span) . 1 ) ,
689+ ExprKind :: Become ( e) => ( Pat :: Str ( "become" ) , inner ( e, outer_span) . 1 ) ,
690+ ExprKind :: Struct ( box StructExpr { path, .. } ) => ( ast_path_search_pat ( path) . 0 , Pat :: Str ( "" ) ) ,
691+ ExprKind :: Use ( e, _) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "use" ) ) ,
692+ ExprKind :: Yield ( YieldKind :: Prefix ( _) ) => ( Pat :: Str ( "yield" ) , Pat :: Str ( "" ) ) ,
693+ ExprKind :: Yield ( YieldKind :: Postfix ( _) ) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "" ) ) ,
694+ ExprKind :: OffsetOf ( ..)
695+ // Syntax unstable
696+ | ExprKind :: Yeet ( _) | ExprKind :: UnsafeBinderCast ( ..)
697+ // Don't have a good `Pat` for `ByteSymbol`s
698+ | ExprKind :: IncludedBytes ( _)
699+ // We don't know how qualified the path to the macro was
700+ | ExprKind :: FormatArgs ( _) | ExprKind :: InlineAsm ( ..)
701+ // Should've been expanded by now (?)
702+ | ExprKind :: MacCall ( ..)
703+ // Dummy/placeholder
704+ | ExprKind :: Err ( _) | ExprKind :: Dummy => ( Pat :: Str ( "" ) , Pat :: Str ( "" ) ) ,
705+ }
706+ }
707+
708+ inner ( e, e. span )
709+ }
710+
711+ fn range_limits_search_pat ( lims : RangeLimits ) -> ( Pat , Pat ) {
712+ match lims {
713+ RangeLimits :: HalfOpen => ( Pat :: Str ( ".." ) , Pat :: Str ( ".." ) ) ,
714+ RangeLimits :: Closed => ( Pat :: Str ( "..=" ) , Pat :: Str ( "..=" ) ) ,
715+ }
716+ }
717+
540718fn ident_search_pat ( ident : Ident ) -> ( Pat , Pat ) {
541719 ( Pat :: Sym ( ident. name ) , Pat :: Sym ( ident. name ) )
542720}
@@ -572,6 +750,7 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pa
572750
573751impl_with_search_pat ! ( ( _cx: EarlyContext <' tcx>, self : Attribute ) => attr_search_pat( self ) ) ;
574752impl_with_search_pat ! ( ( _cx: EarlyContext <' tcx>, self : ast:: Ty ) => ast_ty_search_pat( self ) ) ;
753+ impl_with_search_pat ! ( ( _cx: EarlyContext <' tcx>, self : ast:: Expr ) => ast_expr_search_pat( self ) ) ;
575754
576755impl < ' cx > WithSearchPat < ' cx > for ( & FnKind < ' cx > , & Body < ' cx > , HirId , Span ) {
577756 type Context = LateContext < ' cx > ;
0 commit comments