diff --git a/crates/ra_ssr/src/lib.rs b/crates/ra_ssr/src/lib.rs
index da26ee66941..8f149e3db65 100644
--- a/crates/ra_ssr/src/lib.rs
+++ b/crates/ra_ssr/src/lib.rs
@@ -12,7 +12,7 @@ mod tests;
 use crate::matching::Match;
 use hir::Semantics;
 use ra_db::{FileId, FileRange};
-use ra_syntax::{AstNode, SmolStr, SyntaxNode};
+use ra_syntax::{ast, AstNode, SmolStr, SyntaxNode};
 use ra_text_edit::TextEdit;
 use rustc_hash::FxHashMap;
 
@@ -107,6 +107,22 @@ impl<'db> MatchFinder<'db> {
                 return;
             }
         }
+        // If we've got a macro call, we already tried matching it pre-expansion, which is the only
+        // way to match the whole macro, now try expanding it and matching the expansion.
+        if let Some(macro_call) = ast::MacroCall::cast(code.clone()) {
+            if let Some(expanded) = self.sema.expand(&macro_call) {
+                if let Some(tt) = macro_call.token_tree() {
+                    // When matching within a macro expansion, we only want to allow matches of
+                    // nodes that originated entirely from within the token tree of the macro call.
+                    // i.e. we don't want to match something that came from the macro itself.
+                    self.find_matches(
+                        &expanded,
+                        &Some(self.sema.original_range(tt.syntax())),
+                        matches_out,
+                    );
+                }
+            }
+        }
         for child in code.children() {
             self.find_matches(&child, restrict_range, matches_out);
         }
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs
index bdaba9f1b61..85420ed3ca5 100644
--- a/crates/ra_ssr/src/matching.rs
+++ b/crates/ra_ssr/src/matching.rs
@@ -343,7 +343,9 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
     }
 
     /// Outside of token trees, a placeholder can only match a single AST node, whereas in a token
-    /// tree it can match a sequence of tokens.
+    /// tree it can match a sequence of tokens. Note, that this code will only be used when the
+    /// pattern matches the macro invocation. For matches within the macro call, we'll already have
+    /// expanded the macro.
     fn attempt_match_token_tree(
         &mut self,
         match_inputs: &MatchInputs,
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs
index 3ee1e74e959..d7e6d817a0f 100644
--- a/crates/ra_ssr/src/tests.rs
+++ b/crates/ra_ssr/src/tests.rs
@@ -355,6 +355,18 @@ fn match_nested_method_calls() {
     );
 }
 
+// Make sure that our node matching semantics don't differ within macro calls.
+#[test]
+fn match_nested_method_calls_with_macro_call() {
+    assert_matches(
+        "$a.z().z().z()",
+        r#"
+            macro_rules! m1 { ($a:expr) => {$a}; }
+            fn f() {m1!(h().i().j().z().z().z().d().e())}"#,
+        &["h().i().j().z().z().z()"],
+    );
+}
+
 #[test]
 fn match_complex_expr() {
     let code = "fn f() -> i32 {foo(bar(40, 2), 42)}";
@@ -547,3 +559,40 @@ fn multiple_rules() {
         "fn f() -> i32 {add_one(add(3, 2))}",
     )
 }
+
+#[test]
+fn match_within_macro_invocation() {
+    let code = r#"
+            macro_rules! foo {
+                ($a:stmt; $b:expr) => {
+                    $b
+                };
+            }
+            struct A {}
+            impl A {
+                fn bar() {}
+            }
+            fn f1() {
+                let aaa = A {};
+                foo!(macro_ignores_this(); aaa.bar());
+            }
+        "#;
+    assert_matches("$a.bar()", code, &["aaa.bar()"]);
+}
+
+#[test]
+fn replace_within_macro_expansion() {
+    assert_ssr_transform(
+        "$a.foo() ==>> bar($a)",
+        r#"
+            macro_rules! macro1 {
+                ($a:expr) => {$a}
+            }
+            fn f() {macro1!(5.x().foo().o2())}"#,
+        r#"
+            macro_rules! macro1 {
+                ($a:expr) => {$a}
+            }
+            fn f() {macro1!(bar(5.x()).o2())}"#,
+    )
+}