diff options
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r-- | crates/ra_hir_def/src/body/scope.rs | 219 | ||||
-rw-r--r-- | crates/ra_hir_def/src/db.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir_def/src/imp.rs | 71 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/raw.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/incremental.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | 2 |
9 files changed, 394 insertions, 22 deletions
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index 09a39e721..10cb87d37 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -67,6 +67,11 @@ impl ExprScopes { | |||
67 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) | 67 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) |
68 | } | 68 | } |
69 | 69 | ||
70 | pub fn resolve_name_in_scope(&self, scope: ScopeId, name: &Name) -> Option<&ScopeEntry> { | ||
71 | self.scope_chain(Some(scope)) | ||
72 | .find_map(|scope| self.entries(scope).iter().find(|it| it.name == *name)) | ||
73 | } | ||
74 | |||
70 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | 75 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { |
71 | self.scope_by_expr.get(&expr).copied() | 76 | self.scope_by_expr.get(&expr).copied() |
72 | } | 77 | } |
@@ -163,3 +168,217 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope | |||
163 | e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), | 168 | e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), |
164 | }; | 169 | }; |
165 | } | 170 | } |
171 | |||
172 | #[cfg(test)] | ||
173 | mod tests { | ||
174 | use hir_expand::{name::AsName, Source}; | ||
175 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; | ||
176 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | ||
177 | use test_utils::{assert_eq_text, extract_offset}; | ||
178 | |||
179 | use crate::{db::DefDatabase2, test_db::TestDB, FunctionId, ModuleDefId}; | ||
180 | |||
181 | fn find_function(db: &TestDB, file_id: FileId) -> FunctionId { | ||
182 | let krate = db.test_crate(); | ||
183 | let crate_def_map = db.crate_def_map(krate); | ||
184 | |||
185 | let module = crate_def_map.modules_for_file(file_id).next().unwrap(); | ||
186 | let (_, res) = crate_def_map[module].scope.entries().next().unwrap(); | ||
187 | match res.def.take_values().unwrap() { | ||
188 | ModuleDefId::FunctionId(it) => it, | ||
189 | _ => panic!(), | ||
190 | } | ||
191 | } | ||
192 | |||
193 | fn do_check(code: &str, expected: &[&str]) { | ||
194 | let (off, code) = extract_offset(code); | ||
195 | let code = { | ||
196 | let mut buf = String::new(); | ||
197 | let off = u32::from(off) as usize; | ||
198 | buf.push_str(&code[..off]); | ||
199 | buf.push_str("marker"); | ||
200 | buf.push_str(&code[off..]); | ||
201 | buf | ||
202 | }; | ||
203 | |||
204 | let (db, file_id) = TestDB::with_single_file(&code); | ||
205 | |||
206 | let file_syntax = db.parse(file_id).syntax_node(); | ||
207 | let marker: ast::PathExpr = find_node_at_offset(&file_syntax, off).unwrap(); | ||
208 | let function = find_function(&db, file_id); | ||
209 | |||
210 | let scopes = db.expr_scopes(function.into()); | ||
211 | let (_body, source_map) = db.body_with_source_map(function.into()); | ||
212 | |||
213 | let expr_id = | ||
214 | source_map.node_expr(Source { file_id: file_id.into(), ast: &marker.into() }).unwrap(); | ||
215 | let scope = scopes.scope_for(expr_id); | ||
216 | |||
217 | let actual = scopes | ||
218 | .scope_chain(scope) | ||
219 | .flat_map(|scope| scopes.entries(scope)) | ||
220 | .map(|it| it.name().to_string()) | ||
221 | .collect::<Vec<_>>() | ||
222 | .join("\n"); | ||
223 | let expected = expected.join("\n"); | ||
224 | assert_eq_text!(&expected, &actual); | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn test_lambda_scope() { | ||
229 | do_check( | ||
230 | r" | ||
231 | fn quux(foo: i32) { | ||
232 | let f = |bar, baz: i32| { | ||
233 | <|> | ||
234 | }; | ||
235 | }", | ||
236 | &["bar", "baz", "foo"], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn test_call_scope() { | ||
242 | do_check( | ||
243 | r" | ||
244 | fn quux() { | ||
245 | f(|x| <|> ); | ||
246 | }", | ||
247 | &["x"], | ||
248 | ); | ||
249 | } | ||
250 | |||
251 | #[test] | ||
252 | fn test_method_call_scope() { | ||
253 | do_check( | ||
254 | r" | ||
255 | fn quux() { | ||
256 | z.f(|x| <|> ); | ||
257 | }", | ||
258 | &["x"], | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
263 | fn test_loop_scope() { | ||
264 | do_check( | ||
265 | r" | ||
266 | fn quux() { | ||
267 | loop { | ||
268 | let x = (); | ||
269 | <|> | ||
270 | }; | ||
271 | }", | ||
272 | &["x"], | ||
273 | ); | ||
274 | } | ||
275 | |||
276 | #[test] | ||
277 | fn test_match() { | ||
278 | do_check( | ||
279 | r" | ||
280 | fn quux() { | ||
281 | match () { | ||
282 | Some(x) => { | ||
283 | <|> | ||
284 | } | ||
285 | }; | ||
286 | }", | ||
287 | &["x"], | ||
288 | ); | ||
289 | } | ||
290 | |||
291 | #[test] | ||
292 | fn test_shadow_variable() { | ||
293 | do_check( | ||
294 | r" | ||
295 | fn foo(x: String) { | ||
296 | let x : &str = &x<|>; | ||
297 | }", | ||
298 | &["x"], | ||
299 | ); | ||
300 | } | ||
301 | |||
302 | fn do_check_local_name(code: &str, expected_offset: u32) { | ||
303 | let (off, code) = extract_offset(code); | ||
304 | |||
305 | let (db, file_id) = TestDB::with_single_file(&code); | ||
306 | |||
307 | let file = db.parse(file_id).ok().unwrap(); | ||
308 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | ||
309 | .expect("failed to find a name at the target offset"); | ||
310 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | ||
311 | |||
312 | let function = find_function(&db, file_id); | ||
313 | |||
314 | let scopes = db.expr_scopes(function.into()); | ||
315 | let (_body, source_map) = db.body_with_source_map(function.into()); | ||
316 | |||
317 | let expr_scope = { | ||
318 | let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); | ||
319 | let expr_id = | ||
320 | source_map.node_expr(Source { file_id: file_id.into(), ast: &expr_ast }).unwrap(); | ||
321 | scopes.scope_for(expr_id).unwrap() | ||
322 | }; | ||
323 | |||
324 | let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap(); | ||
325 | let pat_src = source_map.pat_syntax(resolved.pat()).unwrap(); | ||
326 | |||
327 | let local_name = pat_src.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
328 | assert_eq!(local_name.range(), expected_name.syntax().text_range()); | ||
329 | } | ||
330 | |||
331 | #[test] | ||
332 | fn test_resolve_local_name() { | ||
333 | do_check_local_name( | ||
334 | r#" | ||
335 | fn foo(x: i32, y: u32) { | ||
336 | { | ||
337 | let z = x * 2; | ||
338 | } | ||
339 | { | ||
340 | let t = x<|> * 3; | ||
341 | } | ||
342 | }"#, | ||
343 | 21, | ||
344 | ); | ||
345 | } | ||
346 | |||
347 | #[test] | ||
348 | fn test_resolve_local_name_declaration() { | ||
349 | do_check_local_name( | ||
350 | r#" | ||
351 | fn foo(x: String) { | ||
352 | let x : &str = &x<|>; | ||
353 | }"#, | ||
354 | 21, | ||
355 | ); | ||
356 | } | ||
357 | |||
358 | #[test] | ||
359 | fn test_resolve_local_name_shadow() { | ||
360 | do_check_local_name( | ||
361 | r" | ||
362 | fn foo(x: String) { | ||
363 | let x : &str = &x; | ||
364 | x<|> | ||
365 | } | ||
366 | ", | ||
367 | 53, | ||
368 | ); | ||
369 | } | ||
370 | |||
371 | #[test] | ||
372 | fn ref_patterns_contribute_bindings() { | ||
373 | do_check_local_name( | ||
374 | r" | ||
375 | fn foo() { | ||
376 | if let Some(&from) = bar() { | ||
377 | from<|>; | ||
378 | } | ||
379 | } | ||
380 | ", | ||
381 | 53, | ||
382 | ); | ||
383 | } | ||
384 | } | ||
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 40b5920d9..348aca07f 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -8,30 +8,32 @@ use ra_syntax::ast; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | adt::{EnumData, StructData}, | 9 | adt::{EnumData, StructData}, |
10 | body::{scope::ExprScopes, Body, BodySourceMap}, | 10 | body::{scope::ExprScopes, Body, BodySourceMap}, |
11 | imp::ImplData, | ||
11 | nameres::{ | 12 | nameres::{ |
12 | raw::{ImportSourceMap, RawItems}, | 13 | raw::{ImportSourceMap, RawItems}, |
13 | CrateDefMap, | 14 | CrateDefMap, |
14 | }, | 15 | }, |
15 | DefWithBodyId, EnumId, StructOrUnionId, | 16 | DefWithBodyId, EnumId, ImplId, ItemLoc, StructOrUnionId, |
16 | }; | 17 | }; |
17 | 18 | ||
18 | #[salsa::query_group(InternDatabaseStorage)] | 19 | #[salsa::query_group(InternDatabaseStorage)] |
19 | pub trait InternDatabase: SourceDatabase { | 20 | pub trait InternDatabase: SourceDatabase { |
20 | #[salsa::interned] | 21 | #[salsa::interned] |
21 | fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId; | 22 | fn intern_function(&self, loc: ItemLoc<ast::FnDef>) -> crate::FunctionId; |
22 | #[salsa::interned] | 23 | #[salsa::interned] |
23 | fn intern_struct_or_union(&self, loc: crate::ItemLoc<ast::StructDef>) | 24 | fn intern_struct_or_union(&self, loc: ItemLoc<ast::StructDef>) -> crate::StructOrUnionId; |
24 | -> crate::StructOrUnionId; | ||
25 | #[salsa::interned] | 25 | #[salsa::interned] |
26 | fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId; | 26 | fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> crate::EnumId; |
27 | #[salsa::interned] | 27 | #[salsa::interned] |
28 | fn intern_const(&self, loc: crate::ItemLoc<ast::ConstDef>) -> crate::ConstId; | 28 | fn intern_const(&self, loc: ItemLoc<ast::ConstDef>) -> crate::ConstId; |
29 | #[salsa::interned] | 29 | #[salsa::interned] |
30 | fn intern_static(&self, loc: crate::ItemLoc<ast::StaticDef>) -> crate::StaticId; | 30 | fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> crate::StaticId; |
31 | #[salsa::interned] | 31 | #[salsa::interned] |
32 | fn intern_trait(&self, loc: crate::ItemLoc<ast::TraitDef>) -> crate::TraitId; | 32 | fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> crate::TraitId; |
33 | #[salsa::interned] | 33 | #[salsa::interned] |
34 | fn intern_type_alias(&self, loc: crate::ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; | 34 | fn intern_type_alias(&self, loc: ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; |
35 | #[salsa::interned] | ||
36 | fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> crate::ImplId; | ||
35 | } | 37 | } |
36 | 38 | ||
37 | #[salsa::query_group(DefDatabase2Storage)] | 39 | #[salsa::query_group(DefDatabase2Storage)] |
@@ -54,6 +56,9 @@ pub trait DefDatabase2: InternDatabase + AstDatabase { | |||
54 | #[salsa::invoke(EnumData::enum_data_query)] | 56 | #[salsa::invoke(EnumData::enum_data_query)] |
55 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; | 57 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; |
56 | 58 | ||
59 | #[salsa::invoke(ImplData::impl_data_query)] | ||
60 | fn impl_data(&self, e: ImplId) -> Arc<ImplData>; | ||
61 | |||
57 | #[salsa::invoke(Body::body_with_source_map_query)] | 62 | #[salsa::invoke(Body::body_with_source_map_query)] |
58 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); | 63 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); |
59 | 64 | ||
diff --git a/crates/ra_hir_def/src/imp.rs b/crates/ra_hir_def/src/imp.rs new file mode 100644 index 000000000..717991c40 --- /dev/null +++ b/crates/ra_hir_def/src/imp.rs | |||
@@ -0,0 +1,71 @@ | |||
1 | //! Defines hir-level representation of impls. | ||
2 | //! | ||
3 | //! The handling is similar, but is not quite the same as for other items, | ||
4 | //! because `impl`s don't have names. | ||
5 | |||
6 | use std::sync::Arc; | ||
7 | |||
8 | use ra_syntax::ast; | ||
9 | |||
10 | use crate::{ | ||
11 | db::DefDatabase2, type_ref::TypeRef, AssocItemId, AstItemDef, ConstId, FunctionId, ImplId, | ||
12 | LocationCtx, TypeAliasId, | ||
13 | }; | ||
14 | |||
15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
16 | pub struct ImplData { | ||
17 | target_trait: Option<TypeRef>, | ||
18 | target_type: TypeRef, | ||
19 | items: Vec<AssocItemId>, | ||
20 | negative: bool, | ||
21 | } | ||
22 | |||
23 | impl ImplData { | ||
24 | pub(crate) fn impl_data_query(db: &impl DefDatabase2, id: ImplId) -> Arc<ImplData> { | ||
25 | let src = id.source(db); | ||
26 | let items = db.ast_id_map(src.file_id); | ||
27 | |||
28 | let target_trait = src.ast.target_trait().map(TypeRef::from_ast); | ||
29 | let target_type = TypeRef::from_ast_opt(src.ast.target_type()); | ||
30 | let negative = src.ast.is_negative(); | ||
31 | |||
32 | let items = if let Some(item_list) = src.ast.item_list() { | ||
33 | let ctx = LocationCtx::new(db, id.module(db), src.file_id); | ||
34 | item_list | ||
35 | .impl_items() | ||
36 | .map(|item_node| match item_node { | ||
37 | ast::ImplItem::FnDef(it) => { | ||
38 | FunctionId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
39 | } | ||
40 | ast::ImplItem::ConstDef(it) => { | ||
41 | ConstId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
42 | } | ||
43 | ast::ImplItem::TypeAliasDef(it) => { | ||
44 | TypeAliasId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
45 | } | ||
46 | }) | ||
47 | .collect() | ||
48 | } else { | ||
49 | Vec::new() | ||
50 | }; | ||
51 | |||
52 | let res = ImplData { target_trait, target_type, items, negative }; | ||
53 | Arc::new(res) | ||
54 | } | ||
55 | |||
56 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
57 | self.target_trait.as_ref() | ||
58 | } | ||
59 | |||
60 | pub fn target_type(&self) -> &TypeRef { | ||
61 | &self.target_type | ||
62 | } | ||
63 | |||
64 | pub fn items(&self) -> &[AssocItemId] { | ||
65 | &self.items | ||
66 | } | ||
67 | |||
68 | pub fn is_negative(&self) -> bool { | ||
69 | self.negative | ||
70 | } | ||
71 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 3fab7965c..0a59c4ad7 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -13,6 +13,7 @@ pub mod path; | |||
13 | pub mod type_ref; | 13 | pub mod type_ref; |
14 | pub mod builtin_type; | 14 | pub mod builtin_type; |
15 | pub mod adt; | 15 | pub mod adt; |
16 | pub mod imp; | ||
16 | pub mod diagnostics; | 17 | pub mod diagnostics; |
17 | pub mod expr; | 18 | pub mod expr; |
18 | pub mod body; | 19 | pub mod body; |
@@ -321,6 +322,18 @@ impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { | |||
321 | } | 322 | } |
322 | } | 323 | } |
323 | 324 | ||
325 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
326 | pub struct ImplId(salsa::InternId); | ||
327 | impl_intern_key!(ImplId); | ||
328 | impl AstItemDef<ast::ImplBlock> for ImplId { | ||
329 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ImplBlock>) -> Self { | ||
330 | db.intern_impl(loc) | ||
331 | } | ||
332 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ImplBlock> { | ||
333 | db.lookup_intern_impl(self) | ||
334 | } | ||
335 | } | ||
336 | |||
324 | macro_rules! impl_froms { | 337 | macro_rules! impl_froms { |
325 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { | 338 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { |
326 | $( | 339 | $( |
@@ -384,3 +397,15 @@ pub enum DefWithBodyId { | |||
384 | } | 397 | } |
385 | 398 | ||
386 | impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); | 399 | impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); |
400 | |||
401 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
402 | pub enum AssocItemId { | ||
403 | FunctionId(FunctionId), | ||
404 | ConstId(ConstId), | ||
405 | TypeAliasId(TypeAliasId), | ||
406 | } | ||
407 | // FIXME: not every function, ... is actually an assoc item. maybe we should make | ||
408 | // sure that you can only turn actual assoc items into AssocItemIds. This would | ||
409 | // require not implementing From, and instead having some checked way of | ||
410 | // casting them, and somehow making the constructors private, which would be annoying. | ||
411 | impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId); | ||
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index d3ecabb9b..49e33ccc4 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -58,7 +58,7 @@ mod tests; | |||
58 | 58 | ||
59 | use std::sync::Arc; | 59 | use std::sync::Arc; |
60 | 60 | ||
61 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId}; | 61 | use hir_expand::{ast_id_map::FileAstId, diagnostics::DiagnosticSink, name::Name, MacroDefId}; |
62 | use once_cell::sync::Lazy; | 62 | use once_cell::sync::Lazy; |
63 | use ra_arena::Arena; | 63 | use ra_arena::Arena; |
64 | use ra_db::{CrateId, Edition, FileId}; | 64 | use ra_db::{CrateId, Edition, FileId}; |
@@ -73,7 +73,7 @@ use crate::{ | |||
73 | diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId, | 73 | diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId, |
74 | }, | 74 | }, |
75 | path::Path, | 75 | path::Path, |
76 | AstId, CrateModuleId, ModuleDefId, ModuleId, TraitId, | 76 | AstId, CrateModuleId, FunctionId, ImplId, ModuleDefId, ModuleId, TraitId, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /// Contains all top-level defs from a macro-expanded crate | 79 | /// Contains all top-level defs from a macro-expanded crate |
@@ -87,7 +87,7 @@ pub struct CrateDefMap { | |||
87 | prelude: Option<ModuleId>, | 87 | prelude: Option<ModuleId>, |
88 | extern_prelude: FxHashMap<Name, ModuleDefId>, | 88 | extern_prelude: FxHashMap<Name, ModuleDefId>, |
89 | root: CrateModuleId, | 89 | root: CrateModuleId, |
90 | pub modules: Arena<CrateModuleId, ModuleData>, | 90 | modules: Arena<CrateModuleId, ModuleData>, |
91 | 91 | ||
92 | /// Some macros are not well-behavior, which leads to infinite loop | 92 | /// Some macros are not well-behavior, which leads to infinite loop |
93 | /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } | 93 | /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } |
@@ -122,11 +122,17 @@ pub struct ModuleData { | |||
122 | /// | 122 | /// |
123 | /// Note that non-inline modules, by definition, live inside non-macro file. | 123 | /// Note that non-inline modules, by definition, live inside non-macro file. |
124 | pub definition: Option<FileId>, | 124 | pub definition: Option<FileId>, |
125 | pub impls: Vec<ImplId>, | ||
126 | } | ||
127 | |||
128 | #[derive(Default, Debug, PartialEq, Eq, Clone)] | ||
129 | pub(crate) struct Declarations { | ||
130 | fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>, | ||
125 | } | 131 | } |
126 | 132 | ||
127 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 133 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
128 | pub struct ModuleScope { | 134 | pub struct ModuleScope { |
129 | pub items: FxHashMap<Name, Resolution>, | 135 | items: FxHashMap<Name, Resolution>, |
130 | /// Macros visable in current module in legacy textual scope | 136 | /// Macros visable in current module in legacy textual scope |
131 | /// | 137 | /// |
132 | /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. | 138 | /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. |
@@ -258,6 +264,17 @@ impl CrateDefMap { | |||
258 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); | 264 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); |
259 | (res.resolved_def, res.segment_index) | 265 | (res.resolved_def, res.segment_index) |
260 | } | 266 | } |
267 | |||
268 | pub fn modules(&self) -> impl Iterator<Item = CrateModuleId> + '_ { | ||
269 | self.modules.iter().map(|(id, _data)| id) | ||
270 | } | ||
271 | |||
272 | pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = CrateModuleId> + '_ { | ||
273 | self.modules | ||
274 | .iter() | ||
275 | .filter(move |(_id, data)| data.definition == Some(file_id)) | ||
276 | .map(|(id, _data)| id) | ||
277 | } | ||
261 | } | 278 | } |
262 | 279 | ||
263 | mod diagnostics { | 280 | mod diagnostics { |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 37d0f3093..c9ccb9023 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode, | 19 | per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode, |
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, ImplId, |
23 | LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId, | 23 | LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId, |
24 | UnionId, | 24 | UnionId, |
25 | }; | 25 | }; |
@@ -571,6 +571,15 @@ where | |||
571 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), | 571 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), |
572 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), | 572 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), |
573 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 573 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
574 | raw::RawItemKind::Impl(imp) => { | ||
575 | let module = ModuleId { | ||
576 | krate: self.def_collector.def_map.krate, | ||
577 | module_id: self.module_id, | ||
578 | }; | ||
579 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | ||
580 | let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id); | ||
581 | self.def_collector.def_map.modules[self.module_id].impls.push(imp_id) | ||
582 | } | ||
574 | } | 583 | } |
575 | } | 584 | } |
576 | } | 585 | } |
@@ -664,7 +673,8 @@ where | |||
664 | let name = def.name.clone(); | 673 | let name = def.name.clone(); |
665 | let def: PerNs = match def.kind { | 674 | let def: PerNs = match def.kind { |
666 | raw::DefKind::Function(ast_id) => { | 675 | raw::DefKind::Function(ast_id) => { |
667 | PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into()) | 676 | let f = FunctionId::from_ast_id(ctx, ast_id); |
677 | PerNs::values(f.into()) | ||
668 | } | 678 | } |
669 | raw::DefKind::Struct(ast_id) => { | 679 | raw::DefKind::Struct(ast_id) => { |
670 | let id = StructOrUnionId::from_ast_id(ctx, ast_id).into(); | 680 | let id = StructOrUnionId::from_ast_id(ctx, ast_id).into(); |
@@ -798,7 +808,7 @@ mod tests { | |||
798 | 808 | ||
799 | fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap { | 809 | fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap { |
800 | let (db, _file_id) = TestDB::with_single_file(&code); | 810 | let (db, _file_id) = TestDB::with_single_file(&code); |
801 | let krate = db.crate_graph().iter().next().unwrap(); | 811 | let krate = db.test_crate(); |
802 | 812 | ||
803 | let def_map = { | 813 | let def_map = { |
804 | let edition = db.crate_graph().edition(krate); | 814 | let edition = db.crate_graph().edition(krate); |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index f52002bc0..a0a2c7273 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -28,6 +28,7 @@ pub struct RawItems { | |||
28 | imports: Arena<ImportId, ImportData>, | 28 | imports: Arena<ImportId, ImportData>, |
29 | defs: Arena<Def, DefData>, | 29 | defs: Arena<Def, DefData>, |
30 | macros: Arena<Macro, MacroData>, | 30 | macros: Arena<Macro, MacroData>, |
31 | impls: Arena<Impl, ImplData>, | ||
31 | /// items for top-level module | 32 | /// items for top-level module |
32 | items: Vec<RawItem>, | 33 | items: Vec<RawItem>, |
33 | } | 34 | } |
@@ -121,6 +122,13 @@ impl Index<Macro> for RawItems { | |||
121 | } | 122 | } |
122 | } | 123 | } |
123 | 124 | ||
125 | impl Index<Impl> for RawItems { | ||
126 | type Output = ImplData; | ||
127 | fn index(&self, idx: Impl) -> &ImplData { | ||
128 | &self.impls[idx] | ||
129 | } | ||
130 | } | ||
131 | |||
124 | // Avoid heap allocation on items without attributes. | 132 | // Avoid heap allocation on items without attributes. |
125 | type Attrs = Option<Arc<[Attr]>>; | 133 | type Attrs = Option<Arc<[Attr]>>; |
126 | 134 | ||
@@ -142,6 +150,7 @@ pub(super) enum RawItemKind { | |||
142 | Import(ImportId), | 150 | Import(ImportId), |
143 | Def(Def), | 151 | Def(Def), |
144 | Macro(Macro), | 152 | Macro(Macro), |
153 | Impl(Impl), | ||
145 | } | 154 | } |
146 | 155 | ||
147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -203,6 +212,15 @@ pub(super) struct MacroData { | |||
203 | pub(super) builtin: bool, | 212 | pub(super) builtin: bool, |
204 | } | 213 | } |
205 | 214 | ||
215 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
216 | pub(super) struct Impl(RawId); | ||
217 | impl_arena_id!(Impl); | ||
218 | |||
219 | #[derive(Debug, PartialEq, Eq)] | ||
220 | pub(super) struct ImplData { | ||
221 | pub(super) ast_id: FileAstId<ast::ImplBlock>, | ||
222 | } | ||
223 | |||
206 | struct RawItemsCollector { | 224 | struct RawItemsCollector { |
207 | raw_items: RawItems, | 225 | raw_items: RawItems, |
208 | source_ast_id_map: Arc<AstIdMap>, | 226 | source_ast_id_map: Arc<AstIdMap>, |
@@ -236,8 +254,8 @@ impl RawItemsCollector { | |||
236 | self.add_extern_crate_item(current_module, extern_crate); | 254 | self.add_extern_crate_item(current_module, extern_crate); |
237 | return; | 255 | return; |
238 | } | 256 | } |
239 | ast::ModuleItem::ImplBlock(_) => { | 257 | ast::ModuleItem::ImplBlock(it) => { |
240 | // impls don't participate in name resolution | 258 | self.add_impl(current_module, it); |
241 | return; | 259 | return; |
242 | } | 260 | } |
243 | ast::ModuleItem::StructDef(it) => { | 261 | ast::ModuleItem::StructDef(it) => { |
@@ -376,6 +394,13 @@ impl RawItemsCollector { | |||
376 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); | 394 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); |
377 | } | 395 | } |
378 | 396 | ||
397 | fn add_impl(&mut self, current_module: Option<Module>, imp: ast::ImplBlock) { | ||
398 | let attrs = self.parse_attrs(&imp); | ||
399 | let ast_id = self.source_ast_id_map.ast_id(&imp); | ||
400 | let imp = self.raw_items.impls.alloc(ImplData { ast_id }); | ||
401 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) | ||
402 | } | ||
403 | |||
379 | fn push_import( | 404 | fn push_import( |
380 | &mut self, | 405 | &mut self, |
381 | current_module: Option<Module>, | 406 | current_module: Option<Module>, |
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs index 80dcec62f..903a22771 100644 --- a/crates/ra_hir_def/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs | |||
@@ -1,12 +1,12 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | 3 | use ra_db::SourceDatabaseExt; |
4 | 4 | ||
5 | use super::*; | 5 | use super::*; |
6 | 6 | ||
7 | fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { | 7 | fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { |
8 | let (mut db, pos) = TestDB::with_position(initial); | 8 | let (mut db, pos) = TestDB::with_position(initial); |
9 | let krate = db.crate_graph().iter().next().unwrap(); | 9 | let krate = db.test_crate(); |
10 | { | 10 | { |
11 | let events = db.log_executed(|| { | 11 | let events = db.log_executed(|| { |
12 | db.crate_def_map(krate); | 12 | db.crate_def_map(krate); |
@@ -111,7 +111,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
111 | m!(X); | 111 | m!(X); |
112 | ", | 112 | ", |
113 | ); | 113 | ); |
114 | let krate = db.crate_graph().iter().next().unwrap(); | 114 | let krate = db.test_crate(); |
115 | { | 115 | { |
116 | let events = db.log_executed(|| { | 116 | let events = db.log_executed(|| { |
117 | let crate_def_map = db.crate_def_map(krate); | 117 | let crate_def_map = db.crate_def_map(krate); |
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index dee364a14..eb7b85c07 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -656,7 +656,7 @@ fn unresolved_module_diagnostics() { | |||
656 | //- /foo.rs | 656 | //- /foo.rs |
657 | ", | 657 | ", |
658 | ); | 658 | ); |
659 | let krate = db.crate_graph().iter().next().unwrap(); | 659 | let krate = db.test_crate(); |
660 | 660 | ||
661 | let crate_def_map = db.crate_def_map(krate); | 661 | let crate_def_map = db.crate_def_map(krate); |
662 | 662 | ||