aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rw-r--r--Cargo.toml4
-rw-r--r--crates/ra_hir/src/adt.rs2
-rw-r--r--crates/ra_hir/src/code_model.rs12
-rw-r--r--crates/ra_hir/src/code_model/src.rs4
-rw-r--r--crates/ra_hir/src/expr/scope.rs5
-rw-r--r--crates/ra_hir/src/from_source.rs10
-rw-r--r--crates/ra_hir/src/lib.rs6
-rw-r--r--crates/ra_hir/src/ty/lower.rs4
-rw-r--r--crates/ra_hir_def/src/adt.rs16
-rw-r--r--crates/ra_hir_def/src/builtin_type.rs32
-rw-r--r--crates/ra_hir_def/src/db.rs12
-rw-r--r--crates/ra_hir_def/src/lib.rs28
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs22
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs31
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs62
-rw-r--r--crates/ra_ide_api/src/display.rs2
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs328
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs16
-rw-r--r--crates/ra_ide_api/src/goto_type_definition.rs4
-rw-r--r--crates/ra_ide_api/src/hover.rs46
-rw-r--r--crates/ra_ide_api/src/impls.rs11
-rw-r--r--crates/ra_ide_api/src/lib.rs4
-rw-r--r--crates/ra_ide_api/src/references.rs12
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs145
-rw-r--r--crates/ra_project_model/src/lib.rs10
-rw-r--r--crates/ra_project_model/src/sysroot.rs4
-rw-r--r--crates/ra_syntax/src/syntax_error.rs4
-rw-r--r--crates/ra_syntax/src/validation.rs23
-rw-r--r--crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt99
31 files changed, 634 insertions, 331 deletions
diff --git a/.travis.yml b/.travis.yml
index 7d66f72d8..af71a9cce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,6 @@ matrix:
14 script: 14 script:
15 - rustup component add rustfmt 15 - rustup component add rustfmt
16 - rustup component add rust-src 16 - rustup component add rust-src
17 - sed -i "s/debug = 1/debug = false/g" Cargo.toml
18 - cargo test --no-run # let's measure compile time separately 17 - cargo test --no-run # let's measure compile time separately
19 - cargo test 18 - cargo test
20 env: 19 env:
diff --git a/Cargo.toml b/Cargo.toml
index 97c02b40f..5c57020f7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,9 @@
2members = [ "crates/*", "xtask/" ] 2members = [ "crates/*", "xtask/" ]
3 3
4[profile.dev] 4[profile.dev]
5debug = 1 # only line info 5# disabling debug info speeds up builds a bunch,
6# and we don't rely on it for debugging that much.
7debug = 0
6 8
7[profile.release] 9[profile.release]
8incremental = true 10incremental = true
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index 0436d20b7..945f236c2 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -12,7 +12,7 @@ use crate::{
12 12
13impl Struct { 13impl Struct {
14 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 14 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
15 db.struct_data(self.id).variant_data.clone() 15 db.struct_data(self.id.into()).variant_data.clone()
16 } 16 }
17} 17}
18 18
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 9d0db8024..e5bfad3ca 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -288,7 +288,7 @@ pub struct Struct {
288 288
289impl Struct { 289impl Struct {
290 pub fn module(self, db: &impl DefDatabase) -> Module { 290 pub fn module(self, db: &impl DefDatabase) -> Module {
291 Module { id: self.id.module(db) } 291 Module { id: self.id.0.module(db) }
292 } 292 }
293 293
294 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 294 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -296,11 +296,11 @@ impl Struct {
296 } 296 }
297 297
298 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 298 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
299 db.struct_data(self.id).name.clone() 299 db.struct_data(self.id.into()).name.clone()
300 } 300 }
301 301
302 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> { 302 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
303 db.struct_data(self.id) 303 db.struct_data(self.id.into())
304 .variant_data 304 .variant_data
305 .fields() 305 .fields()
306 .into_iter() 306 .into_iter()
@@ -310,7 +310,7 @@ impl Struct {
310 } 310 }
311 311
312 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { 312 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
313 db.struct_data(self.id) 313 db.struct_data(self.id.into())
314 .variant_data 314 .variant_data
315 .fields() 315 .fields()
316 .into_iter() 316 .into_iter()
@@ -346,11 +346,11 @@ pub struct Union {
346 346
347impl Union { 347impl Union {
348 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 348 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
349 db.union_data(self.id).name.clone() 349 db.struct_data(self.id.into()).name.clone()
350 } 350 }
351 351
352 pub fn module(self, db: &impl HirDatabase) -> Module { 352 pub fn module(self, db: &impl HirDatabase) -> Module {
353 Module { id: self.id.module(db) } 353 Module { id: self.id.0.module(db) }
354 } 354 }
355 355
356 pub fn ty(self, db: &impl HirDatabase) -> Ty { 356 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 6d116ee75..247ae3e55 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 {
78impl HasSource for Struct { 78impl HasSource for Struct {
79 type Ast = ast::StructDef; 79 type Ast = ast::StructDef;
80 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 80 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> {
81 self.id.source(db) 81 self.id.0.source(db)
82 } 82 }
83} 83}
84impl HasSource for Union { 84impl HasSource for Union {
85 type Ast = ast::StructDef; 85 type Ast = ast::StructDef;
86 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 86 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> {
87 self.id.source(db) 87 self.id.0.source(db)
88 } 88 }
89} 89}
90impl HasSource for Enum { 90impl HasSource for Enum {
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index c14c2ab66..5a1eade2c 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -67,10 +67,7 @@ impl ExprScopes {
67 &self.scopes[scope].entries 67 &self.scopes[scope].entries
68 } 68 }
69 69
70 pub(crate) fn scope_chain<'a>( 70 pub(crate) fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
71 &'a self,
72 scope: Option<ScopeId>,
73 ) -> impl Iterator<Item = ScopeId> + 'a {
74 std::iter::successors(scope, move |&scope| self.scopes[scope].parent) 71 std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
75 } 72 }
76 73
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 9899bdbbc..c95d2cdd0 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,5 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{StructId, StructOrUnionId, UnionId};
3use hir_expand::name::AsName; 4use hir_expand::name::AsName;
4use ra_syntax::ast::{self, AstNode, NameOwner}; 5use ra_syntax::ast::{self, AstNode, NameOwner};
5 6
@@ -15,18 +16,19 @@ pub trait FromSource: Sized {
15 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>; 16 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>;
16} 17}
17 18
19// FIXIME: these two impls are wrong, `ast::StructDef` might produce either a struct or a union
18impl FromSource for Struct { 20impl FromSource for Struct {
19 type Ast = ast::StructDef; 21 type Ast = ast::StructDef;
20 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 22 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
21 let id = from_source(db, src)?; 23 let id: StructOrUnionId = from_source(db, src)?;
22 Some(Struct { id }) 24 Some(Struct { id: StructId(id) })
23 } 25 }
24} 26}
25impl FromSource for Union { 27impl FromSource for Union {
26 type Ast = ast::StructDef; 28 type Ast = ast::StructDef;
27 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 29 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
28 let id = from_source(db, src)?; 30 let id: StructOrUnionId = from_source(db, src)?;
29 Some(Union { id }) 31 Some(Union { id: UnionId(id) })
30 } 32 }
31} 33}
32impl FromSource for Enum { 34impl FromSource for Enum {
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 131f6c797..9dc8d139b 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -76,7 +76,11 @@ pub use crate::{
76 resolve::ScopeDef, 76 resolve::ScopeDef,
77 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 77 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
78 ty::{ 78 ty::{
79 display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 79 display::HirDisplay,
80 primitive::{
81 FloatBitness, FloatTy, IntBitness, IntTy, Signedness, UncertainFloatTy, UncertainIntTy,
82 },
83 ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
80 }, 84 },
81}; 85};
82 86
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index d26b16cb2..1fed5025e 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 {
665} 665}
666 666
667fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { 667fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
668 let struct_data = db.struct_data(def.id); 668 let struct_data = db.struct_data(def.id.into());
669 let fields = match struct_data.variant_data.fields() { 669 let fields = match struct_data.variant_data.fields() {
670 Some(fields) => fields, 670 Some(fields) => fields,
671 None => panic!("fn_sig_for_struct_constructor called on unit struct"), 671 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 {
681 681
682/// Build the type of a tuple struct constructor. 682/// Build the type of a tuple struct constructor.
683fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { 683fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
684 let struct_data = db.struct_data(def.id); 684 let struct_data = db.struct_data(def.id.into());
685 if struct_data.variant_data.fields().is_none() { 685 if struct_data.variant_data.fields().is_none() {
686 return type_for_adt(db, def); // Unit struct 686 return type_for_adt(db, def); // Unit struct
687 } 687 }
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 8f41e55d2..a29c4d41e 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};
8 8
9use crate::{ 9use crate::{
10 db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId, 10 db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId,
11 LocalStructFieldId, StructId, UnionId, 11 LocalStructFieldId, StructOrUnionId,
12}; 12};
13 13
14/// Note that we use `StructData` for unions as well! 14/// Note that we use `StructData` for unions as well!
@@ -49,15 +49,11 @@ pub struct StructFieldData {
49} 49}
50 50
51impl StructData { 51impl StructData {
52 pub(crate) fn struct_data_query(db: &impl DefDatabase2, struct_: StructId) -> Arc<StructData> { 52 pub(crate) fn struct_data_query(
53 let src = struct_.source(db); 53 db: &impl DefDatabase2,
54 let name = src.ast.name().map(|n| n.as_name()); 54 id: StructOrUnionId,
55 let variant_data = VariantData::new(src.ast.kind()); 55 ) -> Arc<StructData> {
56 let variant_data = Arc::new(variant_data); 56 let src = id.source(db);
57 Arc::new(StructData { name, variant_data })
58 }
59 pub(crate) fn union_data_query(db: &impl DefDatabase2, struct_: UnionId) -> Arc<StructData> {
60 let src = struct_.source(db);
61 let name = src.ast.name().map(|n| n.as_name()); 57 let name = src.ast.name().map(|n| n.as_name());
62 let variant_data = VariantData::new(src.ast.kind()); 58 let variant_data = VariantData::new(src.ast.kind());
63 let variant_data = Arc::new(variant_data); 59 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 12929caa9..2ec0c83fe 100644
--- a/crates/ra_hir_def/src/builtin_type.rs
+++ b/crates/ra_hir_def/src/builtin_type.rs
@@ -3,6 +3,8 @@
3//! A peculiarity of built-in types is that they are always available and are 3//! A peculiarity of built-in types is that they are always available and are
4//! not associated with any particular crate. 4//! not associated with any particular crate.
5 5
6use std::fmt;
7
6use hir_expand::name::{self, Name}; 8use hir_expand::name::{self, Name};
7 9
8#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@@ -61,3 +63,33 @@ impl BuiltinType {
61 (name::F64, BuiltinType::Float { bitness: FloatBitness::X64 }), 63 (name::F64, BuiltinType::Float { bitness: FloatBitness::X64 }),
62 ]; 64 ];
63} 65}
66
67impl fmt::Display for BuiltinType {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 let type_name = match self {
70 BuiltinType::Char => "char",
71 BuiltinType::Bool => "bool",
72 BuiltinType::Str => "str",
73 BuiltinType::Int { signedness, bitness } => match (signedness, bitness) {
74 (Signedness::Signed, IntBitness::Xsize) => "isize",
75 (Signedness::Signed, IntBitness::X8) => "i8",
76 (Signedness::Signed, IntBitness::X16) => "i16",
77 (Signedness::Signed, IntBitness::X32) => "i32",
78 (Signedness::Signed, IntBitness::X64) => "i64",
79 (Signedness::Signed, IntBitness::X128) => "i128",
80
81 (Signedness::Unsigned, IntBitness::Xsize) => "usize",
82 (Signedness::Unsigned, IntBitness::X8) => "u8",
83 (Signedness::Unsigned, IntBitness::X16) => "u16",
84 (Signedness::Unsigned, IntBitness::X32) => "u32",
85 (Signedness::Unsigned, IntBitness::X64) => "u64",
86 (Signedness::Unsigned, IntBitness::X128) => "u128",
87 },
88 BuiltinType::Float { bitness } => match bitness {
89 FloatBitness::X32 => "f32",
90 FloatBitness::X64 => "f64",
91 },
92 };
93 f.write_str(type_name)
94 }
95}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index a42348101..29cf71a59 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -11,7 +11,7 @@ use crate::{
11 raw::{ImportSourceMap, RawItems}, 11 raw::{ImportSourceMap, RawItems},
12 CrateDefMap, 12 CrateDefMap,
13 }, 13 },
14 EnumId, StructId, UnionId, 14 EnumId, StructOrUnionId,
15}; 15};
16 16
17#[salsa::query_group(InternDatabaseStorage)] 17#[salsa::query_group(InternDatabaseStorage)]
@@ -19,9 +19,8 @@ pub trait InternDatabase: SourceDatabase {
19 #[salsa::interned] 19 #[salsa::interned]
20 fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId; 20 fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId;
21 #[salsa::interned] 21 #[salsa::interned]
22 fn intern_struct(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::StructId; 22 fn intern_struct_or_union(&self, loc: crate::ItemLoc<ast::StructDef>)
23 #[salsa::interned] 23 -> crate::StructOrUnionId;
24 fn intern_union(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::UnionId;
25 #[salsa::interned] 24 #[salsa::interned]
26 fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId; 25 fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId;
27 #[salsa::interned] 26 #[salsa::interned]
@@ -49,10 +48,7 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
49 fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; 48 fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;
50 49
51 #[salsa::invoke(StructData::struct_data_query)] 50 #[salsa::invoke(StructData::struct_data_query)]
52 fn struct_data(&self, s: StructId) -> Arc<StructData>; 51 fn struct_data(&self, id: StructOrUnionId) -> Arc<StructData>;
53
54 #[salsa::invoke(StructData::union_data_query)]
55 fn union_data(&self, s: UnionId) -> Arc<StructData>;
56 52
57 #[salsa::invoke(EnumData::enum_data_query)] 53 #[salsa::invoke(EnumData::enum_data_query)]
58 fn enum_data(&self, e: EnumId) -> Arc<EnumData>; 54 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 63ed2a098..239317efe 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -205,26 +205,30 @@ impl AstItemDef<ast::FnDef> for FunctionId {
205} 205}
206 206
207#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 207#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
208pub struct StructId(salsa::InternId); 208pub struct StructOrUnionId(salsa::InternId);
209impl_intern_key!(StructId); 209impl_intern_key!(StructOrUnionId);
210impl AstItemDef<ast::StructDef> for StructId { 210impl AstItemDef<ast::StructDef> for StructOrUnionId {
211 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self { 211 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
212 db.intern_struct(loc) 212 db.intern_struct_or_union(loc)
213 } 213 }
214 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> { 214 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
215 db.lookup_intern_struct(self) 215 db.lookup_intern_struct_or_union(self)
216 } 216 }
217} 217}
218 218
219#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 219#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
220pub struct UnionId(salsa::InternId); 220pub struct StructId(pub StructOrUnionId);
221impl_intern_key!(UnionId); 221impl From<StructId> for StructOrUnionId {
222impl AstItemDef<ast::StructDef> for UnionId { 222 fn from(id: StructId) -> StructOrUnionId {
223 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self { 223 id.0
224 db.intern_union(loc)
225 } 224 }
226 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> { 225}
227 db.lookup_intern_union(self) 226
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
228pub struct UnionId(pub StructOrUnionId);
229impl From<UnionId> for StructOrUnionId {
230 fn from(id: UnionId) -> StructOrUnionId {
231 id.0
228 } 232 }
229} 233}
230 234
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 30664278e..37d0f3093 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -20,7 +20,8 @@ use crate::{
20 }, 20 },
21 path::{Path, PathKind}, 21 path::{Path, PathKind},
22 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, 22 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId,
23 LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, 23 LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId,
24 UnionId,
24}; 25};
25 26
26pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap { 27pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -36,11 +37,12 @@ pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) ->
36 ); 37 );
37 38
38 // look for the prelude 39 // look for the prelude
39 if def_map.prelude.is_none() { 40 // If the dependency defines a prelude, we overwrite an already defined
40 let map = db.crate_def_map(dep.crate_id); 41 // prelude. This is necessary to import the "std" prelude if a crate
41 if map.prelude.is_some() { 42 // depends on both "core" and "std".
42 def_map.prelude = map.prelude; 43 let dep_def_map = db.crate_def_map(dep.crate_id);
43 } 44 if dep_def_map.prelude.is_some() {
45 def_map.prelude = dep_def_map.prelude;
44 } 46 }
45 } 47 }
46 48
@@ -665,12 +667,14 @@ where
665 PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into()) 667 PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into())
666 } 668 }
667 raw::DefKind::Struct(ast_id) => { 669 raw::DefKind::Struct(ast_id) => {
668 let s = StructId::from_ast_id(ctx, ast_id).into(); 670 let id = StructOrUnionId::from_ast_id(ctx, ast_id).into();
671 let s = StructId(id).into();
669 PerNs::both(s, s) 672 PerNs::both(s, s)
670 } 673 }
671 raw::DefKind::Union(ast_id) => { 674 raw::DefKind::Union(ast_id) => {
672 let s = UnionId::from_ast_id(ctx, ast_id).into(); 675 let id = StructOrUnionId::from_ast_id(ctx, ast_id).into();
673 PerNs::both(s, s) 676 let u = UnionId(id).into();
677 PerNs::both(u, u)
674 } 678 }
675 raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()), 679 raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
676 raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()), 680 raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()),
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 52bd0aa91..256f7d4be 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -464,6 +464,37 @@ fn values_dont_shadow_extern_crates() {
464} 464}
465 465
466#[test] 466#[test]
467fn std_prelude_takes_precedence_above_core_prelude() {
468 let map = def_map(
469 r#"
470 //- /main.rs crate:main deps:core,std
471 use {Foo, Bar};
472
473 //- /std.rs crate:std deps:core
474 #[prelude_import]
475 pub use self::prelude::*;
476 mod prelude {
477 pub struct Foo;
478 pub use core::prelude::Bar;
479 }
480
481 //- /core.rs crate:core
482 #[prelude_import]
483 pub use self::prelude::*;
484 mod prelude {
485 pub struct Bar;
486 }
487 "#,
488 );
489
490 assert_snapshot!(map, @r###"
491 â‹®crate
492 â‹®Bar: t v
493 â‹®Foo: t v
494 "###);
495}
496
497#[test]
467fn cfg_not_test() { 498fn cfg_not_test() {
468 let map = def_map( 499 let map = def_map(
469 r#" 500 r#"
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 4e56de3f5..3e205efd1 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -598,6 +598,68 @@ mod tests {
598 } 598 }
599 599
600 #[test] 600 #[test]
601 fn completes_std_prelude_if_core_is_defined() {
602 assert_debug_snapshot!(
603 do_reference_completion(
604 "
605 //- /main.rs
606 fn foo() { let x: <|> }
607
608 //- /core/lib.rs
609 #[prelude_import]
610 use prelude::*;
611
612 mod prelude {
613 struct Option;
614 }
615
616 //- /std/lib.rs
617 #[prelude_import]
618 use prelude::*;
619
620 mod prelude {
621 struct String;
622 }
623 "
624 ),
625 @r###"
626 [
627 CompletionItem {
628 label: "String",
629 source_range: [18; 18),
630 delete: [18; 18),
631 insert: "String",
632 kind: Struct,
633 },
634 CompletionItem {
635 label: "core",
636 source_range: [18; 18),
637 delete: [18; 18),
638 insert: "core",
639 kind: Module,
640 },
641 CompletionItem {
642 label: "foo()",
643 source_range: [18; 18),
644 delete: [18; 18),
645 insert: "foo()$0",
646 kind: Function,
647 lookup: "foo",
648 detail: "fn foo()",
649 },
650 CompletionItem {
651 label: "std",
652 source_range: [18; 18),
653 delete: [18; 18),
654 insert: "std",
655 kind: Module,
656 },
657 ]
658 "###
659 );
660 }
661
662 #[test]
601 fn completes_macros_as_value() { 663 fn completes_macros_as_value() {
602 assert_debug_snapshot!( 664 assert_debug_snapshot!(
603 do_reference_completion( 665 do_reference_completion(
diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs
index a980c56bc..30617412a 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;
15pub use navigation_target::NavigationTarget; 15pub use navigation_target::NavigationTarget;
16pub use structure::{file_structure, StructureNode}; 16pub use structure::{file_structure, StructureNode};
17 17
18pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol}; 18pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav};
19pub(crate) use short_label::ShortLabel; 19pub(crate) use short_label::ShortLabel;
20 20
21pub(crate) fn function_label(node: &ast::FnDef) -> String { 21pub(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 1bf81e7d5..41d467564 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -29,19 +29,8 @@ pub struct NavigationTarget {
29 docs: Option<String>, 29 docs: Option<String>,
30} 30}
31 31
32fn find_range_from_node( 32pub(crate) trait ToNav {
33 db: &RootDatabase, 33 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget;
34 src: hir::HirFileId,
35 node: &SyntaxNode,
36) -> (FileId, TextRange) {
37 let text_range = node.text_range();
38 let (file_id, text_range) = src
39 .expansion_info(db)
40 .and_then(|expansion_info| expansion_info.find_range(text_range))
41 .unwrap_or((src, text_range));
42
43 // FIXME: handle recursive macro generated macro
44 (file_id.original_file(db), text_range)
45} 34}
46 35
47impl NavigationTarget { 36impl NavigationTarget {
@@ -95,19 +84,6 @@ impl NavigationTarget {
95 NavigationTarget::from_named(db, file_id.into(), pat, None, None) 84 NavigationTarget::from_named(db, file_id.into(), pat, None, None)
96 } 85 }
97 86
98 pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget {
99 NavigationTarget {
100 file_id: symbol.file_id,
101 name: symbol.name.clone(),
102 kind: symbol.ptr.kind(),
103 full_range: symbol.ptr.range(),
104 focus_range: symbol.name_range,
105 container_name: symbol.container_name.clone(),
106 description: description_from_symbol(db, &symbol),
107 docs: docs_from_symbol(db, &symbol),
108 }
109 }
110
111 pub(crate) fn from_pat( 87 pub(crate) fn from_pat(
112 db: &RootDatabase, 88 db: &RootDatabase,
113 file_id: FileId, 89 file_id: FileId,
@@ -136,39 +112,6 @@ impl NavigationTarget {
136 } 112 }
137 } 113 }
138 114
139 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
140 let src = module.definition_source(db);
141 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
142 match src.ast {
143 ModuleSource::SourceFile(node) => {
144 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
145
146 NavigationTarget::from_syntax(
147 file_id,
148 name,
149 None,
150 text_range,
151 node.syntax(),
152 None,
153 None,
154 )
155 }
156 ModuleSource::Module(node) => {
157 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
158
159 NavigationTarget::from_syntax(
160 file_id,
161 name,
162 None,
163 text_range,
164 node.syntax(),
165 node.doc_comment_text(),
166 node.short_label(),
167 )
168 }
169 }
170 }
171
172 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 115 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
173 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 116 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
174 if let Some(src) = module.declaration_source(db) { 117 if let Some(src) = module.declaration_source(db) {
@@ -183,55 +126,7 @@ impl NavigationTarget {
183 src.ast.short_label(), 126 src.ast.short_label(),
184 ); 127 );
185 } 128 }
186 NavigationTarget::from_module(db, module) 129 module.to_nav(db)
187 }
188
189 pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget {
190 let src = field.source(db);
191 match src.ast {
192 FieldSource::Named(it) => NavigationTarget::from_named(
193 db,
194 src.file_id,
195 &it,
196 it.doc_comment_text(),
197 it.short_label(),
198 ),
199 FieldSource::Pos(it) => {
200 let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax());
201 NavigationTarget::from_syntax(
202 file_id,
203 "".into(),
204 None,
205 text_range,
206 it.syntax(),
207 None,
208 None,
209 )
210 }
211 }
212 }
213
214 pub(crate) fn from_def_source<A, D>(db: &RootDatabase, def: D) -> NavigationTarget
215 where
216 D: HasSource<Ast = A>,
217 A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
218 {
219 let src = def.source(db);
220 NavigationTarget::from_named(
221 db,
222 src.file_id,
223 &src.ast,
224 src.ast.doc_comment_text(),
225 src.ast.short_label(),
226 )
227 }
228
229 pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::Adt) -> NavigationTarget {
230 match adt_def {
231 hir::Adt::Struct(it) => NavigationTarget::from_def_source(db, it),
232 hir::Adt::Union(it) => NavigationTarget::from_def_source(db, it),
233 hir::Adt::Enum(it) => NavigationTarget::from_def_source(db, it),
234 }
235 } 130 }
236 131
237 pub(crate) fn from_def( 132 pub(crate) fn from_def(
@@ -239,14 +134,14 @@ impl NavigationTarget {
239 module_def: hir::ModuleDef, 134 module_def: hir::ModuleDef,
240 ) -> Option<NavigationTarget> { 135 ) -> Option<NavigationTarget> {
241 let nav = match module_def { 136 let nav = match module_def {
242 hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module), 137 hir::ModuleDef::Module(module) => module.to_nav(db),
243 hir::ModuleDef::Function(func) => NavigationTarget::from_def_source(db, func), 138 hir::ModuleDef::Function(it) => it.to_nav(db),
244 hir::ModuleDef::Adt(it) => NavigationTarget::from_adt_def(db, it), 139 hir::ModuleDef::Adt(it) => it.to_nav(db),
245 hir::ModuleDef::Const(it) => NavigationTarget::from_def_source(db, it), 140 hir::ModuleDef::Const(it) => it.to_nav(db),
246 hir::ModuleDef::Static(it) => NavigationTarget::from_def_source(db, it), 141 hir::ModuleDef::Static(it) => it.to_nav(db),
247 hir::ModuleDef::EnumVariant(it) => NavigationTarget::from_def_source(db, it), 142 hir::ModuleDef::EnumVariant(it) => it.to_nav(db),
248 hir::ModuleDef::Trait(it) => NavigationTarget::from_def_source(db, it), 143 hir::ModuleDef::Trait(it) => it.to_nav(db),
249 hir::ModuleDef::TypeAlias(it) => NavigationTarget::from_def_source(db, it), 144 hir::ModuleDef::TypeAlias(it) => it.to_nav(db),
250 hir::ModuleDef::BuiltinType(..) => { 145 hir::ModuleDef::BuiltinType(..) => {
251 return None; 146 return None;
252 } 147 }
@@ -254,41 +149,6 @@ impl NavigationTarget {
254 Some(nav) 149 Some(nav)
255 } 150 }
256 151
257 pub(crate) fn from_impl_block(
258 db: &RootDatabase,
259 impl_block: hir::ImplBlock,
260 ) -> NavigationTarget {
261 let src = impl_block.source(db);
262 let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax());
263
264 NavigationTarget::from_syntax(
265 file_id,
266 "impl".into(),
267 None,
268 text_range,
269 src.ast.syntax(),
270 None,
271 None,
272 )
273 }
274
275 pub(crate) fn from_assoc_item(
276 db: &RootDatabase,
277 assoc_item: hir::AssocItem,
278 ) -> NavigationTarget {
279 match assoc_item {
280 AssocItem::Function(it) => NavigationTarget::from_def_source(db, it),
281 AssocItem::Const(it) => NavigationTarget::from_def_source(db, it),
282 AssocItem::TypeAlias(it) => NavigationTarget::from_def_source(db, it),
283 }
284 }
285
286 pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget {
287 let src = macro_call.source(db);
288 log::debug!("nav target {:#?}", src.ast.syntax());
289 NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None)
290 }
291
292 #[cfg(test)] 152 #[cfg(test)]
293 pub(crate) fn assert_match(&self, expected: &str) { 153 pub(crate) fn assert_match(&self, expected: &str) {
294 let actual = self.debug_render(); 154 let actual = self.debug_render();
@@ -359,6 +219,172 @@ impl NavigationTarget {
359 } 219 }
360} 220}
361 221
222impl ToNav for FileSymbol {
223 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
224 NavigationTarget {
225 file_id: self.file_id,
226 name: self.name.clone(),
227 kind: self.ptr.kind(),
228 full_range: self.ptr.range(),
229 focus_range: self.name_range,
230 container_name: self.container_name.clone(),
231 description: description_from_symbol(db, self),
232 docs: docs_from_symbol(db, self),
233 }
234 }
235}
236
237pub(crate) trait ToNavFromAst {}
238impl ToNavFromAst for hir::Function {}
239impl ToNavFromAst for hir::Const {}
240impl ToNavFromAst for hir::Static {}
241impl ToNavFromAst for hir::Struct {}
242impl ToNavFromAst for hir::Enum {}
243impl ToNavFromAst for hir::EnumVariant {}
244impl ToNavFromAst for hir::Union {}
245impl ToNavFromAst for hir::TypeAlias {}
246impl ToNavFromAst for hir::Trait {}
247
248impl<D> ToNav for D
249where
250 D: HasSource + ToNavFromAst + Copy,
251 D::Ast: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
252{
253 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
254 let src = self.source(db);
255 NavigationTarget::from_named(
256 db,
257 src.file_id,
258 &src.ast,
259 src.ast.doc_comment_text(),
260 src.ast.short_label(),
261 )
262 }
263}
264
265impl ToNav for hir::Module {
266 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
267 let src = self.definition_source(db);
268 let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default();
269 match src.ast {
270 ModuleSource::SourceFile(node) => {
271 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
272
273 NavigationTarget::from_syntax(
274 file_id,
275 name,
276 None,
277 text_range,
278 node.syntax(),
279 None,
280 None,
281 )
282 }
283 ModuleSource::Module(node) => {
284 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
285
286 NavigationTarget::from_syntax(
287 file_id,
288 name,
289 None,
290 text_range,
291 node.syntax(),
292 node.doc_comment_text(),
293 node.short_label(),
294 )
295 }
296 }
297 }
298}
299
300impl ToNav for hir::ImplBlock {
301 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
302 let src = self.source(db);
303 let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax());
304
305 NavigationTarget::from_syntax(
306 file_id,
307 "impl".into(),
308 None,
309 text_range,
310 src.ast.syntax(),
311 None,
312 None,
313 )
314 }
315}
316
317impl ToNav for hir::StructField {
318 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
319 let src = self.source(db);
320
321 match src.ast {
322 FieldSource::Named(it) => NavigationTarget::from_named(
323 db,
324 src.file_id,
325 &it,
326 it.doc_comment_text(),
327 it.short_label(),
328 ),
329 FieldSource::Pos(it) => {
330 let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax());
331 NavigationTarget::from_syntax(
332 file_id,
333 "".into(),
334 None,
335 text_range,
336 it.syntax(),
337 None,
338 None,
339 )
340 }
341 }
342 }
343}
344
345impl ToNav for hir::MacroDef {
346 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
347 let src = self.source(db);
348 log::debug!("nav target {:#?}", src.ast.syntax());
349 NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None)
350 }
351}
352
353impl ToNav for hir::Adt {
354 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
355 match self {
356 hir::Adt::Struct(it) => it.to_nav(db),
357 hir::Adt::Union(it) => it.to_nav(db),
358 hir::Adt::Enum(it) => it.to_nav(db),
359 }
360 }
361}
362
363impl ToNav for hir::AssocItem {
364 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
365 match self {
366 AssocItem::Function(it) => it.to_nav(db),
367 AssocItem::Const(it) => it.to_nav(db),
368 AssocItem::TypeAlias(it) => it.to_nav(db),
369 }
370 }
371}
372
373fn find_range_from_node(
374 db: &RootDatabase,
375 src: hir::HirFileId,
376 node: &SyntaxNode,
377) -> (FileId, TextRange) {
378 let text_range = node.text_range();
379 let (file_id, text_range) = src
380 .expansion_info(db)
381 .and_then(|expansion_info| expansion_info.find_range(text_range))
382 .unwrap_or((src, text_range));
383
384 // FIXME: handle recursive macro generated macro
385 (file_id.original_file(db), text_range)
386}
387
362pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { 388pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
363 let parse = db.parse(symbol.file_id); 389 let parse = db.parse(symbol.file_id);
364 let node = symbol.ptr.to_node(parse.tree().syntax()); 390 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 afa59cbe3..713b61d5e 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::{
9 9
10use crate::{ 10use crate::{
11 db::RootDatabase, 11 db::RootDatabase,
12 display::ShortLabel, 12 display::{ShortLabel, ToNav},
13 references::{classify_name_ref, NameKind::*}, 13 references::{classify_name_ref, NameKind::*},
14 FilePosition, NavigationTarget, RangeInfo, 14 FilePosition, NavigationTarget, RangeInfo,
15}; 15};
@@ -56,16 +56,16 @@ pub(crate) fn reference_definition(
56 56
57 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); 57 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
58 match name_kind { 58 match name_kind {
59 Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), 59 Some(Macro(mac)) => return Exact(mac.to_nav(db)),
60 Some(Field(field)) => return Exact(NavigationTarget::from_field(db, field)), 60 Some(Field(field)) => return Exact(field.to_nav(db)),
61 Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)), 61 Some(AssocItem(assoc)) => return Exact(assoc.to_nav(db)),
62 Some(Def(def)) => match NavigationTarget::from_def(db, def) { 62 Some(Def(def)) => match NavigationTarget::from_def(db, def) {
63 Some(nav) => return Exact(nav), 63 Some(nav) => return Exact(nav),
64 None => return Approximate(vec![]), 64 None => return Approximate(vec![]),
65 }, 65 },
66 Some(SelfType(ty)) => { 66 Some(SelfType(ty)) => {
67 if let Some((def_id, _)) = ty.as_adt() { 67 if let Some((adt, _)) = ty.as_adt() {
68 return Exact(NavigationTarget::from_adt_def(db, def_id)); 68 return Exact(adt.to_nav(db));
69 } 69 }
70 } 70 }
71 Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)), 71 Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)),
@@ -79,7 +79,7 @@ pub(crate) fn reference_definition(
79 // Fallback index based approach: 79 // Fallback index based approach:
80 let navs = crate::symbol_index::index_resolve(db, name_ref) 80 let navs = crate::symbol_index::index_resolve(db, name_ref)
81 .into_iter() 81 .into_iter()
82 .map(|s| NavigationTarget::from_symbol(db, s)) 82 .map(|s| s.to_nav(db))
83 .collect(); 83 .collect();
84 Approximate(navs) 84 Approximate(navs)
85} 85}
@@ -95,7 +95,7 @@ pub(crate) fn name_definition(
95 if module.has_semi() { 95 if module.has_semi() {
96 let src = hir::Source { file_id: file_id.into(), ast: module }; 96 let src = hir::Source { file_id: file_id.into(), ast: module };
97 if let Some(child_module) = hir::Module::from_declaration(db, src) { 97 if let Some(child_module) = hir::Module::from_declaration(db, src) {
98 let nav = NavigationTarget::from_module(db, child_module); 98 let nav = child_module.to_nav(db);
99 return Some(vec![nav]); 99 return Some(vec![nav]);
100 } 100 }
101 } 101 }
diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs
index 059d80524..71146591d 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 @@
3use ra_db::SourceDatabase; 3use ra_db::SourceDatabase;
4use ra_syntax::{ast, AstNode}; 4use ra_syntax::{ast, AstNode};
5 5
6use crate::{db::RootDatabase, FilePosition, NavigationTarget, RangeInfo}; 6use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo};
7 7
8pub(crate) fn goto_type_definition( 8pub(crate) fn goto_type_definition(
9 db: &RootDatabase, 9 db: &RootDatabase,
@@ -33,7 +33,7 @@ pub(crate) fn goto_type_definition(
33 33
34 let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?; 34 let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?;
35 35
36 let nav = NavigationTarget::from_adt_def(db, adt_def); 36 let nav = adt_def.to_nav(db);
37 Some(RangeInfo::new(node.text_range(), vec![nav])) 37 Some(RangeInfo::new(node.text_range(), vec![nav]))
38} 38}
39 39
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index ba328efa1..cc41390b2 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -117,27 +117,23 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
117 hir::AssocItem::Const(it) => from_def_source(db, it), 117 hir::AssocItem::Const(it) => from_def_source(db, it),
118 hir::AssocItem::TypeAlias(it) => from_def_source(db, it), 118 hir::AssocItem::TypeAlias(it) => from_def_source(db, it),
119 }), 119 }),
120 Some(Def(it)) => { 120 Some(Def(it)) => match it {
121 match it { 121 hir::ModuleDef::Module(it) => {
122 hir::ModuleDef::Module(it) => { 122 if let hir::ModuleSource::Module(it) = it.definition_source(db).ast {
123 if let hir::ModuleSource::Module(it) = it.definition_source(db).ast { 123 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
124 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
125 }
126 }
127 hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)),
128 hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)),
129 hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)),
130 hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)),
131 hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)),
132 hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)),
133 hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)),
134 hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)),
135 hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)),
136 hir::ModuleDef::BuiltinType(_) => {
137 // FIXME: hover for builtin Type ?
138 } 124 }
139 } 125 }
140 } 126 hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)),
127 hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)),
128 hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)),
129 hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)),
130 hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)),
131 hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)),
132 hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)),
133 hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)),
134 hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)),
135 hir::ModuleDef::BuiltinType(it) => res.extend(Some(it.to_string())),
136 },
141 Some(SelfType(ty)) => { 137 Some(SelfType(ty)) => {
142 if let Some((adt_def, _)) = ty.as_adt() { 138 if let Some((adt_def, _)) = ty.as_adt() {
143 res.extend(match adt_def { 139 res.extend(match adt_def {
@@ -722,4 +718,16 @@ fn func(foo: i32) { if true { <|>foo; }; }
722 assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo")); 718 assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo"));
723 assert_eq!(hover.info.is_exact(), true); 719 assert_eq!(hover.info.is_exact(), true);
724 } 720 }
721
722 #[test]
723 fn test_hover_tuple_field() {
724 let (analysis, position) = single_file_with_position(
725 "
726 struct TS(String, i32<|>);
727 ",
728 );
729 let hover = analysis.hover(position).unwrap().unwrap();
730 assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
731 assert_eq!(hover.info.is_exact(), true);
732 }
725} 733}
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
index b899ed3a5..bc9b66550 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};
4use ra_db::SourceDatabase; 4use ra_db::SourceDatabase;
5use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; 5use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
6 6
7use crate::{db::RootDatabase, FilePosition, NavigationTarget, RangeInfo}; 7use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo};
8 8
9pub(crate) fn goto_implementation( 9pub(crate) fn goto_implementation(
10 db: &RootDatabase, 10 db: &RootDatabase,
@@ -58,7 +58,7 @@ fn impls_for_def(
58 impls 58 impls
59 .all_impls() 59 .all_impls()
60 .filter(|impl_block| is_equal_for_find_impls(&ty, &impl_block.target_ty(db))) 60 .filter(|impl_block| is_equal_for_find_impls(&ty, &impl_block.target_ty(db)))
61 .map(|imp| NavigationTarget::from_impl_block(db, imp)) 61 .map(|imp| imp.to_nav(db))
62 .collect(), 62 .collect(),
63 ) 63 )
64} 64}
@@ -75,12 +75,7 @@ fn impls_for_trait(
75 let krate = module.krate(); 75 let krate = module.krate();
76 let impls = db.impls_in_crate(krate); 76 let impls = db.impls_in_crate(krate);
77 77
78 Some( 78 Some(impls.lookup_impl_blocks_for_trait(tr).map(|imp| imp.to_nav(db)).collect())
79 impls
80 .lookup_impl_blocks_for_trait(tr)
81 .map(|imp| NavigationTarget::from_impl_block(db, imp))
82 .collect(),
83 )
84} 79}
85 80
86fn is_equal_for_find_impls(original_ty: &Ty, impl_ty: &Ty) -> bool { 81fn 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 d0188da44..484fbcc82 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -56,7 +56,7 @@ use ra_db::{
56}; 56};
57use ra_syntax::{SourceFile, TextRange, TextUnit}; 57use ra_syntax::{SourceFile, TextRange, TextUnit};
58 58
59use crate::{db::LineIndexDatabase, symbol_index::FileSymbol}; 59use crate::{db::LineIndexDatabase, display::ToNav, symbol_index::FileSymbol};
60 60
61pub use crate::{ 61pub use crate::{
62 assists::{Assist, AssistId}, 62 assists::{Assist, AssistId},
@@ -351,7 +351,7 @@ impl Analysis {
351 self.with_db(|db| { 351 self.with_db(|db| {
352 symbol_index::world_symbols(db, query) 352 symbol_index::world_symbols(db, query)
353 .into_iter() 353 .into_iter()
354 .map(|s| NavigationTarget::from_symbol(db, s)) 354 .map(|s| s.to_nav(db))
355 .collect::<Vec<_>>() 355 .collect::<Vec<_>>()
356 }) 356 })
357 } 357 }
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index b5b1c9a16..0a76bf484 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -19,7 +19,9 @@ use ra_db::{SourceDatabase, SourceDatabaseExt};
19use ra_prof::profile; 19use ra_prof::profile;
20use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; 20use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit};
21 21
22use crate::{db::RootDatabase, FilePosition, FileRange, NavigationTarget, RangeInfo}; 22use crate::{
23 db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo,
24};
23 25
24pub(crate) use self::{ 26pub(crate) use self::{
25 classify::{classify_name, classify_name_ref}, 27 classify::{classify_name, classify_name_ref},
@@ -76,12 +78,12 @@ pub(crate) fn find_all_refs(
76 let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; 78 let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?;
77 79
78 let declaration = match def.kind { 80 let declaration = match def.kind {
79 NameKind::Macro(mac) => NavigationTarget::from_macro_def(db, mac), 81 NameKind::Macro(mac) => mac.to_nav(db),
80 NameKind::Field(field) => NavigationTarget::from_field(db, field), 82 NameKind::Field(field) => field.to_nav(db),
81 NameKind::AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), 83 NameKind::AssocItem(assoc) => assoc.to_nav(db),
82 NameKind::Def(def) => NavigationTarget::from_def(db, def)?, 84 NameKind::Def(def) => NavigationTarget::from_def(db, def)?,
83 NameKind::SelfType(ref ty) => match ty.as_adt() { 85 NameKind::SelfType(ref ty) => match ty.as_adt() {
84 Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id), 86 Some((adt, _)) => adt.to_nav(db),
85 None => return None, 87 None => return None,
86 }, 88 },
87 NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat), 89 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 33f3caceb..1ee68abe2 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -9,12 +9,15 @@ use ra_syntax::{
9 ast::{self, NameOwner}, 9 ast::{self, NameOwner},
10 AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind, 10 AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind,
11 SyntaxKind::*, 11 SyntaxKind::*,
12 TextRange, T, 12 SyntaxNode, TextRange, T,
13}; 13};
14 14
15use crate::{ 15use crate::{
16 db::RootDatabase, 16 db::RootDatabase,
17 references::{classify_name_ref, NameKind::*}, 17 references::{
18 classify_name, classify_name_ref,
19 NameKind::{self, *},
20 },
18 FileId, 21 FileId,
19}; 22};
20 23
@@ -100,81 +103,43 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
100 if node.ancestors().any(|it| it.kind() == ATTR) { 103 if node.ancestors().any(|it| it.kind() == ATTR) {
101 continue; 104 continue;
102 } 105 }
103 if let Some(name_ref) = node.as_node().cloned().and_then(ast::NameRef::cast) {
104 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
105 match name_kind {
106 Some(Macro(_)) => "macro",
107 Some(Field(_)) => "field",
108 Some(AssocItem(hir::AssocItem::Function(_))) => "function",
109 Some(AssocItem(hir::AssocItem::Const(_))) => "constant",
110 Some(AssocItem(hir::AssocItem::TypeAlias(_))) => "type",
111 Some(Def(hir::ModuleDef::Module(_))) => "module",
112 Some(Def(hir::ModuleDef::Function(_))) => "function",
113 Some(Def(hir::ModuleDef::Adt(_))) => "type",
114 Some(Def(hir::ModuleDef::EnumVariant(_))) => "constant",
115 Some(Def(hir::ModuleDef::Const(_))) => "constant",
116 Some(Def(hir::ModuleDef::Static(_))) => "constant",
117 Some(Def(hir::ModuleDef::Trait(_))) => "type",
118 Some(Def(hir::ModuleDef::TypeAlias(_))) => "type",
119 Some(Def(hir::ModuleDef::BuiltinType(_))) => "type",
120 Some(SelfType(_)) => "type",
121 Some(Pat((_, ptr))) => {
122 let pat = ptr.to_node(&root);
123 if let Some(name) = pat.name() {
124 let text = name.text();
125 let shadow_count =
126 bindings_shadow_count.entry(text.clone()).or_default();
127 binding_hash =
128 Some(calc_binding_hash(file_id, &text, *shadow_count))
129 }
130 106
131 let analyzer = 107 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
132 hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); 108 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
133 if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) { 109
134 "variable.mut" 110 if let Some(Pat((_, ptr))) = &name_kind {
135 } else { 111 let pat = ptr.to_node(&root);
136 "variable" 112 if let Some(name) = pat.name() {
137 } 113 let text = name.text();
138 } 114 let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
139 Some(SelfParam(_)) => "type", 115 binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
140 Some(GenericParam(_)) => "type",
141 None => "text",
142 } 116 }
143 } else { 117 };
144 "text" 118
145 } 119 name_kind
120 .map_or("text", |it| highlight_name(db, file_id, name_ref.syntax(), &root, it))
146 } 121 }
147 NAME => { 122 NAME => {
148 if let Some(name) = node.as_node().cloned().and_then(ast::Name::cast) { 123 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
149 let analyzer = hir::SourceAnalyzer::new(db, file_id, name.syntax(), None); 124 let name_kind = classify_name(db, file_id, &name).map(|d| d.kind);
150 if let Some(pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { 125
151 if let Some(name) = pat.name() { 126 if let Some(Pat((_, ptr))) = &name_kind {
152 let text = name.text(); 127 let pat = ptr.to_node(&root);
153 let shadow_count = 128 if let Some(name) = pat.name() {
154 bindings_shadow_count.entry(text.clone()).or_default(); 129 let text = name.text();
155 *shadow_count += 1; 130 let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
156 binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count)) 131 *shadow_count += 1;
157 } 132 binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
158
159 if is_variable_mutable(db, &analyzer, pat) {
160 "variable.mut"
161 } else {
162 "variable"
163 }
164 } else {
165 name.syntax()
166 .parent()
167 .map(|x| match x.kind() {
168 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => {
169 "type"
170 }
171 RECORD_FIELD_DEF => "field",
172 _ => "function",
173 })
174 .unwrap_or("function")
175 } 133 }
176 } else { 134 };
177 "text" 135
136 match name_kind {
137 Some(name_kind) => highlight_name(db, file_id, name.syntax(), &root, name_kind),
138 None => name.syntax().parent().map_or("function", |x| match x.kind() {
139 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type",
140 RECORD_FIELD_DEF => "field",
141 _ => "function",
142 }),
178 } 143 }
179 } 144 }
180 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", 145 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal",
@@ -272,6 +237,42 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
272 buf 237 buf
273} 238}
274 239
240fn highlight_name(
241 db: &RootDatabase,
242 file_id: FileId,
243 node: &SyntaxNode,
244 root: &SyntaxNode,
245 name_kind: NameKind,
246) -> &'static str {
247 match name_kind {
248 Macro(_) => "macro",
249 Field(_) => "field",
250 AssocItem(hir::AssocItem::Function(_)) => "function",
251 AssocItem(hir::AssocItem::Const(_)) => "constant",
252 AssocItem(hir::AssocItem::TypeAlias(_)) => "type",
253 Def(hir::ModuleDef::Module(_)) => "module",
254 Def(hir::ModuleDef::Function(_)) => "function",
255 Def(hir::ModuleDef::Adt(_)) => "type",
256 Def(hir::ModuleDef::EnumVariant(_)) => "constant",
257 Def(hir::ModuleDef::Const(_)) => "constant",
258 Def(hir::ModuleDef::Static(_)) => "constant",
259 Def(hir::ModuleDef::Trait(_)) => "type",
260 Def(hir::ModuleDef::TypeAlias(_)) => "type",
261 Def(hir::ModuleDef::BuiltinType(_)) => "type",
262 SelfType(_) => "type",
263 SelfParam(_) => "type",
264 GenericParam(_) => "type",
265 Pat((_, ptr)) => {
266 let analyzer = hir::SourceAnalyzer::new(db, file_id, node, None);
267 if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) {
268 "variable.mut"
269 } else {
270 "variable"
271 }
272 }
273 }
274}
275
275//FIXME: like, real html escaping 276//FIXME: like, real html escaping
276fn html_escape(text: &str) -> String { 277fn html_escape(text: &str) -> String {
277 text.replace("<", "&lt;").replace(">", "&gt;") 278 text.replace("<", "&lt;").replace(">", "&gt;")
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 8b8663a78..0e14f1b70 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -199,6 +199,7 @@ impl ProjectWorkspace {
199 } 199 }
200 } 200 }
201 201
202 let libcore = sysroot.core().and_then(|it| sysroot_crates.get(&it).copied());
202 let libstd = sysroot.std().and_then(|it| sysroot_crates.get(&it).copied()); 203 let libstd = sysroot.std().and_then(|it| sysroot_crates.get(&it).copied());
203 204
204 let mut pkg_to_lib_crate = FxHashMap::default(); 205 let mut pkg_to_lib_crate = FxHashMap::default();
@@ -226,7 +227,7 @@ impl ProjectWorkspace {
226 } 227 }
227 } 228 }
228 229
229 // Set deps to the std and to the lib target of the current package 230 // Set deps to the core, std and to the lib target of the current package
230 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 231 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
231 if let Some(to) = lib_tgt { 232 if let Some(to) = lib_tgt {
232 if to != from { 233 if to != from {
@@ -240,6 +241,13 @@ impl ProjectWorkspace {
240 } 241 }
241 } 242 }
242 } 243 }
244 // core is added as a dependency before std in order to
245 // mimic rustcs dependency order
246 if let Some(core) = libcore {
247 if let Err(_) = crate_graph.add_dep(from, "core".into(), core) {
248 log::error!("cyclic dependency on core for {}", pkg.name(&cargo))
249 }
250 }
243 if let Some(std) = libstd { 251 if let Some(std) = libstd {
244 if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { 252 if let Err(_) = crate_graph.add_dep(from, "std".into(), std) {
245 log::error!("cyclic dependency on std for {}", pkg.name(&cargo)) 253 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 35d6df5cb..3d827809e 100644
--- a/crates/ra_project_model/src/sysroot.rs
+++ b/crates/ra_project_model/src/sysroot.rs
@@ -27,6 +27,10 @@ struct SysrootCrateData {
27} 27}
28 28
29impl Sysroot { 29impl Sysroot {
30 pub fn core(&self) -> Option<SysrootCrate> {
31 self.by_name("core")
32 }
33
30 pub fn std(&self) -> Option<SysrootCrate> { 34 pub fn std(&self) -> Option<SysrootCrate> {
31 self.by_name("std") 35 self.by_name("std")
32 } 36 }
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs
index d6eca2ad7..1f60a7aab 100644
--- a/crates/ra_syntax/src/syntax_error.rs
+++ b/crates/ra_syntax/src/syntax_error.rs
@@ -82,6 +82,7 @@ pub enum SyntaxErrorKind {
82 InvalidBlockAttr, 82 InvalidBlockAttr,
83 InvalidMatchInnerAttr, 83 InvalidMatchInnerAttr,
84 InvalidTupleIndexFormat, 84 InvalidTupleIndexFormat,
85 VisibilityNotAllowed,
85} 86}
86 87
87impl fmt::Display for SyntaxErrorKind { 88impl fmt::Display for SyntaxErrorKind {
@@ -99,6 +100,9 @@ impl fmt::Display for SyntaxErrorKind {
99 } 100 }
100 ParseError(msg) => write!(f, "{}", msg.0), 101 ParseError(msg) => write!(f, "{}", msg.0),
101 EscapeError(err) => write!(f, "{}", err), 102 EscapeError(err) => write!(f, "{}", err),
103 VisibilityNotAllowed => {
104 write!(f, "unnecessary visibility qualifier")
105 }
102 } 106 }
103 } 107 }
104} 108}
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index ab4f15908..2d596763e 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -6,7 +6,7 @@ use rustc_lexer::unescape;
6 6
7use crate::{ 7use crate::{
8 ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind, 8 ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind,
9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING}, 9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF},
10 SyntaxNode, SyntaxToken, TextUnit, T, 10 SyntaxNode, SyntaxToken, TextUnit, T,
11}; 11};
12 12
@@ -102,6 +102,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
102 ast::BlockExpr(it) => { block::validate_block_expr(it, &mut errors) }, 102 ast::BlockExpr(it) => { block::validate_block_expr(it, &mut errors) },
103 ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, 103 ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) },
104 ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, 104 ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) },
105 ast::Visibility(it) => { validate_visibility(it, &mut errors) },
105 _ => (), 106 _ => (),
106 } 107 }
107 } 108 }
@@ -206,3 +207,23 @@ fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<Syntax
206 name_ref?.syntax().first_child_or_token()?.into_token().filter(|it| it.kind() == INT_NUMBER) 207 name_ref?.syntax().first_child_or_token()?.into_token().filter(|it| it.kind() == INT_NUMBER)
207 } 208 }
208} 209}
210
211fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
212 let parent = match vis.syntax().parent() {
213 Some(it) => it,
214 None => return,
215 };
216 match parent.kind() {
217 FN_DEF | CONST_DEF | TYPE_ALIAS_DEF => (),
218 _ => return,
219 }
220 let impl_block = match parent.parent().and_then(|it| it.parent()).and_then(ast::ImplBlock::cast)
221 {
222 Some(it) => it,
223 None => return,
224 };
225 if impl_block.target_trait().is_some() {
226 errors
227 .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range()))
228 }
229}
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
new file mode 100644
index 000000000..a43e7ef10
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs
@@ -0,0 +1,6 @@
1impl T for () {
2 fn foo() {}
3 pub fn bar() {}
4 pub(crate) type Baz = ();
5 pub(crate) const C: i32 = 92;
6}
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
new file mode 100644
index 000000000..749c8cddb
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt
@@ -0,0 +1,99 @@
1SOURCE_FILE@[0; 118)
2 IMPL_BLOCK@[0; 117)
3 IMPL_KW@[0; 4) "impl"
4 WHITESPACE@[4; 5) " "
5 PATH_TYPE@[5; 6)
6 PATH@[5; 6)
7 PATH_SEGMENT@[5; 6)
8 NAME_REF@[5; 6)
9 IDENT@[5; 6) "T"
10 WHITESPACE@[6; 7) " "
11 FOR_KW@[7; 10) "for"
12 WHITESPACE@[10; 11) " "
13 TUPLE_TYPE@[11; 13)
14 L_PAREN@[11; 12) "("
15 R_PAREN@[12; 13) ")"
16 WHITESPACE@[13; 14) " "
17 ITEM_LIST@[14; 117)
18 L_CURLY@[14; 15) "{"
19 WHITESPACE@[15; 20) "\n "
20 FN_DEF@[20; 31)
21 FN_KW@[20; 22) "fn"
22 WHITESPACE@[22; 23) " "
23 NAME@[23; 26)
24 IDENT@[23; 26) "foo"
25 PARAM_LIST@[26; 28)
26 L_PAREN@[26; 27) "("
27 R_PAREN@[27; 28) ")"
28 WHITESPACE@[28; 29) " "
29 BLOCK_EXPR@[29; 31)
30 BLOCK@[29; 31)
31 L_CURLY@[29; 30) "{"
32 R_CURLY@[30; 31) "}"
33 WHITESPACE@[31; 36) "\n "
34 FN_DEF@[36; 51)
35 VISIBILITY@[36; 39)
36 PUB_KW@[36; 39) "pub"
37 WHITESPACE@[39; 40) " "
38 FN_KW@[40; 42) "fn"
39 WHITESPACE@[42; 43) " "
40 NAME@[43; 46)
41 IDENT@[43; 46) "bar"
42 PARAM_LIST@[46; 48)
43 L_PAREN@[46; 47) "("
44 R_PAREN@[47; 48) ")"
45 WHITESPACE@[48; 49) " "
46 BLOCK_EXPR@[49; 51)
47 BLOCK@[49; 51)
48 L_CURLY@[49; 50) "{"
49 R_CURLY@[50; 51) "}"
50 WHITESPACE@[51; 56) "\n "
51 TYPE_ALIAS_DEF@[56; 81)
52 VISIBILITY@[56; 66)
53 PUB_KW@[56; 59) "pub"
54 L_PAREN@[59; 60) "("
55 CRATE_KW@[60; 65) "crate"
56 R_PAREN@[65; 66) ")"
57 WHITESPACE@[66; 67) " "
58 TYPE_KW@[67; 71) "type"
59 WHITESPACE@[71; 72) " "
60 NAME@[72; 75)
61 IDENT@[72; 75) "Baz"
62 WHITESPACE@[75; 76) " "
63 EQ@[76; 77) "="
64 WHITESPACE@[77; 78) " "
65 TUPLE_TYPE@[78; 80)
66 L_PAREN@[78; 79) "("
67 R_PAREN@[79; 80) ")"
68 SEMI@[80; 81) ";"
69 WHITESPACE@[81; 86) "\n "
70 CONST_DEF@[86; 115)
71 VISIBILITY@[86; 96)
72 PUB_KW@[86; 89) "pub"
73 L_PAREN@[89; 90) "("
74 CRATE_KW@[90; 95) "crate"
75 R_PAREN@[95; 96) ")"
76 WHITESPACE@[96; 97) " "
77 CONST_KW@[97; 102) "const"
78 WHITESPACE@[102; 103) " "
79 NAME@[103; 104)
80 IDENT@[103; 104) "C"
81 COLON@[104; 105) ":"
82 WHITESPACE@[105; 106) " "
83 PATH_TYPE@[106; 109)
84 PATH@[106; 109)
85 PATH_SEGMENT@[106; 109)
86 NAME_REF@[106; 109)
87 IDENT@[106; 109) "i32"
88 WHITESPACE@[109; 110) " "
89 EQ@[110; 111) "="
90 WHITESPACE@[111; 112) " "
91 LITERAL@[112; 114)
92 INT_NUMBER@[112; 114) "92"
93 SEMI@[114; 115) ";"
94 WHITESPACE@[115; 116) "\n"
95 R_CURLY@[116; 117) "}"
96 WHITESPACE@[117; 118) "\n"
97error [36; 39): unnecessary visibility qualifier
98error [56; 66): unnecessary visibility qualifier
99error [86; 96): unnecessary visibility qualifier