@@ -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,23 +776,17 @@ 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
818- if !file_id. is_macro ( ) {
786+ if let Some ( local_source) = local_ref. try_primary_source ( sema. db )
787+ && let InFile { file_id, value } = local_source. source
788+ && !file_id. is_macro ( )
789+ {
819790 match value {
820791 Either :: Right ( it) => {
821792 self_param. replace ( it) ;
@@ -826,59 +797,11 @@ impl FunctionBody {
826797 }
827798 }
828799 } ;
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- } ) ;
800+
801+ if let Some ( locals) = sema. locals_used ( element, text_range) {
802+ locals. into_iter ( ) . for_each ( & mut add_name_if_local) ;
803+ }
804+
882805 ( res, self_param)
883806 }
884807
@@ -6291,6 +6214,90 @@ fn foo() {
62916214
62926215fn $0fun_name(v: i32) {
62936216 print!("{v:?}{}", v == 123);
6217+ }"# ,
6218+ ) ;
6219+ }
6220+
6221+ #[ test]
6222+ fn no_parameter_for_variable_used_only_let_else ( ) {
6223+ check_assist (
6224+ extract_function,
6225+ r#"
6226+ fn foo() -> u32 {
6227+ let x = 5;
6228+
6229+ $0let Some(y) = Some(1) else {
6230+ return x * 2;
6231+ };$0
6232+
6233+ y
6234+ }"# ,
6235+ r#"
6236+ fn foo() -> u32 {
6237+ let x = 5;
6238+
6239+ let y = match fun_name(x) {
6240+ Ok(value) => value,
6241+ Err(value) => return value,
6242+ };
6243+
6244+ y
6245+ }
6246+
6247+ fn $0fun_name(x: u32) -> Result<_, u32> {
6248+ let Some(y) = Some(1) else {
6249+ return Err(x * 2);
6250+ };
6251+ Ok(y)
6252+ }"# ,
6253+ ) ;
6254+ }
6255+
6256+ #[ test]
6257+ fn deeply_nested_macros ( ) {
6258+ check_assist (
6259+ extract_function,
6260+ r#"
6261+ macro_rules! m {
6262+ ($val:ident) => { $val };
6263+ }
6264+
6265+ macro_rules! n {
6266+ ($v1:ident, $v2:ident) => { m!($v1) + $v2 };
6267+ }
6268+
6269+ macro_rules! o {
6270+ ($v1:ident, $v2:ident, $v3:ident) => { n!($v1, $v2) + $v3 };
6271+ }
6272+
6273+ fn foo() -> u32 {
6274+ let v1 = 1;
6275+ let v2 = 2;
6276+ $0let v3 = 3;
6277+ o!(v1, v2, v3)$0
6278+ }"# ,
6279+ r#"
6280+ macro_rules! m {
6281+ ($val:ident) => { $val };
6282+ }
6283+
6284+ macro_rules! n {
6285+ ($v1:ident, $v2:ident) => { m!($v1) + $v2 };
6286+ }
6287+
6288+ macro_rules! o {
6289+ ($v1:ident, $v2:ident, $v3:ident) => { n!($v1, $v2) + $v3 };
6290+ }
6291+
6292+ fn foo() -> u32 {
6293+ let v1 = 1;
6294+ let v2 = 2;
6295+ fun_name(v1, v2)
6296+ }
6297+
6298+ fn $0fun_name(v1: u32, v2: u32) -> u32 {
6299+ let v3 = 3;
6300+ o!(v1, v2, v3)
62946301}"# ,
62956302 ) ;
62966303 }
0 commit comments