]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide_assists/src/handlers/extract_function.rs
Add macro test
[rust.git] / crates / ide_assists / src / handlers / extract_function.rs
index 8779d8bd1a5028bfc10df228204be16bdc4cd45d..719f22053cce2c85864524adadd8efda60108d57 100644 (file)
         edit::{AstNodeEdit, IndentLevel},
         AstNode,
     },
-    SyntaxElement,
     SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR},
     SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
 };
-use test_utils::mark;
 
 use crate::{
     assist_context::{AssistContext, Assists},
@@ -59,11 +57,14 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
 
     let node = ctx.covering_element();
     if node.kind() == COMMENT {
-        mark::hit!(extract_function_in_comment_is_not_applicable);
+        cov_mark::hit!(extract_function_in_comment_is_not_applicable);
         return None;
     }
 
-    let node = element_to_node(node);
+    let node = match node {
+        syntax::NodeOrToken::Node(n) => n,
+        syntax::NodeOrToken::Token(t) => t.parent()?,
+    };
 
     let body = extraction_target(&node, ctx.frange.range)?;
 
@@ -197,14 +198,14 @@ fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<Con
                 if let Some(kind) = expr_err_kind(&expr, ctx) {
                     Some(FlowKind::TryReturn { expr, kind })
                 } else {
-                    mark::hit!(external_control_flow_try_and_return_non_err);
+                    cov_mark::hit!(external_control_flow_try_and_return_non_err);
                     return None;
                 }
             }
             None => return None,
         },
         (Some(_), _, _, _) => {
-            mark::hit!(external_control_flow_try_and_bc);
+            cov_mark::hit!(external_control_flow_try_and_bc);
             return None;
         }
         (None, Some(r), None, None) => match r.expr() {
@@ -212,11 +213,11 @@ fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<Con
             None => Some(FlowKind::Return),
         },
         (None, Some(_), _, _) => {
-            mark::hit!(external_control_flow_return_and_bc);
+            cov_mark::hit!(external_control_flow_return_and_bc);
             return None;
         }
         (None, None, Some(_), Some(_)) => {
-            mark::hit!(external_control_flow_break_and_continue);
+            cov_mark::hit!(external_control_flow_break_and_continue);
             return None;
         }
         (None, None, Some(b), None) => match b.expr() {
@@ -561,14 +562,6 @@ fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
     }
 }
 
-/// node or token's parent
-fn element_to_node(node: SyntaxElement) -> SyntaxNode {
-    match node {
-        syntax::NodeOrToken::Node(n) => n,
-        syntax::NodeOrToken::Token(t) => t.parent(),
-    }
-}
-
 /// Try to guess what user wants to extract
 ///
 /// We have basically have two cases:
@@ -736,6 +729,14 @@ fn reference_is_exclusive(
 
 /// checks if this expr requires `&mut` access, recurses on field access
 fn expr_require_exclusive_access(ctx: &AssistContext, expr: &ast::Expr) -> Option<bool> {
+    match expr {
+        ast::Expr::MacroCall(_) => {
+            // FIXME: expand macro and check output for mutable usages of the variable?
+            return None;
+        }
+        _ => (),
+    }
+
     let parent = expr.syntax().parent()?;
 
     if let Some(bin_expr) = ast::BinExpr::cast(parent.clone()) {
@@ -794,7 +795,7 @@ fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
     }
 }
 
-/// find relevant `ast::PathExpr` for reference
+/// find relevant `ast::Expr` for reference
 ///
 /// # Preconditions
 ///
@@ -811,7 +812,11 @@ fn path_element_of_reference(
         stdx::never!(false, "cannot find path parent of variable usage: {:?}", token);
         None
     })?;
-    stdx::always!(matches!(path, ast::Expr::PathExpr(_)));
+    stdx::always!(
+        matches!(path, ast::Expr::PathExpr(_) | ast::Expr::MacroCall(_)),
+        "unexpected expression type for variable usage: {:?}",
+        path
+    );
     Some(path)
 }
 
@@ -1247,7 +1252,7 @@ fn make_body(
             })
         }
         FlowHandler::If { .. } => {
-            let lit_false = ast::Literal::cast(make::tokens::literal("false").parent()).unwrap();
+            let lit_false = make::expr_literal("false");
             with_tail_expr(block, lit_false.into())
         }
         FlowHandler::IfOption { .. } => {
@@ -1421,9 +1426,7 @@ fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> S
 fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Option<ast::Expr> {
     let value = match handler {
         FlowHandler::None | FlowHandler::Try { .. } => return None,
-        FlowHandler::If { .. } => {
-            ast::Literal::cast(make::tokens::literal("true").parent()).unwrap().into()
-        }
+        FlowHandler::If { .. } => make::expr_literal("true").into(),
         FlowHandler::IfOption { .. } => {
             let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
             let args = make::arg_list(iter::once(expr));
@@ -1837,7 +1840,7 @@ fn $0fun_name(n: u32) -> u32 {
 
     #[test]
     fn in_comment_is_not_applicable() {
-        mark::check!(extract_function_in_comment_is_not_applicable);
+        cov_mark::check!(extract_function_in_comment_is_not_applicable);
         check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }");
     }
 
@@ -2822,7 +2825,7 @@ fn $0fun_name(n: i32) -> Result<i32, i64> {
 
     #[test]
     fn break_and_continue() {
-        mark::check!(external_control_flow_break_and_continue);
+        cov_mark::check!(external_control_flow_break_and_continue);
         check_assist_not_applicable(
             extract_function,
             r##"
@@ -2842,7 +2845,7 @@ fn foo() {
 
     #[test]
     fn return_and_break() {
-        mark::check!(external_control_flow_return_and_bc);
+        cov_mark::check!(external_control_flow_return_and_bc);
         check_assist_not_applicable(
             extract_function,
             r##"
@@ -3341,7 +3344,7 @@ fn $0fun_name() -> Result<i32, i64> {
 
     #[test]
     fn try_and_break() {
-        mark::check!(external_control_flow_try_and_bc);
+        cov_mark::check!(external_control_flow_try_and_bc);
         check_assist_not_applicable(
             extract_function,
             r##"
@@ -3363,7 +3366,7 @@ fn foo() -> Option<()> {
 
     #[test]
     fn try_and_return_ok() {
-        mark::check!(external_control_flow_try_and_return_non_err);
+        cov_mark::check!(external_control_flow_try_and_return_non_err);
         check_assist_not_applicable(
             extract_function,
             r##"
@@ -3381,4 +3384,36 @@ fn foo() -> Result<(), i64> {
 }"##,
         );
     }
+
+    #[test]
+    fn param_usage_in_macro() {
+        check_assist(
+            extract_function,
+            r"
+macro_rules! m {
+    ($val:expr) => { $val };
+}
+
+fn foo() {
+    let n = 1;
+    $0let k = n * m!(n);$0
+    let m = k + 1;
+}",
+            r"
+macro_rules! m {
+    ($val:expr) => { $val };
+}
+
+fn foo() {
+    let n = 1;
+    let k = fun_name(n);
+    let m = k + 1;
+}
+
+fn $0fun_name(n: i32) -> i32 {
+    let k = n * m!(n);
+    k
+}",
+        );
+    }
 }