1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2 
3 // Based on https://github.com/dtolnay/syn/blob/2.0.37/src/item.rs.
4 
5 use proc_macro2::TokenStream;
6 use syn::{
7     punctuated::Punctuated, token, Abi, Attribute, Generics, Ident, Lifetime, ReturnType, Token,
8     Type, Visibility,
9 };
10 
11 use super::{Pat, PatType};
12 
13 ast_struct! {
14     /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
15     /// }`.
16     pub struct ItemFn {
17         pub attrs: Vec<Attribute>,
18         pub vis: Visibility,
19         pub sig: Signature,
20         pub block: Box<Block>,
21     }
22 }
23 
24 ast_struct! {
25     /// A braced block containing Rust statements.
26     pub struct Block {
27         pub brace_token: token::Brace,
28         /// Statements in a block
29         pub stmts: TokenStream,
30     }
31 }
32 
33 ast_struct! {
34     /// A function signature in a trait or implementation: `unsafe fn
35     /// initialize(&self)`.
36     pub struct Signature {
37         pub constness: Option<Token![const]>,
38         pub asyncness: Option<Token![async]>,
39         pub unsafety: Option<Token![unsafe]>,
40         pub abi: Option<Abi>,
41         pub fn_token: Token![fn],
42         pub ident: Ident,
43         pub generics: Generics,
44         pub paren_token: token::Paren,
45         pub inputs: Punctuated<FnArg, Token![,]>,
46         pub variadic: Option<Variadic>,
47         pub output: ReturnType,
48     }
49 }
50 
51 ast_enum_of_structs! {
52     /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`.
53     pub enum FnArg {
54         /// The `self` argument of an associated method, whether taken by value
55         /// or by reference.
56         Receiver(Receiver),
57 
58         /// A function argument accepted by pattern and type.
59         Typed(PatType),
60     }
61 }
62 
63 ast_struct! {
64     /// The `self` argument of an associated method, whether taken by value
65     /// or by reference.
66     pub struct Receiver {
67         pub attrs: Vec<Attribute>,
68         pub reference: Option<(Token![&], Option<Lifetime>)>,
69         pub mutability: Option<Token![mut]>,
70         pub self_token: Token![self],
71         pub colon_token: Option<Token![:]>,
72         pub ty: Box<Type>,
73     }
74 }
75 
76 ast_struct! {
77     /// The variadic argument of a foreign function.
78     pub struct Variadic {
79         pub attrs: Vec<Attribute>,
80         pub pat: Option<(Box<Pat>, Token![:])>,
81         pub dots: Token![...],
82         pub comma: Option<Token![,]>,
83     }
84 }
85 
86 mod parsing {
87     use syn::{
88         braced, parenthesized,
89         parse::{discouraged::Speculative, Parse, ParseStream, Result},
90         punctuated::Punctuated,
91         Abi, Attribute, Error, Generics, Ident, Lifetime, Path, ReturnType, Token, Type, TypePath,
92         TypeReference, Visibility,
93     };
94 
95     use super::{Block, FnArg, ItemFn, Receiver, Signature, Variadic};
96     use crate::pat::{Pat, PatType, PatWild};
97 
98     impl Parse for Block {
parse(input: ParseStream<'_>) -> Result<Self>99         fn parse(input: ParseStream<'_>) -> Result<Self> {
100             let content;
101             Ok(Self { brace_token: braced!(content in input), stmts: content.parse()? })
102         }
103     }
104 
105     impl Parse for Signature {
parse(input: ParseStream<'_>) -> Result<Self>106         fn parse(input: ParseStream<'_>) -> Result<Self> {
107             let constness: Option<Token![const]> = input.parse()?;
108             let asyncness: Option<Token![async]> = input.parse()?;
109             let unsafety: Option<Token![unsafe]> = input.parse()?;
110             let abi: Option<Abi> = input.parse()?;
111             let fn_token: Token![fn] = input.parse()?;
112             let ident: Ident = input.parse()?;
113             let mut generics: Generics = input.parse()?;
114 
115             let content;
116             let paren_token = parenthesized!(content in input);
117             let (inputs, variadic) = parse_fn_args(&content)?;
118 
119             let output: ReturnType = input.parse()?;
120             generics.where_clause = input.parse()?;
121 
122             Ok(Self {
123                 constness,
124                 asyncness,
125                 unsafety,
126                 abi,
127                 fn_token,
128                 ident,
129                 generics,
130                 paren_token,
131                 inputs,
132                 variadic,
133                 output,
134             })
135         }
136     }
137 
138     impl Parse for ItemFn {
parse(input: ParseStream<'_>) -> Result<Self>139         fn parse(input: ParseStream<'_>) -> Result<Self> {
140             let attrs = input.call(Attribute::parse_outer)?;
141             let vis: Visibility = input.parse()?;
142             let sig: Signature = input.parse()?;
143             let block = input.parse()?;
144             Ok(Self { attrs, vis, sig, block: Box::new(block) })
145         }
146     }
147 
148     impl Parse for FnArg {
parse(input: ParseStream<'_>) -> Result<Self>149         fn parse(input: ParseStream<'_>) -> Result<Self> {
150             let allow_variadic = false;
151             let attrs = input.call(Attribute::parse_outer)?;
152             match parse_fn_arg_or_variadic(input, attrs, allow_variadic)? {
153                 FnArgOrVariadic::FnArg(arg) => Ok(arg),
154                 FnArgOrVariadic::Variadic(_) => unreachable!(),
155             }
156         }
157     }
158 
159     enum FnArgOrVariadic {
160         FnArg(FnArg),
161         Variadic(Variadic),
162     }
163 
parse_fn_arg_or_variadic( input: ParseStream<'_>, attrs: Vec<Attribute>, allow_variadic: bool, ) -> Result<FnArgOrVariadic>164     fn parse_fn_arg_or_variadic(
165         input: ParseStream<'_>,
166         attrs: Vec<Attribute>,
167         allow_variadic: bool,
168     ) -> Result<FnArgOrVariadic> {
169         let ahead = input.fork();
170         if let Ok(mut receiver) = ahead.parse::<Receiver>() {
171             input.advance_to(&ahead);
172             receiver.attrs = attrs;
173             return Ok(FnArgOrVariadic::FnArg(FnArg::Receiver(receiver)));
174         }
175 
176         // Hack to parse pre-2018 syntax in
177         // test/ui/rfc-2565-param-attrs/param-attrs-pretty.rs
178         // because the rest of the test case is valuable.
179         if input.peek(Ident) && input.peek2(Token![<]) {
180             let span = input.fork().parse::<Ident>()?.span();
181             return Ok(FnArgOrVariadic::FnArg(FnArg::Typed(PatType {
182                 attrs,
183                 pat: Box::new(Pat::Wild(PatWild {
184                     attrs: Vec::new(),
185                     underscore_token: Token![_](span),
186                 })),
187                 colon_token: Token![:](span),
188                 ty: input.parse()?,
189             })));
190         }
191 
192         let pat = Box::new(Pat::parse_single(input)?);
193         let colon_token: Token![:] = input.parse()?;
194 
195         if allow_variadic {
196             if let Some(dots) = input.parse::<Option<Token![...]>>()? {
197                 return Ok(FnArgOrVariadic::Variadic(Variadic {
198                     attrs,
199                     pat: Some((pat, colon_token)),
200                     dots,
201                     comma: None,
202                 }));
203             }
204         }
205 
206         Ok(FnArgOrVariadic::FnArg(FnArg::Typed(PatType {
207             attrs,
208             pat,
209             colon_token,
210             ty: input.parse()?,
211         })))
212     }
213 
214     impl Parse for Receiver {
parse(input: ParseStream<'_>) -> Result<Self>215         fn parse(input: ParseStream<'_>) -> Result<Self> {
216             let reference = if input.peek(Token![&]) {
217                 let ampersand: Token![&] = input.parse()?;
218                 let lifetime: Option<Lifetime> = input.parse()?;
219                 Some((ampersand, lifetime))
220             } else {
221                 None
222             };
223             let mutability: Option<Token![mut]> = input.parse()?;
224             let self_token: Token![self] = input.parse()?;
225             let colon_token: Option<Token![:]> =
226                 if reference.is_some() { None } else { input.parse()? };
227             let ty: Type = if colon_token.is_some() {
228                 input.parse()?
229             } else {
230                 let mut ty = Type::Path(TypePath {
231                     qself: None,
232                     path: Path::from(Ident::new("Self", self_token.span)),
233                 });
234                 if let Some((ampersand, lifetime)) = reference.as_ref() {
235                     ty = Type::Reference(TypeReference {
236                         and_token: Token![&](ampersand.span),
237                         lifetime: lifetime.clone(),
238                         mutability: mutability.as_ref().map(|m| Token![mut](m.span)),
239                         elem: Box::new(ty),
240                     });
241                 }
242                 ty
243             };
244             Ok(Self {
245                 attrs: Vec::new(),
246                 reference,
247                 mutability,
248                 self_token,
249                 colon_token,
250                 ty: Box::new(ty),
251             })
252         }
253     }
254 
parse_fn_args( input: ParseStream<'_>, ) -> Result<(Punctuated<FnArg, Token![,]>, Option<Variadic>)>255     fn parse_fn_args(
256         input: ParseStream<'_>,
257     ) -> Result<(Punctuated<FnArg, Token![,]>, Option<Variadic>)> {
258         let mut args = Punctuated::new();
259         let mut variadic = None;
260         let mut has_receiver = false;
261 
262         while !input.is_empty() {
263             let attrs = input.call(Attribute::parse_outer)?;
264 
265             if let Some(dots) = input.parse::<Option<Token![...]>>()? {
266                 variadic = Some(Variadic {
267                     attrs,
268                     pat: None,
269                     dots,
270                     comma: if input.is_empty() { None } else { Some(input.parse()?) },
271                 });
272                 break;
273             }
274 
275             let allow_variadic = true;
276             let arg = match parse_fn_arg_or_variadic(input, attrs, allow_variadic)? {
277                 FnArgOrVariadic::FnArg(arg) => arg,
278                 FnArgOrVariadic::Variadic(arg) => {
279                     variadic = Some(Variadic {
280                         comma: if input.is_empty() { None } else { Some(input.parse()?) },
281                         ..arg
282                     });
283                     break;
284                 }
285             };
286 
287             match &arg {
288                 FnArg::Receiver(receiver) if has_receiver => {
289                     return Err(Error::new(
290                         receiver.self_token.span,
291                         "unexpected second method receiver",
292                     ));
293                 }
294                 FnArg::Receiver(receiver) if !args.is_empty() => {
295                     return Err(Error::new(receiver.self_token.span, "unexpected method receiver"));
296                 }
297                 FnArg::Receiver(_) => has_receiver = true,
298                 FnArg::Typed(_) => {}
299             }
300             args.push_value(arg);
301 
302             if input.is_empty() {
303                 break;
304             }
305 
306             let comma: Token![,] = input.parse()?;
307             args.push_punct(comma);
308         }
309 
310         Ok((args, variadic))
311     }
312 }
313 
314 mod printing {
315     use proc_macro2::TokenStream;
316     use quote::{ToTokens, TokenStreamExt};
317     use syn::{Token, Type};
318 
319     use super::{Block, ItemFn, Receiver, Signature, Variadic};
320 
321     impl ToTokens for ItemFn {
to_tokens(&self, tokens: &mut TokenStream)322         fn to_tokens(&self, tokens: &mut TokenStream) {
323             tokens.append_all(&self.attrs);
324             self.vis.to_tokens(tokens);
325             self.sig.to_tokens(tokens);
326             self.block.to_tokens(tokens);
327         }
328     }
329 
330     impl ToTokens for Block {
to_tokens(&self, tokens: &mut TokenStream)331         fn to_tokens(&self, tokens: &mut TokenStream) {
332             self.brace_token.surround(tokens, |tokens| {
333                 tokens.append_all(self.stmts.clone());
334             });
335         }
336     }
337 
338     impl ToTokens for Signature {
to_tokens(&self, tokens: &mut TokenStream)339         fn to_tokens(&self, tokens: &mut TokenStream) {
340             self.constness.to_tokens(tokens);
341             self.asyncness.to_tokens(tokens);
342             self.unsafety.to_tokens(tokens);
343             self.abi.to_tokens(tokens);
344             self.fn_token.to_tokens(tokens);
345             self.ident.to_tokens(tokens);
346             self.generics.to_tokens(tokens);
347             self.paren_token.surround(tokens, |tokens| {
348                 self.inputs.to_tokens(tokens);
349                 if let Some(variadic) = &self.variadic {
350                     if !self.inputs.empty_or_trailing() {
351                         <Token![,]>::default().to_tokens(tokens);
352                     }
353                     variadic.to_tokens(tokens);
354                 }
355             });
356             self.output.to_tokens(tokens);
357             self.generics.where_clause.to_tokens(tokens);
358         }
359     }
360 
361     impl ToTokens for Receiver {
to_tokens(&self, tokens: &mut TokenStream)362         fn to_tokens(&self, tokens: &mut TokenStream) {
363             tokens.append_all(&self.attrs);
364             if let Some((ampersand, lifetime)) = &self.reference {
365                 ampersand.to_tokens(tokens);
366                 lifetime.to_tokens(tokens);
367             }
368             self.mutability.to_tokens(tokens);
369             self.self_token.to_tokens(tokens);
370             if let Some(colon_token) = &self.colon_token {
371                 colon_token.to_tokens(tokens);
372                 self.ty.to_tokens(tokens);
373             } else {
374                 let consistent = match (&self.reference, &self.mutability, &*self.ty) {
375                     (Some(_), mutability, Type::Reference(ty)) => {
376                         mutability.is_some() == ty.mutability.is_some()
377                             && match &*ty.elem {
378                                 Type::Path(ty) => ty.qself.is_none() && ty.path.is_ident("Self"),
379                                 _ => false,
380                             }
381                     }
382                     (None, _, Type::Path(ty)) => ty.qself.is_none() && ty.path.is_ident("Self"),
383                     _ => false,
384                 };
385                 if !consistent {
386                     <Token![:]>::default().to_tokens(tokens);
387                     self.ty.to_tokens(tokens);
388                 }
389             }
390         }
391     }
392 
393     impl ToTokens for Variadic {
to_tokens(&self, tokens: &mut TokenStream)394         fn to_tokens(&self, tokens: &mut TokenStream) {
395             tokens.append_all(&self.attrs);
396             if let Some((pat, colon)) = &self.pat {
397                 pat.to_tokens(tokens);
398                 colon.to_tokens(tokens);
399             }
400             self.dots.to_tokens(tokens);
401             self.comma.to_tokens(tokens);
402         }
403     }
404 }
405