Repository: rust-analyzer/rust-analyzer
Pull request #6719 (2020-12-04 14:53:13)

Use items can also have doc comments
Prior to this change modules show more docs than they have cause they inherit the docs from documented use items inside of them.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 8dcea6ea44..d8838cf2b0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -802,9 +802,9 @@ checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
 
 [[package]]
 name = "libloading"
-version = "0.6.6"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9367bdfa836b7e3cf895867f7a570283444da90562980ec2263d6e1569b16bc"
+checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0"
 dependencies = [
  "cfg-if 1.0.0",
  "winapi 0.3.9",
@@ -956,9 +956,9 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.6.23"
+version = "0.6.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
+checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
 dependencies = [
  "cfg-if 0.1.10",
  "fuchsia-zircon",
@@ -1555,9 +1555,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.60"
+version = "1.0.59"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
+checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
 dependencies = [
  "itoa",
  "ryu",
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 92bcc17053..33eb5e78c4 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -120,24 +120,18 @@ impl Expander {
             self.resolve_path_as_macro(db, &path)
         };
 
-        let mut err = None;
-        let call_id =
-            macro_call.as_call_id_with_errors(db, self.crate_def_map.krate, resolver, &mut |e| {
-                err.get_or_insert(e);
-            });
-        let call_id = match call_id {
+        let call_id = match macro_call.as_call_id(db, self.crate_def_map.krate, resolver) {
             Some(it) => it,
             None => {
-                if err.is_none() {
-                    eprintln!("no error despite `as_call_id_with_errors` returning `None`");
-                }
-                return ExpandResult { value: None, err };
+                // FIXME: this can mean other things too, but `as_call_id` doesn't provide enough
+                // info.
+                return ExpandResult::only_err(mbe::ExpandError::Other(
+                    "failed to parse or resolve macro invocation".into(),
+                ));
             }
         };
 
-        if err.is_none() {
-            err = db.macro_expand_error(call_id);
-        }
+        let err = db.macro_expand_error(call_id);
 
         let file_id = call_id.as_file();
 
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index b41c5acb2a..1b22d1eec9 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -465,37 +465,21 @@ pub trait AsMacroCall {
         db: &dyn db::DefDatabase,
         krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
-    ) -> Option<MacroCallId> {
-        self.as_call_id_with_errors(db, krate, resolver, &mut |_| ())
-    }
-
-    fn as_call_id_with_errors(
-        &self,
-        db: &dyn db::DefDatabase,
-        krate: CrateId,
-        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
-        error_sink: &mut dyn FnMut(mbe::ExpandError),
     ) -> Option<MacroCallId>;
 }
 
 impl AsMacroCall for InFile<&ast::MacroCall> {
-    fn as_call_id_with_errors(
+    fn as_call_id(
         &self,
         db: &dyn db::DefDatabase,
         krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
-        error_sink: &mut dyn FnMut(mbe::ExpandError),
     ) -> Option<MacroCallId> {
         let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
         let h = Hygiene::new(db.upcast(), self.file_id);
-        let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h));
-
-        if path.is_none() {
-            error_sink(mbe::ExpandError::Other("malformed macro invocation".into()));
-        }
+        let path = path::ModPath::from_src(self.value.path()?, &h)?;
 
-        AstIdWithPath::new(ast_id.file_id, ast_id.value, path?)
-            .as_call_id_with_errors(db, krate, resolver, error_sink)
+        AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver)
     }
 }
 
@@ -513,32 +497,22 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
 }
 
 impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
-    fn as_call_id_with_errors(
+    fn as_call_id(
         &self,
         db: &dyn db::DefDatabase,
         krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
-        error_sink: &mut dyn FnMut(mbe::ExpandError),
     ) -> Option<MacroCallId> {
-        let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
-            error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path)));
-            None
-        })?;
+        let def: MacroDefId = resolver(self.path.clone())?;
 
         if let MacroDefKind::BuiltInEager(_) = def.kind {
             let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast()));
             let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
 
             Some(
-                expand_eager_macro(
-                    db.upcast(),
-                    krate,
-                    macro_call,
-                    def,
-                    &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?),
-                    error_sink,
-                )
-                .ok()?
+                expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| {
+                    resolver(path::ModPath::from_src(path, &hygiene)?)
+                })?
                 .into(),
             )
         } else {
@@ -548,18 +522,13 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
 }
 
 impl AsMacroCall for AstIdWithPath<ast::Item> {
-    fn as_call_id_with_errors(
+    fn as_call_id(
         &self,
         db: &dyn db::DefDatabase,
         krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
-        error_sink: &mut dyn FnMut(mbe::ExpandError),
     ) -> Option<MacroCallId> {
-        let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
-            error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path)));
-            None
-        })?;
-
+        let def = resolver(self.path.clone())?;
         Some(
             def.as_lazy_macro(
                 db.upcast(),
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 44a5556b67..7f4db106db 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -86,6 +86,7 @@ pub fn find_builtin_macro(
 register_builtin! {
     LAZY:
     (column, Column) => column_expand,
+    (compile_error, CompileError) => compile_error_expand,
     (file, File) => file_expand,
     (line, Line) => line_expand,
     (assert, Assert) => assert_expand,
@@ -96,7 +97,6 @@ register_builtin! {
     (format_args_nl, FormatArgsNl) => format_args_expand,
 
     EAGER:
-    (compile_error, CompileError) => compile_error_expand,
     (concat, Concat) => concat_expand,
     (include, Include) => include_expand,
     (include_bytes, IncludeBytes) => include_bytes_expand,
@@ -213,6 +213,25 @@ fn file_expand(
     ExpandResult::ok(expanded)
 }
 
+fn compile_error_expand(
+    _db: &dyn AstDatabase,
+    _id: LazyMacroId,
+    tt: &tt::Subtree,
+) -> ExpandResult<tt::Subtree> {
+    if tt.count() == 1 {
+        if let tt::TokenTree::Leaf(tt::Leaf::Literal(it)) = &tt.token_trees[0] {
+            let s = it.text.as_str();
+            if s.contains('"') {
+                return ExpandResult::ok(quote! { loop { #it }});
+            }
+        };
+    }
+
+    ExpandResult::only_err(mbe::ExpandError::BindingError(
+        "`compile_error!` argument be a string".into(),
+    ))
+}
+
 fn format_args_expand(
     _db: &dyn AstDatabase,
     _id: LazyMacroId,
@@ -261,27 +280,6 @@ fn unquote_str(lit: &tt::Literal) -> Option<String> {
     token.value().map(|it| it.into_owned())
 }
 
-fn compile_error_expand(
-    _db: &dyn AstDatabase,
-    _id: EagerMacroId,
-    tt: &tt::Subtree,
-) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
-    let err = match &*tt.token_trees {
-        [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => {
-            let text = it.text.as_str();
-            if text.starts_with('"') && text.ends_with('"') {
-                // FIXME: does not handle raw strings
-                mbe::ExpandError::Other(text[1..text.len() - 1].to_string())
-            } else {
-                mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into())
-            }
-        }
-        _ => mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into()),
-    };
-
-    ExpandResult { value: Some((quote! {}, FragmentKind::Items)), err: Some(err) }
-}
-
 fn concat_expand(
     _db: &dyn AstDatabase,
     _arg_id: EagerMacroId,
@@ -419,25 +417,17 @@ fn env_expand(
         Err(e) => return ExpandResult::only_err(e),
     };
 
-    let mut err = None;
-    let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| {
-        // The only variable rust-analyzer ever sets is `OUT_DIR`, so only diagnose that to avoid
-        // unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
-        if key == "OUT_DIR" {
-            err = Some(mbe::ExpandError::Other(
-                r#"`OUT_DIR` not set, enable "load out dirs from check" to fix"#.into(),
-            ));
-        }
-
-        // If the variable is unset, still return a dummy string to help type inference along.
-        // We cannot use an empty string here, because for
-        // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become
-        // `include!("foo.rs"), which might go to infinite loop
-        "__RA_UNIMPLEMENTED__".to_string()
-    });
+    // FIXME:
+    // If the environment variable is not defined int rustc, then a compilation error will be emitted.
+    // We might do the same if we fully support all other stuffs.
+    // But for now on, we should return some dummy string for better type infer purpose.
+    // However, we cannot use an empty string here, because for
+    // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become
+    // `include!("foo.rs"), which might go to infinite loop
+    let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| "__RA_UNIMPLEMENTED__".to_string());
     let expanded = quote! { #s };
 
-    ExpandResult { value: Some((expanded, FragmentKind::Expr)), err }
+    ExpandResult::ok(Some((expanded, FragmentKind::Expr)))
 }
 
 fn option_env_expand(
@@ -648,8 +638,7 @@ mod tests {
             "#,
         );
 
-        // This expands to nothing (since it's in item position), but emits an error.
-        assert_eq!(expanded, "");
+        assert_eq!(expanded, r#"loop{"error!"}"#);
     }
 
     #[test]
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 842a177db3..4fd0ba290f 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -207,7 +207,6 @@ fn macro_expand_with_arg(
             } else {
                 return ExpandResult {
                     value: Some(db.lookup_intern_eager_expansion(id).subtree),
-                    // FIXME: There could be errors here!
                     err: None,
                 };
             }
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 0229a836ec..ab6b4477c6 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -26,89 +26,19 @@ use crate::{
 };
 
 use base_db::CrateId;
-use mbe::ExpandResult;
 use parser::FragmentKind;
 use std::sync::Arc;
 use syntax::{algo::SyntaxRewriter, SyntaxNode};
 
-pub struct ErrorEmitted {
-    _private: (),
-}
-
-trait ErrorSink {
-    fn emit(&mut self, err: mbe::ExpandError);
-
-    fn option<T>(
-        &mut self,
-        opt: Option<T>,
-        error: impl FnOnce() -> mbe::ExpandError,
-    ) -> Result<T, ErrorEmitted> {
-        match opt {
-            Some(it) => Ok(it),
-            None => {
-                self.emit(error());
-                Err(ErrorEmitted { _private: () })
-            }
-        }
-    }
-
-    fn option_with<T>(
-        &mut self,
-        opt: impl FnOnce() -> Option<T>,
-        error: impl FnOnce() -> mbe::ExpandError,
-    ) -> Result<T, ErrorEmitted> {
-        self.option(opt(), error)
-    }
-
-    fn result<T>(&mut self, res: Result<T, mbe::ExpandError>) -> Result<T, ErrorEmitted> {
-        match res {
-            Ok(it) => Ok(it),
-            Err(e) => {
-                self.emit(e);
-                Err(ErrorEmitted { _private: () })
-            }
-        }
-    }
-
-    fn expand_result_option<T>(&mut self, res: ExpandResult<Option<T>>) -> Result<T, ErrorEmitted> {
-        match (res.value, res.err) {
-            (None, Some(err)) => {
-                self.emit(err);
-                Err(ErrorEmitted { _private: () })
-            }
-            (Some(value), opt_err) => {
-                if let Some(err) = opt_err {
-                    self.emit(err);
-                }
-                Ok(value)
-            }
-            (None, None) => unreachable!("`ExpandResult` without value or error"),
-        }
-    }
-}
-
-impl ErrorSink for &'_ mut dyn FnMut(mbe::ExpandError) {
-    fn emit(&mut self, err: mbe::ExpandError) {
-        self(err);
-    }
-}
-
-fn err(msg: impl Into<String>) -> mbe::ExpandError {
-    mbe::ExpandError::Other(msg.into())
-}
-
 pub fn expand_eager_macro(
     db: &dyn AstDatabase,
     krate: CrateId,
     macro_call: InFile<ast::MacroCall>,
     def: MacroDefId,
     resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
-    mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
-) -> Result<EagerMacroId, ErrorEmitted> {
-    let parsed_args = diagnostic_sink.option_with(
-        || Some(mbe::ast_to_token_tree(&macro_call.value.token_tree()?)?.0),
-        || err("malformed macro invocation"),
-    )?;
+) -> Option<EagerMacroId> {
+    let args = macro_call.value.token_tree()?;
+    let parsed_args = mbe::ast_to_token_tree(&args)?.0;
 
     // Note:
     // When `lazy_expand` is called, its *parent* file must be already exists.
@@ -125,22 +55,17 @@ pub fn expand_eager_macro(
     });
     let arg_file_id: MacroCallId = arg_id.into();
 
-    let parsed_args =
-        diagnostic_sink.result(mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr))?.0;
+    let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr).ok()?.0;
     let result = eager_macro_recur(
         db,
         InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
         krate,
         resolver,
-        diagnostic_sink,
     )?;
-    let subtree =
-        diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?;
+    let subtree = to_subtree(&result)?;
 
     if let MacroDefKind::BuiltInEager(eager) = def.kind {
-        let res = eager.expand(db, arg_id, &subtree);
-
-        let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?;
+        let (subtree, fragment) = eager.expand(db, arg_id, &subtree).value?;
         let eager = EagerCallLoc {
             def,
             fragment,
@@ -149,9 +74,9 @@ pub fn expand_eager_macro(
             file_id: macro_call.file_id,
         };
 
-        Ok(db.intern_eager_expansion(eager))
+        Some(db.intern_eager_expansion(eager))
     } else {
-        panic!("called `expand_eager_macro` on non-eager macro def {:?}", def);
+        None
     }
 }
 
@@ -166,16 +91,13 @@ fn lazy_expand(
     def: &MacroDefId,
     macro_call: InFile<ast::MacroCall>,
     krate: CrateId,
-) -> ExpandResult<Option<InFile<SyntaxNode>>> {
+) -> Option<InFile<SyntaxNode>> {
     let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
 
     let id: MacroCallId =
         def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
 
-    let err = db.macro_expand_error(id);
-    let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));
-
-    ExpandResult { value, err }
+    db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node))
 }
 
 fn eager_macro_recur(
@@ -183,8 +105,7 @@ fn eager_macro_recur(
     curr: InFile<SyntaxNode>,
     krate: CrateId,
     macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
-    mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
-) -> Result<SyntaxNode, ErrorEmitted> {
+) -> Option<SyntaxNode> {
     let original = curr.value.clone();
 
     let children = curr.value.descendants().filter_map(ast::MacroCall::cast);
@@ -192,8 +113,7 @@ fn eager_macro_recur(
 
     // Collect replacement
     for child in children {
-        let def = diagnostic_sink
-            .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?;
+        let def: MacroDefId = macro_resolver(child.path()?)?;
         let insert = match def.kind {
             MacroDefKind::BuiltInEager(_) => {
                 let id: MacroCallId = expand_eager_macro(
@@ -202,21 +122,17 @@ fn eager_macro_recur(
                     curr.with_value(child.clone()),
                     def,
                     macro_resolver,
-                    diagnostic_sink,
                 )?
                 .into();
-                db.parse_or_expand(id.as_file())
-                    .expect("successful macro expansion should be parseable")
+                db.parse_or_expand(id.as_file())?
             }
             MacroDefKind::Declarative
             | MacroDefKind::BuiltIn(_)
             | MacroDefKind::BuiltInDerive(_)
             | MacroDefKind::ProcMacro(_) => {
-                let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
-                let val = diagnostic_sink.expand_result_option(res)?;
-
+                let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?;
                 // replace macro inside
-                eager_macro_recur(db, val, krate, macro_resolver, diagnostic_sink)?
+                eager_macro_recur(db, expanded, krate, macro_resolver)?
             }
         };
 
@@ -224,5 +140,5 @@ fn eager_macro_recur(
     }
 
     let res = rewriter.rewrite(&original);
-    Ok(res)
+    Some(res)
 }
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 2633fd8f73..6dad2507bf 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -143,11 +143,7 @@ impl HirFileId {
                 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id);
 
                 let arg_tt = loc.kind.arg(db)?;
-
-                let def = loc.def.ast_id.and_then(|id| {
-                    let def_tt = id.to_node(db).token_tree()?;
-                    Some(InFile::new(id.file_id, def_tt))
-                });
+                let def_tt = loc.def.ast_id?.to_node(db).token_tree()?;
 
                 let macro_def = db.macro_def(loc.def)?;
                 let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?;
@@ -156,7 +152,7 @@ impl HirFileId {
                 Some(ExpansionInfo {
                     expanded: InFile::new(self, parse.syntax_node()),
                     arg: InFile::new(loc.kind.file_id(), arg_tt),
-                    def,
+                    def: InFile::new(loc.def.ast_id?.file_id, def_tt),
                     macro_arg,
                     macro_def,
                     exp_map,
@@ -315,8 +311,7 @@ pub struct EagerCallLoc {
 pub struct ExpansionInfo {
     expanded: InFile<SyntaxNode>,
     arg: InFile<SyntaxNode>,
-    /// The `macro_rules!` arguments.
-    def: Option<InFile<ast::TokenTree>>,
+    def: InFile<ast::TokenTree>,
 
     macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
     macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
@@ -353,14 +348,9 @@ impl ExpansionInfo {
         let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
         let (token_map, tt) = match origin {
             mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
-            mbe::Origin::Def => (
-                &self.macro_def.1,
-                self.def
-                    .as_ref()
-                    .expect("`Origin::Def` used with non-`macro_rules!` macro")
-                    .as_ref()
-                    .map(|tt| tt.syntax().clone()),
-            ),
+            mbe::Origin::Def => {
+                (&self.macro_def.1, self.def.as_ref().map(|tt| tt.syntax().clone()))
+            }
         };
 
         let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index c8453edb30..9d3d882895 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -135,11 +135,6 @@ pub(crate) fn diagnostics(
             res.borrow_mut().push(warning_with_fix(d, &sema));
         })
         .on::<hir::diagnostics::InactiveCode, _>(|d| {
-            // If there's inactive code somewhere in a macro, don't propagate to the call-site.
-            if d.display_source().file_id.expansion_info(db).is_some() {
-                return;
-            }
-
             // Override severity and mark as unused.
             res.borrow_mut().push(
                 Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 7523aec557..45170dd29d 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -83,7 +83,6 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
 fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
     match kind {
         COMMENT => Some(FoldKind::Comment),
-        USE => Some(FoldKind::Imports),
         ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
         ASSOC_ITEM_LIST
         | RECORD_FIELD_LIST
@@ -258,11 +257,11 @@ fn main() <fold block>{
     fn test_fold_imports() {
         check(
             r#"
-<fold imports>use std::<fold block>{
+use std::<fold block>{
     str,
     vec,
     io as iop
-}</fold>;</fold>
+}</fold>;
 
 fn main() <fold block>{
 }</fold>"#,
@@ -306,9 +305,9 @@ use std::io as iop;</fold>
 <fold imports>use std::mem;
 use std::f64;</fold>
 
-use std::collections::HashMap;
+<fold imports>use std::collections::HashMap;
 // Some random comment
-use std::collections::VecDeque;
+use std::collections::VecDeque;</fold>
 
 fn main() <fold block>{
 }</fold>"#,
@@ -326,10 +325,10 @@ use std::io as iop;</fold>
 <fold imports>use std::mem;
 use std::f64;</fold>
 
-<fold imports>use std::collections::<fold block>{
+use std::collections::<fold block>{
     HashMap,
     VecDeque,
-}</fold>;</fold>
+}</fold>;
 // Some random comment
 
 fn main() <fold block>{
diff --git a/crates/ide_db/src/call_info.rs b/crates/ide_db/src/call_info.rs
index 615fa7b0ee..83a602b9ad 100644
--- a/crates/ide_db/src/call_info.rs
+++ b/crates/ide_db/src/call_info.rs
@@ -228,4 +228,529 @@ impl FnCallNode {
 }
 
 #[cfg(test)]
-mod tests;
+mod tests {
+    use crate::RootDatabase;
+    use base_db::{fixture::ChangeFixture, FilePosition};
+    use expect_test::{expect, Expect};
+    use test_utils::{mark, RangeOrOffset};
+
+    /// Creates analysis from a multi-file fixture, returns positions marked with <|>.
+    pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
+        let change_fixture = ChangeFixture::parse(ra_fixture);
+        let mut database = RootDatabase::default();
+        database.apply_change(change_fixture.change);
+        let (file_id, range_or_offset) =
+            change_fixture.file_position.expect("expected a marker (<|>)");
+        let offset = match range_or_offset {
+            RangeOrOffset::Range(_) => panic!(),
+            RangeOrOffset::Offset(it) => it,
+        };
+        (database, FilePosition { file_id, offset })
+    }
+
+    fn check(ra_fixture: &str, expect: Expect) {
+        let (db, position) = position(ra_fixture);
+        let call_info = crate::call_info::call_info(&db, position);
+        let actual = match call_info {
+            Some(call_info) => {
+                let docs = match &call_info.doc {
+                    None => "".to_string(),
+                    Some(docs) => format!("{}\n------\n", docs.as_str()),
+                };
+                let params = call_info
+                    .parameter_labels()
+                    .enumerate()
+                    .map(|(i, param)| {
+                        if Some(i) == call_info.active_parameter {
+                            format!("<{}>", param)
+                        } else {
+                            param.to_string()
+                        }
+                    })
+                    .collect::<Vec<_>>()
+                    .join(", ");
+                format!("{}{}\n({})\n", docs, call_info.signature, params)
+            }
+            None => String::new(),
+        };
+        expect.assert_eq(&actual);
+    }
+
+    #[test]
+    fn test_fn_signature_two_args() {
+        check(
+            r#"
+fn foo(x: u32, y: u32) -> u32 {x + y}
+fn bar() { foo(<|>3, ); }
+"#,
+            expect![[r#"
+                fn foo(x: u32, y: u32) -> u32
+                (<x: u32>, y: u32)
+            "#]],
+        );
+        check(
+            r#"
+fn foo(x: u32, y: u32) -> u32 {x + y}
+fn bar() { foo(3<|>, ); }
+"#,
+            expect![[r#"
+                fn foo(x: u32, y: u32) -> u32
+                (<x: u32>, y: u32)
+            "#]],
+        );
+        check(
+            r#"
+fn foo(x: u32, y: u32) -> u32 {x + y}
+fn bar() { foo(3,<|> ); }
+"#,
+            expect![[r#"
+                fn foo(x: u32, y: u32) -> u32
+                (x: u32, <y: u32>)
+            "#]],
+        );
+        check(
+            r#"
+fn foo(x: u32, y: u32) -> u32 {x + y}
+fn bar() { foo(3, <|>); }
+"#,
+            expect![[r#"
+                fn foo(x: u32, y: u32) -> u32
+                (x: u32, <y: u32>)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_two_args_empty() {
+        check(
+            r#"
+fn foo(x: u32, y: u32) -> u32 {x + y}
+fn bar() { foo(<|>); }
+"#,
+            expect![[r#"
+                fn foo(x: u32, y: u32) -> u32
+                (<x: u32>, y: u32)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_two_args_first_generics() {
+        check(
+            r#"
+fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
+    where T: Copy + Display, U: Debug
+{ x + y }
+
+fn bar() { foo(<|>3, ); }
+"#,
+            expect![[r#"
+                fn foo(x: i32, y: {unknown}) -> u32
+                (<x: i32>, y: {unknown})
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_no_params() {
+        check(
+            r#"
+fn foo<T>() -> T where T: Copy + Display {}
+fn bar() { foo(<|>); }
+"#,
+            expect![[r#"
+                fn foo() -> {unknown}
+                ()
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_for_impl() {
+        check(
+            r#"
+struct F;
+impl F { pub fn new() { } }
+fn bar() {
+    let _ : F = F::new(<|>);
+}
+"#,
+            expect![[r#"
+                fn new()
+                ()
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_for_method_self() {
+        check(
+            r#"
+struct S;
+impl S { pub fn do_it(&self) {} }
+
+fn bar() {
+    let s: S = S;
+    s.do_it(<|>);
+}
+"#,
+            expect![[r#"
+                fn do_it(&self)
+                ()
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_for_method_with_arg() {
+        check(
+            r#"
+struct S;
+impl S {
+    fn foo(&self, x: i32) {}
+}
+
+fn main() { S.foo(<|>); }
+"#,
+            expect![[r#"
+                fn foo(&self, x: i32)
+                (<x: i32>)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
+        check(
+            r#"
+struct S;
+impl S {
+    fn foo(&self, x: i32) {}
+}
+
+fn main() { S::foo(<|>); }
+"#,
+            expect![[r#"
+                fn foo(self: &S, x: i32)
+                (<self: &S>, x: i32)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_with_docs_simple() {
+        check(
+            r#"
+/// test
+// non-doc-comment
+fn foo(j: u32) -> u32 {
+    j
+}
+
+fn bar() {
+    let _ = foo(<|>);
+}
+"#,
+            expect![[r#"
+                test
+                ------
+                fn foo(j: u32) -> u32
+                (<j: u32>)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_with_docs() {
+        check(
+            r#"
+/// Adds one to the number given.
+///
+/// # Examples
+///
+/// ```
+/// let five = 5;
+///
+/// assert_eq!(6, my_crate::add_one(5));
+/// ```
+pub fn add_one(x: i32) -> i32 {
+    x + 1
+}
+
+pub fn do() {
+    add_one(<|>
+}"#,
+            expect![[r##"
+                Adds one to the number given.
+
+                # Examples
+
+                ```
+                let five = 5;
+
+                assert_eq!(6, my_crate::add_one(5));
+                ```
+                ------
+                fn add_one(x: i32) -> i32
+                (<x: i32>)
+            "##]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_with_docs_impl() {
+        check(
+            r#"
+struct addr;
+impl addr {
+    /// Adds one to the number given.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let five = 5;
+    ///
+    /// assert_eq!(6, my_crate::add_one(5));
+    /// ```
+    pub fn add_one(x: i32) -> i32 {
+        x + 1
+    }
+}
+
+pub fn do_it() {
+    addr {};
+    addr::add_one(<|>);
+}
+"#,
+            expect![[r##"
+                Adds one to the number given.
+
+                # Examples
+
+                ```
+                let five = 5;
+
+                assert_eq!(6, my_crate::add_one(5));
+                ```
+                ------
+                fn add_one(x: i32) -> i32
+                (<x: i32>)
+            "##]],
+        );
+    }
+
+    #[test]
+    fn test_fn_signature_with_docs_from_actix() {
+        check(
+            r#"
+struct WriteHandler<E>;
+
+impl<E> WriteHandler<E> {
+    /// Method is called when writer emits error.
+    ///
+    /// If this method returns `ErrorAction::Continue` writer processing
+    /// continues otherwise stream processing stops.
+    fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
+        Running::Stop
+    }
+
+    /// Method is called when writer finishes.
+    ///
+    /// By default this method stops actor's `Context`.
+    fn finished(&mut self, ctx: &mut Self::Context) {
+        ctx.stop()
+    }
+}
+
+pub fn foo(mut r: WriteHandler<()>) {
+    r.finished(<|>);
+}
+"#,
+            expect![[r#"
+                Method is called when writer finishes.
+
+                By default this method stops actor's `Context`.
+                ------
+                fn finished(&mut self, ctx: &mut {unknown})
+                (<ctx: &mut {unknown}>)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn call_info_bad_offset() {
+        mark::check!(call_info_bad_offset);
+        check(
+            r#"
+fn foo(x: u32, y: u32) -> u32 {x + y}
+fn bar() { foo <|> (3, ); }
+"#,
+            expect![[""]],
+        );
+    }
+
+    #[test]
+    fn test_nested_method_in_lambda() {
+        check(
+            r#"
+struct Foo;
+impl Foo { fn bar(&self, _: u32) { } }
+
+fn bar(_: u32) { }
+
+fn main() {
+    let foo = Foo;
+    std::thread::spawn(move || foo.bar(<|>));
+}
+"#,
+            expect![[r#"
+                fn bar(&self, _: u32)
+                (<_: u32>)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn works_for_tuple_structs() {
+        check(
+            r#"
+/// A cool tuple struct
+struct S(u32, i32);
+fn main() {
+    let s = S(0, <|>);
+}
+"#,
+            expect![[r#"
+                A cool tuple struct
+                ------
+                struct S(u32, i32)
+                (u32, <i32>)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn generic_struct() {
+        check(
+            r#"
+struct S<T>(T);
+fn main() {
+    let s = S(<|>);
+}
+"#,
+            expect![[r#"
+                struct S({unknown})
+                (<{unknown}>)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn works_for_enum_variants() {
+        check(
+            r#"
+enum E {
+    /// A Variant
+    A(i32),
+    /// Another
+    B,
+    /// And C
+    C { a: i32, b: i32 }
+}
+
+fn main() {
+    let a = E::A(<|>);
+}
+"#,
+            expect![[r#"
+                A Variant
+                ------
+                enum E::A(i32)
+                (<i32>)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn cant_call_struct_record() {
+        check(
+            r#"
+struct S { x: u32, y: i32 }
+fn main() {
+    let s = S(<|>);
+}
+"#,
+            expect![[""]],
+        );
+    }
+
+    #[test]
+    fn cant_call_enum_record() {
+        check(
+            r#"
+enum E {
+    /// A Variant
+    A(i32),
+    /// Another
+    B,
+    /// And C
+    C { a: i32, b: i32 }
+}
+
+fn main() {
+    let a = E::C(<|>);
+}
+"#,
+            expect![[""]],
+        );
+    }
+
+    #[test]
+    fn fn_signature_for_call_in_macro() {
+        check(
+            r#"
+macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
+fn foo() { }
+id! {
+    fn bar() { foo(<|>); }
+}
+"#,
+            expect![[r#"
+                fn foo()
+                ()
+            "#]],
+        );
+    }
+
+    #[test]
+    fn call_info_for_lambdas() {
+        check(
+            r#"
+struct S;
+fn foo(s: S) -> i32 { 92 }
+fn main() {
+    (|s| foo(s))(<|>)
+}
+        "#,
+            expect![[r#"
+                (S) -> i32
+                (<S>)
+            "#]],
+        )
+    }
+
+    #[test]
+    fn call_info_for_fn_ptr() {
+        check(
+            r#"
+fn main(f: fn(i32, f64) -> char) {
+    f(0, <|>)
+}
+        "#,
+            expect![[r#"
+                (i32, f64) -> char
+                (i32, <f64>)
+            "#]],
+        )
+    }
+}
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 040843990d..08d246c167 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -573,4 +573,641 @@ fn find_insert_position(
 }
 
 #[cfg(test)]
-mod tests;
+mod tests {
+    use super::*;
+
+    use test_utils::assert_eq_text;
+
+    #[test]
+    fn insert_existing() {
+        check_full("std::fs", "use std::fs;", "use std::fs;")
+    }
+
+    #[test]
+    fn insert_start() {
+        check_none(
+            "std::bar::AA",
+            r"
+use std::bar::B;
+use std::bar::D;
+use std::bar::F;
+use std::bar::G;",
+            r"
+use std::bar::AA;
+use std::bar::B;
+use std::bar::D;
+use std::bar::F;
+use std::bar::G;",
+        )
+    }
+
+    #[test]
+    fn insert_start_indent() {
+        mark::check!(insert_use_indent_after);
+        check_none(
+            "std::bar::AA",
+            r"
+    use std::bar::B;
+    use std::bar::D;",
+            r"
+    use std::bar::AA;
+    use std::bar::B;
+    use std::bar::D;",
+        )
+    }
+
+    #[test]
+    fn insert_middle() {
+        check_none(
+            "std::bar::EE",
+            r"
+use std::bar::A;
+use std::bar::D;
+use std::bar::F;
+use std::bar::G;",
+            r"
+use std::bar::A;
+use std::bar::D;
+use std::bar::EE;
+use std::bar::F;
+use std::bar::G;",
+        )
+    }
+
+    #[test]
+    fn insert_middle_indent() {
+        check_none(
+            "std::bar::EE",
+            r"
+    use std::bar::A;
+    use std::bar::D;
+    use std::bar::F;
+    use std::bar::G;",
+            r"
+    use std::bar::A;
+    use std::bar::D;
+    use std::bar::EE;
+    use std::bar::F;
+    use std::bar::G;",
+        )
+    }
+
+    #[test]
+    fn insert_end() {
+        check_none(
+            "std::bar::ZZ",
+            r"
+use std::bar::A;
+use std::bar::D;
+use std::bar::F;
+use std::bar::G;",
+            r"
+use std::bar::A;
+use std::bar::D;
+use std::bar::F;
+use std::bar::G;
+use std::bar::ZZ;",
+        )
+    }
+
+    #[test]
+    fn insert_end_indent() {
+        mark::check!(insert_use_indent_before);
+        check_none(
+            "std::bar::ZZ",
+            r"
+    use std::bar::A;
+    use std::bar::D;
+    use std::bar::F;
+    use std::bar::G;",
+            r"
+    use std::bar::A;
+    use std::bar::D;
+    use std::bar::F;
+    use std::bar::G;
+    use std::bar::ZZ;",
+        )
+    }
+
+    #[test]
+    fn insert_middle_nested() {
+        check_none(
+            "std::bar::EE",
+            r"
+use std::bar::A;
+use std::bar::{D, Z}; // example of weird imports due to user
+use std::bar::F;
+use std::bar::G;",
+            r"
+use std::bar::A;
+use std::bar::EE;
+use std::bar::{D, Z}; // example of weird imports due to user
+use std::bar::F;
+use std::bar::G;",
+        )
+    }
+
+    #[test]
+    fn insert_middle_groups() {
+        check_none(
+            "foo::bar::GG",
+            r"
+    use std::bar::A;
+    use std::bar::D;
+
+    use foo::bar::F;
+    use foo::bar::H;",
+            r"
+    use std::bar::A;
+    use std::bar::D;
+
+    use foo::bar::F;
+    use foo::bar::GG;
+    use foo::bar::H;",
+        )
+    }
+
+    #[test]
+    fn insert_first_matching_group() {
+        check_none(
+            "foo::bar::GG",
+            r"
+    use foo::bar::A;
+    use foo::bar::D;
+
+    use std;
+
+    use foo::bar::F;
+    use foo::bar::H;",
+            r"
+    use foo::bar::A;
+    use foo::bar::D;
+    use foo::bar::GG;
+
+    use std;
+
+    use foo::bar::F;
+    use foo::bar::H;",
+        )
+    }
+
+    #[test]
+    fn insert_missing_group_std() {
+        check_none(
+            "std::fmt",
+            r"
+    use foo::bar::A;
+    use foo::bar::D;",
+            r"
+    use std::fmt;
+
+    use foo::bar::A;
+    use foo::bar::D;",
+        )
+    }
+
+    #[test]
+    fn insert_missing_group_self() {
+        check_none(
+            "self::fmt",
+            r"
+use foo::bar::A;
+use foo::bar::D;",
+            r"
+use foo::bar::A;
+use foo::bar::D;
+
+use self::fmt;",
+        )
+    }
+
+    #[test]
+    fn insert_no_imports() {
+        check_full(
+            "foo::bar",
+            "fn main() {}",
+            r"use foo::bar;
+
+fn main() {}",
+        )
+    }
+
+    #[test]
+    fn insert_empty_file() {
+        // empty files will get two trailing newlines
+        // this is due to the test case insert_no_imports above
+        check_full(
+            "foo::bar",
+            "",
+            r"use foo::bar;
+
+",
+        )
+    }
+
+    #[test]
+    fn insert_empty_module() {
+        mark::check!(insert_use_no_indent_after);
+        check(
+            "foo::bar",
+            "mod x {}",
+            r"{
+    use foo::bar;
+}",
+            None,
+            true,
+        )
+    }
+
+    #[test]
+    fn insert_after_inner_attr() {
+        check_full(
+            "foo::bar",
+            r"#![allow(unused_imports)]",
+            r"#![allow(unused_imports)]
+
+use foo::bar;",
+        )
+    }
+
+    #[test]
+    fn insert_after_inner_attr2() {
+        check_full(
+            "foo::bar",
+            r"#![allow(unused_imports)]
+
+#![no_std]
+fn main() {}",
+            r"#![allow(unused_imports)]
+
+#![no_std]
+
+use foo::bar;
+fn main() {}",
+        );
+    }
+
+    #[test]
+    fn inserts_after_single_line_inner_comments() {
+        check_none(
+            "foo::bar::Baz",
+            "//! Single line inner comments do not allow any code before them.",
+            r#"//! Single line inner comments do not allow any code before them.
+
+use foo::bar::Baz;"#,
+        );
+    }
+
+    #[test]
+    fn inserts_after_multiline_inner_comments() {
+        check_none(
+            "foo::bar::Baz",
+            r#"/*! Multiline inner comments do not allow any code before them. */
+
+/*! Still an inner comment, cannot place any code before. */
+fn main() {}"#,
+            r#"/*! Multiline inner comments do not allow any code before them. */
+
+/*! Still an inner comment, cannot place any code before. */
+
+use foo::bar::Baz;
+fn main() {}"#,
+        )
+    }
+
+    #[test]
+    fn inserts_after_all_inner_items() {
+        check_none(
+            "foo::bar::Baz",
+            r#"#![allow(unused_imports)]
+/*! Multiline line comment 2 */
+
+
+//! Single line comment 1
+#![no_std]
+//! Single line comment 2
+fn main() {}"#,
+            r#"#![allow(unused_imports)]
+/*! Multiline line comment 2 */
+
+
+//! Single line comment 1
+#![no_std]
+//! Single line comment 2
+
+use foo::bar::Baz;
+fn main() {}"#,
+        )
+    }
+
+    #[test]
+    fn merge_groups() {
+        check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};")
+    }
+
+    #[test]
+    fn merge_groups_last() {
+        check_last(
+            "std::io",
+            r"use std::fmt::{Result, Display};",
+            r"use std::fmt::{Result, Display};
+use std::io;",
+        )
+    }
+
+    #[test]
+    fn merge_last_into_self() {
+        check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
+    }
+
+    #[test]
+    fn merge_groups_full() {
+        check_full(
+            "std::io",
+            r"use std::fmt::{Result, Display};",
+            r"use std::{fmt::{Result, Display}, io};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_long_full() {
+        check_full(
+            "std::foo::bar::Baz",
+            r"use std::foo::bar::Qux;",
+            r"use std::foo::bar::{Baz, Qux};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_long_last() {
+        check_last(
+            "std::foo::bar::Baz",
+            r"use std::foo::bar::Qux;",
+            r"use std::foo::bar::{Baz, Qux};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_long_full_list() {
+        check_full(
+            "std::foo::bar::Baz",
+            r"use std::foo::bar::{Qux, Quux};",
+            r"use std::foo::bar::{Baz, Quux, Qux};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_long_last_list() {
+        check_last(
+            "std::foo::bar::Baz",
+            r"use std::foo::bar::{Qux, Quux};",
+            r"use std::foo::bar::{Baz, Quux, Qux};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_long_full_nested() {
+        check_full(
+            "std::foo::bar::Baz",
+            r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
+            r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_long_last_nested() {
+        check_last(
+            "std::foo::bar::Baz",
+            r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
+            r"use std::foo::bar::Baz;
+use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_full_nested_deep() {
+        check_full(
+            "std::foo::bar::quux::Baz",
+            r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
+            r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_full_nested_long() {
+        check_full(
+            "std::foo::bar::Baz",
+            r"use std::{foo::bar::Qux};",
+            r"use std::{foo::bar::{Baz, Qux}};",
+        );
+    }
+
+    #[test]
+    fn merge_groups_last_nested_long() {
+        check_full(
+            "std::foo::bar::Baz",
+            r"use std::{foo::bar::Qux};",
+            r"use std::{foo::bar::{Baz, Qux}};",
+        );
+    }
+
+    #[test]
+    fn merge_groups_skip_pub() {
+        check_full(
+            "std::io",
+            r"pub use std::fmt::{Result, Display};",
+            r"pub use std::fmt::{Result, Display};
+use std::io;",
+        )
+    }
+
+    #[test]
+    fn merge_groups_skip_pub_crate() {
+        check_full(
+            "std::io",
+            r"pub(crate) use std::fmt::{Result, Display};",
+            r"pub(crate) use std::fmt::{Result, Display};
+use std::io;",
+        )
+    }
+
+    #[test]
+    #[ignore] // FIXME: Support this
+    fn split_out_merge() {
+        check_last(
+            "std::fmt::Result",
+            r"use std::{fmt, io};",
+            r"use std::fmt::{self, Result};
+use std::io;",
+        )
+    }
+
+    #[test]
+    fn merge_into_module_import() {
+        check_full(
+            "std::fmt::Result",
+            r"use std::{fmt, io};",
+            r"use std::{fmt::{self, Result}, io};",
+        )
+    }
+
+    #[test]
+    fn merge_groups_self() {
+        check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
+    }
+
+    #[test]
+    fn merge_mod_into_glob() {
+        check_full(
+            "token::TokenKind",
+            r"use token::TokenKind::*;",
+            r"use token::TokenKind::{*, self};",
+        )
+        // FIXME: have it emit `use token::TokenKind::{self, *}`?
+    }
+
+    #[test]
+    fn merge_self_glob() {
+        check_full("self", r"use self::*;", r"use self::{*, self};")
+        // FIXME: have it emit `use {self, *}`?
+    }
+
+    #[test]
+    fn merge_glob_nested() {
+        check_full(
+            "foo::bar::quux::Fez",
+            r"use foo::bar::{Baz, quux::*};",
+            r"use foo::bar::{Baz, quux::{self::*, Fez}};",
+        )
+    }
+
+    #[test]
+    fn merge_nested_considers_first_segments() {
+        check_full(
+            "hir_ty::display::write_bounds_like_dyn_trait",
+            r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};",
+            r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};",
+        );
+    }
+
+    #[test]
+    fn skip_merge_last_too_long() {
+        check_last(
+            "foo::bar",
+            r"use foo::bar::baz::Qux;",
+            r"use foo::bar;
+use foo::bar::baz::Qux;",
+        );
+    }
+
+    #[test]
+    fn skip_merge_last_too_long2() {
+        check_last(
+            "foo::bar::baz::Qux",
+            r"use foo::bar;",
+            r"use foo::bar;
+use foo::bar::baz::Qux;",
+        );
+    }
+
+    #[test]
+    fn insert_short_before_long() {
+        check_none(
+            "foo::bar",
+            r"use foo::bar::baz::Qux;",
+            r"use foo::bar;
+use foo::bar::baz::Qux;",
+        );
+    }
+
+    #[test]
+    fn merge_last_fail() {
+        check_merge_only_fail(
+            r"use foo::bar::{baz::{Qux, Fez}};",
+            r"use foo::bar::{baaz::{Quux, Feez}};",
+            MergeBehaviour::Last,
+        );
+    }
+
+    #[test]
+    fn merge_last_fail1() {
+        check_merge_only_fail(
+            r"use foo::bar::{baz::{Qux, Fez}};",
+            r"use foo::bar::baaz::{Quux, Feez};",
+            MergeBehaviour::Last,
+        );
+    }
+
+    #[test]
+    fn merge_last_fail2() {
+        check_merge_only_fail(
+            r"use foo::bar::baz::{Qux, Fez};",
+            r"use foo::bar::{baaz::{Quux, Feez}};",
+            MergeBehaviour::Last,
+        );
+    }
+
+    #[test]
+    fn merge_last_fail3() {
+        check_merge_only_fail(
+            r"use foo::bar::baz::{Qux, Fez};",
+            r"use foo::bar::baaz::{Quux, Feez};",
+            MergeBehaviour::Last,
+        );
+    }
+
+    fn check(
+        path: &str,
+        ra_fixture_before: &str,
+        ra_fixture_after: &str,
+        mb: Option<MergeBehaviour>,
+        module: bool,
+    ) {
+        let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
+        if module {
+            syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone();
+        }
+        let file = super::ImportScope::from(syntax).unwrap();
+        let path = ast::SourceFile::parse(&format!("use {};", path))
+            .tree()
+            .syntax()
+            .descendants()
+            .find_map(ast::Path::cast)
+            .unwrap();
+
+        let rewriter = insert_use(&file, path, mb);
+        let result = rewriter.rewrite(file.as_syntax_node()).to_string();
+        assert_eq_text!(&result, ra_fixture_after);
+    }
+
+    fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+        check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full), false)
+    }
+
+    fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+        check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last), false)
+    }
+
+    fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
+        check(path, ra_fixture_before, ra_fixture_after, None, false)
+    }
+
+    fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) {
+        let use0 = ast::SourceFile::parse(ra_fixture0)
+            .tree()
+            .syntax()
+            .descendants()
+            .find_map(ast::Use::cast)
+            .unwrap();
+
+        let use1 = ast::SourceFile::parse(ra_fixture1)
+            .tree()
+            .syntax()
+            .descendants()
+            .find_map(ast::Use::cast)
+            .unwrap();
+
+        let result = try_merge_imports(&use0, &use1, mb);
+        assert_eq!(result.map(|u| u.to_string()), None);
+    }
+}
diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs
index 41226305ea..a381f7fb8d 100644
--- a/crates/ide_db/src/line_index.rs
+++ b/crates/ide_db/src/line_index.rs
@@ -149,4 +149,133 @@ impl LineIndex {
 }
 
 #[cfg(test)]
-mod tests;
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_line_index() {
+        let text = "hello\nworld";
+        let index = LineIndex::new(text);
+        assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
+        assert_eq!(index.line_col(1.into()), LineCol { line: 0, col_utf16: 1 });
+        assert_eq!(index.line_col(5.into()), LineCol { line: 0, col_utf16: 5 });
+        assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 0 });
+        assert_eq!(index.line_col(7.into()), LineCol { line: 1, col_utf16: 1 });
+        assert_eq!(index.line_col(8.into()), LineCol { line: 1, col_utf16: 2 });
+        assert_eq!(index.line_col(10.into()), LineCol { line: 1, col_utf16: 4 });
+        assert_eq!(index.line_col(11.into()), LineCol { line: 1, col_utf16: 5 });
+        assert_eq!(index.line_col(12.into()), LineCol { line: 1, col_utf16: 6 });
+
+        let text = "\nhello\nworld";
+        let index = LineIndex::new(text);
+        assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
+        assert_eq!(index.line_col(1.into()), LineCol { line: 1, col_utf16: 0 });
+        assert_eq!(index.line_col(2.into()), LineCol { line: 1, col_utf16: 1 });
+        assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 5 });
+        assert_eq!(index.line_col(7.into()), LineCol { line: 2, col_utf16: 0 });
+    }
+
+    #[test]
+    fn test_char_len() {
+        assert_eq!('メ'.len_utf8(), 3);
+        assert_eq!('メ'.len_utf16(), 1);
+    }
+
+    #[test]
+    fn test_empty_index() {
+        let col_index = LineIndex::new(
+            "
+const C: char = 'x';
+",
+        );
+        assert_eq!(col_index.utf16_lines.len(), 0);
+    }
+
+    #[test]
+    fn test_single_char() {
+        let col_index = LineIndex::new(
+            "
+const C: char = 'メ';
+",
+        );
+
+        assert_eq!(col_index.utf16_lines.len(), 1);
+        assert_eq!(col_index.utf16_lines[&1].len(), 1);
+        assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
+
+        // UTF-8 to UTF-16, no changes
+        assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
+
+        // UTF-8 to UTF-16
+        assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
+
+        // UTF-16 to UTF-8, no changes
+        assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
+
+        // UTF-16 to UTF-8
+        assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21));
+
+        let col_index = LineIndex::new("a𐐏b");
+        assert_eq!(col_index.utf16_to_utf8_col(0, 3), TextSize::from(5));
+    }
+
+    #[test]
+    fn test_string() {
+        let col_index = LineIndex::new(
+            "
+const C: char = \"メ メ\";
+",
+        );
+
+        assert_eq!(col_index.utf16_lines.len(), 1);
+        assert_eq!(col_index.utf16_lines[&1].len(), 2);
+        assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
+        assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() });
+
+        // UTF-8 to UTF-16
+        assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
+
+        assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19);
+        assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21);
+
+        assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
+
+        // UTF-16 to UTF-8
+        assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
+
+        // メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1
+        assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20
+        assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space
+        assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24
+
+        assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15));
+    }
+
+    #[test]
+    fn test_splitlines() {
+        fn r(lo: u32, hi: u32) -> TextRange {
+            TextRange::new(lo.into(), hi.into())
+        }
+
+        let text = "a\nbb\nccc\n";
+        let line_index = LineIndex::new(text);
+
+        let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>();
+        let expected = vec![r(0, 2), r(2, 5), r(5, 9)];
+        assert_eq!(actual, expected);
+
+        let text = "";
+        let line_index = LineIndex::new(text);
+
+        let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>();
+        let expected = vec![];
+        assert_eq!(actual, expected);
+
+        let text = "\n";
+        let line_index = LineIndex::new(text);
+
+        let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>();
+        let expected = vec![r(0, 1)];
+        assert_eq!(actual, expected)
+    }
+}
diff --git a/crates/ide_db/src/traits.rs b/crates/ide_db/src/traits.rs
index 78a43f587a..f57b6dd91e 100644
--- a/crates/ide_db/src/traits.rs
+++ b/crates/ide_db/src/traits.rs
@@ -78,4 +78,150 @@ pub fn get_missing_assoc_items(
 }
 
 #[cfg(test)]
-mod tests;
+mod tests {
+    use crate::RootDatabase;
+    use base_db::{fixture::ChangeFixture, FilePosition};
+    use expect_test::{expect, Expect};
+    use hir::Semantics;
+    use syntax::ast::{self, AstNode};
+    use test_utils::RangeOrOffset;
+
+    /// Creates analysis from a multi-file fixture, returns positions marked with <|>.
+    pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
+        let change_fixture = ChangeFixture::parse(ra_fixture);
+        let mut database = RootDatabase::default();
+        database.apply_change(change_fixture.change);
+        let (file_id, range_or_offset) =
+            change_fixture.file_position.expect("expected a marker (<|>)");
+        let offset = match range_or_offset {
+            RangeOrOffset::Range(_) => panic!(),
+            RangeOrOffset::Offset(it) => it,
+        };
+        (database, FilePosition { file_id, offset })
+    }
+
+    fn check_trait(ra_fixture: &str, expect: Expect) {
+        let (db, position) = position(ra_fixture);
+        let sema = Semantics::new(&db);
+        let file = sema.parse(position.file_id);
+        let impl_block: ast::Impl =
+            sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
+        let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
+        let actual = match trait_ {
+            Some(trait_) => trait_.name(&db).to_string(),
+            None => String::new(),
+        };
+        expect.assert_eq(&actual);
+    }
+
+    fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
+        let (db, position) = position(ra_fixture);
+        let sema = Semantics::new(&db);
+        let file = sema.parse(position.file_id);
+        let impl_block: ast::Impl =
+            sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
+        let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
+        let actual = items
+            .into_iter()
+            .map(|item| item.name(&db).unwrap().to_string())
+            .collect::<Vec<_>>()
+            .join("\n");
+        expect.assert_eq(&actual);
+    }
+
+    #[test]
+    fn resolve_trait() {
+        check_trait(
+            r#"
+pub trait Foo {
+    fn bar();
+}
+impl Foo for u8 {
+    <|>
+}
+            "#,
+            expect![["Foo"]],
+        );
+        check_trait(
+            r#"
+pub trait Foo {
+    fn bar();
+}
+impl Foo for u8 {
+    fn bar() {
+        fn baz() {
+            <|>
+        }
+        baz();
+    }
+}
+            "#,
+            expect![["Foo"]],
+        );
+        check_trait(
+            r#"
+pub trait Foo {
+    fn bar();
+}
+pub struct Bar;
+impl Bar {
+    <|>
+}
+            "#,
+            expect![[""]],
+        );
+    }
+
+    #[test]
+    fn missing_assoc_items() {
+        check_missing_assoc(
+            r#"
+pub trait Foo {
+    const FOO: u8;
+    fn bar();
+}
+impl Foo for u8 {
+    <|>
+}"#,
+            expect![[r#"
+                FOO
+                bar"#]],
+        );
+
+        check_missing_assoc(
+            r#"
+pub trait Foo {
+    const FOO: u8;
+    fn bar();
+}
+impl Foo for u8 {
+    const FOO: u8 = 10;
+    <|>
+}"#,
+            expect![[r#"
+                bar"#]],
+        );
+
+        check_missing_assoc(
+            r#"
+pub trait Foo {
+    const FOO: u8;
+    fn bar();
+}
+impl Foo for u8 {
+    const FOO: u8 = 10;
+    fn bar() {<|>}
+}"#,
+            expect![[r#""#]],
+        );
+
+        check_missing_assoc(
+            r#"
+pub struct Foo;
+impl Foo {
+    fn bar() {<|>}
+}"#,
+            expect![[r#""#]],
+        );
+    }
+}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 55d46b09e7..f349b08103 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -506,7 +506,7 @@ impl GlobalState {
                         .write()
                         .0
                         .set_file_contents(path, Some(params.text_document.text.into_bytes()));
-                    this.maybe_update_diagnostics();
+                    this.update_file_notifications_on_threadpool();
                 }
                 Ok(())
             })?
@@ -616,23 +616,6 @@ impl GlobalState {
         Ok(())
     }
     fn update_file_notifications_on_threadpool(&mut self) {
-        self.maybe_update_diagnostics();
-        self.task_pool.handle.spawn_with_sender({
-            let snap = self.snapshot();
-            move |sender| {
-                snap.analysis
-                    .prime_caches(|progress| {
-                        sender.send(Task::PrimeCaches(progress)).unwrap();
-                    })
-                    .unwrap_or_else(|_: Canceled| {
-                        // Pretend that we're done, so that the progress bar is removed. Otherwise
-                        // the editor may complain about it already existing.
-                        sender.send(Task::PrimeCaches(PrimeCachesProgress::Finished)).unwrap()
-                    });
-            }
-        });
-    }
-    fn maybe_update_diagnostics(&mut self) {
         let subscriptions = self
             .mem_docs
             .keys()
@@ -661,5 +644,19 @@ impl GlobalState {
                 Task::Diagnostics(diagnostics)
             })
         }
+        self.task_pool.handle.spawn_with_sender({
+            let snap = self.snapshot();
+            move |sender| {
+                snap.analysis
+                    .prime_caches(|progress| {
+                        sender.send(Task::PrimeCaches(progress)).unwrap();
+                    })
+                    .unwrap_or_else(|_: Canceled| {
+                        // Pretend that we're done, so that the progress bar is removed. Otherwise
+                        // the editor may complain about it already existing.
+                        sender.send(Task::PrimeCaches(PrimeCachesProgress::Finished)).unwrap()
+                    });
+            }
+        });
     }
 }
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index b70b840b81..aa3a4b6065 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -477,3 +477,4 @@ impl ast::DocCommentsOwner for ast::Const {}
 impl ast::DocCommentsOwner for ast::TypeAlias {}
 impl ast::DocCommentsOwner for ast::Impl {}
 impl ast::DocCommentsOwner for ast::MacroCall {}
+impl ast::DocCommentsOwner for ast::Use {}
diff --git a/crates/syntax/src/parsing/text_tree_sink.rs b/crates/syntax/src/parsing/text_tree_sink.rs
index 997bc5d288..49842177a8 100644
--- a/crates/syntax/src/parsing/text_tree_sink.rs
+++ b/crates/syntax/src/parsing/text_tree_sink.rs
@@ -148,7 +148,7 @@ fn n_attached_trivias<'a>(
 ) -> usize {
     match kind {
         MACRO_CALL | CONST | TYPE_ALIAS | STRUCT | ENUM | VARIANT | FN | TRAIT | MODULE
-        | RECORD_FIELD | STATIC => {
+        | RECORD_FIELD | STATIC | USE => {
             let mut res = 0;
             let mut trivias = trivias.enumerate().peekable();
 
diff --git a/docs/dev/README.md b/docs/dev/README.md
index ca324493f5..abb387e8ef 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -170,22 +170,6 @@ In general, API is centered around UI concerns -- the result of the call is what
 The results are 100% Rust specific though.
 Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at.
 
-## LSP is sateless
-
-The protocol is implemented in the mostly stateless way.
-A good mental model is HTTP, which doesn't store per-client state, and instead relies on devices like cookies to maintain an illusion of state.
-If some action requires multi-step protocol, each step should be self-contained.
-
-A good example here is code action resolving process.
-TO display the lightbulb, we compute the list of code actions without computing edits.
-Figuring out the edit is done in a separate `codeAction/resolve` call.
-Rather than storing some `lazy_edit: Box<dyn FnOnce() -> Edit>` somewhere, we use a string ID of action to re-compute the list of actions during the resolve process.
-(See [this post](https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html) for more details.)
-The benefit here is that, generally speaking, the state of the world might change between `codeAction` and `codeAction` resolve requests, so any closure we store might become invalid.
-
-While we don't currently implement any complicated refactors with complex GUI, I imagine we'd use the same techniques for refactors.
-After clicking each "Next" button during refactor, the client would send all the info which server needs to re-recreate the context from scratch.
-
 ## CI
 
 CI does not test rust-analyzer, CI is a core part of rust-analyzer, and is maintained with above average standard of quality.


Test patch:
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index 6dba9817d4..baf1179f1f 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -78,41 +78,21 @@ fn f() {
 fn macro_diag_builtin() {
     check_diagnostics(
         r#"
-#[rustc_builtin_macro]
-macro_rules! env {}
-
-#[rustc_builtin_macro]
-macro_rules! include {}
-
-#[rustc_builtin_macro]
-macro_rules! compile_error {}
-
-#[rustc_builtin_macro]
-macro_rules! format_args {
-    () => {}
-}
-
 fn f() {
     // Test a handful of built-in (eager) macros:
 
     include!(invalid);
-  //^^^^^^^^^^^^^^^^^ could not convert tokens
+  //^^^^^^^^^^^^^^^^^ failed to parse or resolve macro invocation
     include!("does not exist");
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to parse or resolve macro invocation
 
     env!(invalid);
-  //^^^^^^^^^^^^^ could not convert tokens
-
-    env!("OUT_DIR");
-  //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix
-
-    compile_error!("compile_error works");
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
+  //^^^^^^^^^^^^^ failed to parse or resolve macro invocation
 
     // Lazy:
 
     format_args!();
-  //^^^^^^^^^^^^^^ no rule matches input tokens
+  //^^^^^^^^^^^^^^ failed to parse or resolve macro invocation
 }
         "#,
     );
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs
deleted file mode 100644
index 9335aeaa5f..0000000000
--- a/crates/ide_db/src/call_info/tests.rs
+++ /dev/null
@@ -1,523 +0,0 @@
-use crate::RootDatabase;
-use base_db::{fixture::ChangeFixture, FilePosition};
-use expect_test::{expect, Expect};
-use test_utils::{mark, RangeOrOffset};
-
-/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
-pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
-    let change_fixture = ChangeFixture::parse(ra_fixture);
-    let mut database = RootDatabase::default();
-    database.apply_change(change_fixture.change);
-    let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
-    let offset = match range_or_offset {
-        RangeOrOffset::Range(_) => panic!(),
-        RangeOrOffset::Offset(it) => it,
-    };
-    (database, FilePosition { file_id, offset })
-}
-
-fn check(ra_fixture: &str, expect: Expect) {
-    let (db, position) = position(ra_fixture);
-    let call_info = crate::call_info::call_info(&db, position);
-    let actual = match call_info {
-        Some(call_info) => {
-            let docs = match &call_info.doc {
-                None => "".to_string(),
-                Some(docs) => format!("{}\n------\n", docs.as_str()),
-            };
-            let params = call_info
-                .parameter_labels()
-                .enumerate()
-                .map(|(i, param)| {
-                    if Some(i) == call_info.active_parameter {
-                        format!("<{}>", param)
-                    } else {
-                        param.to_string()
-                    }
-                })
-                .collect::<Vec<_>>()
-                .join(", ");
-            format!("{}{}\n({})\n", docs, call_info.signature, params)
-        }
-        None => String::new(),
-    };
-    expect.assert_eq(&actual);
-}
-
-#[test]
-fn test_fn_signature_two_args() {
-    check(
-        r#"
-fn foo(x: u32, y: u32) -> u32 {x + y}
-fn bar() { foo(<|>3, ); }
-"#,
-        expect![[r#"
-                fn foo(x: u32, y: u32) -> u32
-                (<x: u32>, y: u32)
-            "#]],
-    );
-    check(
-        r#"
-fn foo(x: u32, y: u32) -> u32 {x + y}
-fn bar() { foo(3<|>, ); }
-"#,
-        expect![[r#"
-                fn foo(x: u32, y: u32) -> u32
-                (<x: u32>, y: u32)
-            "#]],
-    );
-    check(
-        r#"
-fn foo(x: u32, y: u32) -> u32 {x + y}
-fn bar() { foo(3,<|> ); }
-"#,
-        expect![[r#"
-                fn foo(x: u32, y: u32) -> u32
-                (x: u32, <y: u32>)
-            "#]],
-    );
-    check(
-        r#"
-fn foo(x: u32, y: u32) -> u32 {x + y}
-fn bar() { foo(3, <|>); }
-"#,
-        expect![[r#"
-                fn foo(x: u32, y: u32) -> u32
-                (x: u32, <y: u32>)
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_two_args_empty() {
-    check(
-        r#"
-fn foo(x: u32, y: u32) -> u32 {x + y}
-fn bar() { foo(<|>); }
-"#,
-        expect![[r#"
-                fn foo(x: u32, y: u32) -> u32
-                (<x: u32>, y: u32)
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_two_args_first_generics() {
-    check(
-        r#"
-fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
-    where T: Copy + Display, U: Debug
-{ x + y }
-
-fn bar() { foo(<|>3, ); }
-"#,
-        expect![[r#"
-                fn foo(x: i32, y: {unknown}) -> u32
-                (<x: i32>, y: {unknown})
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_no_params() {
-    check(
-        r#"
-fn foo<T>() -> T where T: Copy + Display {}
-fn bar() { foo(<|>); }
-"#,
-        expect![[r#"
-                fn foo() -> {unknown}
-                ()
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_for_impl() {
-    check(
-        r#"
-struct F;
-impl F { pub fn new() { } }
-fn bar() {
-    let _ : F = F::new(<|>);
-}
-"#,
-        expect![[r#"
-                fn new()
-                ()
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_for_method_self() {
-    check(
-        r#"
-struct S;
-impl S { pub fn do_it(&self) {} }
-
-fn bar() {
-    let s: S = S;
-    s.do_it(<|>);
-}
-"#,
-        expect![[r#"
-                fn do_it(&self)
-                ()
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_for_method_with_arg() {
-    check(
-        r#"
-struct S;
-impl S {
-    fn foo(&self, x: i32) {}
-}
-
-fn main() { S.foo(<|>); }
-"#,
-        expect![[r#"
-                fn foo(&self, x: i32)
-                (<x: i32>)
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
-    check(
-        r#"
-struct S;
-impl S {
-    fn foo(&self, x: i32) {}
-}
-
-fn main() { S::foo(<|>); }
-"#,
-        expect![[r#"
-                fn foo(self: &S, x: i32)
-                (<self: &S>, x: i32)
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_with_docs_simple() {
-    check(
-        r#"
-/// test
-// non-doc-comment
-fn foo(j: u32) -> u32 {
-    j
-}
-
-fn bar() {
-    let _ = foo(<|>);
-}
-"#,
-        expect![[r#"
-                test
-                ------
-                fn foo(j: u32) -> u32
-                (<j: u32>)
-            "#]],
-    );
-}
-
-#[test]
-fn test_fn_signature_with_docs() {
-    check(
-        r#"
-/// Adds one to the number given.
-///
-/// # Examples
-///
-/// ```
-/// let five = 5;
-///
-/// assert_eq!(6, my_crate::add_one(5));
-/// ```
-pub fn add_one(x: i32) -> i32 {
-    x + 1
-}
-
-pub fn do() {
-    add_one(<|>
-}"#,
-        expect![[r##"
-                Adds one to the number given.
-
-                # Examples
-
-                ```
-                let five = 5;
-
-                assert_eq!(6, my_crate::add_one(5));
-                ```
-                ------
-                fn add_one(x: i32) -> i32
-                (<x: i32>)
-            "##]],
-    );
-}
-
-#[test]
-fn test_fn_signature_with_docs_impl() {
-    check(
-        r#"
-struct addr;
-impl addr {
-    /// Adds one to the number given.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let five = 5;
-    ///
-    /// assert_eq!(6, my_crate::add_one(5));
-    /// ```
-    pub fn add_one(x: i32) -> i32 {
-        x + 1
-    }
-}
-
-pub fn do_it() {
-    addr {};
-    addr::add_one(<|>);
-}
-"#,
-        expect![[r##"
-                Adds one to the number given.
-
-                # Examples
-
-                ```
-                let five = 5;
-
-                assert_eq!(6, my_crate::add_one(5));
-                ```
-                ------
-                fn add_one(x: i32) -> i32
-                (<x: i32>)
-            "##]],
-    );
-}
-
-#[test]
-fn test_fn_signature_with_docs_from_actix() {
-    check(
-        r#"
-struct WriteHandler<E>;
-
-impl<E> WriteHandler<E> {
-    /// Method is called when writer emits error.
-    ///
-    /// If this method returns `ErrorAction::Continue` writer processing
-    /// continues otherwise stream processing stops.
-    fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
-        Running::Stop
-    }
-
-    /// Method is called when writer finishes.
-    ///
-    /// By default this method stops actor's `Context`.
-    fn finished(&mut self, ctx: &mut Self::Context) {
-        ctx.stop()
-    }
-}
-
-pub fn foo(mut r: WriteHandler<()>) {
-    r.finished(<|>);
-}
-"#,
-        expect![[r#"
-                Method is called when writer finishes.
-
-                By default this method stops actor's `Context`.
-                ------
-                fn finished(&mut self, ctx: &mut {unknown})
-                (<ctx: &mut {unknown}>)
-            "#]],
-    );
-}
-
-#[test]
-fn call_info_bad_offset() {
-    mark::check!(call_info_bad_offset);
-    check(
-        r#"
-fn foo(x: u32, y: u32) -> u32 {x + y}
-fn bar() { foo <|> (3, ); }
-"#,
-        expect![[""]],
-    );
-}
-
-#[test]
-fn test_nested_method_in_lambda() {
-    check(
-        r#"
-struct Foo;
-impl Foo { fn bar(&self, _: u32) { } }
-
-fn bar(_: u32) { }
-
-fn main() {
-    let foo = Foo;
-    std::thread::spawn(move || foo.bar(<|>));
-}
-"#,
-        expect![[r#"
-                fn bar(&self, _: u32)
-                (<_: u32>)
-            "#]],
-    );
-}
-
-#[test]
-fn works_for_tuple_structs() {
-    check(
-        r#"
-/// A cool tuple struct
-struct S(u32, i32);
-fn main() {
-    let s = S(0, <|>);
-}
-"#,
-        expect![[r#"
-                A cool tuple struct
-                ------
-                struct S(u32, i32)
-                (u32, <i32>)
-            "#]],
-    );
-}
-
-#[test]
-fn generic_struct() {
-    check(
-        r#"
-struct S<T>(T);
-fn main() {
-    let s = S(<|>);
-}
-"#,
-        expect![[r#"
-                struct S({unknown})
-                (<{unknown}>)
-            "#]],
-    );
-}
-
-#[test]
-fn works_for_enum_variants() {
-    check(
-        r#"
-enum E {
-    /// A Variant
-    A(i32),
-    /// Another
-    B,
-    /// And C
-    C { a: i32, b: i32 }
-}
-
-fn main() {
-    let a = E::A(<|>);
-}
-"#,
-        expect![[r#"
-                A Variant
-                ------
-                enum E::A(i32)
-                (<i32>)
-            "#]],
-    );
-}
-
-#[test]
-fn cant_call_struct_record() {
-    check(
-        r#"
-struct S { x: u32, y: i32 }
-fn main() {
-    let s = S(<|>);
-}
-"#,
-        expect![[""]],
-    );
-}
-
-#[test]
-fn cant_call_enum_record() {
-    check(
-        r#"
-enum E {
-    /// A Variant
-    A(i32),
-    /// Another
-    B,
-    /// And C
-    C { a: i32, b: i32 }
-}
-
-fn main() {
-    let a = E::C(<|>);
-}
-"#,
-        expect![[""]],
-    );
-}
-
-#[test]
-fn fn_signature_for_call_in_macro() {
-    check(
-        r#"
-macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
-fn foo() { }
-id! {
-    fn bar() { foo(<|>); }
-}
-"#,
-        expect![[r#"
-                fn foo()
-                ()
-            "#]],
-    );
-}
-
-#[test]
-fn call_info_for_lambdas() {
-    check(
-        r#"
-struct S;
-fn foo(s: S) -> i32 { 92 }
-fn main() {
-    (|s| foo(s))(<|>)
-}
-        "#,
-        expect![[r#"
-                (S) -> i32
-                (<S>)
-            "#]],
-    )
-}
-
-#[test]
-fn call_info_for_fn_ptr() {
-    check(
-        r#"
-fn main(f: fn(i32, f64) -> char) {
-    f(0, <|>)
-}
-        "#,
-        expect![[r#"
-                (i32, f64) -> char
-                (i32, <f64>)
-            "#]],
-    )
-}
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
deleted file mode 100644
index 86bfa5b41f..0000000000
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ /dev/null
@@ -1,620 +0,0 @@
-use super::*;
-
-use test_utils::assert_eq_text;
-
-#[test]
-fn insert_existing() {
-    check_full("std::fs", "use std::fs;", "use std::fs;")
-}
-
-#[test]
-fn insert_start() {
-    check_none(
-        "std::bar::AA",
-        r"
-use std::bar::B;
-use std::bar::D;
-use std::bar::F;
-use std::bar::G;",
-        r"
-use std::bar::AA;
-use std::bar::B;
-use std::bar::D;
-use std::bar::F;
-use std::bar::G;",
-    )
-}
-
-#[test]
-fn insert_start_indent() {
-    mark::check!(insert_use_indent_after);
-    check_none(
-        "std::bar::AA",
-        r"
-    use std::bar::B;
-    use std::bar::D;",
-        r"
-    use std::bar::AA;
-    use std::bar::B;
-    use std::bar::D;",
-    )
-}
-
-#[test]
-fn insert_middle() {
-    check_none(
-        "std::bar::EE",
-        r"
-use std::bar::A;
-use std::bar::D;
-use std::bar::F;
-use std::bar::G;",
-        r"
-use std::bar::A;
-use std::bar::D;
-use std::bar::EE;
-use std::bar::F;
-use std::bar::G;",
-    )
-}
-
-#[test]
-fn insert_middle_indent() {
-    check_none(
-        "std::bar::EE",
-        r"
-    use std::bar::A;
-    use std::bar::D;
-    use std::bar::F;
-    use std::bar::G;",
-        r"
-    use std::bar::A;
-    use std::bar::D;
-    use std::bar::EE;
-    use std::bar::F;
-    use std::bar::G;",
-    )
-}
-
-#[test]
-fn insert_end() {
-    check_none(
-        "std::bar::ZZ",
-        r"
-use std::bar::A;
-use std::bar::D;
-use std::bar::F;
-use std::bar::G;",
-        r"
-use std::bar::A;
-use std::bar::D;
-use std::bar::F;
-use std::bar::G;
-use std::bar::ZZ;",
-    )
-}
-
-#[test]
-fn insert_end_indent() {
-    mark::check!(insert_use_indent_before);
-    check_none(
-        "std::bar::ZZ",
-        r"
-    use std::bar::A;
-    use std::bar::D;
-    use std::bar::F;
-    use std::bar::G;",
-        r"
-    use std::bar::A;
-    use std::bar::D;
-    use std::bar::F;
-    use std::bar::G;
-    use std::bar::ZZ;",
-    )
-}
-
-#[test]
-fn insert_middle_nested() {
-    check_none(
-        "std::bar::EE",
-        r"
-use std::bar::A;
-use std::bar::{D, Z}; // example of weird imports due to user
-use std::bar::F;
-use std::bar::G;",
-        r"
-use std::bar::A;
-use std::bar::EE;
-use std::bar::{D, Z}; // example of weird imports due to user
-use std::bar::F;
-use std::bar::G;",
-    )
-}
-
-#[test]
-fn insert_middle_groups() {
-    check_none(
-        "foo::bar::GG",
-        r"
-    use std::bar::A;
-    use std::bar::D;
-
-    use foo::bar::F;
-    use foo::bar::H;",
-        r"
-    use std::bar::A;
-    use std::bar::D;
-
-    use foo::bar::F;
-    use foo::bar::GG;
-    use foo::bar::H;",
-    )
-}
-
-#[test]
-fn insert_first_matching_group() {
-    check_none(
-        "foo::bar::GG",
-        r"
-    use foo::bar::A;
-    use foo::bar::D;
-
-    use std;
-
-    use foo::bar::F;
-    use foo::bar::H;",
-        r"
-    use foo::bar::A;
-    use foo::bar::D;
-    use foo::bar::GG;
-
-    use std;
-
-    use foo::bar::F;
-    use foo::bar::H;",
-    )
-}
-
-#[test]
-fn insert_missing_group_std() {
-    check_none(
-        "std::fmt",
-        r"
-    use foo::bar::A;
-    use foo::bar::D;",
-        r"
-    use std::fmt;
-
-    use foo::bar::A;
-    use foo::bar::D;",
-    )
-}
-
-#[test]
-fn insert_missing_group_self() {
-    check_none(
-        "self::fmt",
-        r"
-use foo::bar::A;
-use foo::bar::D;",
-        r"
-use foo::bar::A;
-use foo::bar::D;
-
-use self::fmt;",
-    )
-}
-
-#[test]
-fn insert_no_imports() {
-    check_full(
-        "foo::bar",
-        "fn main() {}",
-        r"use foo::bar;
-
-fn main() {}",
-    )
-}
-
-#[test]
-fn insert_empty_file() {
-    // empty files will get two trailing newlines
-    // this is due to the test case insert_no_imports above
-    check_full(
-        "foo::bar",
-        "",
-        r"use foo::bar;
-
-",
-    )
-}
-
-#[test]
-fn insert_empty_module() {
-    mark::check!(insert_use_no_indent_after);
-    check(
-        "foo::bar",
-        "mod x {}",
-        r"{
-    use foo::bar;
-}",
-        None,
-        true,
-    )
-}
-
-#[test]
-fn insert_after_inner_attr() {
-    check_full(
-        "foo::bar",
-        r"#![allow(unused_imports)]",
-        r"#![allow(unused_imports)]
-
-use foo::bar;",
-    )
-}
-
-#[test]
-fn insert_after_inner_attr2() {
-    check_full(
-        "foo::bar",
-        r"#![allow(unused_imports)]
-
-#![no_std]
-fn main() {}",
-        r"#![allow(unused_imports)]
-
-#![no_std]
-
-use foo::bar;
-fn main() {}",
-    );
-}
-
-#[test]
-fn inserts_after_single_line_inner_comments() {
-    check_none(
-        "foo::bar::Baz",
-        "//! Single line inner comments do not allow any code before them.",
-        r#"//! Single line inner comments do not allow any code before them.
-
-use foo::bar::Baz;"#,
-    );
-}
-
-#[test]
-fn inserts_after_multiline_inner_comments() {
-    check_none(
-        "foo::bar::Baz",
-        r#"/*! Multiline inner comments do not allow any code before them. */
-
-/*! Still an inner comment, cannot place any code before. */
-fn main() {}"#,
-        r#"/*! Multiline inner comments do not allow any code before them. */
-
-/*! Still an inner comment, cannot place any code before. */
-
-use foo::bar::Baz;
-fn main() {}"#,
-    )
-}
-
-#[test]
-fn inserts_after_all_inner_items() {
-    check_none(
-        "foo::bar::Baz",
-        r#"#![allow(unused_imports)]
-/*! Multiline line comment 2 */
-
-
-//! Single line comment 1
-#![no_std]
-//! Single line comment 2
-fn main() {}"#,
-        r#"#![allow(unused_imports)]
-/*! Multiline line comment 2 */
-
-
-//! Single line comment 1
-#![no_std]
-//! Single line comment 2
-
-use foo::bar::Baz;
-fn main() {}"#,
-    )
-}
-
-#[test]
-fn merge_groups() {
-    check_last("std::io", r"use std::fmt;", r"use std::{fmt, io};")
-}
-
-#[test]
-fn merge_groups_last() {
-    check_last(
-        "std::io",
-        r"use std::fmt::{Result, Display};",
-        r"use std::fmt::{Result, Display};
-use std::io;",
-    )
-}
-
-#[test]
-fn merge_last_into_self() {
-    check_last("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
-}
-
-#[test]
-fn merge_groups_full() {
-    check_full(
-        "std::io",
-        r"use std::fmt::{Result, Display};",
-        r"use std::{fmt::{Result, Display}, io};",
-    )
-}
-
-#[test]
-fn merge_groups_long_full() {
-    check_full("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
-}
-
-#[test]
-fn merge_groups_long_last() {
-    check_last("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
-}
-
-#[test]
-fn merge_groups_long_full_list() {
-    check_full(
-        "std::foo::bar::Baz",
-        r"use std::foo::bar::{Qux, Quux};",
-        r"use std::foo::bar::{Baz, Quux, Qux};",
-    )
-}
-
-#[test]
-fn merge_groups_long_last_list() {
-    check_last(
-        "std::foo::bar::Baz",
-        r"use std::foo::bar::{Qux, Quux};",
-        r"use std::foo::bar::{Baz, Quux, Qux};",
-    )
-}
-
-#[test]
-fn merge_groups_long_full_nested() {
-    check_full(
-        "std::foo::bar::Baz",
-        r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
-        r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};",
-    )
-}
-
-#[test]
-fn merge_groups_long_last_nested() {
-    check_last(
-        "std::foo::bar::Baz",
-        r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
-        r"use std::foo::bar::Baz;
-use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
-    )
-}
-
-#[test]
-fn merge_groups_full_nested_deep() {
-    check_full(
-        "std::foo::bar::quux::Baz",
-        r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
-        r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};",
-    )
-}
-
-#[test]
-fn merge_groups_full_nested_long() {
-    check_full(
-        "std::foo::bar::Baz",
-        r"use std::{foo::bar::Qux};",
-        r"use std::{foo::bar::{Baz, Qux}};",
-    );
-}
-
-#[test]
-fn merge_groups_last_nested_long() {
-    check_full(
-        "std::foo::bar::Baz",
-        r"use std::{foo::bar::Qux};",
-        r"use std::{foo::bar::{Baz, Qux}};",
-    );
-}
-
-#[test]
-fn merge_groups_skip_pub() {
-    check_full(
-        "std::io",
-        r"pub use std::fmt::{Result, Display};",
-        r"pub use std::fmt::{Result, Display};
-use std::io;",
-    )
-}
-
-#[test]
-fn merge_groups_skip_pub_crate() {
-    check_full(
-        "std::io",
-        r"pub(crate) use std::fmt::{Result, Display};",
-        r"pub(crate) use std::fmt::{Result, Display};
-use std::io;",
-    )
-}
-
-#[test]
-#[ignore] // FIXME: Support this
-fn split_out_merge() {
-    check_last(
-        "std::fmt::Result",
-        r"use std::{fmt, io};",
-        r"use std::fmt::{self, Result};
-use std::io;",
-    )
-}
-
-#[test]
-fn merge_into_module_import() {
-    check_full("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};")
-}
-
-#[test]
-fn merge_groups_self() {
-    check_full("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
-}
-
-#[test]
-fn merge_mod_into_glob() {
-    check_full("token::TokenKind", r"use token::TokenKind::*;", r"use token::TokenKind::{*, self};")
-    // FIXME: have it emit `use token::TokenKind::{self, *}`?
-}
-
-#[test]
-fn merge_self_glob() {
-    check_full("self", r"use self::*;", r"use self::{*, self};")
-    // FIXME: have it emit `use {self, *}`?
-}
-
-#[test]
-fn merge_glob_nested() {
-    check_full(
-        "foo::bar::quux::Fez",
-        r"use foo::bar::{Baz, quux::*};",
-        r"use foo::bar::{Baz, quux::{self::*, Fez}};",
-    )
-}
-
-#[test]
-fn merge_nested_considers_first_segments() {
-    check_full(
-        "hir_ty::display::write_bounds_like_dyn_trait",
-        r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};",
-        r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};",
-    );
-}
-
-#[test]
-fn skip_merge_last_too_long() {
-    check_last(
-        "foo::bar",
-        r"use foo::bar::baz::Qux;",
-        r"use foo::bar;
-use foo::bar::baz::Qux;",
-    );
-}
-
-#[test]
-fn skip_merge_last_too_long2() {
-    check_last(
-        "foo::bar::baz::Qux",
-        r"use foo::bar;",
-        r"use foo::bar;
-use foo::bar::baz::Qux;",
-    );
-}
-
-#[test]
-fn insert_short_before_long() {
-    check_none(
-        "foo::bar",
-        r"use foo::bar::baz::Qux;",
-        r"use foo::bar;
-use foo::bar::baz::Qux;",
-    );
-}
-
-#[test]
-fn merge_last_fail() {
-    check_merge_only_fail(
-        r"use foo::bar::{baz::{Qux, Fez}};",
-        r"use foo::bar::{baaz::{Quux, Feez}};",
-        MergeBehaviour::Last,
-    );
-}
-
-#[test]
-fn merge_last_fail1() {
-    check_merge_only_fail(
-        r"use foo::bar::{baz::{Qux, Fez}};",
-        r"use foo::bar::baaz::{Quux, Feez};",
-        MergeBehaviour::Last,
-    );
-}
-
-#[test]
-fn merge_last_fail2() {
-    check_merge_only_fail(
-        r"use foo::bar::baz::{Qux, Fez};",
-        r"use foo::bar::{baaz::{Quux, Feez}};",
-        MergeBehaviour::Last,
-    );
-}
-
-#[test]
-fn merge_last_fail3() {
-    check_merge_only_fail(
-        r"use foo::bar::baz::{Qux, Fez};",
-        r"use foo::bar::baaz::{Quux, Feez};",
-        MergeBehaviour::Last,
-    );
-}
-
-fn check(
-    path: &str,
-    ra_fixture_before: &str,
-    ra_fixture_after: &str,
-    mb: Option<MergeBehaviour>,
-    module: bool,
-) {
-    let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
-    if module {
-        syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone();
-    }
-    let file = super::ImportScope::from(syntax).unwrap();
-    let path = ast::SourceFile::parse(&format!("use {};", path))
-        .tree()
-        .syntax()
-        .descendants()
-        .find_map(ast::Path::cast)
-        .unwrap();
-
-    let rewriter = insert_use(&file, path, mb);
-    let result = rewriter.rewrite(file.as_syntax_node()).to_string();
-    assert_eq_text!(&result, ra_fixture_after);
-}
-
-fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-    check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full), false)
-}
-
-fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-    check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last), false)
-}
-
-fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-    check(path, ra_fixture_before, ra_fixture_after, None, false)
-}
-
-fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) {
-    let use0 = ast::SourceFile::parse(ra_fixture0)
-        .tree()
-        .syntax()
-        .descendants()
-        .find_map(ast::Use::cast)
-        .unwrap();
-
-    let use1 = ast::SourceFile::parse(ra_fixture1)
-        .tree()
-        .syntax()
-        .descendants()
-        .find_map(ast::Use::cast)
-        .unwrap();
-
-    let result = try_merge_imports(&use0, &use1, mb);
-    assert_eq!(result.map(|u| u.to_string()), None);
-}
diff --git a/crates/ide_db/src/line_index/tests.rs b/crates/ide_db/src/line_index/tests.rs
deleted file mode 100644
index 05f7484e8f..0000000000
--- a/crates/ide_db/src/line_index/tests.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-use super::*;
-
-#[test]
-fn test_line_index() {
-    let text = "hello\nworld";
-    let index = LineIndex::new(text);
-    assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
-    assert_eq!(index.line_col(1.into()), LineCol { line: 0, col_utf16: 1 });
-    assert_eq!(index.line_col(5.into()), LineCol { line: 0, col_utf16: 5 });
-    assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 0 });
-    assert_eq!(index.line_col(7.into()), LineCol { line: 1, col_utf16: 1 });
-    assert_eq!(index.line_col(8.into()), LineCol { line: 1, col_utf16: 2 });
-    assert_eq!(index.line_col(10.into()), LineCol { line: 1, col_utf16: 4 });
-    assert_eq!(index.line_col(11.into()), LineCol { line: 1, col_utf16: 5 });
-    assert_eq!(index.line_col(12.into()), LineCol { line: 1, col_utf16: 6 });
-
-    let text = "\nhello\nworld";
-    let index = LineIndex::new(text);
-    assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
-    assert_eq!(index.line_col(1.into()), LineCol { line: 1, col_utf16: 0 });
-    assert_eq!(index.line_col(2.into()), LineCol { line: 1, col_utf16: 1 });
-    assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 5 });
-    assert_eq!(index.line_col(7.into()), LineCol { line: 2, col_utf16: 0 });
-}
-
-#[test]
-fn test_char_len() {
-    assert_eq!('メ'.len_utf8(), 3);
-    assert_eq!('メ'.len_utf16(), 1);
-}
-
-#[test]
-fn test_empty_index() {
-    let col_index = LineIndex::new(
-        "
-const C: char = 'x';
-",
-    );
-    assert_eq!(col_index.utf16_lines.len(), 0);
-}
-
-#[test]
-fn test_single_char() {
-    let col_index = LineIndex::new(
-        "
-const C: char = 'メ';
-",
-    );
-
-    assert_eq!(col_index.utf16_lines.len(), 1);
-    assert_eq!(col_index.utf16_lines[&1].len(), 1);
-    assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
-
-    // UTF-8 to UTF-16, no changes
-    assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
-
-    // UTF-8 to UTF-16
-    assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
-
-    // UTF-16 to UTF-8, no changes
-    assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
-
-    // UTF-16 to UTF-8
-    assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21));
-
-    let col_index = LineIndex::new("a𐐏b");
-    assert_eq!(col_index.utf16_to_utf8_col(0, 3), TextSize::from(5));
-}
-
-#[test]
-fn test_string() {
-    let col_index = LineIndex::new(
-        "
-const C: char = \"メ メ\";
-",
-    );
-
-    assert_eq!(col_index.utf16_lines.len(), 1);
-    assert_eq!(col_index.utf16_lines[&1].len(), 2);
-    assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
-    assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() });
-
-    // UTF-8 to UTF-16
-    assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
-
-    assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19);
-    assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21);
-
-    assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
-
-    // UTF-16 to UTF-8
-    assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
-
-    // メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1
-    assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20
-    assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space
-    assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24
-
-    assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15));
-}
-
-#[test]
-fn test_splitlines() {
-    fn r(lo: u32, hi: u32) -> TextRange {
-        TextRange::new(lo.into(), hi.into())
-    }
-
-    let text = "a\nbb\nccc\n";
-    let line_index = LineIndex::new(text);
-
-    let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>();
-    let expected = vec![r(0, 2), r(2, 5), r(5, 9)];
-    assert_eq!(actual, expected);
-
-    let text = "";
-    let line_index = LineIndex::new(text);
-
-    let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>();
-    let expected = vec![];
-    assert_eq!(actual, expected);
-
-    let text = "\n";
-    let line_index = LineIndex::new(text);
-
-    let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>();
-    let expected = vec![r(0, 1)];
-    assert_eq!(actual, expected)
-}
diff --git a/crates/ide_db/src/traits/tests.rs b/crates/ide_db/src/traits/tests.rs
deleted file mode 100644
index 09c7ac3ec4..0000000000
--- a/crates/ide_db/src/traits/tests.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-use crate::RootDatabase;
-use base_db::{fixture::ChangeFixture, FilePosition};
-use expect_test::{expect, Expect};
-use hir::Semantics;
-use syntax::ast::{self, AstNode};
-use test_utils::RangeOrOffset;
-
-/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
-pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
-    let change_fixture = ChangeFixture::parse(ra_fixture);
-    let mut database = RootDatabase::default();
-    database.apply_change(change_fixture.change);
-    let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
-    let offset = match range_or_offset {
-        RangeOrOffset::Range(_) => panic!(),
-        RangeOrOffset::Offset(it) => it,
-    };
-    (database, FilePosition { file_id, offset })
-}
-
-fn check_trait(ra_fixture: &str, expect: Expect) {
-    let (db, position) = position(ra_fixture);
-    let sema = Semantics::new(&db);
-    let file = sema.parse(position.file_id);
-    let impl_block: ast::Impl =
-        sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
-    let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
-    let actual = match trait_ {
-        Some(trait_) => trait_.name(&db).to_string(),
-        None => String::new(),
-    };
-    expect.assert_eq(&actual);
-}
-
-fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
-    let (db, position) = position(ra_fixture);
-    let sema = Semantics::new(&db);
-    let file = sema.parse(position.file_id);
-    let impl_block: ast::Impl =
-        sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
-    let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
-    let actual = items
-        .into_iter()
-        .map(|item| item.name(&db).unwrap().to_string())
-        .collect::<Vec<_>>()
-        .join("\n");
-    expect.assert_eq(&actual);
-}
-
-#[test]
-fn resolve_trait() {
-    check_trait(
-        r#"
-pub trait Foo {
-    fn bar();
-}
-impl Foo for u8 {
-    <|>
-}
-            "#,
-        expect![["Foo"]],
-    );
-    check_trait(
-        r#"
-pub trait Foo {
-    fn bar();
-}
-impl Foo for u8 {
-    fn bar() {
-        fn baz() {
-            <|>
-        }
-        baz();
-    }
-}
-            "#,
-        expect![["Foo"]],
-    );
-    check_trait(
-        r#"
-pub trait Foo {
-    fn bar();
-}
-pub struct Bar;
-impl Bar {
-    <|>
-}
-            "#,
-        expect![[""]],
-    );
-}
-
-#[test]
-fn missing_assoc_items() {
-    check_missing_assoc(
-        r#"
-pub trait Foo {
-    const FOO: u8;
-    fn bar();
-}
-impl Foo for u8 {
-    <|>
-}"#,
-        expect![[r#"
-                FOO
-                bar"#]],
-    );
-
-    check_missing_assoc(
-        r#"
-pub trait Foo {
-    const FOO: u8;
-    fn bar();
-}
-impl Foo for u8 {
-    const FOO: u8 = 10;
-    <|>
-}"#,
-        expect![[r#"
-                bar"#]],
-    );
-
-    check_missing_assoc(
-        r#"
-pub trait Foo {
-    const FOO: u8;
-    fn bar();
-}
-impl Foo for u8 {
-    const FOO: u8 = 10;
-    fn bar() {<|>}
-}"#,
-        expect![[r#""#]],
-    );
-
-    check_missing_assoc(
-        r#"
-pub struct Foo;
-impl Foo {
-    fn bar() {<|>}
-}"#,
-        expect![[r#""#]],
-    );
-}
diff --git a/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast b/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
index 1e80dd7e27..b1fb75ed1e 100644
--- a/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
@@ -49,9 +49,9 @@ SOURCE_FILE@0..249
         R_CURLY@56..57 "}"
     SEMICOLON@57..58 ";"
   WHITESPACE@58..59 " "
-  COMMENT@59..97 "// Rust 2018 (with a  ..."
-  WHITESPACE@97..98 "\n"
-  USE@98..121
+  USE@59..121
+    COMMENT@59..97 "// Rust 2018 (with a  ..."
+    WHITESPACE@97..98 "\n"
     USE_KW@98..101 "use"
     WHITESPACE@101..102 " "
     USE_TREE@102..120
@@ -75,9 +75,9 @@ SOURCE_FILE@0..249
         R_CURLY@119..120 "}"
     SEMICOLON@120..121 ";"
   WHITESPACE@121..122 " "
-  COMMENT@122..134 "// Rust 2015"
-  WHITESPACE@134..135 "\n"
-  USE@135..166
+  USE@122..166
+    COMMENT@122..134 "// Rust 2015"
+    WHITESPACE@134..135 "\n"
     USE_KW@135..138 "use"
     WHITESPACE@138..139 " "
     USE_TREE@139..165
@@ -102,9 +102,9 @@ SOURCE_FILE@0..249
         R_CURLY@164..165 "}"
     SEMICOLON@165..166 ";"
   WHITESPACE@166..167 " "
-  COMMENT@167..179 "// Rust 2015"
-  WHITESPACE@179..180 "\n"
-  USE@180..205
+  USE@167..205
+    COMMENT@167..179 "// Rust 2015"
+    WHITESPACE@179..180 "\n"
     USE_KW@180..183 "use"
     WHITESPACE@183..184 " "
     USE_TREE@184..204
diff --git a/crates/syntax/test_data/parser/inline/ok/0110_use_path.rast b/crates/syntax/test_data/parser/inline/ok/0110_use_path.rast
index 82028096f8..c9fad5f8c5 100644
--- a/crates/syntax/test_data/parser/inline/ok/0110_use_path.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0110_use_path.rast
@@ -10,9 +10,9 @@ SOURCE_FILE@0..154
             IDENT@6..16 "crate_name"
     SEMICOLON@16..17 ";"
   WHITESPACE@17..18 " "
-  COMMENT@18..45 "// Rust 2018 - All fl ..."
-  WHITESPACE@45..46 "\n"
-  USE@46..61
+  USE@18..61
+    COMMENT@18..45 "// Rust 2018 - All fl ..."
+    WHITESPACE@45..46 "\n"
     USE_KW@46..49 "use"
     WHITESPACE@49..50 " "
     USE_TREE@50..60
@@ -22,9 +22,9 @@ SOURCE_FILE@0..154
             IDENT@50..60 "crate_name"
     SEMICOLON@60..61 ";"
   WHITESPACE@61..62 " "
-  COMMENT@62..91 "// Rust 2018 - Anchor ..."
-  WHITESPACE@91..92 "\n"
-  USE@92..124
+  USE@62..124
+    COMMENT@62..91 "// Rust 2018 - Anchor ..."
+    WHITESPACE@91..92 "\n"
     USE_KW@92..95 "use"
     WHITESPACE@95..96 " "
     USE_TREE@96..123