Skip to content

Commit 9beaa92

Browse files
authored
maint(clang-tidy): Improve code readability with explicit boolean casts (#3148)
* maint(clang-tidy) Improve code readability * Fix minor typos * Revert optimization that removed test case * Fix comment formatting * Revert another optimization to repro an issue * Remove make_unique since it C++14 and newer only * eformat comments * Fix unsignedness of comparison * Update comment
1 parent 7cc0ebb commit 9beaa92

16 files changed

+73
-44
lines changed

.clang-tidy

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ cppcoreguidelines-init-variables,
55
clang-analyzer-optin.cplusplus.VirtualCall,
66
llvm-namespace-comment,
77
misc-misplaced-const,
8+
misc-non-copyable-objects,
89
misc-static-assert,
910
misc-throw-by-value-catch-by-reference,
1011
misc-uniqueptr-reset-release,
12+
misc-unused-parameters,
1113
modernize-avoid-bind,
14+
modernize-make-shared,
1215
modernize-redundant-void-arg,
1316
modernize-replace-auto-ptr,
1417
modernize-replace-disallow-copy-and-assign-macro,
18+
modernize-replace-random-shuffle,
1519
modernize-shrink-to-fit,
1620
modernize-use-auto,
1721
modernize-use-bool-literals,
@@ -23,13 +27,20 @@ modernize-use-emplace,
2327
modernize-use-override,
2428
modernize-use-using,
2529
*performance*,
30+
readability-avoid-const-params-in-decls,
2631
readability-container-size-empty,
2732
readability-else-after-return,
33+
readability-delete-null-pointer,
34+
readability-implicit-bool-conversion,
2835
readability-make-member-function-const,
36+
readability-misplaced-array-index,
37+
readability-non-const-parameter,
2938
readability-redundant-function-ptr-dereference,
3039
readability-redundant-smartptr-get,
3140
readability-redundant-string-cstr,
3241
readability-simplify-subscript-expr,
42+
readability-static-accessed-through-instance,
43+
readability-static-definition-in-anonymous-namespace,
3344
readability-string-compare,
3445
readability-uniqueptr-delete-release,
3546
'
@@ -39,6 +50,8 @@ CheckOptions:
3950
value: true
4051
- key: performance-unnecessary-value-param.AllowedTypes
4152
value: 'exception_ptr$;'
53+
- key: readability-implicit-bool-conversion.AllowPointerConditions
54+
value: true
4255

4356
HeaderFilterRegex: 'pybind11/.*h'
4457

include/pybind11/cast.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
181181
// Signed/unsigned checks happen elsewhere
182182
if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) && py_value != (py_type) (T) py_value)) {
183183
PyErr_Clear();
184-
if (py_err && convert && PyNumber_Check(src.ptr())) {
184+
if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) {
185185
auto tmp = reinterpret_steal<object>(std::is_floating_point<T>::value
186186
? PyNumber_Float(src.ptr())
187187
: PyNumber_Long(src.ptr()));
@@ -300,7 +300,7 @@ template <> class type_caster<bool> {
300300
value = false;
301301
return true;
302302
}
303-
if (convert || !std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) {
303+
if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) {
304304
// (allow non-implicit conversion for numpy booleans)
305305

306306
Py_ssize_t res = -1;
@@ -501,10 +501,14 @@ template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type
501501
// can fit into a single char value.
502502
if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) {
503503
auto v0 = static_cast<unsigned char>(value[0]);
504-
size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127
505-
(v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence
506-
(v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence
507-
4; // 0b11110xxx - start of 4-byte sequence
504+
// low bits only: 0-127
505+
// 0b110xxxxx - start of 2-byte sequence
506+
// 0b1110xxxx - start of 3-byte sequence
507+
// 0b11110xxx - start of 4-byte sequence
508+
size_t char0_bytes = (v0 & 0x80) == 0 ? 1
509+
: (v0 & 0xE0) == 0xC0 ? 2
510+
: (v0 & 0xF0) == 0xE0 ? 3
511+
: 4;
508512

509513
if (char0_bytes == str_len) {
510514
// If we have a 128-255 value, we can decode it into a single char:

include/pybind11/detail/class.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyOb
129129
// 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop`
130130
// 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
131131
const auto static_prop = (PyObject *) get_internals().static_property_type;
132-
const auto call_descr_set = descr && value && PyObject_IsInstance(descr, static_prop)
133-
&& !PyObject_IsInstance(value, static_prop);
132+
const auto call_descr_set = (descr != nullptr) && (value != nullptr)
133+
&& (PyObject_IsInstance(descr, static_prop) != 0)
134+
&& (PyObject_IsInstance(value, static_prop) == 0);
134135
if (call_descr_set) {
135136
// Call `static_property.__set__()` instead of replacing the `static_property`.
136137
#if !defined(PYPY_VERSION)
@@ -562,7 +563,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
562563
view->len = view->itemsize;
563564
for (auto s : info->shape)
564565
view->len *= s;
565-
view->readonly = info->readonly;
566+
view->readonly = static_cast<int>(info->readonly);
566567
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
567568
view->format = const_cast<char *>(info->format.c_str());
568569
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {

include/pybind11/detail/internals.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ PYBIND11_NOINLINE inline internals &get_internals() {
297297
PyThreadState *tstate = PyThreadState_Get();
298298
#if PY_VERSION_HEX >= 0x03070000
299299
internals_ptr->tstate = PyThread_tss_alloc();
300-
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
300+
if (!internals_ptr->tstate || (PyThread_tss_create(internals_ptr->tstate) != 0))
301301
pybind11_fail("get_internals: could not successfully initialize the TSS key!");
302302
PyThread_tss_set(internals_ptr->tstate, tstate);
303303
#else

include/pybind11/detail/type_caster_base.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ struct value_and_holder {
238238
}
239239
bool holder_constructed() const {
240240
return inst->simple_layout
241-
? inst->simple_holder_constructed
242-
: inst->nonsimple.status[index] & instance::status_holder_constructed;
241+
? inst->simple_holder_constructed
242+
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
243243
}
244244
void set_holder_constructed(bool v = true) const {
245245
if (inst->simple_layout)

include/pybind11/embed.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct embedded_module {
7676
using init_t = void (*)();
7777
#endif
7878
embedded_module(const char *name, init_t init) {
79-
if (Py_IsInitialized())
79+
if (Py_IsInitialized() != 0)
8080
pybind11_fail("Can't add new modules after the interpreter has been initialized");
8181

8282
auto result = PyImport_AppendInittab(name, init);
@@ -101,7 +101,7 @@ PYBIND11_NAMESPACE_END(detail)
101101
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
102102
\endrst */
103103
inline void initialize_interpreter(bool init_signal_handlers = true) {
104-
if (Py_IsInitialized())
104+
if (Py_IsInitialized() != 0)
105105
pybind11_fail("The interpreter is already running");
106106

107107
Py_InitializeEx(init_signal_handlers ? 1 : 0);

include/pybind11/numpy.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,9 @@ class dtype : public object {
465465
explicit dtype(const buffer_info &info) {
466466
dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format)));
467467
// If info.itemsize == 0, use the value calculated from the format string
468-
m_ptr = descr.strip_padding(info.itemsize ? info.itemsize : descr.itemsize()).release().ptr();
468+
m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
469+
.release()
470+
.ptr();
469471
}
470472

471473
explicit dtype(const std::string &format) {
@@ -486,7 +488,7 @@ class dtype : public object {
486488
/// This is essentially the same as calling numpy.dtype(args) in Python.
487489
static dtype from_args(object args) {
488490
PyObject *ptr = nullptr;
489-
if (!detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) || !ptr)
491+
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr)
490492
throw error_already_set();
491493
return reinterpret_steal<dtype>(ptr);
492494
}
@@ -542,7 +544,7 @@ class dtype : public object {
542544
auto name = spec[0].cast<pybind11::str>();
543545
auto format = spec[1].cast<tuple>()[0].cast<dtype>();
544546
auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>();
545-
if (!len(name) && format.kind() == 'V')
547+
if ((len(name) == 0u) && format.kind() == 'V')
546548
continue;
547549
field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
548550
}
@@ -872,11 +874,12 @@ template <typename T, int ExtraFlags = array::forcecast> class array_t : public
872874
: array(std::move(shape), std::move(strides), ptr, base) { }
873875

874876
explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
875-
: array_t(private_ctor{}, std::move(shape),
876-
ExtraFlags & f_style
877-
? detail::f_strides(*shape, itemsize())
878-
: detail::c_strides(*shape, itemsize()),
879-
ptr, base) { }
877+
: array_t(private_ctor{},
878+
std::move(shape),
879+
(ExtraFlags & f_style) != 0 ? detail::f_strides(*shape, itemsize())
880+
: detail::c_strides(*shape, itemsize()),
881+
ptr,
882+
base) {}
880883

881884
explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle())
882885
: array({count}, {}, ptr, base) { }

include/pybind11/pybind11.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,8 @@ class cpp_function : public function {
318318
a.descr = guarded_strdup(repr(a.value).cast<std::string>().c_str());
319319
}
320320

321-
rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");
321+
rec->is_constructor
322+
= (strcmp(rec->name, "__init__") == 0) || (strcmp(rec->name, "__setstate__") == 0);
322323

323324
#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
324325
if (rec->is_constructor && !rec->is_new_style_constructor) {
@@ -1131,7 +1132,8 @@ class generic_type : public object {
11311132
pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) +
11321133
"\": an object with that name is already defined");
11331134

1134-
if (rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type))
1135+
if ((rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type))
1136+
!= nullptr)
11351137
pybind11_fail("generic_type: type \"" + std::string(rec.name) +
11361138
"\" is already registered!");
11371139

@@ -1209,8 +1211,9 @@ class generic_type : public object {
12091211
void def_property_static_impl(const char *name,
12101212
handle fget, handle fset,
12111213
detail::function_record *rec_func) {
1212-
const auto is_static = rec_func && !(rec_func->is_method && rec_func->scope);
1213-
const auto has_doc = rec_func && rec_func->doc && pybind11::options::show_user_defined_docstrings();
1214+
const auto is_static = (rec_func != nullptr) && !(rec_func->is_method && rec_func->scope);
1215+
const auto has_doc = (rec_func != nullptr) && (rec_func->doc != nullptr)
1216+
&& pybind11::options::show_user_defined_docstrings();
12141217
auto property = handle((PyObject *) (is_static ? get_internals().static_property_type
12151218
: &PyProperty_Type));
12161219
attr(name) = property(fget.ptr() ? fget : none(),
@@ -2220,8 +2223,8 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty
22202223
Unfortunately this doesn't work on PyPy. */
22212224
#if !defined(PYPY_VERSION)
22222225
PyFrameObject *frame = PyThreadState_Get()->frame;
2223-
if (frame && (std::string) str(frame->f_code->co_name) == name &&
2224-
frame->f_code->co_argcount > 0) {
2226+
if (frame != nullptr && (std::string) str(frame->f_code->co_name) == name
2227+
&& frame->f_code->co_argcount > 0) {
22252228
PyFrame_FastToLocals(frame);
22262229
PyObject *self_caller = dict_getitem(
22272230
frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0));

include/pybind11/pytypes.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,11 @@ class dict_readonly {
773773
dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); }
774774

775775
reference dereference() const { return {key, value}; }
776-
void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } }
776+
void increment() {
777+
if (PyDict_Next(obj.ptr(), &pos, &key, &value) == 0) {
778+
pos = -1;
779+
}
780+
}
777781
bool equal(const dict_readonly &b) const { return pos == b.pos; }
778782

779783
private:
@@ -1169,14 +1173,14 @@ class bool_ : public object {
11691173
bool_() : object(Py_False, borrowed_t{}) { }
11701174
// Allow implicit conversion from and to `bool`:
11711175
bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { }
1172-
operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; }
1176+
operator bool() const { return (m_ptr != nullptr) && PyLong_AsLong(m_ptr) != 0; }
11731177

11741178
private:
11751179
/// Return the truth value of an object -- always returns a new reference
11761180
static PyObject *raw_bool(PyObject *op) {
11771181
const auto value = PyObject_IsTrue(op);
11781182
if (value == -1) return nullptr;
1179-
return handle(value ? Py_True : Py_False).inc_ref().ptr();
1183+
return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr();
11801184
}
11811185
};
11821186

@@ -1607,7 +1611,7 @@ inline memoryview memoryview::from_buffer(
16071611
size_t ndim = shape->size();
16081612
if (ndim != strides->size())
16091613
pybind11_fail("memoryview: shape length doesn't match strides length");
1610-
ssize_t size = ndim ? 1 : 0;
1614+
ssize_t size = ndim != 0u ? 1 : 0;
16111615
for (size_t i = 0; i < ndim; ++i)
16121616
size *= (*shape)[i];
16131617
Py_buffer view;

include/pybind11/stl/filesystem.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,15 @@ template<typename T> struct path_caster {
6767
}
6868
PyObject* native = nullptr;
6969
if constexpr (std::is_same_v<typename T::value_type, char>) {
70-
if (PyUnicode_FSConverter(buf, &native)) {
70+
if (PyUnicode_FSConverter(buf, &native) != 0) {
7171
if (auto c_str = PyBytes_AsString(native)) {
7272
// AsString returns a pointer to the internal buffer, which
7373
// must not be free'd.
7474
value = c_str;
7575
}
7676
}
7777
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
78-
if (PyUnicode_FSDecoder(buf, &native)) {
78+
if (PyUnicode_FSDecoder(buf, &native) != 0) {
7979
if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) {
8080
// AsWideCharString returns a new string that must be free'd.
8181
value = c_str; // Copies the string.

tests/test_embed/test_interpreter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ bool has_pybind11_internals_builtin() {
103103

104104
bool has_pybind11_internals_static() {
105105
auto **&ipp = py::detail::get_internals_pp();
106-
return ipp && *ipp;
106+
return (ipp != nullptr) && (*ipp != nullptr);
107107
}
108108

109109
TEST_CASE("Restart the interpreter") {

tests/test_methods_and_attributes.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class ExampleMandA {
4343
void add6(int other) { value += other; } // passing by value
4444
void add7(int &other) { value += other; } // passing by reference
4545
void add8(const int &other) { value += other; } // passing by const reference
46+
// NOLINTNEXTLINE(readability-non-const-parameter) Deliberately non-const for testing
4647
void add9(int *other) { value += *other; } // passing by pointer
4748
void add10(const int *other) { value += *other; } // passing by const pointer
4849

tests/test_numpy_dtypes.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,11 @@ PYBIND11_PACKED(struct EnumStruct {
108108

109109
std::ostream& operator<<(std::ostream& os, const StringStruct& v) {
110110
os << "a='";
111-
for (size_t i = 0; i < 3 && v.a[i]; i++) os << v.a[i];
111+
for (size_t i = 0; i < 3 && (v.a[i] != 0); i++)
112+
os << v.a[i];
112113
os << "',b='";
113-
for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i];
114+
for (size_t i = 0; i < 3 && (v.b[i] != 0); i++)
115+
os << v.b[i];
114116
return os << "'";
115117
}
116118

tests/test_numpy_vectorize.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ TEST_SUBMODULE(numpy_vectorize, m) {
5959
.def(py::init<int>())
6060
.def_readwrite("value", &NonPODClass::value);
6161
m.def("vec_passthrough",
62-
py::vectorize([](double *a,
62+
py::vectorize([](const double *a,
6363
double b,
6464
// Changing this broke things
6565
// NOLINTNEXTLINE(performance-unnecessary-value-param)

tests/test_smart_ptr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class MyObject3 : public std::enable_shared_from_this<MyObject3> {
101101
// test_unique_nodelete
102102
// Object with a private destructor
103103
class MyObject4;
104-
static std::unordered_set<MyObject4 *> myobject4_instances;
104+
std::unordered_set<MyObject4 *> myobject4_instances;
105105
class MyObject4 {
106106
public:
107107
MyObject4(int value) : value{value} {
@@ -127,7 +127,7 @@ class MyObject4 {
127127
// Object with std::unique_ptr<T, D> where D is not matching the base class
128128
// Object with a protected destructor
129129
class MyObject4a;
130-
static std::unordered_set<MyObject4a *> myobject4a_instances;
130+
std::unordered_set<MyObject4a *> myobject4a_instances;
131131
class MyObject4a {
132132
public:
133133
MyObject4a(int i) {

tests/test_stl.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ TEST_SUBMODULE(stl, m) {
102102
// test_set
103103
m.def("cast_set", []() { return std::set<std::string>{"key1", "key2"}; });
104104
m.def("load_set", [](const std::set<std::string> &set) {
105-
return set.count("key1") && set.count("key2") && set.count("key3");
105+
return (set.count("key1") != 0u) && (set.count("key2") != 0u) && (set.count("key3") != 0u);
106106
});
107107

108108
// test_recursive_casting
@@ -196,9 +196,7 @@ TEST_SUBMODULE(stl, m) {
196196
m.def("double_or_zero", [](const opt_int& x) -> int {
197197
return x.value_or(0) * 2;
198198
});
199-
m.def("half_or_none", [](int x) -> opt_int {
200-
return x ? opt_int(x / 2) : opt_int();
201-
});
199+
m.def("half_or_none", [](int x) -> opt_int { return x != 0 ? opt_int(x / 2) : opt_int(); });
202200
m.def("test_nullopt", [](opt_int x) {
203201
return x.value_or(42);
204202
}, py::arg_v("x", std::nullopt, "None"));

0 commit comments

Comments
 (0)