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},
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)?;
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() {
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() {
}
}
-/// 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:
/// 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()) {
}
}
-/// find relevant `ast::PathExpr` for reference
+/// find relevant `ast::Expr` for reference
///
/// # Preconditions
///
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)
}
})
}
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 { .. } => {
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));
#[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; }");
}
#[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##"
#[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##"
#[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##"
#[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##"
}"##,
);
}
+
+ #[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
+}",
+ );
+ }
}