diff --git a/checks/clang-query/prefer-reinterpret-cast/prefer-reinterpret-cast.query b/checks/clang-query/prefer-reinterpret-cast/prefer-reinterpret-cast.query new file mode 100644 index 0000000..d944813 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/prefer-reinterpret-cast.query @@ -0,0 +1,13 @@ +# Flags C-style and function-style casts that reinterpret an object's bits +# (clang's BitCast / LValueBitCast cast kinds); spell these as reinterpret_cast +# (plus const_cast when constness is also discarded) so the intent is explicit. +# Template instantiations are traversed so that dependent casts are reported +# once they resolve to a bit cast. +set traversal AsIs +match explicitCastExpr( + isExpansionInMainFile(), + anyOf(cStyleCastExpr(), cxxFunctionalCastExpr()), + anyOf( + hasCastKind("CK_BitCast"), + hasCastKind("CK_LValueBitCast"), + has(implicitCastExpr(anyOf(hasCastKind("CK_BitCast"), hasCastKind("CK_LValueBitCast")))))) diff --git a/checks/clang-query/prefer-reinterpret-cast/tests/fail/bit_cast_discarding_const.cpp b/checks/clang-query/prefer-reinterpret-cast/tests/fail/bit_cast_discarding_const.cpp new file mode 100644 index 0000000..556cbe1 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/tests/fail/bit_cast_discarding_const.cpp @@ -0,0 +1,9 @@ +[[nodiscard]] char *mutable_bytes(const int *value) +{ + return (char *)value;// expect-finding +} + +[[nodiscard]] void *mutable_address(const int &value) +{ + return (void *)&value;// expect-finding +} diff --git a/checks/clang-query/prefer-reinterpret-cast/tests/fail/bit_cast_in_template.cpp b/checks/clang-query/prefer-reinterpret-cast/tests/fail/bit_cast_in_template.cpp new file mode 100644 index 0000000..d7e6c56 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/tests/fail/bit_cast_in_template.cpp @@ -0,0 +1,6 @@ +template [[nodiscard]] To convert(const From value) +{ + return (To)value;// expect-finding +} + +[[nodiscard]] const char *as_chars(const int *value) { return convert(value); } diff --git a/checks/clang-query/prefer-reinterpret-cast/tests/fail/c_style_pointer_bit_cast.cpp b/checks/clang-query/prefer-reinterpret-cast/tests/fail/c_style_pointer_bit_cast.cpp new file mode 100644 index 0000000..fb03845 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/tests/fail/c_style_pointer_bit_cast.cpp @@ -0,0 +1,4 @@ +[[nodiscard]] const unsigned char *object_bytes(const int &value) +{ + return (const unsigned char *)&value;// expect-finding +} diff --git a/checks/clang-query/prefer-reinterpret-cast/tests/fail/c_style_reference_bit_cast.cpp b/checks/clang-query/prefer-reinterpret-cast/tests/fail/c_style_reference_bit_cast.cpp new file mode 100644 index 0000000..a47a213 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/tests/fail/c_style_reference_bit_cast.cpp @@ -0,0 +1,4 @@ +[[nodiscard]] float &reinterpret_bits(int &value) +{ + return (float &)value;// expect-finding +} diff --git a/checks/clang-query/prefer-reinterpret-cast/tests/fail/function_style_pointer_bit_cast.cpp b/checks/clang-query/prefer-reinterpret-cast/tests/fail/function_style_pointer_bit_cast.cpp new file mode 100644 index 0000000..cc28104 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/tests/fail/function_style_pointer_bit_cast.cpp @@ -0,0 +1,6 @@ +using byte_pointer = const unsigned char *; + +[[nodiscard]] byte_pointer object_bytes(const int &value) +{ + return byte_pointer(&value);// expect-finding +} diff --git a/checks/clang-query/prefer-reinterpret-cast/tests/pass/reinterpret_cast.cpp b/checks/clang-query/prefer-reinterpret-cast/tests/pass/reinterpret_cast.cpp new file mode 100644 index 0000000..fd3e550 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/tests/pass/reinterpret_cast.cpp @@ -0,0 +1,6 @@ +[[nodiscard]] const unsigned char *object_bytes(const int &value) +{ + return reinterpret_cast(&value); +} + +[[nodiscard]] float &reinterpret_bits(int &value) { return reinterpret_cast(value); } diff --git a/checks/clang-query/prefer-reinterpret-cast/tests/pass/template_without_bit_cast.cpp b/checks/clang-query/prefer-reinterpret-cast/tests/pass/template_without_bit_cast.cpp new file mode 100644 index 0000000..ad16e25 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/tests/pass/template_without_bit_cast.cpp @@ -0,0 +1,6 @@ +template [[nodiscard]] constexpr To convert(const From value) +{ + return (To)value; +} + +[[nodiscard]] constexpr int truncate(const double value) { return convert(value); } diff --git a/checks/clang-query/prefer-reinterpret-cast/tests/pass/value_conversions.cpp b/checks/clang-query/prefer-reinterpret-cast/tests/pass/value_conversions.cpp new file mode 100644 index 0000000..a6dcf38 --- /dev/null +++ b/checks/clang-query/prefer-reinterpret-cast/tests/pass/value_conversions.cpp @@ -0,0 +1,21 @@ +struct Base +{ + int base_value; +}; + +struct Derived : Base +{ + int derived_value; +}; + +using integer = int; + +[[nodiscard]] constexpr int truncate(const double value) { return (int)value; } + +[[nodiscard]] constexpr int truncate_functional(const double value) { return integer(value); } + +[[nodiscard]] const Derived *as_derived(const Base *base) { return (const Derived *)base; } + +[[nodiscard]] const Base *as_base(const Derived *derived) { return (const Base *)derived; } + +[[nodiscard]] float to_float(const int &value) { return (const float &)value; }