Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/toggle_macro_delimiter.rs')
-rw-r--r--crates/ide-assists/src/handlers/toggle_macro_delimiter.rs55
1 files changed, 41 insertions, 14 deletions
diff --git a/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs b/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
index 60b0797f02..15143575e7 100644
--- a/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
+++ b/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs
@@ -1,6 +1,7 @@
use ide_db::assists::AssistId;
use syntax::{
- AstNode, SyntaxToken, T,
+ AstNode, SyntaxKind, SyntaxToken, T,
+ algo::{previous_non_trivia_token, skip_trivia_token},
ast::{self, syntax_factory::SyntaxFactory},
};
@@ -36,15 +37,18 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>)
RCur,
}
- let makro = ctx.find_node_at_offset::<ast::MacroCall>()?;
+ let token_tree = ctx.find_node_at_offset::<ast::TokenTree>()?;
let cursor_offset = ctx.offset();
- let semicolon = macro_semicolon(&makro);
- let token_tree = makro.token_tree()?;
+ let semicolon = macro_semicolon(&token_tree);
let ltoken = token_tree.left_delimiter_token()?;
let rtoken = token_tree.right_delimiter_token()?;
+ if !is_macro_call(&token_tree)? {
+ return None;
+ }
+
if !ltoken.text_range().contains(cursor_offset) && !rtoken.text_range().contains(cursor_offset)
{
return None;
@@ -70,7 +74,7 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>)
token_tree.syntax().text_range(),
|builder| {
let make = SyntaxFactory::with_mappings();
- let mut editor = builder.make_editor(makro.syntax());
+ let mut editor = builder.make_editor(token_tree.syntax());
match token {
MacroDelims::LPar | MacroDelims::RPar => {
@@ -102,12 +106,21 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>)
)
}
-fn macro_semicolon(makro: &ast::MacroCall) -> Option<SyntaxToken> {
- makro.semicolon_token().or_else(|| {
- let macro_expr = ast::MacroExpr::cast(makro.syntax().parent()?)?;
- let expr_stmt = ast::ExprStmt::cast(macro_expr.syntax().parent()?)?;
- expr_stmt.semicolon_token()
- })
+fn is_macro_call(token_tree: &ast::TokenTree) -> Option<bool> {
+ let parent = token_tree.syntax().parent()?;
+ if ast::MacroCall::can_cast(parent.kind()) {
+ return Some(true);
+ }
+
+ let token_tree = ast::TokenTree::cast(parent)?;
+ let prev = previous_non_trivia_token(token_tree.syntax().clone())?;
+ let prev_prev = previous_non_trivia_token(prev.clone())?;
+ Some(prev.kind() == T![!] && prev_prev.kind() == SyntaxKind::IDENT)
+}
+
+fn macro_semicolon(token_tree: &ast::TokenTree) -> Option<SyntaxToken> {
+ let next_token = token_tree.syntax().last_token()?.next_token()?;
+ skip_trivia_token(next_token, syntax::Direction::Next).filter(|it| it.kind() == T![;])
}
fn needs_semicolon(tt: ast::TokenTree) -> bool {
@@ -402,10 +415,9 @@ prt!{(3 + 5)}
)
}
- // FIXME @alibektas : Inner macro_call is not seen as such. So this doesn't work.
#[test]
fn test_nested_macros() {
- check_assist_not_applicable(
+ check_assist(
toggle_macro_delimiter,
r#"
macro_rules! prt {
@@ -420,7 +432,22 @@ macro_rules! abc {
}};
}
-prt!{abc!($03 + 5)};
+prt!{abc!$0(3 + 5)};
+"#,
+ r#"
+macro_rules! prt {
+ ($e:expr) => {{
+ println!("{}", stringify!{$e});
+ }};
+}
+
+macro_rules! abc {
+ ($e:expr) => {{
+ println!("{}", stringify!{$e});
+ }};
+}
+
+prt!{abc!{3 + 5}};
"#,
)
}