rust/src/libsyntax/ext/derive.rs

82 lines
2.7 KiB
Rust
Raw Normal View History

// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use attr::HasAttrs;
2017-03-16 23:04:41 -05:00
use ast;
use codemap::{ExpnInfo, NameAndSpan, ExpnFormat};
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
2017-03-08 17:13:35 -06:00
use parse::parser::PathStyle;
use symbol::Symbol;
use syntax_pos::Span;
2017-03-16 23:04:41 -05:00
use std::collections::HashSet;
2017-03-08 17:13:35 -06:00
pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
let mut result = Vec::new();
attrs.retain(|attr| {
if attr.path != "derive" {
return true;
}
2017-03-08 17:13:35 -06:00
match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) {
Ok(ref traits) if traits.is_empty() => {
cx.span_warn(attr.span, "empty trait list in `derive`");
false
}
Ok(traits) => {
result.extend(traits);
true
}
Err(mut e) => {
e.emit();
false
}
}
});
result
}
2017-03-16 23:04:41 -05:00
pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T
where T: HasAttrs,
{
let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned());
for (i, path) in traits.iter().enumerate() {
if i > 0 {
pretty_name.push_str(", ");
}
pretty_name.push_str(&path.to_string());
names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name);
}
2017-03-16 23:04:41 -05:00
pretty_name.push(')');
2017-03-16 23:04:41 -05:00
cx.current_expansion.mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
span: None,
allow_internal_unstable: true,
},
});
2017-03-16 23:04:41 -05:00
let span = Span { ctxt: cx.backtrace(), ..span };
item.map_attrs(|mut attrs| {
2017-03-16 23:04:41 -05:00
if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
let meta = cx.meta_word(span, Symbol::intern("structural_match"));
attrs.push(cx.attribute(span, meta));
}
2017-03-16 23:04:41 -05:00
if names.contains(&Symbol::intern("Copy")) && names.contains(&Symbol::intern("Clone")) {
let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
attrs.push(cx.attribute(span, meta));
}
attrs
})
}