aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/attr.rs46
-rw-r--r--crates/hir_def/src/nameres/collector.rs28
-rw-r--r--crates/hir_def/src/nameres/tests.rs4
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs8
-rw-r--r--crates/hir_def/src/path.rs12
-rw-r--r--crates/hir_expand/src/name.rs1
6 files changed, 66 insertions, 33 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 1b9c64ee5..18525406c 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -5,7 +5,7 @@ use std::{ops, sync::Arc};
5use base_db::CrateId; 5use base_db::CrateId;
6use cfg::{CfgExpr, CfgOptions}; 6use cfg::{CfgExpr, CfgOptions};
7use either::Either; 7use either::Either;
8use hir_expand::{hygiene::Hygiene, AstId, InFile}; 8use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile};
9use itertools::Itertools; 9use itertools::Itertools;
10use mbe::ast_to_token_tree; 10use mbe::ast_to_token_tree;
11use syntax::{ 11use syntax::{
@@ -19,7 +19,7 @@ use crate::{
19 db::DefDatabase, 19 db::DefDatabase,
20 item_tree::{ItemTreeId, ItemTreeNode}, 20 item_tree::{ItemTreeId, ItemTreeNode},
21 nameres::ModuleSource, 21 nameres::ModuleSource,
22 path::ModPath, 22 path::{ModPath, PathKind},
23 src::HasChildSource, 23 src::HasChildSource,
24 AdtId, AttrDefId, Lookup, 24 AdtId, AttrDefId, Lookup,
25}; 25};
@@ -357,6 +357,46 @@ impl Attr {
357 }; 357 };
358 Some(Attr { path, input }) 358 Some(Attr { path, input })
359 } 359 }
360
361 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
362 /// to derive macros.
363 ///
364 /// Returns `None` when the attribute is not a well-formed `#[derive]` attribute.
365 pub(crate) fn parse_derive(&self) -> Option<impl Iterator<Item = ModPath>> {
366 if self.path.as_ident() != Some(&hir_expand::name![derive]) {
367 return None;
368 }
369
370 match &self.input {
371 Some(AttrInput::TokenTree(args)) => {
372 let mut counter = 0;
373 let paths = args
374 .token_trees
375 .iter()
376 .group_by(move |tt| {
377 match tt {
378 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
379 counter += 1;
380 }
381 _ => {}
382 }
383 counter
384 })
385 .into_iter()
386 .map(|(_, tts)| {
387 let segments = tts.filter_map(|tt| match tt {
388 tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
389 _ => None,
390 });
391 ModPath::from_segments(PathKind::Plain, segments)
392 })
393 .collect::<Vec<_>>();
394
395 Some(paths.into_iter())
396 }
397 _ => None,
398 }
399 }
360} 400}
361 401
362#[derive(Debug, Clone, Copy)] 402#[derive(Debug, Clone, Copy)]
@@ -384,7 +424,7 @@ impl<'a> AttrQuery<'a> {
384 self.attrs().next().is_some() 424 self.attrs().next().is_some()
385 } 425 }
386 426
387 fn attrs(self) -> impl Iterator<Item = &'a Attr> { 427 pub(crate) fn attrs(self) -> impl Iterator<Item = &'a Attr> {
388 let key = self.key; 428 let key = self.key;
389 self.attrs 429 self.attrs
390 .iter() 430 .iter()
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 55228e480..a636ec77d 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1289,20 +1289,20 @@ impl ModCollector<'_, '_> {
1289 } 1289 }
1290 1290
1291 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) { 1291 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
1292 for derive_subtree in attrs.by_key("derive").tt_values() { 1292 for derive in attrs.by_key("derive").attrs() {
1293 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree 1293 match derive.parse_derive() {
1294 for tt in &derive_subtree.token_trees { 1294 Some(derive_macros) => {
1295 let ident = match &tt { 1295 for path in derive_macros {
1296 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident, 1296 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
1297 tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok 1297 self.def_collector
1298 _ => continue, // anything else would be an error (which we currently ignore) 1298 .unexpanded_attribute_macros
1299 }; 1299 .push(DeriveDirective { module_id: self.module_id, ast_id });
1300 let path = ModPath::from_tt_ident(ident); 1300 }
1301 1301 }
1302 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); 1302 None => {
1303 self.def_collector 1303 // FIXME: diagnose
1304 .unexpanded_attribute_macros 1304 log::debug!("malformed derive: {:?}", derive);
1305 .push(DeriveDirective { module_id: self.module_id, ast_id }); 1305 }
1306 } 1306 }
1307 } 1307 }
1308 } 1308 }
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index a4d1fb8f3..c459fa66d 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -13,8 +13,8 @@ use test_utils::mark;
13 13
14use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 14use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
15 15
16fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> { 16fn compute_crate_def_map(ra_fixture: &str) -> Arc<CrateDefMap> {
17 let db = TestDB::with_files(fixture); 17 let db = TestDB::with_files(ra_fixture);
18 let krate = db.crate_graph().iter().next().unwrap(); 18 let krate = db.crate_graph().iter().next().unwrap();
19 db.crate_def_map(krate) 19 db.crate_def_map(krate)
20} 20}
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index 6fe2ee78a..f9bf5bc72 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -632,11 +632,11 @@ pub struct bar;
632#[test] 632#[test]
633fn expand_derive() { 633fn expand_derive() {
634 let map = compute_crate_def_map( 634 let map = compute_crate_def_map(
635 " 635 r#"
636 //- /main.rs crate:main deps:core 636 //- /main.rs crate:main deps:core
637 use core::*; 637 use core::Copy;
638 638
639 #[derive(Copy, Clone)] 639 #[derive(Copy, core::Clone)]
640 struct Foo; 640 struct Foo;
641 641
642 //- /core.rs crate:core 642 //- /core.rs crate:core
@@ -645,7 +645,7 @@ fn expand_derive() {
645 645
646 #[rustc_builtin_macro] 646 #[rustc_builtin_macro]
647 pub macro Clone {} 647 pub macro Clone {}
648 ", 648 "#,
649 ); 649 );
650 assert_eq!(map.modules[map.root].scope.impls().len(), 2); 650 assert_eq!(map.modules[map.root].scope.impls().len(), 2);
651} 651}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 00a69a8a6..e2bf85bbc 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -9,11 +9,8 @@ use std::{
9 9
10use crate::{body::LowerCtx, type_ref::LifetimeRef}; 10use crate::{body::LowerCtx, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{ 12use hir_expand::{hygiene::Hygiene, name::Name};
13 hygiene::Hygiene, 13use syntax::ast;
14 name::{AsName, Name},
15};
16use syntax::ast::{self};
17 14
18use crate::{ 15use crate::{
19 type_ref::{TypeBound, TypeRef}, 16 type_ref::{TypeBound, TypeRef},
@@ -56,11 +53,6 @@ impl ModPath {
56 ModPath { kind, segments } 53 ModPath { kind, segments }
57 } 54 }
58 55
59 /// Converts an `tt::Ident` into a single-identifier `Path`.
60 pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
61 ident.as_name().into()
62 }
63
64 /// Calls `cb` with all paths, represented by this use item. 56 /// Calls `cb` with all paths, represented by this use item.
65 pub(crate) fn expand_use_item( 57 pub(crate) fn expand_use_item(
66 item_src: InFile<ast::Use>, 58 item_src: InFile<ast::Use>,
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 77eeee3fe..2f44876a8 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -152,6 +152,7 @@ pub mod known {
152 str, 152 str,
153 // Special names 153 // Special names
154 macro_rules, 154 macro_rules,
155 derive,
155 doc, 156 doc,
156 cfg_attr, 157 cfg_attr,
157 // Components of known path (value or mod name) 158 // Components of known path (value or mod name)