3 use source_map::{hygiene, ExpnInfo, ExpnFormat};
4 use ext::base::ExtCtxt;
5 use ext::build::AstBuilder;
6 use parse::parser::PathStyle;
10 use rustc_data_structures::fx::FxHashSet;
12 pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
13 let mut result = Vec::new();
15 if attr.path != "derive" {
18 if !attr.is_meta_item_list() {
19 cx.span_err(attr.span,
20 "attribute must be of the form `#[derive(Trait1, Trait2, ...)]`");
24 match attr.parse_list(cx.parse_sess,
25 |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
26 Ok(ref traits) if traits.is_empty() => {
27 cx.span_warn(attr.span, "empty trait list in `derive`");
31 result.extend(traits);
43 pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: &mut T)
46 let (mut names, mut pretty_name) = (FxHashSet::default(), "derive(".to_owned());
47 for (i, path) in traits.iter().enumerate() {
49 pretty_name.push_str(", ");
51 pretty_name.push_str(&path.to_string());
52 names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
54 pretty_name.push(')');
56 cx.current_expansion.mark.set_expn_info(ExpnInfo {
59 format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
60 allow_internal_unstable: true,
61 allow_internal_unsafe: false,
62 local_inner_macros: false,
63 edition: hygiene::default_edition(),
66 let span = span.with_ctxt(cx.backtrace());
67 item.visit_attrs(|attrs| {
68 if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
69 let meta = cx.meta_word(span, Symbol::intern("structural_match"));
70 attrs.push(cx.attribute(span, meta));
72 if names.contains(&Symbol::intern("Copy")) {
73 let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
74 attrs.push(cx.attribute(span, meta));