6942: Minor `#[derive]` resolution cleanup r=jonas-schievink a=jonas-schievink

bors r+

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
bors[bot] 2020-12-19 00:13:27 +00:00 committed by GitHub
commit 83a2725828
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 33 deletions

View file

@ -5,7 +5,7 @@ use std::{ops, sync::Arc};
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{hygiene::Hygiene, AstId, InFile};
use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile};
use itertools::Itertools;
use mbe::ast_to_token_tree;
use syntax::{
@ -19,7 +19,7 @@ use crate::{
db::DefDatabase,
item_tree::{ItemTreeId, ItemTreeNode},
nameres::ModuleSource,
path::ModPath,
path::{ModPath, PathKind},
src::HasChildSource,
AdtId, AttrDefId, Lookup,
};
@ -357,6 +357,46 @@ impl Attr {
};
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)]
@ -384,7 +424,7 @@ impl<'a> AttrQuery<'a> {
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;
self.attrs
.iter()

View file

@ -1289,20 +1289,20 @@ impl ModCollector<'_, '_> {
}
fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
for derive_subtree in attrs.by_key("derive").tt_values() {
// for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
for tt in &derive_subtree.token_trees {
let ident = match &tt {
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident,
tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
_ => continue, // anything else would be an error (which we currently ignore)
};
let path = ModPath::from_tt_ident(ident);
let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
self.def_collector
.unexpanded_attribute_macros
.push(DeriveDirective { module_id: self.module_id, ast_id });
for derive in attrs.by_key("derive").attrs() {
match derive.parse_derive() {
Some(derive_macros) => {
for path in derive_macros {
let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
self.def_collector
.unexpanded_attribute_macros
.push(DeriveDirective { module_id: self.module_id, ast_id });
}
}
None => {
// FIXME: diagnose
log::debug!("malformed derive: {:?}", derive);
}
}
}
}

View file

@ -13,8 +13,8 @@ use test_utils::mark;
use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
let db = TestDB::with_files(fixture);
fn compute_crate_def_map(ra_fixture: &str) -> Arc<CrateDefMap> {
let db = TestDB::with_files(ra_fixture);
let krate = db.crate_graph().iter().next().unwrap();
db.crate_def_map(krate)
}

View file

@ -632,11 +632,11 @@ pub struct bar;
#[test]
fn expand_derive() {
let map = compute_crate_def_map(
"
r#"
//- /main.rs crate:main deps:core
use core::*;
use core::Copy;
#[derive(Copy, Clone)]
#[derive(Copy, core::Clone)]
struct Foo;
//- /core.rs crate:core
@ -645,7 +645,7 @@ fn expand_derive() {
#[rustc_builtin_macro]
pub macro Clone {}
",
"#,
);
assert_eq!(map.modules[map.root].scope.impls().len(), 2);
}

View file

@ -9,11 +9,8 @@ use std::{
use crate::{body::LowerCtx, type_ref::LifetimeRef};
use base_db::CrateId;
use hir_expand::{
hygiene::Hygiene,
name::{AsName, Name},
};
use syntax::ast::{self};
use hir_expand::{hygiene::Hygiene, name::Name};
use syntax::ast;
use crate::{
type_ref::{TypeBound, TypeRef},
@ -56,11 +53,6 @@ impl ModPath {
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.
pub(crate) fn expand_use_item(
item_src: InFile<ast::Use>,

View file

@ -152,6 +152,7 @@ pub mod known {
str,
// Special names
macro_rules,
derive,
doc,
cfg_attr,
// Components of known path (value or mod name)