clang-tidy: resolve cppguidelines-pro-type-*cast*#554
clang-tidy: resolve cppguidelines-pro-type-*cast*#554greenc-FNAL wants to merge 3 commits intomainfrom
clang-tidy: resolve cppguidelines-pro-type-*cast*#554Conversation
Ignore: - `cppcoreguidelines-pro-type-const-cast` - `cppcoreguidelines-pro-type-reinterpret-cast` in `form/root_storage` and `plugins/python/src` due to ROOT and Python interaction limitations, respectively.
There was a problem hiding this comment.
Pull request overview
This PR updates Python and ROOT interop code to address clang-tidy cppcoreguidelines-pro-type-*cast* findings by replacing C-style casts, adding targeted NOLINT annotations, and introducing per-directory .clang-tidy overrides.
Changes:
- Replace many C-style casts with
reinterpret_cast/const_castin Python wrapper code. - Add per-directory
.clang-tidyconfigs to disablecppcoreguidelines-pro-type-const-castandcppcoreguidelines-pro-type-reinterpret-castfor interop-heavy directories. - Add a justified
NOLINTfor a verifiedstatic_castdowncast in ROOT storage code.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/python/src/modulewrap.cpp | Reworks casts around Python object conversions and method/type table definitions to address clang-tidy findings. |
| plugins/python/src/lifelinewrap.cpp | Updates allocation/deallocation and PyTypeObject initialization casts to satisfy cast-related checks. |
| plugins/python/src/dciwrap.cpp | Updates object wrapping and method/type table casts away from C-style. |
| plugins/python/src/configwrap.cpp | Updates casts in configuration wrapper and PyTypeObject/mapping method setup. |
| plugins/python/src/.clang-tidy | Disables pro-type-const-cast and pro-type-reinterpret-cast checks for Python plugin sources. |
| form/root_storage/root_tbranch_read_container.cpp | Documents and suppresses a verified safe downcast for fundamental ROOT types. |
| form/root_storage/.clang-tidy | Disables pro-type-const-cast and pro-type-reinterpret-cast checks for ROOT storage sources. |
| static char const* kwnames[] = { | ||
| "callable", "input_family", "output_product_suffixes", "concurrency", "name", nullptr}; | ||
| PyObject *callable = 0, *input = 0, *output = 0, *concurrency = 0, *pyname = 0; | ||
| if (!PyArg_ParseTupleAndKeywords( | ||
| args, kwds, "OO|OOO", (char**)kwnames, &callable, &input, &output, &concurrency, &pyname)) { | ||
| if (!PyArg_ParseTupleAndKeywords(args, | ||
| kwds, | ||
| "OO|OOO", | ||
| const_cast<char**>(kwnames), | ||
| &callable, |
There was a problem hiding this comment.
In parse_args, kwnames is an array of const char* but it is passed to PyArg_ParseTupleAndKeywords via const_cast<char**>. That cast is type-unsafe (it implies the callee may mutate both the pointers and the pointed-to characters). Prefer declaring a static char* kwlist with writable storage (e.g., static char kw0[] = "callable"; ...; static char* kwnames[] = {kw0, ... , nullptr};) and pass kwnames without casting.
| { \ | ||
| PyGILRAII gil; \ | ||
| cpptype i = (cpptype)frompy((PyObject*)pyobj); \ | ||
| cpptype i = (cpptype)frompy(reinterpret_cast<PyObject*>(pyobj)); \ |
There was a problem hiding this comment.
BASIC_CONVERTER still uses a C-style cast to cpptype (cpptype i = (cpptype)frompy(...)). This will continue to trigger cppcoreguidelines-pro-type-cstyle-cast and is easy to replace with static_cast<cpptype>(...).
| cpptype i = (cpptype)frompy(reinterpret_cast<PyObject*>(pyobj)); \ | |
| cpptype i = static_cast<cpptype>(frompy(reinterpret_cast<PyObject*>(pyobj))); \ |
| PyObject* np_view = PyArray_SimpleNewFromData(1, /* 1-D array */ \ | ||
| dims, /* dimension sizes */ \ | ||
| nptype, /* numpy C type */ \ | ||
| (void*)(v->data()) /* raw buffer */ \ | ||
| ); \ |
There was a problem hiding this comment.
In VECTOR_CONVERTER, the (void*)(v->data()) cast is unnecessary (object pointers implicitly convert to void* in C++) and also trips cppcoreguidelines-pro-type-cstyle-cast. Prefer passing v->data() directly or using static_cast<void*>(v->data()) if an explicit cast is desired.
| for (Py_ssize_t i = 0; i < total; ++i) { \ | ||
| PyObject* item = PyList_GetItem((PyObject*)pyobj, i); \ | ||
| PyObject* item = PyList_GetItem(reinterpret_cast<PyObject*>(pyobj), i); \ | ||
| vec->push_back((cpptype)frompy(item)); \ |
There was a problem hiding this comment.
In NUMPY_ARRAY_CONVERTER, vec->push_back((cpptype)frompy(item)); is another remaining C-style cast that will be flagged by cppcoreguidelines-pro-type-cstyle-cast. Prefer static_cast<cpptype>(frompy(item)).
| vec->push_back((cpptype)frompy(item)); \ | |
| vec->push_back(static_cast<cpptype>(frompy(item))); \ |
| //Assume this is a fundamental type like int or double | ||
| // We can avoid a `dynamic_cast` to `TDataType` here after checking EProperty::kIsFundamental | ||
| // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) | ||
| auto fundInfo = static_cast<TDataType*>(TDictionary::GetDictionary(type)); |
There was a problem hiding this comment.
dictInfo is already retrieved just above and proven fundamental, but the code calls TDictionary::GetDictionary(type) again to initialize fundInfo. This is redundant and could be replaced with static_cast<TDataType*>(dictInfo) to avoid a second lookup and make the downcast intent clearer.
| auto fundInfo = static_cast<TDataType*>(TDictionary::GetDictionary(type)); | |
| auto fundInfo = static_cast<TDataType*>(dictInfo); |
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## main #554 +/- ##
==========================================
+ Coverage 85.27% 85.36% +0.08%
==========================================
Files 144 144
Lines 3675 3683 +8
Branches 632 632
==========================================
+ Hits 3134 3144 +10
Misses 324 324
+ Partials 217 215 -2
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 1 file with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
| PyTypeObject phlex::experimental::PhlexConfig_Type = { | ||
| PyVarObject_HEAD_INIT(&PyType_Type, 0) | ||
| (char*) "pyphlex.configuration", // tp_name | ||
| const_cast<char*>("pyphlex.configuration"), // tp_name |
There was a problem hiding this comment.
If I remember correctly, I think that each of these hard-casts (now const_casts) can simply be replaced by the string literal:
| const_cast<char*>("pyphlex.configuration"), // tp_name | |
| "pyphlex.configuration", // tp_name |
Can we try making that change here and elsewhere? If that works, we'd be able to re-enable the cppcoreguidelines-pro-type-const-cast check for this directory.
clang-tidychecks by directorystatic_castto derived