mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-14 21:16:50 +00:00
Merge #10789
10789: internal: Check for derive attributes by item path, not `derive` identifier r=Veykril a=Veykril Prior we only checked if an attribute is the exact `derive` identifier and nothing else to collect derive attributes. That means when we encounter the following: ```rs #[::core::macros::builtin::derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ModPath { pub kind: PathKind, segments: Vec<Name>, } ``` We won't actually expand the derive attributes, but instead we just expand the `derive` attribute with our dummy identity expander. The changes here make it so we actually lookup the attribute path, check if it is the derive attribute and then collect the derives. Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
fdd49b9713
@ -8,7 +8,7 @@ use either::Either;
|
||||
use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile};
|
||||
use itertools::Itertools;
|
||||
use la_arena::ArenaMap;
|
||||
use mbe::{syntax_node_to_token_tree, DelimiterKind};
|
||||
use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use syntax::{
|
||||
ast::{self, AstNode, HasAttrs, IsString},
|
||||
@ -722,41 +722,35 @@ impl Attr {
|
||||
/// 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.
|
||||
/// Returns `None` when the attribute does not have a well-formed `#[derive]` attribute input.
|
||||
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.as_deref() {
|
||||
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())
|
||||
if let Some(AttrInput::TokenTree(args, _)) = self.input.as_deref() {
|
||||
if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) {
|
||||
return None;
|
||||
}
|
||||
_ => None,
|
||||
let mut counter = 0;
|
||||
let paths = args
|
||||
.token_trees
|
||||
.iter()
|
||||
.group_by(move |tt| {
|
||||
if let tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })) = tt {
|
||||
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<_>>();
|
||||
|
||||
return Some(paths.into_iter());
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn string_value(&self) -> Option<&SmolStr> {
|
||||
|
@ -776,13 +776,10 @@ fn attr_macro_as_call_id(
|
||||
macro_attr: &Attr,
|
||||
db: &dyn db::DefDatabase,
|
||||
krate: CrateId,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
def: Option<MacroDefId>,
|
||||
) -> Result<MacroCallId, UnresolvedMacro> {
|
||||
let attr_path = &item_attr.path;
|
||||
|
||||
let def = resolver(attr_path.clone())
|
||||
.filter(MacroDefId::is_attribute)
|
||||
.ok_or_else(|| UnresolvedMacro { path: attr_path.clone() })?;
|
||||
let def = def.ok_or_else(|| UnresolvedMacro { path: attr_path.clone() })?;
|
||||
let last_segment =
|
||||
attr_path.segments().last().ok_or_else(|| UnresolvedMacro { path: attr_path.clone() })?;
|
||||
let mut arg = match macro_attr.input.as_deref() {
|
||||
|
@ -26,12 +26,16 @@ fn test_copy_expand_in_core() {
|
||||
check(
|
||||
r#"
|
||||
#[rustc_builtin_macro]
|
||||
macro derive {}
|
||||
#[rustc_builtin_macro]
|
||||
macro Copy {}
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
"#,
|
||||
expect![[r##"
|
||||
#[rustc_builtin_macro]
|
||||
macro derive {}
|
||||
#[rustc_builtin_macro]
|
||||
macro Copy {}
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
|
@ -31,6 +31,7 @@ fn derive_censoring() {
|
||||
check(
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore:derive
|
||||
#[attr1]
|
||||
#[derive(Foo)]
|
||||
#[derive(proc_macros::DeriveIdentity)]
|
||||
|
@ -9,7 +9,7 @@ use base_db::{CrateId, Edition, FileId, ProcMacroId};
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use hir_expand::{
|
||||
ast_id_map::FileAstId,
|
||||
builtin_attr_macro::{find_builtin_attr, is_builtin_test_or_bench_attr},
|
||||
builtin_attr_macro::find_builtin_attr,
|
||||
builtin_derive_macro::find_builtin_derive,
|
||||
builtin_fn_macro::find_builtin_macro,
|
||||
name::{name, AsName, Name},
|
||||
@ -781,7 +781,7 @@ impl DefCollector<'_> {
|
||||
}
|
||||
|
||||
fn resolve_extern_crate(&self, name: &Name) -> PerNs {
|
||||
if name == &name!(self) {
|
||||
if *name == name!(self) {
|
||||
cov_mark::hit!(extern_crate_self_as);
|
||||
let root = match self.def_map.block {
|
||||
Some(_) => {
|
||||
@ -1054,14 +1054,15 @@ impl DefCollector<'_> {
|
||||
|
||||
match &directive.kind {
|
||||
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
||||
match macro_call_as_call_id(
|
||||
let call_id = macro_call_as_call_id(
|
||||
ast_id,
|
||||
*expand_to,
|
||||
self.db,
|
||||
self.def_map.krate,
|
||||
&resolver,
|
||||
&mut |_err| (),
|
||||
) {
|
||||
);
|
||||
match call_id {
|
||||
Ok(Ok(call_id)) => {
|
||||
resolved.push((directive.module_id, call_id, directive.depth));
|
||||
res = ReachedFixedPoint::No;
|
||||
@ -1071,13 +1072,14 @@ impl DefCollector<'_> {
|
||||
}
|
||||
}
|
||||
MacroDirectiveKind::Derive { ast_id, derive_attr } => {
|
||||
match derive_macro_as_call_id(
|
||||
let call_id = derive_macro_as_call_id(
|
||||
ast_id,
|
||||
*derive_attr,
|
||||
self.db,
|
||||
self.def_map.krate,
|
||||
&resolver,
|
||||
) {
|
||||
);
|
||||
match call_id {
|
||||
Ok(call_id) => {
|
||||
self.def_map.modules[directive.module_id].scope.add_derive_macro_invoc(
|
||||
ast_id.ast_id,
|
||||
@ -1089,73 +1091,103 @@ impl DefCollector<'_> {
|
||||
res = ReachedFixedPoint::No;
|
||||
return false;
|
||||
}
|
||||
Err(UnresolvedMacro { .. }) => (),
|
||||
Err(UnresolvedMacro { .. }) => {}
|
||||
}
|
||||
}
|
||||
MacroDirectiveKind::Attr { ast_id, mod_item, attr } => {
|
||||
let file_id = ast_id.ast_id.file_id;
|
||||
let mut recollect_without = |collector: &mut Self, item_tree| {
|
||||
// Remove the original directive since we resolved it.
|
||||
let mod_dir = collector.mod_dirs[&directive.module_id].clone();
|
||||
collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
|
||||
ModCollector {
|
||||
def_collector: collector,
|
||||
macro_depth: directive.depth,
|
||||
module_id: directive.module_id,
|
||||
tree_id: TreeId::new(file_id, None),
|
||||
item_tree,
|
||||
mod_dir,
|
||||
}
|
||||
.collect(&[*mod_item]);
|
||||
res = ReachedFixedPoint::No;
|
||||
false
|
||||
};
|
||||
|
||||
if let Some(ident) = ast_id.path.as_ident() {
|
||||
if let Some(helpers) = self.derive_helpers_in_scope.get(&ast_id.ast_id) {
|
||||
if helpers.contains(ident) {
|
||||
cov_mark::hit!(resolved_derive_helper);
|
||||
|
||||
// Resolved to derive helper. Collect the item's attributes again,
|
||||
// starting after the derive helper.
|
||||
let file_id = ast_id.ast_id.file_id;
|
||||
let item_tree = self.db.file_item_tree(file_id);
|
||||
let mod_dir = self.mod_dirs[&directive.module_id].clone();
|
||||
self.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
|
||||
ModCollector {
|
||||
def_collector: &mut *self,
|
||||
macro_depth: directive.depth,
|
||||
module_id: directive.module_id,
|
||||
tree_id: TreeId::new(file_id, None),
|
||||
item_tree: &item_tree,
|
||||
mod_dir,
|
||||
}
|
||||
.collect(&[*mod_item]);
|
||||
return recollect_without(self, &item_tree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the original directive since we resolved it.
|
||||
let def = resolver(ast_id.path.clone()).filter(MacroDefId::is_attribute);
|
||||
if matches!(
|
||||
def,
|
||||
Some(MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. })
|
||||
if expander.is_derive()
|
||||
) {
|
||||
// Resolved to `#[derive]`
|
||||
let file_id = ast_id.ast_id.file_id;
|
||||
let item_tree = self.db.file_item_tree(file_id);
|
||||
|
||||
let ast_id: FileAstId<ast::Item> = match *mod_item {
|
||||
ModItem::Struct(it) => item_tree[it].ast_id.upcast(),
|
||||
ModItem::Union(it) => item_tree[it].ast_id.upcast(),
|
||||
ModItem::Enum(it) => item_tree[it].ast_id.upcast(),
|
||||
_ => {
|
||||
// Cannot use derive on this item.
|
||||
// FIXME: diagnose
|
||||
res = ReachedFixedPoint::No;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
match attr.parse_derive() {
|
||||
Some(derive_macros) => {
|
||||
for path in derive_macros {
|
||||
let ast_id = AstIdWithPath::new(file_id, ast_id, path);
|
||||
self.unresolved_macros.push(MacroDirective {
|
||||
module_id: directive.module_id,
|
||||
depth: directive.depth + 1,
|
||||
kind: MacroDirectiveKind::Derive {
|
||||
ast_id,
|
||||
derive_attr: attr.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// FIXME: diagnose
|
||||
tracing::debug!("malformed derive: {:?}", attr);
|
||||
}
|
||||
}
|
||||
|
||||
return recollect_without(self, &item_tree);
|
||||
}
|
||||
|
||||
if !self.db.enable_proc_attr_macros() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not resolved to a derive helper, so try to resolve as a macro.
|
||||
match attr_macro_as_call_id(
|
||||
ast_id,
|
||||
attr,
|
||||
self.db,
|
||||
self.def_map.krate,
|
||||
&resolver,
|
||||
) {
|
||||
// Not resolved to a derive helper or the derive attribute, so try to resolve as a normal attribute.
|
||||
match attr_macro_as_call_id(ast_id, attr, self.db, self.def_map.krate, def) {
|
||||
Ok(call_id) => {
|
||||
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id);
|
||||
|
||||
// Skip #[test]/#[bench] expansion, which would merely result in more memory usage
|
||||
// due to duplicating functions into macro expansions
|
||||
if is_builtin_test_or_bench_attr(loc.def) {
|
||||
let file_id = ast_id.ast_id.file_id;
|
||||
if matches!(
|
||||
loc.def.kind,
|
||||
MacroDefKind::BuiltInAttr(expander, _)
|
||||
if expander.is_test() || expander.is_bench()
|
||||
) {
|
||||
let item_tree = self.db.file_item_tree(file_id);
|
||||
let mod_dir = self.mod_dirs[&directive.module_id].clone();
|
||||
self.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
|
||||
ModCollector {
|
||||
def_collector: &mut *self,
|
||||
macro_depth: directive.depth,
|
||||
module_id: directive.module_id,
|
||||
tree_id: TreeId::new(file_id, None),
|
||||
item_tree: &item_tree,
|
||||
mod_dir,
|
||||
}
|
||||
.collect(&[*mod_item]);
|
||||
|
||||
// Remove the original directive since we resolved it.
|
||||
res = ReachedFixedPoint::No;
|
||||
return false;
|
||||
return recollect_without(self, &item_tree);
|
||||
}
|
||||
|
||||
if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind {
|
||||
@ -1171,21 +1203,7 @@ impl DefCollector<'_> {
|
||||
|
||||
let file_id = ast_id.ast_id.file_id;
|
||||
let item_tree = self.db.file_item_tree(file_id);
|
||||
let mod_dir = self.mod_dirs[&directive.module_id].clone();
|
||||
self.skip_attrs
|
||||
.insert(InFile::new(file_id, *mod_item), attr.id);
|
||||
ModCollector {
|
||||
def_collector: &mut *self,
|
||||
macro_depth: directive.depth,
|
||||
module_id: directive.module_id,
|
||||
tree_id: TreeId::new(file_id, None),
|
||||
item_tree: &item_tree,
|
||||
mod_dir,
|
||||
}
|
||||
.collect(&[*mod_item]);
|
||||
|
||||
// Remove the macro directive.
|
||||
return false;
|
||||
return recollect_without(self, &item_tree);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1281,7 +1299,7 @@ impl DefCollector<'_> {
|
||||
for directive in &self.unresolved_macros {
|
||||
match &directive.kind {
|
||||
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
||||
match macro_call_as_call_id(
|
||||
let macro_call_as_call_id = macro_call_as_call_id(
|
||||
ast_id,
|
||||
*expand_to,
|
||||
self.db,
|
||||
@ -1297,15 +1315,13 @@ impl DefCollector<'_> {
|
||||
resolved_res.resolved_def.take_macros()
|
||||
},
|
||||
&mut |_| (),
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(UnresolvedMacro { path }) => {
|
||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
||||
directive.module_id,
|
||||
ast_id.ast_id,
|
||||
path,
|
||||
));
|
||||
}
|
||||
);
|
||||
if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
|
||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
||||
directive.module_id,
|
||||
ast_id.ast_id,
|
||||
path,
|
||||
));
|
||||
}
|
||||
}
|
||||
MacroDirectiveKind::Derive { .. } | MacroDirectiveKind::Attr { .. } => {
|
||||
@ -1747,26 +1763,23 @@ impl ModCollector<'_, '_> {
|
||||
});
|
||||
|
||||
for attr in iter {
|
||||
if attr.path.as_ident() == Some(&hir_expand::name![derive]) {
|
||||
self.collect_derive(attr, mod_item);
|
||||
} else if self.is_builtin_or_registered_attr(&attr.path) {
|
||||
if self.is_builtin_or_registered_attr(&attr.path) {
|
||||
continue;
|
||||
} else {
|
||||
tracing::debug!("non-builtin attribute {}", attr.path);
|
||||
|
||||
let ast_id = AstIdWithPath::new(
|
||||
self.file_id(),
|
||||
mod_item.ast_id(self.item_tree),
|
||||
attr.path.as_ref().clone(),
|
||||
);
|
||||
self.def_collector.unresolved_macros.push(MacroDirective {
|
||||
module_id: self.module_id,
|
||||
depth: self.macro_depth + 1,
|
||||
kind: MacroDirectiveKind::Attr { ast_id, attr: attr.clone(), mod_item },
|
||||
});
|
||||
|
||||
return Err(());
|
||||
}
|
||||
tracing::debug!("non-builtin attribute {}", attr.path);
|
||||
|
||||
let ast_id = AstIdWithPath::new(
|
||||
self.file_id(),
|
||||
mod_item.ast_id(self.item_tree),
|
||||
attr.path.as_ref().clone(),
|
||||
);
|
||||
self.def_collector.unresolved_macros.push(MacroDirective {
|
||||
module_id: self.module_id,
|
||||
depth: self.macro_depth + 1,
|
||||
kind: MacroDirectiveKind::Attr { ast_id, attr: attr.clone(), mod_item },
|
||||
});
|
||||
|
||||
return Err(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1800,36 +1813,6 @@ impl ModCollector<'_, '_> {
|
||||
false
|
||||
}
|
||||
|
||||
fn collect_derive(&mut self, attr: &Attr, mod_item: ModItem) {
|
||||
let ast_id: FileAstId<ast::Item> = match mod_item {
|
||||
ModItem::Struct(it) => self.item_tree[it].ast_id.upcast(),
|
||||
ModItem::Union(it) => self.item_tree[it].ast_id.upcast(),
|
||||
ModItem::Enum(it) => self.item_tree[it].ast_id.upcast(),
|
||||
_ => {
|
||||
// Cannot use derive on this item.
|
||||
// FIXME: diagnose
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match attr.parse_derive() {
|
||||
Some(derive_macros) => {
|
||||
for path in derive_macros {
|
||||
let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path);
|
||||
self.def_collector.unresolved_macros.push(MacroDirective {
|
||||
module_id: self.module_id,
|
||||
depth: self.macro_depth + 1,
|
||||
kind: MacroDirectiveKind::Derive { ast_id, derive_attr: attr.id },
|
||||
});
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// FIXME: diagnose
|
||||
tracing::debug!("malformed derive: {:?}", attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If `attrs` registers a procedural macro, collects its definition.
|
||||
fn collect_proc_macro_def(&mut self, func_name: &Name, ast_id: AstId<ast::Fn>, attrs: &Attrs) {
|
||||
// FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere
|
||||
|
@ -669,19 +669,20 @@ pub struct bar;
|
||||
fn expand_derive() {
|
||||
let map = compute_crate_def_map(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core
|
||||
use core::Copy;
|
||||
//- /main.rs crate:main deps:core
|
||||
use core::Copy;
|
||||
|
||||
#[derive(Copy, core::Clone)]
|
||||
struct Foo;
|
||||
#[core::derive(Copy, core::Clone)]
|
||||
struct Foo;
|
||||
|
||||
//- /core.rs crate:core
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Copy {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
"#,
|
||||
//- /core.rs crate:core
|
||||
#[rustc_builtin_macro]
|
||||
pub macro derive($item:item) {}
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Copy {}
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
"#,
|
||||
);
|
||||
assert_eq!(map.modules[map.root].scope.impls().len(), 2);
|
||||
}
|
||||
@ -712,17 +713,19 @@ fn builtin_derive_with_unresolved_attributes_fall_back() {
|
||||
cov_mark::check!(unresolved_attribute_fallback);
|
||||
let map = compute_crate_def_map(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core
|
||||
use core::Clone;
|
||||
//- /main.rs crate:main deps:core
|
||||
use core::{Clone, derive};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[unresolved]
|
||||
struct Foo;
|
||||
#[derive(Clone)]
|
||||
#[unresolved]
|
||||
struct Foo;
|
||||
|
||||
//- /core.rs crate:core
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
"#,
|
||||
//- /core.rs crate:core
|
||||
#[rustc_builtin_macro]
|
||||
pub macro derive($item:item) {}
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
"#,
|
||||
);
|
||||
assert_eq!(map.modules[map.root].scope.impls().len(), 1);
|
||||
}
|
||||
@ -799,6 +802,9 @@ fn resolves_derive_helper() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:proc
|
||||
#[rustc_builtin_macro]
|
||||
pub macro derive($item:item) {}
|
||||
|
||||
#[derive(proc::Derive)]
|
||||
#[helper]
|
||||
#[unresolved]
|
||||
@ -811,6 +817,7 @@ fn derive() {}
|
||||
expect![[r#"
|
||||
crate
|
||||
S: t v
|
||||
derive: m
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -36,6 +36,18 @@ macro_rules! register_builtin {
|
||||
};
|
||||
}
|
||||
|
||||
impl BuiltinAttrExpander {
|
||||
pub fn is_derive(self) -> bool {
|
||||
matches!(self, BuiltinAttrExpander::Derive)
|
||||
}
|
||||
pub fn is_test(self) -> bool {
|
||||
matches!(self, BuiltinAttrExpander::Test)
|
||||
}
|
||||
pub fn is_bench(self) -> bool {
|
||||
matches!(self, BuiltinAttrExpander::Bench)
|
||||
}
|
||||
}
|
||||
|
||||
register_builtin! {
|
||||
(bench, Bench) => dummy_attr_expand,
|
||||
(cfg_accessible, CfgAccessible) => dummy_attr_expand,
|
||||
@ -46,16 +58,6 @@ register_builtin! {
|
||||
(test_case, TestCase) => dummy_attr_expand
|
||||
}
|
||||
|
||||
pub fn is_builtin_test_or_bench_attr(makro: MacroDefId) -> bool {
|
||||
match makro.kind {
|
||||
MacroDefKind::BuiltInAttr(expander, ..) => {
|
||||
BuiltinAttrExpander::find_by_name(&name!(test)) == Some(expander)
|
||||
|| BuiltinAttrExpander::find_by_name(&name!(bench)) == Some(expander)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_builtin_attr(
|
||||
ident: &name::Name,
|
||||
krate: CrateId,
|
||||
|
@ -974,61 +974,12 @@ fn infer_builtin_macros_env() {
|
||||
fn infer_derive_clone_simple() {
|
||||
check_types(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core
|
||||
//- minicore: derive, clone
|
||||
#[derive(Clone)]
|
||||
struct S;
|
||||
fn test() {
|
||||
S.clone();
|
||||
} //^^^^^^^^^ S
|
||||
|
||||
//- /lib.rs crate:core
|
||||
pub mod prelude {
|
||||
pub mod rust_2018 {
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
pub use crate::clone::Clone;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod clone {
|
||||
pub trait Clone {
|
||||
fn clone(&self) -> Self;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_derive_clone_in_core() {
|
||||
check_types(
|
||||
r#"
|
||||
//- /lib.rs crate:core
|
||||
#[prelude_import]
|
||||
use prelude::rust_2018::*;
|
||||
|
||||
pub mod prelude {
|
||||
pub mod rust_2018 {
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
pub use crate::clone::Clone;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod clone {
|
||||
pub trait Clone {
|
||||
fn clone(&self) -> Self;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct S;
|
||||
|
||||
//- /main.rs crate:main deps:core
|
||||
use core::S;
|
||||
fn test() {
|
||||
S.clone();
|
||||
} //^^^^^^^^^ S
|
||||
"#,
|
||||
);
|
||||
}
|
||||
@ -1037,7 +988,7 @@ fn test() {
|
||||
fn infer_derive_clone_with_params() {
|
||||
check_types(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core
|
||||
//- minicore: clone, derive
|
||||
#[derive(Clone)]
|
||||
struct S;
|
||||
#[derive(Clone)]
|
||||
@ -1048,21 +999,6 @@ fn test() {
|
||||
x;
|
||||
//^ (Wrapper<S>, {unknown})
|
||||
}
|
||||
|
||||
//- /lib.rs crate:core
|
||||
pub mod prelude {
|
||||
pub mod rust_2018 {
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
pub use crate::clone::Clone;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod clone {
|
||||
pub trait Clone {
|
||||
fn clone(&self) -> Self;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
@ -1072,7 +1008,7 @@ fn infer_custom_derive_simple() {
|
||||
// FIXME: this test current now do nothing
|
||||
check_types(
|
||||
r#"
|
||||
//- /main.rs crate:main
|
||||
//- minicore: derive
|
||||
use foo::Foo;
|
||||
|
||||
#[derive(Foo)]
|
||||
|
@ -367,9 +367,7 @@ fn main() {
|
||||
check(
|
||||
r#"
|
||||
//- proc_macros: identity
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
//- minicore: clone, derive
|
||||
|
||||
#[proc_macros::identity]
|
||||
#[derive(C$0lone)]
|
||||
@ -377,7 +375,7 @@ struct Foo {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Clone
|
||||
impl< >crate::clone::Clone for Foo< >{}
|
||||
impl< >core::clone::Clone for Foo< >{}
|
||||
|
||||
"#]],
|
||||
);
|
||||
@ -387,10 +385,7 @@ struct Foo {}
|
||||
fn macro_expand_derive2() {
|
||||
check(
|
||||
r#"
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Copy {}
|
||||
//- minicore: copy, clone, derive
|
||||
|
||||
#[derive(Cop$0y)]
|
||||
#[derive(Clone)]
|
||||
@ -398,7 +393,7 @@ struct Foo {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Copy
|
||||
impl< >crate::marker::Copy for Foo< >{}
|
||||
impl< >core::marker::Copy for Foo< >{}
|
||||
|
||||
"#]],
|
||||
);
|
||||
@ -408,19 +403,16 @@ struct Foo {}
|
||||
fn macro_expand_derive_multi() {
|
||||
check(
|
||||
r#"
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Copy {}
|
||||
//- minicore: copy, clone, derive
|
||||
|
||||
#[derive(Cop$0y, Clone)]
|
||||
struct Foo {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
Copy, Clone
|
||||
impl< >crate::marker::Copy for Foo< >{}
|
||||
impl< >core::marker::Copy for Foo< >{}
|
||||
|
||||
impl< >crate::clone::Clone for Foo< >{}
|
||||
impl< >core::clone::Clone for Foo< >{}
|
||||
|
||||
"#]],
|
||||
);
|
||||
|
@ -805,6 +805,9 @@ bar = {path = "../bar"}
|
||||
|
||||
//- /foo/src/main.rs
|
||||
use bar::Bar;
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro derive($item:item) {}
|
||||
trait Bar {
|
||||
fn bar();
|
||||
}
|
||||
@ -875,7 +878,7 @@ pub fn foo(_input: TokenStream) -> TokenStream {
|
||||
let res = server.send_request::<HoverRequest>(HoverParams {
|
||||
text_document_position_params: TextDocumentPositionParams::new(
|
||||
server.doc_id("foo/src/main.rs"),
|
||||
Position::new(7, 9),
|
||||
Position::new(10, 9),
|
||||
),
|
||||
work_done_progress_params: Default::default(),
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user