8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
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 ;
15
14
use ext:: build:: AstBuilder ;
16
15
use symbol:: Symbol ;
17
16
use syntax_pos:: Span ;
18
17
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| {
41
21
if attr. name ( ) != "derive" {
42
- continue ;
22
+ return true ;
43
23
}
44
24
45
25
if attr. value_str ( ) . is_some ( ) {
46
26
cx. span_err ( attr. span , "unexpected value in `derive`" ) ;
27
+ return false ;
47
28
}
48
29
49
30
let traits = attr. meta_item_list ( ) . unwrap_or ( & [ ] ) . to_owned ( ) ;
50
-
51
31
if traits. is_empty ( ) {
52
32
cx. span_warn ( attr. span , "empty trait list in `derive`" ) ;
53
- attr:: mark_used ( & attr) ;
54
- continue ;
33
+ return false ;
55
34
}
35
+
56
36
for titem in traits {
57
37
if titem. word ( ) . is_none ( ) {
58
38
cx. span_err ( titem. span , "malformed `derive` entry" ) ;
39
+ return false ;
59
40
}
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 ) ) ;
112
42
}
113
43
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
129
47
}
130
48
131
49
fn 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 {
142
60
}
143
61
}
144
62
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
183
83
} )
184
84
}
0 commit comments