From 52b7f318d59df894ccbfbe408619c15d4e0a7bfa Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 30 Aug 2020 13:04:27 +0900 Subject: [PATCH] Fix HasSelf visitor to visit Self keyword inside macro invocations --- src/receiver.rs | 20 +++++++++++++++++--- tests/test.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/receiver.rs b/src/receiver.rs index 1e9e397..4273359 100644 --- a/src/receiver.rs +++ b/src/receiver.rs @@ -29,6 +29,14 @@ pub fn has_self_in_block(block: &mut Block) -> bool { visitor.0 } +fn has_self_in_token_stream(tokens: TokenStream) -> bool { + tokens.into_iter().any(|tt| match tt { + TokenTree::Ident(ident) => ident == "Self", + TokenTree::Group(group) => has_self_in_token_stream(group.stream()), + _ => false, + }) +} + struct HasSelf(bool); impl VisitMut for HasSelf { @@ -54,6 +62,12 @@ impl VisitMut for HasSelf { fn visit_item_mut(&mut self, _: &mut Item) { // Do not recurse into nested items. } + + fn visit_macro_mut(&mut self, mac: &mut Macro) { + if !contains_fn(mac.tokens.clone()) { + self.0 |= has_self_in_token_stream(mac.tokens.clone()); + } + } } pub struct ReplaceReceiver { @@ -278,14 +292,14 @@ impl VisitMut for ReplaceReceiver { } } - fn visit_macro_mut(&mut self, i: &mut Macro) { + fn visit_macro_mut(&mut self, mac: &mut Macro) { // We can't tell in general whether `self` inside a macro invocation // refers to the self in the argument list or a different self // introduced within the macro. Heuristic: if the macro input contains // `fn`, then `self` is more likely to refer to something other than the // outer function's self argument. - if !contains_fn(i.tokens.clone()) { - self.visit_token_stream(&mut i.tokens); + if !contains_fn(mac.tokens.clone()) { + self.visit_token_stream(&mut mac.tokens); } } } diff --git a/tests/test.rs b/tests/test.rs index 5225c51..2d8b75b 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -883,6 +883,35 @@ pub mod issue92 { } } +// https://github.com/dtolnay/async-trait/issues/92#issuecomment-683370136 +pub mod issue92_2 { + use async_trait::async_trait; + + macro_rules! mac { + ($($tt:tt)*) => { + $($tt)* + }; + } + + pub trait Trait1 { + fn func1(); + } + + #[async_trait] + pub trait Trait2: Trait1 { + async fn func2() { + mac!(Self::func1()); + + macro_rules! mac2 { + ($($tt:tt)*) => { + Self::func1(); + }; + } + mac2!(); + } + } +} + // https://github.com/dtolnay/async-trait/issues/104 pub mod issue104 { use async_trait::async_trait;