Repository: rust-analyzer/rust-analyzer
Pull request #6879 (2020-12-14 16:13:59)

Change HasChildSource::ChildId assoc item to generic param


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index ff2c33f45d..ec8ad11cb4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1827,9 +1827,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
 [[package]]
 name = "ungrammar"
-version = "1.2.2"
+version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "873186a460627379e7e28880a0d33b729c205634f6f021321f50b323235e62d7"
+checksum = "df0cd89993af555540e2436fc6adb8479b0dbe386339a136397952e9c89e17a9"
 
 [[package]]
 name = "unicase"
diff --git a/Cargo.toml b/Cargo.toml
index 59d36fbc1d..e30ef0e2f6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,5 +25,3 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
 # chalk-solve = { path = "../chalk/chalk-solve" }
 # chalk-ir = { path = "../chalk/chalk-ir" }
 # chalk-recursive = { path = "../chalk/chalk-recursive" }
-
-# ungrammar = { path = "../ungrammar" }
diff --git a/crates/assists/src/handlers/reorder_fields.rs b/crates/assists/src/handlers/reorder_fields.rs
index fe55742420..7c0f0f44e1 100644
--- a/crates/assists/src/handlers/reorder_fields.rs
+++ b/crates/assists/src/handlers/reorder_fields.rs
@@ -4,7 +4,6 @@ use rustc_hash::FxHashMap;
 use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
 use ide_db::RootDatabase;
 use syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode};
-use test_utils::mark;
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
@@ -39,7 +38,6 @@ fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     });
 
     if sorted_fields == fields {
-        mark::hit!(reorder_sorted_fields);
         return None;
     }
 
@@ -109,25 +107,22 @@ fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashM
 
 #[cfg(test)]
 mod tests {
-    use test_utils::mark;
-
     use crate::tests::{check_assist, check_assist_not_applicable};
 
     use super::*;
 
     #[test]
-    fn reorder_sorted_fields() {
-        mark::check!(reorder_sorted_fields);
+    fn not_applicable_if_sorted() {
         check_assist_not_applicable(
             reorder_fields,
             r#"
-struct Foo {
-    foo: i32,
-    bar: i32,
-}
+        struct Foo {
+            foo: i32,
+            bar: i32,
+        }
 
-const test: Foo = <|>Foo { foo: 0, bar: 0 };
-"#,
+        const test: Foo = <|>Foo { foo: 0, bar: 0 };
+        "#,
         )
     }
 
@@ -136,9 +131,9 @@ const test: Foo = <|>Foo { foo: 0, bar: 0 };
         check_assist_not_applicable(
             reorder_fields,
             r#"
-struct Foo {};
-const test: Foo = <|>Foo {}
-"#,
+        struct Foo {};
+        const test: Foo = <|>Foo {}
+        "#,
         )
     }
 
@@ -147,13 +142,13 @@ const test: Foo = <|>Foo {}
         check_assist(
             reorder_fields,
             r#"
-struct Foo {foo: i32, bar: i32};
-const test: Foo = <|>Foo {bar: 0, foo: 1}
-"#,
+        struct Foo {foo: i32, bar: i32};
+        const test: Foo = <|>Foo {bar: 0, foo: 1}
+        "#,
             r#"
-struct Foo {foo: i32, bar: i32};
-const test: Foo = Foo {foo: 1, bar: 0}
-"#,
+        struct Foo {foo: i32, bar: i32};
+        const test: Foo = Foo {foo: 1, bar: 0}
+        "#,
         )
     }
 
@@ -162,25 +157,25 @@ const test: Foo = Foo {foo: 1, bar: 0}
         check_assist(
             reorder_fields,
             r#"
-struct Foo { foo: i64, bar: i64, baz: i64 }
+        struct Foo { foo: i64, bar: i64, baz: i64 }
 
-fn f(f: Foo) -> {
-    match f {
-        <|>Foo { baz: 0, ref mut bar, .. } => (),
-        _ => ()
-    }
-}
-"#,
+        fn f(f: Foo) -> {
+            match f {
+                <|>Foo { baz: 0, ref mut bar, .. } => (),
+                _ => ()
+            }
+        }
+        "#,
             r#"
-struct Foo { foo: i64, bar: i64, baz: i64 }
+        struct Foo { foo: i64, bar: i64, baz: i64 }
 
-fn f(f: Foo) -> {
-    match f {
-        Foo { ref mut bar, baz: 0, .. } => (),
-        _ => ()
-    }
-}
-"#,
+        fn f(f: Foo) -> {
+            match f {
+                Foo { ref mut bar, baz: 0, .. } => (),
+                _ => ()
+            }
+        }
+        "#,
         )
     }
 
@@ -189,39 +184,39 @@ fn f(f: Foo) -> {
         check_assist(
             reorder_fields,
             r#"
-struct Foo {
-    foo: String,
-    bar: String,
-}
+            struct Foo {
+                foo: String,
+                bar: String,
+            }
 
-impl Foo {
-    fn new() -> Foo {
-        let foo = String::new();
-        <|>Foo {
-            bar: foo.clone(),
-            extra: "Extra field",
-            foo,
-        }
-    }
-}
-"#,
+            impl Foo {
+                fn new() -> Foo {
+                    let foo = String::new();
+                    <|>Foo {
+                        bar: foo.clone(),
+                        extra: "Extra field",
+                        foo,
+                    }
+                }
+            }
+            "#,
             r#"
-struct Foo {
-    foo: String,
-    bar: String,
-}
+            struct Foo {
+                foo: String,
+                bar: String,
+            }
 
-impl Foo {
-    fn new() -> Foo {
-        let foo = String::new();
-        Foo {
-            foo,
-            bar: foo.clone(),
-            extra: "Extra field",
-        }
-    }
-}
-"#,
+            impl Foo {
+                fn new() -> Foo {
+                    let foo = String::new();
+                    Foo {
+                        foo,
+                        bar: foo.clone(),
+                        extra: "Extra field",
+                    }
+                }
+            }
+            "#,
         )
     }
 }
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index 6cfbd6c9ba..eb3209bee3 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -144,7 +144,7 @@ mod tests {
 use foo::<|>;
 //- /foo/lib.rs crate:foo
 #[macro_export]
-macro_rules! frobnicate { () => () }
+macro_rules frobnicate { () => () }
 "#,
             r#"
 use foo::frobnicate;
@@ -154,11 +154,11 @@ use foo::frobnicate;
         check_edit(
             "frobnicate!",
             r#"
-macro_rules! frobnicate { () => () }
+macro_rules frobnicate { () => () }
 fn main() { frob<|>!(); }
 "#,
             r#"
-macro_rules! frobnicate { () => () }
+macro_rules frobnicate { () => () }
 fn main() { frobnicate!(); }
 "#,
         );
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 107ad06904..552c8e433e 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -110,8 +110,8 @@ impl HasSource for TypeAlias {
     }
 }
 impl HasSource for MacroDef {
-    type Ast = ast::MacroRules;
-    fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroRules> {
+    type Ast = ast::MacroCall;
+    fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroCall> {
         InFile {
             file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
             value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
@@ -129,7 +129,7 @@ impl HasSource for TypeParam {
     type Ast = Either<ast::Trait, ast::TypeParam>;
     fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
         let child_source = self.id.parent.child_source(db.upcast());
-        child_source.map(|it| it.type_params[self.id.local_id].clone())
+        child_source.map(|it| it[self.id.local_id].clone())
     }
 }
 
@@ -137,6 +137,6 @@ impl HasSource for LifetimeParam {
     type Ast = ast::LifetimeParam;
     fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
         let child_source = self.id.parent.child_source(db.upcast());
-        child_source.map(|it| it.lifetime_params[self.id.local_id].clone())
+        child_source.map(|it| it[self.id.local_id].clone())
     }
 }
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 5959ac4ca9..e4fc21cedf 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -723,7 +723,7 @@ to_def_impls![
     (crate::EnumVariant, ast::Variant, enum_variant_to_def),
     (crate::TypeParam, ast::TypeParam, type_param_to_def),
     (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
-    (crate::MacroDef, ast::MacroRules, macro_rules_to_def),
+    (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros
     (crate::Local, ast::IdentPat, bind_pat_to_def),
 ];
 
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index a333d7aea9..badcf0ae80 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -149,10 +149,7 @@ impl SourceToDefCtx<'_, '_> {
     }
 
     // FIXME: use DynMap as well?
-    pub(super) fn macro_rules_to_def(
-        &mut self,
-        src: InFile<ast::MacroRules>,
-    ) -> Option<MacroDefId> {
+    pub(super) fn macro_call_to_def(&mut self, src: InFile<ast::MacroCall>) -> Option<MacroDefId> {
         let kind = MacroDefKind::Declarative;
         let file_id = src.file_id.original_file(self.db.upcast());
         let krate = self.file_to_def(file_id)?.krate;
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index 6539959c3c..eafa3abb6a 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -145,10 +145,12 @@ impl EnumData {
     }
 }
 
-impl HasChildSource for EnumId {
-    type ChildId = LocalEnumVariantId;
+impl HasChildSource<LocalEnumVariantId> for EnumId {
     type Value = ast::Variant;
-    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
+    fn child_source(
+        &self,
+        db: &dyn DefDatabase,
+    ) -> InFile<ArenaMap<LocalEnumVariantId, Self::Value>> {
         let src = self.lookup(db).source(db);
         let mut trace = Trace::new_for_map();
         lower_enum(db, &mut trace, &src, self.lookup(db).container.module(db));
@@ -212,11 +214,10 @@ impl VariantData {
     }
 }
 
-impl HasChildSource for VariantId {
-    type ChildId = LocalFieldId;
+impl HasChildSource<LocalFieldId> for VariantId {
     type Value = Either<ast::TupleField, ast::RecordField>;
 
-    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
+    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> {
         let (src, module_id) = match self {
             VariantId::EnumVariantId(it) => {
                 // I don't really like the fact that we call into parent source
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index bdba4c33ea..689a3274c7 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -548,70 +548,63 @@ impl ExprCollector<'_> {
                 }
             }
             ast::Expr::MacroCall(e) => {
-                let mut ids = vec![];
-                self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| {
-                    ids.push(match expansion {
-                        Some(it) => this.collect_expr(it),
-                        None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
-                    })
-                });
-                ids[0]
-            }
-        }
-    }
-
-    fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
-        &mut self,
-        e: ast::MacroCall,
-        syntax_ptr: AstPtr<ast::Expr>,
-        mut collector: F,
-    ) {
-        // File containing the macro call. Expansion errors will be attached here.
-        let outer_file = self.expander.current_file_id;
-
-        let macro_call = self.expander.to_source(AstPtr::new(&e));
-        let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);
-
-        match &res.err {
-            Some(ExpandError::UnresolvedProcMacro) => {
-                self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
-                    UnresolvedProcMacro {
-                        file: outer_file,
-                        node: syntax_ptr.into(),
-                        precise_location: None,
-                        macro_name: None,
-                    },
-                ));
-            }
-            Some(err) => {
-                self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError {
-                    file: outer_file,
-                    node: syntax_ptr.into(),
-                    message: err.to_string(),
-                }));
-            }
-            None => {}
-        }
+                if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) {
+                    let mac = MacroDefId {
+                        krate: Some(self.expander.module.krate),
+                        ast_id: Some(self.expander.ast_id(&e)),
+                        kind: MacroDefKind::Declarative,
+                        local_inner: false,
+                    };
+                    self.body.item_scope.define_legacy_macro(name, mac);
 
-        match res.value {
-            Some((mark, expansion)) => {
-                // FIXME: Statements are too complicated to recover from error for now.
-                // It is because we don't have any hygenine for local variable expansion right now.
-                if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
-                    self.expander.exit(self.db, mark);
-                    collector(self, None);
+                    // FIXME: do we still need to allocate this as missing ?
+                    self.alloc_expr(Expr::Missing, syntax_ptr)
                 } else {
-                    self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
-
-                    let item_tree = self.db.item_tree(self.expander.current_file_id);
-                    self.item_trees.insert(self.expander.current_file_id, item_tree);
+                    // File containing the macro call. Expansion errors will be attached here.
+                    let outer_file = self.expander.current_file_id;
+
+                    let macro_call = self.expander.to_source(AstPtr::new(&e));
+                    let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);
+
+                    match res.err {
+                        Some(ExpandError::UnresolvedProcMacro) => {
+                            self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
+                                UnresolvedProcMacro {
+                                    file: outer_file,
+                                    node: syntax_ptr.clone().into(),
+                                    precise_location: None,
+                                    macro_name: None,
+                                },
+                            ));
+                        }
+                        Some(err) => {
+                            self.source_map.diagnostics.push(BodyDiagnostic::MacroError(
+                                MacroError {
+                                    file: outer_file,
+                                    node: syntax_ptr.clone().into(),
+                                    message: err.to_string(),
+                                },
+                            ));
+                        }
+                        None => {}
+                    }
 
-                    let id = collector(self, Some(expansion));
-                    self.expander.exit(self.db, mark);
-                    id
+                    match res.value {
+                        Some((mark, expansion)) => {
+                            self.source_map
+                                .expansions
+                                .insert(macro_call, self.expander.current_file_id);
+
+                            let item_tree = self.db.item_tree(self.expander.current_file_id);
+                            self.item_trees.insert(self.expander.current_file_id, item_tree);
+                            let id = self.collect_expr(expansion);
+                            self.expander.exit(self.db, mark);
+                            id
+                        }
+                        None => self.alloc_expr(Expr::Missing, syntax_ptr),
+                    }
                 }
             }
-            None => collector(self, None),
         }
     }
 
@@ -649,75 +642,44 @@ impl ExprCollector<'_> {
         }
     }
 
-    fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
-        let stmt =
-            match s {
-                ast::Stmt::LetStmt(stmt) => {
-                    self.check_cfg(&stmt)?;
-
-                    let pat = self.collect_pat_opt(stmt.pat());
-                    let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
-                    let initializer = stmt.initializer().map(|e| self.collect_expr(e));
-                    vec![Statement::Let { pat, type_ref, initializer }]
-                }
-                ast::Stmt::ExprStmt(stmt) => {
-                    self.check_cfg(&stmt)?;
-
-                    // Note that macro could be expended to multiple statements
-                    if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
-                        let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
-                        let mut stmts = vec![];
-
-                        self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| {
-                            match expansion {
-                                Some(expansion) => {
-                                    let statements: ast::MacroStmts = expansion;
-                                    this.collect_stmts_items(statements.statements());
-
-                                    statements.statements().for_each(|stmt| {
-                                        if let Some(mut r) = this.collect_stmt(stmt) {
-                                            stmts.append(&mut r);
-                                        }
-                                    });
-                                    if let Some(expr) = statements.expr() {
-                                        stmts.push(Statement::Expr(this.collect_expr(expr)));
-                                    }
-                                }
-                                None => {
-                                    stmts.push(Statement::Expr(
-                                        this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
-                                    ));
-                                }
-                            }
-                        });
-                        stmts
-                    } else {
-                        vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
+    fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
+        let syntax_node_ptr = AstPtr::new(&block.clone().into());
+        self.collect_block_items(&block);
+        let statements = block
+            .statements()
+            .filter_map(|s| {
+                let stmt = match s {
+                    ast::Stmt::LetStmt(stmt) => {
+                        self.check_cfg(&stmt)?;
+
+                        let pat = self.collect_pat_opt(stmt.pat());
+                        let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
+                        let initializer = stmt.initializer().map(|e| self.collect_expr(e));
+                        Statement::Let { pat, type_ref, initializer }
                     }
-                }
-                ast::Stmt::Item(item) => {
-                    self.check_cfg(&item)?;
+                    ast::Stmt::ExprStmt(stmt) => {
+                        self.check_cfg(&stmt)?;
 
-                    return None;
-                }
-            };
-
-        Some(stmt)
-    }
+                        Statement::Expr(self.collect_expr_opt(stmt.expr()))
+                    }
+                    ast::Stmt::Item(item) => {
+                        self.check_cfg(&item)?;
 
-    fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
-        let syntax_node_ptr = AstPtr::new(&block.clone().into());
-        self.collect_stmts_items(block.statements());
-        let statements =
-            block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
+                        return None;
+                    }
+                };
+                Some(stmt)
+            })
+            .collect();
         let tail = block.expr().map(|e| self.collect_expr(e));
         self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr)
     }
 
-    fn collect_stmts_items(&mut self, stmts: ast::AstChildren<ast::Stmt>) {
+    fn collect_block_items(&mut self, block: &ast::BlockExpr) {
         let container = ContainerId::DefWithBodyId(self.def);
 
-        let items = stmts
+        let items = block
+            .statements()
             .filter_map(|stmt| match stmt {
                 ast::Stmt::Item(it) => Some(it),
                 ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None,
@@ -771,44 +733,26 @@ impl ExprCollector<'_> {
                     | ast::Item::ExternCrate(_)
                     | ast::Item::Module(_)
                     | ast::Item::MacroCall(_) => return None,
-                    ast::Item::MacroRules(def) => {
-                        return Some(Either::Right(def));
-                    }
                 };
 
-                Some(Either::Left((def, name)))
+                Some((def, name))
             })
             .collect::<Vec<_>>();
 
-        for either in items {
-            match either {
-                Either::Left((def, name)) => {
-                    self.body.item_scope.define_def(def);
-                    if let Some(name) = name {
-                        let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
-                        let has_constructor = match def {
-                            ModuleDefId::AdtId(AdtId::StructId(s)) => {
-                                self.db.struct_data(s).variant_data.kind() != StructKind::Record
-                            }
-                            _ => true,
-                        };
-                        self.body.item_scope.push_res(
-                            name.as_name(),
-                            crate::per_ns::PerNs::from_def(def, vis, has_constructor),
-                        );
+        for (def, name) in items {
+            self.body.item_scope.define_def(def);
+            if let Some(name) = name {
+                let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
+                let has_constructor = match def {
+                    ModuleDefId::AdtId(AdtId::StructId(s)) => {
+                        self.db.struct_data(s).variant_data.kind() != StructKind::Record
                     }
-                }
-                Either::Right(e) => {
-                    let mac = MacroDefId {
-                        krate: Some(self.expander.module.krate),
-                        ast_id: Some(self.expander.ast_id(&e)),
-                        kind: MacroDefKind::Declarative,
-                        local_inner: false,
-                    };
-                    if let Some(name) = e.name() {
-                        self.body.item_scope.define_legacy_macro(name.as_name(), mac);
-                    }
-                }
+                    _ => true,
+                };
+                self.body.item_scope.push_res(
+                    name.as_name(),
+                    crate::per_ns::PerNs::from_def(def, vis, has_constructor),
+                );
             }
         }
     }
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 81912a4546..924046435b 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -19,7 +19,7 @@ use crate::{
     db::DefDatabase,
     dyn_map::DynMap,
     keys,
-    src::HasSource,
+    src::{HasChildSource, HasSource},
     type_ref::{LifetimeRef, TypeBound, TypeRef},
     AdtId, GenericDefId, LifetimeParamId, LocalLifetimeParamId, LocalTypeParamId, Lookup,
     TypeParamId,
@@ -73,9 +73,9 @@ pub enum WherePredicateTypeTarget {
 }
 
 #[derive(Default)]
-pub struct SourceMaps {
-    pub type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>,
-    pub lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>,
+pub(crate) struct SourceMap {
+    pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>,
+    lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>,
 }
 
 impl GenericParams {
@@ -133,9 +133,9 @@ impl GenericParams {
         Arc::new(generics)
     }
 
-    fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMaps>) {
+    fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
         let mut generics = GenericParams::default();
-        let mut sm = SourceMaps::default();
+        let mut sm = SourceMap::default();
 
         // FIXME: add `: Sized` bound for everything except for `Self` in traits
         let file_id = match def {
@@ -214,7 +214,7 @@ impl GenericParams {
     pub(crate) fn fill(
         &mut self,
         lower_ctx: &LowerCtx,
-        sm: &mut SourceMaps,
+        sm: &mut SourceMap,
         node: &dyn GenericParamsOwner,
     ) {
         if let Some(params) = node.generic_param_list() {
@@ -241,7 +241,7 @@ impl GenericParams {
     fn fill_params(
         &mut self,
         lower_ctx: &LowerCtx,
-        sm: &mut SourceMaps,
+        sm: &mut SourceMap,
         params: ast::GenericParamList,
     ) {
         for type_param in params.type_params() {
@@ -345,10 +345,24 @@ impl GenericParams {
         })
     }
 }
-impl GenericDefId {
-    // FIXME: Change HasChildSource's ChildId AssocItem to be a generic parameter instead
-    pub fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMaps> {
-        GenericParams::new(db, *self).1
+
+impl HasChildSource<LocalTypeParamId> for GenericDefId {
+    type Value = Either<ast::Trait, ast::TypeParam>;
+    fn child_source(
+        &self,
+        db: &dyn DefDatabase,
+    ) -> InFile<ArenaMap<LocalTypeParamId, Self::Value>> {
+        GenericParams::new(db, *self).1.map(|source_maps| source_maps.type_params)
+    }
+}
+
+impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
+    type Value = ast::LifetimeParam;
+    fn child_source(
+        &self,
+        db: &dyn DefDatabase,
+    ) -> InFile<ArenaMap<LocalLifetimeParamId, Self::Value>> {
+        GenericParams::new(db, *self).1.map(|source_maps| source_maps.lifetime_params)
     }
 }
 
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 1c9babf371..b08167281d 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -94,9 +94,6 @@ impl ItemTree {
                 ast::MacroItems(items) => {
                     ctx.lower_module_items(&items)
                 },
-                ast::MacroStmts(stmts) => {
-                    ctx.lower_inner_items(stmts.syntax())
-                },
                 // Macros can expand to expressions. We return an empty item tree in this case, but
                 // still need to collect inner items.
                 ast::Expr(e) => {
@@ -142,7 +139,6 @@ impl ItemTree {
                 type_aliases,
                 mods,
                 macro_calls,
-                macro_rules,
                 exprs,
                 vis,
                 generics,
@@ -163,7 +159,6 @@ impl ItemTree {
             type_aliases.shrink_to_fit();
             mods.shrink_to_fit();
             macro_calls.shrink_to_fit();
-            macro_rules.shrink_to_fit();
             exprs.shrink_to_fit();
 
             vis.arena.shrink_to_fit();
@@ -282,7 +277,6 @@ struct ItemTreeData {
     type_aliases: Arena<TypeAlias>,
     mods: Arena<Mod>,
     macro_calls: Arena<MacroCall>,
-    macro_rules: Arena<MacroRules>,
     exprs: Arena<Expr>,
 
     vis: ItemVisibilities,
@@ -430,7 +424,6 @@ mod_items! {
     TypeAlias in type_aliases -> ast::TypeAlias,
     Mod in mods -> ast::Module,
     MacroCall in macro_calls -> ast::MacroCall,
-    MacroRules in macro_rules -> ast::MacroRules,
 }
 
 macro_rules! impl_index {
@@ -633,22 +626,17 @@ pub enum ModKind {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct MacroCall {
+    /// For `macro_rules!` declarations, this is the name of the declared macro.
+    pub name: Option<Name>,
     /// Path to the called macro.
     pub path: ModPath,
-    pub ast_id: FileAstId<ast::MacroCall>,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct MacroRules {
-    /// For `macro_rules!` declarations, this is the name of the declared macro.
-    pub name: Name,
     /// Has `#[macro_export]`.
     pub is_export: bool,
     /// Has `#[macro_export(local_inner_macros)]`.
     pub is_local_inner: bool,
     /// Has `#[rustc_builtin_macro]`.
     pub is_builtin: bool,
-    pub ast_id: FileAstId<ast::MacroRules>,
+    pub ast_id: FileAstId<ast::MacroCall>,
 }
 
 // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
@@ -679,8 +667,7 @@ impl ModItem {
             | ModItem::Static(_)
             | ModItem::Trait(_)
             | ModItem::Impl(_)
-            | ModItem::Mod(_)
-            | ModItem::MacroRules(_) => None,
+            | ModItem::Mod(_) => None,
             ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
             ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
             ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
@@ -707,7 +694,6 @@ impl ModItem {
             ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(),
             ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
             ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
-            ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(),
         }
     }
 }
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index b39d7fb7ac..2939c6b1e3 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -84,7 +84,8 @@ impl Ctx {
             | ast::Item::Fn(_)
             | ast::Item::TypeAlias(_)
             | ast::Item::Const(_)
-            | ast::Item::Static(_) => {
+            | ast::Item::Static(_)
+            | ast::Item::MacroCall(_) => {
                 // Skip this if we're already collecting inner items. We'll descend into all nodes
                 // already.
                 if !inner {
@@ -97,11 +98,7 @@ impl Ctx {
             ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {}
 
             // These don't have inner items.
-            ast::Item::Module(_)
-            | ast::Item::ExternCrate(_)
-            | ast::Item::Use(_)
-            | ast::Item::MacroCall(_)
-            | ast::Item::MacroRules(_) => {}
+            ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {}
         };
 
         let attrs = Attrs::new(item, &self.hygiene);
@@ -121,7 +118,6 @@ impl Ctx {
             )),
             ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
             ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
-            ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
             ast::Item::ExternBlock(ast) => {
                 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
             }
@@ -529,15 +525,9 @@ impl Ctx {
     }
 
     fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
-        let path = ModPath::from_src(m.path()?, &self.hygiene)?;
-        let ast_id = self.source_ast_id_map.ast_id(m);
-        let res = MacroCall { path, ast_id };
-        Some(id(self.data().macro_calls.alloc(res)))
-    }
-
-    fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<FileItemTreeId<MacroRules>> {
-        let name = m.name().map(|it| it.as_name())?;
+        let name = m.name().map(|it| it.as_name());
         let attrs = Attrs::new(m, &self.hygiene);
+        let path = ModPath::from_src(m.path()?, &self.hygiene)?;
 
         let ast_id = self.source_ast_id_map.ast_id(m);
 
@@ -557,8 +547,8 @@ impl Ctx {
         };
 
         let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
-        let res = MacroRules { name, is_export, is_builtin, is_local_inner, ast_id };
-        Some(id(self.data().macro_rules.alloc(res)))
+        let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id };
+        Some(id(self.data().macro_calls.alloc(res)))
     }
 
     fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 85cc342c44..19cd713ba0 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -11,7 +11,7 @@ use hir_expand::{
     ast_id_map::FileAstId,
     builtin_derive::find_builtin_derive,
     builtin_macro::find_builtin_macro,
-    name::{AsName, Name},
+    name::{name, AsName, Name},
     proc_macro::ProcMacroExpander,
     HirFileId, MacroCallId, MacroDefId, MacroDefKind,
 };
@@ -25,9 +25,7 @@ use crate::{
     attr::Attrs,
     db::DefDatabase,
     item_scope::{ImportType, PerNsGlobImports},
-    item_tree::{
-        self, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, StructDefKind,
-    },
+    item_tree::{self, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind},
     nameres::{
         diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
         BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
@@ -974,8 +972,7 @@ impl ModCollector<'_, '_> {
                         status: PartialResolvedImport::Unresolved,
                     })
                 }
-                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
-                ModItem::MacroRules(mac) => self.collect_macro_rules(&self.item_tree[mac]),
+                ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]),
                 ModItem::Impl(imp) => {
                     let module = ModuleId {
                         krate: self.def_collector.def_map.krate,
@@ -1279,37 +1276,45 @@ impl ModCollector<'_, '_> {
         self.def_collector.resolve_proc_macro(&macro_name);
     }
 
-    fn collect_macro_rules(&mut self, mac: &MacroRules) {
-        let ast_id = InFile::new(self.file_id, mac.ast_id);
+    fn collect_macro(&mut self, mac: &MacroCall) {
+        let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
 
-        // Case 1: builtin macros
+        // Case 0: builtin macros
         if mac.is_builtin {
-            let krate = self.def_collector.def_map.krate;
-            if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) {
+            if let Some(name) = &mac.name {
+                let krate = self.def_collector.def_map.krate;
+                if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) {
+                    self.def_collector.define_macro(
+                        self.module_id,
+                        name.clone(),
+                        macro_id,
+                        mac.is_export,
+                    );
+                    return;
+                }
+            }
+        }
+
+        // Case 1: macro rules, define a macro in crate-global mutable scope
+        if is_macro_rules(&mac.path) {
+            if let Some(name) = &mac.name {
+                let macro_id = MacroDefId {
+                    ast_id: Some(ast_id.ast_id),
+                    krate: Some(self.def_collector.def_map.krate),
+                    kind: MacroDefKind::Declarative,
+                    local_inner: mac.is_local_inner,
+                };
                 self.def_collector.define_macro(
                     self.module_id,
-                    mac.name.clone(),
+                    name.clone(),
                     macro_id,
                     mac.is_export,
                 );
-                return;
             }
+            return;
         }
 
-        // Case 2: normal `macro_rules!` macro
-        let macro_id = MacroDefId {
-            ast_id: Some(ast_id),
-            krate: Some(self.def_collector.def_map.krate),
-            kind: MacroDefKind::Declarative,
-            local_inner: mac.is_local_inner,
-        };
-        self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, mac.is_export);
-    }
-
-    fn collect_macro_call(&mut self, mac: &MacroCall) {
-        let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
-
-        // Case 1: try to resolve in legacy scope and expand macro_rules
+        // Case 2: try to resolve in legacy scope and expand macro_rules
         if let Some(macro_call_id) =
             ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
                 path.as_ident().and_then(|name| {
@@ -1327,7 +1332,7 @@ impl ModCollector<'_, '_> {
             return;
         }
 
-        // Case 2: resolve in module scope, expand during name resolution.
+        // Case 3: resolve in module scope, expand during name resolution.
         // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
         if ast_id.path.is_ident() {
             ast_id.path.kind = PathKind::Super(0);
@@ -1365,6 +1370,10 @@ impl ModCollector<'_, '_> {
     }
 }
 
+fn is_macro_rules(path: &ModPath) -> bool {
+    path.as_ident() == Some(&name![macro_rules])
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{db::DefDatabase, test_db::TestDB};
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 6099250129..60fa7646b2 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -122,9 +122,11 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
     // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
     // We follow what it did anyway :)
     if segments.len() == 1 && kind == PathKind::Plain {
-        if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
-            if let Some(crate_id) = hygiene.local_inner_macros() {
-                kind = PathKind::DollarCrate(crate_id);
+        if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
+            if macro_call.is_bang() {
+                if let Some(crate_id) = hygiene.local_inner_macros() {
+                    kind = PathKind::DollarCrate(crate_id);
+                }
             }
         }
     }
diff --git a/crates/hir_def/src/src.rs b/crates/hir_def/src/src.rs
index 7a79b03149..f67244b464 100644
--- a/crates/hir_def/src/src.rs
+++ b/crates/hir_def/src/src.rs
@@ -36,8 +36,7 @@ impl<N: ItemTreeNode> HasSource for ItemLoc<N> {
     }
 }
 
-pub trait HasChildSource {
-    type ChildId;
+pub trait HasChildSource<ChildId> {
     type Value;
-    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>>;
+    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<ChildId, Self::Value>>;
 }
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index bd92238257..8db8c7d0c0 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -63,7 +63,7 @@ macro_rules! register_builtin {
 pub fn find_builtin_macro(
     ident: &name::Name,
     krate: CrateId,
-    ast_id: AstId<ast::MacroRules>,
+    ast_id: AstId<ast::MacroCall>,
 ) -> Option<MacroDefId> {
     let kind = find_by_name(ident)?;
 
@@ -95,8 +95,6 @@ register_builtin! {
     // format_args_nl only differs in that it adds a newline in the end,
     // so we use the same stub expansion for now
     (format_args_nl, FormatArgsNl) => format_args_expand,
-    (llvm_asm, LlvmAsm) => asm_expand,
-    (asm, Asm) => asm_expand,
 
     EAGER:
     (compile_error, CompileError) => compile_error_expand,
@@ -273,19 +271,6 @@ fn format_args_expand(
     ExpandResult::ok(expanded)
 }
 
-fn asm_expand(
-    _db: &dyn AstDatabase,
-    _id: LazyMacroId,
-    _tt: &tt::Subtree,
-) -> ExpandResult<tt::Subtree> {
-    // both asm and llvm_asm don't return anything, so we can expand them to nothing,
-    // for now
-    let expanded = quote! {
-        ()
-    };
-    ExpandResult::ok(expanded)
-}
-
 fn unquote_str(lit: &tt::Literal) -> Option<String> {
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::String::cast(lit)?;
@@ -515,16 +500,12 @@ mod tests {
     fn expand_builtin_macro(ra_fixture: &str) -> String {
         let (db, file_id) = TestDB::with_single_file(&ra_fixture);
         let parsed = db.parse(file_id);
-        let macro_rules: Vec<_> =
-            parsed.syntax_node().descendants().filter_map(ast::MacroRules::cast).collect();
         let macro_calls: Vec<_> =
             parsed.syntax_node().descendants().filter_map(ast::MacroCall::cast).collect();
 
         let ast_id_map = db.ast_id_map(file_id.into());
 
-        assert_eq!(macro_rules.len(), 1, "test must contain exactly 1 `macro_rules!`");
-        assert_eq!(macro_calls.len(), 1, "test must contain exactly 1 macro call");
-        let expander = find_by_name(&macro_rules[0].name().unwrap().as_name()).unwrap();
+        let expander = find_by_name(&macro_calls[0].name().unwrap().as_name()).unwrap();
 
         let krate = CrateId(0);
         let file_id = match expander {
@@ -532,7 +513,7 @@ mod tests {
                 // the first one should be a macro_rules
                 let def = MacroDefId {
                     krate: Some(CrateId(0)),
-                    ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules[0]))),
+                    ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
                     kind: MacroDefKind::BuiltIn(expander),
                     local_inner: false,
                 };
@@ -542,7 +523,7 @@ mod tests {
                     krate,
                     kind: MacroCallKind::FnLike(AstId::new(
                         file_id.into(),
-                        ast_id_map.ast_id(&macro_calls[0]),
+                        ast_id_map.ast_id(&macro_calls[1]),
                     )),
                 };
 
@@ -553,12 +534,12 @@ mod tests {
                 // the first one should be a macro_rules
                 let def = MacroDefId {
                     krate: Some(krate),
-                    ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules[0]))),
+                    ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
                     kind: MacroDefKind::BuiltInEager(expander),
                     local_inner: false,
                 };
 
-                let args = macro_calls[0].token_tree().unwrap();
+                let args = macro_calls[1].token_tree().unwrap();
                 let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0;
 
                 let arg_id = db.intern_eager_expansion({
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 11b5b98c87..ffb70f723c 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -394,8 +394,8 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
             // FIXME: Handle Pattern
             FragmentKind::Expr
         }
-        EXPR_STMT => FragmentKind::Statements,
-        BLOCK_EXPR => FragmentKind::Expr,
+        // FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that
+        EXPR_STMT | BLOCK_EXPR => FragmentKind::Expr,
         ARG_LIST => FragmentKind::Expr,
         TRY_EXPR => FragmentKind::Expr,
         TUPLE_EXPR => FragmentKind::Expr,
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index ae3086a95b..1a94285143 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -228,7 +228,7 @@ pub struct MacroDefId {
     // (which will probably require touching this code), we can instead use
     // that (and also remove the hacks for resolving built-in derives).
     pub krate: Option<CrateId>,
-    pub ast_id: Option<AstId<ast::MacroRules>>,
+    pub ast_id: Option<AstId<ast::MacroCall>>,
     pub kind: MacroDefKind,
 
     pub local_inner: bool,
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 69d8e68039..6ec5ca0a97 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -199,8 +199,6 @@ pub mod known {
         format_args_nl,
         env,
         option_env,
-        llvm_asm,
-        asm,
         // Builtin derives
         Copy,
         Clone,
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index c515313914..415795e8cd 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -150,7 +150,13 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
                 };
                 Some(node)
             },
-            ast::MacroRules(it) => decl(it),
+            ast::MacroCall(it) => {
+                match it.path().and_then(|it| it.segment()).and_then(|it| it.name_ref()) {
+                    Some(path_segment) if path_segment.text() == "macro_rules"
+                    => decl(it),
+                    _ => None,
+                }
+            },
             _ => None,
         }
     }
@@ -374,7 +380,7 @@ fn very_obsolete() {}
                         label: "mc",
                         navigation_range: 284..286,
                         node_range: 271..303,
-                        kind: MACRO_RULES,
+                        kind: MACRO_CALL,
                         detail: None,
                         deprecated: false,
                     },
@@ -383,7 +389,7 @@ fn very_obsolete() {}
                         label: "mcexp",
                         navigation_range: 334..339,
                         node_range: 305..356,
-                        kind: MACRO_RULES,
+                        kind: MACRO_CALL,
                         detail: None,
                         deprecated: false,
                     },
@@ -392,7 +398,7 @@ fn very_obsolete() {}
                         label: "mcexp",
                         navigation_range: 387..392,
                         node_range: 358..409,
-                        kind: MACRO_RULES,
+                        kind: MACRO_CALL,
                         detail: None,
                         deprecated: false,
                     },
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 675957fff6..7395b81bd2 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -97,9 +97,6 @@ pub(crate) fn find_all_refs(
         get_struct_def_name_for_struct_literal_search(&sema, &syntax, position)
     {
         (Some(name), ReferenceKind::StructLiteral)
-    } else if let Some(name) = get_enum_def_name_for_struct_literal_search(&sema, &syntax, position)
-    {
-        (Some(name), ReferenceKind::EnumLiteral)
     } else {
         (
             sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset),
@@ -201,33 +198,6 @@ fn get_struct_def_name_for_struct_literal_search(
     None
 }
 
-fn get_enum_def_name_for_struct_literal_search(
-    sema: &Semantics<RootDatabase>,
-    syntax: &SyntaxNode,
-    position: FilePosition,
-) -> Option<ast::Name> {
-    if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) {
-        if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN {
-            return None;
-        }
-        if let Some(name) =
-            sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start())
-        {
-            return name.syntax().ancestors().find_map(ast::Enum::cast).and_then(|l| l.name());
-        }
-        if sema
-            .find_node_at_offset_with_descend::<ast::GenericParamList>(
-                &syntax,
-                left.text_range().start(),
-            )
-            .is_some()
-        {
-            return left.ancestors().find_map(ast::Enum::cast).and_then(|l| l.name());
-        }
-    }
-    None
-}
-
 fn try_find_self_references(
     syntax: &SyntaxNode,
     position: FilePosition,
@@ -386,91 +356,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn test_enum_after_space() {
-        check(
-            r#"
-enum Foo <|>{
-    A,
-    B,
-}
-fn main() {
-    let f: Foo;
-    f = Foo::A;
-}
-"#,
-            expect![[r#"
-                Foo ENUM FileId(0) 0..26 5..8 Other
-
-                FileId(0) 63..66 EnumLiteral
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_enum_before_space() {
-        check(
-            r#"
-enum Foo<|> {
-    A,
-    B,
-}
-fn main() {
-    let f: Foo;
-    f = Foo::A;
-}
-"#,
-            expect![[r#"
-                Foo ENUM FileId(0) 0..26 5..8 Other
-
-                FileId(0) 50..53 Other
-                FileId(0) 63..66 EnumLiteral
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_enum_with_generic_type() {
-        check(
-            r#"
-enum Foo<T> <|>{
-    A(T),
-    B,
-}
-fn main() {
-    let f: Foo<i8>;
-    f = Foo::A(1);
-}
-"#,
-            expect![[r#"
-                Foo ENUM FileId(0) 0..32 5..8 Other
-
-                FileId(0) 73..76 EnumLiteral
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_enum_for_tuple() {
-        check(
-            r#"
-enum Foo<|>{
-    A(i8),
-    B(i8),
-}
-fn main() {
-    let f: Foo;
-    f = Foo::A(1);
-}
-"#,
-            expect![[r#"
-                Foo ENUM FileId(0) 0..33 5..8 Other
-
-                FileId(0) 70..73 EnumLiteral
-            "#]],
-        );
-    }
-
     #[test]
     fn test_find_all_refs_for_local() {
         check(
@@ -770,7 +655,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-                m1 MACRO_RULES FileId(0) 0..46 29..31 Other
+                m1 MACRO_CALL FileId(0) 0..46 29..31 Other
 
                 FileId(0) 63..65 StructLiteral
                 FileId(0) 73..75 StructLiteral
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 990b0f7d95..f5c6eabeff 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -74,7 +74,6 @@ pub(crate) fn highlight(
     let mut stack = HighlightedRangeStack::new();
 
     let mut current_macro_call: Option<ast::MacroCall> = None;
-    let mut current_macro_rules: Option<ast::MacroRules> = None;
     let mut format_string_highlighter = FormatStringHighlighter::default();
     let mut macro_rules_highlighter = MacroRulesHighlighter::default();
     let mut inside_attribute = false;
@@ -107,26 +106,28 @@ pub(crate) fn highlight(
                         binding_hash: None,
                     });
                 }
+                if let Some(name) = mc.is_macro_rules() {
+                    macro_rules_highlighter.init();
+                    if let Some((highlight, binding_hash)) = highlight_element(
+                        &sema,
+                        &mut bindings_shadow_count,
+                        syntactic_name_ref_highlighting,
+                        name.syntax().clone().into(),
+                    ) {
+                        stack.add(HighlightedRange {
+                            range: name.syntax().text_range(),
+                            highlight,
+                            binding_hash,
+                        });
+                    }
+                }
                 current_macro_call = Some(mc.clone());
                 continue;
             }
             WalkEvent::Leave(Some(mc)) => {
-                assert_eq!(current_macro_call, Some(mc));
+                assert!(current_macro_call == Some(mc));
                 current_macro_call = None;
                 format_string_highlighter = FormatStringHighlighter::default();
-            }
-            _ => (),
-        }
-
-        match event.clone().map(|it| it.into_node().and_then(ast::MacroRules::cast)) {
-            WalkEvent::Enter(Some(mac)) => {
-                macro_rules_highlighter.init();
-                current_macro_rules = Some(mac);
-                continue;
-            }
-            WalkEvent::Leave(Some(mac)) => {
-                assert_eq!(current_macro_rules, Some(mac));
-                current_macro_rules = None;
                 macro_rules_highlighter = MacroRulesHighlighter::default();
             }
             _ => (),
@@ -162,12 +163,6 @@ pub(crate) fn highlight(
 
         let range = element.text_range();
 
-        if current_macro_rules.is_some() {
-            if let Some(tok) = element.as_token() {
-                macro_rules_highlighter.advance(tok);
-            }
-        }
-
         let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT {
             // Inside a macro -- expand it first
             let token = match element.clone().into_token() {
@@ -178,6 +173,9 @@ pub(crate) fn highlight(
             let parent = token.parent();
 
             format_string_highlighter.check_for_format_string(&parent);
+            if let Some(tok) = element.as_token() {
+                macro_rules_highlighter.advance(tok);
+            }
 
             // We only care Name and Name_ref
             match (token.kind(), parent.kind()) {
@@ -388,14 +386,10 @@ impl HighlightedRangeStack {
         let mut res = self.stack.pop().unwrap();
         res.sort_by_key(|range| range.range.start());
         // Check that ranges are sorted and disjoint
-        for (left, right) in res.iter().zip(res.iter().skip(1)) {
-            assert!(
-                left.range.end() <= right.range.start(),
-                "left: {:#?}, right: {:#?}",
-                left,
-                right
-            );
-        }
+        assert!(res
+            .iter()
+            .zip(res.iter().skip(1))
+            .all(|(left, right)| left.range.end() <= right.range.start()));
         res
     }
 }
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index d4a774261c..5d2cd30d1e 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -217,7 +217,7 @@ impl NameClass {
                     let def: hir::TypeAlias = sema.to_def(&it)?;
                     Some(NameClass::Definition(Definition::ModuleDef(def.into())))
                 },
-                ast::MacroRules(it) => {
+                ast::MacroCall(it) => {
                     let def = sema.to_def(&it)?;
                     Some(NameClass::Definition(Definition::Macro(def)))
                 },
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 3936c7390f..607185ca97 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -32,7 +32,6 @@ pub enum ReferenceKind {
     StructLiteral,
     RecordFieldExprOrPat,
     SelfKw,
-    EnumLiteral,
     Other,
 }
 
@@ -285,8 +284,6 @@ impl<'a> FindUsages<'a> {
                     ReferenceKind::RecordFieldExprOrPat
                 } else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) {
                     ReferenceKind::StructLiteral
-                } else if is_enum_lit_name_ref(&name_ref) {
-                    ReferenceKind::EnumLiteral
                 } else {
                     ReferenceKind::Other
                 };
@@ -405,15 +402,3 @@ fn is_record_field_expr_or_pat(name_ref: &ast::NameRef) -> bool {
         false
     }
 }
-
-fn is_enum_lit_name_ref(name_ref: &ast::NameRef) -> bool {
-    name_ref
-        .syntax()
-        .ancestors()
-        .find_map(ast::PathExpr::cast)
-        .and_then(|p| p.path())
-        .and_then(|p| p.qualifier())
-        .and_then(|p| p.segment())
-        .map(|p| p.name_ref().as_ref() == Some(name_ref))
-        .unwrap_or(false)
-}
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 121063aeab..654df898e9 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -404,7 +404,13 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
             ast::TypeAlias(it) => decl(it),
             ast::Const(it) => decl(it),
             ast::Static(it) => decl(it),
-            ast::MacroRules(it) => decl(it),
+            ast::MacroCall(it) => {
+                if it.is_macro_rules().is_some() {
+                    decl(it)
+                } else {
+                    None
+                }
+            },
             _ => None,
         }
     }
diff --git a/crates/mbe/src/mbe_expander.rs b/crates/mbe/src/mbe_expander.rs
index a80b73db4c..97bce0536f 100644
--- a/crates/mbe/src/mbe_expander.rs
+++ b/crates/mbe/src/mbe_expander.rs
@@ -163,7 +163,7 @@ mod tests {
     fn create_rules(macro_definition: &str) -> crate::MacroRules {
         let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap();
         let macro_definition =
-            source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
+            source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
 
         let (definition_tt, _) =
             ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
index 8999829b43..ad29b82f77 100644
--- a/crates/parser/src/grammar/items.rs
+++ b/crates/parser/src/grammar/items.rs
@@ -232,9 +232,6 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
         T![macro] => {
             macro_def(p, m);
         }
-        IDENT if p.at_contextual_kw("macro_rules") && p.nth(1) == BANG => {
-            macro_rules(p, m);
-        }
         IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
             // test union_items
             // union Foo {}
@@ -366,34 +363,6 @@ pub(crate) fn item_list(p: &mut Parser) {
     m.complete(p, ITEM_LIST);
 }
 
-fn macro_rules(p: &mut Parser, m: Marker) {
-    assert!(p.at_contextual_kw("macro_rules"));
-    p.bump_remap(T![macro_rules]);
-    p.expect(T![!]);
-
-    if p.at(IDENT) {
-        name(p);
-    }
-    // Special-case `macro_rules! try`.
-    // This is a hack until we do proper edition support
-
-    // test try_macro_rules
-    // macro_rules! try { () => {} }
-    if p.at(T![try]) {
-        let m = p.start();
-        p.bump_remap(IDENT);
-        m.complete(p, NAME);
-    }
-
-    match p.current() {
-        T!['{'] => {
-            token_tree(p);
-        }
-        _ => p.error("expected `{`"),
-    }
-    m.complete(p, MACRO_RULES);
-}
-
 // test macro_def
 // macro m { ($i:ident) => {} }
 // macro m($i:ident) {}
@@ -425,6 +394,19 @@ fn macro_call(p: &mut Parser) -> BlockLike {
 
 pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
     p.expect(T![!]);
+    if p.at(IDENT) {
+        name(p);
+    }
+    // Special-case `macro_rules! try`.
+    // This is a hack until we do proper edition support
+
+    // test try_macro_rules
+    // macro_rules! try { () => {} }
+    if p.at(T![try]) {
+        let m = p.start();
+        p.bump_remap(IDENT);
+        m.complete(p, NAME);
+    }
 
     match p.current() {
         T!['{'] => {
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index 5d6ec17a4c..8bc6688f3c 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -106,7 +106,6 @@ pub enum SyntaxKind {
     EXISTENTIAL_KW,
     UNION_KW,
     RAW_KW,
-    MACRO_RULES_KW,
     INT_NUMBER,
     FLOAT_NUMBER,
     CHAR,
@@ -136,8 +135,6 @@ pub enum SyntaxKind {
     IMPL,
     TYPE_ALIAS,
     MACRO_CALL,
-    MACRO_RULES,
-    MACRO_ARM,
     TOKEN_TREE,
     MACRO_DEF,
     PAREN_TYPE,
@@ -261,7 +258,7 @@ impl SyntaxKind {
             | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
             | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW
             | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW
-            | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW | MACRO_RULES_KW => true,
+            | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW => true,
             _ => false,
         }
     }
@@ -364,4 +361,4 @@ impl SyntaxKind {
     }
 }
 #[macro_export]
-macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime] => { $ crate :: SyntaxKind :: LIFETIME } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
+macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [lifetime] => { $ crate :: SyntaxKind :: LIFETIME } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 0ad75214fc..30d11b1464 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -128,6 +128,7 @@ pub struct MacroCall {
     pub(crate) syntax: SyntaxNode,
 }
 impl ast::AttrsOwner for MacroCall {}
+impl ast::NameOwner for MacroCall {}
 impl MacroCall {
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
     pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
@@ -272,20 +273,6 @@ impl Impl {
     pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct MacroRules {
-    pub(crate) syntax: SyntaxNode,
-}
-impl ast::AttrsOwner for MacroRules {}
-impl ast::NameOwner for MacroRules {}
-impl ast::VisibilityOwner for MacroRules {}
-impl MacroRules {
-    pub fn macro_rules_token(&self) -> Option<SyntaxToken> {
-        support::token(&self.syntax, T![macro_rules])
-    }
-    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
-    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
-}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Module {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1331,7 +1318,6 @@ pub enum Item {
     Fn(Fn),
     Impl(Impl),
     MacroCall(MacroCall),
-    MacroRules(MacroRules),
     Module(Module),
     Static(Static),
     Struct(Struct),
@@ -1388,6 +1374,7 @@ pub enum AssocItem {
     TypeAlias(TypeAlias),
 }
 impl ast::AttrsOwner for AssocItem {}
+impl ast::NameOwner for AssocItem {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum ExternItem {
     Fn(Fn),
@@ -1396,6 +1383,7 @@ pub enum ExternItem {
     TypeAlias(TypeAlias),
 }
 impl ast::AttrsOwner for ExternItem {}
+impl ast::NameOwner for ExternItem {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum GenericParam {
     ConstParam(ConstParam),
@@ -1678,17 +1666,6 @@ impl AstNode for Impl {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for MacroRules {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
-    }
-    fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
 impl AstNode for Module {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3083,9 +3060,6 @@ impl From<Impl> for Item {
 impl From<MacroCall> for Item {
     fn from(node: MacroCall) -> Item { Item::MacroCall(node) }
 }
-impl From<MacroRules> for Item {
-    fn from(node: MacroRules) -> Item { Item::MacroRules(node) }
-}
 impl From<Module> for Item {
     fn from(node: Module) -> Item { Item::Module(node) }
 }
@@ -3110,8 +3084,8 @@ impl From<Use> for Item {
 impl AstNode for Item {
     fn can_cast(kind: SyntaxKind) -> bool {
         match kind {
-            CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES
-            | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
+            CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MODULE
+            | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
             _ => false,
         }
     }
@@ -3124,7 +3098,6 @@ impl AstNode for Item {
             FN => Item::Fn(Fn { syntax }),
             IMPL => Item::Impl(Impl { syntax }),
             MACRO_CALL => Item::MacroCall(MacroCall { syntax }),
-            MACRO_RULES => Item::MacroRules(MacroRules { syntax }),
             MODULE => Item::Module(Module { syntax }),
             STATIC => Item::Static(Static { syntax }),
             STRUCT => Item::Struct(Struct { syntax }),
@@ -3145,7 +3118,6 @@ impl AstNode for Item {
             Item::Fn(it) => &it.syntax,
             Item::Impl(it) => &it.syntax,
             Item::MacroCall(it) => &it.syntax,
-            Item::MacroRules(it) => &it.syntax,
             Item::Module(it) => &it.syntax,
             Item::Static(it) => &it.syntax,
             Item::Struct(it) => &it.syntax,
@@ -3610,11 +3582,6 @@ impl std::fmt::Display for Impl {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for MacroRules {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        std::fmt::Display::fmt(self.syntax(), f)
-    }
-}
 impl std::fmt::Display for Module {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index c59a29eab3..820af2d20b 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -382,6 +382,21 @@ impl ast::Visibility {
     }
 }
 
+impl ast::MacroCall {
+    pub fn is_macro_rules(&self) -> Option<ast::Name> {
+        let name_ref = self.path()?.segment()?.name_ref()?;
+        if name_ref.text() == "macro_rules" {
+            self.name()
+        } else {
+            None
+        }
+    }
+
+    pub fn is_bang(&self) -> bool {
+        self.is_macro_rules().is_none()
+    }
+}
+
 impl ast::LifetimeParam {
     pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
         self.syntax()
@@ -461,5 +476,5 @@ impl ast::DocCommentsOwner for ast::Static {}
 impl ast::DocCommentsOwner for ast::Const {}
 impl ast::DocCommentsOwner for ast::TypeAlias {}
 impl ast::DocCommentsOwner for ast::Impl {}
-impl ast::DocCommentsOwner for ast::MacroRules {}
+impl ast::DocCommentsOwner for ast::MacroCall {}
 impl ast::DocCommentsOwner for ast::Use {}
diff --git a/crates/syntax/src/display.rs b/crates/syntax/src/display.rs
index d33bde30c5..8d2c7eae44 100644
--- a/crates/syntax/src/display.rs
+++ b/crates/syntax/src/display.rs
@@ -76,7 +76,7 @@ pub fn type_label(node: &ast::TypeAlias) -> String {
     label.trim().to_owned()
 }
 
-pub fn macro_label(node: &ast::MacroRules) -> String {
+pub fn macro_label(node: &ast::MacroCall) -> String {
     let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
     let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
     format!("{}macro_rules! {}", vis, name)
diff --git a/crates/syntax/src/parsing/text_tree_sink.rs b/crates/syntax/src/parsing/text_tree_sink.rs
index ce27c3dd96..49842177a8 100644
--- a/crates/syntax/src/parsing/text_tree_sink.rs
+++ b/crates/syntax/src/parsing/text_tree_sink.rs
@@ -147,8 +147,8 @@ fn n_attached_trivias<'a>(
     trivias: impl Iterator<Item = (SyntaxKind, &'a str)>,
 ) -> usize {
     match kind {
-        MACRO_CALL | MACRO_RULES | CONST | TYPE_ALIAS | STRUCT | ENUM | VARIANT | FN | TRAIT
-        | MODULE | RECORD_FIELD | STATIC | USE => {
+        MACRO_CALL | CONST | TYPE_ALIAS | STRUCT | ENUM | VARIANT | FN | TRAIT | MODULE
+        | RECORD_FIELD | STATIC | USE => {
             let mut res = 0;
             let mut trivias = trivias.enumerate().peekable();
 
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 2ddaeb1766..6f45149bf6 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -3,9 +3,7 @@
 mod block;
 
 use crate::{
-    algo,
-    ast::{self, VisibilityOwner},
-    match_ast, AstNode, SyntaxError,
+    algo, ast, match_ast, AstNode, SyntaxError,
     SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS},
     SyntaxNode, SyntaxToken, TextSize, T,
 };
@@ -101,7 +99,6 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
                 ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
                 ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
                 ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
-                ast::MacroRules(it) => validate_macro_rules(it, &mut errors),
                 _ => (),
             }
         }
@@ -353,12 +350,3 @@ fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
     }
     None
 }
-
-fn validate_macro_rules(mac: ast::MacroRules, errors: &mut Vec<SyntaxError>) {
-    if let Some(vis) = mac.visibility() {
-        errors.push(SyntaxError::new(
-            "visibilities are not allowed on `macro_rules!` items",
-            vis.syntax().text_range(),
-        ));
-    }
-}
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 13c6a2a167..c8d943142a 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -96,19 +96,19 @@ When using multiline fixtures, use unindented raw string literals:
     fn inline_field_shorthand() {
         check_assist(
             inline_local_variable,
-            r#"
+            r"
 struct S { foo: i32}
 fn main() {
     let <|>foo = 92;
     S { foo }
 }
-"#,
-            r#"
+",
+            r"
 struct S { foo: i32}
 fn main() {
     S { foo: 92 }
 }
-"#,
+",
         );
     }
 ```
diff --git a/editors/code/.vscodeignore b/editors/code/.vscodeignore
index 5096ce4dab..7149ab7992 100644
--- a/editors/code/.vscodeignore
+++ b/editors/code/.vscodeignore
@@ -1,5 +1,4 @@
 **
-!language-configuration.json
 !out/src/main.js
 !package.json
 !package-lock.json
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 72a4c10f54..8ceaaf60eb 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -70,7 +70,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
         "match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super",
         "trait", "true", "try", "type", "unsafe", "use", "where", "while",
     ],
-    contextual_keywords: &["auto", "default", "existential", "union", "raw", "macro_rules"],
+    contextual_keywords: &["auto", "default", "existential", "union", "raw"],
     literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING"],
     tokens: &[
         "ERROR",
@@ -98,8 +98,6 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
         "IMPL",
         "TYPE_ALIAS",
         "MACRO_CALL",
-        "MACRO_RULES",
-        "MACRO_ARM",
         "TOKEN_TREE",
         "MACRO_DEF",
         "PAREN_TYPE",


Test patch:
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index de97ec3c20..597a195d02 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -413,6 +413,7 @@ fn infer_local_macro() {
         expect![[r#"
             !0..6 '1usize': usize
             10..89 '{     ...!(); }': ()
+            16..65 'macro_...     }': {unknown}
             74..76 '_a': usize
         "#]],
     );
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 307a257b17..da81704170 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -592,30 +592,6 @@ fn issue_4465_dollar_crate_at_type() {
     );
 }
 
-#[test]
-fn issue_6811() {
-    check_infer(
-        r#"
-        macro_rules! profile_function {
-            () => {
-                let _a = 1;
-                let _b = 1;
-            };
-        }
-        fn main() {
-            profile_function!();
-        }
-        "#,
-        expect![[r#"
-            !3..5 '_a': i32
-            !6..7 '1': i32
-            !11..13 '_b': i32
-            !14..15 '1': i32
-            103..131 '{     ...!(); }': ()
-        "#]],
-    );
-}
-
 #[test]
 fn issue_4053_diesel_where_clauses() {
     check_infer(
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 920956b51f..396fd46fbd 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -95,7 +95,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="punctuation injected">(</span><span class="numeric_literal injected">1</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected">
 </span><span class="comment documentation">/// ```</span>
-<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
+<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
     <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>
         <span class="punctuation">$</span>expr
     <span class="punctuation">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index c843b5085d..d398e1ec85 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -35,13 +35,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span>
+<pre><code><span class="macro">macro_rules!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span>
     <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">{</span>
         <span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span>crate<span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
     <span class="punctuation">}</span><span class="punctuation">)</span>
 <span class="punctuation">}</span>
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
-<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span>
+#[rustc_builtin_macro]
+<span class="macro">macro_rules!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span>
     <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span>
     <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">,</span> <span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>args<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span>
 <span class="punctuation">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 0569cf1e5a..a3b4f20e87 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -125,7 +125,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
 <span class="punctuation">}</span>
 
-<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span>
+<span class="macro">macro_rules!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span>
     <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">}</span>
 <span class="punctuation">}</span>
 
@@ -135,13 +135,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="punctuation">}</span>
 <span class="punctuation">}</span>
 
-<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
+<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
     <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>
         <span class="punctuation">$</span>expr
     <span class="punctuation">}</span>
 <span class="punctuation">}</span>
 
-<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span>
+<span class="macro">macro_rules!</span> <span class="macro declaration">keyword_frag</span> <span class="punctuation">{</span>
     <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">:</span>ty<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">$</span>type<span class="punctuation">)</span>
 <span class="punctuation">}</span>
 
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index dff6e98c2d..843054fe85 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -48,7 +48,7 @@ mod rule_parsing {
         let macro_definition = format!(" macro_rules! m {{ {} }} ", arm_definition);
         let source_file = ast::SourceFile::parse(&macro_definition).ok().unwrap();
         let macro_definition =
-            source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
+            source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
 
         let (definition_tt, _) =
             ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
@@ -1668,7 +1668,7 @@ impl MacroFixture {
 fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree {
     let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
     let macro_definition =
-        source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
+        source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
 
     let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
 
diff --git a/crates/syntax/test_data/parser/err/0002_duplicate_shebang.rast b/crates/syntax/test_data/parser/err/0002_duplicate_shebang.rast
index 9ad5b12b8b..4cfd1bce4b 100644
--- a/crates/syntax/test_data/parser/err/0002_duplicate_shebang.rast
+++ b/crates/syntax/test_data/parser/err/0002_duplicate_shebang.rast
@@ -17,17 +17,14 @@ SOURCE_FILE@0..42
           IDENT@28..31 "bin"
   ERROR@31..32
     SLASH@31..32 "/"
-  MACRO_CALL@32..35
+  MACRO_CALL@32..41
     PATH@32..35
       PATH_SEGMENT@32..35
         NAME_REF@32..35
           IDENT@32..35 "env"
-  WHITESPACE@35..36 " "
-  MACRO_CALL@36..41
-    PATH@36..41
-      PATH_SEGMENT@36..41
-        NAME_REF@36..41
-          IDENT@36..41 "rusti"
+    WHITESPACE@35..36 " "
+    NAME@36..41
+      IDENT@36..41 "rusti"
   WHITESPACE@41..42 "\n"
 error 23..23: expected `[`
 error 23..23: expected an item
@@ -38,8 +35,5 @@ error 31..31: expected `{`, `[`, `(`
 error 31..31: expected SEMICOLON
 error 31..31: expected an item
 error 35..35: expected BANG
-error 35..35: expected `{`, `[`, `(`
-error 35..35: expected SEMICOLON
-error 41..41: expected BANG
 error 41..41: expected `{`, `[`, `(`
 error 41..41: expected SEMICOLON
diff --git a/crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast b/crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast
index e4fb32de11..de8217064f 100644
--- a/crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0062_mod_contents.rast
@@ -12,8 +12,11 @@ SOURCE_FILE@0..70
       L_CURLY@9..10 "{"
       R_CURLY@10..11 "}"
   WHITESPACE@11..12 "\n"
-  MACRO_RULES@12..31
-    MACRO_RULES_KW@12..23 "macro_rules"
+  MACRO_CALL@12..31
+    PATH@12..23
+      PATH_SEGMENT@12..23
+        NAME_REF@12..23
+          IDENT@12..23 "macro_rules"
     BANG@23..24 "!"
     WHITESPACE@24..25 " "
     NAME@25..28
diff --git a/crates/syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast b/crates/syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast
index e84b9164ff..e757249f06 100644
--- a/crates/syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast
@@ -82,28 +82,32 @@ SOURCE_FILE@0..167
           L_CURLY@102..103 "{"
           R_CURLY@103..104 "}"
       WHITESPACE@104..109 "\n    "
-      MACRO_RULES@109..152
-        MACRO_RULES_KW@109..120 "macro_rules"
-        BANG@120..121 "!"
-        WHITESPACE@121..122 " "
-        NAME@122..126
-          IDENT@122..126 "test"
-        WHITESPACE@126..127 " "
-        TOKEN_TREE@127..152
-          L_CURLY@127..128 "{"
-          WHITESPACE@128..138 "\n         "
-          TOKEN_TREE@138..140
-            L_PAREN@138..139 "("
-            R_PAREN@139..140 ")"
-          WHITESPACE@140..141 " "
-          EQ@141..142 "="
-          R_ANGLE@142..143 ">"
-          WHITESPACE@143..144 " "
-          TOKEN_TREE@144..146
-            L_CURLY@144..145 "{"
-            R_CURLY@145..146 "}"
-          WHITESPACE@146..151 "\n    "
-          R_CURLY@151..152 "}"
+      EXPR_STMT@109..152
+        MACRO_CALL@109..152
+          PATH@109..120
+            PATH_SEGMENT@109..120
+              NAME_REF@109..120
+                IDENT@109..120 "macro_rules"
+          BANG@120..121 "!"
+          WHITESPACE@121..122 " "
+          NAME@122..126
+            IDENT@122..126 "test"
+          WHITESPACE@126..127 " "
+          TOKEN_TREE@127..152
+            L_CURLY@127..128 "{"
+            WHITESPACE@128..138 "\n         "
+            TOKEN_TREE@138..140
+              L_PAREN@138..139 "("
+              R_PAREN@139..140 ")"
+            WHITESPACE@140..141 " "
+            EQ@141..142 "="
+            R_ANGLE@142..143 ">"
+            WHITESPACE@143..144 " "
+            TOKEN_TREE@144..146
+              L_CURLY@144..145 "{"
+              R_CURLY@145..146 "}"
+            WHITESPACE@146..151 "\n    "
+            R_CURLY@151..152 "}"
       WHITESPACE@152..157 "\n    "
       MACRO_CALL@157..164
         PATH@157..161
diff --git a/crates/syntax/test_data/parser/inline/ok/0160_try_macro_rules.rast b/crates/syntax/test_data/parser/inline/ok/0160_try_macro_rules.rast
index d1c22947b5..05b89d1c36 100644
--- a/crates/syntax/test_data/parser/inline/ok/0160_try_macro_rules.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0160_try_macro_rules.rast
@@ -1,6 +1,9 @@
 SOURCE_FILE@0..30
-  MACRO_RULES@0..29
-    MACRO_RULES_KW@0..11 "macro_rules"
+  MACRO_CALL@0..29
+    PATH@0..11
+      PATH_SEGMENT@0..11
+        NAME_REF@0..11
+          IDENT@0..11 "macro_rules"
     BANG@11..12 "!"
     WHITESPACE@12..13 " "
     NAME@13..16
diff --git a/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast b/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast
index 87d8ebcba5..be60f7a8ed 100644
--- a/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast
+++ b/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast
@@ -1,5 +1,5 @@
 SOURCE_FILE@0..65
-  MACRO_RULES@0..64
+  MACRO_CALL@0..64
     COMMENT@0..13 "/// Some docs"
     WHITESPACE@13..14 "\n"
     ATTR@14..29
@@ -11,7 +11,10 @@ SOURCE_FILE@0..65
             IDENT@16..28 "macro_export"
       R_BRACK@28..29 "]"
     WHITESPACE@29..30 "\n"
-    MACRO_RULES_KW@30..41 "macro_rules"
+    PATH@30..41
+      PATH_SEGMENT@30..41
+        NAME_REF@30..41
+          IDENT@30..41 "macro_rules"
     BANG@41..42 "!"
     WHITESPACE@42..43 " "
     NAME@43..46