Repository: rust-analyzer/rust-analyzer
Pull request #2205 (2019-11-11 06:29:24)

Implement bulitin line! macro
This PR implements bulitin macro `line!` and add basic infra-structure for other bulitin macros:

1. Extend `MacroDefId` to support builtin macros
2. Add a `quote!` macro for simple quasi quoting.

Note that for support others builtin macros, eager macro expansion have to be supported first, this PR not try to handle it. :)


Patch:
diff --git a/.travis.yml b/.travis.yml
index af71a9ccea..7d66f72d8f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,6 +14,7 @@ matrix:
           script:
               - rustup component add rustfmt
               - rustup component add rust-src
+              - sed -i "s/debug = 1/debug = false/g" Cargo.toml
               - cargo test --no-run  # let's measure compile time separately
               - cargo test
           env:
diff --git a/Cargo.toml b/Cargo.toml
index 5c57020f72..97c02b40f4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,9 +2,7 @@
 members = [ "crates/*", "xtask/" ]
 
 [profile.dev]
-# disabling debug info speeds up builds a bunch,
-# and we don't rely on it for debugging that much.
-debug = 0
+debug = 1 # only line info
 
 [profile.release]
 incremental = true
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index 945f236c22..0436d20b79 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -12,7 +12,7 @@ use crate::{
 
 impl Struct {
     pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
-        db.struct_data(self.id.into()).variant_data.clone()
+        db.struct_data(self.id).variant_data.clone()
     }
 }
 
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index e5bfad3ca8..9d0db80249 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -288,7 +288,7 @@ pub struct Struct {
 
 impl Struct {
     pub fn module(self, db: &impl DefDatabase) -> Module {
-        Module { id: self.id.0.module(db) }
+        Module { id: self.id.module(db) }
     }
 
     pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -296,11 +296,11 @@ impl Struct {
     }
 
     pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
-        db.struct_data(self.id.into()).name.clone()
+        db.struct_data(self.id).name.clone()
     }
 
     pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
-        db.struct_data(self.id.into())
+        db.struct_data(self.id)
             .variant_data
             .fields()
             .into_iter()
@@ -310,7 +310,7 @@ impl Struct {
     }
 
     pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
-        db.struct_data(self.id.into())
+        db.struct_data(self.id)
             .variant_data
             .fields()
             .into_iter()
@@ -346,11 +346,11 @@ pub struct Union {
 
 impl Union {
     pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
-        db.struct_data(self.id.into()).name.clone()
+        db.union_data(self.id).name.clone()
     }
 
     pub fn module(self, db: &impl HirDatabase) -> Module {
-        Module { id: self.id.0.module(db) }
+        Module { id: self.id.module(db) }
     }
 
     pub fn ty(self, db: &impl HirDatabase) -> Ty {
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 247ae3e55d..6d116ee75c 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -78,13 +78,13 @@ impl HasSource for StructField {
 impl HasSource for Struct {
     type Ast = ast::StructDef;
     fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> {
-        self.id.0.source(db)
+        self.id.source(db)
     }
 }
 impl HasSource for Union {
     type Ast = ast::StructDef;
     fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> {
-        self.id.0.source(db)
+        self.id.source(db)
     }
 }
 impl HasSource for Enum {
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index 5a1eade2cc..c14c2ab663 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -67,7 +67,10 @@ impl ExprScopes {
         &self.scopes[scope].entries
     }
 
-    pub(crate) fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
+    pub(crate) fn scope_chain<'a>(
+        &'a self,
+        scope: Option<ScopeId>,
+    ) -> impl Iterator<Item = ScopeId> + 'a {
         std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
     }
 
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index c95d2cdd05..9899bdbbce 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,6 +1,5 @@
 //! FIXME: write short doc here
 
-use hir_def::{StructId, StructOrUnionId, UnionId};
 use hir_expand::name::AsName;
 use ra_syntax::ast::{self, AstNode, NameOwner};
 
@@ -16,19 +15,18 @@ pub trait FromSource: Sized {
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>;
 }
 
-// FIXIME: these two impls are wrong, `ast::StructDef` might produce either a struct or a union
 impl FromSource for Struct {
     type Ast = ast::StructDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
-        let id: StructOrUnionId = from_source(db, src)?;
-        Some(Struct { id: StructId(id) })
+        let id = from_source(db, src)?;
+        Some(Struct { id })
     }
 }
 impl FromSource for Union {
     type Ast = ast::StructDef;
     fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
-        let id: StructOrUnionId = from_source(db, src)?;
-        Some(Union { id: UnionId(id) })
+        let id = from_source(db, src)?;
+        Some(Union { id })
     }
 }
 impl FromSource for Enum {
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 9dc8d139b3..131f6c797a 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -76,11 +76,7 @@ pub use crate::{
     resolve::ScopeDef,
     source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
     ty::{
-        display::HirDisplay,
-        primitive::{
-            FloatBitness, FloatTy, IntBitness, IntTy, Signedness, UncertainFloatTy, UncertainIntTy,
-        },
-        ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
+        display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
     },
 };
 
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 1fed5025eb..d26b16cb2f 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -665,7 +665,7 @@ fn type_for_builtin(def: BuiltinType) -> Ty {
 }
 
 fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
-    let struct_data = db.struct_data(def.id.into());
+    let struct_data = db.struct_data(def.id);
     let fields = match struct_data.variant_data.fields() {
         Some(fields) => fields,
         None => panic!("fn_sig_for_struct_constructor called on unit struct"),
@@ -681,7 +681,7 @@ fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
 
 /// Build the type of a tuple struct constructor.
 fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
-    let struct_data = db.struct_data(def.id.into());
+    let struct_data = db.struct_data(def.id);
     if struct_data.variant_data.fields().is_none() {
         return type_for_adt(db, def); // Unit struct
     }
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index a29c4d41e5..8f41e55d26 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -8,7 +8,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
 
 use crate::{
     db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId,
-    LocalStructFieldId, StructOrUnionId,
+    LocalStructFieldId, StructId, UnionId,
 };
 
 /// Note that we use `StructData` for unions as well!
@@ -49,11 +49,15 @@ pub struct StructFieldData {
 }
 
 impl StructData {
-    pub(crate) fn struct_data_query(
-        db: &impl DefDatabase2,
-        id: StructOrUnionId,
-    ) -> Arc<StructData> {
-        let src = id.source(db);
+    pub(crate) fn struct_data_query(db: &impl DefDatabase2, struct_: StructId) -> Arc<StructData> {
+        let src = struct_.source(db);
+        let name = src.ast.name().map(|n| n.as_name());
+        let variant_data = VariantData::new(src.ast.kind());
+        let variant_data = Arc::new(variant_data);
+        Arc::new(StructData { name, variant_data })
+    }
+    pub(crate) fn union_data_query(db: &impl DefDatabase2, struct_: UnionId) -> Arc<StructData> {
+        let src = struct_.source(db);
         let name = src.ast.name().map(|n| n.as_name());
         let variant_data = VariantData::new(src.ast.kind());
         let variant_data = Arc::new(variant_data);
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs
index 2ec0c83fe5..12929caa90 100644
--- a/crates/ra_hir_def/src/builtin_type.rs
+++ b/crates/ra_hir_def/src/builtin_type.rs
@@ -3,8 +3,6 @@
 //! A peculiarity of built-in types is that they are always available and are
 //! not associated with any particular crate.
 
-use std::fmt;
-
 use hir_expand::name::{self, Name};
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@@ -63,33 +61,3 @@ impl BuiltinType {
         (name::F64, BuiltinType::Float { bitness: FloatBitness::X64 }),
     ];
 }
-
-impl fmt::Display for BuiltinType {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let type_name = match self {
-            BuiltinType::Char => "char",
-            BuiltinType::Bool => "bool",
-            BuiltinType::Str => "str",
-            BuiltinType::Int { signedness, bitness } => match (signedness, bitness) {
-                (Signedness::Signed, IntBitness::Xsize) => "isize",
-                (Signedness::Signed, IntBitness::X8) => "i8",
-                (Signedness::Signed, IntBitness::X16) => "i16",
-                (Signedness::Signed, IntBitness::X32) => "i32",
-                (Signedness::Signed, IntBitness::X64) => "i64",
-                (Signedness::Signed, IntBitness::X128) => "i128",
-
-                (Signedness::Unsigned, IntBitness::Xsize) => "usize",
-                (Signedness::Unsigned, IntBitness::X8) => "u8",
-                (Signedness::Unsigned, IntBitness::X16) => "u16",
-                (Signedness::Unsigned, IntBitness::X32) => "u32",
-                (Signedness::Unsigned, IntBitness::X64) => "u64",
-                (Signedness::Unsigned, IntBitness::X128) => "u128",
-            },
-            BuiltinType::Float { bitness } => match bitness {
-                FloatBitness::X32 => "f32",
-                FloatBitness::X64 => "f64",
-            },
-        };
-        f.write_str(type_name)
-    }
-}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 29cf71a594..a42348101b 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -11,7 +11,7 @@ use crate::{
         raw::{ImportSourceMap, RawItems},
         CrateDefMap,
     },
-    EnumId, StructOrUnionId,
+    EnumId, StructId, UnionId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -19,8 +19,9 @@ pub trait InternDatabase: SourceDatabase {
     #[salsa::interned]
     fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId;
     #[salsa::interned]
-    fn intern_struct_or_union(&self, loc: crate::ItemLoc<ast::StructDef>)
-        -> crate::StructOrUnionId;
+    fn intern_struct(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::StructId;
+    #[salsa::interned]
+    fn intern_union(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::UnionId;
     #[salsa::interned]
     fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId;
     #[salsa::interned]
@@ -48,7 +49,10 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
     fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;
 
     #[salsa::invoke(StructData::struct_data_query)]
-    fn struct_data(&self, id: StructOrUnionId) -> Arc<StructData>;
+    fn struct_data(&self, s: StructId) -> Arc<StructData>;
+
+    #[salsa::invoke(StructData::union_data_query)]
+    fn union_data(&self, s: UnionId) -> Arc<StructData>;
 
     #[salsa::invoke(EnumData::enum_data_query)]
     fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 239317efe3..63ed2a0983 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -205,30 +205,26 @@ impl AstItemDef<ast::FnDef> for FunctionId {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct StructOrUnionId(salsa::InternId);
-impl_intern_key!(StructOrUnionId);
-impl AstItemDef<ast::StructDef> for StructOrUnionId {
+pub struct StructId(salsa::InternId);
+impl_intern_key!(StructId);
+impl AstItemDef<ast::StructDef> for StructId {
     fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
-        db.intern_struct_or_union(loc)
+        db.intern_struct(loc)
     }
     fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
-        db.lookup_intern_struct_or_union(self)
+        db.lookup_intern_struct(self)
     }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct StructId(pub StructOrUnionId);
-impl From<StructId> for StructOrUnionId {
-    fn from(id: StructId) -> StructOrUnionId {
-        id.0
+pub struct UnionId(salsa::InternId);
+impl_intern_key!(UnionId);
+impl AstItemDef<ast::StructDef> for UnionId {
+    fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
+        db.intern_union(loc)
     }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct UnionId(pub StructOrUnionId);
-impl From<UnionId> for StructOrUnionId {
-    fn from(id: UnionId) -> StructOrUnionId {
-        id.0
+    fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
+        db.lookup_intern_union(self)
     }
 }
 
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 6db9937a43..30664278e5 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -1,8 +1,9 @@
 //! FIXME: write short doc here
 
 use hir_expand::{
+    builtin_macro::find_builtin_macro,
     name::{self, AsName, Name},
-    HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind,
+    HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFileKind,
 };
 use ra_cfg::CfgOptions;
 use ra_db::{CrateId, FileId};
@@ -19,8 +20,7 @@ use crate::{
     },
     path::{Path, PathKind},
     AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId,
-    LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId,
-    UnionId,
+    LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
 };
 
 pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -36,12 +36,11 @@ pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) ->
         );
 
         // look for the prelude
-        // If the dependency defines a prelude, we overwrite an already defined
-        // prelude. This is necessary to import the "std" prelude if a crate
-        // depends on both "core" and "std".
-        let dep_def_map = db.crate_def_map(dep.crate_id);
-        if dep_def_map.prelude.is_some() {
-            def_map.prelude = dep_def_map.prelude;
+        if def_map.prelude.is_none() {
+            let map = db.crate_def_map(dep.crate_id);
+            if map.prelude.is_some() {
+                def_map.prelude = map.prelude;
+            }
         }
     }
 
@@ -666,14 +665,12 @@ where
                 PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into())
             }
             raw::DefKind::Struct(ast_id) => {
-                let id = StructOrUnionId::from_ast_id(ctx, ast_id).into();
-                let s = StructId(id).into();
+                let s = StructId::from_ast_id(ctx, ast_id).into();
                 PerNs::both(s, s)
             }
             raw::DefKind::Union(ast_id) => {
-                let id = StructOrUnionId::from_ast_id(ctx, ast_id).into();
-                let u = UnionId(id).into();
-                PerNs::both(u, u)
+                let s = UnionId::from_ast_id(ctx, ast_id).into();
+                PerNs::both(s, s)
             }
             raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
             raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()),
@@ -692,10 +689,30 @@ where
     fn collect_macro(&mut self, mac: &raw::MacroData) {
         let ast_id = AstId::new(self.file_id, mac.ast_id);
 
+        // Case 0: builtin macros
+        if mac.builtin {
+            if let Some(name) = &mac.name {
+                let krate = self.def_collector.def_map.krate;
+                if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
+                    self.def_collector.define_macro(
+                        self.module_id,
+                        name.clone(),
+                        macro_id,
+                        mac.export,
+                    );
+                    return;
+                }
+            }
+        }
+
         // Case 1: macro rules, define a macro in crate-global mutable scope
         if is_macro_rules(&mac.path) {
             if let Some(name) = &mac.name {
-                let macro_id = MacroDefId { ast_id, krate: self.def_collector.def_map.krate };
+                let macro_id = MacroDefId {
+                    ast_id,
+                    krate: self.def_collector.def_map.krate,
+                    kind: MacroDefKind::Declarative,
+                };
                 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
             }
             return;
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 369376f309..f52002bc0b 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -200,6 +200,7 @@ pub(super) struct MacroData {
     pub(super) path: Path,
     pub(super) name: Option<Name>,
     pub(super) export: bool,
+    pub(super) builtin: bool,
 }
 
 struct RawItemsCollector {
@@ -367,7 +368,11 @@ impl RawItemsCollector {
         // FIXME: cfg_attr
         let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
 
-        let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
+        // FIXME: cfg_attr
+        let builtin =
+            m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "rustc_builtin_macro");
+
+        let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export, builtin });
         self.push_item(current_module, attrs, RawItemKind::Macro(m));
     }
 
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
new file mode 100644
index 0000000000..97fb0cb552
--- /dev/null
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -0,0 +1,80 @@
+//! Builtin macro
+use crate::db::AstDatabase;
+use crate::{
+    ast::{self, AstNode},
+    name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind,
+    TextUnit,
+};
+
+use crate::quote;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum BuiltinExpander {
+    Line,
+}
+
+impl BuiltinExpander {
+    pub fn expand(
+        &self,
+        db: &dyn AstDatabase,
+        id: MacroCallId,
+        tt: &tt::Subtree,
+    ) -> Result<tt::Subtree, mbe::ExpandError> {
+        match self {
+            BuiltinExpander::Line => line_expand(db, id, tt),
+        }
+    }
+}
+
+pub fn find_builtin_macro(
+    ident: &name::Name,
+    krate: CrateId,
+    ast_id: AstId<ast::MacroCall>,
+) -> Option<MacroDefId> {
+    // FIXME: Better registering method
+    if ident == &name::LINE_MACRO {
+        Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) })
+    } else {
+        None
+    }
+}
+
+fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
+    // FIXME: Use expansion info
+    let file_id = file.original_file(db);
+    let text = db.file_text(file_id);
+    let mut line_num = 1;
+
+    // Count line end
+    for (i, c) in text.chars().enumerate() {
+        if i == pos.to_usize() {
+            break;
+        }
+        if c == '\n' {
+            line_num += 1;
+        }
+    }
+
+    line_num
+}
+
+fn line_expand(
+    db: &dyn AstDatabase,
+    id: MacroCallId,
+    _tt: &tt::Subtree,
+) -> Result<tt::Subtree, mbe::ExpandError> {
+    let loc = db.lookup_intern_macro(id);
+    let macro_call = loc.ast_id.to_node(db);
+
+    let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
+    let arg_start = arg.syntax().text_range().start();
+
+    let file = id.as_file(MacroFileKind::Expr);
+    let line_num = to_line_number(db, file, arg_start);
+
+    let expanded = quote! {
+        #line_num
+    };
+
+    Ok(expanded)
+}
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index b4dafe1d87..5eadee9c28 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -9,10 +9,37 @@ use ra_prof::profile;
 use ra_syntax::{AstNode, Parse, SyntaxNode};
 
 use crate::{
-    ast_id_map::AstIdMap, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId,
-    MacroFile, MacroFileKind,
+    ast_id_map::AstIdMap, BuiltinExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc,
+    MacroDefId, MacroDefKind, MacroFile, MacroFileKind,
 };
 
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum TokenExpander {
+    MacroRules(mbe::MacroRules),
+    Builtin(BuiltinExpander),
+}
+
+impl TokenExpander {
+    pub fn expand(
+        &self,
+        db: &dyn AstDatabase,
+        id: MacroCallId,
+        tt: &tt::Subtree,
+    ) -> Result<tt::Subtree, mbe::ExpandError> {
+        match self {
+            TokenExpander::MacroRules(it) => it.expand(tt),
+            TokenExpander::Builtin(it) => it.expand(db, id, tt),
+        }
+    }
+
+    pub fn shift(&self) -> u32 {
+        match self {
+            TokenExpander::MacroRules(it) => it.shift(),
+            TokenExpander::Builtin(_) => 0,
+        }
+    }
+}
+
 // FIXME: rename to ExpandDatabase
 #[salsa::query_group(AstDatabaseStorage)]
 pub trait AstDatabase: SourceDatabase {
@@ -24,7 +51,7 @@ pub trait AstDatabase: SourceDatabase {
     #[salsa::interned]
     fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId;
     fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
-    fn macro_def(&self, id: MacroDefId) -> Option<Arc<(mbe::MacroRules, mbe::TokenMap)>>;
+    fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>;
     fn parse_macro(
         &self,
         macro_file: MacroFile,
@@ -41,18 +68,25 @@ pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdM
 pub(crate) fn macro_def(
     db: &dyn AstDatabase,
     id: MacroDefId,
-) -> Option<Arc<(mbe::MacroRules, mbe::TokenMap)>> {
-    let macro_call = id.ast_id.to_node(db);
-    let arg = macro_call.token_tree()?;
-    let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
-        log::warn!("fail on macro_def to token tree: {:#?}", arg);
-        None
-    })?;
-    let rules = MacroRules::parse(&tt).ok().or_else(|| {
-        log::warn!("fail on macro_def parse: {:#?}", tt);
-        None
-    })?;
-    Some(Arc::new((rules, tmap)))
+) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
+    match id.kind {
+        MacroDefKind::Declarative => {
+            let macro_call = id.ast_id.to_node(db);
+            let arg = macro_call.token_tree()?;
+            let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
+                log::warn!("fail on macro_def to token tree: {:#?}", arg);
+                None
+            })?;
+            let rules = MacroRules::parse(&tt).ok().or_else(|| {
+                log::warn!("fail on macro_def parse: {:#?}", tt);
+                None
+            })?;
+            Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
+        }
+        MacroDefKind::BuiltIn(expander) => {
+            Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default())))
+        }
+    }
 }
 
 pub(crate) fn macro_arg(
@@ -74,7 +108,7 @@ pub(crate) fn macro_expand(
     let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;
 
     let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
-    let tt = macro_rules.0.expand(&macro_arg.0).map_err(|err| format!("{:?}", err))?;
+    let tt = macro_rules.0.expand(db, id, &macro_arg.0).map_err(|err| format!("{:?}", err))?;
     // Set a hard limit for the expanded tt
     let count = tt.count();
     if count > 65536 {
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs
index 77428ec990..379562a2c1 100644
--- a/crates/ra_hir_expand/src/hygiene.rs
+++ b/crates/ra_hir_expand/src/hygiene.rs
@@ -9,7 +9,7 @@ use crate::{
     db::AstDatabase,
     either::Either,
     name::{AsName, Name},
-    HirFileId, HirFileIdRepr,
+    HirFileId, HirFileIdRepr, MacroDefKind,
 };
 
 #[derive(Debug)]
@@ -24,7 +24,10 @@ impl Hygiene {
             HirFileIdRepr::FileId(_) => None,
             HirFileIdRepr::MacroFile(macro_file) => {
                 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
-                Some(loc.def.krate)
+                match loc.def.kind {
+                    MacroDefKind::Declarative => Some(loc.def.krate),
+                    MacroDefKind::BuiltIn(_) => None,
+                }
             }
         };
         Hygiene { def_crate }
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 151d1d7858..c6ffa2c6f2 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -10,6 +10,8 @@ pub mod either;
 pub mod name;
 pub mod hygiene;
 pub mod diagnostics;
+pub mod builtin_macro;
+pub mod quote;
 
 use std::hash::{Hash, Hasher};
 use std::sync::Arc;
@@ -21,6 +23,7 @@ use ra_syntax::{
 };
 
 use crate::ast_id_map::FileAstId;
+use crate::builtin_macro::BuiltinExpander;
 
 /// Input to the analyzer is a set of files, where each file is identified by
 /// `FileId` and contains source code. However, another source of source code in
@@ -122,6 +125,13 @@ impl salsa::InternKey for MacroCallId {
 pub struct MacroDefId {
     pub krate: CrateId,
     pub ast_id: AstId<ast::MacroCall>,
+    pub kind: MacroDefKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum MacroDefKind {
+    Declarative,
+    BuiltIn(BuiltinExpander),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -144,7 +154,7 @@ pub struct ExpansionInfo {
     pub(crate) def_start: (HirFileId, TextUnit),
     pub(crate) shift: u32,
 
-    pub(crate) macro_def: Arc<(mbe::MacroRules, mbe::TokenMap)>,
+    pub(crate) macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
     pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
     pub(crate) exp_map: Arc<mbe::RevTokenMap>,
 }
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 720896ee8e..1bf17d12b5 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -140,3 +140,6 @@ pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result");
 pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output");
 pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target");
 pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box");
+
+// Builtin Macros
+pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line");
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs
new file mode 100644
index 0000000000..9cd17f0e35
--- /dev/null
+++ b/crates/ra_hir_expand/src/quote.rs
@@ -0,0 +1,261 @@
+//! A simplified version of quote-crate like quasi quote macro
+
+// A helper macro quote macro
+// FIXME:
+// 1. Not all puncts are handled
+// 2. #()* pattern repetition not supported now
+//    * But we can do it manually, see `test_quote_derive_copy_hack`
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __quote {
+    () => {
+        Vec::<tt::TokenTree>::new()
+    };
+
+    ( @SUBTREE $delim:ident $($tt:tt)* ) => {
+        {
+            let children = $crate::__quote!($($tt)*);
+            let subtree = tt::Subtree {
+                delimiter: tt::Delimiter::$delim,
+                token_trees: $crate::quote::IntoTt::to_tokens(children),
+            };
+            subtree
+        }
+    };
+
+    ( @PUNCT $first:literal ) => {
+        {
+            vec![
+                tt::Leaf::Punct(tt::Punct {
+                    char: $first,
+                    spacing: tt::Spacing::Alone,
+                }).into()
+            ]
+        }
+    };
+
+    ( @PUNCT $first:literal, $sec:literal ) => {
+        {
+            vec![
+                tt::Leaf::Punct(tt::Punct {
+                    char: $first,
+                    spacing: tt::Spacing::Joint,
+                }).into(),
+                tt::Leaf::Punct(tt::Punct {
+                    char: $sec,
+                    spacing: tt::Spacing::Alone,
+                }).into()
+            ]
+        }
+    };
+
+    // hash variable
+    ( # $first:ident $($tail:tt)* ) => {
+        {
+            let token = $crate::quote::ToTokenTree::to_token($first);
+            let mut tokens = vec![token.into()];
+            let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
+            tokens.append(&mut tail_tokens);
+            tokens
+        }
+    };
+
+    // Brace
+    ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) };
+    // Bracket
+    ( [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE Bracket $($tt)*) };
+    // Parenthesis
+    ( ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE Parenthesis $($tt)*) };
+
+    // Literal
+    ( $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt).into()] };
+    // Ident
+    ( $tt:ident ) => {
+        vec![ {
+            tt::Leaf::Ident(tt::Ident {
+                text: stringify!($tt).into(),
+                id: tt::TokenId::unspecified(),
+            }).into()
+        }]
+    };
+
+    // Puncts
+    // FIXME: Not all puncts are handled
+    ( -> ) => {$crate::__quote!(@PUNCT '-', '>')};
+    ( & ) => {$crate::__quote!(@PUNCT '&')};
+    ( , ) => {$crate::__quote!(@PUNCT ',')};
+    ( : ) => {$crate::__quote!(@PUNCT ':')};
+    ( . ) => {$crate::__quote!(@PUNCT '.')};
+
+    ( $first:tt $($tail:tt)+ ) => {
+        {
+            let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first));
+            let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
+
+            tokens.append(&mut tail_tokens);
+            tokens
+        }
+    };
+}
+
+/// FIXME:
+/// It probably should implement in proc-macro
+#[macro_export]
+macro_rules! quote {
+    ( $($tt:tt)* ) => {
+        $crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*))
+    }
+}
+
+pub(crate) trait IntoTt {
+    fn to_subtree(self) -> tt::Subtree;
+    fn to_tokens(self) -> Vec<tt::TokenTree>;
+}
+
+impl IntoTt for Vec<tt::TokenTree> {
+    fn to_subtree(self) -> tt::Subtree {
+        tt::Subtree { delimiter: tt::Delimiter::None, token_trees: self }
+    }
+
+    fn to_tokens(self) -> Vec<tt::TokenTree> {
+        self
+    }
+}
+
+impl IntoTt for tt::Subtree {
+    fn to_subtree(self) -> tt::Subtree {
+        self
+    }
+
+    fn to_tokens(self) -> Vec<tt::TokenTree> {
+        vec![tt::TokenTree::Subtree(self)]
+    }
+}
+
+pub(crate) trait ToTokenTree {
+    fn to_token(self) -> tt::TokenTree;
+}
+
+impl ToTokenTree for tt::TokenTree {
+    fn to_token(self) -> tt::TokenTree {
+        self
+    }
+}
+
+impl ToTokenTree for tt::Subtree {
+    fn to_token(self) -> tt::TokenTree {
+        self.into()
+    }
+}
+
+macro_rules! impl_to_to_tokentrees {
+    ($($ty:ty => $this:ident $im:block);*) => {
+        $(
+            impl ToTokenTree for $ty {
+                fn to_token($this) -> tt::TokenTree {
+                    let leaf: tt::Leaf = $im.into();
+                    leaf.into()
+                }
+            }
+
+            impl ToTokenTree for &$ty {
+                fn to_token($this) -> tt::TokenTree {
+                    let leaf: tt::Leaf = $im.clone().into();
+                    leaf.into()
+                }
+            }
+        )*
+    }
+}
+
+impl_to_to_tokentrees! {
+    u32 => self { tt::Literal{text: self.to_string().into()} };
+    usize => self { tt::Literal{text: self.to_string().into()}};
+    i32 => self { tt::Literal{text: self.to_string().into()}};
+    &str => self { tt::Literal{text: self.to_string().into()}};
+    String => self { tt::Literal{text: self.into()}};
+    tt::Leaf => self { self };
+    tt::Literal => self { self };
+    tt::Ident => self { self };
+    tt::Punct => self { self }
+}
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn test_quote_delimiters() {
+        assert_eq!(quote!({}).to_string(), "{}");
+        assert_eq!(quote!(()).to_string(), "()");
+        assert_eq!(quote!([]).to_string(), "[]");
+    }
+
+    #[test]
+    fn test_quote_idents() {
+        assert_eq!(quote!(32).to_string(), "32");
+        assert_eq!(quote!(struct).to_string(), "struct");
+    }
+
+    #[test]
+    fn test_quote_hash_simple_literal() {
+        let a = 20;
+        assert_eq!(quote!(#a).to_string(), "20");
+        let s: String = "hello".into();
+        assert_eq!(quote!(#s).to_string(), "hello");
+    }
+
+    fn mk_ident(name: &str) -> tt::Ident {
+        tt::Ident { text: name.into(), id: tt::TokenId::unspecified() }
+    }
+
+    #[test]
+    fn test_quote_hash_token_tree() {
+        let a = mk_ident("hello");
+
+        let quoted = quote!(#a);
+        assert_eq!(quoted.to_string(), "hello");
+        let t = format!("{:?}", quoted);
+        assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }");
+    }
+
+    #[test]
+    fn test_quote_simple_derive_copy() {
+        let name = mk_ident("Foo");
+
+        let quoted = quote! {
+            impl Clone for #name {
+                fn clone(&self) -> Self {
+                    Self {}
+                }
+            }
+        };
+
+        assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {}}}");
+    }
+
+    #[test]
+    fn test_quote_derive_copy_hack() {
+        // Assume the given struct is:
+        // struct Foo {
+        //  name: String,
+        //  id: u32,
+        // }
+        let struct_name = mk_ident("Foo");
+        let fields = [mk_ident("name"), mk_ident("id")];
+        let fields = fields
+            .into_iter()
+            .map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone())
+            .flatten();
+
+        let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() };
+
+        let quoted = quote! {
+            impl Clone for #struct_name {
+                fn clone(&self) -> Self {
+                    Self #list
+                }
+            }
+        };
+
+        assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {name : self . name . clone () , id : self . id . clone () ,}}}");
+    }
+}
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 3e205efd12..4e56de3f54 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -597,68 +597,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn completes_std_prelude_if_core_is_defined() {
-        assert_debug_snapshot!(
-            do_reference_completion(
-                "
-                //- /main.rs
-                fn foo() { let x: <|> }
-
-                //- /core/lib.rs
-                #[prelude_import]
-                use prelude::*;
-
-                mod prelude {
-                    struct Option;
-                }
-
-                //- /std/lib.rs
-                #[prelude_import]
-                use prelude::*;
-
-                mod prelude {
-                    struct String;
-                }
-                "
-            ),
-            @r###"
-        [
-            CompletionItem {
-                label: "String",
-                source_range: [18; 18),
-                delete: [18; 18),
-                insert: "String",
-                kind: Struct,
-            },
-            CompletionItem {
-                label: "core",
-                source_range: [18; 18),
-                delete: [18; 18),
-                insert: "core",
-                kind: Module,
-            },
-            CompletionItem {
-                label: "foo()",
-                source_range: [18; 18),
-                delete: [18; 18),
-                insert: "foo()$0",
-                kind: Function,
-                lookup: "foo",
-                detail: "fn foo()",
-            },
-            CompletionItem {
-                label: "std",
-                source_range: [18; 18),
-                delete: [18; 18),
-                insert: "std",
-                kind: Module,
-            },
-        ]
-        "###
-        );
-    }
-
     #[test]
     fn completes_macros_as_value() {
         assert_debug_snapshot!(
diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs
index 30617412a6..a980c56bc0 100644
--- a/crates/ra_ide_api/src/display.rs
+++ b/crates/ra_ide_api/src/display.rs
@@ -15,7 +15,7 @@ pub use function_signature::FunctionSignature;
 pub use navigation_target::NavigationTarget;
 pub use structure::{file_structure, StructureNode};
 
-pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav};
+pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol};
 pub(crate) use short_label::ShortLabel;
 
 pub(crate) fn function_label(node: &ast::FnDef) -> String {
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index 41d4675640..1bf81e7d51 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -29,8 +29,19 @@ pub struct NavigationTarget {
     docs: Option<String>,
 }
 
-pub(crate) trait ToNav {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget;
+fn find_range_from_node(
+    db: &RootDatabase,
+    src: hir::HirFileId,
+    node: &SyntaxNode,
+) -> (FileId, TextRange) {
+    let text_range = node.text_range();
+    let (file_id, text_range) = src
+        .expansion_info(db)
+        .and_then(|expansion_info| expansion_info.find_range(text_range))
+        .unwrap_or((src, text_range));
+
+    // FIXME: handle recursive macro generated macro
+    (file_id.original_file(db), text_range)
 }
 
 impl NavigationTarget {
@@ -84,6 +95,19 @@ impl NavigationTarget {
         NavigationTarget::from_named(db, file_id.into(), pat, None, None)
     }
 
+    pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget {
+        NavigationTarget {
+            file_id: symbol.file_id,
+            name: symbol.name.clone(),
+            kind: symbol.ptr.kind(),
+            full_range: symbol.ptr.range(),
+            focus_range: symbol.name_range,
+            container_name: symbol.container_name.clone(),
+            description: description_from_symbol(db, &symbol),
+            docs: docs_from_symbol(db, &symbol),
+        }
+    }
+
     pub(crate) fn from_pat(
         db: &RootDatabase,
         file_id: FileId,
@@ -112,6 +136,39 @@ impl NavigationTarget {
         }
     }
 
+    pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
+        let src = module.definition_source(db);
+        let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
+        match src.ast {
+            ModuleSource::SourceFile(node) => {
+                let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
+
+                NavigationTarget::from_syntax(
+                    file_id,
+                    name,
+                    None,
+                    text_range,
+                    node.syntax(),
+                    None,
+                    None,
+                )
+            }
+            ModuleSource::Module(node) => {
+                let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
+
+                NavigationTarget::from_syntax(
+                    file_id,
+                    name,
+                    None,
+                    text_range,
+                    node.syntax(),
+                    node.doc_comment_text(),
+                    node.short_label(),
+                )
+            }
+        }
+    }
+
     pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
         let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
         if let Some(src) = module.declaration_source(db) {
@@ -126,7 +183,55 @@ impl NavigationTarget {
                 src.ast.short_label(),
             );
         }
-        module.to_nav(db)
+        NavigationTarget::from_module(db, module)
+    }
+
+    pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget {
+        let src = field.source(db);
+        match src.ast {
+            FieldSource::Named(it) => NavigationTarget::from_named(
+                db,
+                src.file_id,
+                &it,
+                it.doc_comment_text(),
+                it.short_label(),
+            ),
+            FieldSource::Pos(it) => {
+                let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax());
+                NavigationTarget::from_syntax(
+                    file_id,
+                    "".into(),
+                    None,
+                    text_range,
+                    it.syntax(),
+                    None,
+                    None,
+                )
+            }
+        }
+    }
+
+    pub(crate) fn from_def_source<A, D>(db: &RootDatabase, def: D) -> NavigationTarget
+    where
+        D: HasSource<Ast = A>,
+        A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
+    {
+        let src = def.source(db);
+        NavigationTarget::from_named(
+            db,
+            src.file_id,
+            &src.ast,
+            src.ast.doc_comment_text(),
+            src.ast.short_label(),
+        )
+    }
+
+    pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::Adt) -> NavigationTarget {
+        match adt_def {
+            hir::Adt::Struct(it) => NavigationTarget::from_def_source(db, it),
+            hir::Adt::Union(it) => NavigationTarget::from_def_source(db, it),
+            hir::Adt::Enum(it) => NavigationTarget::from_def_source(db, it),
+        }
     }
 
     pub(crate) fn from_def(
@@ -134,14 +239,14 @@ impl NavigationTarget {
         module_def: hir::ModuleDef,
     ) -> Option<NavigationTarget> {
         let nav = match module_def {
-            hir::ModuleDef::Module(module) => module.to_nav(db),
-            hir::ModuleDef::Function(it) => it.to_nav(db),
-            hir::ModuleDef::Adt(it) => it.to_nav(db),
-            hir::ModuleDef::Const(it) => it.to_nav(db),
-            hir::ModuleDef::Static(it) => it.to_nav(db),
-            hir::ModuleDef::EnumVariant(it) => it.to_nav(db),
-            hir::ModuleDef::Trait(it) => it.to_nav(db),
-            hir::ModuleDef::TypeAlias(it) => it.to_nav(db),
+            hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module),
+            hir::ModuleDef::Function(func) => NavigationTarget::from_def_source(db, func),
+            hir::ModuleDef::Adt(it) => NavigationTarget::from_adt_def(db, it),
+            hir::ModuleDef::Const(it) => NavigationTarget::from_def_source(db, it),
+            hir::ModuleDef::Static(it) => NavigationTarget::from_def_source(db, it),
+            hir::ModuleDef::EnumVariant(it) => NavigationTarget::from_def_source(db, it),
+            hir::ModuleDef::Trait(it) => NavigationTarget::from_def_source(db, it),
+            hir::ModuleDef::TypeAlias(it) => NavigationTarget::from_def_source(db, it),
             hir::ModuleDef::BuiltinType(..) => {
                 return None;
             }
@@ -149,6 +254,41 @@ impl NavigationTarget {
         Some(nav)
     }
 
+    pub(crate) fn from_impl_block(
+        db: &RootDatabase,
+        impl_block: hir::ImplBlock,
+    ) -> NavigationTarget {
+        let src = impl_block.source(db);
+        let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax());
+
+        NavigationTarget::from_syntax(
+            file_id,
+            "impl".into(),
+            None,
+            text_range,
+            src.ast.syntax(),
+            None,
+            None,
+        )
+    }
+
+    pub(crate) fn from_assoc_item(
+        db: &RootDatabase,
+        assoc_item: hir::AssocItem,
+    ) -> NavigationTarget {
+        match assoc_item {
+            AssocItem::Function(it) => NavigationTarget::from_def_source(db, it),
+            AssocItem::Const(it) => NavigationTarget::from_def_source(db, it),
+            AssocItem::TypeAlias(it) => NavigationTarget::from_def_source(db, it),
+        }
+    }
+
+    pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget {
+        let src = macro_call.source(db);
+        log::debug!("nav target {:#?}", src.ast.syntax());
+        NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None)
+    }
+
     #[cfg(test)]
     pub(crate) fn assert_match(&self, expected: &str) {
         let actual = self.debug_render();
@@ -219,172 +359,6 @@ impl NavigationTarget {
     }
 }
 
-impl ToNav for FileSymbol {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        NavigationTarget {
-            file_id: self.file_id,
-            name: self.name.clone(),
-            kind: self.ptr.kind(),
-            full_range: self.ptr.range(),
-            focus_range: self.name_range,
-            container_name: self.container_name.clone(),
-            description: description_from_symbol(db, self),
-            docs: docs_from_symbol(db, self),
-        }
-    }
-}
-
-pub(crate) trait ToNavFromAst {}
-impl ToNavFromAst for hir::Function {}
-impl ToNavFromAst for hir::Const {}
-impl ToNavFromAst for hir::Static {}
-impl ToNavFromAst for hir::Struct {}
-impl ToNavFromAst for hir::Enum {}
-impl ToNavFromAst for hir::EnumVariant {}
-impl ToNavFromAst for hir::Union {}
-impl ToNavFromAst for hir::TypeAlias {}
-impl ToNavFromAst for hir::Trait {}
-
-impl<D> ToNav for D
-where
-    D: HasSource + ToNavFromAst + Copy,
-    D::Ast: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
-{
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
-        NavigationTarget::from_named(
-            db,
-            src.file_id,
-            &src.ast,
-            src.ast.doc_comment_text(),
-            src.ast.short_label(),
-        )
-    }
-}
-
-impl ToNav for hir::Module {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.definition_source(db);
-        let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default();
-        match src.ast {
-            ModuleSource::SourceFile(node) => {
-                let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
-
-                NavigationTarget::from_syntax(
-                    file_id,
-                    name,
-                    None,
-                    text_range,
-                    node.syntax(),
-                    None,
-                    None,
-                )
-            }
-            ModuleSource::Module(node) => {
-                let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
-
-                NavigationTarget::from_syntax(
-                    file_id,
-                    name,
-                    None,
-                    text_range,
-                    node.syntax(),
-                    node.doc_comment_text(),
-                    node.short_label(),
-                )
-            }
-        }
-    }
-}
-
-impl ToNav for hir::ImplBlock {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
-        let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax());
-
-        NavigationTarget::from_syntax(
-            file_id,
-            "impl".into(),
-            None,
-            text_range,
-            src.ast.syntax(),
-            None,
-            None,
-        )
-    }
-}
-
-impl ToNav for hir::StructField {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
-
-        match src.ast {
-            FieldSource::Named(it) => NavigationTarget::from_named(
-                db,
-                src.file_id,
-                &it,
-                it.doc_comment_text(),
-                it.short_label(),
-            ),
-            FieldSource::Pos(it) => {
-                let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax());
-                NavigationTarget::from_syntax(
-                    file_id,
-                    "".into(),
-                    None,
-                    text_range,
-                    it.syntax(),
-                    None,
-                    None,
-                )
-            }
-        }
-    }
-}
-
-impl ToNav for hir::MacroDef {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let src = self.source(db);
-        log::debug!("nav target {:#?}", src.ast.syntax());
-        NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None)
-    }
-}
-
-impl ToNav for hir::Adt {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        match self {
-            hir::Adt::Struct(it) => it.to_nav(db),
-            hir::Adt::Union(it) => it.to_nav(db),
-            hir::Adt::Enum(it) => it.to_nav(db),
-        }
-    }
-}
-
-impl ToNav for hir::AssocItem {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        match self {
-            AssocItem::Function(it) => it.to_nav(db),
-            AssocItem::Const(it) => it.to_nav(db),
-            AssocItem::TypeAlias(it) => it.to_nav(db),
-        }
-    }
-}
-
-fn find_range_from_node(
-    db: &RootDatabase,
-    src: hir::HirFileId,
-    node: &SyntaxNode,
-) -> (FileId, TextRange) {
-    let text_range = node.text_range();
-    let (file_id, text_range) = src
-        .expansion_info(db)
-        .and_then(|expansion_info| expansion_info.find_range(text_range))
-        .unwrap_or((src, text_range));
-
-    // FIXME: handle recursive macro generated macro
-    (file_id.original_file(db), text_range)
-}
-
 pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
     let parse = db.parse(symbol.file_id);
     let node = symbol.ptr.to_node(parse.tree().syntax());
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 713b61d5ee..afa59cbe3a 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
 
 use crate::{
     db::RootDatabase,
-    display::{ShortLabel, ToNav},
+    display::ShortLabel,
     references::{classify_name_ref, NameKind::*},
     FilePosition, NavigationTarget, RangeInfo,
 };
@@ -56,16 +56,16 @@ pub(crate) fn reference_definition(
 
     let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
     match name_kind {
-        Some(Macro(mac)) => return Exact(mac.to_nav(db)),
-        Some(Field(field)) => return Exact(field.to_nav(db)),
-        Some(AssocItem(assoc)) => return Exact(assoc.to_nav(db)),
+        Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)),
+        Some(Field(field)) => return Exact(NavigationTarget::from_field(db, field)),
+        Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)),
         Some(Def(def)) => match NavigationTarget::from_def(db, def) {
             Some(nav) => return Exact(nav),
             None => return Approximate(vec![]),
         },
         Some(SelfType(ty)) => {
-            if let Some((adt, _)) = ty.as_adt() {
-                return Exact(adt.to_nav(db));
+            if let Some((def_id, _)) = ty.as_adt() {
+                return Exact(NavigationTarget::from_adt_def(db, def_id));
             }
         }
         Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)),
@@ -79,7 +79,7 @@ pub(crate) fn reference_definition(
     // Fallback index based approach:
     let navs = crate::symbol_index::index_resolve(db, name_ref)
         .into_iter()
-        .map(|s| s.to_nav(db))
+        .map(|s| NavigationTarget::from_symbol(db, s))
         .collect();
     Approximate(navs)
 }
@@ -95,7 +95,7 @@ pub(crate) fn name_definition(
         if module.has_semi() {
             let src = hir::Source { file_id: file_id.into(), ast: module };
             if let Some(child_module) = hir::Module::from_declaration(db, src) {
-                let nav = child_module.to_nav(db);
+                let nav = NavigationTarget::from_module(db, child_module);
                 return Some(vec![nav]);
             }
         }
diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs
index 71146591df..059d80524e 100644
--- a/crates/ra_ide_api/src/goto_type_definition.rs
+++ b/crates/ra_ide_api/src/goto_type_definition.rs
@@ -3,7 +3,7 @@
 use ra_db::SourceDatabase;
 use ra_syntax::{ast, AstNode};
 
-use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo};
+use crate::{db::RootDatabase, FilePosition, NavigationTarget, RangeInfo};
 
 pub(crate) fn goto_type_definition(
     db: &RootDatabase,
@@ -33,7 +33,7 @@ pub(crate) fn goto_type_definition(
 
     let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?;
 
-    let nav = adt_def.to_nav(db);
+    let nav = NavigationTarget::from_adt_def(db, adt_def);
     Some(RangeInfo::new(node.text_range(), vec![nav]))
 }
 
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index cc41390b25..ba328efa14 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -117,23 +117,27 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
                 hir::AssocItem::Const(it) => from_def_source(db, it),
                 hir::AssocItem::TypeAlias(it) => from_def_source(db, it),
             }),
-            Some(Def(it)) => match it {
-                hir::ModuleDef::Module(it) => {
-                    if let hir::ModuleSource::Module(it) = it.definition_source(db).ast {
-                        res.extend(hover_text(it.doc_comment_text(), it.short_label()))
+            Some(Def(it)) => {
+                match it {
+                    hir::ModuleDef::Module(it) => {
+                        if let hir::ModuleSource::Module(it) = it.definition_source(db).ast {
+                            res.extend(hover_text(it.doc_comment_text(), it.short_label()))
+                        }
+                    }
+                    hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)),
+                    hir::ModuleDef::BuiltinType(_) => {
+                        // FIXME: hover for builtin Type ?
                     }
                 }
-                hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)),
-                hir::ModuleDef::BuiltinType(it) => res.extend(Some(it.to_string())),
-            },
+            }
             Some(SelfType(ty)) => {
                 if let Some((adt_def, _)) = ty.as_adt() {
                     res.extend(match adt_def {
@@ -718,16 +722,4 @@ fn func(foo: i32) { if true { <|>foo; }; }
         assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo"));
         assert_eq!(hover.info.is_exact(), true);
     }
-
-    #[test]
-    fn test_hover_tuple_field() {
-        let (analysis, position) = single_file_with_position(
-            "
-            struct TS(String, i32<|>);
-            ",
-        );
-        let hover = analysis.hover(position).unwrap().unwrap();
-        assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
-        assert_eq!(hover.info.is_exact(), true);
-    }
 }
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
index bc9b665507..b899ed3a5f 100644
--- a/crates/ra_ide_api/src/impls.rs
+++ b/crates/ra_ide_api/src/impls.rs
@@ -4,7 +4,7 @@ use hir::{db::HirDatabase, ApplicationTy, FromSource, Ty, TypeCtor};
 use ra_db::SourceDatabase;
 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
 
-use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo};
+use crate::{db::RootDatabase, FilePosition, NavigationTarget, RangeInfo};
 
 pub(crate) fn goto_implementation(
     db: &RootDatabase,
@@ -58,7 +58,7 @@ fn impls_for_def(
         impls
             .all_impls()
             .filter(|impl_block| is_equal_for_find_impls(&ty, &impl_block.target_ty(db)))
-            .map(|imp| imp.to_nav(db))
+            .map(|imp| NavigationTarget::from_impl_block(db, imp))
             .collect(),
     )
 }
@@ -75,7 +75,12 @@ fn impls_for_trait(
     let krate = module.krate();
     let impls = db.impls_in_crate(krate);
 
-    Some(impls.lookup_impl_blocks_for_trait(tr).map(|imp| imp.to_nav(db)).collect())
+    Some(
+        impls
+            .lookup_impl_blocks_for_trait(tr)
+            .map(|imp| NavigationTarget::from_impl_block(db, imp))
+            .collect(),
+    )
 }
 
 fn is_equal_for_find_impls(original_ty: &Ty, impl_ty: &Ty) -> bool {
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 484fbcc823..d0188da449 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -56,7 +56,7 @@ use ra_db::{
 };
 use ra_syntax::{SourceFile, TextRange, TextUnit};
 
-use crate::{db::LineIndexDatabase, display::ToNav, symbol_index::FileSymbol};
+use crate::{db::LineIndexDatabase, symbol_index::FileSymbol};
 
 pub use crate::{
     assists::{Assist, AssistId},
@@ -351,7 +351,7 @@ impl Analysis {
         self.with_db(|db| {
             symbol_index::world_symbols(db, query)
                 .into_iter()
-                .map(|s| s.to_nav(db))
+                .map(|s| NavigationTarget::from_symbol(db, s))
                 .collect::<Vec<_>>()
         })
     }
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 0a76bf4846..b5b1c9a16f 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -19,9 +19,7 @@ use ra_db::{SourceDatabase, SourceDatabaseExt};
 use ra_prof::profile;
 use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit};
 
-use crate::{
-    db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo,
-};
+use crate::{db::RootDatabase, FilePosition, FileRange, NavigationTarget, RangeInfo};
 
 pub(crate) use self::{
     classify::{classify_name, classify_name_ref},
@@ -78,12 +76,12 @@ pub(crate) fn find_all_refs(
     let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?;
 
     let declaration = match def.kind {
-        NameKind::Macro(mac) => mac.to_nav(db),
-        NameKind::Field(field) => field.to_nav(db),
-        NameKind::AssocItem(assoc) => assoc.to_nav(db),
+        NameKind::Macro(mac) => NavigationTarget::from_macro_def(db, mac),
+        NameKind::Field(field) => NavigationTarget::from_field(db, field),
+        NameKind::AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc),
         NameKind::Def(def) => NavigationTarget::from_def(db, def)?,
         NameKind::SelfType(ref ty) => match ty.as_adt() {
-            Some((adt, _)) => adt.to_nav(db),
+            Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id),
             None => return None,
         },
         NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat),
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 1ee68abe20..33f3cacebe 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -9,15 +9,12 @@ use ra_syntax::{
     ast::{self, NameOwner},
     AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind,
     SyntaxKind::*,
-    SyntaxNode, TextRange, T,
+    TextRange, T,
 };
 
 use crate::{
     db::RootDatabase,
-    references::{
-        classify_name, classify_name_ref,
-        NameKind::{self, *},
-    },
+    references::{classify_name_ref, NameKind::*},
     FileId,
 };
 
@@ -103,43 +100,81 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
                 if node.ancestors().any(|it| it.kind() == ATTR) {
                     continue;
                 }
+                if let Some(name_ref) = node.as_node().cloned().and_then(ast::NameRef::cast) {
+                    let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
+                    match name_kind {
+                        Some(Macro(_)) => "macro",
+                        Some(Field(_)) => "field",
+                        Some(AssocItem(hir::AssocItem::Function(_))) => "function",
+                        Some(AssocItem(hir::AssocItem::Const(_))) => "constant",
+                        Some(AssocItem(hir::AssocItem::TypeAlias(_))) => "type",
+                        Some(Def(hir::ModuleDef::Module(_))) => "module",
+                        Some(Def(hir::ModuleDef::Function(_))) => "function",
+                        Some(Def(hir::ModuleDef::Adt(_))) => "type",
+                        Some(Def(hir::ModuleDef::EnumVariant(_))) => "constant",
+                        Some(Def(hir::ModuleDef::Const(_))) => "constant",
+                        Some(Def(hir::ModuleDef::Static(_))) => "constant",
+                        Some(Def(hir::ModuleDef::Trait(_))) => "type",
+                        Some(Def(hir::ModuleDef::TypeAlias(_))) => "type",
+                        Some(Def(hir::ModuleDef::BuiltinType(_))) => "type",
+                        Some(SelfType(_)) => "type",
+                        Some(Pat((_, ptr))) => {
+                            let pat = ptr.to_node(&root);
+                            if let Some(name) = pat.name() {
+                                let text = name.text();
+                                let shadow_count =
+                                    bindings_shadow_count.entry(text.clone()).or_default();
+                                binding_hash =
+                                    Some(calc_binding_hash(file_id, &text, *shadow_count))
+                            }
 
-                let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
-                let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
-
-                if let Some(Pat((_, ptr))) = &name_kind {
-                    let pat = ptr.to_node(&root);
-                    if let Some(name) = pat.name() {
-                        let text = name.text();
-                        let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
-                        binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
+                            let analyzer =
+                                hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
+                            if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) {
+                                "variable.mut"
+                            } else {
+                                "variable"
+                            }
+                        }
+                        Some(SelfParam(_)) => "type",
+                        Some(GenericParam(_)) => "type",
+                        None => "text",
                     }
-                };
-
-                name_kind
-                    .map_or("text", |it| highlight_name(db, file_id, name_ref.syntax(), &root, it))
+                } else {
+                    "text"
+                }
             }
             NAME => {
-                let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
-                let name_kind = classify_name(db, file_id, &name).map(|d| d.kind);
-
-                if let Some(Pat((_, ptr))) = &name_kind {
-                    let pat = ptr.to_node(&root);
-                    if let Some(name) = pat.name() {
-                        let text = name.text();
-                        let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
-                        *shadow_count += 1;
-                        binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
+                if let Some(name) = node.as_node().cloned().and_then(ast::Name::cast) {
+                    let analyzer = hir::SourceAnalyzer::new(db, file_id, name.syntax(), None);
+                    if let Some(pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
+                        if let Some(name) = pat.name() {
+                            let text = name.text();
+                            let shadow_count =
+                                bindings_shadow_count.entry(text.clone()).or_default();
+                            *shadow_count += 1;
+                            binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
+                        }
+
+                        if is_variable_mutable(db, &analyzer, pat) {
+                            "variable.mut"
+                        } else {
+                            "variable"
+                        }
+                    } else {
+                        name.syntax()
+                            .parent()
+                            .map(|x| match x.kind() {
+                                TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => {
+                                    "type"
+                                }
+                                RECORD_FIELD_DEF => "field",
+                                _ => "function",
+                            })
+                            .unwrap_or("function")
                     }
-                };
-
-                match name_kind {
-                    Some(name_kind) => highlight_name(db, file_id, name.syntax(), &root, name_kind),
-                    None => name.syntax().parent().map_or("function", |x| match x.kind() {
-                        TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type",
-                        RECORD_FIELD_DEF => "field",
-                        _ => "function",
-                    }),
+                } else {
+                    "text"
                 }
             }
             INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal",
@@ -237,42 +272,6 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
     buf
 }
 
-fn highlight_name(
-    db: &RootDatabase,
-    file_id: FileId,
-    node: &SyntaxNode,
-    root: &SyntaxNode,
-    name_kind: NameKind,
-) -> &'static str {
-    match name_kind {
-        Macro(_) => "macro",
-        Field(_) => "field",
-        AssocItem(hir::AssocItem::Function(_)) => "function",
-        AssocItem(hir::AssocItem::Const(_)) => "constant",
-        AssocItem(hir::AssocItem::TypeAlias(_)) => "type",
-        Def(hir::ModuleDef::Module(_)) => "module",
-        Def(hir::ModuleDef::Function(_)) => "function",
-        Def(hir::ModuleDef::Adt(_)) => "type",
-        Def(hir::ModuleDef::EnumVariant(_)) => "constant",
-        Def(hir::ModuleDef::Const(_)) => "constant",
-        Def(hir::ModuleDef::Static(_)) => "constant",
-        Def(hir::ModuleDef::Trait(_)) => "type",
-        Def(hir::ModuleDef::TypeAlias(_)) => "type",
-        Def(hir::ModuleDef::BuiltinType(_)) => "type",
-        SelfType(_) => "type",
-        SelfParam(_) => "type",
-        GenericParam(_) => "type",
-        Pat((_, ptr)) => {
-            let analyzer = hir::SourceAnalyzer::new(db, file_id, node, None);
-            if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) {
-                "variable.mut"
-            } else {
-                "variable"
-            }
-        }
-    }
-}
-
 //FIXME: like, real html escaping
 fn html_escape(text: &str) -> String {
     text.replace("<", "&lt;").replace(">", "&gt;")
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 0e14f1b70c..8b8663a78f 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -199,7 +199,6 @@ impl ProjectWorkspace {
                     }
                 }
 
-                let libcore = sysroot.core().and_then(|it| sysroot_crates.get(&it).copied());
                 let libstd = sysroot.std().and_then(|it| sysroot_crates.get(&it).copied());
 
                 let mut pkg_to_lib_crate = FxHashMap::default();
@@ -227,7 +226,7 @@ impl ProjectWorkspace {
                         }
                     }
 
-                    // Set deps to the core, std and to the lib target of the current package
+                    // Set deps to the std and to the lib target of the current package
                     for &from in pkg_crates.get(&pkg).into_iter().flatten() {
                         if let Some(to) = lib_tgt {
                             if to != from {
@@ -241,13 +240,6 @@ impl ProjectWorkspace {
                                 }
                             }
                         }
-                        // core is added as a dependency before std in order to
-                        // mimic rustcs dependency order
-                        if let Some(core) = libcore {
-                            if let Err(_) = crate_graph.add_dep(from, "core".into(), core) {
-                                log::error!("cyclic dependency on core for {}", pkg.name(&cargo))
-                            }
-                        }
                         if let Some(std) = libstd {
                             if let Err(_) = crate_graph.add_dep(from, "std".into(), std) {
                                 log::error!("cyclic dependency on std for {}", pkg.name(&cargo))
diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs
index 3d827809ee..35d6df5cb5 100644
--- a/crates/ra_project_model/src/sysroot.rs
+++ b/crates/ra_project_model/src/sysroot.rs
@@ -27,10 +27,6 @@ struct SysrootCrateData {
 }
 
 impl Sysroot {
-    pub fn core(&self) -> Option<SysrootCrate> {
-        self.by_name("core")
-    }
-
     pub fn std(&self) -> Option<SysrootCrate> {
         self.by_name("std")
     }
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs
index 1f60a7aabd..d6eca2ad77 100644
--- a/crates/ra_syntax/src/syntax_error.rs
+++ b/crates/ra_syntax/src/syntax_error.rs
@@ -82,7 +82,6 @@ pub enum SyntaxErrorKind {
     InvalidBlockAttr,
     InvalidMatchInnerAttr,
     InvalidTupleIndexFormat,
-    VisibilityNotAllowed,
 }
 
 impl fmt::Display for SyntaxErrorKind {
@@ -100,9 +99,6 @@ impl fmt::Display for SyntaxErrorKind {
             }
             ParseError(msg) => write!(f, "{}", msg.0),
             EscapeError(err) => write!(f, "{}", err),
-            VisibilityNotAllowed => {
-                write!(f, "unnecessary visibility qualifier")
-            }
         }
     }
 }
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 2d596763ee..ab4f15908c 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -6,7 +6,7 @@ use rustc_lexer::unescape;
 
 use crate::{
     ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind,
-    SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF},
+    SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING},
     SyntaxNode, SyntaxToken, TextUnit, T,
 };
 
@@ -102,7 +102,6 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
                 ast::BlockExpr(it) => { block::validate_block_expr(it, &mut errors) },
                 ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) },
                 ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) },
-                ast::Visibility(it) => { validate_visibility(it, &mut errors) },
                 _ => (),
             }
         }
@@ -207,23 +206,3 @@ fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<Syntax
         name_ref?.syntax().first_child_or_token()?.into_token().filter(|it| it.kind() == INT_NUMBER)
     }
 }
-
-fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
-    let parent = match vis.syntax().parent() {
-        Some(it) => it,
-        None => return,
-    };
-    match parent.kind() {
-        FN_DEF | CONST_DEF | TYPE_ALIAS_DEF => (),
-        _ => return,
-    }
-    let impl_block = match parent.parent().and_then(|it| it.parent()).and_then(ast::ImplBlock::cast)
-    {
-        Some(it) => it,
-        None => return,
-    };
-    if impl_block.target_trait().is_some() {
-        errors
-            .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range()))
-    }
-}


Test patch:
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index e56b9356e9..896bf2924b 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -4810,3 +4810,22 @@ fn no_such_field_diagnostics() {
     "###
     );
 }
+
+#[test]
+fn infer_builtin_macros_line() {
+    assert_snapshot!(
+        infer(r#"
+#[rustc_builtin_macro]
+macro_rules! line {() => {}}
+
+fn main() {
+    let x = line!();
+}
+"#),
+        @r###"
+        ![0; 1) '6': i32
+        [64; 88) '{     ...!(); }': ()
+        [74; 75) 'x': i32        
+    "###
+    );
+}
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 256f7d4be7..52bd0aa91e 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -463,37 +463,6 @@ fn values_dont_shadow_extern_crates() {
     "###);
 }
 
-#[test]
-fn std_prelude_takes_precedence_above_core_prelude() {
-    let map = def_map(
-        r#"
-        //- /main.rs crate:main deps:core,std
-        use {Foo, Bar};
-
-        //- /std.rs crate:std deps:core
-        #[prelude_import]
-        pub use self::prelude::*;
-        mod prelude {
-            pub struct Foo;
-            pub use core::prelude::Bar;
-        }
-
-        //- /core.rs crate:core
-        #[prelude_import]
-        pub use self::prelude::*;
-        mod prelude {
-            pub struct Bar;
-        }
-        "#,
-    );
-
-    assert_snapshot!(map, @r###"
-        ⋮crate
-        ⋮Bar: t v
-        ⋮Foo: t v
-    "###);
-}
-
 #[test]
 fn cfg_not_test() {
     let map = def_map(
diff --git a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs
deleted file mode 100644
index a43e7ef10c..0000000000
--- a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-impl T for () {
-    fn foo() {}
-    pub fn bar() {}
-    pub(crate) type Baz = ();
-    pub(crate) const C: i32 = 92;
-}
diff --git a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt
deleted file mode 100644
index 749c8cddbc..0000000000
--- a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-SOURCE_FILE@[0; 118)
-  IMPL_BLOCK@[0; 117)
-    IMPL_KW@[0; 4) "impl"
-    WHITESPACE@[4; 5) " "
-    PATH_TYPE@[5; 6)
-      PATH@[5; 6)
-        PATH_SEGMENT@[5; 6)
-          NAME_REF@[5; 6)
-            IDENT@[5; 6) "T"
-    WHITESPACE@[6; 7) " "
-    FOR_KW@[7; 10) "for"
-    WHITESPACE@[10; 11) " "
-    TUPLE_TYPE@[11; 13)
-      L_PAREN@[11; 12) "("
-      R_PAREN@[12; 13) ")"
-    WHITESPACE@[13; 14) " "
-    ITEM_LIST@[14; 117)
-      L_CURLY@[14; 15) "{"
-      WHITESPACE@[15; 20) "\n    "
-      FN_DEF@[20; 31)
-        FN_KW@[20; 22) "fn"
-        WHITESPACE@[22; 23) " "
-        NAME@[23; 26)
-          IDENT@[23; 26) "foo"
-        PARAM_LIST@[26; 28)
-          L_PAREN@[26; 27) "("
-          R_PAREN@[27; 28) ")"
-        WHITESPACE@[28; 29) " "
-        BLOCK_EXPR@[29; 31)
-          BLOCK@[29; 31)
-            L_CURLY@[29; 30) "{"
-            R_CURLY@[30; 31) "}"
-      WHITESPACE@[31; 36) "\n    "
-      FN_DEF@[36; 51)
-        VISIBILITY@[36; 39)
-          PUB_KW@[36; 39) "pub"
-        WHITESPACE@[39; 40) " "
-        FN_KW@[40; 42) "fn"
-        WHITESPACE@[42; 43) " "
-        NAME@[43; 46)
-          IDENT@[43; 46) "bar"
-        PARAM_LIST@[46; 48)
-          L_PAREN@[46; 47) "("
-          R_PAREN@[47; 48) ")"
-        WHITESPACE@[48; 49) " "
-        BLOCK_EXPR@[49; 51)
-          BLOCK@[49; 51)
-            L_CURLY@[49; 50) "{"
-            R_CURLY@[50; 51) "}"
-      WHITESPACE@[51; 56) "\n    "
-      TYPE_ALIAS_DEF@[56; 81)
-        VISIBILITY@[56; 66)
-          PUB_KW@[56; 59) "pub"
-          L_PAREN@[59; 60) "("
-          CRATE_KW@[60; 65) "crate"
-          R_PAREN@[65; 66) ")"
-        WHITESPACE@[66; 67) " "
-        TYPE_KW@[67; 71) "type"
-        WHITESPACE@[71; 72) " "
-        NAME@[72; 75)
-          IDENT@[72; 75) "Baz"
-        WHITESPACE@[75; 76) " "
-        EQ@[76; 77) "="
-        WHITESPACE@[77; 78) " "
-        TUPLE_TYPE@[78; 80)
-          L_PAREN@[78; 79) "("
-          R_PAREN@[79; 80) ")"
-        SEMI@[80; 81) ";"
-      WHITESPACE@[81; 86) "\n    "
-      CONST_DEF@[86; 115)
-        VISIBILITY@[86; 96)
-          PUB_KW@[86; 89) "pub"
-          L_PAREN@[89; 90) "("
-          CRATE_KW@[90; 95) "crate"
-          R_PAREN@[95; 96) ")"
-        WHITESPACE@[96; 97) " "
-        CONST_KW@[97; 102) "const"
-        WHITESPACE@[102; 103) " "
-        NAME@[103; 104)
-          IDENT@[103; 104) "C"
-        COLON@[104; 105) ":"
-        WHITESPACE@[105; 106) " "
-        PATH_TYPE@[106; 109)
-          PATH@[106; 109)
-            PATH_SEGMENT@[106; 109)
-              NAME_REF@[106; 109)
-                IDENT@[106; 109) "i32"
-        WHITESPACE@[109; 110) " "
-        EQ@[110; 111) "="
-        WHITESPACE@[111; 112) " "
-        LITERAL@[112; 114)
-          INT_NUMBER@[112; 114) "92"
-        SEMI@[114; 115) ";"
-      WHITESPACE@[115; 116) "\n"
-      R_CURLY@[116; 117) "}"
-  WHITESPACE@[117; 118) "\n"
-error [36; 39): unnecessary visibility qualifier
-error [56; 66): unnecessary visibility qualifier
-error [86; 96): unnecessary visibility qualifier