Skip to content

Commit

Permalink
Fix HasSelf visitor to visit Self keyword inside macro invocations
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Aug 30, 2020
1 parent 8288d9d commit 52b7f31
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 3 deletions.
20 changes: 17 additions & 3 deletions src/receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
29 changes: 29 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 52b7f31

Please sign in to comment.