@@ -5,8 +5,8 @@ use crate::syntax::Atom::{self, *};
55use crate :: syntax:: { cfg, Derive , Doc , ForeignName } ;
66use proc_macro2:: { Ident , TokenStream } ;
77use 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 } ;
1010
1111// Intended usage:
1212//
@@ -47,8 +47,9 @@ pub struct Parser<'a> {
4747pub fn parse ( cx : & mut Errors , attrs : Vec < Attribute > , mut parser : Parser ) -> OtherAttrs {
4848 let mut passthrough_attrs = Vec :: new ( ) ;
4949 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 ) {
5253 Ok ( attr) => {
5354 if let Some ( doc) = & mut parser. doc {
5455 match attr {
@@ -63,7 +64,7 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
6364 break ;
6465 }
6566 }
66- } else if attr . path . is_ident ( "derive" ) {
67+ } else if attr_path . is_ident ( "derive" ) {
6768 match attr. parse_args_with ( |attr : ParseStream | parse_derive_attribute ( cx, attr) ) {
6869 Ok ( attr) => {
6970 if let Some ( derives) = & mut parser. derives {
@@ -76,7 +77,7 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
7677 break ;
7778 }
7879 }
79- } else if attr . path . is_ident ( "repr" ) {
80+ } else if attr_path . is_ident ( "repr" ) {
8081 match attr. parse_args_with ( parse_repr_attribute) {
8182 Ok ( attr) => {
8283 if let Some ( repr) = & mut parser. repr {
@@ -89,8 +90,8 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
8990 break ;
9091 }
9192 }
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 ) {
9495 Ok ( attr) => {
9596 if let Some ( namespace) = & mut parser. namespace {
9697 * * namespace = attr;
@@ -102,8 +103,8 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
102103 break ;
103104 }
104105 }
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 ) {
107108 Ok ( attr) => {
108109 if let Some ( cxx_name) = & mut parser. cxx_name {
109110 * * cxx_name = Some ( attr) ;
@@ -115,8 +116,8 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
115116 break ;
116117 }
117118 }
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 ) {
120121 Ok ( attr) => {
121122 if let Some ( rust_name) = & mut parser. rust_name {
122123 * * rust_name = Some ( attr) ;
@@ -128,8 +129,8 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
128129 break ;
129130 }
130131 }
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) {
133134 Ok ( cfg_expr) => {
134135 if let Some ( cfg) = & mut parser. cfg {
135136 cfg. merge ( cfg_expr) ;
@@ -142,31 +143,31 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
142143 break ;
143144 }
144145 }
145- } else if attr . path . is_ident ( "variants_from_header" )
146+ } else if attr_path . is_ident ( "variants_from_header" )
146147 && cfg ! ( feature = "experimental-enum-variants-from-header" )
147148 {
148- if let Err ( err) = Nothing :: parse . parse2 ( attr. tokens . clone ( ) ) {
149+ if let Err ( err) = require_empty_attribute ( & attr. meta ) {
149150 cx. push ( err) ;
150151 }
151152 if let Some ( variants_from_header) = & mut parser. variants_from_header {
152153 * * variants_from_header = Some ( attr) ;
153154 continue ;
154155 }
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" )
161162 {
162163 // https://doc.rust-lang.org/reference/attributes/diagnostics.html
163164 passthrough_attrs. push ( attr) ;
164165 continue ;
165- } else if attr . path . is_ident ( "serde" ) {
166+ } else if attr_path . is_ident ( "serde" ) {
166167 passthrough_attrs. push ( attr) ;
167168 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 ;
170171 if tool == "rustfmt" {
171172 // Skip, rustfmt only needs to find it in the pre-expansion source file.
172173 continue ;
@@ -192,24 +193,26 @@ mod kw {
192193 syn:: custom_keyword!( hidden) ;
193194}
194195
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 ( _) => { }
208210 }
211+ Err ( Error :: new_spanned ( meta, "unsupported doc attribute" ) )
209212}
210213
211214fn 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 ! [ , ] ) ?;
213216
214217 let mut derives = Vec :: new ( ) ;
215218 for path in paths {
@@ -241,31 +244,42 @@ fn parse_repr_attribute(input: ParseStream) -> Result<Atom> {
241244 ) )
242245}
243246
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+ }
258262 }
263+ Err ( Error :: new_spanned ( meta, "unsupported cxx_name attribute" ) )
259264}
260265
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+ }
268281 }
282+ Err ( Error :: new_spanned ( meta, "unsupported rust_name attribute" ) )
269283}
270284
271285#[ derive( Clone ) ]
@@ -288,15 +302,20 @@ impl ToTokens for OtherAttrs {
288302 pound_token,
289303 style,
290304 bracket_token,
291- path,
292- tokens : attr_tokens,
305+ meta,
293306 } = attr;
294307 pound_token. to_tokens ( tokens) ;
295308 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) ) ;
300310 }
301311 }
302312}
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