From 234a10d5bc133f9963db58fd4c08715fe43c2b94 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 2 Feb 2010 19:33:24 -0500 Subject: introduce custom postprocessing code to (partly) deal with module initialization; add selftests for same --- 2to3c | 4 +- fixes/init-module.cocci | 76 +++++++++++++++------------- fixes/initmodule.py | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 36 deletions(-) create mode 100644 fixes/initmodule.py diff --git a/2to3c b/2to3c index ede6fb2..ae3233a 100755 --- a/2to3c +++ b/2to3c @@ -3,10 +3,12 @@ def get_fixers(): from fixes.typeobject import FixTypeobjectInitializers from fixes import CocciFix + from fixes.initmodule import FixInitModule fixes = [FixTypeobjectInitializers()] for filename in ['RO.cocci', 'int-to-long.cocci', 'ob_type.cocci', - 'repr.cocci', 'init-module.cocci']: + 'repr.cocci']: fixes.append(CocciFix(filename)) + fixes.append(FixInitModule()) return fixes def fixup_content(content): diff --git a/fixes/init-module.cocci b/fixes/init-module.cocci index afeb89a..ca3bcc9 100644 --- a/fixes/init-module.cocci +++ b/fixes/init-module.cocci @@ -10,13 +10,43 @@ T FN(void) { ... } + + +@@ +identifier MOD_VAR; +expression MODULE_NAME, MODULE_METHODS, MODULE_DOC; +expression E; +@@ + if (E) { +- return; ++ return MOD_ERROR_VAL; + } + ... + MOD_VAR = Py_InitModule3(MODULE_NAME, MODULE_METHODS, MODULE_DOC); + + +@@ +identifier MOD_VAR; +expression MODULE_NAME, MODULE_METHODS, MODULE_DOC; +expression E; +@@ + MOD_VAR = Py_InitModule3(MODULE_NAME, MODULE_METHODS, MODULE_DOC); + ... + if (E) { +- return; ++ return MOD_ERROR_VAL; + } + + @@ type mod_init_fn.T; identifier mod_init_fn.FN; identifier mod_init_fn.MOD_VAR; expression MODULE_NAME, MODULE_METHODS, MODULE_DOC; +expression E; +statement list SL; @@ -+ #if PY_MAJOR_VERSION >= 3 ++struct __HASH_IF_PY_MAJOR_VERSION_ge_3; +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + MODULE_NAME, /* m_name */ @@ -28,45 +58,21 @@ expression MODULE_NAME, MODULE_METHODS, MODULE_DOC; + NULL, /* m_clear */ + NULL, /* m_free */ +}; -+#define MOD_ERROR_VAL NULL -+#else -+#endif ++struct __HASH_DEFINE__MOD_ERROR_VAL__NULL; ++struct __HASH_ELSE; ++struct __HASH_DEFINE__MOD_ERROR_VAL__; ++struct __HASH_ENDIF; -T FN(void) { + T FN(void) { ... -+ #if PY_MAJOR_VERSION >= 3 ++__HASH_IF_PY_MAJOR_VERSION_ge_3; + MOD_VAR = PyModule_Create(&moduledef); -+ #else ++__HASH_ELSE; MOD_VAR = Py_InitModule3(MODULE_NAME, MODULE_METHODS, MODULE_DOC); -+ #endif - - ... -} - - ++__HASH_ENDIF; -@@ -type mod_init_fn.T; -identifier mod_init_fn.FN; -expression E; -@@ -T FN(void) { ... -- if (E) return; -+ if (E) return MOD_ERROR_VAL; - ... -} + } + -@@ -type mod_init_fn.T; -identifier mod_init_fn.FN; -identifier mod_init_fn.MOD_VAR; -@@ -T FN(void) { - ... -- return; -+ #if PY_MAJOR_VERSION >= 3 -+ return MOD_VAR; -+ #endif -} diff --git a/fixes/initmodule.py b/fixes/initmodule.py new file mode 100644 index 0000000..c106079 --- /dev/null +++ b/fixes/initmodule.py @@ -0,0 +1,132 @@ +from fixes import CocciFix, FixTest +class FixInitModule(CocciFix): + def __init__(self): + CocciFix.__init__(self, 'init-module.cocci') + + def preprocess(self, string): + # FIXME + return string + + def postprocess(self, string): + for (before, after) in [('struct __HASH_IF_PY_MAJOR_VERSION_ge_3;', + '#if PY_MAJOR_VERSION > 3'), + ('struct __HASH_ELSE;', + '#else'), + ('struct __HASH_DEFINE__MOD_ERROR_VAL__NULL;', + '#define MOD_ERROR_VAL NULL'), + ('struct __HASH_DEFINE__MOD_ERROR_VAL__;', + '#define MOD_ERROR_VAL'), + ('struct __HASH_ENDIF;', + '#endif'), + ('__HASH_IF_PY_MAJOR_VERSION_ge_3;', + '#if PY_MAJOR_VERSION > 3'), + ('__HASH_ELSE;', + '#else'), + ('__HASH_ENDIF;', + '#endif'), + ]: + string = string.replace(before, after) + + # etc + return string + + def transform(self, string): + # FIXME: preprocess + string = self.preprocess(string) + #print 'input:', repr(string) + string = CocciFix.transform(self, string) + #print 'output:', repr(string) + string = self.postprocess(string) + return string + +#import unittest +class TestFixups(FixTest): + def setUp(self): + self.fixer = FixInitModule() + + def test_fixups(self): + self.assertTransformsTo(self.fixer, + ''' +PyMODINIT_FUNC +initxx(void) +{ + PyObject *m; + + if (something_that_can_fail() < 0) + return; + + m = Py_InitModule3("xx", xx_methods, module_doc); + if (m == NULL) + return; + + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); +} +''', + ''' +#if PY_MAJOR_VERSION > 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "xx",/* m_name */ + module_doc,/* m_doc */ + 0,/* m_size */ + xx_methods,/* m_methods */ + NULL,/* m_reload */ + NULL,/* m_traverse */ + NULL,/* m_clear */ + NULL,/* m_free */ +}; +#define MOD_ERROR_VAL NULL +#else +#define MOD_ERROR_VAL +#endif +PyMODINIT_FUNC +initxx(void) +{ + PyObject *m; + + if (something_that_can_fail() < 0) + return MOD_ERROR_VAL; + + #if PY_MAJOR_VERSION > 3 + m = PyModule_Create(&moduledef); + #else + m = Py_InitModule3("xx", xx_methods, module_doc); + #endif + if (m == NULL) + return MOD_ERROR_VAL; + + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); +} +''') +# FIXME: this should have a trailing: +''' + #if PY_MAJOR_VERSION > 3 + return m; + #endif +''' +# but I haven't figured out how to get spatch to add that whilst correctly +# handling error paths + +# Some code that isn't handled yet: +# Multiple error-handling paths: +''' +PyMODINIT_FUNC +initxx(void) +{ + PyObject *m; + + if (something_that_can_fail() < 0) + return; + + m = Py_InitModule3("xx", xx_methods, module_doc); + if (m == NULL) + return; + + if (PyType_Ready(&Null_Type) < 0) + return; + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); +} +''' + +if __name__ == '__main__': + unittest.main() -- cgit