diff options
author | Aleksey Kladov <[email protected]> | 2019-09-17 20:22:40 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-09-18 02:34:48 +0100 |
commit | 7d15c81a3367bc538470b5f63d61498eef8efdc7 (patch) | |
tree | 742e3278b495b3a8827a7ac1628e66aa76948ff8 /crates/ra_hir | |
parent | 54379ec6f8f82a470a275771e70825634d3d553b (diff) |
account for impls generated by macros
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 81 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 17 |
3 files changed, 74 insertions, 28 deletions
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index c463d351c..d830202bd 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -12,29 +12,29 @@ use crate::{ | |||
12 | db::{AstDatabase, DefDatabase, HirDatabase}, | 12 | db::{AstDatabase, DefDatabase, HirDatabase}, |
13 | generics::HasGenericParams, | 13 | generics::HasGenericParams, |
14 | ids::LocationCtx, | 14 | ids::LocationCtx, |
15 | ids::MacroCallLoc, | ||
15 | resolve::Resolver, | 16 | resolve::Resolver, |
16 | ty::Ty, | 17 | ty::Ty, |
17 | type_ref::TypeRef, | 18 | type_ref::TypeRef, |
18 | AssocItem, Const, Function, HasSource, HirFileId, Source, TraitRef, TypeAlias, | 19 | AssocItem, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef, |
20 | TypeAlias, | ||
19 | }; | 21 | }; |
20 | 22 | ||
21 | #[derive(Debug, Default, PartialEq, Eq)] | 23 | #[derive(Debug, Default, PartialEq, Eq)] |
22 | pub struct ImplSourceMap { | 24 | pub struct ImplSourceMap { |
23 | map: ArenaMap<ImplId, AstPtr<ast::ImplBlock>>, | 25 | map: ArenaMap<ImplId, Source<AstPtr<ast::ImplBlock>>>, |
24 | } | 26 | } |
25 | 27 | ||
26 | impl ImplSourceMap { | 28 | impl ImplSourceMap { |
27 | fn insert(&mut self, impl_id: ImplId, impl_block: &ast::ImplBlock) { | 29 | fn insert(&mut self, impl_id: ImplId, file_id: HirFileId, impl_block: &ast::ImplBlock) { |
28 | self.map.insert(impl_id, AstPtr::new(impl_block)) | 30 | let source = Source { file_id, ast: AstPtr::new(impl_block) }; |
31 | self.map.insert(impl_id, source) | ||
29 | } | 32 | } |
30 | 33 | ||
31 | pub fn get(&self, source: &ModuleSource, impl_id: ImplId) -> ast::ImplBlock { | 34 | pub fn get(&self, db: &impl AstDatabase, impl_id: ImplId) -> Source<ast::ImplBlock> { |
32 | let root = match source { | 35 | let src = self.map[impl_id]; |
33 | ModuleSource::SourceFile(file) => file.syntax().clone(), | 36 | let root = src.file_syntax(db); |
34 | ModuleSource::Module(m) => m.syntax().ancestors().last().unwrap(), | 37 | src.map(|ptr| ptr.to_node(&root)) |
35 | }; | ||
36 | |||
37 | self.map[impl_id].to_node(&root) | ||
38 | } | 38 | } |
39 | } | 39 | } |
40 | 40 | ||
@@ -48,8 +48,7 @@ impl HasSource for ImplBlock { | |||
48 | type Ast = ast::ImplBlock; | 48 | type Ast = ast::ImplBlock; |
49 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> { | 49 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> { |
50 | let source_map = db.impls_in_module_with_source_map(self.module).1; | 50 | let source_map = db.impls_in_module_with_source_map(self.module).1; |
51 | let src = self.module.definition_source(db); | 51 | source_map.get(db, self.impl_id) |
52 | Source { file_id: src.file_id, ast: source_map.get(&src.ast, self.impl_id) } | ||
53 | } | 52 | } |
54 | } | 53 | } |
55 | 54 | ||
@@ -185,24 +184,55 @@ impl ModuleImplBlocks { | |||
185 | }; | 184 | }; |
186 | 185 | ||
187 | let src = m.module.definition_source(db); | 186 | let src = m.module.definition_source(db); |
188 | let node = match &src.ast { | 187 | match &src.ast { |
189 | ModuleSource::SourceFile(node) => node.syntax().clone(), | 188 | ModuleSource::SourceFile(node) => { |
189 | m.collect_from_item_owner(db, source_map, node, src.file_id) | ||
190 | } | ||
190 | ModuleSource::Module(node) => { | 191 | ModuleSource::Module(node) => { |
191 | node.item_list().expect("inline module should have item list").syntax().clone() | 192 | let item_list = node.item_list().expect("inline module should have item list"); |
193 | m.collect_from_item_owner(db, source_map, &item_list, src.file_id) | ||
192 | } | 194 | } |
193 | }; | 195 | }; |
196 | m | ||
197 | } | ||
194 | 198 | ||
195 | for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { | 199 | fn collect_from_item_owner( |
196 | let impl_block = ImplData::from_ast(db, src.file_id, m.module, &impl_block_ast); | 200 | &mut self, |
197 | let id = m.impls.alloc(impl_block); | 201 | db: &(impl DefDatabase + AstDatabase), |
198 | for &impl_item in &m.impls[id].items { | 202 | source_map: &mut ImplSourceMap, |
199 | m.impls_by_def.insert(impl_item, id); | 203 | owner: &dyn ast::ModuleItemOwner, |
204 | file_id: HirFileId, | ||
205 | ) { | ||
206 | for item in owner.items_with_macros() { | ||
207 | match item { | ||
208 | ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { | ||
209 | let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); | ||
210 | let id = self.impls.alloc(impl_block); | ||
211 | for &impl_item in &self.impls[id].items { | ||
212 | self.impls_by_def.insert(impl_item, id); | ||
213 | } | ||
214 | |||
215 | source_map.insert(id, file_id, &impl_block_ast); | ||
216 | } | ||
217 | ast::ItemOrMacro::Item(_) => (), | ||
218 | ast::ItemOrMacro::Macro(macro_call) => { | ||
219 | //FIXME: we should really cut down on the boilerplate required to process a macro | ||
220 | let ast_id = db.ast_id_map(file_id).ast_id(¯o_call).with_file_id(file_id); | ||
221 | if let Some(path) = macro_call.path().and_then(Path::from_ast) { | ||
222 | if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) | ||
223 | { | ||
224 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); | ||
225 | let file_id = call_id.as_file(MacroFileKind::Items); | ||
226 | if let Some(item_list) = | ||
227 | db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) | ||
228 | { | ||
229 | self.collect_from_item_owner(db, source_map, &item_list, file_id) | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | } | ||
200 | } | 234 | } |
201 | |||
202 | source_map.insert(id, &impl_block_ast); | ||
203 | } | 235 | } |
204 | |||
205 | m | ||
206 | } | 236 | } |
207 | } | 237 | } |
208 | 238 | ||
@@ -213,7 +243,6 @@ pub(crate) fn impls_in_module_with_source_map_query( | |||
213 | let mut source_map = ImplSourceMap::default(); | 243 | let mut source_map = ImplSourceMap::default(); |
214 | 244 | ||
215 | let result = ModuleImplBlocks::collect(db, module, &mut source_map); | 245 | let result = ModuleImplBlocks::collect(db, module, &mut source_map); |
216 | |||
217 | (Arc::new(result), Arc::new(source_map)) | 246 | (Arc::new(result), Arc::new(source_map)) |
218 | } | 247 | } |
219 | 248 | ||
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index a23c8792a..254d1a964 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -5,7 +5,7 @@ use rustc_hash::FxHashSet; | |||
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | code_model::Crate, | 7 | code_model::Crate, |
8 | db::HirDatabase, | 8 | db::{DefDatabase, HirDatabase}, |
9 | expr::{ | 9 | expr::{ |
10 | scope::{ExprScopes, ScopeId}, | 10 | scope::{ExprScopes, ScopeId}, |
11 | PatId, | 11 | PatId, |
@@ -290,7 +290,7 @@ impl Resolver { | |||
290 | 290 | ||
291 | pub(crate) fn resolve_path_as_macro( | 291 | pub(crate) fn resolve_path_as_macro( |
292 | &self, | 292 | &self, |
293 | db: &impl HirDatabase, | 293 | db: &impl DefDatabase, |
294 | path: &Path, | 294 | path: &Path, |
295 | ) -> Option<MacroDef> { | 295 | ) -> Option<MacroDef> { |
296 | let (item_map, module) = self.module()?; | 296 | let (item_map, module) = self.module()?; |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 09c17fdf4..3b0a99460 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2997,6 +2997,23 @@ fn foo() { | |||
2997 | ); | 2997 | ); |
2998 | } | 2998 | } |
2999 | 2999 | ||
3000 | #[test] | ||
3001 | fn processes_impls_generated_by_macros() { | ||
3002 | let t = type_at( | ||
3003 | r#" | ||
3004 | //- /main.rs | ||
3005 | macro_rules! m { | ||
3006 | ($ident:ident) => (impl Trait for $ident {}) | ||
3007 | } | ||
3008 | trait Trait { fn foo(self) -> u128 {} } | ||
3009 | struct S; | ||
3010 | m!(S); | ||
3011 | fn test() { S.foo()<|>; } | ||
3012 | "#, | ||
3013 | ); | ||
3014 | assert_eq!(t, "u128"); | ||
3015 | } | ||
3016 | |||
3000 | #[ignore] | 3017 | #[ignore] |
3001 | #[test] | 3018 | #[test] |
3002 | fn method_resolution_trait_before_autoref() { | 3019 | fn method_resolution_trait_before_autoref() { |