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, 186 })), 187 colon_token: Token, 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, 237 lifetime: lifetime.clone(), 238 mutability: mutability.as_ref().map(|m| Token), 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