More accurate #[derive]
parsing
This now allows full paths to the derive macro
This commit is contained in:
parent
c7b7c37ea5
commit
ea5cc8d07a
@ -5,7 +5,7 @@
|
|||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use cfg::{CfgExpr, CfgOptions};
|
use cfg::{CfgExpr, CfgOptions};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_expand::{hygiene::Hygiene, AstId, InFile};
|
use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use mbe::ast_to_token_tree;
|
use mbe::ast_to_token_tree;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
@ -19,7 +19,7 @@
|
|||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
item_tree::{ItemTreeId, ItemTreeNode},
|
item_tree::{ItemTreeId, ItemTreeNode},
|
||||||
nameres::ModuleSource,
|
nameres::ModuleSource,
|
||||||
path::ModPath,
|
path::{ModPath, PathKind},
|
||||||
src::HasChildSource,
|
src::HasChildSource,
|
||||||
AdtId, AttrDefId, Lookup,
|
AdtId, AttrDefId, Lookup,
|
||||||
};
|
};
|
||||||
@ -357,6 +357,46 @@ fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
|
|||||||
};
|
};
|
||||||
Some(Attr { path, input })
|
Some(Attr { path, input })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
|
||||||
|
/// to derive macros.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the attribute is not a well-formed `#[derive]` attribute.
|
||||||
|
pub(crate) fn parse_derive(&self) -> Option<impl Iterator<Item = ModPath>> {
|
||||||
|
if self.path.as_ident() != Some(&hir_expand::name![derive]) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &self.input {
|
||||||
|
Some(AttrInput::TokenTree(args)) => {
|
||||||
|
let mut counter = 0;
|
||||||
|
let paths = args
|
||||||
|
.token_trees
|
||||||
|
.iter()
|
||||||
|
.group_by(move |tt| {
|
||||||
|
match tt {
|
||||||
|
tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
counter
|
||||||
|
})
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, tts)| {
|
||||||
|
let segments = tts.filter_map(|tt| match tt {
|
||||||
|
tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
ModPath::from_segments(PathKind::Plain, segments)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Some(paths.into_iter())
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@ -384,7 +424,7 @@ pub fn exists(self) -> bool {
|
|||||||
self.attrs().next().is_some()
|
self.attrs().next().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attrs(self) -> impl Iterator<Item = &'a Attr> {
|
pub(crate) fn attrs(self) -> impl Iterator<Item = &'a Attr> {
|
||||||
let key = self.key;
|
let key = self.key;
|
||||||
self.attrs
|
self.attrs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1289,20 +1289,20 @@ fn push_child_module(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
|
fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
|
||||||
for derive_subtree in attrs.by_key("derive").tt_values() {
|
for derive in attrs.by_key("derive").attrs() {
|
||||||
// for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
|
match derive.parse_derive() {
|
||||||
for tt in &derive_subtree.token_trees {
|
Some(derive_macros) => {
|
||||||
let ident = match &tt {
|
for path in derive_macros {
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident,
|
let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
|
self.def_collector
|
||||||
_ => continue, // anything else would be an error (which we currently ignore)
|
.unexpanded_attribute_macros
|
||||||
};
|
.push(DeriveDirective { module_id: self.module_id, ast_id });
|
||||||
let path = ModPath::from_tt_ident(ident);
|
}
|
||||||
|
}
|
||||||
let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
|
None => {
|
||||||
self.def_collector
|
// FIXME: diagnose
|
||||||
.unexpanded_attribute_macros
|
log::debug!("malformed derive: {:?}", derive);
|
||||||
.push(DeriveDirective { module_id: self.module_id, ast_id });
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,8 @@
|
|||||||
|
|
||||||
use crate::{body::LowerCtx, type_ref::LifetimeRef};
|
use crate::{body::LowerCtx, type_ref::LifetimeRef};
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use hir_expand::{
|
use hir_expand::{hygiene::Hygiene, name::Name};
|
||||||
hygiene::Hygiene,
|
use syntax::ast;
|
||||||
name::{AsName, Name},
|
|
||||||
};
|
|
||||||
use syntax::ast::{self};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
type_ref::{TypeBound, TypeRef},
|
type_ref::{TypeBound, TypeRef},
|
||||||
@ -56,11 +53,6 @@ pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -
|
|||||||
ModPath { kind, segments }
|
ModPath { kind, segments }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an `tt::Ident` into a single-identifier `Path`.
|
|
||||||
pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
|
|
||||||
ident.as_name().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calls `cb` with all paths, represented by this use item.
|
/// Calls `cb` with all paths, represented by this use item.
|
||||||
pub(crate) fn expand_use_item(
|
pub(crate) fn expand_use_item(
|
||||||
item_src: InFile<ast::Use>,
|
item_src: InFile<ast::Use>,
|
||||||
|
@ -152,6 +152,7 @@ macro_rules! known_names {
|
|||||||
str,
|
str,
|
||||||
// Special names
|
// Special names
|
||||||
macro_rules,
|
macro_rules,
|
||||||
|
derive,
|
||||||
doc,
|
doc,
|
||||||
cfg_attr,
|
cfg_attr,
|
||||||
// Components of known path (value or mod name)
|
// Components of known path (value or mod name)
|
||||||
|
Loading…
Reference in New Issue
Block a user