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