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