Repository: rust-analyzer/rust-analyzer
Pull request #2544 (2019-12-12 18:41:46)

Map first and last tokens in original_range
This PR try to fix the first part of the `original_range` : Try to map the first token and last token of a `SyntaxNode` , If success, return the union range of mapped tokens. 


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index af874945c1..caa52fb69d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -620,7 +620,7 @@ dependencies = [
 
 [[package]]
 name = "lsp-types"
-version = "0.63.1"
+version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1048,7 +1048,7 @@ dependencies = [
  "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lsp-types 0.63.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_ide 0.1.0",
  "ra_prof 0.1.0",
@@ -1123,7 +1123,6 @@ dependencies = [
  "rowan 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
  "smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "test_utils 0.1.0",
  "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1840,7 +1839,7 @@ dependencies = [
 "checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586"
 "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
 "checksum lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba36405bd742139ab79c246ca5adb7fde2fe1a0f495e2c8e2f607b607dedb12"
-"checksum lsp-types 0.63.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70090cea3cd5db0aa923575e03874b33da90c4d0fe1eaf63fa51b8925a78ef03"
+"checksum lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa3268fbe8beb2795c2fb327bf44f4f3d24f5fe9ebc18d7e2980afd444d72bcf"
 "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
 "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
 "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index c705d16302..c013ff99bb 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -11,7 +11,7 @@ use hir_def::{
     per_ns::PerNs,
     resolver::HasResolver,
     type_ref::{Mutability, TypeRef},
-    AdtId, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId,
+    AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId,
     LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId,
     StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
 };
@@ -269,7 +269,7 @@ pub struct Struct {
 
 impl Struct {
     pub fn module(self, db: &impl DefDatabase) -> Module {
-        Module { id: self.id.lookup(db).container }
+        Module { id: self.id.module(db) }
     }
 
     pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -290,7 +290,7 @@ impl Struct {
     }
 
     pub fn ty(self, db: &impl HirDatabase) -> Type {
-        Type::from_def(db, self.id.lookup(db).container.krate, self.id)
+        Type::from_def(db, self.id.module(db).krate, self.id)
     }
 
     fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
@@ -309,11 +309,11 @@ impl Union {
     }
 
     pub fn module(self, db: &impl DefDatabase) -> Module {
-        Module { id: self.id.lookup(db).container }
+        Module { id: self.id.module(db) }
     }
 
     pub fn ty(self, db: &impl HirDatabase) -> Type {
-        Type::from_def(db, self.id.lookup(db).container.krate, self.id)
+        Type::from_def(db, self.id.module(db).krate, self.id)
     }
 
     pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
@@ -337,7 +337,7 @@ pub struct Enum {
 
 impl Enum {
     pub fn module(self, db: &impl DefDatabase) -> Module {
-        Module { id: self.id.lookup(db).container }
+        Module { id: self.id.module(db) }
     }
 
     pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -357,7 +357,7 @@ impl Enum {
     }
 
     pub fn ty(self, db: &impl HirDatabase) -> Type {
-        Type::from_def(db, self.id.lookup(db).container.krate, self.id)
+        Type::from_def(db, self.id.module(db).krate, self.id)
     }
 }
 
@@ -577,7 +577,7 @@ pub struct Trait {
 
 impl Trait {
     pub fn module(self, db: &impl DefDatabase) -> Module {
-        Module { id: self.id.lookup(db).container }
+        Module { id: self.id.module(db) }
     }
 
     pub fn name(self, db: &impl DefDatabase) -> Name {
@@ -809,10 +809,7 @@ impl ImplBlock {
         let resolver = self.id.resolver(db);
         let environment = TraitEnvironment::lower(db, &resolver);
         let ty = Ty::from_hir(db, &resolver, &impl_data.target_type);
-        Type {
-            krate: self.id.lookup(db).container.krate,
-            ty: InEnvironment { value: ty, environment },
-        }
+        Type { krate: self.id.module(db).krate, ty: InEnvironment { value: ty, environment } }
     }
 
     pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> {
@@ -824,7 +821,7 @@ impl ImplBlock {
     }
 
     pub fn module(&self, db: &impl DefDatabase) -> Module {
-        self.id.lookup(db).container.into()
+        self.id.module(db).into()
     }
 
     pub fn krate(&self, db: &impl DefDatabase) -> Crate {
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 7abb4bd75a..307f3d5bff 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,8 +1,7 @@
 //! FIXME: write short doc here
 use hir_def::{
-    child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource,
-    ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, StaticId, StructId,
-    TraitId, TypeAliasId, UnionId, VariantId,
+    child_by_source::ChildBySource, dyn_map::DynMap, keys, nameres::ModuleSource, AstItemDef,
+    EnumVariantId, GenericDefId, LocationCtx, ModuleId, VariantId,
 };
 use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
 use ra_syntax::{
@@ -21,46 +20,73 @@ pub trait FromSource: Sized {
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self>;
 }
 
-pub trait FromSourceByContainer: Sized {
-    type Ast: AstNode + 'static;
-    type Id: Copy + 'static;
-    const KEY: Key<Self::Ast, Self::Id>;
+impl FromSource for Struct {
+    type Ast = ast::StructDef;
+    fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
+        let id = from_source(db, src)?;
+        Some(Struct { id })
+    }
 }
-
-impl<T: FromSourceByContainer> FromSource for T
-where
-    T: From<<T as FromSourceByContainer>::Id>,
-{
-    type Ast = <T as FromSourceByContainer>::Ast;
+impl FromSource for Union {
+    type Ast = ast::UnionDef;
+    fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
+        let id = from_source(db, src)?;
+        Some(Union { id })
+    }
+}
+impl FromSource for Enum {
+    type Ast = ast::EnumDef;
+    fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
+        let id = from_source(db, src)?;
+        Some(Enum { id })
+    }
+}
+impl FromSource for Trait {
+    type Ast = ast::TraitDef;
+    fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
+        let id = from_source(db, src)?;
+        Some(Trait { id })
+    }
+}
+impl FromSource for Function {
+    type Ast = ast::FnDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
-        analyze_container(db, src.as_ref().map(|it| it.syntax()))[T::KEY]
+        Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::FUNCTION]
             .get(&src)
             .copied()
-            .map(Self::from)
+            .map(Function::from)
     }
 }
 
-macro_rules! from_source_by_container_impls {
-    ($(($hir:ident, $id:ident, $ast:path, $key:path)),* ,) => {$(
-        impl FromSourceByContainer for $hir {
-            type Ast = $ast;
-            type Id = $id;
-            const KEY: Key<Self::Ast, Self::Id> = $key;
-        }
-    )*}
+impl FromSource for Const {
+    type Ast = ast::ConstDef;
+    fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
+        Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::CONST]
+            .get(&src)
+            .copied()
+            .map(Const::from)
+    }
+}
+impl FromSource for Static {
+    type Ast = ast::StaticDef;
+    fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
+        Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)[keys::STATIC]
+            .get(&src)
+            .copied()
+            .map(Static::from)
+    }
 }
 
-from_source_by_container_impls![
-    (Struct, StructId, ast::StructDef, keys::STRUCT),
-    (Union, UnionId, ast::UnionDef, keys::UNION),
-    (Enum, EnumId, ast::EnumDef, keys::ENUM),
-    (Trait, TraitId, ast::TraitDef, keys::TRAIT),
-    (Function, FunctionId, ast::FnDef, keys::FUNCTION),
-    (Static, StaticId, ast::StaticDef, keys::STATIC),
-    (Const, ConstId, ast::ConstDef, keys::CONST),
-    (TypeAlias, TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
-    (ImplBlock, ImplId, ast::ImplBlock, keys::IMPL),
-];
+impl FromSource for TypeAlias {
+    type Ast = ast::TypeAliasDef;
+    fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
+        Container::find(db, src.as_ref().map(|it| it.syntax()))?.child_by_source(db)
+            [keys::TYPE_ALIAS]
+            .get(&src)
+            .copied()
+            .map(TypeAlias::from)
+    }
+}
 
 impl FromSource for MacroDef {
     type Ast = ast::MacroCall;
@@ -78,6 +104,14 @@ impl FromSource for MacroDef {
     }
 }
 
+impl FromSource for ImplBlock {
+    type Ast = ast::ImplBlock;
+    fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
+        let id = from_source(db, src)?;
+        Some(ImplBlock { id })
+    }
+}
+
 impl FromSource for EnumVariant {
     type Ast = ast::EnumVariant;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
@@ -211,30 +245,57 @@ impl Module {
     }
 }
 
-fn analyze_container(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> DynMap {
-    _analyze_container(db, src).unwrap_or_default()
+fn from_source<N, DEF>(db: &(impl DefDatabase + AstDatabase), src: InFile<N>) -> Option<DEF>
+where
+    N: AstNode,
+    DEF: AstItemDef<N>,
+{
+    let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
+    let module = Module::from_definition(db, InFile::new(src.file_id, module_src))?;
+    let ctx = LocationCtx::new(db, module.id, src.file_id);
+    let items = db.ast_id_map(src.file_id);
+    let item_id = items.ast_id(&src.value);
+    Some(DEF::from_ast_id(ctx, item_id))
 }
 
-fn _analyze_container(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> Option<DynMap> {
-    // FIXME: this doesn't try to handle nested declarations
-    for container in src.value.ancestors().skip(1) {
-        let res = match_ast! {
-            match container {
-                ast::TraitDef(it) => {
-                    let c = Trait::from_source(db, src.with_value(it))?;
-                    c.id.child_by_source(db)
-                },
-                ast::ImplBlock(it) => {
-                    let c = ImplBlock::from_source(db, src.with_value(it))?;
-                    c.id.child_by_source(db)
-                 },
-                _ => { continue },
-            }
-        };
-        return Some(res);
+enum Container {
+    Trait(Trait),
+    ImplBlock(ImplBlock),
+    Module(Module),
+}
+
+impl Container {
+    fn find(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> Option<Container> {
+        // FIXME: this doesn't try to handle nested declarations
+        for container in src.value.ancestors() {
+            let res = match_ast! {
+                match container {
+                    ast::TraitDef(it) => {
+                        let c = Trait::from_source(db, src.with_value(it))?;
+                        Container::Trait(c)
+                    },
+                    ast::ImplBlock(it) => {
+                        let c = ImplBlock::from_source(db, src.with_value(it))?;
+                        Container::ImplBlock(c)
+                     },
+                    _ => { continue },
+                }
+            };
+            return Some(res);
+        }
+
+        let module_source = ModuleSource::from_child_node(db, src);
+        let c = Module::from_definition(db, src.with_value(module_source))?;
+        Some(Container::Module(c))
     }
+}
 
-    let module_source = ModuleSource::from_child_node(db, src);
-    let c = Module::from_definition(db, src.with_value(module_source))?;
-    Some(c.id.child_by_source(db))
+impl ChildBySource for Container {
+    fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
+        match self {
+            Container::Trait(it) => it.id.child_by_source(db),
+            Container::ImplBlock(it) => it.id.child_by_source(db),
+            Container::Module(it) => it.id.child_by_source(db),
+        }
+    }
 }
diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs
index 72afecf26c..b09582f93c 100644
--- a/crates/ra_hir/src/has_source.rs
+++ b/crates/ra_hir/src/has_source.rs
@@ -4,7 +4,7 @@ use either::Either;
 use hir_def::{
     nameres::ModuleSource,
     src::{HasChildSource, HasSource as _},
-    Lookup, VariantId,
+    AstItemDef, Lookup, VariantId,
 };
 use ra_syntax::ast;
 
@@ -51,19 +51,19 @@ impl HasSource for StructField {
 impl HasSource for Struct {
     type Ast = ast::StructDef;
     fn source(self, db: &impl DefDatabase) -> InFile<ast::StructDef> {
-        self.id.lookup(db).source(db)
+        self.id.source(db)
     }
 }
 impl HasSource for Union {
     type Ast = ast::UnionDef;
     fn source(self, db: &impl DefDatabase) -> InFile<ast::UnionDef> {
-        self.id.lookup(db).source(db)
+        self.id.source(db)
     }
 }
 impl HasSource for Enum {
     type Ast = ast::EnumDef;
     fn source(self, db: &impl DefDatabase) -> InFile<ast::EnumDef> {
-        self.id.lookup(db).source(db)
+        self.id.source(db)
     }
 }
 impl HasSource for EnumVariant {
@@ -93,7 +93,7 @@ impl HasSource for Static {
 impl HasSource for Trait {
     type Ast = ast::TraitDef;
     fn source(self, db: &impl DefDatabase) -> InFile<ast::TraitDef> {
-        self.id.lookup(db).source(db)
+        self.id.source(db)
     }
 }
 impl HasSource for TypeAlias {
@@ -114,7 +114,7 @@ impl HasSource for MacroDef {
 impl HasSource for ImplBlock {
     type Ast = ast::ImplBlock;
     fn source(self, db: &impl DefDatabase) -> InFile<ast::ImplBlock> {
-        self.id.lookup(db).source(db)
+        self.id.source(db)
     }
 }
 impl HasSource for Import {
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index ec3d57d1a9..db3e63ef82 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -11,8 +11,8 @@ use ra_arena::{map::ArenaMap, Arena};
 use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
 
 use crate::{
-    db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, EnumId,
-    LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, UnionId, VariantId,
+    db::DefDatabase, src::HasChildSource, trace::Trace, type_ref::TypeRef, AstItemDef, EnumId,
+    LocalEnumVariantId, LocalStructFieldId, StructId, UnionId, VariantId,
 };
 
 /// Note that we use `StructData` for unions as well!
@@ -50,14 +50,14 @@ pub struct StructFieldData {
 
 impl StructData {
     pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> {
-        let src = id.lookup(db).source(db);
+        let src = id.source(db);
         let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
         let variant_data = VariantData::new(src.value.kind());
         let variant_data = Arc::new(variant_data);
         Arc::new(StructData { name, variant_data })
     }
     pub(crate) fn union_data_query(db: &impl DefDatabase, id: UnionId) -> Arc<StructData> {
-        let src = id.lookup(db).source(db);
+        let src = id.source(db);
         let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
         let variant_data = VariantData::new(
             src.value
@@ -72,7 +72,7 @@ impl StructData {
 
 impl EnumData {
     pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> {
-        let src = e.lookup(db).source(db);
+        let src = e.source(db);
         let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
         let mut trace = Trace::new_for_arena();
         lower_enum(&mut trace, &src.value);
@@ -89,7 +89,7 @@ impl HasChildSource for EnumId {
     type ChildId = LocalEnumVariantId;
     type Value = ast::EnumVariant;
     fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
-        let src = self.lookup(db).source(db);
+        let src = self.source(db);
         let mut trace = Trace::new_for_map();
         lower_enum(&mut trace, &src.value);
         src.with_value(trace.into_map())
@@ -153,8 +153,8 @@ impl HasChildSource for VariantId {
                 let src = it.parent.child_source(db);
                 src.map(|map| map[it.local_id].kind())
             }
-            VariantId::StructId(it) => it.lookup(db).source(db).map(|it| it.kind()),
-            VariantId::UnionId(it) => it.lookup(db).source(db).map(|it| {
+            VariantId::StructId(it) => it.source(db).map(|it| it.kind()),
+            VariantId::UnionId(it) => it.source(db).map(|it| {
                 it.record_field_def_list()
                     .map(ast::StructKind::Record)
                     .unwrap_or(ast::StructKind::Unit)
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 5bf82e191c..2f8f02d821 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -12,7 +12,8 @@ use ra_syntax::{
 use tt::Subtree;
 
 use crate::{
-    db::DefDatabase, path::Path, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup,
+    db::DefDatabase, path::Path, src::HasChildSource, src::HasSource, AdtId, AstItemDef, AttrDefId,
+    Lookup,
 };
 
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
@@ -55,15 +56,15 @@ impl Attrs {
                 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
             }
             AttrDefId::AdtId(it) => match it {
-                AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db),
-                AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db),
-                AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db),
+                AdtId::StructId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
+                AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
+                AdtId::UnionId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
             },
-            AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db),
+            AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
             AttrDefId::MacroDefId(it) => {
                 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
             }
-            AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db),
+            AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
             AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db),
             AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db),
             AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db),
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs
index 3c9379b151..a3574a9dbb 100644
--- a/crates/ra_hir_def/src/child_by_source.rs
+++ b/crates/ra_hir_def/src/child_by_source.rs
@@ -11,8 +11,8 @@ use crate::{
     dyn_map::DynMap,
     keys,
     src::{HasChildSource, HasSource},
-    AdtId, AssocItemId, EnumId, EnumVariantId, ImplId, Lookup, ModuleDefId, ModuleId,
-    StructFieldId, TraitId, VariantId,
+    AssocItemId, EnumId, EnumVariantId, ImplId, Lookup, ModuleDefId, ModuleId, StructFieldId,
+    TraitId, VariantId,
 };
 
 pub trait ChildBySource {
@@ -94,33 +94,10 @@ impl ChildBySource for ModuleId {
                     let src = ty.lookup(db).source(db);
                     res[keys::TYPE_ALIAS].insert(src, ty)
                 }
-                ModuleDefId::TraitId(trait_) => {
-                    let src = trait_.lookup(db).source(db);
-                    res[keys::TRAIT].insert(src, trait_)
-                }
-                ModuleDefId::AdtId(adt) => match adt {
-                    AdtId::StructId(strukt) => {
-                        let src = strukt.lookup(db).source(db);
-                        res[keys::STRUCT].insert(src, strukt)
-                    }
-                    AdtId::UnionId(union_) => {
-                        let src = union_.lookup(db).source(db);
-                        res[keys::UNION].insert(src, union_)
-                    }
-                    AdtId::EnumId(enum_) => {
-                        let src = enum_.lookup(db).source(db);
-                        res[keys::ENUM].insert(src, enum_)
-                    }
-                },
                 _ => (),
             }
         }
 
-        for &impl_ in crate_def_map[self.local_id].impls.iter() {
-            let src = impl_.lookup(db).source(db);
-            res[keys::IMPL].insert(src, impl_)
-        }
-
         res
     }
 }
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index b2dac183e3..095d7064a0 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -12,8 +12,8 @@ use crate::{
     db::DefDatabase,
     src::HasSource,
     type_ref::{Mutability, TypeRef},
-    AssocItemId, ConstId, ConstLoc, ContainerId, FunctionId, FunctionLoc, ImplId, Intern, Lookup,
-    StaticId, TraitId, TypeAliasId, TypeAliasLoc,
+    AssocItemId, AstItemDef, ConstId, ConstLoc, ContainerId, FunctionId, FunctionLoc, ImplId,
+    Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -94,7 +94,7 @@ pub struct TraitData {
 
 impl TraitData {
     pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> {
-        let src = tr.lookup(db).source(db);
+        let src = tr.source(db);
         let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
         let auto = src.value.is_auto();
         let ast_id_map = db.ast_id_map(src.file_id);
@@ -167,7 +167,7 @@ pub struct ImplData {
 
 impl ImplData {
     pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> {
-        let src = id.lookup(db).source(db);
+        let src = id.source(db);
         let items = db.ast_id_map(src.file_id);
 
         let target_trait = src.value.target_trait().map(TypeRef::from_ast);
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 98bff6cb78..ef5611ffc0 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
 
 use hir_expand::{db::AstDatabase, HirFileId};
 use ra_db::{salsa, CrateId, SourceDatabase};
-use ra_syntax::SmolStr;
+use ra_syntax::{ast, SmolStr};
 
 use crate::{
     adt::{EnumData, StructData},
@@ -17,9 +17,9 @@ use crate::{
         raw::{ImportSourceMap, RawItems},
         CrateDefMap,
     },
-    AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
-    GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId,
-    TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
+    AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, FunctionId, FunctionLoc, GenericDefId,
+    ImplId, ItemLoc, ModuleId, StaticId, StaticLoc, StructId, TraitId, TypeAliasId, TypeAliasLoc,
+    UnionId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -27,21 +27,21 @@ pub trait InternDatabase: SourceDatabase {
     #[salsa::interned]
     fn intern_function(&self, loc: FunctionLoc) -> FunctionId;
     #[salsa::interned]
-    fn intern_struct(&self, loc: StructLoc) -> StructId;
+    fn intern_struct(&self, loc: ItemLoc<ast::StructDef>) -> StructId;
     #[salsa::interned]
-    fn intern_union(&self, loc: UnionLoc) -> UnionId;
+    fn intern_union(&self, loc: ItemLoc<ast::UnionDef>) -> UnionId;
     #[salsa::interned]
-    fn intern_enum(&self, loc: EnumLoc) -> EnumId;
+    fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> EnumId;
     #[salsa::interned]
     fn intern_const(&self, loc: ConstLoc) -> ConstId;
     #[salsa::interned]
     fn intern_static(&self, loc: StaticLoc) -> StaticId;
     #[salsa::interned]
-    fn intern_trait(&self, loc: TraitLoc) -> TraitId;
+    fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> TraitId;
     #[salsa::interned]
     fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId;
     #[salsa::interned]
-    fn intern_impl(&self, loc: ImplLoc) -> ImplId;
+    fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> ImplId;
 }
 
 #[salsa::query_group(DefDatabaseStorage)]
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs
index b29f142e33..61727bd260 100644
--- a/crates/ra_hir_def/src/docs.rs
+++ b/crates/ra_hir_def/src/docs.rs
@@ -11,7 +11,7 @@ use ra_syntax::ast;
 use crate::{
     db::DefDatabase,
     src::{HasChildSource, HasSource},
-    AdtId, AttrDefId, Lookup,
+    AdtId, AstItemDef, AttrDefId, Lookup,
 };
 
 /// Holds documentation
@@ -51,15 +51,15 @@ impl Documentation {
                 }
             }
             AttrDefId::AdtId(it) => match it {
-                AdtId::StructId(it) => docs_from_ast(&it.lookup(db).source(db).value),
-                AdtId::EnumId(it) => docs_from_ast(&it.lookup(db).source(db).value),
-                AdtId::UnionId(it) => docs_from_ast(&it.lookup(db).source(db).value),
+                AdtId::StructId(it) => docs_from_ast(&it.source(db).value),
+                AdtId::EnumId(it) => docs_from_ast(&it.source(db).value),
+                AdtId::UnionId(it) => docs_from_ast(&it.source(db).value),
             },
             AttrDefId::EnumVariantId(it) => {
                 let src = it.parent.child_source(db);
                 docs_from_ast(&src.value[it.local_id])
             }
-            AttrDefId::TraitId(it) => docs_from_ast(&it.lookup(db).source(db).value),
+            AttrDefId::TraitId(it) => docs_from_ast(&it.source(db).value),
             AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id?.to_node(db)),
             AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value),
             AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value),
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index e502dd7983..976cf72d09 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -21,7 +21,7 @@ use crate::{
     src::HasChildSource,
     src::HasSource,
     type_ref::{TypeBound, TypeRef},
-    AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId,
+    AdtId, AstItemDef, GenericDefId, LocalTypeParamId, Lookup, TypeParamId,
 };
 
 /// Data about a generic parameter (to a function, struct, impl, ...).
@@ -71,22 +71,22 @@ impl GenericParams {
                 src.file_id
             }
             GenericDefId::AdtId(AdtId::StructId(it)) => {
-                let src = it.lookup(db).source(db);
+                let src = it.source(db);
                 generics.fill(&mut sm, &src.value);
                 src.file_id
             }
             GenericDefId::AdtId(AdtId::UnionId(it)) => {
-                let src = it.lookup(db).source(db);
+                let src = it.source(db);
                 generics.fill(&mut sm, &src.value);
                 src.file_id
             }
             GenericDefId::AdtId(AdtId::EnumId(it)) => {
-                let src = it.lookup(db).source(db);
+                let src = it.source(db);
                 generics.fill(&mut sm, &src.value);
                 src.file_id
             }
             GenericDefId::TraitId(it) => {
-                let src = it.lookup(db).source(db);
+                let src = it.source(db);
 
                 // traits get the Self type as an implicit first type parameter
                 let self_param_id =
@@ -109,7 +109,7 @@ impl GenericParams {
             // type-parameter, but rather is a type-alias for impl's target
             // type, so this is handled by the resolver.
             GenericDefId::ImplId(it) => {
-                let src = it.lookup(db).source(db);
+                let src = it.source(db);
                 generics.fill(&mut sm, &src.value);
                 src.file_id
             }
diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs
index d844f7a627..be702a4f80 100644
--- a/crates/ra_hir_def/src/keys.rs
+++ b/crates/ra_hir_def/src/keys.rs
@@ -8,23 +8,16 @@ use rustc_hash::FxHashMap;
 
 use crate::{
     dyn_map::{DynMap, Policy},
-    ConstId, EnumId, EnumVariantId, FunctionId, ImplId, StaticId, StructFieldId, StructId, TraitId,
-    TypeAliasId, TypeParamId, UnionId,
+    ConstId, EnumVariantId, FunctionId, StaticId, StructFieldId, TypeAliasId, TypeParamId,
 };
 
-pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
+type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
 
 pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new();
 pub const CONST: Key<ast::ConstDef, ConstId> = Key::new();
 pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new();
-pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new();
-pub const IMPL: Key<ast::ImplBlock, ImplId> = Key::new();
-pub const TRAIT: Key<ast::TraitDef, TraitId> = Key::new();
-pub const STRUCT: Key<ast::StructDef, StructId> = Key::new();
-pub const UNION: Key<ast::UnionDef, UnionId> = Key::new();
-pub const ENUM: Key<ast::EnumDef, EnumId> = Key::new();
-
 pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new();
+pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new();
 pub const TUPLE_FIELD: Key<ast::TupleFieldDef, StructFieldId> = Key::new();
 pub const RECORD_FIELD: Key<ast::RecordFieldDef, StructFieldId> = Key::new();
 pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index f085bbe872..569da4f284 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -40,14 +40,14 @@ mod test_db;
 #[cfg(test)]
 mod marks;
 
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
 
-use hir_expand::{ast_id_map::FileAstId, AstId, HirFileId, InFile, MacroDefId};
+use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, InFile, MacroDefId};
 use ra_arena::{impl_arena_id, RawId};
 use ra_db::{impl_intern_key, salsa, CrateId};
-use ra_syntax::ast;
+use ra_syntax::{ast, AstNode};
 
-use crate::builtin_type::BuiltinType;
+use crate::{builtin_type::BuiltinType, db::InternDatabase};
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct LocalImportId(RawId);
@@ -65,6 +65,63 @@ pub struct ModuleId {
 pub struct LocalModuleId(RawId);
 impl_arena_id!(LocalModuleId);
 
+#[derive(Debug)]
+pub struct ItemLoc<N: AstNode> {
+    pub(crate) module: ModuleId,
+    ast_id: AstId<N>,
+}
+
+impl<N: AstNode> PartialEq for ItemLoc<N> {
+    fn eq(&self, other: &Self) -> bool {
+        self.module == other.module && self.ast_id == other.ast_id
+    }
+}
+impl<N: AstNode> Eq for ItemLoc<N> {}
+impl<N: AstNode> Hash for ItemLoc<N> {
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        self.module.hash(hasher);
+        self.ast_id.hash(hasher);
+    }
+}
+
+impl<N: AstNode> Clone for ItemLoc<N> {
+    fn clone(&self) -> ItemLoc<N> {
+        ItemLoc { module: self.module, ast_id: self.ast_id }
+    }
+}
+
+#[derive(Clone, Copy)]
+pub struct LocationCtx<DB> {
+    db: DB,
+    module: ModuleId,
+    file_id: HirFileId,
+}
+
+impl<'a, DB> LocationCtx<&'a DB> {
+    pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> {
+        LocationCtx { db, module, file_id }
+    }
+}
+
+pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
+    fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self;
+    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>;
+
+    fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self {
+        let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) };
+        Self::intern(ctx.db, loc)
+    }
+    fn source(self, db: &(impl AstDatabase + InternDatabase)) -> InFile<N> {
+        let loc = self.lookup_intern(db);
+        let value = loc.ast_id.to_node(db);
+        InFile { file_id: loc.ast_id.file_id, value }
+    }
+    fn module(self, db: &impl InternDatabase) -> ModuleId {
+        let loc = self.lookup_intern(db);
+        loc.module
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct FunctionId(salsa::InternId);
 impl_intern_key!(FunctionId);
@@ -92,72 +149,36 @@ impl Lookup for FunctionId {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct StructId(salsa::InternId);
 impl_intern_key!(StructId);
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct StructLoc {
-    pub container: ModuleId,
-    pub ast_id: AstId<ast::StructDef>,
-}
-
-impl Intern for StructLoc {
-    type ID = StructId;
-    fn intern(self, db: &impl db::DefDatabase) -> StructId {
-        db.intern_struct(self)
+impl AstItemDef<ast::StructDef> for StructId {
+    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
+        db.intern_struct(loc)
     }
-}
-
-impl Lookup for StructId {
-    type Data = StructLoc;
-    fn lookup(&self, db: &impl db::DefDatabase) -> StructLoc {
-        db.lookup_intern_struct(*self)
+    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
+        db.lookup_intern_struct(self)
     }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct UnionId(salsa::InternId);
 impl_intern_key!(UnionId);
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct UnionLoc {
-    pub container: ModuleId,
-    pub ast_id: AstId<ast::UnionDef>,
-}
-
-impl Intern for UnionLoc {
-    type ID = UnionId;
-    fn intern(self, db: &impl db::DefDatabase) -> UnionId {
-        db.intern_union(self)
+impl AstItemDef<ast::UnionDef> for UnionId {
+    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::UnionDef>) -> Self {
+        db.intern_union(loc)
     }
-}
-
-impl Lookup for UnionId {
-    type Data = UnionLoc;
-    fn lookup(&self, db: &impl db::DefDatabase) -> UnionLoc {
-        db.lookup_intern_union(*self)
+    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::UnionDef> {
+        db.lookup_intern_union(self)
     }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct EnumId(salsa::InternId);
 impl_intern_key!(EnumId);
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct EnumLoc {
-    pub container: ModuleId,
-    pub ast_id: AstId<ast::EnumDef>,
-}
-
-impl Intern for EnumLoc {
-    type ID = EnumId;
-    fn intern(self, db: &impl db::DefDatabase) -> EnumId {
-        db.intern_enum(self)
+impl AstItemDef<ast::EnumDef> for EnumId {
+    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
+        db.intern_enum(loc)
     }
-}
-
-impl Lookup for EnumId {
-    type Data = EnumLoc;
-    fn lookup(&self, db: &impl db::DefDatabase) -> EnumLoc {
-        db.lookup_intern_enum(*self)
+    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
+        db.lookup_intern_enum(self)
     }
 }
 
@@ -232,24 +253,12 @@ impl Lookup for StaticId {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct TraitId(salsa::InternId);
 impl_intern_key!(TraitId);
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TraitLoc {
-    pub container: ModuleId,
-    pub ast_id: AstId<ast::TraitDef>,
-}
-
-impl Intern for TraitLoc {
-    type ID = TraitId;
-    fn intern(self, db: &impl db::DefDatabase) -> TraitId {
-        db.intern_trait(self)
+impl AstItemDef<ast::TraitDef> for TraitId {
+    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
+        db.intern_trait(loc)
     }
-}
-
-impl Lookup for TraitId {
-    type Data = TraitLoc;
-    fn lookup(&self, db: &impl db::DefDatabase) -> TraitLoc {
-        db.lookup_intern_trait(*self)
+    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
+        db.lookup_intern_trait(self)
     }
 }
 
@@ -280,24 +289,12 @@ impl Lookup for TypeAliasId {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct ImplId(salsa::InternId);
 impl_intern_key!(ImplId);
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ImplLoc {
-    pub container: ModuleId,
-    pub ast_id: AstId<ast::ImplBlock>,
-}
-
-impl Intern for ImplLoc {
-    type ID = ImplId;
-    fn intern(self, db: &impl db::DefDatabase) -> ImplId {
-        db.intern_impl(self)
+impl AstItemDef<ast::ImplBlock> for ImplId {
+    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ImplBlock>) -> Self {
+        db.intern_impl(loc)
     }
-}
-
-impl Lookup for ImplId {
-    type Data = ImplLoc;
-    fn lookup(&self, db: &impl db::DefDatabase) -> ImplLoc {
-        db.lookup_intern_impl(*self)
+    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ImplBlock> {
+        db.lookup_intern_impl(self)
     }
 }
 
@@ -482,8 +479,8 @@ impl HasModule for FunctionLoc {
     fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
         match self.container {
             ContainerId::ModuleId(it) => it,
-            ContainerId::ImplId(it) => it.lookup(db).container,
-            ContainerId::TraitId(it) => it.lookup(db).container,
+            ContainerId::ImplId(it) => it.module(db),
+            ContainerId::TraitId(it) => it.module(db),
         }
     }
 }
@@ -492,8 +489,8 @@ impl HasModule for TypeAliasLoc {
     fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
         match self.container {
             ContainerId::ModuleId(it) => it,
-            ContainerId::ImplId(it) => it.lookup(db).container,
-            ContainerId::TraitId(it) => it.lookup(db).container,
+            ContainerId::ImplId(it) => it.module(db),
+            ContainerId::TraitId(it) => it.module(db),
         }
     }
 }
@@ -502,8 +499,8 @@ impl HasModule for ConstLoc {
     fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
         match self.container {
             ContainerId::ModuleId(it) => it,
-            ContainerId::ImplId(it) => it.lookup(db).container,
-            ContainerId::TraitId(it) => it.lookup(db).container,
+            ContainerId::ImplId(it) => it.module(db),
+            ContainerId::TraitId(it) => it.module(db),
         }
     }
 }
@@ -511,9 +508,9 @@ impl HasModule for ConstLoc {
 impl HasModule for AdtId {
     fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
         match self {
-            AdtId::StructId(it) => it.lookup(db).container,
-            AdtId::UnionId(it) => it.lookup(db).container,
-            AdtId::EnumId(it) => it.lookup(db).container,
+            AdtId::StructId(it) => it.module(db),
+            AdtId::UnionId(it) => it.module(db),
+            AdtId::EnumId(it) => it.module(db),
         }
     }
 }
@@ -533,10 +530,10 @@ impl HasModule for GenericDefId {
         match self {
             GenericDefId::FunctionId(it) => it.lookup(db).module(db),
             GenericDefId::AdtId(it) => it.module(db),
-            GenericDefId::TraitId(it) => it.lookup(db).container,
+            GenericDefId::TraitId(it) => it.module(db),
             GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
-            GenericDefId::ImplId(it) => it.lookup(db).container,
-            GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container,
+            GenericDefId::ImplId(it) => it.module(db),
+            GenericDefId::EnumVariantId(it) => it.parent.module(db),
             GenericDefId::ConstId(it) => it.lookup(db).module(db),
         }
     }
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 04aadead19..a80067979f 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -24,9 +24,9 @@ use crate::{
     },
     path::{Path, PathKind},
     per_ns::PerNs,
-    AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
-    LocalImportId, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc,
-    TypeAliasLoc, UnionLoc,
+    AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplId,
+    Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticLoc, StructId,
+    TraitId, TypeAliasLoc, UnionId,
 };
 
 pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -661,11 +661,9 @@ where
                             krate: self.def_collector.def_map.krate,
                             local_id: self.module_id,
                         };
-                        let ast_id = self.raw_items[imp].ast_id;
-                        let impl_id =
-                            ImplLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) }
-                                .intern(self.def_collector.db);
-                        self.def_collector.def_map.modules[self.module_id].impls.push(impl_id)
+                        let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id);
+                        let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id);
+                        self.def_collector.def_map.modules[self.module_id].impls.push(imp_id)
                     }
                 }
             }
@@ -753,6 +751,8 @@ where
 
     fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) {
         let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
+        let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id);
+
         // FIXME: check attrs to see if this is an attribute macro invocation;
         // in which case we don't add the invocation, just a single attribute
         // macro invocation
@@ -771,20 +771,14 @@ where
                 PerNs::values(def.into())
             }
             raw::DefKind::Struct(ast_id) => {
-                let def = StructLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) }
-                    .intern(self.def_collector.db);
-                PerNs::both(def.into(), def.into())
+                let id = StructId::from_ast_id(ctx, ast_id).into();
+                PerNs::both(id, id)
             }
             raw::DefKind::Union(ast_id) => {
-                let def = UnionLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) }
-                    .intern(self.def_collector.db);
-                PerNs::both(def.into(), def.into())
-            }
-            raw::DefKind::Enum(ast_id) => {
-                let def = EnumLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) }
-                    .intern(self.def_collector.db);
-                PerNs::types(def.into())
+                let id = UnionId::from_ast_id(ctx, ast_id).into();
+                PerNs::both(id, id)
             }
+            raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
             raw::DefKind::Const(ast_id) => {
                 let def = ConstLoc {
                     container: ContainerId::ModuleId(module),
@@ -800,12 +794,7 @@ where
 
                 PerNs::values(def.into())
             }
-            raw::DefKind::Trait(ast_id) => {
-                let def = TraitLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) }
-                    .intern(self.def_collector.db);
-
-                PerNs::types(def.into())
-            }
+            raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()),
             raw::DefKind::TypeAlias(ast_id) => {
                 let def = TypeAliasLoc {
                     container: ContainerId::ModuleId(module),
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index ec9d13e827..e547b2f03c 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -1,5 +1,4 @@
 //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
-mod lower_use;
 
 use std::{iter, sync::Arc};
 
@@ -10,7 +9,7 @@ use hir_expand::{
 };
 use ra_db::CrateId;
 use ra_syntax::{
-    ast::{self, TypeAscriptionOwner},
+    ast::{self, NameOwner, TypeAscriptionOwner},
     AstNode,
 };
 
@@ -29,7 +28,8 @@ pub struct PathSegment {
 }
 
 /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
-/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
+/// can (in the future) also include bindings of associated types, like in
+/// `Iterator<Item = Foo>`.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GenericArgs {
     pub args: Vec<GenericArg>,
@@ -72,7 +72,7 @@ impl Path {
         mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
     ) {
         if let Some(tree) = item_src.value.use_tree() {
-            lower_use::lower_use_tree(None, tree, hygiene, &mut cb);
+            expand_use_tree(None, tree, hygiene, &mut cb);
         }
     }
 
@@ -296,6 +296,108 @@ impl From<Name> for Path {
     }
 }
 
+fn expand_use_tree(
+    prefix: Option<Path>,
+    tree: ast::UseTree,
+    hygiene: &Hygiene,
+    cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>),
+) {
+    if let Some(use_tree_list) = tree.use_tree_list() {
+        let prefix = match tree.path() {
+            // E.g. use something::{{{inner}}};
+            None => prefix,
+            // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
+            // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
+            Some(path) => match convert_path(prefix, path, hygiene) {
+                Some(it) => Some(it),
+                None => return, // FIXME: report errors somewhere
+            },
+        };
+        for child_tree in use_tree_list.use_trees() {
+            expand_use_tree(prefix.clone(), child_tree, hygiene, cb);
+        }
+    } else {
+        let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
+        if let Some(ast_path) = tree.path() {
+            // Handle self in a path.
+            // E.g. `use something::{self, <...>}`
+            if ast_path.qualifier().is_none() {
+                if let Some(segment) = ast_path.segment() {
+                    if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
+                        if let Some(prefix) = prefix {
+                            cb(prefix, &tree, false, alias);
+                            return;
+                        }
+                    }
+                }
+            }
+            if let Some(path) = convert_path(prefix, ast_path, hygiene) {
+                let is_glob = tree.has_star();
+                cb(path, &tree, is_glob, alias)
+            }
+            // FIXME: report errors somewhere
+            // We get here if we do
+        }
+    }
+}
+
+fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
+    let prefix = if let Some(qual) = path.qualifier() {
+        Some(convert_path(prefix, qual, hygiene)?)
+    } else {
+        prefix
+    };
+
+    let segment = path.segment()?;
+    let res = match segment.kind()? {
+        ast::PathSegmentKind::Name(name_ref) => {
+            match hygiene.name_ref_to_name(name_ref) {
+                Either::Left(name) => {
+                    // no type args in use
+                    let mut res = prefix.unwrap_or_else(|| Path {
+                        kind: PathKind::Plain,
+                        segments: Vec::with_capacity(1),
+                    });
+                    res.segments.push(PathSegment {
+                        name,
+                        args_and_bindings: None, // no type args in use
+                    });
+                    res
+                }
+                Either::Right(crate_id) => {
+                    return Some(Path::from_simple_segments(
+                        PathKind::DollarCrate(crate_id),
+                        iter::empty(),
+                    ))
+                }
+            }
+        }
+        ast::PathSegmentKind::CrateKw => {
+            if prefix.is_some() {
+                return None;
+            }
+            Path::from_simple_segments(PathKind::Crate, iter::empty())
+        }
+        ast::PathSegmentKind::SelfKw => {
+            if prefix.is_some() {
+                return None;
+            }
+            Path::from_simple_segments(PathKind::Self_, iter::empty())
+        }
+        ast::PathSegmentKind::SuperKw => {
+            if prefix.is_some() {
+                return None;
+            }
+            Path::from_simple_segments(PathKind::Super, iter::empty())
+        }
+        ast::PathSegmentKind::Type { .. } => {
+            // not allowed in imports
+            return None;
+        }
+    };
+    Some(res)
+}
+
 pub mod known {
     use hir_expand::name;
 
diff --git a/crates/ra_hir_def/src/path/lower_use.rs b/crates/ra_hir_def/src/path/lower_use.rs
deleted file mode 100644
index e2e1f716dc..0000000000
--- a/crates/ra_hir_def/src/path/lower_use.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-//! Lowers a single complex use like `use foo::{bar, baz};` into a list of paths like
-//! `foo::bar`, `foo::baz`;
-
-use std::iter;
-
-use either::Either;
-use hir_expand::{
-    hygiene::Hygiene,
-    name::{AsName, Name},
-};
-use ra_syntax::ast::{self, NameOwner};
-
-use crate::path::{Path, PathKind, PathSegment};
-
-pub(crate) fn lower_use_tree(
-    prefix: Option<Path>,
-    tree: ast::UseTree,
-    hygiene: &Hygiene,
-    cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>),
-) {
-    if let Some(use_tree_list) = tree.use_tree_list() {
-        let prefix = match tree.path() {
-            // E.g. use something::{{{inner}}};
-            None => prefix,
-            // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
-            // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
-            Some(path) => match convert_path(prefix, path, hygiene) {
-                Some(it) => Some(it),
-                None => return, // FIXME: report errors somewhere
-            },
-        };
-        for child_tree in use_tree_list.use_trees() {
-            lower_use_tree(prefix.clone(), child_tree, hygiene, cb);
-        }
-    } else {
-        let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
-        if let Some(ast_path) = tree.path() {
-            // Handle self in a path.
-            // E.g. `use something::{self, <...>}`
-            if ast_path.qualifier().is_none() {
-                if let Some(segment) = ast_path.segment() {
-                    if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
-                        if let Some(prefix) = prefix {
-                            cb(prefix, &tree, false, alias);
-                            return;
-                        }
-                    }
-                }
-            }
-            if let Some(path) = convert_path(prefix, ast_path, hygiene) {
-                let is_glob = tree.has_star();
-                cb(path, &tree, is_glob, alias)
-            }
-            // FIXME: report errors somewhere
-            // We get here if we do
-        }
-    }
-}
-
-fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
-    let prefix = if let Some(qual) = path.qualifier() {
-        Some(convert_path(prefix, qual, hygiene)?)
-    } else {
-        prefix
-    };
-
-    let segment = path.segment()?;
-    let res = match segment.kind()? {
-        ast::PathSegmentKind::Name(name_ref) => {
-            match hygiene.name_ref_to_name(name_ref) {
-                Either::Left(name) => {
-                    // no type args in use
-                    let mut res = prefix.unwrap_or_else(|| Path {
-                        kind: PathKind::Plain,
-                        segments: Vec::with_capacity(1),
-                    });
-                    res.segments.push(PathSegment {
-                        name,
-                        args_and_bindings: None, // no type args in use
-                    });
-                    res
-                }
-                Either::Right(crate_id) => {
-                    return Some(Path::from_simple_segments(
-                        PathKind::DollarCrate(crate_id),
-                        iter::empty(),
-                    ))
-                }
-            }
-        }
-        ast::PathSegmentKind::CrateKw => {
-            if prefix.is_some() {
-                return None;
-            }
-            Path::from_simple_segments(PathKind::Crate, iter::empty())
-        }
-        ast::PathSegmentKind::SelfKw => {
-            if prefix.is_some() {
-                return None;
-            }
-            Path::from_simple_segments(PathKind::Self_, iter::empty())
-        }
-        ast::PathSegmentKind::SuperKw => {
-            if prefix.is_some() {
-                return None;
-            }
-            Path::from_simple_segments(PathKind::Super, iter::empty())
-        }
-        ast::PathSegmentKind::Type { .. } => {
-            // not allowed in imports
-            return None;
-        }
-    };
-    Some(res)
-}
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 17b2169d2a..9484a61d53 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -17,9 +17,9 @@ use crate::{
     nameres::{BuiltinShadowMode, CrateDefMap},
     path::{Path, PathKind},
     per_ns::PerNs,
-    AdtId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId,
-    HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId,
-    TypeAliasId, TypeParamId, VariantId,
+    AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
+    GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId,
+    StructId, TraitId, TypeAliasId, TypeParamId, VariantId,
 };
 
 #[derive(Debug, Clone, Default)]
@@ -524,7 +524,7 @@ impl HasResolver for ModuleId {
 
 impl HasResolver for TraitId {
     fn resolver(self, db: &impl DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
+        self.module(db).resolver(db).push_generic_params_scope(db, self.into())
     }
 }
 
@@ -564,8 +564,7 @@ impl HasResolver for TypeAliasId {
 
 impl HasResolver for ImplId {
     fn resolver(self, db: &impl DefDatabase) -> Resolver {
-        self.lookup(db)
-            .container
+        self.module(db)
             .resolver(db)
             .push_generic_params_scope(db, self.into())
             .push_impl_block_scope(self)
diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs
index 20200d1db4..27caa02cc4 100644
--- a/crates/ra_hir_def/src/src.rs
+++ b/crates/ra_hir_def/src/src.rs
@@ -4,10 +4,7 @@ use hir_expand::InFile;
 use ra_arena::map::ArenaMap;
 use ra_syntax::ast;
 
-use crate::{
-    db::DefDatabase, ConstLoc, EnumLoc, FunctionLoc, ImplLoc, StaticLoc, StructLoc, TraitLoc,
-    TypeAliasLoc, UnionLoc,
-};
+use crate::{db::DefDatabase, ConstLoc, FunctionLoc, StaticLoc, TypeAliasLoc};
 
 pub trait HasSource {
     type Value;
@@ -50,51 +47,6 @@ impl HasSource for StaticLoc {
     }
 }
 
-impl HasSource for ImplLoc {
-    type Value = ast::ImplBlock;
-
-    fn source(&self, db: &impl DefDatabase) -> InFile<ast::ImplBlock> {
-        let node = self.ast_id.to_node(db);
-        InFile::new(self.ast_id.file_id, node)
-    }
-}
-
-impl HasSource for TraitLoc {
-    type Value = ast::TraitDef;
-
-    fn source(&self, db: &impl DefDatabase) -> InFile<ast::TraitDef> {
-        let node = self.ast_id.to_node(db);
-        InFile::new(self.ast_id.file_id, node)
-    }
-}
-
-impl HasSource for StructLoc {
-    type Value = ast::StructDef;
-
-    fn source(&self, db: &impl DefDatabase) -> InFile<ast::StructDef> {
-        let node = self.ast_id.to_node(db);
-        InFile::new(self.ast_id.file_id, node)
-    }
-}
-
-impl HasSource for UnionLoc {
-    type Value = ast::UnionDef;
-
-    fn source(&self, db: &impl DefDatabase) -> InFile<ast::UnionDef> {
-        let node = self.ast_id.to_node(db);
-        InFile::new(self.ast_id.file_id, node)
-    }
-}
-
-impl HasSource for EnumLoc {
-    type Value = ast::EnumDef;
-
-    fn source(&self, db: &impl DefDatabase) -> InFile<ast::EnumDef> {
-        let node = self.ast_id.to_node(db);
-        InFile::new(self.ast_id.file_id, node)
-    }
-}
-
 pub trait HasChildSource {
     type ChildId;
     type Value;
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index be5f3cbe35..ec5ace757c 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -367,9 +367,6 @@ mod tests {
             BuiltinFnLikeExpander::FormatArgs,
         );
 
-        assert_eq!(
-            expanded,
-            r#"std::fmt::Arguments::new_v1(&[] ,&[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"#
-        );
+        assert_eq!(expanded, r#"std::fmt::Arguments::new_v1(&[] ,&[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"#);
     }
 }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 5f795bc022..eab91229e3 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -14,7 +14,7 @@ use hir_def::{
     path::{GenericArg, Path, PathKind, PathSegment},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{TypeBound, TypeRef},
-    AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
+    AdtId, AstItemDef, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
     LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
 };
 use ra_arena::map::ArenaMap;
@@ -698,11 +698,10 @@ impl_froms!(CallableDef: FunctionId, StructId, EnumVariantId);
 impl CallableDef {
     pub fn krate(self, db: &impl HirDatabase) -> CrateId {
         match self {
-            CallableDef::FunctionId(f) => f.lookup(db).module(db),
-            CallableDef::StructId(s) => s.lookup(db).container,
-            CallableDef::EnumVariantId(e) => e.parent.lookup(db).container,
+            CallableDef::FunctionId(f) => f.lookup(db).module(db).krate,
+            CallableDef::StructId(s) => s.module(db).krate,
+            CallableDef::EnumVariantId(e) => e.parent.module(db).krate,
         }
-        .krate
     }
 }
 
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 848e306e9e..7220d6e0a7 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -6,8 +6,8 @@ use std::sync::Arc;
 
 use arrayvec::ArrayVec;
 use hir_def::{
-    lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, FunctionId,
-    HasModule, ImplId, Lookup, TraitId,
+    lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef,
+    FunctionId, HasModule, ImplId, Lookup, TraitId,
 };
 use hir_expand::name::Name;
 use ra_db::CrateId;
@@ -134,7 +134,7 @@ impl Ty {
                 LangItemTarget::ImplBlockId(it) => Some(it),
                 _ => None,
             })
-            .map(|it| it.lookup(db).container.krate)
+            .map(|it| it.module(db).krate)
             .collect();
         Some(res)
     }
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index fc21872b2b..1e7ff93d59 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -9,7 +9,9 @@ use chalk_ir::{
 };
 use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
 
-use hir_def::{AssocItemId, ContainerId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId};
+use hir_def::{
+    AssocItemId, AstItemDef, ContainerId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId,
+};
 use ra_db::{
     salsa::{InternId, InternKey},
     CrateId,
@@ -591,7 +593,7 @@ pub(crate) fn trait_datum_query(
     let bound_vars = Substs::bound_vars(&generic_params);
     let flags = chalk_rust_ir::TraitFlags {
         auto: trait_data.auto,
-        upstream: trait_.lookup(db).container.krate != krate,
+        upstream: trait_.module(db).krate != krate,
         non_enumerable: true,
         coinductive: false, // only relevant for Chalk testing
         // FIXME set these flags correctly
@@ -671,7 +673,7 @@ fn impl_block_datum(
     let bound_vars = Substs::bound_vars(&generic_params);
     let trait_ref = trait_ref.subst(&bound_vars);
     let trait_ = trait_ref.trait_;
-    let impl_type = if impl_id.lookup(db).container.krate == krate {
+    let impl_type = if impl_id.module(db).krate == krate {
         chalk_rust_ir::ImplType::Local
     } else {
         chalk_rust_ir::ImplType::External
diff --git a/crates/ra_ide/src/expand.rs b/crates/ra_ide/src/expand.rs
index 216d5cfec7..661628ae46 100644
--- a/crates/ra_ide/src/expand.rs
+++ b/crates/ra_ide/src/expand.rs
@@ -3,7 +3,7 @@ use std::iter::successors;
 
 use hir::InFile;
 use ra_db::FileId;
-use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken};
+use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange};
 
 use crate::{db::RootDatabase, FileRange};
 
@@ -17,26 +17,45 @@ pub(crate) fn original_range(db: &RootDatabase, node: InFile<&SyntaxNode>) -> Fi
         }
         Some(it) => it,
     };
-    // FIXME: the following completely wrong.
-    //
-    // *First*, we should try to map first and last tokens of node, and, if that
-    // fails, return the range of the overall macro expansions.
-    //
-    // *Second*, we should handle recurside macro expansions
-
-    let token = node
-        .value
-        .descendants_with_tokens()
-        .filter_map(|it| it.into_token())
-        .find_map(|it| expansion.map_token_up(node.with_value(&it)));
-
-    match token {
-        Some(it) => {
-            FileRange { file_id: it.file_id.original_file(db), range: it.value.text_range() }
+    // FIXME: We should handle recurside macro expansions
+
+    let range = node.value.descendants_with_tokens().find_map(|it| {
+        match it.as_token() {
+            // FIXME: Remove this branch after all `tt::TokenTree`s have a proper `TokenId`,
+            // and return the range of the overall macro expansions if mapping first and last tokens fails.
+            Some(token) => {
+                let token = expansion.map_token_up(node.with_value(&token))?;
+                Some(token.with_value(token.value.text_range()))
+            }
+            None => {
+                // Try to map first and last tokens of node, and, if success, return the union range of mapped tokens
+                let n = it.into_node()?;
+                let first = expansion.map_token_up(node.with_value(&n.first_token()?))?;
+                let last = expansion.map_token_up(node.with_value(&n.last_token()?))?;
+
+                // FIXME: Is is possible ?
+                if first.file_id != last.file_id {
+                    return None;
+                }
+
+                // FIXME: Add union method in TextRange
+                let range = union_range(first.value.text_range(), last.value.text_range());
+                Some(first.with_value(range))
+            }
         }
+    });
+
+    return match range {
+        Some(it) => FileRange { file_id: it.file_id.original_file(db), range: it.value },
         None => {
             FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() }
         }
+    };
+
+    fn union_range(a: TextRange, b: TextRange) -> TextRange {
+        let start = a.start().min(b.start());
+        let end = a.end().max(b.end());
+        TextRange::from_to(start, end)
     }
 }
 
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index e29b688fdb..41672eaffe 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -14,7 +14,7 @@ serde_json = "1.0.34"
 serde = { version = "1.0.83", features = ["derive"] }
 crossbeam-channel = "0.4"
 log = "0.4.3"
-lsp-types = { version = "0.63.1", features = ["proposed"] }
+lsp-types = { version = "0.61.0", features = ["proposed"] }
 rustc-hash = "1.0"
 parking_lot = "0.10.0"
 jod-thread = "0.1.0"
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index e0bb756666..eea0965edb 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -5,7 +5,7 @@ use lsp_types::{
     DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, GenericCapability,
     ImplementationProviderCapability, RenameOptions, RenameProviderCapability, ServerCapabilities,
     SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
-    TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions,
+    TextDocumentSyncOptions, TypeDefinitionProviderCapability,
 };
 
 pub fn server_capabilities() -> ServerCapabilities {
@@ -21,14 +21,10 @@ pub fn server_capabilities() -> ServerCapabilities {
         completion_provider: Some(CompletionOptions {
             resolve_provider: None,
             trigger_characters: Some(vec![":".to_string(), ".".to_string()]),
-            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
         }),
         signature_help_provider: Some(SignatureHelpOptions {
-            trigger_characters: Some(vec!["(".to_string(), ",".to_string()]),
-            retrigger_characters: None,
-            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
+            trigger_characters: Some(vec!["(".to_string(), ",".to_string(), ")".to_string()]),
         }),
-        declaration_provider: None,
         definition_provider: Some(true),
         type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
         implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
@@ -48,7 +44,6 @@ pub fn server_capabilities() -> ServerCapabilities {
         folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
         rename_provider: Some(RenameProviderCapability::Options(RenameOptions {
             prepare_provider: Some(true),
-            work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
         })),
         document_link_provider: None,
         color_provider: None,
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 158cac0be1..83845f1e00 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -520,8 +520,7 @@ fn on_notification(
             if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
                 subs.remove_sub(FileId(file_id.0));
             }
-            let params =
-                req::PublishDiagnosticsParams { uri, diagnostics: Vec::new(), version: None };
+            let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new() };
             let not = notification_new::<req::PublishDiagnostics>(params);
             msg_sender.send(not.into()).unwrap();
             return Ok(());
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 5b64b27cd2..4095836344 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -648,7 +648,6 @@ pub fn handle_code_action(
             diagnostics: None,
             edit: None,
             command: Some(command),
-            is_preferred: None,
         };
         res.push(action.into());
     }
@@ -671,7 +670,6 @@ pub fn handle_code_action(
             diagnostics: None,
             edit: None,
             command: Some(command),
-            is_preferred: None,
         };
         res.push(action.into());
     }
@@ -830,10 +828,9 @@ pub fn publish_diagnostics(
             source: Some("rust-analyzer".to_string()),
             message: d.message,
             related_information: None,
-            tags: None,
         })
         .collect();
-    Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None })
+    Ok(req::PublishDiagnosticsParams { uri, diagnostics })
 }
 
 pub fn publish_decorations(
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index b6ebb129d0..1c0b184e1f 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -18,14 +18,13 @@ rustc-hash = "1.0.1"
 arrayvec = "0.5.1"
 once_cell = "1.2.0"
 
-ra_text_edit = { path = "../ra_text_edit" }
-ra_parser = { path = "../ra_parser" }
-
 # This crate transitively depends on `smol_str` via `rowan`.
 # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
 # to reduce number of compilations
 smol_str = { version = "0.1.12", features = ["serde"] }
-serde = { version = "1", features = ["derive"] }
+
+ra_text_edit = { path = "../ra_text_edit" }
+ra_parser = { path = "../ra_parser" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts
index 2777ced247..9e4ce0eb3c 100644
--- a/editors/code/src/commands/analyzer_status.ts
+++ b/editors/code/src/commands/analyzer_status.ts
@@ -9,7 +9,7 @@ export class TextDocumentContentProvider
     public syntaxTree: string = 'Not available';
 
     public provideTextDocumentContent(
-        _uri: vscode.Uri,
+        uri: vscode.Uri,
     ): vscode.ProviderResult<string> {
         const editor = vscode.window.activeTextEditor;
         if (editor == null) {
diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts
index 17c78280a8..842898020b 100644
--- a/editors/code/src/commands/expand_macro.ts
+++ b/editors/code/src/commands/expand_macro.ts
@@ -11,7 +11,7 @@ export class ExpandMacroContentProvider
     public eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 
     public provideTextDocumentContent(
-        _uri: vscode.Uri,
+        uri: vscode.Uri,
     ): vscode.ProviderResult<string> {
         async function handle() {
             const editor = vscode.window.activeTextEditor;
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index cf980e2578..9b1c6643d4 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -73,7 +73,7 @@ function createTask(spec: Runnable): vscode.Task {
 }
 
 let prevRunnable: RunnableQuickPick | undefined;
-export async function handle(): Promise<vscode.TaskExecution | undefined> {
+export async function handle() {
     const editor = vscode.window.activeTextEditor;
     if (editor == null || editor.document.languageId !== 'rust') {
         return;
@@ -105,14 +105,12 @@ export async function handle(): Promise<vscode.TaskExecution | undefined> {
         items.push(new RunnableQuickPick(r));
     }
     const item = await vscode.window.showQuickPick(items);
-    if (!item) {
-        return;
+    if (item) {
+        item.detail = 'rerun';
+        prevRunnable = item;
+        const task = createTask(item.runnable);
+        return await vscode.tasks.executeTask(task);
     }
-
-    item.detail = 'rerun';
-    prevRunnable = item;
-    const task = createTask(item.runnable);
-    return await vscode.tasks.executeTask(task);
 }
 
 export async function handleSingle(runnable: Runnable) {
@@ -180,7 +178,7 @@ export async function startCargoWatch(
         }
 
         const label = 'install-cargo-watch';
-        const taskFinished = new Promise((resolve, _reject) => {
+        const taskFinished = new Promise((resolve, reject) => {
             const disposable = vscode.tasks.onDidEndTask(({ execution }) => {
                 if (execution.task.name === label) {
                     disposable.dispose();
diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json
index 5e11c37751..9ad2e967b2 100644
--- a/editors/code/tsconfig.json
+++ b/editors/code/tsconfig.json
@@ -1,16 +1,13 @@
 {
     "compilerOptions": {
         "module": "commonjs",
-        "target": "es2018",
+        "target": "es6",
         "outDir": "out",
-        "lib": ["es2018"],
+        "lib": ["es6"],
         "sourceMap": true,
         "rootDir": "src",
         "strict": true,
-        "noUnusedLocals": true,
-        "noUnusedParameters": true,
-        "noImplicitReturns": true,
-        "noFallthroughCasesInSwitch": true
+        "noUnusedLocals": true
     },
     "exclude": ["node_modules", ".vscode-test"]
 }
diff --git a/editors/code/tslint.json b/editors/code/tslint.json
index b69c5574d2..bdeb4895ee 100644
--- a/editors/code/tslint.json
+++ b/editors/code/tslint.json
@@ -4,8 +4,6 @@
     "rules": {
         "quotemark": [true, "single"],
         "interface-name": false,
-        "object-literal-sort-keys": false,
-        // Allow `_bar` to sort with tsc's `noUnusedParameters` option
-        "variable-name": [true, "allow-leading-underscore"]
+        "object-literal-sort-keys": false
     }
 }


Test patch:
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index dff63a12d4..cfbf16ea5f 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -4,8 +4,7 @@ use std::{collections::HashMap, time::Instant};
 
 use lsp_types::{
     CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions,
-    PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams,
-    WorkDoneProgressParams,
+    Position, Range, TextDocumentItem, TextDocumentPositionParams,
 };
 use ra_lsp_server::req::{
     CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument,
@@ -49,8 +48,6 @@ use std::collections::Spam;
             Position::new(0, 23),
         ),
         context: None,
-        partial_result_params: PartialResultParams::default(),
-        work_done_progress_params: WorkDoneProgressParams::default(),
     });
     assert!(format!("{}", res).contains("HashMap"));
     eprintln!("completion took {:?}", completion_start.elapsed());
@@ -214,12 +211,8 @@ pub use std::collections::HashMap;
             options: FormattingOptions {
                 tab_size: 4,
                 insert_spaces: false,
-                insert_final_newline: None,
-                trim_final_newlines: None,
-                trim_trailing_whitespace: None,
                 properties: HashMap::new(),
             },
-            work_done_progress_params: WorkDoneProgressParams::default(),
         },
         json!([
             {
@@ -279,11 +272,7 @@ pub use std::collections::HashMap;
                 tab_size: 4,
                 insert_spaces: false,
                 properties: HashMap::new(),
-                insert_final_newline: None,
-                trim_final_newlines: None,
-                trim_trailing_whitespace: None,
             },
-            work_done_progress_params: WorkDoneProgressParams::default(),
         },
         json!([
             {
@@ -336,8 +325,6 @@ fn main() {}
             text_document: server.doc_id("src/lib.rs"),
             range: Range::new(Position::new(0, 4), Position::new(0, 7)),
             context: empty_context(),
-            partial_result_params: PartialResultParams::default(),
-            work_done_progress_params: WorkDoneProgressParams::default(),
         },
         json!([
           {
@@ -369,8 +356,6 @@ fn main() {}
             text_document: server.doc_id("src/lib.rs"),
             range: Range::new(Position::new(2, 4), Position::new(2, 7)),
             context: empty_context(),
-            partial_result_params: PartialResultParams::default(),
-            work_done_progress_params: WorkDoneProgressParams::default(),
         },
         json!([]),
     );
@@ -419,8 +404,6 @@ fn main() {{}}
             text_document: server.doc_id("src/lib.rs"),
             range: Range::new(Position::new(0, 4), Position::new(0, 7)),
             context: empty_context(),
-            partial_result_params: PartialResultParams::default(),
-            work_done_progress_params: WorkDoneProgressParams::default(),
         },
         json!([
           {
@@ -452,8 +435,6 @@ fn main() {{}}
             text_document: server.doc_id("src/lib.rs"),
             range: Range::new(Position::new(2, 4), Position::new(2, 7)),
             context: empty_context(),
-            partial_result_params: PartialResultParams::default(),
-            work_done_progress_params: WorkDoneProgressParams::default(),
         },
         json!([]),
     );
diff --git a/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts b/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
index 2b25eb705d..96ec8c614d 100644
--- a/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
+++ b/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
@@ -114,8 +114,7 @@ describe('SuggestedFix', () => {
 
             const edit = codeAction.edit;
             if (!edit) {
-                assert.fail('Code Action edit unexpectedly missing');
-                return;
+                return assert.fail('Code Action edit unexpectedly missing');
             }
 
             const editEntries = edit.entries();
diff --git a/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts b/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
index ef09013f41..4c1467b576 100644
--- a/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
+++ b/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
@@ -53,8 +53,7 @@ describe('SuggestedFixCollection', () => {
 
         const { diagnostics } = codeAction;
         if (!diagnostics) {
-            assert.fail('Diagnostics unexpectedly missing');
-            return;
+            return assert.fail('Diagnostics unexpectedly missing');
         }
 
         assert.strictEqual(diagnostics.length, 1);
@@ -115,8 +114,7 @@ describe('SuggestedFixCollection', () => {
         const { diagnostics } = codeAction;
 
         if (!diagnostics) {
-            assert.fail('Diagnostics unexpectedly missing');
-            return;
+            return assert.fail('Diagnostics unexpectedly missing');
         }
 
         // We should be associated with both diagnostics
diff --git a/editors/code/src/test/utils/diagnotics/rust.test.ts b/editors/code/src/test/utils/diagnotics/rust.test.ts
index 0222dbbaa0..cee59061f3 100644
--- a/editors/code/src/test/utils/diagnotics/rust.test.ts
+++ b/editors/code/src/test/utils/diagnotics/rust.test.ts
@@ -120,8 +120,7 @@ describe('mapRustDiagnosticToVsCode', () => {
         // One related information for the original definition
         const relatedInformation = diagnostic.relatedInformation;
         if (!relatedInformation) {
-            assert.fail('Related information unexpectedly undefined');
-            return;
+            return assert.fail('Related information unexpectedly undefined');
         }
         assert.strictEqual(relatedInformation.length, 1);
         const [related] = relatedInformation;
@@ -155,8 +154,7 @@ describe('mapRustDiagnosticToVsCode', () => {
         // One related information for the lint definition
         const relatedInformation = diagnostic.relatedInformation;
         if (!relatedInformation) {
-            assert.fail('Related information unexpectedly undefined');
-            return;
+            return assert.fail('Related information unexpectedly undefined');
         }
         assert.strictEqual(relatedInformation.length, 1);
         const [related] = relatedInformation;