1
1
// Copyright (c) 2017-present PyO3 Project and Contributors
2
2
3
3
use crate :: pyfunction:: Argument ;
4
- use crate :: pyfunction:: PyFunctionAttr ;
4
+ use crate :: pyfunction:: { PyFunctionAttr , parse_name_attribute } ;
5
5
use crate :: utils;
6
6
use proc_macro2:: TokenStream ;
7
7
use quote:: quote;
8
8
use quote:: ToTokens ;
9
+ use syn:: ext:: IdentExt ;
9
10
use syn:: spanned:: Spanned ;
10
11
11
12
#[ derive( Clone , PartialEq , Debug ) ]
@@ -36,8 +37,9 @@ pub struct FnSpec<'a> {
36
37
pub tp : FnType ,
37
38
// Rust function name
38
39
pub name : & ' a syn:: Ident ,
39
- // Wrapped python name
40
- pub python_name : Option < syn:: Ident > ,
40
+ // Wrapped python name. This should have been sent through syn::IdentExt::unraw()
41
+ // to ensure that any leading r# is removed.
42
+ pub python_name : syn:: Ident ,
41
43
pub attrs : Vec < Argument > ,
42
44
pub args : Vec < FnArg < ' a > > ,
43
45
pub output : syn:: Type ,
@@ -59,24 +61,8 @@ impl<'a> FnSpec<'a> {
59
61
allow_custom_name : bool ,
60
62
) -> syn:: Result < FnSpec < ' a > > {
61
63
let name = & sig. ident ;
62
- let ( mut fn_type, fn_attrs, mut python_name) =
63
- parse_attributes ( meth_attrs, allow_custom_name) ?;
64
-
65
- // "Tweak" getter / setter names: strip off set_ and get_ if needed
66
- if let FnType :: Getter | FnType :: Setter = & fn_type {
67
- if python_name. is_none ( ) {
68
- let prefix = match & fn_type {
69
- FnType :: Getter => "get_" ,
70
- FnType :: Setter => "set_" ,
71
- _ => unreachable ! ( ) ,
72
- } ;
73
-
74
- let ident = sig. ident . to_string ( ) ;
75
- if ident. starts_with ( prefix) {
76
- python_name = Some ( syn:: Ident :: new ( & ident[ prefix. len ( ) ..] , ident. span ( ) ) )
77
- }
78
- }
79
- }
64
+ let MethodAttributes { ty : mut fn_type, args : fn_attrs, mut python_name } =
65
+ parse_method_attributes ( meth_attrs, allow_custom_name) ?;
80
66
81
67
let mut has_self = false ;
82
68
let mut arguments = Vec :: new ( ) ;
@@ -136,12 +122,28 @@ impl<'a> FnSpec<'a> {
136
122
fn_type = FnType :: PySelf ( tp) ;
137
123
}
138
124
139
- let mut parse_erroneous_text_signature = |error_msg : & str | {
140
- let py_name = python_name. as_ref ( ) . unwrap_or ( name) ;
125
+ // "Tweak" getter / setter names: strip off set_ and get_ if needed
126
+ if let FnType :: Getter | FnType :: Setter = & fn_type {
127
+ if python_name. is_none ( ) {
128
+ let prefix = match & fn_type {
129
+ FnType :: Getter => "get_" ,
130
+ FnType :: Setter => "set_" ,
131
+ _ => unreachable ! ( ) ,
132
+ } ;
133
+
134
+ let ident = sig. ident . unraw ( ) . to_string ( ) ;
135
+ if ident. starts_with ( prefix) {
136
+ python_name = Some ( syn:: Ident :: new ( & ident[ prefix. len ( ) ..] , ident. span ( ) ) )
137
+ }
138
+ }
139
+ }
140
+
141
+ let python_name = python_name. unwrap_or_else ( || name. unraw ( ) ) ;
141
142
143
+ let mut parse_erroneous_text_signature = |error_msg : & str | {
142
144
// try to parse anyway to give better error messages
143
145
if let Some ( text_signature) =
144
- utils:: parse_text_signature_attrs ( & mut * meth_attrs, py_name ) ?
146
+ utils:: parse_text_signature_attrs ( meth_attrs, & python_name ) ?
145
147
{
146
148
Err ( syn:: Error :: new_spanned ( text_signature, error_msg) )
147
149
} else {
@@ -181,10 +183,6 @@ impl<'a> FnSpec<'a> {
181
183
} )
182
184
}
183
185
184
- pub fn py_name ( & self ) -> & syn:: Ident {
185
- self . python_name . as_ref ( ) . unwrap_or ( self . name )
186
- }
187
-
188
186
pub fn is_args ( & self , name : & syn:: Ident ) -> bool {
189
187
for s in self . attrs . iter ( ) {
190
188
if let Argument :: VarArgs ( ref path) = s {
@@ -344,14 +342,20 @@ pub fn check_arg_ty_and_optional<'a>(
344
342
}
345
343
}
346
344
347
- fn parse_attributes (
345
+ #[ derive( Clone , PartialEq , Debug ) ]
346
+ struct MethodAttributes {
347
+ ty : FnType ,
348
+ args : Vec < Argument > ,
349
+ python_name : Option < syn:: Ident >
350
+ }
351
+
352
+ fn parse_method_attributes (
348
353
attrs : & mut Vec < syn:: Attribute > ,
349
354
allow_custom_name : bool ,
350
- ) -> syn:: Result < ( FnType , Vec < Argument > , Option < syn :: Ident > ) > {
355
+ ) -> syn:: Result < MethodAttributes > {
351
356
let mut new_attrs = Vec :: new ( ) ;
352
- let mut spec = Vec :: new ( ) ;
357
+ let mut args = Vec :: new ( ) ;
353
358
let mut res: Option < FnType > = None ;
354
- let mut name_with_span = None ;
355
359
let mut property_name = None ;
356
360
357
361
for attr in attrs. iter ( ) {
@@ -454,77 +458,66 @@ fn parse_attributes(
454
458
} ;
455
459
} else if path. is_ident ( "args" ) {
456
460
let attrs = PyFunctionAttr :: from_meta ( nested) ?;
457
- spec . extend ( attrs. arguments )
461
+ args . extend ( attrs. arguments )
458
462
} else {
459
463
new_attrs. push ( attr. clone ( ) )
460
464
}
461
465
}
462
- syn:: Meta :: NameValue ( ref nv) if allow_custom_name && nv. path . is_ident ( "name" ) => {
463
- if name_with_span. is_some ( ) {
464
- return Err ( syn:: Error :: new_spanned (
465
- & nv. path ,
466
- "name can not be specified multiple times" ,
467
- ) ) ;
468
- }
469
-
470
- match & nv. lit {
471
- syn:: Lit :: Str ( s) => name_with_span = Some ( ( s. parse ( ) ?, nv. path . span ( ) ) ) ,
472
- _ => {
473
- return Err ( syn:: Error :: new_spanned (
474
- & nv. lit ,
475
- "Expected string literal for method name" ,
476
- ) )
477
- }
478
- }
479
- }
480
466
syn:: Meta :: NameValue ( _) => new_attrs. push ( attr. clone ( ) ) ,
481
467
}
482
468
}
469
+
483
470
attrs. clear ( ) ;
484
471
attrs. extend ( new_attrs) ;
485
472
486
- if let Some ( ( _, span) ) = & name_with_span {
487
- match & res {
488
- Some ( FnType :: FnNew ) => {
489
- return Err ( syn:: Error :: new (
490
- * span,
491
- "name can not be specified with #[new]" ,
492
- ) )
493
- }
494
- Some ( FnType :: FnCall ) => {
495
- return Err ( syn:: Error :: new (
496
- * span,
497
- "name can not be specified with #[call]" ,
498
- ) )
499
- }
500
- Some ( FnType :: Getter ) => {
501
- return Err ( syn:: Error :: new (
502
- * span,
503
- "name can not be specified for getter" ,
504
- ) )
505
- }
506
- Some ( FnType :: Setter ) => {
507
- return Err ( syn:: Error :: new (
508
- * span,
509
- "name can not be specified for setter" ,
510
- ) )
511
- }
473
+ let ty = res. unwrap_or ( FnType :: Fn ) ;
474
+ let python_name = if allow_custom_name {
475
+ parse_method_name_attribute ( & ty, attrs, property_name) ?
476
+ } else {
477
+ property_name
478
+ } ;
479
+
480
+ Ok ( MethodAttributes { ty, args, python_name } )
481
+ }
482
+
483
+ fn parse_method_name_attribute (
484
+ ty : & FnType ,
485
+ attrs : & mut Vec < syn:: Attribute > ,
486
+ property_name : Option < syn:: Ident >
487
+ ) -> syn:: Result < Option < syn:: Ident > > {
488
+
489
+ let name = parse_name_attribute ( attrs) ?;
490
+
491
+ // Reject some invalid combinations
492
+ if let Some ( name) = & name {
493
+ match ty {
494
+ FnType :: FnNew => return Err ( syn:: Error :: new_spanned (
495
+ name,
496
+ "name can not be specified with #[new]" ,
497
+ ) ) ,
498
+ FnType :: FnCall => return Err ( syn:: Error :: new_spanned (
499
+ name,
500
+ "name can not be specified with #[call]" ,
501
+ ) ) ,
502
+ FnType :: Getter => return Err ( syn:: Error :: new_spanned (
503
+ name,
504
+ "name can not be specified for getter" ,
505
+ ) ) ,
506
+ FnType :: Setter => return Err ( syn:: Error :: new_spanned (
507
+ name,
508
+ "name can not be specified for setter" ,
509
+ ) ) ,
512
510
_ => { }
513
511
}
514
512
}
515
513
516
514
// Thanks to check above we can be sure that this generates the right python name
517
- let python_name = match res {
518
- Some ( FnType :: FnNew ) => Some ( syn:: Ident :: new ( "__new__" , proc_macro2:: Span :: call_site ( ) ) ) ,
519
- Some ( FnType :: FnCall ) => Some ( syn:: Ident :: new ( "__call__" , proc_macro2:: Span :: call_site ( ) ) ) ,
520
- Some ( FnType :: Getter ) | Some ( FnType :: Setter ) => property_name,
521
- _ => name_with_span. map ( |ns| ns. 0 ) ,
522
- } ;
523
-
524
- match res {
525
- Some ( tp) => Ok ( ( tp, spec, python_name) ) ,
526
- None => Ok ( ( FnType :: Fn , spec, python_name) ) ,
527
- }
515
+ Ok ( match ty {
516
+ FnType :: FnNew => Some ( syn:: Ident :: new ( "__new__" , proc_macro2:: Span :: call_site ( ) ) ) ,
517
+ FnType :: FnCall => Some ( syn:: Ident :: new ( "__call__" , proc_macro2:: Span :: call_site ( ) ) ) ,
518
+ FnType :: Getter | FnType :: Setter => property_name,
519
+ _ => name,
520
+ } )
528
521
}
529
522
530
523
// Replace A<Self> with A<_>
0 commit comments