From e1a9461806a4d6dd2ad58be2d6148c0e8fdb2299 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 21 Mar 2020 22:43:48 +0800 Subject: Add identity expansion checking --- crates/ra_hir_expand/src/db.rs | 24 +++++++++++++++++++++--- crates/ra_ide/src/diagnostics.rs | 30 ++++++++++++++++++++++++++++++ crates/ra_syntax/src/algo.rs | 4 ++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index d171d2dfd..4421d187b 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -6,7 +6,7 @@ use mbe::{ExpandResult, MacroRules}; use ra_db::{salsa, SourceDatabase}; use ra_parser::FragmentKind; use ra_prof::profile; -use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode}; +use ra_syntax::{algo::diff, AstNode, Parse, SyntaxKind::*, SyntaxNode}; use crate::{ ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, @@ -238,7 +238,7 @@ pub fn parse_macro_with_arg( } else { db.macro_expand(macro_call_id) }; - if let Some(err) = err { + if let Some(err) = &err { // Note: // The final goal we would like to make all parse_macro success, // such that the following log will not call anyway. @@ -272,7 +272,25 @@ pub fn parse_macro_with_arg( let fragment_kind = to_fragment_kind(db, macro_call_id); let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?; - Some((parse, Arc::new(rev_token_map))) + + if err.is_none() { + Some((parse, Arc::new(rev_token_map))) + } else { + // FIXME: + // In future, we should proprate the actual error with recovery information + // instead of ignore the error here. + + // Safe check for recurisve identity macro + let node = parse.syntax_node(); + let file: HirFileId = macro_file.into(); + let call_node = file.call_node(db)?; + + if !diff(&node, &call_node.value).is_empty() { + Some((parse, Arc::new(rev_token_map))) + } else { + None + } + } } /// Given a `MacroCallId`, return what `FragmentKind` it belongs to. diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index a10e642db..50106e31e 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -715,4 +715,34 @@ fn main() { check_struct_shorthand_initialization, ); } + + #[test] + fn test_bad_macro_stackover() { + check_no_diagnostic( + r#" + //- /main.rs + #[macro_export] + macro_rules! match_ast { + (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; + + (match ($node:expr) { + $( ast::$ast:ident($it:ident) => $res:expr, )* + _ => $catch_all:expr $(,)? + }) => {{ + $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )* + { $catch_all } + }}; + } + + fn main() { + let anchor = match_ast! { + match parent { + as => {}, + _ => return None + } + }; + } + "#, + ); + } } diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index 344cf0fbe..ffdbdc767 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -95,6 +95,10 @@ impl TreeDiff { builder.replace(from.text_range(), to.to_string()) } } + + pub fn is_empty(&self) -> bool { + self.replacements.is_empty() + } } /// Finds minimal the diff, which, applied to `from`, will result in `to`. -- cgit v1.2.3 From 6d6606895cf15998a71a23c6d5e78dc955153b4e Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 21 Mar 2020 23:08:53 +0800 Subject: Fix typo --- crates/ra_hir_expand/src/db.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 4421d187b..5a696542f 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -277,7 +277,7 @@ pub fn parse_macro_with_arg( Some((parse, Arc::new(rev_token_map))) } else { // FIXME: - // In future, we should proprate the actual error with recovery information + // In future, we should propagate the actual error with recovery information // instead of ignore the error here. // Safe check for recurisve identity macro -- cgit v1.2.3 From 9ff50d7e839c635632021d47e2dd3982916e4738 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 21 Mar 2020 23:41:07 +0800 Subject: Move test to hir_ty --- crates/ra_hir_ty/src/tests/regression.rs | 31 +++++++++++++++++++++++++++++++ crates/ra_ide/src/diagnostics.rs | 30 ------------------------------ 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index 14c8ed3a9..a02e3ee05 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs @@ -453,3 +453,34 @@ pub mod str { // should be Option, but currently not because of Chalk ambiguity problem assert_eq!("(Option<{unknown}>, Option<{unknown}>)", super::type_at_pos(&db, pos)); } + +#[test] +fn issue_3642_bad_macro_stackover() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs +#[macro_export] +macro_rules! match_ast { + (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; + + (match ($node:expr) { + $( ast::$ast:ident($it:ident) => $res:expr, )* + _ => $catch_all:expr $(,)? + }) => {{ + $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )* + { $catch_all } + }}; +} + +fn main() { + let anchor<|> = match_ast! { + match parent { + as => {}, + _ => return None + } + }; +}"#, + ); + + assert_eq!("()", super::type_at_pos(&db, pos)); +} diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 50106e31e..a10e642db 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -715,34 +715,4 @@ fn main() { check_struct_shorthand_initialization, ); } - - #[test] - fn test_bad_macro_stackover() { - check_no_diagnostic( - r#" - //- /main.rs - #[macro_export] - macro_rules! match_ast { - (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; - - (match ($node:expr) { - $( ast::$ast:ident($it:ident) => $res:expr, )* - _ => $catch_all:expr $(,)? - }) => {{ - $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )* - { $catch_all } - }}; - } - - fn main() { - let anchor = match_ast! { - match parent { - as => {}, - _ => return None - } - }; - } - "#, - ); - } } -- cgit v1.2.3