aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/attr.rs4
-rw-r--r--crates/ra_hir_def/src/body.rs6
-rw-r--r--crates/ra_hir_def/src/docs.rs2
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs73
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs15
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs24
-rw-r--r--crates/ra_hir_def/src/path.rs5
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;
6use std::{ops::Index, sync::Arc}; 6use std::{ops::Index, sync::Arc};
7 7
8use either::Either; 8use either::Either;
9use hir_expand::{hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId, MacroFileKind}; 9use hir_expand::{
10 hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId, MacroFileKind,
11};
10use ra_arena::{map::ArenaMap, Arena}; 12use ra_arena::{map::ArenaMap, Arena};
11use ra_syntax::{ast, AstNode, AstPtr}; 13use ra_syntax::{ast, AstNode, AstPtr};
12use rustc_hash::FxHashMap; 14use 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
6use hir_expand::{ 6use 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};
11use ra_cfg::CfgOptions; 12use ra_cfg::CfgOptions;
12use ra_db::{CrateId, FileId}; 13use 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
187impl 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)]
188pub(super) struct Macro(RawId); 203pub(super) struct Macro(RawId);
189impl_arena_id!(Macro); 204impl_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]
605fn 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]
617fn 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