aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/adt.rs108
-rw-r--r--crates/ra_hir/src/code_model_api.rs83
-rw-r--r--crates/ra_hir/src/code_model_impl/function.rs23
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs28
-rw-r--r--crates/ra_hir/src/db.rs7
-rw-r--r--crates/ra_hir/src/expr.rs2
-rw-r--r--crates/ra_hir/src/ids.rs21
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/mock.rs1
-rw-r--r--crates/ra_hir/src/ty.rs20
-rw-r--r--crates/ra_hir/src/ty/tests.rs16
-rw-r--r--crates/ra_hir/src/ty/tests/data/enum.txt4
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs23
-rw-r--r--crates/ra_ide_api/src/db.rs1
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs43
-rw-r--r--crates/ra_ide_api/src/lib.rs64
16 files changed, 384 insertions, 62 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index d30390f25..bcb705c24 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -1,10 +1,15 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_db::Cancelable; 3use ra_db::Cancelable;
4use ra_syntax::ast::{self, NameOwner, StructFlavor, AstNode}; 4use ra_syntax::{
5 SyntaxNode,
6 ast::{self, NameOwner, StructFlavor, AstNode}
7};
5 8
6use crate::{ 9use crate::{
7 DefId, Name, AsName, Struct, Enum, HirDatabase, DefKind, 10 DefId, DefLoc, Name, AsName, Struct, Enum, EnumVariant,
11 HirDatabase, DefKind,
12 SourceItemId,
8 type_ref::TypeRef, 13 type_ref::TypeRef,
9}; 14};
10 15
@@ -45,33 +50,37 @@ impl StructData {
45 } 50 }
46} 51}
47 52
48impl Enum { 53fn get_def_id(
49 pub(crate) fn new(def_id: DefId) -> Self { 54 db: &impl HirDatabase,
50 Enum { def_id } 55 same_file_loc: &DefLoc,
51 } 56 node: &SyntaxNode,
57 expected_kind: DefKind,
58) -> DefId {
59 let file_id = same_file_loc.source_item_id.file_id;
60 let file_items = db.file_items(file_id);
61
62 let item_id = file_items.id_of(file_id, node);
63 let source_item_id = SourceItemId {
64 item_id: Some(item_id),
65 ..same_file_loc.source_item_id
66 };
67 let loc = DefLoc {
68 kind: expected_kind,
69 source_item_id: source_item_id,
70 ..*same_file_loc
71 };
72 loc.id(db)
52} 73}
53 74
54#[derive(Debug, Clone, PartialEq, Eq)] 75#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct EnumData { 76pub struct EnumData {
56 pub(crate) name: Option<Name>, 77 pub(crate) name: Option<Name>,
57 pub(crate) variants: Vec<(Name, Arc<VariantData>)>, 78 pub(crate) variants: Vec<(Name, EnumVariant)>,
58} 79}
59 80
60impl EnumData { 81impl EnumData {
61 fn new(enum_def: &ast::EnumDef) -> Self { 82 fn new(enum_def: &ast::EnumDef, variants: Vec<(Name, EnumVariant)>) -> Self {
62 let name = enum_def.name().map(|n| n.as_name()); 83 let name = enum_def.name().map(|n| n.as_name());
63 let variants = if let Some(evl) = enum_def.variant_list() {
64 evl.variants()
65 .map(|v| {
66 (
67 v.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
68 Arc::new(VariantData::new(v.flavor())),
69 )
70 })
71 .collect()
72 } else {
73 Vec::new()
74 };
75 EnumData { name, variants } 84 EnumData { name, variants }
76 } 85 }
77 86
@@ -83,7 +92,64 @@ impl EnumData {
83 assert!(def_loc.kind == DefKind::Enum); 92 assert!(def_loc.kind == DefKind::Enum);
84 let syntax = db.file_item(def_loc.source_item_id); 93 let syntax = db.file_item(def_loc.source_item_id);
85 let enum_def = ast::EnumDef::cast(&syntax).expect("enum def should point to EnumDef node"); 94 let enum_def = ast::EnumDef::cast(&syntax).expect("enum def should point to EnumDef node");
86 Ok(Arc::new(EnumData::new(enum_def))) 95 let variants = if let Some(vl) = enum_def.variant_list() {
96 vl.variants()
97 .filter_map(|variant_def| {
98 let name = variant_def.name().map(|n| n.as_name());
99
100 name.map(|n| {
101 let def_id =
102 get_def_id(db, &def_loc, variant_def.syntax(), DefKind::EnumVariant);
103 (n, EnumVariant::new(def_id))
104 })
105 })
106 .collect()
107 } else {
108 Vec::new()
109 };
110 Ok(Arc::new(EnumData::new(enum_def, variants)))
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct EnumVariantData {
116 pub(crate) name: Option<Name>,
117 pub(crate) variant_data: Arc<VariantData>,
118 pub(crate) parent_enum: Enum,
119}
120
121impl EnumVariantData {
122 fn new(variant_def: &ast::EnumVariant, parent_enum: Enum) -> EnumVariantData {
123 let name = variant_def.name().map(|n| n.as_name());
124 let variant_data = VariantData::new(variant_def.flavor());
125 let variant_data = Arc::new(variant_data);
126 EnumVariantData {
127 name,
128 variant_data,
129 parent_enum,
130 }
131 }
132
133 pub(crate) fn enum_variant_data_query(
134 db: &impl HirDatabase,
135 def_id: DefId,
136 ) -> Cancelable<Arc<EnumVariantData>> {
137 let def_loc = def_id.loc(db);
138 assert!(def_loc.kind == DefKind::EnumVariant);
139 let syntax = db.file_item(def_loc.source_item_id);
140 let variant_def = ast::EnumVariant::cast(&syntax)
141 .expect("enum variant def should point to EnumVariant node");
142 let enum_node = syntax
143 .parent()
144 .expect("enum variant should have enum variant list ancestor")
145 .parent()
146 .expect("enum variant list should have enum ancestor");
147 let enum_def_id = get_def_id(db, &def_loc, enum_node, DefKind::Enum);
148
149 Ok(Arc::new(EnumVariantData::new(
150 variant_def,
151 Enum::new(enum_def_id),
152 )))
87 } 153 }
88} 154}
89 155
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index fa3e4baa7..e69f546ff 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -2,10 +2,10 @@ use std::sync::Arc;
2 2
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use ra_db::{CrateId, Cancelable, FileId}; 4use ra_db::{CrateId, Cancelable, FileId};
5use ra_syntax::{ast, TreePtr, SyntaxNode}; 5use ra_syntax::{ast, TreePtr, SyntaxNode, AstNode};
6 6
7use crate::{ 7use crate::{
8 Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty, 8 Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId,
9 type_ref::TypeRef, 9 type_ref::TypeRef,
10 nameres::ModuleScope, 10 nameres::ModuleScope,
11 db::HirDatabase, 11 db::HirDatabase,
@@ -44,6 +44,7 @@ pub enum Def {
44 Module(Module), 44 Module(Module),
45 Struct(Struct), 45 Struct(Struct),
46 Enum(Enum), 46 Enum(Enum),
47 EnumVariant(EnumVariant),
47 Function(Function), 48 Function(Function),
48 Item, 49 Item,
49} 50}
@@ -180,6 +181,19 @@ impl Struct {
180 .collect(); 181 .collect();
181 Ok(res) 182 Ok(res)
182 } 183 }
184
185 pub fn source(
186 &self,
187 db: &impl HirDatabase,
188 ) -> Cancelable<(HirFileId, TreePtr<ast::StructDef>)> {
189 let (file_id, syntax) = self.def_id.source(db);
190 Ok((
191 file_id,
192 ast::StructDef::cast(&syntax)
193 .expect("struct def should point to StructDef node")
194 .to_owned(),
195 ))
196 }
183} 197}
184 198
185#[derive(Debug, Clone, PartialEq, Eq, Hash)] 199#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -188,6 +202,10 @@ pub struct Enum {
188} 202}
189 203
190impl Enum { 204impl Enum {
205 pub(crate) fn new(def_id: DefId) -> Self {
206 Enum { def_id }
207 }
208
191 pub fn def_id(&self) -> DefId { 209 pub fn def_id(&self) -> DefId {
192 self.def_id 210 self.def_id
193 } 211 }
@@ -196,9 +214,59 @@ impl Enum {
196 Ok(db.enum_data(self.def_id)?.name.clone()) 214 Ok(db.enum_data(self.def_id)?.name.clone())
197 } 215 }
198 216
199 pub fn variants(&self, db: &impl HirDatabase) -> Cancelable<Vec<(Name, Arc<VariantData>)>> { 217 pub fn variants(&self, db: &impl HirDatabase) -> Cancelable<Vec<(Name, EnumVariant)>> {
200 Ok(db.enum_data(self.def_id)?.variants.clone()) 218 Ok(db.enum_data(self.def_id)?.variants.clone())
201 } 219 }
220
221 pub fn source(&self, db: &impl HirDatabase) -> Cancelable<(HirFileId, TreePtr<ast::EnumDef>)> {
222 let (file_id, syntax) = self.def_id.source(db);
223 Ok((
224 file_id,
225 ast::EnumDef::cast(&syntax)
226 .expect("enum def should point to EnumDef node")
227 .to_owned(),
228 ))
229 }
230}
231
232#[derive(Debug, Clone, PartialEq, Eq, Hash)]
233pub struct EnumVariant {
234 pub(crate) def_id: DefId,
235}
236
237impl EnumVariant {
238 pub(crate) fn new(def_id: DefId) -> Self {
239 EnumVariant { def_id }
240 }
241
242 pub fn def_id(&self) -> DefId {
243 self.def_id
244 }
245
246 pub fn parent_enum(&self, db: &impl HirDatabase) -> Cancelable<Enum> {
247 Ok(db.enum_variant_data(self.def_id)?.parent_enum.clone())
248 }
249
250 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
251 Ok(db.enum_variant_data(self.def_id)?.name.clone())
252 }
253
254 pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
255 Ok(db.enum_variant_data(self.def_id)?.variant_data.clone())
256 }
257
258 pub fn source(
259 &self,
260 db: &impl HirDatabase,
261 ) -> Cancelable<(HirFileId, TreePtr<ast::EnumVariant>)> {
262 let (file_id, syntax) = self.def_id.source(db);
263 Ok((
264 file_id,
265 ast::EnumVariant::cast(&syntax)
266 .expect("variant def should point to EnumVariant node")
267 .to_owned(),
268 ))
269 }
202} 270}
203 271
204#[derive(Debug, Clone, PartialEq, Eq, Hash)] 272#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -209,11 +277,16 @@ pub struct Function {
209/// The declared signature of a function. 277/// The declared signature of a function.
210#[derive(Debug, Clone, PartialEq, Eq)] 278#[derive(Debug, Clone, PartialEq, Eq)]
211pub struct FnSignature { 279pub struct FnSignature {
280 pub(crate) name: Name,
212 pub(crate) args: Vec<TypeRef>, 281 pub(crate) args: Vec<TypeRef>,
213 pub(crate) ret_type: TypeRef, 282 pub(crate) ret_type: TypeRef,
214} 283}
215 284
216impl FnSignature { 285impl FnSignature {
286 pub fn name(&self) -> &Name {
287 &self.name
288 }
289
217 pub fn args(&self) -> &[TypeRef] { 290 pub fn args(&self) -> &[TypeRef] {
218 &self.args 291 &self.args
219 } 292 }
@@ -228,8 +301,8 @@ impl Function {
228 self.def_id 301 self.def_id
229 } 302 }
230 303
231 pub fn source(&self, db: &impl HirDatabase) -> TreePtr<ast::FnDef> { 304 pub fn source(&self, db: &impl HirDatabase) -> Cancelable<(HirFileId, TreePtr<ast::FnDef>)> {
232 self.source_impl(db) 305 Ok(self.source_impl(db))
233 } 306 }
234 307
235 pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Cancelable<Arc<BodySyntaxMapping>> { 308 pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Cancelable<Arc<BodySyntaxMapping>> {
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs
index 13c57ed21..1bd4cc802 100644
--- a/crates/ra_hir/src/code_model_impl/function.rs
+++ b/crates/ra_hir/src/code_model_impl/function.rs
@@ -5,11 +5,11 @@ use std::sync::Arc;
5use ra_db::Cancelable; 5use ra_db::Cancelable;
6use ra_syntax::{ 6use ra_syntax::{
7 TreePtr, 7 TreePtr,
8 ast::{self, AstNode}, 8 ast::{self, AstNode, NameOwner},
9}; 9};
10 10
11use crate::{ 11use crate::{
12 DefId, DefKind, HirDatabase, Name, Function, FnSignature, Module, 12 DefId, DefKind, HirDatabase, Name, AsName, Function, FnSignature, Module, HirFileId,
13 type_ref::{TypeRef, Mutability}, 13 type_ref::{TypeRef, Mutability},
14 expr::Body, 14 expr::Body,
15 impl_block::ImplBlock, 15 impl_block::ImplBlock,
@@ -22,11 +22,14 @@ impl Function {
22 Function { def_id } 22 Function { def_id }
23 } 23 }
24 24
25 pub(crate) fn source_impl(&self, db: &impl HirDatabase) -> TreePtr<ast::FnDef> { 25 pub(crate) fn source_impl(&self, db: &impl HirDatabase) -> (HirFileId, TreePtr<ast::FnDef>) {
26 let def_loc = self.def_id.loc(db); 26 let def_loc = self.def_id.loc(db);
27 assert!(def_loc.kind == DefKind::Function); 27 assert!(def_loc.kind == DefKind::Function);
28 let syntax = db.file_item(def_loc.source_item_id); 28 let syntax = db.file_item(def_loc.source_item_id);
29 ast::FnDef::cast(&syntax).unwrap().to_owned() 29 (
30 def_loc.source_item_id.file_id,
31 ast::FnDef::cast(&syntax).unwrap().to_owned(),
32 )
30 } 33 }
31 34
32 pub(crate) fn body(&self, db: &impl HirDatabase) -> Cancelable<Arc<Body>> { 35 pub(crate) fn body(&self, db: &impl HirDatabase) -> Cancelable<Arc<Body>> {
@@ -46,7 +49,11 @@ impl Function {
46impl FnSignature { 49impl FnSignature {
47 pub(crate) fn fn_signature_query(db: &impl HirDatabase, def_id: DefId) -> Arc<FnSignature> { 50 pub(crate) fn fn_signature_query(db: &impl HirDatabase, def_id: DefId) -> Arc<FnSignature> {
48 let func = Function::new(def_id); 51 let func = Function::new(def_id);
49 let node = func.source(db); 52 let node = func.source_impl(db).1; // TODO we're using source_impl here to avoid returning Cancelable... this is a bit hacky
53 let name = node
54 .name()
55 .map(|n| n.as_name())
56 .unwrap_or_else(Name::missing);
50 let mut args = Vec::new(); 57 let mut args = Vec::new();
51 if let Some(param_list) = node.param_list() { 58 if let Some(param_list) = node.param_list() {
52 if let Some(self_param) = param_list.self_param() { 59 if let Some(self_param) = param_list.self_param() {
@@ -76,7 +83,11 @@ impl FnSignature {
76 } else { 83 } else {
77 TypeRef::unit() 84 TypeRef::unit()
78 }; 85 };
79 let sig = FnSignature { args, ret_type }; 86 let sig = FnSignature {
87 name,
88 args,
89 ret_type,
90 };
80 Arc::new(sig) 91 Arc::new(sig)
81 } 92 }
82} 93}
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 1cb408cff..878dc37c8 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -13,6 +13,7 @@ impl Module {
13 pub(crate) fn new(def_id: DefId) -> Self { 13 pub(crate) fn new(def_id: DefId) -> Self {
14 crate::code_model_api::Module { def_id } 14 crate::code_model_api::Module { def_id }
15 } 15 }
16
16 pub(crate) fn from_module_id( 17 pub(crate) fn from_module_id(
17 db: &impl HirDatabase, 18 db: &impl HirDatabase,
18 source_root_id: SourceRootId, 19 source_root_id: SourceRootId,
@@ -85,6 +86,7 @@ impl Module {
85 let module_id = loc.module_id.crate_root(&module_tree); 86 let module_id = loc.module_id.crate_root(&module_tree);
86 Module::from_module_id(db, loc.source_root_id, module_id) 87 Module::from_module_id(db, loc.source_root_id, module_id)
87 } 88 }
89
88 /// Finds a child module with the specified name. 90 /// Finds a child module with the specified name.
89 pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { 91 pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
90 let loc = self.def_id.loc(db); 92 let loc = self.def_id.loc(db);
@@ -92,12 +94,14 @@ impl Module {
92 let child_id = ctry!(loc.module_id.child(&module_tree, name)); 94 let child_id = ctry!(loc.module_id.child(&module_tree, name));
93 Module::from_module_id(db, loc.source_root_id, child_id).map(Some) 95 Module::from_module_id(db, loc.source_root_id, child_id).map(Some)
94 } 96 }
97
95 pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> { 98 pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
96 let loc = self.def_id.loc(db); 99 let loc = self.def_id.loc(db);
97 let module_tree = db.module_tree(loc.source_root_id)?; 100 let module_tree = db.module_tree(loc.source_root_id)?;
98 let parent_id = ctry!(loc.module_id.parent(&module_tree)); 101 let parent_id = ctry!(loc.module_id.parent(&module_tree));
99 Module::from_module_id(db, loc.source_root_id, parent_id).map(Some) 102 Module::from_module_id(db, loc.source_root_id, parent_id).map(Some)
100 } 103 }
104
101 /// Returns a `ModuleScope`: a set of items, visible in this module. 105 /// Returns a `ModuleScope`: a set of items, visible in this module.
102 pub fn scope_impl(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> { 106 pub fn scope_impl(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
103 let loc = self.def_id.loc(db); 107 let loc = self.def_id.loc(db);
@@ -105,6 +109,7 @@ impl Module {
105 let res = item_map.per_module[&loc.module_id].clone(); 109 let res = item_map.per_module[&loc.module_id].clone();
106 Ok(res) 110 Ok(res)
107 } 111 }
112
108 pub fn resolve_path_impl( 113 pub fn resolve_path_impl(
109 &self, 114 &self,
110 db: &impl HirDatabase, 115 db: &impl HirDatabase,
@@ -126,7 +131,7 @@ impl Module {
126 ); 131 );
127 132
128 let segments = &path.segments; 133 let segments = &path.segments;
129 for name in segments.iter() { 134 for (idx, name) in segments.iter().enumerate() {
130 let curr = if let Some(r) = curr_per_ns.as_ref().take_types() { 135 let curr = if let Some(r) = curr_per_ns.as_ref().take_types() {
131 r 136 r
132 } else { 137 } else {
@@ -134,7 +139,25 @@ impl Module {
134 }; 139 };
135 let module = match curr.resolve(db)? { 140 let module = match curr.resolve(db)? {
136 Def::Module(it) => it, 141 Def::Module(it) => it,
137 // TODO here would be the place to handle enum variants... 142 Def::Enum(e) => {
143 if segments.len() == idx + 1 {
144 // enum variant
145 let matching_variant =
146 e.variants(db)?.into_iter().find(|(n, _variant)| n == name);
147
148 if let Some((_n, variant)) = matching_variant {
149 return Ok(PerNs::both(variant.def_id(), e.def_id()));
150 } else {
151 return Ok(PerNs::none());
152 }
153 } else if segments.len() == idx {
154 // enum
155 return Ok(PerNs::types(e.def_id()));
156 } else {
157 // malformed enum?
158 return Ok(PerNs::none());
159 }
160 }
138 _ => return Ok(PerNs::none()), 161 _ => return Ok(PerNs::none()),
139 }; 162 };
140 let scope = module.scope(db)?; 163 let scope = module.scope(db)?;
@@ -146,6 +169,7 @@ impl Module {
146 } 169 }
147 Ok(curr_per_ns) 170 Ok(curr_per_ns)
148 } 171 }
172
149 pub fn problems_impl( 173 pub fn problems_impl(
150 &self, 174 &self,
151 db: &impl HirDatabase, 175 db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 7dbe93f2b..9a6ef8083 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -12,7 +12,7 @@ use crate::{
12 module_tree::{ModuleId, ModuleTree}, 12 module_tree::{ModuleId, ModuleTree},
13 nameres::{ItemMap, InputModuleItems}, 13 nameres::{ItemMap, InputModuleItems},
14 ty::{InferenceResult, Ty}, 14 ty::{InferenceResult, Ty},
15 adt::{StructData, EnumData}, 15 adt::{StructData, EnumData, EnumVariantData},
16 impl_block::ModuleImplBlocks, 16 impl_block::ModuleImplBlocks,
17}; 17};
18 18
@@ -47,6 +47,11 @@ pub trait HirDatabase: SyntaxDatabase
47 use fn crate::adt::EnumData::enum_data_query; 47 use fn crate::adt::EnumData::enum_data_query;
48 } 48 }
49 49
50 fn enum_variant_data(def_id: DefId) -> Cancelable<Arc<EnumVariantData>> {
51 type EnumVariantDataQuery;
52 use fn crate::adt::EnumVariantData::enum_variant_data_query;
53 }
54
50 fn infer(def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 55 fn infer(def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
51 type InferQuery; 56 type InferQuery;
52 use fn crate::ty::infer; 57 use fn crate::ty::infer;
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index ebb83d084..e5596cbaa 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -762,7 +762,7 @@ pub(crate) fn body_syntax_mapping(
762 let def = def_id.resolve(db)?; 762 let def = def_id.resolve(db)?;
763 763
764 let body_syntax_mapping = match def { 764 let body_syntax_mapping = match def {
765 Def::Function(f) => collect_fn_body_syntax(&f.source(db)), 765 Def::Function(f) => collect_fn_body_syntax(&f.source(db)?.1),
766 // TODO: consts, etc. 766 // TODO: consts, etc.
767 _ => panic!("Trying to get body for item type without body"), 767 _ => panic!("Trying to get body for item type without body"),
768 }; 768 };
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 0aa687a08..c75ef4ae7 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -3,7 +3,7 @@ use ra_syntax::{TreePtr, SyntaxKind, SyntaxNode, SourceFile, AstNode, ast};
3use ra_arena::{Arena, RawId, impl_arena_id}; 3use ra_arena::{Arena, RawId, impl_arena_id};
4 4
5use crate::{ 5use crate::{
6 HirDatabase, PerNs, Def, Function, Struct, Enum, ImplBlock, Crate, 6 HirDatabase, PerNs, Def, Function, Struct, Enum, EnumVariant, ImplBlock, Crate,
7 module_tree::ModuleId, 7 module_tree::ModuleId,
8}; 8};
9 9
@@ -34,7 +34,7 @@ pub struct HirFileId(HirFileIdRepr);
34impl HirFileId { 34impl HirFileId {
35 /// For macro-expansion files, returns the file original source file the 35 /// For macro-expansion files, returns the file original source file the
36 /// expansionoriginated from. 36 /// expansionoriginated from.
37 pub(crate) fn original_file(self, db: &impl HirDatabase) -> FileId { 37 pub fn original_file(self, db: &impl HirDatabase) -> FileId {
38 match self.0 { 38 match self.0 {
39 HirFileIdRepr::File(file_id) => file_id, 39 HirFileIdRepr::File(file_id) => file_id,
40 HirFileIdRepr::Macro(macro_call_id) => { 40 HirFileIdRepr::Macro(macro_call_id) => {
@@ -145,6 +145,7 @@ pub(crate) enum DefKind {
145 Function, 145 Function,
146 Struct, 146 Struct,
147 Enum, 147 Enum,
148 EnumVariant,
148 Item, 149 Item,
149 150
150 StructCtor, 151 StructCtor,
@@ -170,16 +171,20 @@ impl DefId {
170 let struct_def = Struct::new(self); 171 let struct_def = Struct::new(self);
171 Def::Struct(struct_def) 172 Def::Struct(struct_def)
172 } 173 }
173 DefKind::Enum => { 174 DefKind::Enum => Def::Enum(Enum::new(self)),
174 let enum_def = Enum::new(self); 175 DefKind::EnumVariant => Def::EnumVariant(EnumVariant::new(self)),
175 Def::Enum(enum_def)
176 }
177 DefKind::StructCtor => Def::Item, 176 DefKind::StructCtor => Def::Item,
178 DefKind::Item => Def::Item, 177 DefKind::Item => Def::Item,
179 }; 178 };
180 Ok(res) 179 Ok(res)
181 } 180 }
182 181
182 pub(crate) fn source(self, db: &impl HirDatabase) -> (HirFileId, TreePtr<SyntaxNode>) {
183 let loc = self.loc(db);
184 let syntax = db.file_item(loc.source_item_id);
185 (loc.source_item_id.file_id, syntax)
186 }
187
183 /// For a module, returns that module; for any other def, returns the containing module. 188 /// For a module, returns that module; for any other def, returns the containing module.
184 pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> { 189 pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> {
185 let loc = self.loc(db); 190 let loc = self.loc(db);
@@ -258,7 +263,9 @@ impl SourceFileItems {
258 // change parent's id. This means that, say, adding a new function to a 263 // change parent's id. This means that, say, adding a new function to a
259 // trait does not chage ids of top-level items, which helps caching. 264 // trait does not chage ids of top-level items, which helps caching.
260 bfs(source_file.syntax(), |it| { 265 bfs(source_file.syntax(), |it| {
261 if let Some(module_item) = ast::ModuleItem::cast(it) { 266 if let Some(enum_variant) = ast::EnumVariant::cast(it) {
267 self.alloc(enum_variant.syntax().to_owned());
268 } else if let Some(module_item) = ast::ModuleItem::cast(it) {
262 self.alloc(module_item.syntax().to_owned()); 269 self.alloc(module_item.syntax().to_owned());
263 } else if let Some(macro_call) = ast::MacroCall::cast(it) { 270 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
264 self.alloc(macro_call.syntax().to_owned()); 271 self.alloc(macro_call.syntax().to_owned());
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index b8246a7d1..1aca2f067 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -58,6 +58,6 @@ pub use self::code_model_api::{
58 Crate, CrateDependency, 58 Crate, CrateDependency,
59 Def, 59 Def,
60 Module, ModuleSource, Problem, 60 Module, ModuleSource, Problem,
61 Struct, Enum, 61 Struct, Enum, EnumVariant,
62 Function, FnSignature, 62 Function, FnSignature,
63}; 63};
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 7a0301648..6f93bb59d 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -233,6 +233,7 @@ salsa::database_storage! {
233 fn type_for_field() for db::TypeForFieldQuery; 233 fn type_for_field() for db::TypeForFieldQuery;
234 fn struct_data() for db::StructDataQuery; 234 fn struct_data() for db::StructDataQuery;
235 fn enum_data() for db::EnumDataQuery; 235 fn enum_data() for db::EnumDataQuery;
236 fn enum_variant_data() for db::EnumVariantDataQuery;
236 fn impls_in_module() for db::ImplsInModuleQuery; 237 fn impls_in_module() for db::ImplsInModuleQuery;
237 fn body_hir() for db::BodyHirQuery; 238 fn body_hir() for db::BodyHirQuery;
238 fn body_syntax_mapping() for db::BodySyntaxMappingQuery; 239 fn body_syntax_mapping() for db::BodySyntaxMappingQuery;
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index eb7764f65..18c41a015 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -30,7 +30,7 @@ use join_to_string::join;
30use ra_db::Cancelable; 30use ra_db::Cancelable;
31 31
32use crate::{ 32use crate::{
33 Def, DefId, Module, Function, Struct, Enum, Path, Name, ImplBlock, 33 Def, DefId, Module, Function, Struct, Enum, EnumVariant, Path, Name, ImplBlock,
34 FnSignature, FnScopes, 34 FnSignature, FnScopes,
35 db::HirDatabase, 35 db::HirDatabase,
36 type_ref::{TypeRef, Mutability}, 36 type_ref::{TypeRef, Mutability},
@@ -453,6 +453,12 @@ pub fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Cancelable<Ty> {
453 }) 453 })
454} 454}
455 455
456pub fn type_for_enum_variant(db: &impl HirDatabase, ev: EnumVariant) -> Cancelable<Ty> {
457 let enum_parent = ev.parent_enum(db)?;
458
459 type_for_enum(db, enum_parent)
460}
461
456pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { 462pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
457 let def = def_id.resolve(db)?; 463 let def = def_id.resolve(db)?;
458 match def { 464 match def {
@@ -463,6 +469,7 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<T
463 Def::Function(f) => type_for_fn(db, f), 469 Def::Function(f) => type_for_fn(db, f),
464 Def::Struct(s) => type_for_struct(db, s), 470 Def::Struct(s) => type_for_struct(db, s),
465 Def::Enum(e) => type_for_enum(db, e), 471 Def::Enum(e) => type_for_enum(db, e),
472 Def::EnumVariant(ev) => type_for_enum_variant(db, ev),
466 Def::Item => { 473 Def::Item => {
467 log::debug!("trying to get type for item of unknown type {:?}", def_id); 474 log::debug!("trying to get type for item of unknown type {:?}", def_id);
468 Ok(Ty::Unknown) 475 Ok(Ty::Unknown)
@@ -477,12 +484,9 @@ pub(super) fn type_for_field(
477) -> Cancelable<Option<Ty>> { 484) -> Cancelable<Option<Ty>> {
478 let def = def_id.resolve(db)?; 485 let def = def_id.resolve(db)?;
479 let variant_data = match def { 486 let variant_data = match def {
480 Def::Struct(s) => { 487 Def::Struct(s) => s.variant_data(db)?,
481 let variant_data = s.variant_data(db)?; 488 Def::EnumVariant(ev) => ev.variant_data(db)?,
482 variant_data
483 }
484 // TODO: unions 489 // TODO: unions
485 // TODO: enum variants
486 _ => panic!( 490 _ => panic!(
487 "trying to get type for field in non-struct/variant {:?}", 491 "trying to get type for field in non-struct/variant {:?}",
488 def_id 492 def_id
@@ -788,6 +792,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
788 let ty = type_for_struct(self.db, s)?; 792 let ty = type_for_struct(self.db, s)?;
789 (ty, Some(def_id)) 793 (ty, Some(def_id))
790 } 794 }
795 Def::EnumVariant(ev) => {
796 let ty = type_for_enum_variant(self.db, ev)?;
797 (ty, Some(def_id))
798 }
791 _ => (Ty::Unknown, None), 799 _ => (Ty::Unknown, None),
792 }) 800 })
793 } 801 }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index ba2a44474..d8c0af326 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -95,6 +95,22 @@ fn test() {
95} 95}
96 96
97#[test] 97#[test]
98fn infer_enum() {
99 check_inference(
100 r#"
101enum E {
102 V1 { field: u32 },
103 V2
104}
105fn test() {
106 E::V1 { field: 1 };
107 E::V2;
108}"#,
109 "enum.txt",
110 );
111}
112
113#[test]
98fn infer_refs() { 114fn infer_refs() {
99 check_inference( 115 check_inference(
100 r#" 116 r#"
diff --git a/crates/ra_hir/src/ty/tests/data/enum.txt b/crates/ra_hir/src/ty/tests/data/enum.txt
new file mode 100644
index 000000000..481eb0bc7
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/enum.txt
@@ -0,0 +1,4 @@
1[48; 82) '{ E:...:V2; }': ()
2[52; 70) 'E::V1 ...d: 1 }': E
3[67; 68) '1': u32
4[74; 79) 'E::V2': E
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index 2494d28ed..a25ad3f13 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -15,20 +15,21 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
15 match def_id.resolve(ctx.db)? { 15 match def_id.resolve(ctx.db)? {
16 hir::Def::Module(module) => { 16 hir::Def::Module(module) => {
17 let module_scope = module.scope(ctx.db)?; 17 let module_scope = module.scope(ctx.db)?;
18 module_scope.entries().for_each(|(name, res)| { 18 for (name, res) in module_scope.entries() {
19 CompletionItem::new(CompletionKind::Reference, name.to_string()) 19 CompletionItem::new(CompletionKind::Reference, name.to_string())
20 .from_resolution(ctx, res) 20 .from_resolution(ctx, res)
21 .add_to(acc) 21 .add_to(acc);
22 }); 22 }
23 }
24 hir::Def::Enum(e) => {
25 e.variants(ctx.db)?
26 .into_iter()
27 .for_each(|(variant_name, _variant)| {
28 CompletionItem::new(CompletionKind::Reference, variant_name.to_string())
29 .kind(CompletionItemKind::EnumVariant)
30 .add_to(acc)
31 });
23 } 32 }
24 hir::Def::Enum(e) => e
25 .variants(ctx.db)?
26 .into_iter()
27 .for_each(|(name, _variant)| {
28 CompletionItem::new(CompletionKind::Reference, name.to_string())
29 .kind(CompletionItemKind::EnumVariant)
30 .add_to(acc)
31 }),
32 _ => return Ok(()), 33 _ => return Ok(()),
33 }; 34 };
34 Ok(()) 35 Ok(())
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index a2e06f5db..efdf261be 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -122,6 +122,7 @@ salsa::database_storage! {
122 fn type_for_field() for hir::db::TypeForFieldQuery; 122 fn type_for_field() for hir::db::TypeForFieldQuery;
123 fn struct_data() for hir::db::StructDataQuery; 123 fn struct_data() for hir::db::StructDataQuery;
124 fn enum_data() for hir::db::EnumDataQuery; 124 fn enum_data() for hir::db::EnumDataQuery;
125 fn enum_variant_data() for hir::db::EnumVariantDataQuery;
125 fn impls_in_module() for hir::db::ImplsInModuleQuery; 126 fn impls_in_module() for hir::db::ImplsInModuleQuery;
126 fn body_hir() for hir::db::BodyHirQuery; 127 fn body_hir() for hir::db::BodyHirQuery;
127 fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery; 128 fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery;
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 0d524b6f1..eaddd5083 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -42,6 +42,24 @@ pub(crate) fn reference_definition(
42 return Ok(vec![nav]); 42 return Ok(vec![nav]);
43 }; 43 };
44 } 44 }
45 // Then try module name resolution
46 if let Some(module) =
47 hir::source_binder::module_from_child_node(db, file_id, name_ref.syntax())?
48 {
49 if let Some(path) = name_ref
50 .syntax()
51 .ancestors()
52 .find_map(ast::Path::cast)
53 .and_then(hir::Path::from_ast)
54 {
55 let resolved = module.resolve_path(db, &path)?;
56 if let Some(def_id) = resolved.take_types().or(resolved.take_values()) {
57 if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)?)? {
58 return Ok(vec![target]);
59 }
60 }
61 }
62 }
45 // If that fails try the index based approach. 63 // If that fails try the index based approach.
46 let navs = db 64 let navs = db
47 .index_resolve(name_ref)? 65 .index_resolve(name_ref)?
@@ -105,6 +123,31 @@ mod tests {
105 } 123 }
106 124
107 #[test] 125 #[test]
126 fn goto_definition_resolves_correct_name() {
127 let (analysis, pos) = analysis_and_position(
128 "
129 //- /lib.rs
130 use a::Foo;
131 mod a;
132 mod b;
133 enum E { X(Foo<|>) }
134 //- /a.rs
135 struct Foo;
136 //- /b.rs
137 struct Foo;
138 ",
139 );
140
141 let symbols = analysis.goto_definition(pos).unwrap().unwrap();
142 assert_eq_dbg(
143 r#"[NavigationTarget { file_id: FileId(2), name: "Foo",
144 kind: STRUCT_DEF, range: [0; 11),
145 ptr: Some(LocalSyntaxPtr { range: [0; 11), kind: STRUCT_DEF }) }]"#,
146 &symbols,
147 );
148 }
149
150 #[test]
108 fn goto_definition_works_for_module_declaration() { 151 fn goto_definition_works_for_module_declaration() {
109 let (analysis, pos) = analysis_and_position( 152 let (analysis, pos) = analysis_and_position(
110 " 153 "
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index f505959ce..65d21d899 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -33,7 +33,8 @@ mod syntax_highlighting;
33 33
34use std::{fmt, sync::Arc}; 34use std::{fmt, sync::Arc};
35 35
36use ra_syntax::{SmolStr, SourceFile, TreePtr, SyntaxKind, TextRange, TextUnit}; 36use hir::{Def, ModuleSource, Name};
37use ra_syntax::{SmolStr, SourceFile, TreePtr, SyntaxKind, SyntaxNode, TextRange, TextUnit, AstNode};
37use ra_text_edit::TextEdit; 38use ra_text_edit::TextEdit;
38use ra_db::{SyntaxDatabase, FilesDatabase, LocalSyntaxPtr, BaseDatabase}; 39use ra_db::{SyntaxDatabase, FilesDatabase, LocalSyntaxPtr, BaseDatabase};
39use rayon::prelude::*; 40use rayon::prelude::*;
@@ -268,6 +269,67 @@ impl NavigationTarget {
268 } 269 }
269 } 270 }
270 271
272 fn from_syntax(name: Option<Name>, file_id: FileId, node: &SyntaxNode) -> NavigationTarget {
273 NavigationTarget {
274 file_id,
275 name: name.map(|n| n.to_string().into()).unwrap_or("".into()),
276 kind: node.kind(),
277 range: node.range(),
278 ptr: Some(LocalSyntaxPtr::new(node)),
279 }
280 }
281 // TODO once Def::Item is gone, this should be able to always return a NavigationTarget
282 fn from_def(db: &db::RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> {
283 Ok(match def {
284 Def::Struct(s) => {
285 let (file_id, node) = s.source(db)?;
286 Some(NavigationTarget::from_syntax(
287 s.name(db)?,
288 file_id.original_file(db),
289 node.syntax(),
290 ))
291 }
292 Def::Enum(e) => {
293 let (file_id, node) = e.source(db)?;
294 Some(NavigationTarget::from_syntax(
295 e.name(db)?,
296 file_id.original_file(db),
297 node.syntax(),
298 ))
299 }
300 Def::EnumVariant(ev) => {
301 let (file_id, node) = ev.source(db)?;
302 Some(NavigationTarget::from_syntax(
303 ev.name(db)?,
304 file_id.original_file(db),
305 node.syntax(),
306 ))
307 }
308 Def::Function(f) => {
309 let (file_id, node) = f.source(db)?;
310 let name = f.signature(db).name().clone();
311 Some(NavigationTarget::from_syntax(
312 Some(name),
313 file_id.original_file(db),
314 node.syntax(),
315 ))
316 }
317 Def::Module(m) => {
318 let (file_id, source) = m.definition_source(db)?;
319 let name = m.name(db)?;
320 match source {
321 ModuleSource::SourceFile(node) => {
322 Some(NavigationTarget::from_syntax(name, file_id, node.syntax()))
323 }
324 ModuleSource::Module(node) => {
325 Some(NavigationTarget::from_syntax(name, file_id, node.syntax()))
326 }
327 }
328 }
329 Def::Item => None,
330 })
331 }
332
271 pub fn name(&self) -> &SmolStr { 333 pub fn name(&self) -> &SmolStr {
272 &self.name 334 &self.name
273 } 335 }