Repository: rust-analyzer/rust-analyzer
Pull request #8081 (2021-03-18 09:23:40)

Reorganize mbe tests
bors r+


Patch:
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index dab8da7bbf..b9c6959214 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -11,8 +11,8 @@ use hir_ty::db::HirDatabase;
 use syntax::ast;
 
 use crate::{
-    Adt, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam, MacroDef,
-    Module, ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
+    Adt, Const, ConstParam, Enum, Field, Function, GenericParam, LifetimeParam, MacroDef, Module,
+    ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
 };
 
 pub trait HasAttrs {
@@ -64,7 +64,6 @@ impl_has_attrs![
     (Adt, AdtId),
     (Module, ModuleId),
     (GenericParam, GenericParamId),
-    (Impl, ImplId),
 ];
 
 macro_rules! impl_has_attrs_enum {
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs
index 1902a8d167..d444f4bbb1 100644
--- a/crates/hir/src/db.rs
+++ b/crates/hir/src/db.rs
@@ -3,10 +3,10 @@
 pub use hir_def::db::{
     AttrsQuery, BlockDefMapQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery,
     CrateDefMapQueryQuery, CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery,
-    ExprScopesQuery, FileItemTreeQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery,
-    ImportMapQuery, InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery,
-    InternFunctionQuery, InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery,
-    InternTypeAliasQuery, InternUnionQuery, LangItemQuery, StaticDataQuery, StructDataQuery,
+    ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery,
+    InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery,
+    InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery,
+    InternUnionQuery, ItemTreeQuery, LangItemQuery, StaticDataQuery, StructDataQuery,
     TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
 };
 pub use hir_expand::db::{
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b41a36a781..861b7329ef 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -89,7 +89,7 @@ pub use crate::{
 pub use {
     hir_def::{
         adt::StructKind,
-        attr::{Attr, Attrs, Documentation},
+        attr::{Attrs, Documentation},
         body::scope::ExprScopes,
         find_path::PrefixKind,
         import_map,
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 15651bb222..00b076175e 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -574,7 +574,7 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
-        let file_id = self.db.lookup_intern_trait(def.id).id.file_id();
+        let file_id = self.db.lookup_intern_trait(def.id).id.file_id;
         let resolver = def.id.resolver(self.db.upcast());
         SemanticsScope { db: self.db, file_id, resolver }
     }
@@ -752,7 +752,6 @@ macro_rules! to_def_impls {
 
 to_def_impls![
     (crate::Module, ast::Module, module_to_def),
-    (crate::Module, ast::SourceFile, source_file_to_def),
     (crate::Struct, ast::Struct, struct_to_def),
     (crate::Enum, ast::Enum, enum_to_def),
     (crate::Union, ast::Union, union_to_def),
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index c6ad5ecb5f..e9d8201403 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -71,12 +71,6 @@ impl SourceToDefCtx<'_, '_> {
         Some(def_map.module_id(child_id))
     }
 
-    pub(super) fn source_file_to_def(&mut self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
-        let _p = profile::span("source_file_to_def");
-        let file_id = src.file_id.original_file(self.db.upcast());
-        self.file_to_def(file_id).get(0).copied()
-    }
-
     pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> {
         self.to_def(src, keys::TRAIT)
     }
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index 58e35353bc..1b9bb8235f 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -94,7 +94,7 @@ impl StructData {
     pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
-        let item_tree = loc.id.item_tree(db);
+        let item_tree = db.item_tree(loc.id.file_id);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
         let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
 
@@ -110,7 +110,7 @@ impl StructData {
     pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
-        let item_tree = loc.id.item_tree(db);
+        let item_tree = db.item_tree(loc.id.file_id);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
         let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
 
@@ -130,7 +130,7 @@ impl EnumData {
     pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
         let loc = e.lookup(db);
         let krate = loc.container.krate;
-        let item_tree = loc.id.item_tree(db);
+        let item_tree = db.item_tree(loc.id.file_id);
         let cfg_options = db.crate_graph()[krate].cfg_options.clone();
 
         let enum_ = &item_tree[loc.id.value];
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index e4c84afbfa..b0b4b50521 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -76,23 +76,37 @@ impl ops::Deref for Attrs {
 impl RawAttrs {
     pub(crate) const EMPTY: Self = Self { entries: None };
 
-    pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self {
-        let entries = collect_attrs(owner)
-            .enumerate()
-            .flat_map(|(i, attr)| match attr {
-                Either::Left(attr) => Attr::from_src(attr, hygiene, i as u32),
-                Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
-                    index: i as u32,
-                    input: Some(AttrInput::Literal(SmolStr::new(doc))),
-                    path: ModPath::from(hir_expand::name!(doc)),
-                }),
-            })
-            .collect::<Arc<_>>();
-
-        Self { entries: if entries.is_empty() { None } else { Some(entries) } }
+    pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self {
+        let attrs: Vec<_> = collect_attrs(owner).collect();
+        let entries = if attrs.is_empty() {
+            // Avoid heap allocation
+            None
+        } else {
+            Some(
+                attrs
+                    .into_iter()
+                    .enumerate()
+                    .flat_map(|(i, attr)| match attr {
+                        Either::Left(attr) => Attr::from_src(attr, hygiene).map(|attr| (i, attr)),
+                        Either::Right(comment) => comment.doc_comment().map(|doc| {
+                            (
+                                i,
+                                Attr {
+                                    index: 0,
+                                    input: Some(AttrInput::Literal(SmolStr::new(doc))),
+                                    path: ModPath::from(hir_expand::name!(doc)),
+                                },
+                            )
+                        }),
+                    })
+                    .map(|(i, attr)| Attr { index: i as u32, ..attr })
+                    .collect(),
+            )
+        };
+        Self { entries }
     }
 
-    fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self {
+    fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Self {
         let hygiene = Hygiene::new(db.upcast(), owner.file_id);
         Self::new(owner.value, &hygiene)
     }
@@ -122,15 +136,16 @@ impl RawAttrs {
         let new_attrs = self
             .iter()
             .flat_map(|attr| -> SmallVec<[_; 1]> {
+                let attr = attr.clone();
                 let is_cfg_attr =
                     attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]);
                 if !is_cfg_attr {
-                    return smallvec![attr.clone()];
+                    return smallvec![attr];
                 }
 
                 let subtree = match &attr.input {
                     Some(AttrInput::TokenTree(it)) => it,
-                    _ => return smallvec![attr.clone()],
+                    _ => return smallvec![attr],
                 };
 
                 // Input subtree is: `(cfg, $(attr),+)`
@@ -142,13 +157,11 @@ impl RawAttrs {
                 let cfg = parts.next().unwrap();
                 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
                 let cfg = CfgExpr::parse(&cfg);
-                let index = attr.index;
                 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
                     let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
                     let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
-                    // FIXME hygiene
-                    let hygiene = Hygiene::new_unhygienic();
-                    Attr::from_src(attr, &hygiene, index)
+                    let hygiene = Hygiene::new_unhygienic(); // FIXME
+                    Attr::from_src(attr, &hygiene)
                 });
 
                 let cfg_options = &crate_graph[krate].cfg_options;
@@ -178,7 +191,7 @@ impl Attrs {
                     Some(it) => {
                         let raw_attrs = RawAttrs::from_attrs_owner(
                             db,
-                            it.as_ref().map(|it| it as &dyn ast::AttrsOwner),
+                            it.as_ref().map(|it| it as &dyn AttrsOwner),
                         );
                         match mod_data.definition_source(db) {
                             InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs
@@ -189,9 +202,9 @@ impl Attrs {
                     None => RawAttrs::from_attrs_owner(
                         db,
                         mod_data.definition_source(db).as_ref().map(|src| match src {
-                            ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
-                            ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
-                            ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
+                            ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
+                            ModuleSource::Module(module) => module as &dyn AttrsOwner,
+                            ModuleSource::BlockExpr(block) => block as &dyn AttrsOwner,
                         }),
                     ),
                 }
@@ -249,7 +262,7 @@ impl Attrs {
         let mut res = ArenaMap::default();
 
         for (id, var) in src.value.iter() {
-            let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn ast::AttrsOwner))
+            let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn AttrsOwner))
                 .filter(db, krate);
 
             res.insert(id, attrs)
@@ -280,13 +293,6 @@ impl Attrs {
         Arc::new(res)
     }
 
-    /// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes.
-    ///
-    /// `owner` must be the original owner of the attributes.
-    pub fn source_map(&self, owner: &dyn ast::AttrsOwner) -> AttrSourceMap {
-        AttrSourceMap { attrs: collect_attrs(owner).collect() }
-    }
-
     pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
         AttrQuery { attrs: self, key }
     }
@@ -311,34 +317,15 @@ impl Attrs {
             AttrInput::Literal(s) => Some(s),
             AttrInput::TokenTree(_) => None,
         });
-        let indent = docs
-            .clone()
-            .flat_map(|s| s.lines())
-            .filter(|line| !line.chars().all(|c| c.is_whitespace()))
-            .map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
-            .min()
-            .unwrap_or(0);
-        let mut buf = String::new();
-        for doc in docs {
-            // str::lines doesn't yield anything for the empty string
-            if !doc.is_empty() {
-                buf.extend(Itertools::intersperse(
-                    doc.lines().map(|line| {
-                        line.char_indices()
-                            .nth(indent)
-                            .map_or(line, |(offset, _)| &line[offset..])
-                            .trim_end()
-                    }),
-                    "\n",
-                ));
-            }
-            buf.push('\n');
-        }
-        buf.pop();
-        if buf.is_empty() {
+        // FIXME: Replace `Itertools::intersperse` with `Iterator::intersperse[_with]` until the
+        // libstd api gets stabilized (https://github.com/rust-lang/rust/issues/79524).
+        let docs = Itertools::intersperse(docs, &SmolStr::new_inline("\n"))
+            .map(|it| it.as_str())
+            .collect::<String>();
+        if docs.is_empty() {
             None
         } else {
-            Some(Documentation(buf))
+            Some(Documentation(docs))
         }
     }
 }
@@ -378,24 +365,6 @@ fn inner_attributes(
     Some((attrs, docs))
 }
 
-pub struct AttrSourceMap {
-    attrs: Vec<Either<ast::Attr, ast::Comment>>,
-}
-
-impl AttrSourceMap {
-    /// Maps the lowered `Attr` back to its original syntax node.
-    ///
-    /// `attr` must come from the `owner` used for AttrSourceMap
-    ///
-    /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
-    /// the attribute represented by `Attr`.
-    pub fn source_of(&self, attr: &Attr) -> &Either<ast::Attr, ast::Comment> {
-        self.attrs
-            .get(attr.index as usize)
-            .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index))
-    }
-}
-
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Attr {
     index: u32,
@@ -412,7 +381,7 @@ pub enum AttrInput {
 }
 
 impl Attr {
-    fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> {
+    fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
         let path = ModPath::from_src(ast.path()?, hygiene)?;
         let input = if let Some(lit) = ast.literal() {
             let value = match lit.kind() {
@@ -425,7 +394,7 @@ impl Attr {
         } else {
             None
         };
-        Some(Attr { index, path, input })
+        Some(Attr { index: 0, path, input })
     }
 
     /// Maps this lowered `Attr` back to its original syntax node.
@@ -434,7 +403,7 @@ impl Attr {
     ///
     /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
     /// the attribute represented by `Attr`.
-    pub fn to_src(&self, owner: &dyn ast::AttrsOwner) -> Either<ast::Attr, ast::Comment> {
+    pub fn to_src(&self, owner: &dyn AttrsOwner) -> Either<ast::Attr, ast::Comment> {
         collect_attrs(owner).nth(self.index as usize).unwrap_or_else(|| {
             panic!("cannot find `Attr` at index {} in {}", self.index, owner.syntax())
         })
@@ -479,13 +448,6 @@ impl Attr {
             _ => None,
         }
     }
-
-    pub fn string_value(&self) -> Option<&SmolStr> {
-        match self.input.as_ref()? {
-            AttrInput::Literal(it) => Some(it),
-            _ => None,
-        }
-    }
 }
 
 #[derive(Debug, Clone, Copy)]
@@ -513,7 +475,7 @@ impl<'a> AttrQuery<'a> {
         self.attrs().next().is_some()
     }
 
-    pub fn attrs(self) -> impl Iterator<Item = &'a Attr> + Clone {
+    pub(crate) fn attrs(self) -> impl Iterator<Item = &'a Attr> {
         let key = self.key;
         self.attrs
             .iter()
@@ -526,18 +488,16 @@ where
     N: ast::AttrsOwner,
 {
     let src = InFile::new(src.file_id, src.to_node(db.upcast()));
-    RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn ast::AttrsOwner))
+    RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
 }
 
 fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs {
-    let tree = id.item_tree(db);
+    let tree = db.item_tree(id.file_id);
     let mod_item = N::id_to_mod_item(id.value);
     tree.raw_attrs(mod_item.into()).clone()
 }
 
-fn collect_attrs(
-    owner: &dyn ast::AttrsOwner,
-) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> {
+fn collect_attrs(owner: &dyn AttrsOwner) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> {
     let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
         .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs))));
 
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 19f5065d13..60b25db563 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -177,15 +177,12 @@ impl ExprCollector<'_> {
     }
 
     fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
-        self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
-    }
-
-    /// Returns `None` if the expression is `#[cfg]`d out.
-    fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
         let syntax_ptr = AstPtr::new(&expr);
-        self.check_cfg(&expr)?;
+        if self.check_cfg(&expr).is_none() {
+            return self.missing_expr();
+        }
 
-        Some(match expr {
+        match expr {
             ast::Expr::IfExpr(e) => {
                 let then_branch = self.collect_block_opt(e.then_branch());
 
@@ -214,9 +211,8 @@ impl ExprCollector<'_> {
                                     guard: None,
                                 },
                             ];
-                            return Some(
-                                self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
-                            );
+                            return self
+                                .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
                         }
                     },
                 };
@@ -287,9 +283,8 @@ impl ExprCollector<'_> {
                             ];
                             let match_expr =
                                 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
-                            return Some(
-                                self.alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr),
-                            );
+                            return self
+                                .alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr);
                         }
                     },
                 };
@@ -306,7 +301,7 @@ impl ExprCollector<'_> {
             ast::Expr::CallExpr(e) => {
                 let callee = self.collect_expr_opt(e.expr());
                 let args = if let Some(arg_list) = e.arg_list() {
-                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
+                    arg_list.args().map(|e| self.collect_expr(e)).collect()
                 } else {
                     Vec::new()
                 };
@@ -315,7 +310,7 @@ impl ExprCollector<'_> {
             ast::Expr::MethodCallExpr(e) => {
                 let receiver = self.collect_expr_opt(e.receiver());
                 let args = if let Some(arg_list) = e.arg_list() {
-                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
+                    arg_list.args().map(|e| self.collect_expr(e)).collect()
                 } else {
                     Vec::new()
                 };
@@ -543,7 +538,7 @@ impl ExprCollector<'_> {
                     self.alloc_expr(Expr::Missing, syntax_ptr)
                 }
             }
-        })
+        }
     }
 
     fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 0be868ba20..1a27f7bf21 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -9,7 +9,7 @@ use crate::{
     attr::Attrs,
     body::Expander,
     db::DefDatabase,
-    item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param},
+    item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem},
     type_ref::{TypeBound, TypeRef},
     visibility::RawVisibility,
     AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
@@ -36,38 +36,19 @@ impl FunctionData {
     pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
         let loc = func.lookup(db);
         let krate = loc.container.module(db).krate;
-        let crate_graph = db.crate_graph();
-        let cfg_options = &crate_graph[krate].cfg_options;
-        let item_tree = loc.id.item_tree(db);
+        let item_tree = db.item_tree(loc.id.file_id);
         let func = &item_tree[loc.id.value];
 
-        let enabled_params = func
-            .params
-            .clone()
-            .filter(|&param| item_tree.attrs(db, krate, param.into()).is_cfg_enabled(cfg_options));
-
-        // If last cfg-enabled param is a `...` param, it's a varargs function.
-        let is_varargs = enabled_params
-            .clone()
-            .next_back()
-            .map_or(false, |param| matches!(item_tree[param], Param::Varargs));
-
         Arc::new(FunctionData {
             name: func.name.clone(),
-            params: enabled_params
-                .clone()
-                .filter_map(|id| match &item_tree[id] {
-                    Param::Normal(ty) => Some(item_tree[*ty].clone()),
-                    Param::Varargs => None,
-                })
-                .collect(),
+            params: func.params.iter().map(|id| item_tree[*id].clone()).collect(),
             ret_type: item_tree[func.ret_type].clone(),
             attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
             has_self_param: func.has_self_param,
             has_body: func.has_body,
             qualifier: func.qualifier.clone(),
             is_in_extern_block: func.is_in_extern_block,
-            is_varargs,
+            is_varargs: func.is_varargs,
             visibility: item_tree[func.visibility].clone(),
         })
     }
@@ -89,7 +70,7 @@ impl TypeAliasData {
         typ: TypeAliasId,
     ) -> Arc<TypeAliasData> {
         let loc = typ.lookup(db);
-        let item_tree = loc.id.item_tree(db);
+        let item_tree = db.item_tree(loc.id.file_id);
         let typ = &item_tree[loc.id.value];
 
         Arc::new(TypeAliasData {
@@ -115,23 +96,23 @@ pub struct TraitData {
 impl TraitData {
     pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
         let tr_loc = tr.lookup(db);
-        let item_tree = tr_loc.id.item_tree(db);
+        let item_tree = db.item_tree(tr_loc.id.file_id);
         let tr_def = &item_tree[tr_loc.id.value];
         let name = tr_def.name.clone();
         let is_auto = tr_def.is_auto;
         let is_unsafe = tr_def.is_unsafe;
         let module_id = tr_loc.container;
         let container = AssocContainerId::TraitId(tr);
+        let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
         let visibility = item_tree[tr_def.visibility].clone();
         let bounds = tr_def.bounds.clone();
-        let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
 
         let items = collect_items(
             db,
             module_id,
             &mut expander,
             tr_def.items.iter().copied(),
-            tr_loc.id.file_id(),
+            tr_loc.id.file_id,
             container,
             100,
         );
@@ -167,21 +148,21 @@ impl ImplData {
         let _p = profile::span("impl_data_query");
         let impl_loc = id.lookup(db);
 
-        let item_tree = impl_loc.id.item_tree(db);
+        let item_tree = db.item_tree(impl_loc.id.file_id);
         let impl_def = &item_tree[impl_loc.id.value];
         let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone());
         let target_type = item_tree[impl_def.target_type].clone();
         let is_negative = impl_def.is_negative;
         let module_id = impl_loc.container;
         let container = AssocContainerId::ImplId(id);
-        let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id);
+        let mut expander = Expander::new(db, impl_loc.id.file_id, module_id);
 
         let items = collect_items(
             db,
             module_id,
             &mut expander,
             impl_def.items.iter().copied(),
-            impl_loc.id.file_id(),
+            impl_loc.id.file_id,
             container,
             100,
         );
@@ -202,7 +183,7 @@ pub struct ConstData {
 impl ConstData {
     pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
         let loc = konst.lookup(db);
-        let item_tree = loc.id.item_tree(db);
+        let item_tree = db.item_tree(loc.id.file_id);
         let konst = &item_tree[loc.id.value];
 
         Arc::new(ConstData {
@@ -225,7 +206,7 @@ pub struct StaticData {
 impl StaticData {
     pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
         let node = konst.lookup(db);
-        let item_tree = node.id.item_tree(db);
+        let item_tree = db.item_tree(node.id.file_id);
         let statik = &item_tree[node.id.value];
 
         Arc::new(StaticData {
@@ -251,23 +232,22 @@ fn collect_items(
         return Vec::new();
     }
 
-    let item_tree = db.file_item_tree(file_id);
-    let crate_graph = db.crate_graph();
-    let cfg_options = &crate_graph[module.krate].cfg_options;
+    let item_tree = db.item_tree(file_id);
+    let cfg_options = db.crate_graph()[module.krate].cfg_options.clone();
 
     let mut items = Vec::new();
     for item in assoc_items {
-        let attrs = item_tree.attrs(db, module.krate, ModItem::from(item).into());
-        if !attrs.is_cfg_enabled(cfg_options) {
-            continue;
-        }
-
         match item {
             AssocItem::Function(id) => {
                 let item = &item_tree[id];
+                let attrs = item_tree.attrs(db, module.krate, ModItem::from(id).into());
+                if !attrs.is_cfg_enabled(&cfg_options) {
+                    continue;
+                }
                 let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
                 items.push((item.name.clone(), def.into()));
             }
+            // FIXME: cfg?
             AssocItem::Const(id) => {
                 let item = &item_tree[id];
                 let name = match item.name.clone() {
@@ -292,7 +272,7 @@ fn collect_items(
                 if let Ok(res) = res {
                     if let Some((mark, mac)) = res.value {
                         let src: InFile<ast::MacroItems> = expander.to_source(mac);
-                        let item_tree = db.file_item_tree(src.file_id);
+                        let item_tree = db.item_tree(src.file_id);
                         let iter =
                             item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
                         items.extend(collect_items(
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 276caf5b33..cca5a086b4 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -48,8 +48,8 @@ pub trait InternDatabase: SourceDatabase {
 
 #[salsa::query_group(DefDatabaseStorage)]
 pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
-    #[salsa::invoke(ItemTree::file_item_tree_query)]
-    fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
+    #[salsa::invoke(ItemTree::item_tree_query)]
+    fn item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
 
     #[salsa::invoke(crate_def_map_wait)]
     #[salsa::transparent]
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 7c6cbff118..a056ab797e 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -97,43 +97,43 @@ impl GenericParams {
         let generics = match def {
             GenericDefId::FunctionId(id) => {
                 let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
+                let tree = db.item_tree(id.file_id);
                 let item = &tree[id.value];
                 tree[item.generic_params].clone()
             }
             GenericDefId::AdtId(AdtId::StructId(id)) => {
                 let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
+                let tree = db.item_tree(id.file_id);
                 let item = &tree[id.value];
                 tree[item.generic_params].clone()
             }
             GenericDefId::AdtId(AdtId::EnumId(id)) => {
                 let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
+                let tree = db.item_tree(id.file_id);
                 let item = &tree[id.value];
                 tree[item.generic_params].clone()
             }
             GenericDefId::AdtId(AdtId::UnionId(id)) => {
                 let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
+                let tree = db.item_tree(id.file_id);
                 let item = &tree[id.value];
                 tree[item.generic_params].clone()
             }
             GenericDefId::TraitId(id) => {
                 let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
+                let tree = db.item_tree(id.file_id);
                 let item = &tree[id.value];
                 tree[item.generic_params].clone()
             }
             GenericDefId::TypeAliasId(id) => {
                 let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
+                let tree = db.item_tree(id.file_id);
                 let item = &tree[id.value];
                 tree[item.generic_params].clone()
             }
             GenericDefId::ImplId(id) => {
                 let id = id.lookup(db).id;
-                let tree = id.item_tree(db);
+                let tree = db.item_tree(id.file_id);
                 let item = &tree[id.value];
                 tree[item.generic_params].clone()
             }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 5f5b7151ac..7bb22c4c49 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -76,7 +76,7 @@ pub struct ItemTree {
 }
 
 impl ItemTree {
-    pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
+    pub(crate) fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
         let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id));
         let syntax = if let Some(node) = db.parse_or_expand(file_id) {
             if node.kind() == SyntaxKind::ERROR {
@@ -134,7 +134,6 @@ impl ItemTree {
                 imports,
                 extern_crates,
                 functions,
-                params,
                 structs,
                 fields,
                 unions,
@@ -158,7 +157,6 @@ impl ItemTree {
             imports.shrink_to_fit();
             extern_crates.shrink_to_fit();
             functions.shrink_to_fit();
-            params.shrink_to_fit();
             structs.shrink_to_fit();
             fields.shrink_to_fit();
             unions.shrink_to_fit();
@@ -305,7 +303,6 @@ struct ItemTreeData {
     imports: Arena<Import>,
     extern_crates: Arena<ExternCrate>,
     functions: Arena<Function>,
-    params: Arena<Param>,
     structs: Arena<Struct>,
     fields: Arena<Field>,
     unions: Arena<Union>,
@@ -337,7 +334,6 @@ pub enum AttrOwner {
 
     Variant(Idx<Variant>),
     Field(Idx<Field>),
-    Param(Idx<Param>),
 }
 
 macro_rules! from_attrs {
@@ -352,7 +348,7 @@ macro_rules! from_attrs {
     };
 }
 
-from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Idx<Param>));
+from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>));
 
 /// Trait implemented by all item nodes in the item tree.
 pub trait ItemTreeNode: Clone {
@@ -401,47 +397,7 @@ impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> {
     }
 }
 
-#[derive(Debug)]
-pub struct ItemTreeId<N: ItemTreeNode> {
-    file: HirFileId,
-    pub value: FileItemTreeId<N>,
-}
-
-impl<N: ItemTreeNode> ItemTreeId<N> {
-    pub fn new(file: HirFileId, idx: FileItemTreeId<N>) -> Self {
-        Self { file, value: idx }
-    }
-
-    pub fn file_id(self) -> HirFileId {
-        self.file
-    }
-
-    pub fn item_tree(self, db: &dyn DefDatabase) -> Arc<ItemTree> {
-        db.file_item_tree(self.file)
-    }
-}
-
-impl<N: ItemTreeNode> Copy for ItemTreeId<N> {}
-impl<N: ItemTreeNode> Clone for ItemTreeId<N> {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-
-impl<N: ItemTreeNode> PartialEq for ItemTreeId<N> {
-    fn eq(&self, other: &Self) -> bool {
-        self.file == other.file && self.value == other.value
-    }
-}
-
-impl<N: ItemTreeNode> Eq for ItemTreeId<N> {}
-
-impl<N: ItemTreeNode> Hash for ItemTreeId<N> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.file.hash(state);
-        self.value.hash(state);
-    }
-}
+pub type ItemTreeId<N> = InFile<FileItemTreeId<N>>;
 
 macro_rules! mod_items {
     ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
@@ -528,7 +484,7 @@ macro_rules! impl_index {
     };
 }
 
-impl_index!(fields: Field, variants: Variant, params: Param);
+impl_index!(fields: Field, variants: Variant);
 
 impl Index<RawVisibilityId> for ItemTree {
     type Output = RawVisibility;
@@ -604,17 +560,12 @@ pub struct Function {
     /// Whether the function is located in an `extern` block (*not* whether it is an
     /// `extern "abi" fn`).
     pub is_in_extern_block: bool,
-    pub params: IdRange<Param>,
+    pub params: Box<[Idx<TypeRef>]>,
+    pub is_varargs: bool,
     pub ret_type: Idx<TypeRef>,
     pub ast_id: FileAstId<ast::Fn>,
 }
 
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub enum Param {
-    Normal(Idx<TypeRef>),
-    Varargs,
-}
-
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct FunctionQualifier {
     pub is_default: bool,
@@ -845,7 +796,6 @@ pub struct Variant {
     pub fields: Fields,
 }
 
-/// A range of densely allocated ItemTree IDs.
 pub struct IdRange<T> {
     range: Range<u32>,
     _p: PhantomData<T>,
@@ -864,12 +814,6 @@ impl<T> Iterator for IdRange<T> {
     }
 }
 
-impl<T> DoubleEndedIterator for IdRange<T> {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        self.range.next_back().map(|raw| Idx::from_raw(raw.into()))
-    }
-}
-
 impl<T> fmt::Debug for IdRange<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish()
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 3f558edd81..7e91b991d2 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -333,8 +333,8 @@ impl Ctx {
         let visibility = self.lower_visibility(func);
         let name = func.name()?.as_name();
 
+        let mut params = Vec::new();
         let mut has_self_param = false;
-        let start_param = self.next_param_idx();
         if let Some(param_list) = func.param_list() {
             if let Some(self_param) = param_list.self_param() {
                 let self_type = match self_param.ty() {
@@ -356,25 +356,22 @@ impl Ctx {
                         }
                     }
                 };
-                let ty = self.data().type_refs.intern(self_type);
-                let idx = self.data().params.alloc(Param::Normal(ty));
-                self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene));
+                params.push(self_type);
                 has_self_param = true;
             }
             for param in param_list.params() {
-                let idx = match param.dotdotdot_token() {
-                    Some(_) => self.data().params.alloc(Param::Varargs),
-                    None => {
-                        let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
-                        let ty = self.data().type_refs.intern(type_ref);
-                        self.data().params.alloc(Param::Normal(ty))
-                    }
-                };
-                self.add_attrs(idx.into(), RawAttrs::new(&param, &self.hygiene));
+                let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
+                params.push(type_ref);
+            }
+        }
+        let params = params.into_iter().map(|param| self.data().type_refs.intern(param)).collect();
+
+        let mut is_varargs = false;
+        if let Some(params) = func.param_list() {
+            if let Some(last) = params.params().last() {
+                is_varargs = last.dotdotdot_token().is_some();
             }
         }
-        let end_param = self.next_param_idx();
-        let params = IdRange::new(start_param..end_param);
 
         let ret_type = match func.ret_type().and_then(|rt| rt.ty()) {
             Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
@@ -422,6 +419,7 @@ impl Ctx {
             qualifier,
             is_in_extern_block: false,
             params,
+            is_varargs,
             ret_type,
             ast_id,
         };
@@ -684,11 +682,9 @@ impl Ctx {
             GenericsOwner::Function(func) => {
                 generics.fill(&self.body_ctx, sm, node);
                 // lower `impl Trait` in arguments
-                for id in func.params.clone() {
-                    if let Param::Normal(ty) = self.data().params[id] {
-                        let ty = self.data().type_refs.lookup(ty);
-                        generics.fill_implicit_impl_trait_args(ty);
-                    }
+                for param in &*func.params {
+                    let param = self.data().type_refs.lookup(*param);
+                    generics.fill_implicit_impl_trait_args(param);
                 }
             }
             GenericsOwner::Struct
@@ -773,11 +769,6 @@ impl Ctx {
             self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
         ))
     }
-    fn next_param_idx(&self) -> Idx<Param> {
-        Idx::from_raw(RawIdx::from(
-            self.tree.data.as_ref().map_or(0, |data| data.params.len() as u32),
-        ))
-    }
 }
 
 fn desugar_future_path(orig: TypeRef) -> Path {
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index c97be584e2..003d668ca0 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -213,7 +213,7 @@ impl DefMap {
     ) -> Option<Arc<DefMap>> {
         let block: BlockLoc = db.lookup_intern_block(block_id);
 
-        let item_tree = db.file_item_tree(block.ast_id.file_id);
+        let item_tree = db.item_tree(block.ast_id.file_id);
         if item_tree.inner_items_of_block(block.ast_id.value).is_empty() {
             return None;
         }
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index d0fefb5afd..81cf652b0d 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -242,7 +242,7 @@ struct DefCollector<'a> {
 impl DefCollector<'_> {
     fn seed_with_top_level(&mut self) {
         let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
-        let item_tree = self.db.file_item_tree(file_id.into());
+        let item_tree = self.db.item_tree(file_id.into());
         let module_id = self.def_map.root;
         self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
         if item_tree
@@ -263,7 +263,7 @@ impl DefCollector<'_> {
     }
 
     fn seed_with_inner(&mut self, block: AstId<ast::BlockExpr>) {
-        let item_tree = self.db.file_item_tree(block.file_id);
+        let item_tree = self.db.item_tree(block.file_id);
         let module_id = self.def_map.root;
         self.def_map.modules[module_id].origin = ModuleOrigin::BlockExpr { block };
         if item_tree
@@ -656,28 +656,26 @@ impl DefCollector<'_> {
                 }
             }
         } else {
-            let name = match &import.alias {
-                Some(ImportAlias::Alias(name)) => Some(name.clone()),
-                Some(ImportAlias::Underscore) => None,
-                None => match import.path.segments().last() {
-                    Some(last_segment) => Some(last_segment.clone()),
-                    None => {
-                        cov_mark::hit!(bogus_paths);
-                        return;
-                    }
-                },
-            };
+            match import.path.segments().last() {
+                Some(last_segment) => {
+                    let name = match &import.alias {
+                        Some(ImportAlias::Alias(name)) => Some(name.clone()),
+                        Some(ImportAlias::Underscore) => None,
+                        None => Some(last_segment.clone()),
+                    };
+                    log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 
-            log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
+                    // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
+                    if import.is_extern_crate && module_id == self.def_map.root {
+                        if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
+                            self.def_map.extern_prelude.insert(name.clone(), def);
+                        }
+                    }
 
-            // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
-            if import.is_extern_crate && module_id == self.def_map.root {
-                if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
-                    self.def_map.extern_prelude.insert(name.clone(), def);
+                    self.update(module_id, &[(name, def)], vis, ImportType::Named);
                 }
+                None => cov_mark::hit!(bogus_paths),
             }
-
-            self.update(module_id, &[(name, def)], vis, ImportType::Named);
         }
     }
 
@@ -895,7 +893,7 @@ impl DefCollector<'_> {
         }
 
         // Then, fetch and process the item tree. This will reuse the expansion result from above.
-        let item_tree = self.db.file_item_tree(file_id);
+        let item_tree = self.db.item_tree(file_id);
         let mod_dir = self.mod_dirs[&module_id].clone();
         ModCollector {
             def_collector: &mut *self,
@@ -951,21 +949,21 @@ impl DefCollector<'_> {
         let mut diagnosed_extern_crates = FxHashSet::default();
         for directive in &self.unresolved_imports {
             if let ImportSource::ExternCrate(krate) = directive.import.source {
-                let item_tree = krate.item_tree(self.db);
+                let item_tree = self.db.item_tree(krate.file_id);
                 let extern_crate = &item_tree[krate.value];
 
                 diagnosed_extern_crates.insert(extern_crate.name.clone());
 
                 self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
                     directive.module_id,
-                    InFile::new(krate.file_id(), extern_crate.ast_id),
+                    InFile::new(krate.file_id, extern_crate.ast_id),
                 ));
             }
         }
 
         for directive in &self.unresolved_imports {
             if let ImportSource::Import(import) = &directive.import.source {
-                let item_tree = import.item_tree(self.db);
+                let item_tree = self.db.item_tree(import.file_id);
                 let import_data = &item_tree[import.value];
 
                 match (import_data.path.segments().first(), &import_data.path.kind) {
@@ -979,7 +977,7 @@ impl DefCollector<'_> {
 
                 self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
                     directive.module_id,
-                    InFile::new(import.file_id(), import_data.ast_id),
+                    InFile::new(import.file_id, import_data.ast_id),
                     import_data.index,
                 ));
             }
@@ -1055,7 +1053,7 @@ impl ModCollector<'_, '_> {
                             self.def_collector.db,
                             krate,
                             &self.item_tree,
-                            ItemTreeId::new(self.file_id, import_id),
+                            InFile::new(self.file_id, import_id),
                         ),
                         status: PartialResolvedImport::Unresolved,
                     })
@@ -1067,7 +1065,7 @@ impl ModCollector<'_, '_> {
                             self.def_collector.db,
                             krate,
                             &self.item_tree,
-                            ItemTreeId::new(self.file_id, import_id),
+                            InFile::new(self.file_id, import_id),
                         ),
                         status: PartialResolvedImport::Unresolved,
                     })
@@ -1299,7 +1297,7 @@ impl ModCollector<'_, '_> {
                             Some((file_id, is_mod_rs)),
                             &self.item_tree[module.visibility],
                         );
-                        let item_tree = db.file_item_tree(file_id.into());
+                        let item_tree = db.item_tree(file_id.into());
                         ModCollector {
                             def_collector: &mut *self.def_collector,
                             macro_depth: self.macro_depth,
@@ -1471,9 +1469,7 @@ impl ModCollector<'_, '_> {
                     )
                 })
             },
-            &mut |err| {
-                error.get_or_insert(err);
-            },
+            &mut |err| error = Some(err),
         ) {
             Ok(Ok(macro_call_id)) => {
                 self.def_collector.unexpanded_macros.push(MacroDirective {
diff --git a/crates/hir_def/src/src.rs b/crates/hir_def/src/src.rs
index 24e57b4692..751d4c0522 100644
--- a/crates/hir_def/src/src.rs
+++ b/crates/hir_def/src/src.rs
@@ -14,12 +14,12 @@ impl<N: ItemTreeNode> HasSource for AssocItemLoc<N> {
     type Value = N::Source;
 
     fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> {
-        let tree = self.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(self.id.file_id());
-        let root = db.parse_or_expand(self.id.file_id()).unwrap();
+        let tree = db.item_tree(self.id.file_id);
+        let ast_id_map = db.ast_id_map(self.id.file_id);
+        let root = db.parse_or_expand(self.id.file_id).unwrap();
         let node = &tree[self.id.value];
 
-        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root))
+        InFile::new(self.id.file_id, ast_id_map.get(node.ast_id()).to_node(&root))
     }
 }
 
@@ -27,12 +27,12 @@ impl<N: ItemTreeNode> HasSource for ItemLoc<N> {
     type Value = N::Source;
 
     fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> {
-        let tree = self.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(self.id.file_id());
-        let root = db.parse_or_expand(self.id.file_id()).unwrap();
+        let tree = db.item_tree(self.id.file_id);
+        let ast_id_map = db.ast_id_map(self.id.file_id);
+        let root = db.parse_or_expand(self.id.file_id).unwrap();
         let node = &tree[self.id.value];
 
-        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root))
+        InFile::new(self.id.file_id, ast_id_map.get(node.ast_id()).to_node(&root))
     }
 }
 
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index fce09a9e71..2a79c892b5 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -333,19 +333,17 @@ fn concat_expand(
 fn relative_file(
     db: &dyn AstDatabase,
     call_id: MacroCallId,
-    path_str: &str,
+    path: &str,
     allow_recursion: bool,
-) -> Result<FileId, mbe::ExpandError> {
+) -> Option<FileId> {
     let call_site = call_id.as_file().original_file(db);
-    let path = AnchoredPath { anchor: call_site, path: path_str };
-    let res = db
-        .resolve_path(path)
-        .ok_or_else(|| mbe::ExpandError::Other(format!("failed to load file `{}`", path_str)))?;
+    let path = AnchoredPath { anchor: call_site, path };
+    let res = db.resolve_path(path)?;
     // Prevent include itself
     if res == call_site && !allow_recursion {
-        Err(mbe::ExpandError::Other(format!("recursive inclusion of `{}`", path_str)))
+        None
     } else {
-        Ok(res)
+        Some(res)
     }
 }
 
@@ -366,7 +364,8 @@ fn include_expand(
 ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
     let res = (|| {
         let path = parse_string(tt)?;
-        let file_id = relative_file(db, arg_id.into(), &path, false)?;
+        let file_id = relative_file(db, arg_id.into(), &path, false)
+            .ok_or_else(|| mbe::ExpandError::ConversionError)?;
 
         Ok(parse_to_token_tree(&db.file_text(file_id))
             .ok_or_else(|| mbe::ExpandError::ConversionError)?
@@ -418,8 +417,8 @@ fn include_str_expand(
     // Ideally, we'd be able to offer a precise expansion if the user asks for macro
     // expansion.
     let file_id = match relative_file(db, arg_id.into(), &path, true) {
-        Ok(file_id) => file_id,
-        Err(_) => {
+        Some(file_id) => file_id,
+        None => {
             return ExpandResult::ok(Some((quote!(""), FragmentKind::Expr)));
         }
     };
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 3909ad3545..71b2cade08 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -690,61 +690,4 @@ fn main() {
 "#,
         )
     }
-
-    #[test]
-    fn cfgd_out_call_arguments() {
-        check_diagnostics(
-            r#"
-struct C(#[cfg(FALSE)] ());
-impl C {
-    fn new() -> Self {
-        Self(
-            #[cfg(FALSE)]
-            (),
-        )
-    }
-
-    fn method(&self) {}
-}
-
-fn main() {
-    C::new().method(#[cfg(FALSE)] 0);
-}
-            "#,
-        );
-    }
-
-    #[test]
-    fn cfgd_out_fn_params() {
-        check_diagnostics(
-            r#"
-fn foo(#[cfg(NEVER)] x: ()) {}
-
-struct S;
-
-impl S {
-    fn method(#[cfg(NEVER)] self) {}
-    fn method2(#[cfg(NEVER)] self, arg: u8) {}
-    fn method3(self, #[cfg(NEVER)] arg: u8) {}
-}
-
-extern "C" {
-    fn fixed(fixed: u8, #[cfg(NEVER)] ...);
-    fn varargs(#[cfg(not(NEVER))] ...);
-}
-
-fn main() {
-    foo();
-    S::method();
-    S::method2(0);
-    S::method3(S);
-    S.method3();
-    unsafe {
-        fixed(0);
-        varargs(1, 2, 3);
-    }
-}
-            "#,
-        )
-    }
 }
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index c7c1f4fee9..5ea9fc4fb3 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -65,8 +65,6 @@ pub(crate) fn extract_definitions_from_markdown(
 ) -> Vec<(String, Option<hir::Namespace>, Range<usize>)> {
     let mut res = vec![];
     let mut cb = |link: BrokenLink| {
-        // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong
-        // this is fixed in the repo but not on the crates.io release yet
         Some((
             /*url*/ link.reference.to_owned().into(),
             /*title*/ link.reference.to_owned().into(),
@@ -74,10 +72,13 @@ pub(crate) fn extract_definitions_from_markdown(
     };
     let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb));
     for (event, range) in doc.into_offset_iter() {
-        if let Event::Start(Tag::Link(_, target, title)) = event {
-            let link = if target.is_empty() { title } else { target };
-            let (link, ns) = parse_link(&link);
-            res.push((link.to_string(), ns, range));
+        match event {
+            Event::Start(Tag::Link(_link_type, ref target, ref title)) => {
+                let link = if target.is_empty() { title } else { target };
+                let (link, ns) = parse_link(link);
+                res.push((link.to_string(), ns, range));
+            }
+            _ => {}
         }
     }
     res
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 598b47e417..b71f4917c0 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,5 +1,3 @@
-use std::ops::Range;
-
 use either::Either;
 use hir::{HasAttrs, ModuleDef, Semantics};
 use ide_db::{
@@ -7,8 +5,7 @@ use ide_db::{
     RootDatabase,
 };
 use syntax::{
-    ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, TextSize,
-    TokenAtOffset, T,
+    ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T,
 };
 
 use crate::{
@@ -95,18 +92,17 @@ fn extract_positioned_link_from_comment(
     position: FilePosition,
     comment: &ast::Comment,
 ) -> Option<(String, Option<hir::Namespace>)> {
+    let comment_range = comment.syntax().text_range();
     let doc_comment = comment.doc_comment()?;
-    let comment_start =
-        comment.syntax().text_range().start() + TextSize::from(comment.prefix().len() as u32);
     let def_links = extract_definitions_from_markdown(doc_comment);
-    let (def_link, ns, _) = def_links.into_iter().find(|&(_, _, Range { start, end })| {
-        TextRange::at(
-            comment_start + TextSize::from(start as u32),
-            TextSize::from((end - start) as u32),
-        )
-        .contains(position.offset)
+    let (def_link, ns, _) = def_links.iter().min_by_key(|(_, _, def_link_range)| {
+        let matched_position = comment_range.start() + TextSize::from(def_link_range.start as u32);
+        match position.offset.checked_sub(matched_position) {
+            Some(distance) => distance,
+            None => comment_range.end(),
+        }
     })?;
-    Some((def_link, ns))
+    Some((def_link.to_string(), *ns))
 }
 
 fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
@@ -1140,7 +1136,7 @@ fn foo<'foo>(_: &'foo ()) {
     fn goto_def_for_intra_doc_link_same_file() {
         check(
             r#"
-/// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
+/// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar)
 pub fn bar() { }
 
 /// You might want to see [`std::fs::read()`] too.
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 15d309d7d6..3250146221 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1533,21 +1533,12 @@ fn my() {}
     fn test_hover_struct_doc_comment() {
         check(
             r#"
-/// This is an example
-/// multiline doc
-///
-/// # Example
-///
-/// ```
-/// let five = 5;
-///
-/// assert_eq!(6, my_crate::add_one(5));
-/// ```
+/// bar docs
 struct Bar;
 
 fn foo() { let bar = Ba$0r; }
 "#,
-            expect![[r##"
+            expect![[r#"
                 *Bar*
 
                 ```rust
@@ -1560,17 +1551,8 @@ fn foo() { let bar = Ba$0r; }
 
                 ---
 
-                This is an example
-                multiline doc
-
-                # Example
-
-                ```
-                let five = 5;
-
-                assert_eq!(6, my_crate::add_one(5));
-                ```
-            "##]],
+                bar docs
+            "#]],
         );
     }
 
@@ -3441,40 +3423,6 @@ mod Foo$0 {
         );
     }
 
-    #[test]
-    fn hover_doc_block_style_indentend() {
-        check(
-            r#"
-/**
-    foo
-    ```rust
-    let x = 3;
-    ```
-*/
-fn foo$0() {}
-"#,
-            expect![[r#"
-                *foo*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                fn foo()
-                ```
-
-                ---
-
-                foo
-
-                ```rust
-                let x = 3;
-                ```
-            "#]],
-        );
-    }
-
     #[test]
     fn hover_comments_dont_highlight_parent() {
         check_hover_no_result(
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index bea020b061..397e2126b8 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -576,20 +576,6 @@ fn should_have_runnable_1() {}
 /// ```
 fn should_have_runnable_2() {}
 
-/**
-```rust
-let z = 55;
-```
-*/
-fn should_have_no_runnable_3() {}
-
-/**
-    ```rust
-    let z = 55;
-    ```
-*/
-fn should_have_no_runnable_4() {}
-
 /// ```no_run
 /// let z = 55;
 /// ```
@@ -630,7 +616,7 @@ fn should_have_no_runnable_6() {}
 struct StructWithRunnable(String);
 
 "#,
-            &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST],
+            &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST],
             expect![[r#"
                 [
                     Runnable {
@@ -696,37 +682,7 @@ struct StructWithRunnable(String);
                             file_id: FileId(
                                 0,
                             ),
-                            full_range: 256..320,
-                            name: "should_have_no_runnable_3",
-                        },
-                        kind: DocTest {
-                            test_id: Path(
-                                "should_have_no_runnable_3",
-                            ),
-                        },
-                        cfg: None,
-                    },
-                    Runnable {
-                        nav: NavigationTarget {
-                            file_id: FileId(
-                                0,
-                            ),
-                            full_range: 322..398,
-                            name: "should_have_no_runnable_4",
-                        },
-                        kind: DocTest {
-                            test_id: Path(
-                                "should_have_no_runnable_4",
-                            ),
-                        },
-                        cfg: None,
-                    },
-                    Runnable {
-                        nav: NavigationTarget {
-                            file_id: FileId(
-                                0,
-                            ),
-                            full_range: 900..965,
+                            full_range: 756..821,
                             name: "StructWithRunnable",
                         },
                         kind: DocTest {
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index ba3447b3a3..870146d24f 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -150,7 +150,7 @@ fn traverse(
             WalkEvent::Enter(it) => it,
             WalkEvent::Leave(it) => {
                 if let Some(node) = it.as_node() {
-                    inject::doc_comment(hl, sema, node);
+                    inject::doc_comment(hl, node);
                 }
                 continue;
             }
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 1d34731ab9..0ee7bc96e2 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -59,7 +59,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 947cc974ce..4f825523c4 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -1,18 +1,10 @@
 //! "Recursive" Syntax highlighting for code in doctests and fixtures.
 
-use std::{mem, ops::Range};
+use hir::Semantics;
+use ide_db::call_info::ActiveParameter;
+use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
 
-use either::Either;
-use hir::{HasAttrs, Semantics};
-use ide_db::{call_info::ActiveParameter, defs::Definition};
-use syntax::{
-    ast::{self, AstNode, AttrsOwner, DocCommentsOwner},
-    match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
-};
-
-use crate::{
-    doc_links::extract_definitions_from_markdown, Analysis, HlMod, HlRange, HlTag, RootDatabase,
-};
+use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase};
 
 use super::{highlights::Highlights, injector::Injector};
 
@@ -89,181 +81,70 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
     "edition2021",
 ];
 
-// Basically an owned dyn AttrsOwner without extra Boxing
-struct AttrsOwnerNode {
-    node: SyntaxNode,
-}
-
-impl AttrsOwnerNode {
-    fn new<N: DocCommentsOwner>(node: N) -> Self {
-        AttrsOwnerNode { node: node.syntax().clone() }
-    }
-}
-
-impl AttrsOwner for AttrsOwnerNode {}
-impl AstNode for AttrsOwnerNode {
-    fn can_cast(_: syntax::SyntaxKind) -> bool
-    where
-        Self: Sized,
-    {
-        false
-    }
-    fn cast(_: SyntaxNode) -> Option<Self>
-    where
-        Self: Sized,
-    {
-        None
-    }
-    fn syntax(&self) -> &SyntaxNode {
-        &self.node
-    }
-}
+/// Injection of syntax highlighting of doctests.
+pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) {
+    let doc_comments = node
+        .children_with_tokens()
+        .filter_map(|it| it.into_token().and_then(ast::Comment::cast))
+        .filter(|it| it.kind().doc.is_some());
 
-fn doc_attributes<'node>(
-    sema: &Semantics<RootDatabase>,
-    node: &'node SyntaxNode,
-) -> Option<(AttrsOwnerNode, hir::Attrs, Definition)> {
-    match_ast! {
-        match node {
-            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
-            ast::Module(it)      => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
-            ast::Fn(it)          => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))),
-            ast::Struct(it)      => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))),
-            ast::Union(it)       => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))),
-            ast::Enum(it)        => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))),
-            ast::Variant(it)     => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))),
-            ast::Trait(it)       => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))),
-            ast::Static(it)      => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))),
-            ast::Const(it)       => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))),
-            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))),
-            ast::Impl(it)        => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::SelfType(def))),
-            ast::RecordField(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Field(def))),
-            ast::TupleField(it)  => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Field(def))),
-            ast::MacroRules(it)  => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Macro(def))),
-            // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
-            // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
-            _ => return None
-        }
+    if !doc_comments.clone().any(|it| it.text().contains(RUSTDOC_FENCE)) {
+        return;
     }
-}
-
-/// Injection of syntax highlighting of doctests.
-pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, node: &SyntaxNode) {
-    let (owner, attributes, def) = match doc_attributes(sema, node) {
-        Some(it) => it,
-        None => return,
-    };
 
     let mut inj = Injector::default();
     inj.add_unmapped("fn doctest() {\n");
 
-    let attrs_source_map = attributes.source_map(&owner);
-
     let mut is_codeblock = false;
     let mut is_doctest = false;
 
     // Replace the original, line-spanning comment ranges by new, only comment-prefix
     // spanning comment ranges.
     let mut new_comments = Vec::new();
-    let mut intra_doc_links = Vec::new();
-    let mut string;
-    for attr in attributes.by_key("doc").attrs() {
-        let src = attrs_source_map.source_of(&attr);
-        let (line, range, prefix) = match &src {
-            Either::Left(it) => {
-                string = match find_doc_string_in_attr(attr, it) {
-                    Some(it) => it,
-                    None => continue,
-                };
-                let text_range = string.syntax().text_range();
-                let text_range = TextRange::new(
-                    text_range.start() + TextSize::from(1),
-                    text_range.end() - TextSize::from(1),
-                );
-                let text = string.text();
-                (&text[1..text.len() - 1], text_range, "")
-            }
-            Either::Right(comment) => {
-                (comment.text(), comment.syntax().text_range(), comment.prefix())
-            }
-        };
-
-        let mut pos = TextSize::from(prefix.len() as u32);
-        let mut range_start = range.start();
-        for line in line.split('\n') {
-            let line_len = TextSize::from(line.len() as u32);
-            let prev_range_start = {
-                let next_range_start = range_start + line_len + TextSize::from(1);
-                mem::replace(&mut range_start, next_range_start)
-            };
-            // only first line has the prefix so take it away for future iterations
-            let mut pos = mem::take(&mut pos);
-
-            match line.find(RUSTDOC_FENCE) {
-                Some(idx) => {
-                    is_codeblock = !is_codeblock;
-                    // Check whether code is rust by inspecting fence guards
-                    let guards = &line[idx + RUSTDOC_FENCE.len()..];
-                    let is_rust =
-                        guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim()));
-                    is_doctest = is_codeblock && is_rust;
-                    continue;
-                }
-                None if !is_doctest => {
-                    intra_doc_links.extend(
-                        extract_definitions_from_markdown(line)
-                            .into_iter()
-                            .filter(|(link, ns, _)| {
-                                validate_intra_doc_link(sema.db, &def, link, *ns)
-                            })
-                            .map(|(.., Range { start, end })| {
-                                TextRange::at(
-                                    prev_range_start + TextSize::from(start as u32),
-                                    TextSize::from((end - start) as u32),
-                                )
-                            }),
-                    );
-                    continue;
-                }
-                None => (),
+    for comment in doc_comments {
+        match comment.text().find(RUSTDOC_FENCE) {
+            Some(idx) => {
+                is_codeblock = !is_codeblock;
+                // Check whether code is rust by inspecting fence guards
+                let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..];
+                let is_rust =
+                    guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim()));
+                is_doctest = is_codeblock && is_rust;
+                continue;
             }
+            None if !is_doctest => continue,
+            None => (),
+        }
 
-            // whitespace after comment is ignored
-            if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) {
-                pos += TextSize::of(ws);
-            }
-            // lines marked with `#` should be ignored in output, we skip the `#` char
-            if line[pos.into()..].starts_with('#') {
-                pos += TextSize::of('#');
-            }
+        let line: &str = comment.text();
+        let range = comment.syntax().text_range();
 
-            new_comments.push(TextRange::at(prev_range_start, pos));
-            inj.add(&line[pos.into()..], TextRange::new(pos, line_len) + prev_range_start);
-            inj.add_unmapped("\n");
+        let mut pos = TextSize::of(comment.prefix());
+        // whitespace after comment is ignored
+        if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) {
+            pos += TextSize::of(ws);
+        }
+        // lines marked with `#` should be ignored in output, we skip the `#` char
+        if let Some(ws) = line[pos.into()..].chars().next().filter(|&c| c == '#') {
+            pos += TextSize::of(ws);
         }
-    }
 
-    for range in intra_doc_links {
-        hl.add(HlRange {
-            range,
-            highlight: HlTag::IntraDocLink | HlMod::Documentation,
-            binding_hash: None,
-        });
-    }
+        new_comments.push(TextRange::at(range.start(), pos));
 
-    if new_comments.is_empty() {
-        return; // no need to run an analysis on an empty file
+        inj.add(&line[pos.into()..], TextRange::new(range.start() + pos, range.end()));
+        inj.add_unmapped("\n");
     }
-
     inj.add_unmapped("\n}");
 
     let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string());
 
-    for HlRange { range, highlight, binding_hash } in
-        analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap()
-    {
-        for range in inj.map_range_up(range) {
-            hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash });
+    for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() {
+        for r in inj.map_range_up(h.range) {
+            hl.add(HlRange {
+                range: r,
+                highlight: h.highlight | HlMod::Injected,
+                binding_hash: h.binding_hash,
+            });
         }
     }
 
@@ -275,55 +156,3 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
         });
     }
 }
-
-fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::String> {
-    match it.literal() {
-        // #[doc = lit]
-        Some(lit) => match lit.kind() {
-            ast::LiteralKind::String(it) => Some(it),
-            _ => None,
-        },
-        // #[cfg_attr(..., doc = "", ...)]
-        None => {
-            // We gotta hunt the string token manually here
-            let text = attr.string_value()?;
-            // FIXME: We just pick the first string literal that has the same text as the doc attribute
-            // This means technically we might highlight the wrong one
-            it.syntax()
-                .descendants_with_tokens()
-                .filter_map(NodeOrToken::into_token)
-                .filter_map(ast::String::cast)
-                .find(|string| {
-                    string.text().get(1..string.text().len() - 1).map_or(false, |it| it == text)
-                })
-        }
-    }
-}
-
-fn validate_intra_doc_link(
-    db: &RootDatabase,
-    def: &Definition,
-    link: &str,
-    ns: Option<hir::Namespace>,
-) -> bool {
-    match def {
-        Definition::ModuleDef(def) => match def {
-            hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns),
-            hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns),
-            hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns),
-            hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns),
-            hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns),
-            hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns),
-            hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns),
-            hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns),
-            hir::ModuleDef::BuiltinType(_) => None,
-        },
-        Definition::Macro(it) => it.resolve_doc_path(db, &link, ns),
-        Definition::Field(it) => it.resolve_doc_path(db, &link, ns),
-        Definition::SelfType(_)
-        | Definition::Local(_)
-        | Definition::GenericParam(_)
-        | Definition::Label(_) => None,
-    }
-    .is_some()
-}
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index ce46e5127a..3c02fdb115 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -18,20 +18,19 @@ pub struct HlMods(u32);
 pub enum HlTag {
     Symbol(SymbolKind),
 
-    Attribute,
     BoolLiteral,
     BuiltinType,
     ByteLiteral,
     CharLiteral,
+    NumericLiteral,
+    StringLiteral,
+    Attribute,
     Comment,
     EscapeSequence,
     FormatSpecifier,
-    IntraDocLink,
     Keyword,
-    NumericLiteral,
-    Operator,
     Punctuation(HlPunct),
-    StringLiteral,
+    Operator,
     UnresolvedReference,
 
     // For things which don't have a specific highlight.
@@ -117,7 +116,6 @@ impl HlTag {
             HlTag::Comment => "comment",
             HlTag::EscapeSequence => "escape_sequence",
             HlTag::FormatSpecifier => "format_specifier",
-            HlTag::IntraDocLink => "intra_doc_link",
             HlTag::Keyword => "keyword",
             HlTag::Punctuation(punct) => match punct {
                 HlPunct::Bracket => "bracket",
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index d9ea7b7ea1..5b7ad38d5f 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -255,7 +255,7 @@ fn foo() {
     bar.fo$0;
 }
 "#,
-            DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
+            DetailAndDocumentation { detail: "fn(&self)", documentation: " Do the foo" },
         );
     }
 
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs
index 9b590d919b..104ee113fb 100644
--- a/crates/ide_db/src/apply_change.rs
+++ b/crates/ide_db/src/apply_change.rs
@@ -148,7 +148,7 @@ impl RootDatabase {
             hir::db::HygieneFrameQuery
 
             // DefDatabase
-            hir::db::FileItemTreeQuery
+            hir::db::ItemTreeQuery
             hir::db::BlockDefMapQuery
             hir::db::CrateDefMapQueryQuery
             hir::db::StructDataQuery
diff --git a/crates/ide_db/src/call_info.rs b/crates/ide_db/src/call_info.rs
index 7e26c3ccfd..d4016973c6 100644
--- a/crates/ide_db/src/call_info.rs
+++ b/crates/ide_db/src/call_info.rs
@@ -53,15 +53,15 @@ pub fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo>
 
     match callable.kind() {
         hir::CallableKind::Function(func) => {
-            res.doc = func.docs(db).map(|it| it.into());
+            res.doc = func.docs(db).map(|it| it.as_str().to_string());
             format_to!(res.signature, "fn {}", func.name(db));
         }
         hir::CallableKind::TupleStruct(strukt) => {
-            res.doc = strukt.docs(db).map(|it| it.into());
+            res.doc = strukt.docs(db).map(|it| it.as_str().to_string());
             format_to!(res.signature, "struct {}", strukt.name(db));
         }
         hir::CallableKind::TupleEnumVariant(variant) => {
-            res.doc = variant.docs(db).map(|it| it.into());
+            res.doc = variant.docs(db).map(|it| it.as_str().to_string());
             format_to!(
                 res.signature,
                 "enum {}::{}",
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs
index 9e2f02d435..e313f6fb7f 100644
--- a/crates/parser/src/grammar/params.rs
+++ b/crates/parser/src/grammar/params.rs
@@ -41,32 +41,22 @@ fn list_(p: &mut Parser, flavor: Flavor) {
         FnDef | FnTrait | FnPointer => (T!['('], T![')']),
     };
 
-    let list_marker = p.start();
+    let m = p.start();
     p.bump(bra);
 
-    let mut param_marker = None;
     if let FnDef = flavor {
         // test self_param_outer_attr
         // fn f(#[must_use] self) {}
         let m = p.start();
         attributes::outer_attrs(p);
-        match opt_self_param(p, m) {
-            Ok(()) => {}
-            Err(m) => param_marker = Some(m),
-        }
+        opt_self_param(p, m);
     }
 
     while !p.at(EOF) && !p.at(ket) {
         // test param_outer_arg
         // fn f(#[attr1] pat: Type) {}
-        let m = match param_marker.take() {
-            Some(m) => m,
-            None => {
-                let m = p.start();
-                attributes::outer_attrs(p);
-                m
-            }
-        };
+        let m = p.start();
+        attributes::outer_attrs(p);
 
         if !p.at_ts(PARAM_FIRST) {
             p.error("expected value parameter");
@@ -82,12 +72,8 @@ fn list_(p: &mut Parser, flavor: Flavor) {
         }
     }
 
-    if let Some(m) = param_marker {
-        m.abandon(p);
-    }
-
     p.expect(ket);
-    list_marker.complete(p, PARAM_LIST);
+    m.complete(p, PARAM_LIST);
 }
 
 const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
@@ -167,7 +153,7 @@ fn variadic_param(p: &mut Parser) -> bool {
 //     fn d(&'a mut self, x: i32) {}
 //     fn e(mut self) {}
 // }
-fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> {
+fn opt_self_param(p: &mut Parser, m: Marker) {
     if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] {
         p.eat(T![mut]);
         self_as_name(p);
@@ -190,7 +176,7 @@ fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> {
                 | (T![&], LIFETIME_IDENT, T![self], _)
                 | (T![&], LIFETIME_IDENT, T![mut], T![self])
         ) {
-            return Err(m);
+            return m.abandon(p);
         }
         p.bump(T![&]);
         if p.at(LIFETIME_IDENT) {
@@ -203,7 +189,6 @@ fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> {
     if !p.at(T![')']) {
         p.expect(T![,]);
     }
-    Ok(())
 }
 
 fn self_as_name(p: &mut Parser) {
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 0cb7d12a76..be0bea00b7 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -45,16 +45,15 @@ define_semantic_token_types![
     (BRACKET, "bracket"),
     (BUILTIN_TYPE, "builtinType"),
     (CHAR_LITERAL, "characterLiteral"),
-    (COLON, "colon"),
     (COMMA, "comma"),
-    (CONST_PARAMETER, "constParameter"),
+    (COLON, "colon"),
     (DOT, "dot"),
     (ESCAPE_SEQUENCE, "escapeSequence"),
     (FORMAT_SPECIFIER, "formatSpecifier"),
     (GENERIC, "generic"),
-    (INTRA_DOC_LINK, "intraDocLink"),
-    (LABEL, "label"),
+    (CONST_PARAMETER, "constParameter"),
     (LIFETIME, "lifetime"),
+    (LABEL, "label"),
     (PARENTHESIS, "parenthesis"),
     (PUNCTUATION, "punctuation"),
     (SELF_KEYWORD, "selfKeyword"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 70501618e8..c63fe2915e 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -435,20 +435,19 @@ fn semantic_token_type_and_modifiers(
             SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE,
             SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO,
         },
-        HlTag::Attribute => semantic_tokens::ATTRIBUTE,
-        HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
         HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE,
+        HlTag::None => semantic_tokens::GENERIC,
         HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER,
+        HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
+        HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
         HlTag::CharLiteral => semantic_tokens::CHAR_LITERAL,
         HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
-        HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
-        HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
-        HlTag::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
+        HlTag::Attribute => semantic_tokens::ATTRIBUTE,
         HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD,
-        HlTag::None => semantic_tokens::GENERIC,
-        HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
-        HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
         HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
+        HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
+        HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
+        HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
         HlTag::Punctuation(punct) => match punct {
             HlPunct::Bracket => semantic_tokens::BRACKET,
             HlPunct::Brace => semantic_tokens::BRACE,
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs
index 38e0b04efb..19261686cb 100644
--- a/crates/syntax/src/ast.rs
+++ b/crates/syntax/src/ast.rs
@@ -118,7 +118,7 @@ fn test_doc_comment_none() {
     .ok()
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
-    assert!(module.doc_comments().doc_comment_text().is_none());
+    assert!(module.doc_comment_text().is_none());
 }
 
 #[test]
@@ -133,7 +133,7 @@ fn test_outer_doc_comment_of_items() {
     .ok()
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
-    assert_eq!(" doc", module.doc_comments().doc_comment_text().unwrap());
+    assert_eq!("doc", module.doc_comment_text().unwrap());
 }
 
 #[test]
@@ -148,7 +148,7 @@ fn test_inner_doc_comment_of_items() {
     .ok()
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
-    assert!(module.doc_comments().doc_comment_text().is_none());
+    assert!(module.doc_comment_text().is_none());
 }
 
 #[test]
@@ -162,7 +162,7 @@ fn test_doc_comment_of_statics() {
     .ok()
     .unwrap();
     let st = file.syntax().descendants().find_map(Static::cast).unwrap();
-    assert_eq!(" Number of levels", st.doc_comments().doc_comment_text().unwrap());
+    assert_eq!("Number of levels", st.doc_comment_text().unwrap());
 }
 
 #[test]
@@ -181,10 +181,7 @@ fn test_doc_comment_preserves_indents() {
     .ok()
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
-    assert_eq!(
-        " doc1\n ```\n fn foo() {\n     // ...\n }\n ```",
-        module.doc_comments().doc_comment_text().unwrap()
-    );
+    assert_eq!("doc1\n```\nfn foo() {\n    // ...\n}\n```", module.doc_comment_text().unwrap());
 }
 
 #[test]
@@ -201,7 +198,7 @@ fn test_doc_comment_preserves_newlines() {
     .ok()
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
-    assert_eq!(" this\n is\n mod\n foo", module.doc_comments().doc_comment_text().unwrap());
+    assert_eq!("this\nis\nmod\nfoo", module.doc_comment_text().unwrap());
 }
 
 #[test]
@@ -215,7 +212,7 @@ fn test_doc_comment_single_line_block_strips_suffix() {
     .ok()
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
-    assert_eq!(" this is mod foo", module.doc_comments().doc_comment_text().unwrap());
+    assert_eq!("this is mod foo", module.doc_comment_text().unwrap());
 }
 
 #[test]
@@ -229,7 +226,7 @@ fn test_doc_comment_single_line_block_strips_suffix_whitespace() {
     .ok()
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
-    assert_eq!(" this is mod foo ", module.doc_comments().doc_comment_text().unwrap());
+    assert_eq!("this is mod foo ", module.doc_comment_text().unwrap());
 }
 
 #[test]
@@ -248,8 +245,8 @@ fn test_doc_comment_multi_line_block_strips_suffix() {
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
     assert_eq!(
-        "\n        this\n        is\n        mod foo\n        ",
-        module.doc_comments().doc_comment_text().unwrap()
+        "        this\n        is\n        mod foo\n        ",
+        module.doc_comment_text().unwrap()
     );
 }
 
@@ -262,8 +259,8 @@ fn test_comments_preserve_trailing_whitespace() {
     .unwrap();
     let def = file.syntax().descendants().find_map(Struct::cast).unwrap();
     assert_eq!(
-        " Representation of a Realm.   \n In the specification these are called Realm Records.",
-        def.doc_comments().doc_comment_text().unwrap()
+        "Representation of a Realm.   \nIn the specification these are called Realm Records.",
+        def.doc_comment_text().unwrap()
     );
 }
 
@@ -279,7 +276,7 @@ fn test_four_slash_line_comment() {
     .ok()
     .unwrap();
     let module = file.syntax().descendants().find_map(Module::cast).unwrap();
-    assert_eq!(" doc comment", module.doc_comments().doc_comment_text().unwrap());
+    assert_eq!("doc comment", module.doc_comment_text().unwrap());
 }
 
 #[test]
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 6c242d1265..977eb81819 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -33,20 +33,23 @@ impl ast::Comment {
         prefix
     }
 
-    /// Returns the textual content of a doc comment node as a single string with prefix and suffix
-    /// removed.
+    /// Returns the textual content of a doc comment block as a single string.
+    /// That is, strips leading `///` (+ optional 1 character of whitespace),
+    /// trailing `*/`, trailing whitespace and then joins the lines.
     pub fn doc_comment(&self) -> Option<&str> {
         let kind = self.kind();
         match kind {
             CommentKind { shape, doc: Some(_) } => {
                 let prefix = kind.prefix();
                 let text = &self.text()[prefix.len()..];
-                let text = if shape == CommentShape::Block {
-                    text.strip_suffix("*/").unwrap_or(text)
-                } else {
-                    text
-                };
-                Some(text)
+                let ws = text.chars().next().filter(|c| c.is_whitespace());
+                let text = ws.map_or(text, |ws| &text[ws.len_utf8()..]);
+                match shape {
+                    CommentShape::Block if text.ends_with("*/") => {
+                        Some(&text[..text.len() - "*/".len()])
+                    }
+                    _ => Some(text),
+                }
             }
             _ => None,
         }
diff --git a/crates/syntax/src/ast/traits.rs b/crates/syntax/src/ast/traits.rs
index ddd2136370..13a769d51a 100644
--- a/crates/syntax/src/ast/traits.rs
+++ b/crates/syntax/src/ast/traits.rs
@@ -1,6 +1,8 @@
 //! Various traits that are implemented by ast nodes.
 //!
 //! The implementations are usually trivial, and live in generated.rs
+use itertools::Itertools;
+
 use crate::{
     ast::{self, support, AstChildren, AstNode, AstToken},
     syntax_node::SyntaxElementChildren,
@@ -70,10 +72,14 @@ pub trait AttrsOwner: AstNode {
     }
 }
 
-pub trait DocCommentsOwner: AttrsOwner {
+pub trait DocCommentsOwner: AstNode {
     fn doc_comments(&self) -> CommentIter {
         CommentIter { iter: self.syntax().children_with_tokens() }
     }
+
+    fn doc_comment_text(&self) -> Option<String> {
+        self.doc_comments().doc_comment_text()
+    }
 }
 
 impl CommentIter {
@@ -81,12 +87,12 @@ impl CommentIter {
         CommentIter { iter: syntax_node.children_with_tokens() }
     }
 
-    #[cfg(test)]
+    /// Returns the textual content of a doc comment block as a single string.
+    /// That is, strips leading `///` (+ optional 1 character of whitespace),
+    /// trailing `*/`, trailing whitespace and then joins the lines.
     pub fn doc_comment_text(self) -> Option<String> {
-        let docs = itertools::Itertools::join(
-            &mut self.filter_map(|comment| comment.doc_comment().map(ToOwned::to_owned)),
-            "\n",
-        );
+        let docs =
+            self.filter_map(|comment| comment.doc_comment().map(ToOwned::to_owned)).join("\n");
         if docs.is_empty() {
             None
         } else {


Test patch:
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index faa1332970..f8e6f70e87 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -137,7 +137,7 @@ fn f() {
     include!(invalid);
   //^^^^^^^^^^^^^^^^^ could not convert tokens
     include!("does not exist");
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist`
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
 
     env!(invalid);
   //^^^^^^^^^^^^^ could not convert tokens
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 4f2e7a2f96..de3aa4f9ae 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -713,22 +713,3 @@ pub fn f() {}
         "#]],
     );
 }
-
-#[test]
-fn use_crate_as() {
-    check(
-        r#"
-use crate as foo;
-
-use foo::bar as baz;
-
-fn bar() {}
-        "#,
-        expect![[r#"
-            crate
-            bar: v
-            baz: v
-            foo: t
-        "#]],
-    );
-}
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index a89061c2e8..c22ef46fd6 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -196,24 +196,7 @@ fn builtin_macro_fails_expansion() {
           macro_rules! include { () => {} }
 
           include!("doesntexist");
-        //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist`
-        "#,
-    );
-}
-
-#[test]
-fn good_out_dir_diagnostic() {
-    check_diagnostics(
-        r#"
-        #[rustc_builtin_macro]
-        macro_rules! include { () => {} }
-        #[rustc_builtin_macro]
-        macro_rules! env { () => {} }
-        #[rustc_builtin_macro]
-        macro_rules! concat { () => {} }
-
-        include!(concat!(env!("OUT_DIR"), "/out.rs"));
-      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix
+        //^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
         "#,
     );
 }
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index bcc43ed700..f5069eba51 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -2545,22 +2545,3 @@ fn test() {
         "#]],
     )
 }
-
-#[test]
-fn cfgd_out_assoc_items() {
-    check_types(
-        r#"
-struct S;
-
-impl S {
-    #[cfg(FALSE)]
-    const C: S = S;
-}
-
-fn f() {
-    S::C;
-  //^^^^ {unknown}
-}
-    "#,
-    )
-}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 8270fa2193..93d3ad020a 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3253,24 +3253,3 @@ fn f() {
         "#,
     );
 }
-
-#[test]
-fn nested_inner_function_calling_self() {
-    check_infer(
-        r#"
-struct S;
-fn f() {
-    fn inner() -> S {
-        let s = inner();
-    }
-}
-        "#,
-        expect![[r#"
-            17..73 '{     ...   } }': ()
-            39..71 '{     ...     }': ()
-            53..54 's': S
-            57..62 'inner': fn inner() -> S
-            57..64 'inner()': S
-        "#]],
-    )
-}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 60c7518af8..d421a78038 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
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 5d802a6470..5e877df885 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
@@ -82,7 +81,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">/// </span><span class="comment injected">       comment */</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Foo</span>
-    <span class="comment documentation">/// </span><span class="string_literal injected">  bar</span><span class="escape_sequence injected">\n</span>
+    <span class="comment documentation">/// </span><span class="string_literal injected">  bar</span>
     <span class="comment documentation">/// </span><span class="string_literal injected">         "</span><span class="semicolon injected">;</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```</span>
@@ -99,11 +98,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="comment documentation">/// </span><span class="intra_doc_link documentation">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span>
-<span class="comment documentation">/// </span><span class="intra_doc_link documentation">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span>
-<span class="comment documentation">/// [`noop`](noop) is a macro below</span>
-<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
 <span class="comment documentation">/// ```</span>
@@ -111,36 +105,4 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
         <span class="punctuation">$</span>expr
     <span class="brace">}</span>
-<span class="brace">}</span>
-
-<span class="comment documentation">/// ```rust</span>
-<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
-<span class="comment documentation">/// ```</span>
-<span class="comment documentation">///</span>
-<span class="comment documentation">/// ```</span>
-<span class="comment documentation">/// </span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span>
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">not</span><span class="parenthesis attribute">(</span><span class="attribute attribute">feature </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"false"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span><span class="attribute attribute"> doc </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">doc</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="attribute attribute">]</span>
-<span class="comment documentation">/// ```</span>
-<span class="comment documentation">///</span>
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">feature </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"alloc"</span><span class="comma attribute">,</span><span class="attribute attribute"> doc </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"```rust"</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">not</span><span class="parenthesis attribute">(</span><span class="attribute attribute">feature </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"alloc"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span><span class="attribute attribute"> doc </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"```ignore"</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span>
-<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="none injected">alloc::</span><span class="macro injected">vec!</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
-<span class="comment documentation">/// ```</span>
-<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">mix_and_match</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-
-<span class="comment documentation">/**
-It is beyond me why you'd use these when you got ///
-```rust
-</span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="comment documentation">
-```
- */</span>
-<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">block_comments</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-
-<span class="comment documentation">/**
-    Really, I don't get it
-    ```rust
-</span><span class="comment documentation"> </span><span class="none injected">   </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="comment documentation">
-    ```
-*/</span>
-<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">block_comments2</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre>
\ No newline at end of file
+<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index 4e312765c0..6f7a7ffff3 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 57dfe75096..753b535b55 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
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 75dbd0f142..66d80c4b66 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 423256a202..036cb6c115 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index fffe8c0f57..2f983c0b8a 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html
index 34d8deb684..78dfec9518 100644
--- a/crates/ide/src/syntax_highlighting/test_data/injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/injection.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
index d9ca3a4c46..e64f2e5e93 100644
--- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
@@ -7,7 +7,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 7b2922b0d5..9d0cd1af5c 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -468,7 +468,7 @@ fn main() {
 }
 
 #[test]
-fn test_highlight_doc_comment() {
+fn test_highlight_doctest() {
     check_highlighting(
         r#"
 /// ```
@@ -516,7 +516,7 @@ impl Foo {
     ///        comment */
     ///
     /// let multi_line_string = "Foo
-    ///   bar\n
+    ///   bar
     ///          ";
     ///
     /// ```
@@ -533,11 +533,6 @@ impl Foo {
     }
 }
 
-/// [`Foo`](Foo) is a struct
-/// [`all_the_links`](all_the_links) is this function
-/// [`noop`](noop) is a macro below
-pub fn all_the_links() {}
-
 /// ```
 /// noop!(1);
 /// ```
@@ -546,38 +541,6 @@ macro_rules! noop {
         $expr
     }
 }
-
-/// ```rust
-/// let _ = example(&[1, 2, 3]);
-/// ```
-///
-/// ```
-/// loop {}
-#[cfg_attr(not(feature = "false"), doc = "loop {}")]
-#[doc = "loop {}"]
-/// ```
-///
-#[cfg_attr(feature = "alloc", doc = "```rust")]
-#[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
-/// let _ = example(&alloc::vec![1, 2, 3]);
-/// ```
-pub fn mix_and_match() {}
-
-/**
-It is beyond me why you'd use these when you got ///
-```rust
-let _ = example(&[1, 2, 3]);
-```
- */
-pub fn block_comments() {}
-
-/**
-    Really, I don't get it
-    ```rust
-    let _ = example(&[1, 2, 3]);
-    ```
-*/
-pub fn block_comments2() {}
 "#
         .trim(),
         expect_file!["./test_data/highlight_doctest.html"],
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs
index 75ab3eb6ea..9f84c253c1 100644
--- a/crates/ide_db/src/call_info/tests.rs
+++ b/crates/ide_db/src/call_info/tests.rs
@@ -220,11 +220,11 @@ fn bar() {
 }
 "#,
         expect![[r#"
-            test
-            ------
-            fn foo(j: u32) -> u32
-            (<j: u32>)
-        "#]],
+                test
+                ------
+                fn foo(j: u32) -> u32
+                (<j: u32>)
+            "#]],
     );
 }
 
@@ -249,19 +249,19 @@ pub fn do() {
     add_one($0
 }"#,
         expect![[r##"
-            Adds one to the number given.
+                Adds one to the number given.
 
-            # Examples
+                # Examples
 
-            ```
-            let five = 5;
+                ```
+                let five = 5;
 
-            assert_eq!(6, my_crate::add_one(5));
-            ```
-            ------
-            fn add_one(x: i32) -> i32
-            (<x: i32>)
-        "##]],
+                assert_eq!(6, my_crate::add_one(5));
+                ```
+                ------
+                fn add_one(x: i32) -> i32
+                (<x: i32>)
+            "##]],
     );
 }
 
@@ -291,19 +291,19 @@ pub fn do_it() {
 }
 "#,
         expect![[r##"
-            Adds one to the number given.
+                Adds one to the number given.
 
-            # Examples
+                # Examples
 
-            ```
-            let five = 5;
+                ```
+                let five = 5;
 
-            assert_eq!(6, my_crate::add_one(5));
-            ```
-            ------
-            fn add_one(x: i32) -> i32
-            (<x: i32>)
-        "##]],
+                assert_eq!(6, my_crate::add_one(5));
+                ```
+                ------
+                fn add_one(x: i32) -> i32
+                (<x: i32>)
+            "##]],
     );
 }
 
@@ -335,13 +335,13 @@ pub fn foo(mut r: WriteHandler<()>) {
 }
 "#,
         expect![[r#"
-            Method is called when writer finishes.
+                Method is called when writer finishes.
 
-            By default this method stops actor's `Context`.
-            ------
-            fn finished(&mut self, ctx: &mut {unknown})
-            (<ctx: &mut {unknown}>)
-        "#]],
+                By default this method stops actor's `Context`.
+                ------
+                fn finished(&mut self, ctx: &mut {unknown})
+                (<ctx: &mut {unknown}>)
+            "#]],
     );
 }
 
@@ -389,11 +389,11 @@ fn main() {
 }
 "#,
         expect![[r#"
-            A cool tuple struct
-            ------
-            struct S(u32, i32)
-            (u32, <i32>)
-        "#]],
+                A cool tuple struct
+                ------
+                struct S(u32, i32)
+                (u32, <i32>)
+            "#]],
     );
 }
 
@@ -431,11 +431,11 @@ fn main() {
 }
 "#,
         expect![[r#"
-            A Variant
-            ------
-            enum E::A(i32)
-            (<i32>)
-        "#]],
+                A Variant
+                ------
+                enum E::A(i32)
+                (<i32>)
+            "#]],
     );
 }
 
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 25c374b9b2..6da18ecf4e 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -1,1775 +1,14 @@
+mod expand;
+mod rule;
+
 use std::fmt::Write;
 
 use ::parser::FragmentKind;
-use syntax::{
-    ast, AstNode, NodeOrToken,
-    SyntaxKind::{ERROR, IDENT},
-    SyntaxNode, WalkEvent, T,
-};
+use syntax::{ast, AstNode, NodeOrToken, SyntaxNode, WalkEvent};
 use test_utils::assert_eq_text;
 
 use super::*;
 
-mod rule_parsing {
-    use syntax::{ast, AstNode};
-
-    use crate::ast_to_token_tree;
-
-    use super::*;
-
-    #[test]
-    fn test_valid_arms() {
-        fn check(macro_body: &str) {
-            let m = parse_macro_arm(macro_body);
-            m.unwrap();
-        }
-
-        check("($i:ident) => ()");
-        check("($($i:ident)*) => ($_)");
-        check("($($true:ident)*) => ($true)");
-        check("($($false:ident)*) => ($false)");
-        check("($) => ($)");
-    }
-
-    #[test]
-    fn test_invalid_arms() {
-        fn check(macro_body: &str, err: ParseError) {
-            let m = parse_macro_arm(macro_body);
-            assert_eq!(m, Err(err));
-        }
-        check("invalid", ParseError::Expected("expected subtree".into()));
-
-        check("$i:ident => ()", ParseError::Expected("expected subtree".into()));
-        check("($i:ident) ()", ParseError::Expected("expected `=`".into()));
-        check("($($i:ident)_) => ()", ParseError::InvalidRepeat);
-
-        check("($i) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
-        check("($i:) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
-    }
-
-    fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> {
-        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();
-
-        let (definition_tt, _) =
-            ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
-        crate::MacroRules::parse(&definition_tt)
-    }
-}
-
-// Good first issue (although a slightly challenging one):
-//
-// * Pick a random test from here
-//   https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
-// * Port the test to rust and add it to this module
-// * Make it pass :-)
-
-#[test]
-fn test_token_id_shift() {
-    let expansion = parse_macro(
-        r#"
-macro_rules! foobar {
-    ($e:ident) => { foo bar $e }
-}
-"#,
-    )
-    .expand_tt("foobar!(baz);");
-
-    fn get_id(t: &tt::TokenTree) -> Option<u32> {
-        if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t {
-            return Some(ident.id.0);
-        }
-        None
-    }
-
-    assert_eq!(expansion.token_trees.len(), 3);
-    // {($e:ident) => { foo bar $e }}
-    // 012345      67 8 9   T   12
-    assert_eq!(get_id(&expansion.token_trees[0]), Some(9));
-    assert_eq!(get_id(&expansion.token_trees[1]), Some(10));
-
-    // The input args of macro call include parentheses:
-    // (baz)
-    // So baz should be 12+1+1
-    assert_eq!(get_id(&expansion.token_trees[2]), Some(14));
-}
-
-#[test]
-fn test_token_map() {
-    let expanded = parse_macro(
-        r#"
-macro_rules! foobar {
-    ($e:ident) => { fn $e() {} }
-}
-"#,
-    )
-    .expand_tt("foobar!(baz);");
-
-    let (node, token_map) = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap();
-    let content = node.syntax_node().to_string();
-
-    let get_text = |id, kind| -> String {
-        content[token_map.range_by_token(id).unwrap().by_kind(kind).unwrap()].to_string()
-    };
-
-    assert_eq!(expanded.token_trees.len(), 4);
-    // {($e:ident) => { fn $e() {} }}
-    // 012345      67 8 9  T12  3
-
-    assert_eq!(get_text(tt::TokenId(9), IDENT), "fn");
-    assert_eq!(get_text(tt::TokenId(12), T!['(']), "(");
-    assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
-}
-
-#[test]
-fn test_convert_tt() {
-    parse_macro(r#"
-macro_rules! impl_froms {
-    ($e:ident: $($v:ident),*) => {
-        $(
-            impl From<$v> for $e {
-                fn from(it: $v) -> $e {
-                    $e::$v(it)
-                }
-            }
-        )*
-    }
-}
-"#)
-        .assert_expand_tt(
-            "impl_froms!(TokenTree: Leaf, Subtree);",
-            "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
-             impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
-        );
-}
-
-#[test]
-fn test_convert_tt2() {
-    parse_macro(
-        r#"
-macro_rules! impl_froms {
-    ($e:ident: $($v:ident),*) => {
-        $(
-            impl From<$v> for $e {
-                fn from(it: $v) -> $e {
-                    $e::$v(it)
-                }
-            }
-        )*
-    }
-}
-"#,
-    )
-    .assert_expand(
-        "impl_froms!(TokenTree: Leaf, Subtree);",
-        r#"
-SUBTREE $
-  IDENT   impl 20
-  IDENT   From 21
-  PUNCH   < [joint] 22
-  IDENT   Leaf 53
-  PUNCH   > [alone] 25
-  IDENT   for 26
-  IDENT   TokenTree 51
-  SUBTREE {} 29
-    IDENT   fn 30
-    IDENT   from 31
-    SUBTREE () 32
-      IDENT   it 33
-      PUNCH   : [alone] 34
-      IDENT   Leaf 53
-    PUNCH   - [joint] 37
-    PUNCH   > [alone] 38
-    IDENT   TokenTree 51
-    SUBTREE {} 41
-      IDENT   TokenTree 51
-      PUNCH   : [joint] 44
-      PUNCH   : [joint] 45
-      IDENT   Leaf 53
-      SUBTREE () 48
-        IDENT   it 49
-  IDENT   impl 20
-  IDENT   From 21
-  PUNCH   < [joint] 22
-  IDENT   Subtree 55
-  PUNCH   > [alone] 25
-  IDENT   for 26
-  IDENT   TokenTree 51
-  SUBTREE {} 29
-    IDENT   fn 30
-    IDENT   from 31
-    SUBTREE () 32
-      IDENT   it 33
-      PUNCH   : [alone] 34
-      IDENT   Subtree 55
-    PUNCH   - [joint] 37
-    PUNCH   > [alone] 38
-    IDENT   TokenTree 51
-    SUBTREE {} 41
-      IDENT   TokenTree 51
-      PUNCH   : [joint] 44
-      PUNCH   : [joint] 45
-      IDENT   Subtree 55
-      SUBTREE () 48
-        IDENT   it 49
-"#,
-    );
-}
-
-#[test]
-fn test_lifetime_split() {
-    parse_macro(
-        r#"
-macro_rules! foo {
-    ($($t:tt)*) => { $($t)*}
-}
-"#,
-    )
-    .assert_expand(
-        r#"foo!(static bar: &'static str = "hello";);"#,
-        r#"
-SUBTREE $
-  IDENT   static 17
-  IDENT   bar 18
-  PUNCH   : [alone] 19
-  PUNCH   & [alone] 20
-  PUNCH   ' [joint] 21
-  IDENT   static 22
-  IDENT   str 23
-  PUNCH   = [alone] 24
-  LITERAL "hello" 25
-  PUNCH   ; [joint] 26
-"#,
-    );
-}
-
-#[test]
-fn test_expr_order() {
-    let expanded = parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:expr) => {
-                 fn bar() { $ i * 2; }
-            }
-        }
-"#,
-    )
-    .expand_items("foo! { 1 + 1}");
-
-    let dump = format!("{:#?}", expanded);
-    assert_eq_text!(
-        r#"MACRO_ITEMS@0..15
-  FN@0..15
-    FN_KW@0..2 "fn"
-    NAME@2..5
-      IDENT@2..5 "bar"
-    PARAM_LIST@5..7
-      L_PAREN@5..6 "("
-      R_PAREN@6..7 ")"
-    BLOCK_EXPR@7..15
-      L_CURLY@7..8 "{"
-      EXPR_STMT@8..14
-        BIN_EXPR@8..13
-          BIN_EXPR@8..11
-            LITERAL@8..9
-              INT_NUMBER@8..9 "1"
-            PLUS@9..10 "+"
-            LITERAL@10..11
-              INT_NUMBER@10..11 "1"
-          STAR@11..12 "*"
-          LITERAL@12..13
-            INT_NUMBER@12..13 "2"
-        SEMICOLON@13..14 ";"
-      R_CURLY@14..15 "}""#,
-        dump.trim()
-    );
-}
-
-#[test]
-fn test_fail_match_pattern_by_first_token() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:ident) => (
-                mod $ i {}
-            );
-            (= $ i:ident) => (
-                fn $ i() {}
-            );
-            (+ $ i:ident) => (
-                struct $ i;
-            )
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo }", "mod foo {}")
-    .assert_expand_items("foo! { = bar }", "fn bar () {}")
-    .assert_expand_items("foo! { + Baz }", "struct Baz ;");
-}
-
-#[test]
-fn test_fail_match_pattern_by_last_token() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:ident) => (
-                mod $ i {}
-            );
-            ($ i:ident =) => (
-                fn $ i() {}
-            );
-            ($ i:ident +) => (
-                struct $ i;
-            )
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo }", "mod foo {}")
-    .assert_expand_items("foo! { bar = }", "fn bar () {}")
-    .assert_expand_items("foo! { Baz + }", "struct Baz ;");
-}
-
-#[test]
-fn test_fail_match_pattern_by_word_token() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:ident) => (
-                mod $ i {}
-            );
-            (spam $ i:ident) => (
-                fn $ i() {}
-            );
-            (eggs $ i:ident) => (
-                struct $ i;
-            )
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo }", "mod foo {}")
-    .assert_expand_items("foo! { spam bar }", "fn bar () {}")
-    .assert_expand_items("foo! { eggs Baz }", "struct Baz ;");
-}
-
-#[test]
-fn test_match_group_pattern_by_separator_token() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident),*) => ($ (
-                mod $ i {}
-            )*);
-            ($ ($ i:ident)#*) => ($ (
-                fn $ i() {}
-            )*);
-            ($ i:ident ,# $ j:ident) => (
-                struct $ i;
-                struct $ j;
-            )
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "mod foo {} mod bar {}")
-    .assert_expand_items("foo! { foo# bar }", "fn foo () {} fn bar () {}")
-    .assert_expand_items("foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
-}
-
-#[test]
-fn test_match_group_pattern_with_multiple_defs() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident),*) => ( struct Bar { $ (
-                fn $ i {}
-            )*} );
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}");
-}
-
-#[test]
-fn test_match_group_pattern_with_multiple_statement() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident),*) => ( fn baz { $ (
-                $ i ();
-            )*} );
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
-}
-
-#[test]
-fn test_match_group_pattern_with_multiple_statement_without_semi() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident),*) => ( fn baz { $ (
-                $i()
-            );*} );
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}");
-}
-
-#[test]
-fn test_match_group_empty_fixed_token() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident)* #abc) => ( fn baz { $ (
-                $ i ();
-            )*} );
-        }
-"#,
-    )
-    .assert_expand_items("foo! {#abc}", "fn baz {}");
-}
-
-#[test]
-fn test_match_group_in_subtree() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ (
-                $ i ();
-            )*} );
-        }"#,
-    )
-    .assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
-}
-
-#[test]
-fn test_match_group_with_multichar_sep() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
-        }"#,
-    )
-    .assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}");
-}
-
-#[test]
-fn test_match_group_with_multichar_sep2() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            (fn $name:ident {$($i:literal)&&*} ) => ( fn $name() -> bool { $($i)&&*} );
-        }"#,
-    )
-    .assert_expand_items("foo! (fn baz {true && true} );", "fn baz () -> bool {true &&true}");
-}
-
-#[test]
-fn test_match_group_zero_match() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ( $($i:ident)* ) => ();
-        }"#,
-    )
-    .assert_expand_items("foo! ();", "");
-}
-
-#[test]
-fn test_match_group_in_group() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* );
-        }"#,
-    )
-    .assert_expand_items("foo! ( (a b) );", "(a b)");
-}
-
-#[test]
-fn test_expand_to_item_list() {
-    let tree = parse_macro(
-        "
-            macro_rules! structs {
-                ($($i:ident),*) => {
-                    $(struct $i { field: u32 } )*
-                }
-            }
-            ",
-    )
-    .expand_items("structs!(Foo, Bar);");
-    assert_eq!(
-        format!("{:#?}", tree).trim(),
-        r#"
-MACRO_ITEMS@0..40
-  STRUCT@0..20
-    STRUCT_KW@0..6 "struct"
-    NAME@6..9
-      IDENT@6..9 "Foo"
-    RECORD_FIELD_LIST@9..20
-      L_CURLY@9..10 "{"
-      RECORD_FIELD@10..19
-        NAME@10..15
-          IDENT@10..15 "field"
-        COLON@15..16 ":"
-        PATH_TYPE@16..19
-          PATH@16..19
-            PATH_SEGMENT@16..19
-              NAME_REF@16..19
-                IDENT@16..19 "u32"
-      R_CURLY@19..20 "}"
-  STRUCT@20..40
-    STRUCT_KW@20..26 "struct"
-    NAME@26..29
-      IDENT@26..29 "Bar"
-    RECORD_FIELD_LIST@29..40
-      L_CURLY@29..30 "{"
-      RECORD_FIELD@30..39
-        NAME@30..35
-          IDENT@30..35 "field"
-        COLON@35..36 ":"
-        PATH_TYPE@36..39
-          PATH@36..39
-            PATH_SEGMENT@36..39
-              NAME_REF@36..39
-                IDENT@36..39 "u32"
-      R_CURLY@39..40 "}""#
-            .trim()
-    );
-}
-
-fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree {
-    if let tt::TokenTree::Subtree(subtree) = tt {
-        return &subtree;
-    }
-    unreachable!("It is not a subtree");
-}
-fn to_literal(tt: &tt::TokenTree) -> &tt::Literal {
-    if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = tt {
-        return lit;
-    }
-    unreachable!("It is not a literal");
-}
-
-fn to_punct(tt: &tt::TokenTree) -> &tt::Punct {
-    if let tt::TokenTree::Leaf(tt::Leaf::Punct(lit)) = tt {
-        return lit;
-    }
-    unreachable!("It is not a Punct");
-}
-
-#[test]
-fn test_expand_literals_to_token_tree() {
-    let expansion = parse_macro(
-        r#"
-            macro_rules! literals {
-                ($i:ident) => {
-                    {
-                        let a = 'c';
-                        let c = 1000;
-                        let f = 12E+99_f64;
-                        let s = "rust1";
-                    }
-                }
-            }
-            "#,
-    )
-    .expand_tt("literals!(foo);");
-    let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees;
-
-    // [let] [a] [=] ['c'] [;]
-    assert_eq!(to_literal(&stm_tokens[3]).text, "'c'");
-    // [let] [c] [=] [1000] [;]
-    assert_eq!(to_literal(&stm_tokens[5 + 3]).text, "1000");
-    // [let] [f] [=] [12E+99_f64] [;]
-    assert_eq!(to_literal(&stm_tokens[10 + 3]).text, "12E+99_f64");
-    // [let] [s] [=] ["rust1"] [;]
-    assert_eq!(to_literal(&stm_tokens[15 + 3]).text, "\"rust1\"");
-}
-
-#[test]
-fn test_attr_to_token_tree() {
-    let expansion = parse_to_token_tree_by_syntax(
-        r#"
-            #[derive(Copy)]
-            struct Foo;
-            "#,
-    );
-
-    assert_eq!(to_punct(&expansion.token_trees[0]).char, '#');
-    assert_eq!(
-        to_subtree(&expansion.token_trees[1]).delimiter_kind(),
-        Some(tt::DelimiterKind::Bracket)
-    );
-}
-
-#[test]
-fn test_two_idents() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:ident, $ j:ident) => {
-                fn foo() { let a = $ i; let b = $j; }
-            }
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
-}
-
-#[test]
-fn test_tt_to_stmts() {
-    let stmts = parse_macro(
-        r#"
-        macro_rules! foo {
-            () => {
-                 let a = 0;
-                 a = 10 + 1;
-                 a
-            }
-        }
-"#,
-    )
-    .expand_statements("foo!{}");
-
-    assert_eq!(
-        format!("{:#?}", stmts).trim(),
-        r#"MACRO_STMTS@0..15
-  LET_STMT@0..7
-    LET_KW@0..3 "let"
-    IDENT_PAT@3..4
-      NAME@3..4
-        IDENT@3..4 "a"
-    EQ@4..5 "="
-    LITERAL@5..6
-      INT_NUMBER@5..6 "0"
-    SEMICOLON@6..7 ";"
-  EXPR_STMT@7..14
-    BIN_EXPR@7..13
-      PATH_EXPR@7..8
-        PATH@7..8
-          PATH_SEGMENT@7..8
-            NAME_REF@7..8
-              IDENT@7..8 "a"
-      EQ@8..9 "="
-      BIN_EXPR@9..13
-        LITERAL@9..11
-          INT_NUMBER@9..11 "10"
-        PLUS@11..12 "+"
-        LITERAL@12..13
-          INT_NUMBER@12..13 "1"
-    SEMICOLON@13..14 ";"
-  PATH_EXPR@14..15
-    PATH@14..15
-      PATH_SEGMENT@14..15
-        NAME_REF@14..15
-          IDENT@14..15 "a""#,
-    );
-}
-
-#[test]
-fn test_match_literal() {
-    parse_macro(
-        r#"
-    macro_rules! foo {
-        ('(') => {
-            fn foo() {}
-        }
-    }
-"#,
-    )
-    .assert_expand_items("foo! ['('];", "fn foo () {}");
-}
-
-#[test]
-fn test_parse_macro_def_simple() {
-    cov_mark::check!(parse_macro_def_simple);
-
-    parse_macro2(
-        r#"
-macro foo($id:ident) {
-    fn $id() {}
-}
-"#,
-    )
-    .assert_expand_items("foo!(bar);", "fn bar () {}");
-}
-
-#[test]
-fn test_parse_macro_def_rules() {
-    cov_mark::check!(parse_macro_def_rules);
-
-    parse_macro2(
-        r#"
-macro foo {
-    ($id:ident) => {
-        fn $id() {}
-    }
-}
-"#,
-    )
-    .assert_expand_items("foo!(bar);", "fn bar () {}");
-}
-
-// The following tests are port from intellij-rust directly
-// https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
-
-#[test]
-fn test_path() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:path) => {
-                fn foo() { let a = $ i; }
-            }
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo }", "fn foo () {let a = foo ;}")
-    .assert_expand_items(
-        "foo! { bar::<u8>::baz::<u8> }",
-        "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}",
-    );
-}
-
-#[test]
-fn test_two_paths() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:path, $ j:path) => {
-                fn foo() { let a = $ i; let b = $j; }
-            }
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
-}
-
-#[test]
-fn test_path_with_path() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:path) => {
-                fn foo() { let a = $ i :: bar; }
-            }
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo }", "fn foo () {let a = foo :: bar ;}");
-}
-
-#[test]
-fn test_expr() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:expr) => {
-                 fn bar() { $ i; }
-            }
-        }
-"#,
-    )
-    .assert_expand_items(
-        "foo! { 2 + 2 * baz(3).quux() }",
-        "fn bar () {2 + 2 * baz (3) . quux () ;}",
-    );
-}
-
-#[test]
-fn test_last_expr() {
-    parse_macro(
-        r#"
-        macro_rules! vec {
-            ($($item:expr),*) => {
-                {
-                    let mut v = Vec::new();
-                    $(
-                        v.push($item);
-                    )*
-                    v
-                }
-            };
-        }
-"#,
-    )
-    .assert_expand_items(
-        "vec!(1,2,3);",
-        "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}",
-    );
-}
-
-#[test]
-fn test_expr_with_attr() {
-    parse_macro(
-        r#"
-macro_rules! m {
-    ($a:expr) => {0}
-}
-"#,
-    )
-    .assert_expand_items("m!(#[allow(a)]())", "0");
-}
-
-#[test]
-fn test_ty() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:ty) => (
-                fn bar() -> $ i { unimplemented!() }
-            )
-        }
-"#,
-    )
-    .assert_expand_items("foo! { Baz<u8> }", "fn bar () -> Baz < u8 > {unimplemented ! ()}");
-}
-
-#[test]
-fn test_ty_with_complex_type() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:ty) => (
-                fn bar() -> $ i { unimplemented!() }
-            )
-        }
-"#,
-    )
-    // Reference lifetime struct with generic type
-    .assert_expand_items(
-        "foo! { &'a Baz<u8> }",
-        "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}",
-    )
-    // extern "Rust" func type
-    .assert_expand_items(
-        r#"foo! { extern "Rust" fn() -> Ret }"#,
-        r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#,
-    );
-}
-
-#[test]
-fn test_pat_() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:pat) => { fn foo() { let $ i; } }
-        }
-"#,
-    )
-    .assert_expand_items("foo! { (a, b) }", "fn foo () {let (a , b) ;}");
-}
-
-#[test]
-fn test_stmt() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:stmt) => (
-                fn bar() { $ i; }
-            )
-        }
-"#,
-    )
-    .assert_expand_items("foo! { 2 }", "fn bar () {2 ;}")
-    .assert_expand_items("foo! { let a = 0 }", "fn bar () {let a = 0 ;}");
-}
-
-#[test]
-fn test_single_item() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:item) => (
-                $ i
-            )
-        }
-"#,
-    )
-    .assert_expand_items("foo! {mod c {}}", "mod c {}");
-}
-
-#[test]
-fn test_all_items() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:item)*) => ($ (
-                $ i
-            )*)
-        }
-"#,
-    ).
-    assert_expand_items(
-        r#"
-        foo! {
-            extern crate a;
-            mod b;
-            mod c {}
-            use d;
-            const E: i32 = 0;
-            static F: i32 = 0;
-            impl G {}
-            struct H;
-            enum I { Foo }
-            trait J {}
-            fn h() {}
-            extern {}
-            type T = u8;
-        }
-"#,
-        r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#,
-    );
-}
-
-#[test]
-fn test_block() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:block) => { fn foo() $ i }
-        }
-"#,
-    )
-    .assert_expand_statements("foo! { { 1; } }", "fn foo () {1 ;}");
-}
-
-#[test]
-fn test_meta() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:meta) => (
-                #[$ i]
-                fn bar() {}
-            )
-        }
-"#,
-    )
-    .assert_expand_items(
-        r#"foo! { cfg(target_os = "windows") }"#,
-        r#"# [cfg (target_os = "windows")] fn bar () {}"#,
-    )
-    .assert_expand_items(r#"foo! { hello::world }"#, r#"# [hello :: world] fn bar () {}"#);
-}
-
-#[test]
-fn test_meta_doc_comments() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($(#[$ i:meta])+) => (
-                $(#[$ i])+
-                fn bar() {}
-            )
-        }
-"#,
-    ).
-    assert_expand_items(
-        r#"foo! {
-            /// Single Line Doc 1
-            /**
-                MultiLines Doc
-            */
-        }"#,
-        "# [doc = \" Single Line Doc 1\"] # [doc = \"\\\\n                MultiLines Doc\\\\n            \"] fn bar () {}",
-    );
-}
-
-#[test]
-fn test_meta_doc_comments_non_latin() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($(#[$ i:meta])+) => (
-                $(#[$ i])+
-                fn bar() {}
-            )
-        }
-"#,
-    ).
-    assert_expand_items(
-        r#"foo! {
-            /// 錦瑟無端五十弦，一弦一柱思華年。
-            /**
-                莊生曉夢迷蝴蝶，望帝春心託杜鵑。
-            */
-        }"#,
-        "# [doc = \" 錦瑟無端五十弦，一弦一柱思華年。\"] # [doc = \"\\\\n                莊生曉夢迷蝴蝶，望帝春心託杜鵑。\\\\n            \"] fn bar () {}",
-    );
-}
-
-#[test]
-fn test_tt_block() {
-    parse_macro(
-        r#"
-            macro_rules! foo {
-                ($ i:tt) => { fn foo() $ i }
-            }
-    "#,
-    )
-    .assert_expand_items(r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#);
-}
-
-#[test]
-fn test_tt_group() {
-    parse_macro(
-        r#"
-            macro_rules! foo {
-                 ($($ i:tt)*) => { $($ i)* }
-            }
-    "#,
-    )
-    .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#);
-}
-
-#[test]
-fn test_tt_composite() {
-    parse_macro(
-        r#"
-            macro_rules! foo {
-                 ($i:tt) => { 0 }
-            }
-    "#,
-    )
-    .assert_expand_items(r#"foo! { => }"#, r#"0"#);
-}
-
-#[test]
-fn test_tt_composite2() {
-    let node = parse_macro(
-        r#"
-            macro_rules! foo {
-                ($($tt:tt)*) => { abs!(=> $($tt)*) }
-            }
-    "#,
-    )
-    .expand_items(r#"foo!{#}"#);
-
-    let res = format!("{:#?}", &node);
-    assert_eq_text!(
-        r###"MACRO_ITEMS@0..10
-  MACRO_CALL@0..10
-    PATH@0..3
-      PATH_SEGMENT@0..3
-        NAME_REF@0..3
-          IDENT@0..3 "abs"
-    BANG@3..4 "!"
-    TOKEN_TREE@4..10
-      L_PAREN@4..5 "("
-      EQ@5..6 "="
-      R_ANGLE@6..7 ">"
-      WHITESPACE@7..8 " "
-      POUND@8..9 "#"
-      R_PAREN@9..10 ")""###,
-        res.trim()
-    );
-}
-
-#[test]
-fn test_tt_with_composite_without_space() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ op:tt, $j:path) => (
-                0
-            )
-        }
-"#,
-    )
-    // Test macro input without any spaces
-    // See https://github.com/rust-analyzer/rust-analyzer/issues/6692
-    .assert_expand_items("foo!(==,Foo::Bool)", "0");
-}
-
-#[test]
-fn test_underscore() {
-    parse_macro(
-        r#"
-            macro_rules! foo {
-                 ($_:tt) => { 0 }
-            }
-    "#,
-    )
-    .assert_expand_items(r#"foo! { => }"#, r#"0"#);
-}
-
-#[test]
-fn test_underscore_not_greedily() {
-    parse_macro(
-        r#"
-macro_rules! q {
-    ($($a:ident)* _) => {0};
-}
-"#,
-    )
-    // `_` overlaps with `$a:ident` but rustc matches it under the `_` token
-    .assert_expand_items(r#"q![a b c d _]"#, r#"0"#);
-
-    parse_macro(
-        r#"
-macro_rules! q {
-    ($($a:expr => $b:ident)* _ => $c:expr) => {0};
-}
-"#,
-    )
-    // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`
-    .assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#);
-}
-
-#[test]
-fn test_underscore_as_type() {
-    parse_macro(
-        r#"
-macro_rules! q {
-    ($a:ty) => {0};
-}
-"#,
-    )
-    // Underscore is a type
-    .assert_expand_items(r#"q![_]"#, r#"0"#);
-}
-
-#[test]
-fn test_vertical_bar_with_pat() {
-    parse_macro(
-        r#"
-            macro_rules! foo {
-                 (| $pat:pat | ) => { 0 }
-            }
-    "#,
-    )
-    .assert_expand_items(r#"foo! { | x | }"#, r#"0"#);
-}
-
-#[test]
-fn test_dollar_crate_lhs_is_not_meta() {
-    parse_macro(
-        r#"
-macro_rules! foo {
-    ($crate) => {};
-    () => {0};
-}
-    "#,
-    )
-    .assert_expand_items(r#"foo!{}"#, r#"0"#);
-}
-
-#[test]
-fn test_lifetime() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-              ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } }
-        }
-"#,
-    )
-    .assert_expand_items(r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#);
-}
-
-#[test]
-fn test_literal() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-              ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;};
-        }
-"#,
-    )
-    .assert_expand_items(r#"foo!(u8,0);"#, r#"const VALUE : u8 = 0 ;"#);
-
-    parse_macro(
-        r#"
-        macro_rules! foo {
-              ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;};
-        }
-"#,
-    )
-    .assert_expand_items(r#"foo!(i32,-1);"#, r#"const VALUE : i32 = - 1 ;"#);
-}
-
-#[test]
-fn test_boolean_is_ident() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-              ($lit0:literal, $lit1:literal) => { const VALUE: (bool,bool) = ($lit0,$lit1); };
-        }
-"#,
-    )
-    .assert_expand(
-        r#"foo!(true,false);"#,
-        r#"
-SUBTREE $
-  IDENT   const 14
-  IDENT   VALUE 15
-  PUNCH   : [alone] 16
-  SUBTREE () 17
-    IDENT   bool 18
-    PUNCH   , [alone] 19
-    IDENT   bool 20
-  PUNCH   = [alone] 21
-  SUBTREE () 22
-    IDENT   true 29
-    PUNCH   , [joint] 25
-    IDENT   false 31
-  PUNCH   ; [alone] 28
-"#,
-    );
-}
-
-#[test]
-fn test_vis() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-              ($ vis:vis $ name:ident) => { $ vis fn $ name() {}};
-        }
-"#,
-    )
-    .assert_expand_items(r#"foo!(pub foo);"#, r#"pub fn foo () {}"#)
-    // test optional cases
-    .assert_expand_items(r#"foo!(foo);"#, r#"fn foo () {}"#);
-}
-
-#[test]
-fn test_inner_macro_rules() {
-    parse_macro(
-        r#"
-macro_rules! foo {
-    ($a:ident, $b:ident, $c:tt) => {
-
-        macro_rules! bar {
-            ($bi:ident) => {
-                fn $bi() -> u8 {$c}
-            }
-        }
-
-        bar!($a);
-        fn $b() -> u8 {$c}
-    }
-}
-"#,
-    ).
-    assert_expand_items(
-        r#"foo!(x,y, 1);"#,
-        r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#,
-    );
-}
-
-#[test]
-fn test_expr_after_path_colons() {
-    assert!(parse_macro(
-        r#"
-macro_rules! m {
-    ($k:expr) => {
-            f(K::$k);
-       }
-}
-"#,
-    )
-    .expand_statements(r#"m!(C("0"))"#)
-    .descendants()
-    .find(|token| token.kind() == ERROR)
-    .is_some());
-}
-
-#[test]
-fn test_match_is_not_greedy() {
-    parse_macro(
-        r#"
-macro_rules! foo {
-    ($($i:ident $(,)*),*) => {};
-}
-"#,
-    )
-    .assert_expand_items(r#"foo!(a,b);"#, r#""#);
-}
-
-// The following tests are based on real world situations
-#[test]
-fn test_vec() {
-    let fixture = parse_macro(
-        r#"
-         macro_rules! vec {
-            ($($item:expr),*) => {
-                {
-                    let mut v = Vec::new();
-                    $(
-                        v.push($item);
-                    )*
-                    v
-                }
-            };
-}
-"#,
-    );
-    fixture
-        .assert_expand_items(r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#)
-        .assert_expand_items(
-            r#"vec![1u32,2];"#,
-            r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#,
-        );
-
-    let tree = fixture.expand_expr(r#"vec![1u32,2];"#);
-
-    assert_eq!(
-        format!("{:#?}", tree).trim(),
-        r#"BLOCK_EXPR@0..45
-  L_CURLY@0..1 "{"
-  LET_STMT@1..20
-    LET_KW@1..4 "let"
-    IDENT_PAT@4..8
-      MUT_KW@4..7 "mut"
-      NAME@7..8
-        IDENT@7..8 "v"
-    EQ@8..9 "="
-    CALL_EXPR@9..19
-      PATH_EXPR@9..17
-        PATH@9..17
-          PATH@9..12
-            PATH_SEGMENT@9..12
-              NAME_REF@9..12
-                IDENT@9..12 "Vec"
-          COLON2@12..14 "::"
-          PATH_SEGMENT@14..17
-            NAME_REF@14..17
-              IDENT@14..17 "new"
-      ARG_LIST@17..19
-        L_PAREN@17..18 "("
-        R_PAREN@18..19 ")"
-    SEMICOLON@19..20 ";"
-  EXPR_STMT@20..33
-    METHOD_CALL_EXPR@20..32
-      PATH_EXPR@20..21
-        PATH@20..21
-          PATH_SEGMENT@20..21
-            NAME_REF@20..21
-              IDENT@20..21 "v"
-      DOT@21..22 "."
-      NAME_REF@22..26
-        IDENT@22..26 "push"
-      ARG_LIST@26..32
-        L_PAREN@26..27 "("
-        LITERAL@27..31
-          INT_NUMBER@27..31 "1u32"
-        R_PAREN@31..32 ")"
-    SEMICOLON@32..33 ";"
-  EXPR_STMT@33..43
-    METHOD_CALL_EXPR@33..42
-      PATH_EXPR@33..34
-        PATH@33..34
-          PATH_SEGMENT@33..34
-            NAME_REF@33..34
-              IDENT@33..34 "v"
-      DOT@34..35 "."
-      NAME_REF@35..39
-        IDENT@35..39 "push"
-      ARG_LIST@39..42
-        L_PAREN@39..40 "("
-        LITERAL@40..41
-          INT_NUMBER@40..41 "2"
-        R_PAREN@41..42 ")"
-    SEMICOLON@42..43 ";"
-  PATH_EXPR@43..44
-    PATH@43..44
-      PATH_SEGMENT@43..44
-        NAME_REF@43..44
-          IDENT@43..44 "v"
-  R_CURLY@44..45 "}""#
-    );
-}
-
-#[test]
-fn test_winapi_struct() {
-    // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366
-
-    parse_macro(
-        r#"
-macro_rules! STRUCT {
-    ($(#[$attrs:meta])* struct $name:ident {
-        $($field:ident: $ftype:ty,)+
-    }) => (
-        #[repr(C)] #[derive(Copy)] $(#[$attrs])*
-        pub struct $name {
-            $(pub $field: $ftype,)+
-        }
-        impl Clone for $name {
-            #[inline]
-            fn clone(&self) -> $name { *self }
-        }
-        #[cfg(feature = "impl-default")]
-        impl Default for $name {
-            #[inline]
-            fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } }
-        }
-    );
-}
-"#,
-    ).
-    // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs
-    assert_expand_items(r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#,
-        "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
-    )
-    .assert_expand_items(r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#,
-        "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
-    );
-}
-
-#[test]
-fn test_int_base() {
-    parse_macro(
-        r#"
-macro_rules! int_base {
-    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl fmt::$Trait for $T {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                $Radix.fmt_int(*self as $U, f)
-            }
-        }
-    }
-}
-"#,
-    ).assert_expand_items(r#" int_base!{Binary for isize as usize -> Binary}"#,
-        "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
-    );
-}
-
-#[test]
-fn test_generate_pattern_iterators() {
-    // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs
-    parse_macro(
-        r#"
-macro_rules! generate_pattern_iterators {
-        { double ended; with $(#[$common_stability_attribute:meta])*,
-                           $forward_iterator:ident,
-                           $reverse_iterator:ident, $iterty:ty
-        } => {
-            fn foo(){}
-        }
-}
-"#,
-    ).assert_expand_items(
-        r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#,
-        "fn foo () {}",
-    );
-}
-
-#[test]
-fn test_impl_fn_for_zst() {
-    // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs
-    parse_macro(
-        r#"
-macro_rules! impl_fn_for_zst  {
-        {  $( $( #[$attr: meta] )*
-        struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
-            |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
-$body: block; )+
-        } => {
-           $(
-            $( #[$attr] )*
-            struct $Name;
-
-            impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
-                #[inline]
-                extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
-                    $body
-                }
-            }
-
-            impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
-                #[inline]
-                extern "rust-call" fn call_mut(
-                    &mut self,
-                    ($( $arg, )*): ($( $ArgTy, )*)
-                ) -> $ReturnTy {
-                    Fn::call(&*self, ($( $arg, )*))
-                }
-            }
-
-            impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
-                type Output = $ReturnTy;
-
-                #[inline]
-                extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
-                    Fn::call(&self, ($( $arg, )*))
-                }
-            }
-        )+
-}
-        }
-"#,
-    ).assert_expand_items(r#"
-impl_fn_for_zst !   {
-     # [ derive ( Clone ) ]
-     struct   CharEscapeDebugContinue   impl   Fn   =   | c :   char |   ->   char :: EscapeDebug   {
-         c . escape_debug_ext ( false )
-     } ;
-
-     # [ derive ( Clone ) ]
-     struct   CharEscapeUnicode   impl   Fn   =   | c :   char |   ->   char :: EscapeUnicode   {
-         c . escape_unicode ( )
-     } ;
-     # [ derive ( Clone ) ]
-     struct   CharEscapeDefault   impl   Fn   =   | c :   char |   ->   char :: EscapeDefault   {
-         c . escape_default ( )
-     } ;
- }
-"#,
-        "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"
-    );
-}
-
-#[test]
-fn test_impl_nonzero_fmt() {
-    // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
-    parse_macro(
-        r#"
-        macro_rules! impl_nonzero_fmt {
-            ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
-                fn foo () {}
-            }
-        }
-"#,
-    ).assert_expand_items(
-        r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#,
-        "fn foo () {}",
-    );
-}
-
-#[test]
-fn test_cfg_if_items() {
-    // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986
-    parse_macro(
-        r#"
-        macro_rules! __cfg_if_items {
-            (($($not:meta,)*) ; ) => {};
-            (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
-                 __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
-            }
-        }
-"#,
-    ).assert_expand_items(
-        r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#,
-        "__cfg_if_items ! {(rustdoc ,) ;}",
-    );
-}
-
-#[test]
-fn test_cfg_if_main() {
-    // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9
-    parse_macro(
-        r#"
-        macro_rules! cfg_if {
-            ($(
-                if #[cfg($($meta:meta),*)] { $($it:item)* }
-            ) else * else {
-                $($it2:item)*
-            }) => {
-                __cfg_if_items! {
-                    () ;
-                    $( ( ($($meta),*) ($($it)*) ), )*
-                    ( () ($($it2)*) ),
-                }
-            };
-
-            // Internal macro to Apply a cfg attribute to a list of items
-            (@__apply $m:meta, $($it:item)*) => {
-                $(#[$m] $it)*
-            };
-        }
-"#,
-    ).assert_expand_items(r#"
-cfg_if !   {
-     if   # [ cfg ( target_env   =   "msvc" ) ]   {
-         // no extra unwinder support needed
-     }   else   if   # [ cfg ( all ( target_arch   =   "wasm32" ,   not ( target_os   =   "emscripten" ) ) ) ]   {
-         // no unwinder on the system!
-     }   else   {
-         mod   libunwind ;
-         pub   use   libunwind :: * ;
-     }
- }
-"#,
-        "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"
-    ).assert_expand_items(
-        r#"
-cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , }
-"#,
-        "",
-    );
-}
-
-#[test]
-fn test_proptest_arbitrary() {
-    // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16
-    parse_macro(
-        r#"
-macro_rules! arbitrary {
-    ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty;
-        $args: ident => $logic: expr) => {
-        impl<$($bounds)*> $crate::arbitrary::Arbitrary for $typ {
-            type Parameters = $params;
-            type Strategy = $strat;
-            fn arbitrary_with($args: Self::Parameters) -> Self::Strategy {
-                $logic
-            }
-        }
-    };
-
-}"#,
-    ).assert_expand_items(r#"arbitrary !   ( [ A : Arbitrary ]
-        Vec < A > ,
-        VecStrategy < A :: Strategy > ,
-        RangedParams1 < A :: Parameters > ;
-        args =>   { let product_unpack !   [ range , a ] = args ; vec ( any_with :: < A >   ( a ) , range ) }
-    ) ;"#,
-    "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}"
-    );
-}
-
-#[test]
-fn test_old_ridl() {
-    // This is from winapi 2.8, which do not have a link from github
-    //
-    let expanded = parse_macro(
-        r#"
-#[macro_export]
-macro_rules! RIDL {
-    (interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident)
-        {$(
-            fn $method:ident(&mut self $(,$p:ident : $t:ty)*) -> $rtr:ty
-        ),+}
-    ) => {
-        impl $interface {
-            $(pub unsafe fn $method(&mut self) -> $rtr {
-                ((*self.lpVtbl).$method)(self $(,$p)*)
-            })+
-        }
-    };
-}"#,
-    ).expand_tt(r#"
-    RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
-        fn GetDataSize(&mut self) -> UINT
-    }}"#);
-
-    assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}");
-}
-
-#[test]
-fn test_quick_error() {
-    let expanded = parse_macro(
-        r#"
-macro_rules! quick_error {
-
- (SORT [enum $name:ident $( #[$meta:meta] )*]
-        items [$($( #[$imeta:meta] )*
-                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
-                                {$( $ifuncs:tt )*} )* ]
-        buf [ ]
-        queue [ ]
-    ) => {
-        quick_error!(ENUMINITION [enum $name $( #[$meta] )*]
-            body []
-            queue [$(
-                $( #[$imeta] )*
-                =>
-                $iitem: $imode [$( $ivar: $ityp ),*]
-            )*]
-        );
-};
-
-}
-"#,
-    )
-    .expand_tt(
-        r#"
-quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
-        => One : UNIT [] {}
-        => Two : TUPLE [s :String] {display ("two: {}" , s) from ()}
-    ] buf [] queue []) ;
-"#,
-    );
-
-    assert_eq!(expanded.to_string(), "quick_error ! (ENUMINITION [enum Wrapped # [derive (Debug)]] body [] queue [=> One : UNIT [] => Two : TUPLE [s : String]]) ;");
-}
-
-#[test]
-fn test_empty_repeat_vars_in_empty_repeat_vars() {
-    parse_macro(
-        r#"
-macro_rules! delegate_impl {
-    ([$self_type:ident, $self_wrap:ty, $self_map:ident]
-     pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
-
-        // "Escaped" associated types. Stripped before making the `trait`
-        // itself, but forwarded when delegating impls.
-        $(
-        @escape [type $assoc_name_ext:ident]
-        // Associated types. Forwarded.
-        )*
-        $(
-        @section type
-        $(
-            $(#[$_assoc_attr:meta])*
-            type $assoc_name:ident $(: $assoc_bound:ty)*;
-        )+
-        )*
-        // Methods. Forwarded. Using $self_map!(self) around the self argument.
-        // Methods must use receiver `self` or explicit type like `self: &Self`
-        // &self and &mut self are _not_ supported.
-        $(
-        @section self
-        $(
-            $(#[$_method_attr:meta])*
-            fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) -> $mret:ty;
-        )+
-        )*
-        // Arbitrary tail that is ignored when forwarding.
-        $(
-        @section nodelegate
-        $($tail:tt)*
-        )*
-    }) => {
-        impl<> $name for $self_wrap where $self_type: $name {
-            $(
-            $(
-                fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) -> $mret {
-                    $self_map!(self).$method_name($($marg),*)
-                }
-            )*
-            )*
-        }
-    }
-}
-"#,
-    ).assert_expand_items(
-        r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#,
-        "impl <> Data for & \'a mut G where G : Data {}",
-    );
-}
-
-#[test]
-fn expr_interpolation() {
-    let expanded = parse_macro(
-        r#"
-        macro_rules! id {
-            ($expr:expr) => {
-                map($expr)
-            }
-        }
-        "#,
-    )
-    .expand_expr("id!(x + foo);");
-
-    assert_eq!(expanded.to_string(), "map(x+foo)");
-}
-
 pub(crate) struct MacroFixture {
     rules: MacroRules,
 }
@@ -1889,6 +128,37 @@ macro_rules! impl_fixture {
 impl_fixture!(MacroFixture);
 impl_fixture!(MacroFixture2);
 
+pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture {
+    let definition_tt = parse_macro_rules_to_tt(ra_fixture);
+    let rules = MacroRules::parse(&definition_tt).unwrap();
+    MacroFixture { rules }
+}
+
+pub(crate) fn parse_macro2(ra_fixture: &str) -> MacroFixture2 {
+    let definition_tt = parse_macro_def_to_tt(ra_fixture);
+    let rules = MacroDef::parse(&definition_tt).unwrap();
+    MacroFixture2 { rules }
+}
+
+pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError {
+    let definition_tt = parse_macro_rules_to_tt(ra_fixture);
+
+    match MacroRules::parse(&definition_tt) {
+        Ok(_) => panic!("Expect error"),
+        Err(err) => err,
+    }
+}
+
+pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree {
+    let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
+    let tt = syntax_node_to_token_tree(source_file.syntax()).unwrap().0;
+
+    let parsed = parse_to_token_tree(ra_fixture).unwrap().0;
+    assert_eq!(tt, parsed);
+
+    parsed
+}
+
 fn parse_macro_rules_to_tt(ra_fixture: &str) -> tt::Subtree {
     let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
     let macro_definition =
@@ -1922,37 +192,6 @@ fn parse_macro_def_to_tt(ra_fixture: &str) -> tt::Subtree {
     definition_tt
 }
 
-pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture {
-    let definition_tt = parse_macro_rules_to_tt(ra_fixture);
-    let rules = MacroRules::parse(&definition_tt).unwrap();
-    MacroFixture { rules }
-}
-
-pub(crate) fn parse_macro2(ra_fixture: &str) -> MacroFixture2 {
-    let definition_tt = parse_macro_def_to_tt(ra_fixture);
-    let rules = MacroDef::parse(&definition_tt).unwrap();
-    MacroFixture2 { rules }
-}
-
-pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError {
-    let definition_tt = parse_macro_rules_to_tt(ra_fixture);
-
-    match MacroRules::parse(&definition_tt) {
-        Ok(_) => panic!("Expect error"),
-        Err(err) => err,
-    }
-}
-
-pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree {
-    let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
-    let tt = syntax_node_to_token_tree(source_file.syntax()).unwrap().0;
-
-    let parsed = parse_to_token_tree(ra_fixture).unwrap().0;
-    assert_eq!(tt, parsed);
-
-    parsed
-}
-
 fn debug_dump_ignore_spaces(node: &syntax::SyntaxNode) -> String {
     let mut level = 0;
     let mut buf = String::new();
@@ -1988,166 +227,3 @@ fn debug_dump_ignore_spaces(node: &syntax::SyntaxNode) -> String {
 
     buf
 }
-
-#[test]
-fn test_issue_2520() {
-    let macro_fixture = parse_macro(
-        r#"
-        macro_rules! my_macro {
-            {
-                ( $(
-                    $( [] $sname:ident : $stype:ty  )?
-                    $( [$expr:expr] $nname:ident : $ntype:ty  )?
-                ),* )
-            } => {
-                Test {
-                    $(
-                        $( $sname, )?
-                    )*
-                }
-            };
-        }
-    "#,
-    );
-
-    macro_fixture.assert_expand_items(
-        r#"my_macro ! {
-            ([] p1 : u32 , [|_| S0K0] s : S0K0 , [] k0 : i32)
-        }"#,
-        "Test {p1 , k0 ,}",
-    );
-}
-
-#[test]
-fn test_issue_3861() {
-    let macro_fixture = parse_macro(
-        r#"
-        macro_rules! rgb_color {
-            ($p:expr, $t: ty) => {
-                pub fn new() {
-                    let _ = 0 as $t << $p;
-                }
-            };
-        }
-    "#,
-    );
-
-    macro_fixture.expand_items(r#"rgb_color!(8 + 8, u32);"#);
-}
-
-#[test]
-fn test_repeat_bad_var() {
-    // FIXME: the second rule of the macro should be removed and an error about
-    // `$( $c )+` raised
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($( $b:ident )+) => {
-                $( $c )+
-            };
-            ($( $b:ident )+) => {
-                $( $b )+
-            }
-        }
-    "#,
-    )
-    .assert_expand_items("foo!(b0 b1);", "b0 b1");
-}
-
-#[test]
-fn test_no_space_after_semi_colon() {
-    let expanded = parse_macro(
-        r#"
-        macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) }
-    "#,
-    )
-    .expand_items(r#"with_std! {mod m;mod f;}"#);
-
-    let dump = format!("{:#?}", expanded);
-    assert_eq_text!(
-        r###"MACRO_ITEMS@0..52
-  MODULE@0..26
-    ATTR@0..21
-      POUND@0..1 "#"
-      L_BRACK@1..2 "["
-      PATH@2..5
-        PATH_SEGMENT@2..5
-          NAME_REF@2..5
-            IDENT@2..5 "cfg"
-      TOKEN_TREE@5..20
-        L_PAREN@5..6 "("
-        IDENT@6..13 "feature"
-        EQ@13..14 "="
-        STRING@14..19 "\"std\""
-        R_PAREN@19..20 ")"
-      R_BRACK@20..21 "]"
-    MOD_KW@21..24 "mod"
-    NAME@24..25
-      IDENT@24..25 "m"
-    SEMICOLON@25..26 ";"
-  MODULE@26..52
-    ATTR@26..47
-      POUND@26..27 "#"
-      L_BRACK@27..28 "["
-      PATH@28..31
-        PATH_SEGMENT@28..31
-          NAME_REF@28..31
-            IDENT@28..31 "cfg"
-      TOKEN_TREE@31..46
-        L_PAREN@31..32 "("
-        IDENT@32..39 "feature"
-        EQ@39..40 "="
-        STRING@40..45 "\"std\""
-        R_PAREN@45..46 ")"
-      R_BRACK@46..47 "]"
-    MOD_KW@47..50 "mod"
-    NAME@50..51
-      IDENT@50..51 "f"
-    SEMICOLON@51..52 ";""###,
-        dump.trim()
-    );
-}
-
-// https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57597.rs
-#[test]
-fn test_rustc_issue_57597() {
-    fn test_error(fixture: &str) {
-        assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmptyTokenTree);
-    }
-
-    test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }");
-    test_error("macro_rules! foo { ($($($i:ident)?)*) => {}; }");
-    test_error("macro_rules! foo { ($($($i:ident)?)?) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)?)?)?) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)*)?)?) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)?)*)?) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)?)?)*) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)*)*)?) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)?)*)*) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)?)*)+) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)+)?)*) => {}; }");
-    test_error("macro_rules! foo { ($($($($i:ident)+)*)?) => {}; }");
-}
-
-#[test]
-fn test_expand_bad_literal() {
-    parse_macro(
-        r#"
-        macro_rules! foo { ($i:literal) => {}; }
-    "#,
-    )
-    .assert_expand_err(r#"foo!(&k");"#, &ExpandError::BindingError("".into()));
-}
-
-#[test]
-fn test_empty_comments() {
-    parse_macro(
-        r#"
-        macro_rules! one_arg_macro { ($fmt:expr) => (); }
-    "#,
-    )
-    .assert_expand_err(
-        r#"one_arg_macro!(/**/)"#,
-        &ExpandError::BindingError("expected Expr".into()),
-    );
-}
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs
new file mode 100644
index 0000000000..9dd8ff75bc
--- /dev/null
+++ b/crates/mbe/src/tests/expand.rs
@@ -0,0 +1,1872 @@
+use ::parser::FragmentKind;
+use syntax::{
+    SyntaxKind::{ERROR, IDENT},
+    T,
+};
+use test_utils::assert_eq_text;
+
+use super::*;
+
+// Good first issue (although a slightly challenging one):
+//
+// * Pick a random test from here
+//   https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
+// * Port the test to rust and add it to this module
+// * Make it pass :-)
+
+#[test]
+fn test_token_id_shift() {
+    let expansion = parse_macro(
+        r#"
+macro_rules! foobar {
+    ($e:ident) => { foo bar $e }
+}
+"#,
+    )
+    .expand_tt("foobar!(baz);");
+
+    fn get_id(t: &tt::TokenTree) -> Option<u32> {
+        if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t {
+            return Some(ident.id.0);
+        }
+        None
+    }
+
+    assert_eq!(expansion.token_trees.len(), 3);
+    // {($e:ident) => { foo bar $e }}
+    // 012345      67 8 9   T   12
+    assert_eq!(get_id(&expansion.token_trees[0]), Some(9));
+    assert_eq!(get_id(&expansion.token_trees[1]), Some(10));
+
+    // The input args of macro call include parentheses:
+    // (baz)
+    // So baz should be 12+1+1
+    assert_eq!(get_id(&expansion.token_trees[2]), Some(14));
+}
+
+#[test]
+fn test_token_map() {
+    let expanded = parse_macro(
+        r#"
+macro_rules! foobar {
+    ($e:ident) => { fn $e() {} }
+}
+"#,
+    )
+    .expand_tt("foobar!(baz);");
+
+    let (node, token_map) = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap();
+    let content = node.syntax_node().to_string();
+
+    let get_text = |id, kind| -> String {
+        content[token_map.range_by_token(id).unwrap().by_kind(kind).unwrap()].to_string()
+    };
+
+    assert_eq!(expanded.token_trees.len(), 4);
+    // {($e:ident) => { fn $e() {} }}
+    // 012345      67 8 9  T12  3
+
+    assert_eq!(get_text(tt::TokenId(9), IDENT), "fn");
+    assert_eq!(get_text(tt::TokenId(12), T!['(']), "(");
+    assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
+}
+
+#[test]
+fn test_convert_tt() {
+    parse_macro(r#"
+macro_rules! impl_froms {
+    ($e:ident: $($v:ident),*) => {
+        $(
+            impl From<$v> for $e {
+                fn from(it: $v) -> $e {
+                    $e::$v(it)
+                }
+            }
+        )*
+    }
+}
+"#)
+        .assert_expand_tt(
+            "impl_froms!(TokenTree: Leaf, Subtree);",
+            "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
+             impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
+        );
+}
+
+#[test]
+fn test_convert_tt2() {
+    parse_macro(
+        r#"
+macro_rules! impl_froms {
+    ($e:ident: $($v:ident),*) => {
+        $(
+            impl From<$v> for $e {
+                fn from(it: $v) -> $e {
+                    $e::$v(it)
+                }
+            }
+        )*
+    }
+}
+"#,
+    )
+    .assert_expand(
+        "impl_froms!(TokenTree: Leaf, Subtree);",
+        r#"
+SUBTREE $
+  IDENT   impl 20
+  IDENT   From 21
+  PUNCH   < [joint] 22
+  IDENT   Leaf 53
+  PUNCH   > [alone] 25
+  IDENT   for 26
+  IDENT   TokenTree 51
+  SUBTREE {} 29
+    IDENT   fn 30
+    IDENT   from 31
+    SUBTREE () 32
+      IDENT   it 33
+      PUNCH   : [alone] 34
+      IDENT   Leaf 53
+    PUNCH   - [joint] 37
+    PUNCH   > [alone] 38
+    IDENT   TokenTree 51
+    SUBTREE {} 41
+      IDENT   TokenTree 51
+      PUNCH   : [joint] 44
+      PUNCH   : [joint] 45
+      IDENT   Leaf 53
+      SUBTREE () 48
+        IDENT   it 49
+  IDENT   impl 20
+  IDENT   From 21
+  PUNCH   < [joint] 22
+  IDENT   Subtree 55
+  PUNCH   > [alone] 25
+  IDENT   for 26
+  IDENT   TokenTree 51
+  SUBTREE {} 29
+    IDENT   fn 30
+    IDENT   from 31
+    SUBTREE () 32
+      IDENT   it 33
+      PUNCH   : [alone] 34
+      IDENT   Subtree 55
+    PUNCH   - [joint] 37
+    PUNCH   > [alone] 38
+    IDENT   TokenTree 51
+    SUBTREE {} 41
+      IDENT   TokenTree 51
+      PUNCH   : [joint] 44
+      PUNCH   : [joint] 45
+      IDENT   Subtree 55
+      SUBTREE () 48
+        IDENT   it 49
+"#,
+    );
+}
+
+#[test]
+fn test_lifetime_split() {
+    parse_macro(
+        r#"
+macro_rules! foo {
+    ($($t:tt)*) => { $($t)*}
+}
+"#,
+    )
+    .assert_expand(
+        r#"foo!(static bar: &'static str = "hello";);"#,
+        r#"
+SUBTREE $
+  IDENT   static 17
+  IDENT   bar 18
+  PUNCH   : [alone] 19
+  PUNCH   & [alone] 20
+  PUNCH   ' [joint] 21
+  IDENT   static 22
+  IDENT   str 23
+  PUNCH   = [alone] 24
+  LITERAL "hello" 25
+  PUNCH   ; [joint] 26
+"#,
+    );
+}
+
+#[test]
+fn test_expr_order() {
+    let expanded = parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:expr) => {
+                 fn bar() { $ i * 2; }
+            }
+        }
+"#,
+    )
+    .expand_items("foo! { 1 + 1}");
+
+    let dump = format!("{:#?}", expanded);
+    assert_eq_text!(
+        r#"MACRO_ITEMS@0..15
+  FN@0..15
+    FN_KW@0..2 "fn"
+    NAME@2..5
+      IDENT@2..5 "bar"
+    PARAM_LIST@5..7
+      L_PAREN@5..6 "("
+      R_PAREN@6..7 ")"
+    BLOCK_EXPR@7..15
+      L_CURLY@7..8 "{"
+      EXPR_STMT@8..14
+        BIN_EXPR@8..13
+          BIN_EXPR@8..11
+            LITERAL@8..9
+              INT_NUMBER@8..9 "1"
+            PLUS@9..10 "+"
+            LITERAL@10..11
+              INT_NUMBER@10..11 "1"
+          STAR@11..12 "*"
+          LITERAL@12..13
+            INT_NUMBER@12..13 "2"
+        SEMICOLON@13..14 ";"
+      R_CURLY@14..15 "}""#,
+        dump.trim()
+    );
+}
+
+#[test]
+fn test_fail_match_pattern_by_first_token() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:ident) => (
+                mod $ i {}
+            );
+            (= $ i:ident) => (
+                fn $ i() {}
+            );
+            (+ $ i:ident) => (
+                struct $ i;
+            )
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo }", "mod foo {}")
+    .assert_expand_items("foo! { = bar }", "fn bar () {}")
+    .assert_expand_items("foo! { + Baz }", "struct Baz ;");
+}
+
+#[test]
+fn test_fail_match_pattern_by_last_token() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:ident) => (
+                mod $ i {}
+            );
+            ($ i:ident =) => (
+                fn $ i() {}
+            );
+            ($ i:ident +) => (
+                struct $ i;
+            )
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo }", "mod foo {}")
+    .assert_expand_items("foo! { bar = }", "fn bar () {}")
+    .assert_expand_items("foo! { Baz + }", "struct Baz ;");
+}
+
+#[test]
+fn test_fail_match_pattern_by_word_token() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:ident) => (
+                mod $ i {}
+            );
+            (spam $ i:ident) => (
+                fn $ i() {}
+            );
+            (eggs $ i:ident) => (
+                struct $ i;
+            )
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo }", "mod foo {}")
+    .assert_expand_items("foo! { spam bar }", "fn bar () {}")
+    .assert_expand_items("foo! { eggs Baz }", "struct Baz ;");
+}
+
+#[test]
+fn test_match_group_pattern_by_separator_token() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ ($ i:ident),*) => ($ (
+                mod $ i {}
+            )*);
+            ($ ($ i:ident)#*) => ($ (
+                fn $ i() {}
+            )*);
+            ($ i:ident ,# $ j:ident) => (
+                struct $ i;
+                struct $ j;
+            )
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo, bar }", "mod foo {} mod bar {}")
+    .assert_expand_items("foo! { foo# bar }", "fn foo () {} fn bar () {}")
+    .assert_expand_items("foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
+}
+
+#[test]
+fn test_match_group_pattern_with_multiple_defs() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ ($ i:ident),*) => ( struct Bar { $ (
+                fn $ i {}
+            )*} );
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}");
+}
+
+#[test]
+fn test_match_group_pattern_with_multiple_statement() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ ($ i:ident),*) => ( fn baz { $ (
+                $ i ();
+            )*} );
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
+}
+
+#[test]
+fn test_match_group_pattern_with_multiple_statement_without_semi() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ ($ i:ident),*) => ( fn baz { $ (
+                $i()
+            );*} );
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}");
+}
+
+#[test]
+fn test_match_group_empty_fixed_token() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ ($ i:ident)* #abc) => ( fn baz { $ (
+                $ i ();
+            )*} );
+        }
+"#,
+    )
+    .assert_expand_items("foo! {#abc}", "fn baz {}");
+}
+
+#[test]
+fn test_match_group_in_subtree() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ (
+                $ i ();
+            )*} );
+        }"#,
+    )
+    .assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
+}
+
+#[test]
+fn test_match_group_with_multichar_sep() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
+        }"#,
+    )
+    .assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}");
+}
+
+#[test]
+fn test_match_group_with_multichar_sep2() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            (fn $name:ident {$($i:literal)&&*} ) => ( fn $name() -> bool { $($i)&&*} );
+        }"#,
+    )
+    .assert_expand_items("foo! (fn baz {true && true} );", "fn baz () -> bool {true &&true}");
+}
+
+#[test]
+fn test_match_group_zero_match() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ( $($i:ident)* ) => ();
+        }"#,
+    )
+    .assert_expand_items("foo! ();", "");
+}
+
+#[test]
+fn test_match_group_in_group() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* );
+        }"#,
+    )
+    .assert_expand_items("foo! ( (a b) );", "(a b)");
+}
+
+#[test]
+fn test_expand_to_item_list() {
+    let tree = parse_macro(
+        "
+            macro_rules! structs {
+                ($($i:ident),*) => {
+                    $(struct $i { field: u32 } )*
+                }
+            }
+            ",
+    )
+    .expand_items("structs!(Foo, Bar);");
+    assert_eq!(
+        format!("{:#?}", tree).trim(),
+        r#"
+MACRO_ITEMS@0..40
+  STRUCT@0..20
+    STRUCT_KW@0..6 "struct"
+    NAME@6..9
+      IDENT@6..9 "Foo"
+    RECORD_FIELD_LIST@9..20
+      L_CURLY@9..10 "{"
+      RECORD_FIELD@10..19
+        NAME@10..15
+          IDENT@10..15 "field"
+        COLON@15..16 ":"
+        PATH_TYPE@16..19
+          PATH@16..19
+            PATH_SEGMENT@16..19
+              NAME_REF@16..19
+                IDENT@16..19 "u32"
+      R_CURLY@19..20 "}"
+  STRUCT@20..40
+    STRUCT_KW@20..26 "struct"
+    NAME@26..29
+      IDENT@26..29 "Bar"
+    RECORD_FIELD_LIST@29..40
+      L_CURLY@29..30 "{"
+      RECORD_FIELD@30..39
+        NAME@30..35
+          IDENT@30..35 "field"
+        COLON@35..36 ":"
+        PATH_TYPE@36..39
+          PATH@36..39
+            PATH_SEGMENT@36..39
+              NAME_REF@36..39
+                IDENT@36..39 "u32"
+      R_CURLY@39..40 "}""#
+            .trim()
+    );
+}
+
+fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree {
+    if let tt::TokenTree::Subtree(subtree) = tt {
+        return &subtree;
+    }
+    unreachable!("It is not a subtree");
+}
+fn to_literal(tt: &tt::TokenTree) -> &tt::Literal {
+    if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = tt {
+        return lit;
+    }
+    unreachable!("It is not a literal");
+}
+
+fn to_punct(tt: &tt::TokenTree) -> &tt::Punct {
+    if let tt::TokenTree::Leaf(tt::Leaf::Punct(lit)) = tt {
+        return lit;
+    }
+    unreachable!("It is not a Punct");
+}
+
+#[test]
+fn test_expand_literals_to_token_tree() {
+    let expansion = parse_macro(
+        r#"
+            macro_rules! literals {
+                ($i:ident) => {
+                    {
+                        let a = 'c';
+                        let c = 1000;
+                        let f = 12E+99_f64;
+                        let s = "rust1";
+                    }
+                }
+            }
+            "#,
+    )
+    .expand_tt("literals!(foo);");
+    let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees;
+
+    // [let] [a] [=] ['c'] [;]
+    assert_eq!(to_literal(&stm_tokens[3]).text, "'c'");
+    // [let] [c] [=] [1000] [;]
+    assert_eq!(to_literal(&stm_tokens[5 + 3]).text, "1000");
+    // [let] [f] [=] [12E+99_f64] [;]
+    assert_eq!(to_literal(&stm_tokens[10 + 3]).text, "12E+99_f64");
+    // [let] [s] [=] ["rust1"] [;]
+    assert_eq!(to_literal(&stm_tokens[15 + 3]).text, "\"rust1\"");
+}
+
+#[test]
+fn test_attr_to_token_tree() {
+    let expansion = parse_to_token_tree_by_syntax(
+        r#"
+            #[derive(Copy)]
+            struct Foo;
+            "#,
+    );
+
+    assert_eq!(to_punct(&expansion.token_trees[0]).char, '#');
+    assert_eq!(
+        to_subtree(&expansion.token_trees[1]).delimiter_kind(),
+        Some(tt::DelimiterKind::Bracket)
+    );
+}
+
+#[test]
+fn test_two_idents() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:ident, $ j:ident) => {
+                fn foo() { let a = $ i; let b = $j; }
+            }
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
+}
+
+#[test]
+fn test_tt_to_stmts() {
+    let stmts = parse_macro(
+        r#"
+        macro_rules! foo {
+            () => {
+                 let a = 0;
+                 a = 10 + 1;
+                 a
+            }
+        }
+"#,
+    )
+    .expand_statements("foo!{}");
+
+    assert_eq!(
+        format!("{:#?}", stmts).trim(),
+        r#"MACRO_STMTS@0..15
+  LET_STMT@0..7
+    LET_KW@0..3 "let"
+    IDENT_PAT@3..4
+      NAME@3..4
+        IDENT@3..4 "a"
+    EQ@4..5 "="
+    LITERAL@5..6
+      INT_NUMBER@5..6 "0"
+    SEMICOLON@6..7 ";"
+  EXPR_STMT@7..14
+    BIN_EXPR@7..13
+      PATH_EXPR@7..8
+        PATH@7..8
+          PATH_SEGMENT@7..8
+            NAME_REF@7..8
+              IDENT@7..8 "a"
+      EQ@8..9 "="
+      BIN_EXPR@9..13
+        LITERAL@9..11
+          INT_NUMBER@9..11 "10"
+        PLUS@11..12 "+"
+        LITERAL@12..13
+          INT_NUMBER@12..13 "1"
+    SEMICOLON@13..14 ";"
+  PATH_EXPR@14..15
+    PATH@14..15
+      PATH_SEGMENT@14..15
+        NAME_REF@14..15
+          IDENT@14..15 "a""#,
+    );
+}
+
+#[test]
+fn test_match_literal() {
+    parse_macro(
+        r#"
+    macro_rules! foo {
+        ('(') => {
+            fn foo() {}
+        }
+    }
+"#,
+    )
+    .assert_expand_items("foo! ['('];", "fn foo () {}");
+}
+
+#[test]
+fn test_parse_macro_def_simple() {
+    cov_mark::check!(parse_macro_def_simple);
+
+    parse_macro2(
+        r#"
+macro foo($id:ident) {
+    fn $id() {}
+}
+"#,
+    )
+    .assert_expand_items("foo!(bar);", "fn bar () {}");
+}
+
+#[test]
+fn test_parse_macro_def_rules() {
+    cov_mark::check!(parse_macro_def_rules);
+
+    parse_macro2(
+        r#"
+macro foo {
+    ($id:ident) => {
+        fn $id() {}
+    }
+}
+"#,
+    )
+    .assert_expand_items("foo!(bar);", "fn bar () {}");
+}
+
+#[test]
+fn test_path() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:path) => {
+                fn foo() { let a = $ i; }
+            }
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo }", "fn foo () {let a = foo ;}")
+    .assert_expand_items(
+        "foo! { bar::<u8>::baz::<u8> }",
+        "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}",
+    );
+}
+
+#[test]
+fn test_two_paths() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:path, $ j:path) => {
+                fn foo() { let a = $ i; let b = $j; }
+            }
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
+}
+
+#[test]
+fn test_path_with_path() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:path) => {
+                fn foo() { let a = $ i :: bar; }
+            }
+        }
+"#,
+    )
+    .assert_expand_items("foo! { foo }", "fn foo () {let a = foo :: bar ;}");
+}
+
+#[test]
+fn test_expr() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:expr) => {
+                 fn bar() { $ i; }
+            }
+        }
+"#,
+    )
+    .assert_expand_items(
+        "foo! { 2 + 2 * baz(3).quux() }",
+        "fn bar () {2 + 2 * baz (3) . quux () ;}",
+    );
+}
+
+#[test]
+fn test_last_expr() {
+    parse_macro(
+        r#"
+        macro_rules! vec {
+            ($($item:expr),*) => {
+                {
+                    let mut v = Vec::new();
+                    $(
+                        v.push($item);
+                    )*
+                    v
+                }
+            };
+        }
+"#,
+    )
+    .assert_expand_items(
+        "vec!(1,2,3);",
+        "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}",
+    );
+}
+
+#[test]
+fn test_expr_with_attr() {
+    parse_macro(
+        r#"
+macro_rules! m {
+    ($a:expr) => {0}
+}
+"#,
+    )
+    .assert_expand_items("m!(#[allow(a)]())", "0");
+}
+
+#[test]
+fn test_ty() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:ty) => (
+                fn bar() -> $ i { unimplemented!() }
+            )
+        }
+"#,
+    )
+    .assert_expand_items("foo! { Baz<u8> }", "fn bar () -> Baz < u8 > {unimplemented ! ()}");
+}
+
+#[test]
+fn test_ty_with_complex_type() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:ty) => (
+                fn bar() -> $ i { unimplemented!() }
+            )
+        }
+"#,
+    )
+    // Reference lifetime struct with generic type
+    .assert_expand_items(
+        "foo! { &'a Baz<u8> }",
+        "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}",
+    )
+    // extern "Rust" func type
+    .assert_expand_items(
+        r#"foo! { extern "Rust" fn() -> Ret }"#,
+        r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#,
+    );
+}
+
+#[test]
+fn test_pat_() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:pat) => { fn foo() { let $ i; } }
+        }
+"#,
+    )
+    .assert_expand_items("foo! { (a, b) }", "fn foo () {let (a , b) ;}");
+}
+
+#[test]
+fn test_stmt() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:stmt) => (
+                fn bar() { $ i; }
+            )
+        }
+"#,
+    )
+    .assert_expand_items("foo! { 2 }", "fn bar () {2 ;}")
+    .assert_expand_items("foo! { let a = 0 }", "fn bar () {let a = 0 ;}");
+}
+
+#[test]
+fn test_single_item() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:item) => (
+                $ i
+            )
+        }
+"#,
+    )
+    .assert_expand_items("foo! {mod c {}}", "mod c {}");
+}
+
+#[test]
+fn test_all_items() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ ($ i:item)*) => ($ (
+                $ i
+            )*)
+        }
+"#,
+    ).
+    assert_expand_items(
+        r#"
+        foo! {
+            extern crate a;
+            mod b;
+            mod c {}
+            use d;
+            const E: i32 = 0;
+            static F: i32 = 0;
+            impl G {}
+            struct H;
+            enum I { Foo }
+            trait J {}
+            fn h() {}
+            extern {}
+            type T = u8;
+        }
+"#,
+        r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#,
+    );
+}
+
+#[test]
+fn test_block() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:block) => { fn foo() $ i }
+        }
+"#,
+    )
+    .assert_expand_statements("foo! { { 1; } }", "fn foo () {1 ;}");
+}
+
+#[test]
+fn test_meta() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ i:meta) => (
+                #[$ i]
+                fn bar() {}
+            )
+        }
+"#,
+    )
+    .assert_expand_items(
+        r#"foo! { cfg(target_os = "windows") }"#,
+        r#"# [cfg (target_os = "windows")] fn bar () {}"#,
+    )
+    .assert_expand_items(r#"foo! { hello::world }"#, r#"# [hello :: world] fn bar () {}"#);
+}
+
+#[test]
+fn test_meta_doc_comments() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($(#[$ i:meta])+) => (
+                $(#[$ i])+
+                fn bar() {}
+            )
+        }
+"#,
+    ).
+    assert_expand_items(
+        r#"foo! {
+            /// Single Line Doc 1
+            /**
+                MultiLines Doc
+            */
+        }"#,
+        "# [doc = \" Single Line Doc 1\"] # [doc = \"\\\\n                MultiLines Doc\\\\n            \"] fn bar () {}",
+    );
+}
+
+#[test]
+fn test_meta_doc_comments_non_latin() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($(#[$ i:meta])+) => (
+                $(#[$ i])+
+                fn bar() {}
+            )
+        }
+"#,
+    ).
+    assert_expand_items(
+        r#"foo! {
+            /// 錦瑟無端五十弦，一弦一柱思華年。
+            /**
+                莊生曉夢迷蝴蝶，望帝春心託杜鵑。
+            */
+        }"#,
+        "# [doc = \" 錦瑟無端五十弦，一弦一柱思華年。\"] # [doc = \"\\\\n                莊生曉夢迷蝴蝶，望帝春心託杜鵑。\\\\n            \"] fn bar () {}",
+    );
+}
+
+#[test]
+fn test_tt_block() {
+    parse_macro(
+        r#"
+            macro_rules! foo {
+                ($ i:tt) => { fn foo() $ i }
+            }
+    "#,
+    )
+    .assert_expand_items(r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#);
+}
+
+#[test]
+fn test_tt_group() {
+    parse_macro(
+        r#"
+            macro_rules! foo {
+                 ($($ i:tt)*) => { $($ i)* }
+            }
+    "#,
+    )
+    .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#);
+}
+
+#[test]
+fn test_tt_composite() {
+    parse_macro(
+        r#"
+            macro_rules! foo {
+                 ($i:tt) => { 0 }
+            }
+    "#,
+    )
+    .assert_expand_items(r#"foo! { => }"#, r#"0"#);
+}
+
+#[test]
+fn test_tt_composite2() {
+    let node = parse_macro(
+        r#"
+            macro_rules! foo {
+                ($($tt:tt)*) => { abs!(=> $($tt)*) }
+            }
+    "#,
+    )
+    .expand_items(r#"foo!{#}"#);
+
+    let res = format!("{:#?}", &node);
+    assert_eq_text!(
+        r###"MACRO_ITEMS@0..10
+  MACRO_CALL@0..10
+    PATH@0..3
+      PATH_SEGMENT@0..3
+        NAME_REF@0..3
+          IDENT@0..3 "abs"
+    BANG@3..4 "!"
+    TOKEN_TREE@4..10
+      L_PAREN@4..5 "("
+      EQ@5..6 "="
+      R_ANGLE@6..7 ">"
+      WHITESPACE@7..8 " "
+      POUND@8..9 "#"
+      R_PAREN@9..10 ")""###,
+        res.trim()
+    );
+}
+
+#[test]
+fn test_tt_with_composite_without_space() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($ op:tt, $j:path) => (
+                0
+            )
+        }
+"#,
+    )
+    // Test macro input without any spaces
+    // See https://github.com/rust-analyzer/rust-analyzer/issues/6692
+    .assert_expand_items("foo!(==,Foo::Bool)", "0");
+}
+
+#[test]
+fn test_underscore() {
+    parse_macro(
+        r#"
+            macro_rules! foo {
+                 ($_:tt) => { 0 }
+            }
+    "#,
+    )
+    .assert_expand_items(r#"foo! { => }"#, r#"0"#);
+}
+
+#[test]
+fn test_underscore_not_greedily() {
+    parse_macro(
+        r#"
+macro_rules! q {
+    ($($a:ident)* _) => {0};
+}
+"#,
+    )
+    // `_` overlaps with `$a:ident` but rustc matches it under the `_` token
+    .assert_expand_items(r#"q![a b c d _]"#, r#"0"#);
+
+    parse_macro(
+        r#"
+macro_rules! q {
+    ($($a:expr => $b:ident)* _ => $c:expr) => {0};
+}
+"#,
+    )
+    // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`
+    .assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#);
+}
+
+#[test]
+fn test_underscore_as_type() {
+    parse_macro(
+        r#"
+macro_rules! q {
+    ($a:ty) => {0};
+}
+"#,
+    )
+    // Underscore is a type
+    .assert_expand_items(r#"q![_]"#, r#"0"#);
+}
+
+#[test]
+fn test_vertical_bar_with_pat() {
+    parse_macro(
+        r#"
+            macro_rules! foo {
+                 (| $pat:pat | ) => { 0 }
+            }
+    "#,
+    )
+    .assert_expand_items(r#"foo! { | x | }"#, r#"0"#);
+}
+
+#[test]
+fn test_dollar_crate_lhs_is_not_meta() {
+    parse_macro(
+        r#"
+macro_rules! foo {
+    ($crate) => {};
+    () => {0};
+}
+    "#,
+    )
+    .assert_expand_items(r#"foo!{}"#, r#"0"#);
+}
+
+#[test]
+fn test_lifetime() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+              ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } }
+        }
+"#,
+    )
+    .assert_expand_items(r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#);
+}
+
+#[test]
+fn test_literal() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+              ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;};
+        }
+"#,
+    )
+    .assert_expand_items(r#"foo!(u8,0);"#, r#"const VALUE : u8 = 0 ;"#);
+
+    parse_macro(
+        r#"
+        macro_rules! foo {
+              ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;};
+        }
+"#,
+    )
+    .assert_expand_items(r#"foo!(i32,-1);"#, r#"const VALUE : i32 = - 1 ;"#);
+}
+
+#[test]
+fn test_boolean_is_ident() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+              ($lit0:literal, $lit1:literal) => { const VALUE: (bool,bool) = ($lit0,$lit1); };
+        }
+"#,
+    )
+    .assert_expand(
+        r#"foo!(true,false);"#,
+        r#"
+SUBTREE $
+  IDENT   const 14
+  IDENT   VALUE 15
+  PUNCH   : [alone] 16
+  SUBTREE () 17
+    IDENT   bool 18
+    PUNCH   , [alone] 19
+    IDENT   bool 20
+  PUNCH   = [alone] 21
+  SUBTREE () 22
+    IDENT   true 29
+    PUNCH   , [joint] 25
+    IDENT   false 31
+  PUNCH   ; [alone] 28
+"#,
+    );
+}
+
+#[test]
+fn test_vis() {
+    parse_macro(
+        r#"
+        macro_rules! foo {
+              ($ vis:vis $ name:ident) => { $ vis fn $ name() {}};
+        }
+"#,
+    )
+    .assert_expand_items(r#"foo!(pub foo);"#, r#"pub fn foo () {}"#)
+    // test optional cases
+    .assert_expand_items(r#"foo!(foo);"#, r#"fn foo () {}"#);
+}
+
+#[test]
+fn test_inner_macro_rules() {
+    parse_macro(
+        r#"
+macro_rules! foo {
+    ($a:ident, $b:ident, $c:tt) => {
+
+        macro_rules! bar {
+            ($bi:ident) => {
+                fn $bi() -> u8 {$c}
+            }
+        }
+
+        bar!($a);
+        fn $b() -> u8 {$c}
+    }
+}
+"#,
+    ).
+    assert_expand_items(
+        r#"foo!(x,y, 1);"#,
+        r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#,
+    );
+}
+
+#[test]
+fn test_expr_after_path_colons() {
+    assert!(parse_macro(
+        r#"
+macro_rules! m {
+    ($k:expr) => {
+            f(K::$k);
+       }
+}
+"#,
+    )
+    .expand_statements(r#"m!(C("0"))"#)
+    .descendants()
+    .find(|token| token.kind() == ERROR)
+    .is_some());
+}
+
+#[test]
+fn test_match_is_not_greedy() {
+    parse_macro(
+        r#"
+macro_rules! foo {
+    ($($i:ident $(,)*),*) => {};
+}
+"#,
+    )
+    .assert_expand_items(r#"foo!(a,b);"#, r#""#);
+}
+
+// The following tests are based on real world situations
+#[test]
+fn test_vec() {
+    let fixture = parse_macro(
+        r#"
+         macro_rules! vec {
+            ($($item:expr),*) => {
+                {
+                    let mut v = Vec::new();
+                    $(
+                        v.push($item);
+                    )*
+                    v
+                }
+            };
+}
+"#,
+    );
+    fixture
+        .assert_expand_items(r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#)
+        .assert_expand_items(
+            r#"vec![1u32,2];"#,
+            r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#,
+        );
+
+    let tree = fixture.expand_expr(r#"vec![1u32,2];"#);
+
+    assert_eq!(
+        format!("{:#?}", tree).trim(),
+        r#"BLOCK_EXPR@0..45
+  L_CURLY@0..1 "{"
+  LET_STMT@1..20
+    LET_KW@1..4 "let"
+    IDENT_PAT@4..8
+      MUT_KW@4..7 "mut"
+      NAME@7..8
+        IDENT@7..8 "v"
+    EQ@8..9 "="
+    CALL_EXPR@9..19
+      PATH_EXPR@9..17
+        PATH@9..17
+          PATH@9..12
+            PATH_SEGMENT@9..12
+              NAME_REF@9..12
+                IDENT@9..12 "Vec"
+          COLON2@12..14 "::"
+          PATH_SEGMENT@14..17
+            NAME_REF@14..17
+              IDENT@14..17 "new"
+      ARG_LIST@17..19
+        L_PAREN@17..18 "("
+        R_PAREN@18..19 ")"
+    SEMICOLON@19..20 ";"
+  EXPR_STMT@20..33
+    METHOD_CALL_EXPR@20..32
+      PATH_EXPR@20..21
+        PATH@20..21
+          PATH_SEGMENT@20..21
+            NAME_REF@20..21
+              IDENT@20..21 "v"
+      DOT@21..22 "."
+      NAME_REF@22..26
+        IDENT@22..26 "push"
+      ARG_LIST@26..32
+        L_PAREN@26..27 "("
+        LITERAL@27..31
+          INT_NUMBER@27..31 "1u32"
+        R_PAREN@31..32 ")"
+    SEMICOLON@32..33 ";"
+  EXPR_STMT@33..43
+    METHOD_CALL_EXPR@33..42
+      PATH_EXPR@33..34
+        PATH@33..34
+          PATH_SEGMENT@33..34
+            NAME_REF@33..34
+              IDENT@33..34 "v"
+      DOT@34..35 "."
+      NAME_REF@35..39
+        IDENT@35..39 "push"
+      ARG_LIST@39..42
+        L_PAREN@39..40 "("
+        LITERAL@40..41
+          INT_NUMBER@40..41 "2"
+        R_PAREN@41..42 ")"
+    SEMICOLON@42..43 ";"
+  PATH_EXPR@43..44
+    PATH@43..44
+      PATH_SEGMENT@43..44
+        NAME_REF@43..44
+          IDENT@43..44 "v"
+  R_CURLY@44..45 "}""#
+    );
+}
+
+#[test]
+fn test_winapi_struct() {
+    // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366
+
+    parse_macro(
+        r#"
+macro_rules! STRUCT {
+    ($(#[$attrs:meta])* struct $name:ident {
+        $($field:ident: $ftype:ty,)+
+    }) => (
+        #[repr(C)] #[derive(Copy)] $(#[$attrs])*
+        pub struct $name {
+            $(pub $field: $ftype,)+
+        }
+        impl Clone for $name {
+            #[inline]
+            fn clone(&self) -> $name { *self }
+        }
+        #[cfg(feature = "impl-default")]
+        impl Default for $name {
+            #[inline]
+            fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } }
+        }
+    );
+}
+"#,
+    ).
+    // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs
+    assert_expand_items(r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#,
+        "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
+    )
+    .assert_expand_items(r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#,
+        "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
+    );
+}
+
+#[test]
+fn test_int_base() {
+    parse_macro(
+        r#"
+macro_rules! int_base {
+    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl fmt::$Trait for $T {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                $Radix.fmt_int(*self as $U, f)
+            }
+        }
+    }
+}
+"#,
+    ).assert_expand_items(r#" int_base!{Binary for isize as usize -> Binary}"#,
+        "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
+    );
+}
+
+#[test]
+fn test_generate_pattern_iterators() {
+    // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs
+    parse_macro(
+        r#"
+macro_rules! generate_pattern_iterators {
+        { double ended; with $(#[$common_stability_attribute:meta])*,
+                           $forward_iterator:ident,
+                           $reverse_iterator:ident, $iterty:ty
+        } => {
+            fn foo(){}
+        }
+}
+"#,
+    ).assert_expand_items(
+        r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#,
+        "fn foo () {}",
+    );
+}
+
+#[test]
+fn test_impl_fn_for_zst() {
+    // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs
+    parse_macro(
+        r#"
+macro_rules! impl_fn_for_zst  {
+        {  $( $( #[$attr: meta] )*
+        struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
+            |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
+$body: block; )+
+        } => {
+           $(
+            $( #[$attr] )*
+            struct $Name;
+
+            impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
+                #[inline]
+                extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
+                    $body
+                }
+            }
+
+            impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
+                #[inline]
+                extern "rust-call" fn call_mut(
+                    &mut self,
+                    ($( $arg, )*): ($( $ArgTy, )*)
+                ) -> $ReturnTy {
+                    Fn::call(&*self, ($( $arg, )*))
+                }
+            }
+
+            impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
+                type Output = $ReturnTy;
+
+                #[inline]
+                extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
+                    Fn::call(&self, ($( $arg, )*))
+                }
+            }
+        )+
+}
+        }
+"#,
+    ).assert_expand_items(r#"
+impl_fn_for_zst !   {
+     # [ derive ( Clone ) ]
+     struct   CharEscapeDebugContinue   impl   Fn   =   | c :   char |   ->   char :: EscapeDebug   {
+         c . escape_debug_ext ( false )
+     } ;
+
+     # [ derive ( Clone ) ]
+     struct   CharEscapeUnicode   impl   Fn   =   | c :   char |   ->   char :: EscapeUnicode   {
+         c . escape_unicode ( )
+     } ;
+     # [ derive ( Clone ) ]
+     struct   CharEscapeDefault   impl   Fn   =   | c :   char |   ->   char :: EscapeDefault   {
+         c . escape_default ( )
+     } ;
+ }
+"#,
+        "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"
+    );
+}
+
+#[test]
+fn test_impl_nonzero_fmt() {
+    // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
+    parse_macro(
+        r#"
+        macro_rules! impl_nonzero_fmt {
+            ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
+                fn foo () {}
+            }
+        }
+"#,
+    ).assert_expand_items(
+        r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#,
+        "fn foo () {}",
+    );
+}
+
+#[test]
+fn test_cfg_if_items() {
+    // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986
+    parse_macro(
+        r#"
+        macro_rules! __cfg_if_items {
+            (($($not:meta,)*) ; ) => {};
+            (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
+                 __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
+            }
+        }
+"#,
+    ).assert_expand_items(
+        r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#,
+        "__cfg_if_items ! {(rustdoc ,) ;}",
+    );
+}
+
+#[test]
+fn test_cfg_if_main() {
+    // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9
+    parse_macro(
+        r#"
+        macro_rules! cfg_if {
+            ($(
+                if #[cfg($($meta:meta),*)] { $($it:item)* }
+            ) else * else {
+                $($it2:item)*
+            }) => {
+                __cfg_if_items! {
+                    () ;
+                    $( ( ($($meta),*) ($($it)*) ), )*
+                    ( () ($($it2)*) ),
+                }
+            };
+
+            // Internal macro to Apply a cfg attribute to a list of items
+            (@__apply $m:meta, $($it:item)*) => {
+                $(#[$m] $it)*
+            };
+        }
+"#,
+    ).assert_expand_items(r#"
+cfg_if !   {
+     if   # [ cfg ( target_env   =   "msvc" ) ]   {
+         // no extra unwinder support needed
+     }   else   if   # [ cfg ( all ( target_arch   =   "wasm32" ,   not ( target_os   =   "emscripten" ) ) ) ]   {
+         // no unwinder on the system!
+     }   else   {
+         mod   libunwind ;
+         pub   use   libunwind :: * ;
+     }
+ }
+"#,
+        "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"
+    ).assert_expand_items(
+        r#"
+cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , }
+"#,
+        "",
+    );
+}
+
+#[test]
+fn test_proptest_arbitrary() {
+    // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16
+    parse_macro(
+        r#"
+macro_rules! arbitrary {
+    ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty;
+        $args: ident => $logic: expr) => {
+        impl<$($bounds)*> $crate::arbitrary::Arbitrary for $typ {
+            type Parameters = $params;
+            type Strategy = $strat;
+            fn arbitrary_with($args: Self::Parameters) -> Self::Strategy {
+                $logic
+            }
+        }
+    };
+
+}"#,
+    ).assert_expand_items(r#"arbitrary !   ( [ A : Arbitrary ]
+        Vec < A > ,
+        VecStrategy < A :: Strategy > ,
+        RangedParams1 < A :: Parameters > ;
+        args =>   { let product_unpack !   [ range , a ] = args ; vec ( any_with :: < A >   ( a ) , range ) }
+    ) ;"#,
+    "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}"
+    );
+}
+
+#[test]
+fn test_old_ridl() {
+    // This is from winapi 2.8, which do not have a link from github
+    //
+    let expanded = parse_macro(
+        r#"
+#[macro_export]
+macro_rules! RIDL {
+    (interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident)
+        {$(
+            fn $method:ident(&mut self $(,$p:ident : $t:ty)*) -> $rtr:ty
+        ),+}
+    ) => {
+        impl $interface {
+            $(pub unsafe fn $method(&mut self) -> $rtr {
+                ((*self.lpVtbl).$method)(self $(,$p)*)
+            })+
+        }
+    };
+}"#,
+    ).expand_tt(r#"
+    RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
+        fn GetDataSize(&mut self) -> UINT
+    }}"#);
+
+    assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}");
+}
+
+#[test]
+fn test_quick_error() {
+    let expanded = parse_macro(
+        r#"
+macro_rules! quick_error {
+
+ (SORT [enum $name:ident $( #[$meta:meta] )*]
+        items [$($( #[$imeta:meta] )*
+                  => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*]
+                                {$( $ifuncs:tt )*} )* ]
+        buf [ ]
+        queue [ ]
+    ) => {
+        quick_error!(ENUMINITION [enum $name $( #[$meta] )*]
+            body []
+            queue [$(
+                $( #[$imeta] )*
+                =>
+                $iitem: $imode [$( $ivar: $ityp ),*]
+            )*]
+        );
+};
+
+}
+"#,
+    )
+    .expand_tt(
+        r#"
+quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
+        => One : UNIT [] {}
+        => Two : TUPLE [s :String] {display ("two: {}" , s) from ()}
+    ] buf [] queue []) ;
+"#,
+    );
+
+    assert_eq!(expanded.to_string(), "quick_error ! (ENUMINITION [enum Wrapped # [derive (Debug)]] body [] queue [=> One : UNIT [] => Two : TUPLE [s : String]]) ;");
+}
+
+#[test]
+fn test_empty_repeat_vars_in_empty_repeat_vars() {
+    parse_macro(
+        r#"
+macro_rules! delegate_impl {
+    ([$self_type:ident, $self_wrap:ty, $self_map:ident]
+     pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
+
+        $(
+        @escape [type $assoc_name_ext:ident]
+        )*
+        $(
+        @section type
+        $(
+            $(#[$_assoc_attr:meta])*
+            type $assoc_name:ident $(: $assoc_bound:ty)*;
+        )+
+        )*
+        $(
+        @section self
+        $(
+            $(#[$_method_attr:meta])*
+            fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) -> $mret:ty;
+        )+
+        )*
+        $(
+        @section nodelegate
+        $($tail:tt)*
+        )*
+    }) => {
+        impl<> $name for $self_wrap where $self_type: $name {
+            $(
+            $(
+                fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) -> $mret {
+                    $self_map!(self).$method_name($($marg),*)
+                }
+            )*
+            )*
+        }
+    }
+}
+"#,
+    ).assert_expand_items(
+        r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#,
+        "impl <> Data for & \'a mut G where G : Data {}",
+    );
+}
+
+#[test]
+fn expr_interpolation() {
+    let expanded = parse_macro(
+        r#"
+        macro_rules! id {
+            ($expr:expr) => {
+                map($expr)
+            }
+        }
+        "#,
+    )
+    .expand_expr("id!(x + foo);");
+
+    assert_eq!(expanded.to_string(), "map(x+foo)");
+}
+
+#[test]
+fn test_issue_2520() {
+    let macro_fixture = parse_macro(
+        r#"
+        macro_rules! my_macro {
+            {
+                ( $(
+                    $( [] $sname:ident : $stype:ty  )?
+                    $( [$expr:expr] $nname:ident : $ntype:ty  )?
+                ),* )
+            } => {
+                Test {
+                    $(
+                        $( $sname, )?
+                    )*
+                }
+            };
+        }
+    "#,
+    );
+
+    macro_fixture.assert_expand_items(
+        r#"my_macro ! {
+            ([] p1 : u32 , [|_| S0K0] s : S0K0 , [] k0 : i32)
+        }"#,
+        "Test {p1 , k0 ,}",
+    );
+}
+
+#[test]
+fn test_issue_3861() {
+    let macro_fixture = parse_macro(
+        r#"
+        macro_rules! rgb_color {
+            ($p:expr, $t: ty) => {
+                pub fn new() {
+                    let _ = 0 as $t << $p;
+                }
+            };
+        }
+    "#,
+    );
+
+    macro_fixture.expand_items(r#"rgb_color!(8 + 8, u32);"#);
+}
+
+#[test]
+fn test_repeat_bad_var() {
+    // FIXME: the second rule of the macro should be removed and an error about
+    // `$( $c )+` raised
+    parse_macro(
+        r#"
+        macro_rules! foo {
+            ($( $b:ident )+) => {
+                $( $c )+
+            };
+            ($( $b:ident )+) => {
+                $( $b )+
+            }
+        }
+    "#,
+    )
+    .assert_expand_items("foo!(b0 b1);", "b0 b1");
+}
+
+#[test]
+fn test_no_space_after_semi_colon() {
+    let expanded = parse_macro(
+        r#"
+        macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) }
+    "#,
+    )
+    .expand_items(r#"with_std! {mod m;mod f;}"#);
+
+    let dump = format!("{:#?}", expanded);
+    assert_eq_text!(
+        r###"MACRO_ITEMS@0..52
+  MODULE@0..26
+    ATTR@0..21
+      POUND@0..1 "#"
+      L_BRACK@1..2 "["
+      PATH@2..5
+        PATH_SEGMENT@2..5
+          NAME_REF@2..5
+            IDENT@2..5 "cfg"
+      TOKEN_TREE@5..20
+        L_PAREN@5..6 "("
+        IDENT@6..13 "feature"
+        EQ@13..14 "="
+        STRING@14..19 "\"std\""
+        R_PAREN@19..20 ")"
+      R_BRACK@20..21 "]"
+    MOD_KW@21..24 "mod"
+    NAME@24..25
+      IDENT@24..25 "m"
+    SEMICOLON@25..26 ";"
+  MODULE@26..52
+    ATTR@26..47
+      POUND@26..27 "#"
+      L_BRACK@27..28 "["
+      PATH@28..31
+        PATH_SEGMENT@28..31
+          NAME_REF@28..31
+            IDENT@28..31 "cfg"
+      TOKEN_TREE@31..46
+        L_PAREN@31..32 "("
+        IDENT@32..39 "feature"
+        EQ@39..40 "="
+        STRING@40..45 "\"std\""
+        R_PAREN@45..46 ")"
+      R_BRACK@46..47 "]"
+    MOD_KW@47..50 "mod"
+    NAME@50..51
+      IDENT@50..51 "f"
+    SEMICOLON@51..52 ";""###,
+        dump.trim()
+    );
+}
+
+// https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57597.rs
+#[test]
+fn test_rustc_issue_57597() {
+    fn test_error(fixture: &str) {
+        assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmptyTokenTree);
+    }
+
+    test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }");
+    test_error("macro_rules! foo { ($($($i:ident)?)*) => {}; }");
+    test_error("macro_rules! foo { ($($($i:ident)?)?) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)?)?)?) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)*)?)?) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)?)*)?) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)?)?)*) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)*)*)?) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)?)*)*) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)?)*)+) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)+)?)*) => {}; }");
+    test_error("macro_rules! foo { ($($($($i:ident)+)*)?) => {}; }");
+}
+
+#[test]
+fn test_expand_bad_literal() {
+    parse_macro(
+        r#"
+        macro_rules! foo { ($i:literal) => {}; }
+    "#,
+    )
+    .assert_expand_err(r#"foo!(&k");"#, &ExpandError::BindingError("".into()));
+}
+
+#[test]
+fn test_empty_comments() {
+    parse_macro(
+        r#"
+        macro_rules! one_arg_macro { ($fmt:expr) => (); }
+    "#,
+    )
+    .assert_expand_err(
+        r#"one_arg_macro!(/**/)"#,
+        &ExpandError::BindingError("expected Expr".into()),
+    );
+}
diff --git a/crates/mbe/src/tests/rule.rs b/crates/mbe/src/tests/rule.rs
new file mode 100644
index 0000000000..07277966d4
--- /dev/null
+++ b/crates/mbe/src/tests/rule.rs
@@ -0,0 +1,45 @@
+use syntax::{ast, AstNode};
+
+use crate::ast_to_token_tree;
+
+use super::*;
+
+#[test]
+fn test_valid_arms() {
+    fn check(macro_body: &str) {
+        let m = parse_macro_arm(macro_body);
+        m.unwrap();
+    }
+
+    check("($i:ident) => ()");
+    check("($($i:ident)*) => ($_)");
+    check("($($true:ident)*) => ($true)");
+    check("($($false:ident)*) => ($false)");
+    check("($) => ($)");
+}
+
+#[test]
+fn test_invalid_arms() {
+    fn check(macro_body: &str, err: ParseError) {
+        let m = parse_macro_arm(macro_body);
+        assert_eq!(m, Err(err));
+    }
+    check("invalid", ParseError::Expected("expected subtree".into()));
+
+    check("$i:ident => ()", ParseError::Expected("expected subtree".into()));
+    check("($i:ident) ()", ParseError::Expected("expected `=`".into()));
+    check("($($i:ident)_) => ()", ParseError::InvalidRepeat);
+
+    check("($i) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
+    check("($i:) => ($i)", ParseError::UnexpectedToken("bad fragment specifier 1".into()));
+}
+
+fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError> {
+    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();
+
+    let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
+    crate::MacroRules::parse(&definition_tt)
+}
diff --git a/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast b/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
index a84088bf30..495e4c51b5 100644
--- a/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
@@ -6,16 +6,16 @@ SOURCE_FILE@0..28
       IDENT@3..4 "f"
     PARAM_LIST@4..24
       L_PAREN@4..5 "("
-      PARAM@5..23
-        ATTR@5..13
-          POUND@5..6 "#"
-          L_BRACK@6..7 "["
-          PATH@7..12
-            PATH_SEGMENT@7..12
-              NAME_REF@7..12
-                IDENT@7..12 "attr1"
-          R_BRACK@12..13 "]"
-        WHITESPACE@13..14 " "
+      ATTR@5..13
+        POUND@5..6 "#"
+        L_BRACK@6..7 "["
+        PATH@7..12
+          PATH_SEGMENT@7..12
+            NAME_REF@7..12
+              IDENT@7..12 "attr1"
+        R_BRACK@12..13 "]"
+      WHITESPACE@13..14 " "
+      PARAM@14..23
         IDENT_PAT@14..17
           NAME@14..17
             IDENT@14..17 "pat"
diff --git a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
index 88470c41c0..e10521d853 100644
--- a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
+++ b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
@@ -6,25 +6,25 @@ SOURCE_FILE@0..519
       IDENT@3..5 "g1"
     PARAM_LIST@5..34
       L_PAREN@5..6 "("
-      PARAM@6..33
-        ATTR@6..14
-          POUND@6..7 "#"
-          L_BRACK@7..8 "["
-          PATH@8..13
-            PATH_SEGMENT@8..13
-              NAME_REF@8..13
-                IDENT@8..13 "attr1"
-          R_BRACK@13..14 "]"
-        WHITESPACE@14..15 " "
-        ATTR@15..23
-          POUND@15..16 "#"
-          L_BRACK@16..17 "["
-          PATH@17..22
-            PATH_SEGMENT@17..22
-              NAME_REF@17..22
-                IDENT@17..22 "attr2"
-          R_BRACK@22..23 "]"
-        WHITESPACE@23..24 " "
+      ATTR@6..14
+        POUND@6..7 "#"
+        L_BRACK@7..8 "["
+        PATH@8..13
+          PATH_SEGMENT@8..13
+            NAME_REF@8..13
+              IDENT@8..13 "attr1"
+        R_BRACK@13..14 "]"
+      WHITESPACE@14..15 " "
+      ATTR@15..23
+        POUND@15..16 "#"
+        L_BRACK@16..17 "["
+        PATH@17..22
+          PATH_SEGMENT@17..22
+            NAME_REF@17..22
+              IDENT@17..22 "attr2"
+        R_BRACK@22..23 "]"
+      WHITESPACE@23..24 " "
+      PARAM@24..33
         IDENT_PAT@24..27
           NAME@24..27
             IDENT@24..27 "pat"
@@ -48,16 +48,16 @@ SOURCE_FILE@0..519
       IDENT@41..43 "g2"
     PARAM_LIST@43..59
       L_PAREN@43..44 "("
-      PARAM@44..58
-        ATTR@44..52
-          POUND@44..45 "#"
-          L_BRACK@45..46 "["
-          PATH@46..51
-            PATH_SEGMENT@46..51
-              NAME_REF@46..51
-                IDENT@46..51 "attr1"
-          R_BRACK@51..52 "]"
-        WHITESPACE@52..53 " "
+      ATTR@44..52
+        POUND@44..45 "#"
+        L_BRACK@45..46 "["
+        PATH@46..51
+          PATH_SEGMENT@46..51
+            NAME_REF@46..51
+              IDENT@46..51 "attr1"
+        R_BRACK@51..52 "]"
+      WHITESPACE@52..53 " "
+      PARAM@53..58
         IDENT_PAT@53..54
           NAME@53..54
             IDENT@53..54 "x"
@@ -203,16 +203,16 @@ SOURCE_FILE@0..519
           IDENT@193..196 "bar"
         PARAM_LIST@196..233
           L_PAREN@196..197 "("
-          PARAM@197..211
-            ATTR@197..204
-              POUND@197..198 "#"
-              L_BRACK@198..199 "["
-              PATH@199..203
-                PATH_SEGMENT@199..203
-                  NAME_REF@199..203
-                    IDENT@199..203 "attr"
-              R_BRACK@203..204 "]"
-            WHITESPACE@204..205 " "
+          ATTR@197..204
+            POUND@197..198 "#"
+            L_BRACK@198..199 "["
+            PATH@199..203
+              PATH_SEGMENT@199..203
+                NAME_REF@199..203
+                  IDENT@199..203 "attr"
+            R_BRACK@203..204 "]"
+          WHITESPACE@204..205 " "
+          PARAM@205..211
             WILDCARD_PAT@205..206
               UNDERSCORE@205..206 "_"
             COLON@206..207 ":"