aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-12-19 00:09:48 +0000
committerJonas Schievink <[email protected]>2020-12-19 00:10:56 +0000
commitea5cc8d07ac28a2110b894d154468c3fa46d7040 (patch)
treed03e228616092a32a75c7c8af624d4e9c7f7fb2f /crates/hir_def
parentc7b7c37ea5f25806d8c523e309b7ee9be27f2cde (diff)
More accurate `#[derive]` parsing
This now allows full paths to the derive macro
Diffstat (limited to 'crates/hir_def')
-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/path.rs12
3 files changed, 59 insertions, 27 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/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>,