Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit af23244

Browse files
authored
Fix Py_INCREF_assign regex order (#53)
Py_INCREF_return supports cast to "PyObject*".
1 parent ba0752f commit af23244

2 files changed

Lines changed: 65 additions & 25 deletions

File tree

tests/test_upgrade_pythoncapi.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,11 @@ def test_py_incref_return(self):
407407
Py_XINCREF(obj);
408408
return obj;
409409
}
410+
411+
PyObject* cast(PyLongObject *obj) {
412+
Py_XINCREF(obj);
413+
return (PyObject *)obj;
414+
}
410415
""", """
411416
#include "pythoncapi_compat.h"
412417
@@ -421,6 +426,10 @@ def test_py_incref_return(self):
421426
PyObject* new_xref(PyObject *obj) {
422427
return Py_XNewRef(obj);
423428
}
429+
430+
PyObject* cast(PyLongObject *obj) {
431+
return Py_XNewRef(obj);
432+
}
424433
""")
425434

426435
@unittest.skipUnless(upgrade_pythoncapi.FORCE_NEWREF, 'FORCE_NEWREF=False')
@@ -505,6 +514,33 @@ def test_py_incref_assign(self):
505514
}
506515
""")
507516

517+
# the first Py_INCREF should be replaced before the second one,
518+
# otherwise the first Py_INCREF is not replaced.
519+
self.check_replace("""
520+
void set(void)
521+
{
522+
PyObject *x, *y;
523+
Py_INCREF(Py_None);
524+
x = Py_None;
525+
Py_INCREF(Py_None);
526+
x = Py_None;
527+
Py_DECREF(x);
528+
Py_DECREF(y);
529+
}
530+
""", """
531+
#include "pythoncapi_compat.h"
532+
533+
void set(void)
534+
{
535+
PyObject *x, *y;
536+
x = Py_NewRef(Py_None);
537+
x = Py_NewRef(Py_None);
538+
Py_DECREF(x);
539+
Py_DECREF(y);
540+
}
541+
""")
542+
543+
# Indentation matters for conditional code
508544
self.check_dont_replace("""
509545
void test1(int test)
510546
{

upgrade_pythoncapi.py

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ def call_assign_regex(name):
8585
return re.compile(regex)
8686

8787

88+
def optional_ptr_cast(to_type):
89+
return fr'(?:\({to_type}\s*\*\){SPACE_REGEX}*)?'
90+
91+
8892
def is_c_filename(filename):
8993
return filename.endswith(C_FILE_EXT)
9094

@@ -249,28 +253,48 @@ class Py_INCREF_return(Operation):
249253
(re.compile(fr'({INDENTATION_REGEX})'
250254
+ fr'Py_(X?)INCREF\(({EXPR_REGEX})\)\s*;'
251255
+ same_indentation(r'\1')
252-
+ r'return \3;',
256+
+ r'return ' + optional_ptr_cast('PyObject') + r'\3;',
253257
re.MULTILINE),
254258
r'\1return Py_\2NewRef(\3);'),
255259

256260
# Same regex than the previous one,
257261
# but the two statements are on the same line.
258262
(re.compile(fr'Py_(X?)INCREF\(({EXPR_REGEX})\)\s*;'
259263
+ fr'{SPACE_REGEX}*'
260-
+ r'return \2;',
264+
+ r'return ' + optional_ptr_cast('PyObject') + r'\2;',
261265
re.MULTILINE),
262266
r'return Py_\1NewRef(\2);'),
263267
)
264268
# Need Py_NewRef(): new in Python 3.10
265269
NEED_PYTHONCAPI_COMPAT = True
266270

267271

268-
def optional_ptr_cast(to_type):
269-
return fr'(?:\({to_type}\s*\*\))?'
270-
271272
class Py_INCREF_assign(Operation):
272273
NAME = "Py_INCREF_assign"
274+
# "Py_INCREF(x); y = x;" must be replaced before "y = x; Py_INCREF(y);",
275+
# to not miss consecutive "Py_INCREF; assign; Py_INCREF; assign; ..."
276+
# (see unit tests)
273277
REPLACE = (
278+
# "Py_INCREF(x); y = x;" => "y = Py_NewRef(x)"
279+
# "Py_XINCREF(x); y = x;" => "y = Py_XNewRef(x)"
280+
# The two statements must have the same indentation, otherwise the
281+
# regex does not match.
282+
(re.compile(fr'({INDENTATION_REGEX})'
283+
+ fr'Py_(X?)INCREF\(({EXPR_REGEX})\);'
284+
+ same_indentation(r'\1')
285+
+ assign_regex_str(fr'({EXPR_REGEX})',
286+
optional_ptr_cast('PyObject') + r'\3'),
287+
re.MULTILINE),
288+
r'\1\4 = Py_\2NewRef(\3);'),
289+
290+
# Same regex than the previous one,
291+
# but the two statements are on the same line.
292+
(re.compile(fr'Py_(X?)INCREF\(({EXPR_REGEX})\);'
293+
+ fr'{SPACE_REGEX}*'
294+
+ assign_regex_str(fr'({EXPR_REGEX})',
295+
optional_ptr_cast('PyObject') + r'\2')),
296+
r'\3 = Py_\1NewRef(\2);'),
297+
274298
# "y = x; Py_INCREF(x);" => "y = Py_NewRef(x);"
275299
# "y = x; Py_INCREF(y);" => "y = Py_NewRef(x);"
276300
# "y = x; Py_XINCREF(x);" => "y = Py_XNewRef(x);"
@@ -293,26 +317,6 @@ class Py_INCREF_assign(Operation):
293317
+ fr'{SPACE_REGEX}*'
294318
+ r'Py_(X?)INCREF\((?:\1|\2)\);'),
295319
r'\1 = Py_\3NewRef(\2);'),
296-
297-
# "Py_INCREF(x); y = x;" => "y = Py_NewRef(x)"
298-
# "Py_XINCREF(x); y = x;" => "y = Py_XNewRef(x)"
299-
# The two statements must have the same indentation, otherwise the
300-
# regex does not match.
301-
(re.compile(fr'({INDENTATION_REGEX})'
302-
+ fr'Py_(X?)INCREF\(({EXPR_REGEX})\);'
303-
+ same_indentation(r'\1')
304-
+ assign_regex_str(fr'({EXPR_REGEX})',
305-
optional_ptr_cast('PyObject') + r'\3'),
306-
re.MULTILINE),
307-
r'\1\4 = Py_\2NewRef(\3);'),
308-
309-
# Same regex than the previous one,
310-
# but the two statements are on the same line.
311-
(re.compile(fr'Py_(X?)INCREF\(({EXPR_REGEX})\);'
312-
+ fr'{SPACE_REGEX}*'
313-
+ assign_regex_str(fr'({EXPR_REGEX})',
314-
optional_ptr_cast('PyObject') + r'\2')),
315-
r'\3 = Py_\1NewRef(\2);'),
316320
)
317321
# Need Py_NewRef(): new in Python 3.10
318322
NEED_PYTHONCAPI_COMPAT = True

0 commit comments

Comments
 (0)