@@ -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,165 @@ 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+ ExprKind :: Paren ( e) => inner ( e, outer_span) ,
606+ ExprKind :: Array ( _) | ExprKind :: Repeat ( ..) => ( Pat :: Str ( "[" ) , Pat :: Str ( "]" ) ) ,
607+ ExprKind :: Range ( None , None , lims) => range_limits_search_pat ( * lims) ,
608+ ExprKind :: Range ( None , Some ( end) , lims) => ( range_limits_search_pat ( * lims) . 0 , inner ( end, outer_span) . 1 ) ,
609+ ExprKind :: Range ( Some ( start) , None , lims) => ( inner ( start, outer_span) . 0 , range_limits_search_pat ( * lims) . 1 ) ,
610+ ExprKind :: Call ( e, args)
611+ | ExprKind :: MethodCall ( box MethodCall {
612+ seg : _,
613+ receiver : e,
614+ args,
615+ span : _,
616+ } ) => (
617+ inner ( e, outer_span) . 0 ,
618+ // Parenthesis are trimmed from the text before the search patterns are matched.
619+ // See: `span_matches_pat`
620+ match & * * args {
621+ [ ] => Pat :: Str ( "(" ) ,
622+ [ .., last] => inner ( last, outer_span) . 1 ,
623+ } ,
624+ ) ,
625+ ExprKind :: Binary ( _, first, last)
626+ | ExprKind :: Assign ( first, last, _)
627+ | ExprKind :: AssignOp ( _, first, last)
628+ | ExprKind :: Range ( Some ( first) , Some ( last) , _) => {
629+ ( inner ( first, outer_span) . 0 , inner ( last, outer_span) . 1 )
630+ } ,
631+ ExprKind :: Tup ( tup) => {
632+ match & * * tup {
633+ // Parentheses are trimmed from the text before the search patterns are matched.
634+ // See: `span_matches_pat`
635+ [ ] => ( Pat :: Str ( ")" ) , Pat :: Str ( "(" ) ) ,
636+ [ e] => inner ( e, outer_span) ,
637+ [ first, .., last] => ( inner ( first, outer_span) . 0 , inner ( last, outer_span) . 1 ) ,
638+ }
639+ } ,
640+ ExprKind :: Cast ( e, _) | ExprKind :: Type ( e, _) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "" ) ) ,
641+ ExprKind :: Let ( _, init, _, _) => ( Pat :: Str ( "let" ) , inner ( init, outer_span) . 1 ) ,
642+ ExprKind :: If ( ..) => ( Pat :: Str ( "if" ) , Pat :: Str ( "}" ) ) ,
643+ ExprKind :: Loop ( _, Some ( _) , _)
644+ | ExprKind :: While ( _, _, Some ( _) )
645+ | ExprKind :: ForLoop { label : Some ( _) , .. }
646+ | ExprKind :: Block ( _, Some ( _) ) => ( Pat :: Str ( "'" ) , Pat :: Str ( "}" ) ) ,
647+ ExprKind :: Loop ( _, None , _) => ( Pat :: Str ( "loop" ) , Pat :: Str ( "}" ) ) ,
648+ ExprKind :: While ( _, _, None ) => ( Pat :: Str ( "while" ) , Pat :: Str ( "}" ) ) ,
649+ ExprKind :: ForLoop { label : None , .. } => ( Pat :: Str ( "for" ) , Pat :: Str ( "}" ) ) ,
650+ ExprKind :: Match ( _, _, MatchKind :: Prefix ) => ( Pat :: Str ( "match" ) , Pat :: Str ( "}" ) ) ,
651+ ExprKind :: Match ( e, _, MatchKind :: Postfix ) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "}" ) ) ,
652+ ExprKind :: Try ( e) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "?" ) ) ,
653+ ExprKind :: TryBlock ( _) => ( Pat :: Str ( "try" ) , Pat :: Str ( "}" ) ) ,
654+ ExprKind :: Await ( e, _) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "await" ) ) ,
655+ ExprKind :: Closure ( box Closure {
656+ capture_clause, body, ..
657+ } ) => {
658+ let start = match capture_clause {
659+ CaptureBy :: Value { .. } => "move" ,
660+ CaptureBy :: Use { .. } => "use" ,
661+ CaptureBy :: Ref => "|" ,
662+ } ;
663+ ( Pat :: Str ( start) , inner ( body, outer_span) . 1 )
664+ } ,
665+ ExprKind :: Gen ( _, _, GenBlockKind :: Async | GenBlockKind :: AsyncGen , _) => ( Pat :: Str ( "async" ) , Pat :: Str ( "" ) ) ,
666+ ExprKind :: Gen ( _, _, GenBlockKind :: Gen , _) => ( Pat :: Str ( "gen" ) , Pat :: Str ( "" ) ) ,
667+ ExprKind :: Block (
668+ box Block {
669+ rules : BlockCheckMode :: Unsafe ( UnsafeSource :: UserProvided ) ,
670+ ..
671+ } ,
672+ None ,
673+ ) => ( Pat :: Str ( "unsafe" ) , Pat :: Str ( "}" ) ) ,
674+ ExprKind :: Block ( _, None ) => ( Pat :: Str ( "{" ) , Pat :: Str ( "}" ) ) ,
675+ ExprKind :: Field ( e, name) => ( inner ( e, outer_span) . 0 , Pat :: Sym ( name. name ) ) ,
676+ ExprKind :: Index ( e, _, _) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "]" ) ) ,
677+ ExprKind :: Path ( None , path) => ast_path_search_pat ( path) ,
678+ ExprKind :: Path ( Some ( _) , path) => ( Pat :: Str ( "<" ) , ast_path_search_pat ( path) . 1 ) ,
679+ ExprKind :: AddrOf ( _, _, e) => ( Pat :: Str ( "&" ) , inner ( e, outer_span) . 1 ) ,
680+ ExprKind :: Break ( None , None ) => ( Pat :: Str ( "break" ) , Pat :: Str ( "break" ) ) ,
681+ ExprKind :: Break ( Some ( name) , None ) => ( Pat :: Str ( "break" ) , Pat :: Sym ( name. ident . name ) ) ,
682+ ExprKind :: Break ( _, Some ( e) ) => ( Pat :: Str ( "break" ) , inner ( e, outer_span) . 1 ) ,
683+ ExprKind :: Continue ( None ) => ( Pat :: Str ( "continue" ) , Pat :: Str ( "continue" ) ) ,
684+ ExprKind :: Continue ( Some ( name) ) => ( Pat :: Str ( "continue" ) , Pat :: Sym ( name. ident . name ) ) ,
685+ ExprKind :: Ret ( None ) => ( Pat :: Str ( "return" ) , Pat :: Str ( "return" ) ) ,
686+ ExprKind :: Ret ( Some ( e) ) => ( Pat :: Str ( "return" ) , inner ( e, outer_span) . 1 ) ,
687+ ExprKind :: Become ( e) => ( Pat :: Str ( "become" ) , inner ( e, outer_span) . 1 ) ,
688+ ExprKind :: Struct ( box StructExpr { path, .. } ) => ( ast_path_search_pat ( path) . 0 , Pat :: Str ( "" ) ) ,
689+ ExprKind :: Use ( e, _) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "use" ) ) ,
690+ ExprKind :: Yield ( YieldKind :: Prefix ( _) ) => ( Pat :: Str ( "yield" ) , Pat :: Str ( "" ) ) ,
691+ ExprKind :: Yield ( YieldKind :: Postfix ( _) ) => ( inner ( e, outer_span) . 0 , Pat :: Str ( "" ) ) ,
692+ ExprKind :: OffsetOf ( ..)
693+ // Syntax unstable
694+ | ExprKind :: Yeet ( _) | ExprKind :: UnsafeBinderCast ( ..)
695+ // Don't have a good `Pat` for `ByteSymbol`s
696+ | ExprKind :: IncludedBytes ( _)
697+ // We don't know how qualified the path to the macro was
698+ | ExprKind :: FormatArgs ( _) | ExprKind :: InlineAsm ( ..)
699+ // Should've been expanded by now (?)
700+ | ExprKind :: MacCall ( ..)
701+ // Dummy/placeholder
702+ | ExprKind :: Err ( _) | ExprKind :: Dummy => ( Pat :: Str ( "" ) , Pat :: Str ( "" ) ) ,
703+ }
704+ }
705+
706+ inner ( e, e. span )
707+ }
708+
709+ fn range_limits_search_pat ( lims : RangeLimits ) -> ( Pat , Pat ) {
710+ match lims {
711+ RangeLimits :: HalfOpen => ( Pat :: Str ( ".." ) , Pat :: Str ( ".." ) ) ,
712+ RangeLimits :: Closed => ( Pat :: Str ( "..=" ) , Pat :: Str ( "..=" ) ) ,
713+ }
714+ }
715+
540716fn ident_search_pat ( ident : Ident ) -> ( Pat , Pat ) {
541717 ( Pat :: Sym ( ident. name ) , Pat :: Sym ( ident. name ) )
542718}
@@ -572,6 +748,7 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pa
572748
573749impl_with_search_pat ! ( ( _cx: EarlyContext <' tcx>, self : Attribute ) => attr_search_pat( self ) ) ;
574750impl_with_search_pat ! ( ( _cx: EarlyContext <' tcx>, self : ast:: Ty ) => ast_ty_search_pat( self ) ) ;
751+ impl_with_search_pat ! ( ( _cx: EarlyContext <' tcx>, self : ast:: Expr ) => ast_expr_search_pat( self ) ) ;
575752
576753impl < ' cx > WithSearchPat < ' cx > for ( & FnKind < ' cx > , & Body < ' cx > , HirId , Span ) {
577754 type Context = LateContext < ' cx > ;
0 commit comments