@@ -5,8 +5,8 @@ use crate::syntax::Atom::{self, *};
5
5
use crate :: syntax:: { cfg, Derive , Doc , ForeignName } ;
6
6
use proc_macro2:: { Ident , TokenStream } ;
7
7
use quote:: ToTokens ;
8
- use syn:: parse:: { Nothing , Parse , ParseStream , Parser as _ } ;
9
- use syn:: { parenthesized , token , Attribute , Error , LitStr , Path , Result , Token } ;
8
+ use syn:: parse:: ParseStream ;
9
+ use syn:: { Attribute , Error , Expr , Lit , LitStr , Meta , Path , Result , Token } ;
10
10
11
11
// Intended usage:
12
12
//
@@ -47,8 +47,9 @@ pub struct Parser<'a> {
47
47
pub fn parse ( cx : & mut Errors , attrs : Vec < Attribute > , mut parser : Parser ) -> OtherAttrs {
48
48
let mut passthrough_attrs = Vec :: new ( ) ;
49
49
for attr in attrs {
50
- if attr. path . is_ident ( "doc" ) {
51
- match parse_doc_attribute. parse2 ( attr. tokens . clone ( ) ) {
50
+ let attr_path = attr. path ( ) ;
51
+ if attr_path. is_ident ( "doc" ) {
52
+ match parse_doc_attribute ( & attr. meta ) {
52
53
Ok ( attr) => {
53
54
if let Some ( doc) = & mut parser. doc {
54
55
match attr {
@@ -63,7 +64,7 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
63
64
break ;
64
65
}
65
66
}
66
- } else if attr . path . is_ident ( "derive" ) {
67
+ } else if attr_path . is_ident ( "derive" ) {
67
68
match attr. parse_args_with ( |attr : ParseStream | parse_derive_attribute ( cx, attr) ) {
68
69
Ok ( attr) => {
69
70
if let Some ( derives) = & mut parser. derives {
@@ -76,7 +77,7 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
76
77
break ;
77
78
}
78
79
}
79
- } else if attr . path . is_ident ( "repr" ) {
80
+ } else if attr_path . is_ident ( "repr" ) {
80
81
match attr. parse_args_with ( parse_repr_attribute) {
81
82
Ok ( attr) => {
82
83
if let Some ( repr) = & mut parser. repr {
@@ -89,8 +90,8 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
89
90
break ;
90
91
}
91
92
}
92
- } else if attr . path . is_ident ( "namespace" ) {
93
- match parse_namespace_attribute . parse2 ( attr. tokens . clone ( ) ) {
93
+ } else if attr_path . is_ident ( "namespace" ) {
94
+ match Namespace :: parse_meta ( & attr. meta ) {
94
95
Ok ( attr) => {
95
96
if let Some ( namespace) = & mut parser. namespace {
96
97
* * namespace = attr;
@@ -102,8 +103,8 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
102
103
break ;
103
104
}
104
105
}
105
- } else if attr . path . is_ident ( "cxx_name" ) {
106
- match parse_cxx_name_attribute. parse2 ( attr. tokens . clone ( ) ) {
106
+ } else if attr_path . is_ident ( "cxx_name" ) {
107
+ match parse_cxx_name_attribute ( & attr. meta ) {
107
108
Ok ( attr) => {
108
109
if let Some ( cxx_name) = & mut parser. cxx_name {
109
110
* * cxx_name = Some ( attr) ;
@@ -115,8 +116,8 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
115
116
break ;
116
117
}
117
118
}
118
- } else if attr . path . is_ident ( "rust_name" ) {
119
- match parse_rust_name_attribute. parse2 ( attr. tokens . clone ( ) ) {
119
+ } else if attr_path . is_ident ( "rust_name" ) {
120
+ match parse_rust_name_attribute ( & attr. meta ) {
120
121
Ok ( attr) => {
121
122
if let Some ( rust_name) = & mut parser. rust_name {
122
123
* * rust_name = Some ( attr) ;
@@ -128,8 +129,8 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
128
129
break ;
129
130
}
130
131
}
131
- } else if attr . path . is_ident ( "cfg" ) {
132
- match cfg:: parse_attribute. parse2 ( attr. tokens . clone ( ) ) {
132
+ } else if attr_path . is_ident ( "cfg" ) {
133
+ match cfg:: parse_attribute ( & attr) {
133
134
Ok ( cfg_expr) => {
134
135
if let Some ( cfg) = & mut parser. cfg {
135
136
cfg. merge ( cfg_expr) ;
@@ -142,31 +143,31 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
142
143
break ;
143
144
}
144
145
}
145
- } else if attr . path . is_ident ( "variants_from_header" )
146
+ } else if attr_path . is_ident ( "variants_from_header" )
146
147
&& cfg ! ( feature = "experimental-enum-variants-from-header" )
147
148
{
148
- if let Err ( err) = Nothing :: parse . parse2 ( attr. tokens . clone ( ) ) {
149
+ if let Err ( err) = require_empty_attribute ( & attr. meta ) {
149
150
cx. push ( err) ;
150
151
}
151
152
if let Some ( variants_from_header) = & mut parser. variants_from_header {
152
153
* * variants_from_header = Some ( attr) ;
153
154
continue ;
154
155
}
155
- } else if attr . path . is_ident ( "allow" )
156
- || attr . path . is_ident ( "warn" )
157
- || attr . path . is_ident ( "deny" )
158
- || attr . path . is_ident ( "forbid" )
159
- || attr . path . is_ident ( "deprecated" )
160
- || attr . path . is_ident ( "must_use" )
156
+ } else if attr_path . is_ident ( "allow" )
157
+ || attr_path . is_ident ( "warn" )
158
+ || attr_path . is_ident ( "deny" )
159
+ || attr_path . is_ident ( "forbid" )
160
+ || attr_path . is_ident ( "deprecated" )
161
+ || attr_path . is_ident ( "must_use" )
161
162
{
162
163
// https://doc.rust-lang.org/reference/attributes/diagnostics.html
163
164
passthrough_attrs. push ( attr) ;
164
165
continue ;
165
- } else if attr . path . is_ident ( "serde" ) {
166
+ } else if attr_path . is_ident ( "serde" ) {
166
167
passthrough_attrs. push ( attr) ;
167
168
continue ;
168
- } else if attr . path . segments . len ( ) > 1 {
169
- let tool = & attr . path . segments . first ( ) . unwrap ( ) . ident ;
169
+ } else if attr_path . segments . len ( ) > 1 {
170
+ let tool = & attr_path . segments . first ( ) . unwrap ( ) . ident ;
170
171
if tool == "rustfmt" {
171
172
// Skip, rustfmt only needs to find it in the pre-expansion source file.
172
173
continue ;
@@ -192,24 +193,26 @@ mod kw {
192
193
syn:: custom_keyword!( hidden) ;
193
194
}
194
195
195
- fn parse_doc_attribute ( input : ParseStream ) -> Result < DocAttribute > {
196
- let lookahead = input. lookahead1 ( ) ;
197
- if lookahead. peek ( Token ! [ =] ) {
198
- input. parse :: < Token ! [ =] > ( ) ?;
199
- let lit: LitStr = input. parse ( ) ?;
200
- Ok ( DocAttribute :: Doc ( lit) )
201
- } else if lookahead. peek ( token:: Paren ) {
202
- let content;
203
- parenthesized ! ( content in input) ;
204
- content. parse :: < kw:: hidden > ( ) ?;
205
- Ok ( DocAttribute :: Hidden )
206
- } else {
207
- Err ( lookahead. error ( ) )
196
+ fn parse_doc_attribute ( meta : & Meta ) -> Result < DocAttribute > {
197
+ match meta {
198
+ Meta :: NameValue ( meta) => {
199
+ if let Expr :: Lit ( expr) = & meta. value {
200
+ if let Lit :: Str ( lit) = & expr. lit {
201
+ return Ok ( DocAttribute :: Doc ( lit. clone ( ) ) ) ;
202
+ }
203
+ }
204
+ }
205
+ Meta :: List ( meta) => {
206
+ meta. parse_args :: < kw:: hidden > ( ) ?;
207
+ return Ok ( DocAttribute :: Hidden ) ;
208
+ }
209
+ Meta :: Path ( _) => { }
208
210
}
211
+ Err ( Error :: new_spanned ( meta, "unsupported doc attribute" ) )
209
212
}
210
213
211
214
fn parse_derive_attribute ( cx : & mut Errors , input : ParseStream ) -> Result < Vec < Derive > > {
212
- let paths = input. parse_terminated :: < Path , Token ! [ , ] > ( Path :: parse_mod_style ) ?;
215
+ let paths = input. parse_terminated ( Path :: parse_mod_style , Token ! [ , ] ) ?;
213
216
214
217
let mut derives = Vec :: new ( ) ;
215
218
for path in paths {
@@ -241,31 +244,42 @@ fn parse_repr_attribute(input: ParseStream) -> Result<Atom> {
241
244
) )
242
245
}
243
246
244
- fn parse_namespace_attribute ( input : ParseStream ) -> Result < Namespace > {
245
- input. parse :: < Token ! [ =] > ( ) ?;
246
- let namespace = input. parse :: < Namespace > ( ) ?;
247
- Ok ( namespace)
248
- }
249
-
250
- fn parse_cxx_name_attribute ( input : ParseStream ) -> Result < ForeignName > {
251
- input. parse :: < Token ! [ =] > ( ) ?;
252
- if input. peek ( LitStr ) {
253
- let lit: LitStr = input. parse ( ) ?;
254
- ForeignName :: parse ( & lit. value ( ) , lit. span ( ) )
255
- } else {
256
- let ident: Ident = input. parse ( ) ?;
257
- ForeignName :: parse ( & ident. to_string ( ) , ident. span ( ) )
247
+ fn parse_cxx_name_attribute ( meta : & Meta ) -> Result < ForeignName > {
248
+ if let Meta :: NameValue ( meta) = meta {
249
+ match & meta. value {
250
+ Expr :: Lit ( expr) => {
251
+ if let Lit :: Str ( lit) = & expr. lit {
252
+ return ForeignName :: parse ( & lit. value ( ) , lit. span ( ) ) ;
253
+ }
254
+ }
255
+ Expr :: Path ( expr) => {
256
+ if let Some ( ident) = expr. path . get_ident ( ) {
257
+ return ForeignName :: parse ( & ident. to_string ( ) , ident. span ( ) ) ;
258
+ }
259
+ }
260
+ _ => { }
261
+ }
258
262
}
263
+ Err ( Error :: new_spanned ( meta, "unsupported cxx_name attribute" ) )
259
264
}
260
265
261
- fn parse_rust_name_attribute ( input : ParseStream ) -> Result < Ident > {
262
- input. parse :: < Token ! [ =] > ( ) ?;
263
- if input. peek ( LitStr ) {
264
- let lit: LitStr = input. parse ( ) ?;
265
- lit. parse ( )
266
- } else {
267
- input. parse ( )
266
+ fn parse_rust_name_attribute ( meta : & Meta ) -> Result < Ident > {
267
+ if let Meta :: NameValue ( meta) = meta {
268
+ match & meta. value {
269
+ Expr :: Lit ( expr) => {
270
+ if let Lit :: Str ( lit) = & expr. lit {
271
+ return lit. parse ( ) ;
272
+ }
273
+ }
274
+ Expr :: Path ( expr) => {
275
+ if let Some ( ident) = expr. path . get_ident ( ) {
276
+ return Ok ( ident. clone ( ) ) ;
277
+ }
278
+ }
279
+ _ => { }
280
+ }
268
281
}
282
+ Err ( Error :: new_spanned ( meta, "unsupported rust_name attribute" ) )
269
283
}
270
284
271
285
#[ derive( Clone ) ]
@@ -288,15 +302,20 @@ impl ToTokens for OtherAttrs {
288
302
pound_token,
289
303
style,
290
304
bracket_token,
291
- path,
292
- tokens : attr_tokens,
305
+ meta,
293
306
} = attr;
294
307
pound_token. to_tokens ( tokens) ;
295
308
let _ = style; // ignore; render outer and inner attrs both as outer
296
- bracket_token. surround ( tokens, |tokens| {
297
- path. to_tokens ( tokens) ;
298
- attr_tokens. to_tokens ( tokens) ;
299
- } ) ;
309
+ bracket_token. surround ( tokens, |tokens| meta. to_tokens ( tokens) ) ;
300
310
}
301
311
}
302
312
}
313
+
314
+ fn require_empty_attribute ( meta : & Meta ) -> Result < ( ) > {
315
+ let error_span = match meta {
316
+ Meta :: Path ( _) => return Ok ( ( ) ) ,
317
+ Meta :: List ( meta) => meta. delimiter . span ( ) . open ( ) ,
318
+ Meta :: NameValue ( meta) => meta. eq_token . span ,
319
+ } ;
320
+ Err ( Error :: new ( error_span, "unexpected token in cxx attribute" ) )
321
+ }
0 commit comments