Repository: rust-analyzer/rust-analyzer
Pull request #6342 (2020-10-24 08:53:16)

Shorter dependency chain
Continuing implementing suggestions from the `Completion refactoring` zulip thread.

This PR does the following:

- Removes dependency of `completions` on `assists` by moving required functionality into `ide_db`.
- Moves completely `call_info` crate into `ide_db` as it looks like it fits perfect there.
- Adds a bunch of new tests and docs.
- Adds the re-export of `base_db` to the `ide_db` and removes direct dependency on `base_db` from other crates.

The last point is controversial, I guess, but I noticed that in places where `ide_db` is used, `base_db` is also *always* used. Thus I think the dependency on the `base_db` is implied by the fact of `ide_db` interfaces, and thus it makes sense to just provide `base_db` out of the box.



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index fe09e4afeb..769120fc2b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -50,7 +50,6 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
 name = "assists"
 version = "0.0.0"
 dependencies = [
- "base_db",
  "either",
  "hir",
  "ide_db",
@@ -127,20 +126,6 @@ version = "1.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
 
-[[package]]
-name = "call_info"
-version = "0.0.0"
-dependencies = [
- "base_db",
- "either",
- "expect-test",
- "hir",
- "ide_db",
- "stdx",
- "syntax",
- "test_utils",
-]
-
 [[package]]
 name = "cargo_metadata"
 version = "0.12.0"
@@ -268,9 +253,7 @@ dependencies = [
 name = "completion"
 version = "0.0.0"
 dependencies = [
- "assists",
  "base_db",
- "call_info",
  "expect-test",
  "hir",
  "ide_db",
@@ -643,8 +626,6 @@ name = "ide"
 version = "0.0.0"
 dependencies = [
  "assists",
- "base_db",
- "call_info",
  "cfg",
  "completion",
  "either",
@@ -673,6 +654,7 @@ version = "0.0.0"
 dependencies = [
  "base_db",
  "either",
+ "expect-test",
  "fst",
  "hir",
  "log",
@@ -1331,7 +1313,6 @@ name = "rust-analyzer"
 version = "0.0.0"
 dependencies = [
  "anyhow",
- "base_db",
  "cfg",
  "crossbeam-channel 0.5.0",
  "env_logger",
@@ -1564,7 +1545,6 @@ dependencies = [
 name = "ssr"
 version = "0.0.0"
 dependencies = [
- "base_db",
  "expect-test",
  "hir",
  "ide_db",
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml
index 2641256518..108f656e92 100644
--- a/crates/assists/Cargo.toml
+++ b/crates/assists/Cargo.toml
@@ -18,7 +18,6 @@ stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
 text_edit = { path = "../text_edit", version = "0.0.0" }
 profile = { path = "../profile", version = "0.0.0" }
-base_db = { path = "../base_db", version = "0.0.0" }
 ide_db = { path = "../ide_db", version = "0.0.0" }
 hir = { path = "../hir", version = "0.0.0" }
 test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs
index bf520069e8..d11fee196a 100644
--- a/crates/assists/src/assist_context.rs
+++ b/crates/assists/src/assist_context.rs
@@ -3,8 +3,8 @@
 use std::mem;
 
 use algo::find_covering_element;
-use base_db::{FileId, FileRange};
 use hir::Semantics;
+use ide_db::base_db::{FileId, FileRange};
 use ide_db::{
     label::Label,
     source_change::{SourceChange, SourceFileEdit},
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs
index 4c400f287b..b82fb30ad4 100644
--- a/crates/assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/assists/src/handlers/add_missing_impl_members.rs
@@ -1,4 +1,5 @@
 use hir::HasSource;
+use ide_db::traits::{get_missing_assoc_items, resolve_target_trait};
 use syntax::{
     ast::{
         self,
@@ -11,7 +12,7 @@ use syntax::{
 use crate::{
     assist_context::{AssistContext, Assists},
     ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
-    utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor},
+    utils::{render_snippet, Cursor},
     AssistId, AssistKind,
 };
 
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index 7f4f80b237..48433feb9e 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -1,5 +1,5 @@
-use base_db::FileId;
 use hir::{EnumVariant, Module, ModuleDef, Name};
+use ide_db::base_db::FileId;
 use ide_db::{defs::Definition, search::Reference, RootDatabase};
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs
index 66f74150c8..c867207877 100644
--- a/crates/assists/src/handlers/fix_visibility.rs
+++ b/crates/assists/src/handlers/fix_visibility.rs
@@ -1,5 +1,5 @@
-use base_db::FileId;
 use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
+use ide_db::base_db::FileId;
 use syntax::{
     ast::{self, VisibilityOwner},
     AstNode, TextRange, TextSize,
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs
index d23f4293b3..758188a429 100644
--- a/crates/assists/src/handlers/generate_function.rs
+++ b/crates/assists/src/handlers/generate_function.rs
@@ -1,5 +1,5 @@
-use base_db::FileId;
 use hir::HirDisplay;
+use ide_db::base_db::FileId;
 use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::{
     ast::{
diff --git a/crates/assists/src/handlers/replace_if_let_with_match.rs b/crates/assists/src/handlers/replace_if_let_with_match.rs
index 79097621e6..9a49c48c1f 100644
--- a/crates/assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/assists/src/handlers/replace_if_let_with_match.rs
@@ -7,10 +7,8 @@ use syntax::{
     AstNode,
 };
 
-use crate::{
-    utils::{unwrap_trivial_block, TryEnum},
-    AssistContext, AssistId, AssistKind, Assists,
-};
+use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists};
+use ide_db::ty_filter::TryEnum;
 
 // Assist: replace_if_let_with_match
 //
diff --git a/crates/assists/src/handlers/replace_let_with_if_let.rs b/crates/assists/src/handlers/replace_let_with_if_let.rs
index ed6d0c29be..a5bcbda24e 100644
--- a/crates/assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/assists/src/handlers/replace_let_with_if_let.rs
@@ -9,7 +9,8 @@ use syntax::{
     AstNode, T,
 };
 
-use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists};
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+use ide_db::ty_filter::TryEnum;
 
 // Assist: replace_let_with_if_let
 //
diff --git a/crates/assists/src/handlers/replace_unwrap_with_match.rs b/crates/assists/src/handlers/replace_unwrap_with_match.rs
index 4043c219cd..f547066f0d 100644
--- a/crates/assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/assists/src/handlers/replace_unwrap_with_match.rs
@@ -10,9 +10,10 @@ use syntax::{
 };
 
 use crate::{
-    utils::{render_snippet, Cursor, TryEnum},
+    utils::{render_snippet, Cursor},
     AssistContext, AssistId, AssistKind, Assists,
 };
+use ide_db::ty_filter::TryEnum;
 
 // Assist: replace_unwrap_with_match
 //
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 8a664f6542..70a651e10f 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -17,8 +17,8 @@ mod tests;
 pub mod utils;
 pub mod ast_transform;
 
-use base_db::FileRange;
 use hir::Semantics;
+use ide_db::base_db::FileRange;
 use ide_db::{label::Label, source_change::SourceChange, RootDatabase};
 use syntax::TextRange;
 
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 1a6b48b456..56f925ee69 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -2,14 +2,13 @@
 pub(crate) mod insert_use;
 pub(crate) mod import_assets;
 
-use std::{iter, ops};
+use std::ops;
 
-use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type};
+use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
 use ide_db::RootDatabase;
 use itertools::Itertools;
-use rustc_hash::FxHashSet;
 use syntax::{
-    ast::{self, make, ArgListOwner, NameOwner},
+    ast::{self, make, ArgListOwner},
     AstNode, Direction,
     SyntaxKind::*,
     SyntaxNode, TextSize, T,
@@ -115,72 +114,6 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor
     }
 }
 
-pub fn get_missing_assoc_items(
-    sema: &Semantics<RootDatabase>,
-    impl_def: &ast::Impl,
-) -> Vec<hir::AssocItem> {
-    // Names must be unique between constants and functions. However, type aliases
-    // may share the same name as a function or constant.
-    let mut impl_fns_consts = FxHashSet::default();
-    let mut impl_type = FxHashSet::default();
-
-    if let Some(item_list) = impl_def.assoc_item_list() {
-        for item in item_list.assoc_items() {
-            match item {
-                ast::AssocItem::Fn(f) => {
-                    if let Some(n) = f.name() {
-                        impl_fns_consts.insert(n.syntax().to_string());
-                    }
-                }
-
-                ast::AssocItem::TypeAlias(t) => {
-                    if let Some(n) = t.name() {
-                        impl_type.insert(n.syntax().to_string());
-                    }
-                }
-
-                ast::AssocItem::Const(c) => {
-                    if let Some(n) = c.name() {
-                        impl_fns_consts.insert(n.syntax().to_string());
-                    }
-                }
-                ast::AssocItem::MacroCall(_) => (),
-            }
-        }
-    }
-
-    resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
-        target_trait
-            .items(sema.db)
-            .iter()
-            .filter(|i| match i {
-                hir::AssocItem::Function(f) => {
-                    !impl_fns_consts.contains(&f.name(sema.db).to_string())
-                }
-                hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
-                hir::AssocItem::Const(c) => c
-                    .name(sema.db)
-                    .map(|n| !impl_fns_consts.contains(&n.to_string()))
-                    .unwrap_or_default(),
-            })
-            .cloned()
-            .collect()
-    })
-}
-
-pub(crate) fn resolve_target_trait(
-    sema: &Semantics<RootDatabase>,
-    impl_def: &ast::Impl,
-) -> Option<hir::Trait> {
-    let ast_path =
-        impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
-
-    match sema.resolve_path(&ast_path) {
-        Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
-        _ => None,
-    }
-}
-
 pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
     node.children_with_tokens()
         .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
@@ -223,54 +156,6 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
     }
 }
 
-#[derive(Clone, Copy)]
-pub enum TryEnum {
-    Result,
-    Option,
-}
-
-impl TryEnum {
-    const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
-
-    pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
-        let enum_ = match ty.as_adt() {
-            Some(Adt::Enum(it)) => it,
-            _ => return None,
-        };
-        TryEnum::ALL.iter().find_map(|&var| {
-            if &enum_.name(sema.db).to_string() == var.type_name() {
-                return Some(var);
-            }
-            None
-        })
-    }
-
-    pub(crate) fn happy_case(self) -> &'static str {
-        match self {
-            TryEnum::Result => "Ok",
-            TryEnum::Option => "Some",
-        }
-    }
-
-    pub(crate) fn sad_pattern(self) -> ast::Pat {
-        match self {
-            TryEnum::Result => make::tuple_struct_pat(
-                make::path_unqualified(make::path_segment(make::name_ref("Err"))),
-                iter::once(make::wildcard_pat().into()),
-            )
-            .into(),
-            TryEnum::Option => make::ident_pat(make::name("None")).into(),
-        }
-    }
-
-    fn type_name(self) -> &'static str {
-        match self {
-            TryEnum::Result => "Result",
-            TryEnum::Option => "Option",
-        }
-    }
-}
-
 /// Helps with finding well-know things inside the standard library. This is
 /// somewhat similar to the known paths infra inside hir, but it different; We
 /// want to make sure that IDE specific paths don't become interesting inside
diff --git a/crates/call_info/Cargo.toml b/crates/call_info/Cargo.toml
deleted file mode 100644
index 98c0bd6dbe..0000000000
--- a/crates/call_info/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[package]
-name = "call_info"
-version = "0.0.0"
-description = "TBD"
-license = "MIT OR Apache-2.0"
-authors = ["rust-analyzer developers"]
-edition = "2018"
-
-[lib]
-doctest = false
-
-[dependencies]
-either = "1.5.3"
-
-stdx = { path = "../stdx", version = "0.0.0" }
-syntax = { path = "../syntax", version = "0.0.0" }
-base_db = { path = "../base_db", version = "0.0.0" }
-ide_db = { path = "../ide_db", version = "0.0.0" }
-test_utils = { path = "../test_utils", version = "0.0.0" }
-
-# call_info crate should depend only on the top-level `hir` package. if you need
-# something from some `hir_xxx` subpackage, reexport the API via `hir`.
-hir = { path = "../hir", version = "0.0.0" }
-
-[dev-dependencies]
-expect-test = "1.0"
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml
index 25192456a3..b79ee33f73 100644
--- a/crates/completion/Cargo.toml
+++ b/crates/completion/Cargo.toml
@@ -21,8 +21,6 @@ base_db = { path = "../base_db", version = "0.0.0" }
 ide_db = { path = "../ide_db", version = "0.0.0" }
 profile = { path = "../profile", version = "0.0.0" }
 test_utils = { path = "../test_utils", version = "0.0.0" }
-assists = { path = "../assists", version = "0.0.0" }
-call_info = { path = "../call_info", version = "0.0.0" }
 
 # completions crate should depend only on the top-level `hir` package. if you need
 # something from some `hir_xxx` subpackage, reexport the API via `hir`.
diff --git a/crates/completion/src/complete_mod.rs b/crates/completion/src/complete_mod.rs
index 35a57aba34..385911afad 100644
--- a/crates/completion/src/complete_mod.rs
+++ b/crates/completion/src/complete_mod.rs
@@ -1,7 +1,7 @@
 //! Completes mod declarations.
 
-use base_db::{SourceDatabaseExt, VfsPath};
 use hir::{Module, ModuleSource};
+use ide_db::base_db::{SourceDatabaseExt, VfsPath};
 use ide_db::RootDatabase;
 use rustc_hash::FxHashSet;
 
diff --git a/crates/completion/src/complete_postfix.rs b/crates/completion/src/complete_postfix.rs
index 700573cf2c..2622f12ab1 100644
--- a/crates/completion/src/complete_postfix.rs
+++ b/crates/completion/src/complete_postfix.rs
@@ -2,7 +2,7 @@
 
 mod format_like;
 
-use assists::utils::TryEnum;
+use ide_db::ty_filter::TryEnum;
 use syntax::{
     ast::{self, AstNode, AstToken},
     TextRange, TextSize,
diff --git a/crates/completion/src/complete_trait_impl.rs b/crates/completion/src/complete_trait_impl.rs
index c06af99e22..a14be9c73b 100644
--- a/crates/completion/src/complete_trait_impl.rs
+++ b/crates/completion/src/complete_trait_impl.rs
@@ -31,8 +31,8 @@
 //! }
 //! ```
 
-use assists::utils::get_missing_assoc_items;
 use hir::{self, HasAttrs, HasSource};
+use ide_db::traits::get_missing_assoc_items;
 use syntax::{
     ast::{self, edit, Impl},
     display::function_declaration,
diff --git a/crates/completion/src/completion_context.rs b/crates/completion/src/completion_context.rs
index e4f86d0e01..dca304a8f5 100644
--- a/crates/completion/src/completion_context.rs
+++ b/crates/completion/src/completion_context.rs
@@ -1,9 +1,8 @@
 //! See `CompletionContext` structure.
 
-use base_db::{FilePosition, SourceDatabase};
-use call_info::ActiveParameter;
 use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
-use ide_db::RootDatabase;
+use ide_db::base_db::{FilePosition, SourceDatabase};
+use ide_db::{call_info::ActiveParameter, RootDatabase};
 use syntax::{
     algo::{find_covering_element, find_node_at_offset},
     ast, match_ast, AstNode, NodeOrToken,
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index 0a60ea7f28..b72fd249dc 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -23,7 +23,7 @@ mod complete_macro_in_item_position;
 mod complete_trait_impl;
 mod complete_mod;
 
-use base_db::FilePosition;
+use ide_db::base_db::FilePosition;
 use ide_db::RootDatabase;
 
 use crate::{
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 76b52fa047..4d483580df 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -23,14 +23,12 @@ url = "2.1.1"
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
 text_edit = { path = "../text_edit", version = "0.0.0" }
-base_db = { path = "../base_db", version = "0.0.0" }
 ide_db = { path = "../ide_db", version = "0.0.0" }
 cfg = { path = "../cfg", version = "0.0.0" }
 profile = { path = "../profile", version = "0.0.0" }
 test_utils = { path = "../test_utils", version = "0.0.0" }
 assists = { path = "../assists", version = "0.0.0" }
 ssr = { path = "../ssr", version = "0.0.0" }
-call_info = { path = "../call_info", version = "0.0.0" }
 completion = { path = "../completion", version = "0.0.0" }
 
 # ide should depend only on the top-level `hir` package. if you need
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index 9d6433fe07..8ad50a2ee5 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -2,8 +2,8 @@
 
 use indexmap::IndexMap;
 
-use call_info::FnCallNode;
 use hir::Semantics;
+use ide_db::call_info::FnCallNode;
 use ide_db::RootDatabase;
 use syntax::{ast, match_ast, AstNode, TextRange};
 
@@ -137,7 +137,7 @@ impl CallLocations {
 
 #[cfg(test)]
 mod tests {
-    use base_db::FilePosition;
+    use ide_db::base_db::FilePosition;
 
     use crate::fixture;
 
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 232074c3df..d0ee588589 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -9,11 +9,11 @@ mod field_shorthand;
 
 use std::cell::RefCell;
 
-use base_db::SourceDatabase;
 use hir::{
     diagnostics::{Diagnostic as _, DiagnosticSinkBuilder},
     Semantics,
 };
+use ide_db::base_db::SourceDatabase;
 use ide_db::RootDatabase;
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs
index 54e9fce9e5..f41bcd6191 100644
--- a/crates/ide/src/diagnostics/field_shorthand.rs
+++ b/crates/ide/src/diagnostics/field_shorthand.rs
@@ -1,7 +1,7 @@
 //! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
 //! expressions and patterns.
 
-use base_db::FileId;
+use ide_db::base_db::FileId;
 use ide_db::source_change::SourceFileEdit;
 use syntax::{ast, match_ast, AstNode, SyntaxNode};
 use text_edit::TextEdit;
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 0c75e50b01..0c950003e1 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -1,6 +1,5 @@
 //! Provides a way to attach fixes to the diagnostics.
 //! The same module also has all curret custom fixes for the diagnostics implemented.
-use base_db::FileId;
 use hir::{
     db::AstDatabase,
     diagnostics::{
@@ -9,6 +8,7 @@ use hir::{
     },
     HasSource, HirDisplay, Semantics, VariantDef,
 };
+use ide_db::base_db::FileId;
 use ide_db::{
     source_change::{FileSystemEdit, SourceFileEdit},
     RootDatabase,
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index cf9d617dc0..0c429a2629 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -1,8 +1,8 @@
 //! FIXME: write short doc here
 
-use base_db::{FileId, SourceDatabase};
 use either::Either;
 use hir::{original_range, AssocItem, FieldSource, HasSource, InFile, ModuleSource};
+use ide_db::base_db::{FileId, SourceDatabase};
 use ide_db::{defs::Definition, RootDatabase};
 use syntax::{
     ast::{self, DocCommentsOwner, NameOwner},
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs
index ed06689f0c..eb57f9224d 100644
--- a/crates/ide/src/fixture.rs
+++ b/crates/ide/src/fixture.rs
@@ -1,5 +1,5 @@
 //! Utilities for creating `Analysis` instances for tests.
-use base_db::fixture::ChangeFixture;
+use ide_db::base_db::fixture::ChangeFixture;
 use test_utils::{extract_annotations, RangeOrOffset};
 
 use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index a87e31019d..15792f9472 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -100,7 +100,7 @@ pub(crate) fn reference_definition(
 
 #[cfg(test)]
 mod tests {
-    use base_db::FileRange;
+    use ide_db::base_db::FileRange;
     use syntax::{TextRange, TextSize};
 
     use crate::fixture;
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 6c586bbd12..529004878d 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -74,7 +74,7 @@ fn impls_for_trait(
 
 #[cfg(test)]
 mod tests {
-    use base_db::FileRange;
+    use ide_db::base_db::FileRange;
 
     use crate::fixture;
 
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index 6d0df04dd0..aba6bf5dc2 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -54,7 +54,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
 
 #[cfg(test)]
 mod tests {
-    use base_db::FileRange;
+    use ide_db::base_db::FileRange;
 
     use crate::fixture;
 
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 0332c7be04..94d895c5e7 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,8 +1,8 @@
-use base_db::SourceDatabase;
 use hir::{
     Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay,
     Module, ModuleDef, ModuleSource, Semantics,
 };
+use ide_db::base_db::SourceDatabase;
 use ide_db::{
     defs::{Definition, NameClass, NameRefClass},
     RootDatabase,
@@ -385,8 +385,8 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
 
 #[cfg(test)]
 mod tests {
-    use base_db::FileLoader;
     use expect_test::{expect, Expect};
+    use ide_db::base_db::FileLoader;
 
     use crate::fixture;
 
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index cecfae4c70..4bc733b70e 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -48,11 +48,11 @@ mod doc_links;
 
 use std::sync::Arc;
 
-use base_db::{
+use cfg::CfgOptions;
+use ide_db::base_db::{
     salsa::{self, ParallelDatabase},
     CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
 };
-use cfg::CfgOptions;
 use ide_db::{
     symbol_index::{self, FileSymbol},
     LineIndexDatabase,
@@ -80,19 +80,19 @@ pub use crate::{
         Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange,
     },
 };
-pub use call_info::CallInfo;
 pub use completion::{
     CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
 };
+pub use ide_db::call_info::CallInfo;
 
 pub use assists::{
     utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
 };
-pub use base_db::{
+pub use hir::{Documentation, Semantics};
+pub use ide_db::base_db::{
     Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
     SourceRootId,
 };
-pub use hir::{Documentation, Semantics};
 pub use ide_db::{
     label::Label,
     line_index::{LineCol, LineIndex},
@@ -396,7 +396,7 @@ impl Analysis {
 
     /// Computes parameter information for the given call expression.
     pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> {
-        self.with_db(|db| call_info::call_info(db, position))
+        self.with_db(|db| ide_db::call_info::call_info(db, position))
     }
 
     /// Computes call hierarchy candidates for the given file position.
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index ef94acfecd..6cc3b2991c 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -1,5 +1,5 @@
-use base_db::{CrateId, FileId, FilePosition};
 use hir::Semantics;
+use ide_db::base_db::{CrateId, FileId, FilePosition};
 use ide_db::RootDatabase;
 use syntax::{
     algo::find_node_at_offset,
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs
index 6944dbcd2a..ea0acfaa02 100644
--- a/crates/ide/src/prime_caches.rs
+++ b/crates/ide/src/prime_caches.rs
@@ -3,8 +3,8 @@
 //! request takes longer to compute. This modules implemented prepopulating of
 //! various caches, it's not really advanced at the moment.
 
-use base_db::SourceDatabase;
 use hir::db::DefDatabase;
+use ide_db::base_db::SourceDatabase;
 
 use crate::RootDatabase;
 
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 67ec257a8e..a517081d52 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -191,8 +191,8 @@ fn get_struct_def_name_for_struct_literal_search(
 
 #[cfg(test)]
 mod tests {
-    use base_db::FileId;
     use expect_test::{expect, Expect};
+    use ide_db::base_db::FileId;
     use stdx::format_to;
 
     use crate::{fixture, SearchScope};
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 35aafc49d7..26ac2371a5 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -1,7 +1,7 @@
 //! FIXME: write short doc here
 
-use base_db::SourceDatabaseExt;
 use hir::{Module, ModuleDef, ModuleSource, Semantics};
+use ide_db::base_db::SourceDatabaseExt;
 use ide_db::{
     defs::{Definition, NameClass, NameRefClass},
     RootDatabase,
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs
index 0af84daa0a..8e91c99d72 100644
--- a/crates/ide/src/status.rs
+++ b/crates/ide/src/status.rs
@@ -1,10 +1,10 @@
 use std::{fmt, iter::FromIterator, sync::Arc};
 
-use base_db::{
+use hir::MacroFile;
+use ide_db::base_db::{
     salsa::debug::{DebugQueryTable, TableEntry},
     CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
 };
-use hir::MacroFile;
 use ide_db::{
     symbol_index::{LibrarySymbolsQuery, SymbolIndex},
     RootDatabase,
@@ -16,7 +16,7 @@ use stdx::format_to;
 use syntax::{ast, Parse, SyntaxNode};
 
 fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
-    base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
+    ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
 }
 fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
     hir::db::ParseMacroQuery.in_db(db).entries::<SyntaxTreeStats>()
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 57e2d29231..abcc5cccc7 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -1,6 +1,6 @@
 //! Renders a bit of code as HTML.
 
-use base_db::SourceDatabase;
+use ide_db::base_db::SourceDatabase;
 use oorandom::Rand32;
 use stdx::format_to;
 use syntax::{AstNode, TextRange, TextSize};
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs
index acd91b26c0..59a74bc02e 100644
--- a/crates/ide/src/syntax_highlighting/injection.rs
+++ b/crates/ide/src/syntax_highlighting/injection.rs
@@ -3,8 +3,8 @@
 use std::{collections::BTreeMap, convert::TryFrom};
 
 use ast::{HasQuotes, HasStringValue};
-use call_info::ActiveParameter;
 use hir::Semantics;
+use ide_db::call_info::ActiveParameter;
 use itertools::Itertools;
 use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
 
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs
index 0eed2dbd78..7941610d6b 100644
--- a/crates/ide/src/syntax_tree.rs
+++ b/crates/ide/src/syntax_tree.rs
@@ -1,4 +1,4 @@
-use base_db::{FileId, SourceDatabase};
+use ide_db::base_db::{FileId, SourceDatabase};
 use ide_db::RootDatabase;
 use syntax::{
     algo, AstNode, NodeOrToken, SourceFile,
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 94b91f0499..43458a3a2c 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -15,7 +15,7 @@
 
 mod on_enter;
 
-use base_db::{FilePosition, SourceDatabase};
+use ide_db::base_db::{FilePosition, SourceDatabase};
 use ide_db::{source_change::SourceFileEdit, RootDatabase};
 use syntax::{
     algo::find_node_at_offset,
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs
index 98adef1d6f..f4ea303526 100644
--- a/crates/ide/src/typing/on_enter.rs
+++ b/crates/ide/src/typing/on_enter.rs
@@ -1,7 +1,7 @@
 //! Handles the `Enter` key press. At the momently, this only continues
 //! comments, but should handle indent some time in the future as well.
 
-use base_db::{FilePosition, SourceDatabase};
+use ide_db::base_db::{FilePosition, SourceDatabase};
 use ide_db::RootDatabase;
 use syntax::{
     ast::{self, AstToken},
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index 320fb15e55..3ff7a1a6a0 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -29,3 +29,6 @@ test_utils = { path = "../test_utils", version = "0.0.0" }
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir_xxx` subpackage, reexport the API via `hir`.
 hir = { path = "../hir", version = "0.0.0" }
+
+[dev-dependencies]
+expect-test = "1.0"
diff --git a/crates/call_info/src/lib.rs b/crates/ide_db/src/call_info.rs
similarity index 99%
rename from crates/call_info/src/lib.rs
rename to crates/ide_db/src/call_info.rs
index c45406c253..83a602b9ad 100644
--- a/crates/call_info/src/lib.rs
+++ b/crates/ide_db/src/call_info.rs
@@ -2,7 +2,6 @@
 use base_db::FilePosition;
 use either::Either;
 use hir::{HasAttrs, HirDisplay, Semantics, Type};
-use ide_db::RootDatabase;
 use stdx::format_to;
 use syntax::{
     ast::{self, ArgListOwner},
@@ -10,6 +9,8 @@ use syntax::{
 };
 use test_utils::mark;
 
+use crate::RootDatabase;
+
 /// Contains information about a call site. Specifically the
 /// `FunctionSignature`and current parameter.
 #[derive(Debug)]
@@ -228,9 +229,9 @@ impl FnCallNode {
 
 #[cfg(test)]
 mod tests {
+    use crate::RootDatabase;
     use base_db::{fixture::ChangeFixture, FilePosition};
     use expect_test::{expect, Expect};
-    use ide_db::RootDatabase;
     use test_utils::{mark, RangeOrOffset};
 
     /// Creates analysis from a multi-file fixture, returns positions marked with <|>.
@@ -249,7 +250,7 @@ mod tests {
 
     fn check(ra_fixture: &str, expect: Expect) {
         let (db, position) = position(ra_fixture);
-        let call_info = crate::call_info(&db, position);
+        let call_info = crate::call_info::call_info(&db, position);
         let actual = match call_info {
             Some(call_info) => {
                 let docs = match &call_info.doc {
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index 7eff247c73..38ebdbf791 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -10,6 +10,9 @@ pub mod defs;
 pub mod search;
 pub mod imports_locator;
 pub mod source_change;
+pub mod ty_filter;
+pub mod traits;
+pub mod call_info;
 
 use std::{fmt, sync::Arc};
 
@@ -23,6 +26,9 @@ use rustc_hash::FxHashSet;
 
 use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
 
+/// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
+pub use base_db;
+
 #[salsa::database(
     base_db::SourceDatabaseStorage,
     base_db::SourceDatabaseExtStorage,
diff --git a/crates/ide_db/src/traits.rs b/crates/ide_db/src/traits.rs
new file mode 100644
index 0000000000..f57b6dd91e
--- /dev/null
+++ b/crates/ide_db/src/traits.rs
@@ -0,0 +1,227 @@
+//! Functionality for obtaining data related to traits from the DB.
+
+use crate::RootDatabase;
+use hir::Semantics;
+use rustc_hash::FxHashSet;
+use syntax::{
+    ast::{self, NameOwner},
+    AstNode,
+};
+
+/// Given the `impl` block, attempts to find the trait this `impl` corresponds to.
+pub fn resolve_target_trait(
+    sema: &Semantics<RootDatabase>,
+    impl_def: &ast::Impl,
+) -> Option<hir::Trait> {
+    let ast_path =
+        impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
+
+    match sema.resolve_path(&ast_path) {
+        Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
+        _ => None,
+    }
+}
+
+/// Given the `impl` block, returns the list of associated items (e.g. functions or types) that are
+/// missing in this `impl` block.
+pub fn get_missing_assoc_items(
+    sema: &Semantics<RootDatabase>,
+    impl_def: &ast::Impl,
+) -> Vec<hir::AssocItem> {
+    // Names must be unique between constants and functions. However, type aliases
+    // may share the same name as a function or constant.
+    let mut impl_fns_consts = FxHashSet::default();
+    let mut impl_type = FxHashSet::default();
+
+    if let Some(item_list) = impl_def.assoc_item_list() {
+        for item in item_list.assoc_items() {
+            match item {
+                ast::AssocItem::Fn(f) => {
+                    if let Some(n) = f.name() {
+                        impl_fns_consts.insert(n.syntax().to_string());
+                    }
+                }
+
+                ast::AssocItem::TypeAlias(t) => {
+                    if let Some(n) = t.name() {
+                        impl_type.insert(n.syntax().to_string());
+                    }
+                }
+
+                ast::AssocItem::Const(c) => {
+                    if let Some(n) = c.name() {
+                        impl_fns_consts.insert(n.syntax().to_string());
+                    }
+                }
+                ast::AssocItem::MacroCall(_) => (),
+            }
+        }
+    }
+
+    resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
+        target_trait
+            .items(sema.db)
+            .iter()
+            .filter(|i| match i {
+                hir::AssocItem::Function(f) => {
+                    !impl_fns_consts.contains(&f.name(sema.db).to_string())
+                }
+                hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
+                hir::AssocItem::Const(c) => c
+                    .name(sema.db)
+                    .map(|n| !impl_fns_consts.contains(&n.to_string()))
+                    .unwrap_or_default(),
+            })
+            .cloned()
+            .collect()
+    })
+}
+
+#[cfg(test)]
+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/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs
new file mode 100644
index 0000000000..63a9452825
--- /dev/null
+++ b/crates/ide_db/src/ty_filter.rs
@@ -0,0 +1,58 @@
+//! This module contains structures for filtering the expected types.
+//! Use case for structures in this module is, for example, situation when you need to process
+//! only certain `Enum`s.
+
+use crate::RootDatabase;
+use hir::{Adt, Semantics, Type};
+use std::iter;
+use syntax::ast::{self, make};
+
+/// Enum types that implement `std::ops::Try` trait.
+#[derive(Clone, Copy)]
+pub enum TryEnum {
+    Result,
+    Option,
+}
+
+impl TryEnum {
+    const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
+
+    /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`.
+    pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
+        let enum_ = match ty.as_adt() {
+            Some(Adt::Enum(it)) => it,
+            _ => return None,
+        };
+        TryEnum::ALL.iter().find_map(|&var| {
+            if &enum_.name(sema.db).to_string() == var.type_name() {
+                return Some(var);
+            }
+            None
+        })
+    }
+
+    pub fn happy_case(self) -> &'static str {
+        match self {
+            TryEnum::Result => "Ok",
+            TryEnum::Option => "Some",
+        }
+    }
+
+    pub fn sad_pattern(self) -> ast::Pat {
+        match self {
+            TryEnum::Result => make::tuple_struct_pat(
+                make::path_unqualified(make::path_segment(make::name_ref("Err"))),
+                iter::once(make::wildcard_pat().into()),
+            )
+            .into(),
+            TryEnum::Option => make::ident_pat(make::name("None")).into(),
+        }
+    }
+
+    fn type_name(self) -> &'static str {
+        match self {
+            TryEnum::Result => "Result",
+            TryEnum::Option => "Option",
+        }
+    }
+}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 66cf06e1a8..f8f97b1d37 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -46,7 +46,6 @@ cfg = { path = "../cfg", version = "0.0.0" }
 toolchain = { path = "../toolchain", version = "0.0.0" }
 
 # This should only be used in CLI
-base_db = { path = "../base_db", version = "0.0.0" }
 ide_db = { path = "../ide_db", version = "0.0.0" }
 ssr = { path = "../ssr", version = "0.0.0" }
 hir = { path = "../hir", version = "0.0.0" }
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index d1c095ba5c..8e33986d52 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -3,13 +3,13 @@
 use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
 
 use anyhow::{bail, format_err, Result};
-use base_db::{
-    salsa::{Database, Durability},
-    FileId,
-};
 use ide::{
     Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
 };
+use ide_db::base_db::{
+    salsa::{Database, Durability},
+    FileId,
+};
 use vfs::AbsPathBuf;
 
 use crate::{
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index fb2b2b0001..98ef0cd68a 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -6,16 +6,16 @@ use std::{
     time::{SystemTime, UNIX_EPOCH},
 };
 
-use base_db::{
-    salsa::{self, ParallelDatabase},
-    SourceDatabaseExt,
-};
 use hir::{
     db::{AstDatabase, DefDatabase, HirDatabase},
     original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
 };
 use hir_def::FunctionId;
 use hir_ty::{Ty, TypeWalk};
+use ide_db::base_db::{
+    salsa::{self, ParallelDatabase},
+    SourceDatabaseExt,
+};
 use itertools::Itertools;
 use oorandom::Rand32;
 use rayon::prelude::*;
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index a89993a2b2..368f627ac4 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -6,9 +6,9 @@ use std::path::Path;
 use anyhow::anyhow;
 use rustc_hash::FxHashSet;
 
-use base_db::SourceDatabaseExt;
 use hir::Crate;
 use ide::{DiagnosticsConfig, Severity};
+use ide_db::base_db::SourceDatabaseExt;
 
 use crate::cli::{load_cargo::load_cargo, Result};
 
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 7ae1c90552..ab1e2ab92d 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -3,9 +3,9 @@
 use std::{path::Path, sync::Arc};
 
 use anyhow::Result;
-use base_db::CrateGraph;
 use crossbeam_channel::{unbounded, Receiver};
 use ide::{AnalysisHost, Change};
+use ide_db::base_db::CrateGraph;
 use project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace};
 use vfs::{loader::Handle, AbsPath, AbsPathBuf};
 
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs
index c11e109437..a06631daca 100644
--- a/crates/rust-analyzer/src/cli/ssr.rs
+++ b/crates/rust-analyzer/src/cli/ssr.rs
@@ -4,7 +4,7 @@ use crate::cli::{load_cargo::load_cargo, Result};
 use ssr::{MatchFinder, SsrPattern, SsrRule};
 
 pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
-    use base_db::SourceDatabaseExt;
+    use ide_db::base_db::SourceDatabaseExt;
     let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
     let db = host.raw_database();
     let mut match_finder = MatchFinder::at_first_file(db)?;
@@ -26,7 +26,7 @@ pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
 /// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful
 /// for much else.
 pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<String>) -> Result<()> {
-    use base_db::SourceDatabaseExt;
+    use ide_db::base_db::SourceDatabaseExt;
     use ide_db::symbol_index::SymbolsDatabase;
     let (host, _vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
     let db = host.raw_database();
diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs
index 5b9f52993d..aa6b808d6e 100644
--- a/crates/rust-analyzer/src/from_proto.rs
+++ b/crates/rust-analyzer/src/from_proto.rs
@@ -1,8 +1,8 @@
 //! Conversion lsp_types types to rust-analyzer specific ones.
 use std::convert::TryFrom;
 
-use base_db::{FileId, FilePosition, FileRange};
 use ide::{AssistKind, LineCol, LineIndex};
+use ide_db::base_db::{FileId, FilePosition, FileRange};
 use syntax::{TextRange, TextSize};
 use vfs::AbsPathBuf;
 
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index dafab6a6a7..673a2eebc9 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -5,10 +5,10 @@
 
 use std::{sync::Arc, time::Instant};
 
-use base_db::{CrateId, VfsPath};
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
 use ide::{Analysis, AnalysisHost, Change, FileId};
+use ide_db::base_db::{CrateId, VfsPath};
 use lsp_types::{SemanticTokens, Url};
 use parking_lot::{Mutex, RwLock};
 use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index bd888f6347..1d271a9d8b 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -1,8 +1,8 @@
 //! Utilities for LSP-related boilerplate code.
 use std::{error::Error, ops::Range};
 
-use base_db::Canceled;
 use ide::LineIndex;
+use ide_db::base_db::Canceled;
 use lsp_server::Notification;
 
 use crate::{from_proto, global_state::GlobalState};
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index fb18f90147..ed52927330 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -5,10 +5,10 @@ use std::{
     time::{Duration, Instant},
 };
 
-use base_db::VfsPath;
 use crossbeam_channel::{select, Receiver};
 use ide::PrimeCachesProgress;
 use ide::{Canceled, FileId};
+use ide_db::base_db::VfsPath;
 use lsp_server::{Connection, Notification, Request, Response};
 use lsp_types::notification::Notification as _;
 use project_model::ProjectWorkspace;
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index f7215f1290..0eabd51bdb 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -1,9 +1,9 @@
 //! Project loading & configuration updates
 use std::{mem, sync::Arc};
 
-use base_db::{CrateGraph, SourceRoot, VfsPath};
 use flycheck::{FlycheckConfig, FlycheckHandle};
 use ide::Change;
+use ide_db::base_db::{CrateGraph, SourceRoot, VfsPath};
 use project_model::{ProcMacroClient, ProjectWorkspace};
 use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
 
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 0d34970bca..24a658fc65 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -4,13 +4,13 @@ use std::{
     sync::atomic::{AtomicU32, Ordering},
 };
 
-use base_db::{FileId, FileRange};
 use ide::{
     Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation,
     FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, HighlightedRange,
     Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget,
     ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit,
 };
+use ide_db::base_db::{FileId, FileRange};
 use itertools::Itertools;
 use syntax::{SyntaxKind, TextRange, TextSize};
 
@@ -809,7 +809,7 @@ mod tests {
         let completions: Vec<(String, Option<String>)> = analysis
             .completions(
                 &ide::CompletionConfig::default(),
-                base_db::FilePosition { file_id, offset },
+                ide_db::base_db::FilePosition { file_id, offset },
             )
             .unwrap()
             .unwrap()
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml
index 408140014b..98ed25fb69 100644
--- a/crates/ssr/Cargo.toml
+++ b/crates/ssr/Cargo.toml
@@ -16,7 +16,6 @@ itertools = "0.9.0"
 
 text_edit = { path = "../text_edit", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
-base_db = { path = "../base_db", version = "0.0.0" }
 ide_db = { path = "../ide_db", version = "0.0.0" }
 hir = { path = "../hir", version = "0.0.0" }
 test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/ssr/src/lib.rs b/crates/ssr/src/lib.rs
index ba669fd56c..747ce495d4 100644
--- a/crates/ssr/src/lib.rs
+++ b/crates/ssr/src/lib.rs
@@ -73,8 +73,8 @@ use crate::errors::bail;
 pub use crate::errors::SsrError;
 pub use crate::matching::Match;
 use crate::matching::MatchFailureReason;
-use base_db::{FileId, FilePosition, FileRange};
 use hir::Semantics;
+use ide_db::base_db::{FileId, FilePosition, FileRange};
 use ide_db::source_change::SourceFileEdit;
 use resolving::ResolvedRule;
 use rustc_hash::FxHashMap;
@@ -126,7 +126,7 @@ impl<'db> MatchFinder<'db> {
 
     /// Constructs an instance using the start of the first file in `db` as the lookup context.
     pub fn at_first_file(db: &'db ide_db::RootDatabase) -> Result<MatchFinder<'db>, SsrError> {
-        use base_db::SourceDatabaseExt;
+        use ide_db::base_db::SourceDatabaseExt;
         use ide_db::symbol_index::SymbolsDatabase;
         if let Some(first_file_id) = db
             .local_roots()
@@ -160,7 +160,7 @@ impl<'db> MatchFinder<'db> {
 
     /// Finds matches for all added rules and returns edits for all found matches.
     pub fn edits(&self) -> Vec<SourceFileEdit> {
-        use base_db::SourceDatabaseExt;
+        use ide_db::base_db::SourceDatabaseExt;
         let mut matches_by_file = FxHashMap::default();
         for m in self.matches().matches {
             matches_by_file
@@ -205,7 +205,7 @@ impl<'db> MatchFinder<'db> {
     /// them, while recording reasons why they don't match. This API is useful for command
     /// line-based debugging where providing a range is difficult.
     pub fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec<MatchDebugInfo> {
-        use base_db::SourceDatabaseExt;
+        use ide_db::base_db::SourceDatabaseExt;
         let file = self.sema.parse(file_id);
         let mut res = Vec::new();
         let file_text = self.sema.db.file_text(file_id);
diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs
index 948862a775..99b187311a 100644
--- a/crates/ssr/src/matching.rs
+++ b/crates/ssr/src/matching.rs
@@ -6,8 +6,8 @@ use crate::{
     resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo},
     SsrMatches,
 };
-use base_db::FileRange;
 use hir::Semantics;
+use ide_db::base_db::FileRange;
 use rustc_hash::FxHashMap;
 use std::{cell::Cell, iter::Peekable};
 use syntax::ast::{AstNode, AstToken};
diff --git a/crates/ssr/src/resolving.rs b/crates/ssr/src/resolving.rs
index 347cc4aad8..f5ceb57292 100644
--- a/crates/ssr/src/resolving.rs
+++ b/crates/ssr/src/resolving.rs
@@ -2,7 +2,7 @@
 
 use crate::errors::error;
 use crate::{parsing, SsrError};
-use base_db::FilePosition;
+use ide_db::base_db::FilePosition;
 use parsing::Placeholder;
 use rustc_hash::FxHashMap;
 use syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken};
diff --git a/crates/ssr/src/search.rs b/crates/ssr/src/search.rs
index a595fd269c..44b5db029d 100644
--- a/crates/ssr/src/search.rs
+++ b/crates/ssr/src/search.rs
@@ -5,7 +5,7 @@ use crate::{
     resolving::{ResolvedPath, ResolvedPattern, ResolvedRule},
     Match, MatchFinder,
 };
-use base_db::{FileId, FileRange};
+use ide_db::base_db::{FileId, FileRange};
 use ide_db::{
     defs::Definition,
     search::{Reference, SearchScope},
@@ -145,7 +145,7 @@ impl<'db> MatchFinder<'db> {
     fn search_files_do(&self, mut callback: impl FnMut(FileId)) {
         if self.restrict_ranges.is_empty() {
             // Unrestricted search.
-            use base_db::SourceDatabaseExt;
+            use ide_db::base_db::SourceDatabaseExt;
             use ide_db::symbol_index::SymbolsDatabase;
             for &root in self.sema.db.local_roots().iter() {
                 let sr = self.sema.db.source_root(root);


Test patch:
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs
index 2b687decf3..849d85e763 100644
--- a/crates/assists/src/tests.rs
+++ b/crates/assists/src/tests.rs
@@ -1,7 +1,7 @@
 mod generated;
 
-use base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
 use hir::Semantics;
+use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
 use ide_db::RootDatabase;
 use syntax::TextRange;
 use test_utils::{assert_eq_text, extract_offset, extract_range};
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs
index f2cf2561f3..b02556797d 100644
--- a/crates/completion/src/test_utils.rs
+++ b/crates/completion/src/test_utils.rs
@@ -1,7 +1,7 @@
 //! Runs completion for testing purposes.
 
-use base_db::{fixture::ChangeFixture, FileLoader, FilePosition};
 use hir::Semantics;
+use ide_db::base_db::{fixture::ChangeFixture, FileLoader, FilePosition};
 use ide_db::RootDatabase;
 use itertools::Itertools;
 use stdx::{format_to, trim_indent};
diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs
index 20231a9bc6..63131f6ca5 100644
--- a/crates/ssr/src/tests.rs
+++ b/crates/ssr/src/tests.rs
@@ -1,6 +1,6 @@
 use crate::{MatchFinder, SsrRule};
-use base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt};
 use expect_test::{expect, Expect};
+use ide_db::base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt};
 use rustc_hash::FxHashSet;
 use std::sync::Arc;
 use test_utils::{mark, RangeOrOffset};
@@ -62,7 +62,7 @@ fn parser_undefined_placeholder_in_replacement() {
 /// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be
 /// the start of the file. If there's a second cursor marker, then we'll return a single range.
 pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) {
-    use base_db::fixture::WithFixture;
+    use ide_db::base_db::fixture::WithFixture;
     use ide_db::symbol_index::SymbolsDatabase;
     let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) {
         ide_db::RootDatabase::with_range_or_offset(code)
@@ -83,7 +83,7 @@ pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Ve
         }
     }
     let mut local_roots = FxHashSet::default();
-    local_roots.insert(base_db::fixture::WORKSPACE);
+    local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
     db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
     (db, position, selections)
 }