]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/derive.rs
Auto merge of #62069 - Centril:rollup-m8n4uw7, r=Centril
[rust.git] / src / libsyntax / ext / derive.rs
1 use crate::attr::HasAttrs;
2 use crate::ast;
3 use crate::source_map::{ExpnInfo, ExpnFormat};
4 use crate::ext::base::ExtCtxt;
5 use crate::ext::build::AstBuilder;
6 use crate::parse::parser::PathStyle;
7 use crate::symbol::{Symbol, sym};
8 use crate::errors::Applicability;
9
10 use syntax_pos::Span;
11
12 use rustc_data_structures::fx::FxHashSet;
13
14 pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
15     let mut result = Vec::new();
16     attrs.retain(|attr| {
17         if attr.path != sym::derive {
18             return true;
19         }
20         if !attr.is_meta_item_list() {
21             cx.struct_span_err(attr.span, "malformed `derive` attribute input")
22                 .span_suggestion(
23                     attr.span,
24                     "missing traits to be derived",
25                     "#[derive(Trait1, Trait2, ...)]".to_owned(),
26                     Applicability::HasPlaceholders,
27                 ).emit();
28             return false;
29         }
30
31         match attr.parse_list(cx.parse_sess,
32                               |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
33             Ok(traits) => {
34                 result.extend(traits);
35                 true
36             }
37             Err(mut e) => {
38                 e.emit();
39                 false
40             }
41         }
42     });
43     result
44 }
45
46 pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T)
47     where T: HasAttrs,
48 {
49     let (mut names, mut pretty_name) = (FxHashSet::default(), "derive(".to_owned());
50     for (i, path) in traits.iter().enumerate() {
51         if i > 0 {
52             pretty_name.push_str(", ");
53         }
54         pretty_name.push_str(&path.to_string());
55         names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
56     }
57     pretty_name.push(')');
58
59     cx.current_expansion.mark.set_expn_info(ExpnInfo::with_unstable(
60         ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), span, cx.parse_sess.edition,
61         &[sym::rustc_attrs, sym::structural_match],
62     ));
63
64     let span = span.with_ctxt(cx.backtrace());
65     item.visit_attrs(|attrs| {
66         if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
67             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
68             attrs.push(cx.attribute(span, meta));
69         }
70         if names.contains(&Symbol::intern("Copy")) {
71             let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
72             attrs.push(cx.attribute(span, meta));
73         }
74     });
75 }