@@ -7,6 +7,7 @@ use proc_macro2::TokenStream;
77use quote:: { quote, ToTokens } ;
88use syn:: {
99 parse:: { Parse , ParseStream } ,
10+ punctuated:: Punctuated ,
1011 spanned:: Spanned as _,
1112 token,
1213} ;
@@ -20,7 +21,7 @@ use crate::common::{parse::ParseBufferExt as _, SpanContainer};
2021/// [0]: https://spec.graphql.org/October2021#sec--deprecated
2122/// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
2223/// [2]: https://spec.graphql.org/October2021#sec-Enum-Value
23- #[ derive( Debug , Default ) ]
24+ #[ derive( Debug , Default , Eq , PartialEq ) ]
2425pub ( crate ) struct Directive {
2526 /// Optional [reason][1] attached to this [deprecation][0].
2627 ///
@@ -52,16 +53,16 @@ impl Directive {
5253 attrs : & [ syn:: Attribute ] ,
5354 ) -> syn:: Result < Option < SpanContainer < Self > > > {
5455 for attr in attrs {
55- return Ok ( match attr. parse_meta ( ) {
56- Ok ( syn:: Meta :: List ( ref list) ) if list. path . is_ident ( "deprecated" ) => {
56+ return Ok ( match & attr. meta {
57+ syn:: Meta :: List ( list) if list. path . is_ident ( "deprecated" ) => {
5758 let directive = Self :: parse_from_deprecated_meta_list ( list) ?;
5859 Some ( SpanContainer :: new (
5960 list. path . span ( ) ,
6061 directive. reason . as_ref ( ) . map ( |r| r. span ( ) ) ,
6162 directive,
6263 ) )
6364 }
64- Ok ( syn:: Meta :: Path ( ref path) ) if path. is_ident ( "deprecated" ) => {
65+ syn:: Meta :: Path ( path) if path. is_ident ( "deprecated" ) => {
6566 Some ( SpanContainer :: new ( path. span ( ) , None , Self :: default ( ) ) )
6667 }
6768 _ => continue ,
@@ -77,20 +78,24 @@ impl Directive {
7778 ///
7879 /// If the `#[deprecated(note = ...)]` attribute has incorrect format.
7980 fn parse_from_deprecated_meta_list ( list : & syn:: MetaList ) -> syn:: Result < Self > {
80- for meta in & list. nested {
81- if let syn:: NestedMeta :: Meta ( syn :: Meta :: NameValue ( nv) ) = meta {
81+ for meta in list. parse_args_with ( Punctuated :: < syn :: Meta , token :: Comma > :: parse_terminated ) ? {
82+ if let syn:: Meta :: NameValue ( nv) = meta {
8283 return if !nv. path . is_ident ( "note" ) {
8384 Err ( syn:: Error :: new (
8485 nv. path . span ( ) ,
8586 "unrecognized setting on #[deprecated(..)] attribute" ,
8687 ) )
87- } else if let syn:: Lit :: Str ( strlit) = & nv. lit {
88+ } else if let syn:: Expr :: Lit ( syn:: ExprLit {
89+ lit : syn:: Lit :: Str ( strlit) ,
90+ ..
91+ } ) = & nv. value
92+ {
8893 Ok ( Self {
8994 reason : Some ( strlit. clone ( ) ) ,
9095 } )
9196 } else {
9297 Err ( syn:: Error :: new (
93- nv. lit . span ( ) ,
98+ nv. value . span ( ) ,
9499 "only strings are allowed for deprecation" ,
95100 ) )
96101 } ;
@@ -112,3 +117,43 @@ impl ToTokens for Directive {
112117 . to_tokens ( into) ;
113118 }
114119}
120+
121+ #[ cfg( test) ]
122+ mod parse_from_deprecated_attr_test {
123+ use quote:: quote;
124+ use syn:: parse_quote;
125+
126+ use super :: Directive ;
127+
128+ #[ test]
129+ fn single ( ) {
130+ let desc =
131+ Directive :: parse_from_deprecated_attr ( & [ parse_quote ! { #[ deprecated( note = "foo" ) ] } ] )
132+ . unwrap ( )
133+ . unwrap ( )
134+ . into_inner ( ) ;
135+ assert_eq ! (
136+ quote! { #desc } . to_string( ) ,
137+ quote! { . deprecated( :: core:: option:: Option :: Some ( "foo" ) ) } . to_string( ) ,
138+ ) ;
139+ }
140+
141+ #[ test]
142+ fn no_reason ( ) {
143+ let desc = Directive :: parse_from_deprecated_attr ( & [ parse_quote ! { #[ deprecated] } ] )
144+ . unwrap ( )
145+ . unwrap ( )
146+ . into_inner ( ) ;
147+ assert_eq ! (
148+ quote! { #desc } . to_string( ) ,
149+ quote! { . deprecated( :: core:: option:: Option :: None ) } . to_string( ) ,
150+ ) ;
151+ }
152+
153+ #[ test]
154+ fn not_deprecation ( ) {
155+ let desc =
156+ Directive :: parse_from_deprecated_attr ( & [ parse_quote ! { #[ blah = "foo" ] } ] ) . unwrap ( ) ;
157+ assert_eq ! ( desc, None ) ;
158+ }
159+ }
0 commit comments