88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use ast:: Name ;
12- use attr;
13- use ast:: { self , NestedMetaItem } ; use ext:: base:: { ExtCtxt , SyntaxExtension } ;
14- use codemap;
11+ use attr:: HasAttrs ;
12+ use { ast, codemap} ;
13+ use ext:: base:: ExtCtxt ;
1514use ext:: build:: AstBuilder ;
1615use symbol:: Symbol ;
1716use syntax_pos:: Span ;
1817
19- pub fn derive_attr_trait < ' a > ( cx : & mut ExtCtxt , attr : & ' a ast:: Attribute )
20- -> Option < & ' a NestedMetaItem > {
21- if attr. name ( ) != "derive" {
22- return None ;
23- }
24- if attr. value_str ( ) . is_some ( ) {
25- cx. span_err ( attr. span , "unexpected value in `derive`" ) ;
26- return None ;
27- }
28-
29- let traits = attr. meta_item_list ( ) . unwrap_or ( & [ ] ) ;
30-
31- if traits. is_empty ( ) {
32- cx. span_warn ( attr. span , "empty trait list in `derive`" ) ;
33- return None ;
34- }
35-
36- return traits. get ( 0 ) ;
37- }
38-
39- pub fn verify_derive_attrs ( cx : & mut ExtCtxt , attrs : & [ ast:: Attribute ] ) {
40- for attr in attrs {
18+ pub fn collect_derives ( cx : & mut ExtCtxt , attrs : & mut Vec < ast:: Attribute > ) -> Vec < ( Symbol , Span ) > {
19+ let mut result = Vec :: new ( ) ;
20+ attrs. retain ( |attr| {
4121 if attr. name ( ) != "derive" {
42- continue ;
22+ return true ;
4323 }
4424
4525 if attr. value_str ( ) . is_some ( ) {
4626 cx. span_err ( attr. span , "unexpected value in `derive`" ) ;
27+ return false ;
4728 }
4829
4930 let traits = attr. meta_item_list ( ) . unwrap_or ( & [ ] ) . to_owned ( ) ;
50-
5131 if traits. is_empty ( ) {
5232 cx. span_warn ( attr. span , "empty trait list in `derive`" ) ;
53- attr:: mark_used ( & attr) ;
54- continue ;
33+ return false ;
5534 }
35+
5636 for titem in traits {
5737 if titem. word ( ) . is_none ( ) {
5838 cx. span_err ( titem. span , "malformed `derive` entry" ) ;
39+ return false ;
5940 }
60- }
61- }
62- }
63-
64- #[ derive( PartialEq , Debug , Clone , Copy ) ]
65- pub enum DeriveType {
66- ProcMacro ,
67- Builtin
68- }
69-
70- impl DeriveType {
71- // Classify a derive trait name by resolving the macro.
72- pub fn classify ( cx : & mut ExtCtxt , tname : Name ) -> DeriveType {
73- match cx. resolver . resolve_builtin_macro ( tname) {
74- Ok ( ext) => match * ext {
75- SyntaxExtension :: BuiltinDerive ( ..) => DeriveType :: Builtin ,
76- _ => DeriveType :: ProcMacro ,
77- } ,
78- Err ( _) => DeriveType :: ProcMacro ,
79- }
80- }
81- }
82-
83- pub fn get_derive_attr ( cx : & mut ExtCtxt , attrs : & mut Vec < ast:: Attribute > ,
84- derive_type : DeriveType ) -> Option < ast:: Attribute > {
85- for i in 0 ..attrs. len ( ) {
86- if attrs[ i] . name ( ) != "derive" {
87- continue ;
88- }
89-
90- if attrs[ i] . value_str ( ) . is_some ( ) {
91- continue ;
92- }
93-
94- let mut traits = attrs[ i] . meta_item_list ( ) . unwrap_or ( & [ ] ) . to_owned ( ) ;
95-
96- // First, weed out malformed #[derive]
97- traits. retain ( |titem| titem. word ( ) . is_some ( ) ) ;
98-
99- let mut titem = None ;
100-
101- // See if we can find a matching trait.
102- for j in 0 ..traits. len ( ) {
103- let tname = match traits[ j] . name ( ) {
104- Some ( tname) => tname,
105- _ => continue ,
106- } ;
107-
108- if DeriveType :: classify ( cx, tname) == derive_type {
109- titem = Some ( traits. remove ( j) ) ;
110- break ;
111- }
41+ result. push ( ( titem. name ( ) . unwrap ( ) , titem. span ) ) ;
11242 }
11343
114- // If we find a trait, remove the trait from the attribute.
115- if let Some ( titem) = titem {
116- if traits. len ( ) == 0 {
117- attrs. remove ( i) ;
118- } else {
119- let derive = Symbol :: intern ( "derive" ) ;
120- let mitem = cx. meta_list ( titem. span , derive, traits) ;
121- attrs[ i] = cx. attribute ( titem. span , mitem) ;
122- }
123- let derive = Symbol :: intern ( "derive" ) ;
124- let mitem = cx. meta_list ( titem. span , derive, vec ! [ titem] ) ;
125- return Some ( cx. attribute ( mitem. span , mitem) ) ;
126- }
127- }
128- return None ;
44+ true
45+ } ) ;
46+ result
12947}
13048
13149fn allow_unstable ( cx : & mut ExtCtxt , span : Span , attr_name : & str ) -> Span {
@@ -142,43 +60,25 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
14260 }
14361}
14462
145- pub fn add_derived_markers ( cx : & mut ExtCtxt , attrs : & mut Vec < ast:: Attribute > ) {
146- if attrs. is_empty ( ) {
147- return ;
148- }
149-
150- let titems = attrs. iter ( ) . filter ( |a| {
151- a. name ( ) == "derive"
152- } ) . flat_map ( |a| {
153- a. meta_item_list ( ) . unwrap_or ( & [ ] ) . iter ( )
154- } ) . filter_map ( |titem| {
155- titem. name ( )
156- } ) . collect :: < Vec < _ > > ( ) ;
157-
158- let span = attrs[ 0 ] . span ;
159-
160- if !attrs. iter ( ) . any ( |a| a. name ( ) == "structural_match" ) &&
161- titems. iter ( ) . any ( |t| * t == "PartialEq" ) && titems. iter ( ) . any ( |t| * t == "Eq" ) {
162- let structural_match = Symbol :: intern ( "structural_match" ) ;
163- let span = allow_unstable ( cx, span, "derive(PartialEq, Eq)" ) ;
164- let meta = cx. meta_word ( span, structural_match) ;
165- attrs. push ( cx. attribute ( span, meta) ) ;
166- }
167-
168- if !attrs. iter ( ) . any ( |a| a. name ( ) == "rustc_copy_clone_marker" ) &&
169- titems. iter ( ) . any ( |t| * t == "Copy" ) && titems. iter ( ) . any ( |t| * t == "Clone" ) {
170- let structural_match = Symbol :: intern ( "rustc_copy_clone_marker" ) ;
171- let span = allow_unstable ( cx, span, "derive(Copy, Clone)" ) ;
172- let meta = cx. meta_word ( span, structural_match) ;
173- attrs. push ( cx. attribute ( span, meta) ) ;
174- }
175- }
176-
177- pub fn find_derive_attr ( cx : & mut ExtCtxt , attrs : & mut Vec < ast:: Attribute > )
178- -> Option < ast:: Attribute > {
179- verify_derive_attrs ( cx, attrs) ;
180- get_derive_attr ( cx, attrs, DeriveType :: ProcMacro ) . or_else ( || {
181- add_derived_markers ( cx, attrs) ;
182- get_derive_attr ( cx, attrs, DeriveType :: Builtin )
63+ pub fn add_derived_markers < T : HasAttrs > ( cx : & mut ExtCtxt , traits : & [ ( Symbol , Span ) ] , item : T ) -> T {
64+ let span = match traits. get ( 0 ) {
65+ Some ( & ( _, span) ) => span,
66+ None => return item,
67+ } ;
68+
69+ item. map_attrs ( |mut attrs| {
70+ if traits. iter ( ) . any ( |& ( name, _) | name == "PartialEq" ) &&
71+ traits. iter ( ) . any ( |& ( name, _) | name == "Eq" ) {
72+ let span = allow_unstable ( cx, span, "derive(PartialEq, Eq)" ) ;
73+ let meta = cx. meta_word ( span, Symbol :: intern ( "structural_match" ) ) ;
74+ attrs. push ( cx. attribute ( span, meta) ) ;
75+ }
76+ if traits. iter ( ) . any ( |& ( name, _) | name == "Copy" ) &&
77+ traits. iter ( ) . any ( |& ( name, _) | name == "Clone" ) {
78+ let span = allow_unstable ( cx, span, "derive(Copy, Clone)" ) ;
79+ let meta = cx. meta_word ( span, Symbol :: intern ( "rustc_copy_clone_marker" ) ) ;
80+ attrs. push ( cx. attribute ( span, meta) ) ;
81+ }
82+ attrs
18383 } )
18484}
0 commit comments