diff options
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r-- | crates/ra_hir_def/src/attr.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_def/src/docs.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 73 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/raw.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/tests/macros.rs | 24 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 5 |
7 files changed, 118 insertions, 11 deletions
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 7f9a6e7ca..2f8f02d82 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -61,7 +61,9 @@ impl Attrs { | |||
61 | AdtId::UnionId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), | 61 | AdtId::UnionId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), |
62 | }, | 62 | }, |
63 | AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), | 63 | AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), |
64 | AttrDefId::MacroDefId(it) => attrs_from_ast(it.ast_id, db), | 64 | AttrDefId::MacroDefId(it) => { |
65 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) | ||
66 | } | ||
65 | AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), | 67 | AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), |
66 | AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), | 68 | AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), |
67 | AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), | 69 | AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index ef1816836..7b385f3fd 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -6,7 +6,9 @@ pub mod scope; | |||
6 | use std::{ops::Index, sync::Arc}; | 6 | use std::{ops::Index, sync::Arc}; |
7 | 7 | ||
8 | use either::Either; | 8 | use either::Either; |
9 | use hir_expand::{hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId, MacroFileKind}; | 9 | use hir_expand::{ |
10 | hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId, MacroFileKind, | ||
11 | }; | ||
10 | use ra_arena::{map::ArenaMap, Arena}; | 12 | use ra_arena::{map::ArenaMap, Arena}; |
11 | use ra_syntax::{ast, AstNode, AstPtr}; | 13 | use ra_syntax::{ast, AstNode, AstPtr}; |
12 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
@@ -46,7 +48,7 @@ impl Expander { | |||
46 | 48 | ||
47 | if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) { | 49 | if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) { |
48 | if let Some(def) = self.resolve_path_as_macro(db, &path) { | 50 | if let Some(def) = self.resolve_path_as_macro(db, &path) { |
49 | let call_id = def.as_call_id(db, ast_id); | 51 | let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id)); |
50 | let file_id = call_id.as_file(MacroFileKind::Expr); | 52 | let file_id = call_id.as_file(MacroFileKind::Expr); |
51 | if let Some(node) = db.parse_or_expand(file_id) { | 53 | if let Some(node) = db.parse_or_expand(file_id) { |
52 | if let Some(expr) = ast::Expr::cast(node) { | 54 | if let Some(expr) = ast::Expr::cast(node) { |
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs index 3fc6d6934..61727bd26 100644 --- a/crates/ra_hir_def/src/docs.rs +++ b/crates/ra_hir_def/src/docs.rs | |||
@@ -60,7 +60,7 @@ impl Documentation { | |||
60 | docs_from_ast(&src.value[it.local_id]) | 60 | docs_from_ast(&src.value[it.local_id]) |
61 | } | 61 | } |
62 | AttrDefId::TraitId(it) => docs_from_ast(&it.source(db).value), | 62 | AttrDefId::TraitId(it) => docs_from_ast(&it.source(db).value), |
63 | AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id.to_node(db)), | 63 | AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id?.to_node(db)), |
64 | AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value), | 64 | AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
65 | AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value), | 65 | AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
66 | AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value), | 66 | AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value), |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 9d948d4f4..08693cb13 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -4,9 +4,10 @@ | |||
4 | //! resolves imports and expands macros. | 4 | //! resolves imports and expands macros. |
5 | 5 | ||
6 | use hir_expand::{ | 6 | use hir_expand::{ |
7 | builtin_derive::find_builtin_derive, | ||
7 | builtin_macro::find_builtin_macro, | 8 | builtin_macro::find_builtin_macro, |
8 | name::{self, AsName, Name}, | 9 | name::{self, AsName, Name}, |
9 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, | 10 | HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, MacroFileKind, |
10 | }; | 11 | }; |
11 | use ra_cfg::CfgOptions; | 12 | use ra_cfg::CfgOptions; |
12 | use ra_db::{CrateId, FileId}; | 13 | use ra_db::{CrateId, FileId}; |
@@ -58,6 +59,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
58 | glob_imports: FxHashMap::default(), | 59 | glob_imports: FxHashMap::default(), |
59 | unresolved_imports: Vec::new(), | 60 | unresolved_imports: Vec::new(), |
60 | unexpanded_macros: Vec::new(), | 61 | unexpanded_macros: Vec::new(), |
62 | unexpanded_attribute_macros: Vec::new(), | ||
61 | mod_dirs: FxHashMap::default(), | 63 | mod_dirs: FxHashMap::default(), |
62 | macro_stack_monitor: MacroStackMonitor::default(), | 64 | macro_stack_monitor: MacroStackMonitor::default(), |
63 | poison_macros: FxHashSet::default(), | 65 | poison_macros: FxHashSet::default(), |
@@ -102,6 +104,7 @@ struct DefCollector<'a, DB> { | |||
102 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>, | 104 | glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>, |
103 | unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>, | 105 | unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>, |
104 | unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>, | 106 | unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>, |
107 | unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, Path)>, | ||
105 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | 108 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, |
106 | 109 | ||
107 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly | 110 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly |
@@ -470,6 +473,8 @@ where | |||
470 | 473 | ||
471 | fn resolve_macros(&mut self) -> ReachedFixedPoint { | 474 | fn resolve_macros(&mut self) -> ReachedFixedPoint { |
472 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); | 475 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); |
476 | let mut attribute_macros = | ||
477 | std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new()); | ||
473 | let mut resolved = Vec::new(); | 478 | let mut resolved = Vec::new(); |
474 | let mut res = ReachedFixedPoint::Yes; | 479 | let mut res = ReachedFixedPoint::Yes; |
475 | macros.retain(|(module_id, ast_id, path)| { | 480 | macros.retain(|(module_id, ast_id, path)| { |
@@ -482,7 +487,19 @@ where | |||
482 | ); | 487 | ); |
483 | 488 | ||
484 | if let Some(def) = resolved_res.resolved_def.take_macros() { | 489 | if let Some(def) = resolved_res.resolved_def.take_macros() { |
485 | let call_id = def.as_call_id(self.db, *ast_id); | 490 | let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(*ast_id)); |
491 | resolved.push((*module_id, call_id, def)); | ||
492 | res = ReachedFixedPoint::No; | ||
493 | return false; | ||
494 | } | ||
495 | |||
496 | true | ||
497 | }); | ||
498 | attribute_macros.retain(|(module_id, ast_id, path)| { | ||
499 | let resolved_res = self.resolve_attribute_macro(path); | ||
500 | |||
501 | if let Some(def) = resolved_res { | ||
502 | let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id)); | ||
486 | resolved.push((*module_id, call_id, def)); | 503 | resolved.push((*module_id, call_id, def)); |
487 | res = ReachedFixedPoint::No; | 504 | res = ReachedFixedPoint::No; |
488 | return false; | 505 | return false; |
@@ -492,6 +509,7 @@ where | |||
492 | }); | 509 | }); |
493 | 510 | ||
494 | self.unexpanded_macros = macros; | 511 | self.unexpanded_macros = macros; |
512 | self.unexpanded_attribute_macros = attribute_macros; | ||
495 | 513 | ||
496 | for (module_id, macro_call_id, macro_def_id) in resolved { | 514 | for (module_id, macro_call_id, macro_def_id) in resolved { |
497 | self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); | 515 | self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); |
@@ -500,6 +518,20 @@ where | |||
500 | res | 518 | res |
501 | } | 519 | } |
502 | 520 | ||
521 | fn resolve_attribute_macro(&self, path: &Path) -> Option<MacroDefId> { | ||
522 | // FIXME this is currently super hacky, just enough to support the | ||
523 | // built-in derives | ||
524 | if let Some(name) = path.as_ident() { | ||
525 | // FIXME this should actually be handled with the normal name | ||
526 | // resolution; the std lib defines built-in stubs for the derives, | ||
527 | // but these are new-style `macro`s, which we don't support yet | ||
528 | if let Some(def_id) = find_builtin_derive(name) { | ||
529 | return Some(def_id); | ||
530 | } | ||
531 | } | ||
532 | None | ||
533 | } | ||
534 | |||
503 | fn collect_macro_expansion( | 535 | fn collect_macro_expansion( |
504 | &mut self, | 536 | &mut self, |
505 | module_id: LocalModuleId, | 537 | module_id: LocalModuleId, |
@@ -587,7 +619,9 @@ where | |||
587 | .def_collector | 619 | .def_collector |
588 | .unresolved_imports | 620 | .unresolved_imports |
589 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), | 621 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), |
590 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), | 622 | raw::RawItemKind::Def(def) => { |
623 | self.define_def(&self.raw_items[def], &item.attrs) | ||
624 | } | ||
591 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 625 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
592 | raw::RawItemKind::Impl(imp) => { | 626 | raw::RawItemKind::Impl(imp) => { |
593 | let module = ModuleId { | 627 | let module = ModuleId { |
@@ -682,10 +716,16 @@ where | |||
682 | res | 716 | res |
683 | } | 717 | } |
684 | 718 | ||
685 | fn define_def(&mut self, def: &raw::DefData) { | 719 | fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) { |
686 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; | 720 | let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; |
687 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | 721 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); |
688 | 722 | ||
723 | // FIXME: check attrs to see if this is an attribute macro invocation; | ||
724 | // in which case we don't add the invocation, just a single attribute | ||
725 | // macro invocation | ||
726 | |||
727 | self.collect_derives(attrs, def); | ||
728 | |||
689 | let name = def.name.clone(); | 729 | let name = def.name.clone(); |
690 | let def: PerNs = match def.kind { | 730 | let def: PerNs = match def.kind { |
691 | raw::DefKind::Function(ast_id) => { | 731 | raw::DefKind::Function(ast_id) => { |
@@ -736,6 +776,23 @@ where | |||
736 | self.def_collector.update(self.module_id, None, &[(name, resolution)]) | 776 | self.def_collector.update(self.module_id, None, &[(name, resolution)]) |
737 | } | 777 | } |
738 | 778 | ||
779 | fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { | ||
780 | for derive_subtree in attrs.by_key("derive").tt_values() { | ||
781 | // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree | ||
782 | for tt in &derive_subtree.token_trees { | ||
783 | let ident = match &tt { | ||
784 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident, | ||
785 | tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok | ||
786 | _ => continue, // anything else would be an error (which we currently ignore) | ||
787 | }; | ||
788 | let path = Path::from_tt_ident(ident); | ||
789 | |||
790 | let ast_id = AstId::new(self.file_id, def.kind.ast_id()); | ||
791 | self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path)); | ||
792 | } | ||
793 | } | ||
794 | } | ||
795 | |||
739 | fn collect_macro(&mut self, mac: &raw::MacroData) { | 796 | fn collect_macro(&mut self, mac: &raw::MacroData) { |
740 | let ast_id = AstId::new(self.file_id, mac.ast_id); | 797 | let ast_id = AstId::new(self.file_id, mac.ast_id); |
741 | 798 | ||
@@ -759,8 +816,8 @@ where | |||
759 | if is_macro_rules(&mac.path) { | 816 | if is_macro_rules(&mac.path) { |
760 | if let Some(name) = &mac.name { | 817 | if let Some(name) = &mac.name { |
761 | let macro_id = MacroDefId { | 818 | let macro_id = MacroDefId { |
762 | ast_id, | 819 | ast_id: Some(ast_id), |
763 | krate: self.def_collector.def_map.krate, | 820 | krate: Some(self.def_collector.def_map.krate), |
764 | kind: MacroDefKind::Declarative, | 821 | kind: MacroDefKind::Declarative, |
765 | }; | 822 | }; |
766 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); | 823 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); |
@@ -773,7 +830,8 @@ where | |||
773 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { | 830 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { |
774 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | 831 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) |
775 | }) { | 832 | }) { |
776 | let macro_call_id = macro_def.as_call_id(self.def_collector.db, ast_id); | 833 | let macro_call_id = |
834 | macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id)); | ||
777 | 835 | ||
778 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def); | 836 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def); |
779 | return; | 837 | return; |
@@ -829,6 +887,7 @@ mod tests { | |||
829 | glob_imports: FxHashMap::default(), | 887 | glob_imports: FxHashMap::default(), |
830 | unresolved_imports: Vec::new(), | 888 | unresolved_imports: Vec::new(), |
831 | unexpanded_macros: Vec::new(), | 889 | unexpanded_macros: Vec::new(), |
890 | unexpanded_attribute_macros: Vec::new(), | ||
832 | mod_dirs: FxHashMap::default(), | 891 | mod_dirs: FxHashMap::default(), |
833 | macro_stack_monitor: monitor, | 892 | macro_stack_monitor: monitor, |
834 | poison_macros: FxHashSet::default(), | 893 | poison_macros: FxHashSet::default(), |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index de4e706c2..a2821e1c3 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -184,6 +184,21 @@ pub(super) enum DefKind { | |||
184 | TypeAlias(FileAstId<ast::TypeAliasDef>), | 184 | TypeAlias(FileAstId<ast::TypeAliasDef>), |
185 | } | 185 | } |
186 | 186 | ||
187 | impl DefKind { | ||
188 | pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> { | ||
189 | match self { | ||
190 | DefKind::Function(it) => it.upcast(), | ||
191 | DefKind::Struct(it) => it.upcast(), | ||
192 | DefKind::Union(it) => it.upcast(), | ||
193 | DefKind::Enum(it) => it.upcast(), | ||
194 | DefKind::Const(it) => it.upcast(), | ||
195 | DefKind::Static(it) => it.upcast(), | ||
196 | DefKind::Trait(it) => it.upcast(), | ||
197 | DefKind::TypeAlias(it) => it.upcast(), | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | |||
187 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 202 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
188 | pub(super) struct Macro(RawId); | 203 | pub(super) struct Macro(RawId); |
189 | impl_arena_id!(Macro); | 204 | impl_arena_id!(Macro); |
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs index 704065633..cfa4ecb1a 100644 --- a/crates/ra_hir_def/src/nameres/tests/macros.rs +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs | |||
@@ -600,3 +600,27 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() { | |||
600 | ⋮bar: t v | 600 | ⋮bar: t v |
601 | "###); | 601 | "###); |
602 | } | 602 | } |
603 | |||
604 | #[test] | ||
605 | fn expand_derive() { | ||
606 | let map = compute_crate_def_map( | ||
607 | " | ||
608 | //- /main.rs | ||
609 | #[derive(Clone)] | ||
610 | struct Foo; | ||
611 | ", | ||
612 | ); | ||
613 | assert_eq!(map.modules[map.root].impls.len(), 1); | ||
614 | } | ||
615 | |||
616 | #[test] | ||
617 | fn expand_multiple_derive() { | ||
618 | let map = compute_crate_def_map( | ||
619 | " | ||
620 | //- /main.rs | ||
621 | #[derive(Copy, Clone)] | ||
622 | struct Foo; | ||
623 | ", | ||
624 | ); | ||
625 | assert_eq!(map.modules[map.root].impls.len(), 2); | ||
626 | } | ||
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 3030dcdf6..e547b2f03 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -199,6 +199,11 @@ impl Path { | |||
199 | name_ref.as_name().into() | 199 | name_ref.as_name().into() |
200 | } | 200 | } |
201 | 201 | ||
202 | /// Converts an `tt::Ident` into a single-identifier `Path`. | ||
203 | pub(crate) fn from_tt_ident(ident: &tt::Ident) -> Path { | ||
204 | ident.as_name().into() | ||
205 | } | ||
206 | |||
202 | /// `true` is this path is a single identifier, like `foo` | 207 | /// `true` is this path is a single identifier, like `foo` |
203 | pub fn is_ident(&self) -> bool { | 208 | pub fn is_ident(&self) -> bool { |
204 | self.kind == PathKind::Plain && self.segments.len() == 1 | 209 | self.kind == PathKind::Plain && self.segments.len() == 1 |