@@ -9,14 +9,14 @@ use hir::{
99use ide_db:: {
1010 FxIndexSet , RootDatabase ,
1111 assists:: GroupLabel ,
12- defs:: { Definition , NameRefClass } ,
12+ defs:: Definition ,
1313 famous_defs:: FamousDefs ,
1414 helpers:: mod_path_to_ast,
1515 imports:: insert_use:: { ImportScope , insert_use} ,
1616 search:: { FileReference , ReferenceCategory , SearchScope } ,
1717 source_change:: SourceChangeBuilder ,
1818 syntax_helpers:: node_ext:: {
19- for_each_tail_expr, preorder_expr, walk_expr , walk_pat, walk_patterns_in_expr,
19+ for_each_tail_expr, preorder_expr, walk_pat, walk_patterns_in_expr,
2020 } ,
2121} ;
2222use itertools:: Itertools ;
@@ -687,29 +687,6 @@ impl FunctionBody {
687687 }
688688 }
689689
690- fn walk_expr ( & self , cb : & mut dyn FnMut ( ast:: Expr ) ) {
691- match self {
692- FunctionBody :: Expr ( expr) => walk_expr ( expr, cb) ,
693- FunctionBody :: Span { parent, text_range, .. } => {
694- parent
695- . statements ( )
696- . filter ( |stmt| text_range. contains_range ( stmt. syntax ( ) . text_range ( ) ) )
697- . filter_map ( |stmt| match stmt {
698- ast:: Stmt :: ExprStmt ( expr_stmt) => expr_stmt. expr ( ) ,
699- ast:: Stmt :: Item ( _) => None ,
700- ast:: Stmt :: LetStmt ( stmt) => stmt. initializer ( ) ,
701- } )
702- . for_each ( |expr| walk_expr ( & expr, cb) ) ;
703- if let Some ( expr) = parent
704- . tail_expr ( )
705- . filter ( |it| text_range. contains_range ( it. syntax ( ) . text_range ( ) ) )
706- {
707- walk_expr ( & expr, cb) ;
708- }
709- }
710- }
711- }
712-
713690 fn preorder_expr ( & self , cb : & mut dyn FnMut ( WalkEvent < ast:: Expr > ) -> bool ) {
714691 match self {
715692 FunctionBody :: Expr ( expr) => preorder_expr ( expr, cb) ,
@@ -799,22 +776,14 @@ impl FunctionBody {
799776 let mut self_param = None ;
800777 let mut res = FxIndexSet :: default ( ) ;
801778
802- fn local_from_name_ref (
803- sema : & Semantics < ' _ , RootDatabase > ,
804- name_ref : ast:: NameRef ,
805- ) -> Option < hir:: Local > {
806- match NameRefClass :: classify ( sema, & name_ref) {
807- Some (
808- NameRefClass :: Definition ( Definition :: Local ( local_ref) , _)
809- | NameRefClass :: FieldShorthand { local_ref, field_ref : _, adt_subst : _ } ,
810- ) => Some ( local_ref) ,
811- _ => None ,
812- }
813- }
779+ let ( text_range, element) = match self {
780+ FunctionBody :: Expr ( expr) => ( expr. syntax ( ) . text_range ( ) , Either :: Left ( expr) ) ,
781+ FunctionBody :: Span { parent, text_range, .. } => ( * text_range, Either :: Right ( parent) ) ,
782+ } ;
814783
815784 let mut add_name_if_local = |local_ref : Local | {
816- let InFile { file_id, value } = local_ref. primary_source ( sema. db ) . source ;
817785 // locals defined inside macros are not relevant to us
786+ let InFile { file_id, value } = local_ref. primary_source ( sema. db ) . source ;
818787 if !file_id. is_macro ( ) {
819788 match value {
820789 Either :: Right ( it) => {
@@ -826,59 +795,11 @@ impl FunctionBody {
826795 }
827796 }
828797 } ;
829- self . walk_expr ( & mut |expr| match expr {
830- ast:: Expr :: PathExpr ( path_expr) => {
831- if let Some ( local) = path_expr
832- . path ( )
833- . and_then ( |it| it. as_single_name_ref ( ) )
834- . and_then ( |name_ref| local_from_name_ref ( sema, name_ref) )
835- {
836- add_name_if_local ( local) ;
837- }
838- }
839- ast:: Expr :: ClosureExpr ( closure_expr) => {
840- if let Some ( body) = closure_expr. body ( ) {
841- body. syntax ( )
842- . descendants ( )
843- . filter_map ( ast:: NameRef :: cast)
844- . filter_map ( |name_ref| local_from_name_ref ( sema, name_ref) )
845- . for_each ( & mut add_name_if_local) ;
846- }
847- }
848- ast:: Expr :: MacroExpr ( expr) => {
849- if let Some ( tt) = expr. macro_call ( ) . and_then ( |call| call. token_tree ( ) ) {
850- tt. syntax ( )
851- . descendants_with_tokens ( )
852- . filter_map ( SyntaxElement :: into_token)
853- . filter ( |it| {
854- matches ! ( it. kind( ) , SyntaxKind :: STRING | SyntaxKind :: IDENT | T ![ self ] )
855- } )
856- . for_each ( |t| {
857- if ast:: String :: can_cast ( t. kind ( ) ) {
858- if let Some ( parts) =
859- ast:: String :: cast ( t) . and_then ( |s| sema. as_format_args_parts ( & s) )
860- {
861- parts
862- . into_iter ( )
863- . filter_map ( |( _, value) | value. and_then ( |it| it. left ( ) ) )
864- . filter_map ( |path| match path {
865- PathResolution :: Local ( local) => Some ( local) ,
866- _ => None ,
867- } )
868- . for_each ( & mut add_name_if_local) ;
869- }
870- } else {
871- sema. descend_into_macros_exact ( t)
872- . into_iter ( )
873- . filter_map ( |t| t. parent ( ) . and_then ( ast:: NameRef :: cast) )
874- . filter_map ( |name_ref| local_from_name_ref ( sema, name_ref) )
875- . for_each ( & mut add_name_if_local) ;
876- }
877- } ) ;
878- }
879- }
880- _ => ( ) ,
881- } ) ;
798+
799+ if let Some ( locals) = sema. locals_used ( element, text_range) {
800+ locals. into_iter ( ) . for_each ( & mut add_name_if_local) ;
801+ }
802+
882803 ( res, self_param)
883804 }
884805
@@ -6291,6 +6212,90 @@ fn foo() {
62916212
62926213fn $0fun_name(v: i32) {
62936214 print!("{v:?}{}", v == 123);
6215+ }"# ,
6216+ ) ;
6217+ }
6218+
6219+ #[ test]
6220+ fn no_parameter_for_variable_used_only_let_else ( ) {
6221+ check_assist (
6222+ extract_function,
6223+ r#"
6224+ fn foo() -> u32 {
6225+ let x = 5;
6226+
6227+ $0let Some(y) = Some(1) else {
6228+ return x * 2;
6229+ };$0
6230+
6231+ y
6232+ }"# ,
6233+ r#"
6234+ fn foo() -> u32 {
6235+ let x = 5;
6236+
6237+ let y = match fun_name(x) {
6238+ Ok(value) => value,
6239+ Err(value) => return value,
6240+ };
6241+
6242+ y
6243+ }
6244+
6245+ fn $0fun_name(x: u32) -> Result<_, u32> {
6246+ let Some(y) = Some(1) else {
6247+ return Err(x * 2);
6248+ };
6249+ Ok(y)
6250+ }"# ,
6251+ ) ;
6252+ }
6253+
6254+ #[ test]
6255+ fn deeply_nested_macros ( ) {
6256+ check_assist (
6257+ extract_function,
6258+ r#"
6259+ macro_rules! m {
6260+ ($val:ident) => { $val };
6261+ }
6262+
6263+ macro_rules! n {
6264+ ($v1:ident, $v2:ident) => { m!($v1) + $v2 };
6265+ }
6266+
6267+ macro_rules! o {
6268+ ($v1:ident, $v2:ident, $v3:ident) => { n!($v1, $v2) + $v3 };
6269+ }
6270+
6271+ fn foo() -> u32 {
6272+ let v1 = 1;
6273+ let v2 = 2;
6274+ $0let v3 = 3;
6275+ o!(v1, v2, v3)$0
6276+ }"# ,
6277+ r#"
6278+ macro_rules! m {
6279+ ($val:ident) => { $val };
6280+ }
6281+
6282+ macro_rules! n {
6283+ ($v1:ident, $v2:ident) => { m!($v1) + $v2 };
6284+ }
6285+
6286+ macro_rules! o {
6287+ ($v1:ident, $v2:ident, $v3:ident) => { n!($v1, $v2) + $v3 };
6288+ }
6289+
6290+ fn foo() -> u32 {
6291+ let v1 = 1;
6292+ let v2 = 2;
6293+ fun_name(v1, v2)
6294+ }
6295+
6296+ fn $0fun_name(v1: u32, v2: u32) -> u32 {
6297+ let v3 = 3;
6298+ o!(v1, v2, v3)
62946299}"# ,
62956300 ) ;
62966301 }
0 commit comments