]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/derive.rs
c7fa0331c1bd5a9dc55c5f9897edf393212432de
[rust.git] / src / libsyntax / ext / derive.rs
1 // Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use attr::HasAttrs;
12 use ast;
13 use codemap::{ExpnInfo, NameAndSpan, ExpnFormat};
14 use ext::base::ExtCtxt;
15 use ext::build::AstBuilder;
16 use parse::parser::PathStyle;
17 use symbol::Symbol;
18 use syntax_pos::Span;
19
20 use std::collections::HashSet;
21
22 pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
23     let mut result = Vec::new();
24     attrs.retain(|attr| {
25         if attr.path != "derive" {
26             return true;
27         }
28
29         match attr.parse_list(cx.parse_sess,
30                               |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
31             Ok(ref traits) if traits.is_empty() => {
32                 cx.span_warn(attr.span, "empty trait list in `derive`");
33                 false
34             }
35             Ok(traits) => {
36                 result.extend(traits);
37                 true
38             }
39             Err(mut e) => {
40                 e.emit();
41                 false
42             }
43         }
44     });
45     result
46 }
47
48 pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T
49     where T: HasAttrs,
50 {
51     let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned());
52     for (i, path) in traits.iter().enumerate() {
53         if i > 0 {
54             pretty_name.push_str(", ");
55         }
56         pretty_name.push_str(&path.to_string());
57         names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name);
58     }
59     pretty_name.push(')');
60
61     cx.current_expansion.mark.set_expn_info(ExpnInfo {
62         call_site: span,
63         callee: NameAndSpan {
64             format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
65             span: None,
66             allow_internal_unstable: true,
67             allow_internal_unsafe: false,
68         },
69     });
70
71     let span = span.with_ctxt(cx.backtrace());
72     item.map_attrs(|mut attrs| {
73         if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
74             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
75             attrs.push(cx.attribute(span, meta));
76         }
77         if names.contains(&Symbol::intern("Copy")) {
78             let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
79             attrs.push(cx.attribute(span, meta));
80         }
81         attrs
82     })
83 }