[clang-tools-extra] [clang-tidy]Add new check bugprone-casting-through-void (PR #69465)

Congcong Cai via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 18 09:11:45 PDT 2023


https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/69465

>From 627f68e57b2526fb72285ef4831fc3c02a6ee6d0 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 18 Oct 2023 08:47:02 +0800
Subject: [PATCH 1/5] [clang-tidy]Add new check bugprone-casting-through-void

Fixes: #68532
---
 .../bugprone/BugproneTidyModule.cpp           |  3 ++
 .../clang-tidy/bugprone/CMakeLists.txt        |  1 +
 .../bugprone/CastingThroughVoidCheck.cpp      | 46 +++++++++++++++++++
 .../bugprone/CastingThroughVoidCheck.h        | 37 +++++++++++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  6 +++
 .../checks/bugprone/casting-through-void.rst  | 11 +++++
 .../docs/clang-tidy/checks/list.rst           |  1 +
 .../bugprone/casting-through-void.cpp         | 18 ++++++++
 8 files changed, 123 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 543c522899d7a52..7a910037368c832 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -16,6 +16,7 @@
 #include "BadSignalToKillThreadCheck.h"
 #include "BoolPointerImplicitConversionCheck.h"
 #include "BranchCloneCheck.h"
+#include "CastingThroughVoidCheck.h"
 #include "ComparePointerToMemberVirtualFunctionCheck.h"
 #include "CopyConstructorInitCheck.h"
 #include "DanglingHandleCheck.h"
@@ -104,6 +105,8 @@ class BugproneModule : public ClangTidyModule {
     CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>(
         "bugprone-bool-pointer-implicit-conversion");
     CheckFactories.registerCheck<BranchCloneCheck>("bugprone-branch-clone");
+    CheckFactories.registerCheck<CastingThroughVoidCheck>(
+        "bugprone-casting-through-void");
     CheckFactories.registerCheck<ComparePointerToMemberVirtualFunctionCheck>(
         "bugprone-compare-pointer-to-member-virtual-function");
     CheckFactories.registerCheck<CopyConstructorInitCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 0df9e439b715e5a..d443fd8d1452f16 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_library(clangTidyBugproneModule
   BoolPointerImplicitConversionCheck.cpp
   BranchCloneCheck.cpp
   BugproneTidyModule.cpp
+  CastingThroughVoidCheck.cpp
   ComparePointerToMemberVirtualFunctionCheck.cpp
   CopyConstructorInitCheck.cpp
   DanglingHandleCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
new file mode 100644
index 000000000000000..7b9cd7dd51fc47f
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
@@ -0,0 +1,46 @@
+//===--- CastingThroughVoidCheck.cpp - clang-tidy -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CastingThroughVoidCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/ADT/StringSet.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      explicitCastExpr(
+          hasDestinationType(qualType(pointsTo(qualType(unless(voidType()))))
+                                 .bind("target_type")),
+          hasSourceExpression(
+              explicitCastExpr(hasSourceExpression(expr(
+                                   hasType(qualType().bind("source_type")))),
+                               hasDestinationType(pointsTo(voidType())))))
+          .bind("cast"),
+      this);
+}
+
+void CastingThroughVoidCheck::check(const MatchFinder::MatchResult &Result) {
+  ASTContext *Context = Result.Context;
+  const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
+  const auto *TT = Result.Nodes.getNodeAs<QualType>("target_type");
+  const auto *ST = Result.Nodes.getNodeAs<QualType>("source_type");
+  if (Context->hasSameType(*TT, *ST))
+    return;
+  diag(CE->getSourceRange().getBegin(), "do not cast %0 to %1 through void *",
+       DiagnosticIDs::Level::Warning)
+      << ST->getAsString() << TT->getAsString();
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h
new file mode 100644
index 000000000000000..542b1c50dc782e7
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h
@@ -0,0 +1,37 @@
+//===--- CastingThroughVoidCheck.h - clang-tidy -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CASTINGTHROUGHVOIDCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CASTINGTHROUGHVOIDCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// A check detects usage of ``static_cast`` pointer to the other pointer
+/// throght
+/// ``static_cast`` to ``void *`` in C++ code.
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/casting-through-void.html
+class CastingThroughVoidCheck : public ClangTidyCheck {
+public:
+  CastingThroughVoidCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CASTINGTHROUGHVOIDCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index af164d0462d52c1..3ceb844a036240c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -125,6 +125,12 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`bugprone-casting-through-void
+  <clang-tidy/checks/bugprone/casting-through-void>` check.
+
+  Detects usage of ``static_cast`` pointer to the other pointer throght
+  ``static_cast`` to ``void *`` in C++ code.
+
 - New :doc:`bugprone-compare-pointer-to-member-virtual-function
   <clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst
new file mode 100644
index 000000000000000..4a20d8eb9b41c8b
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - bugprone-casting-through-void
+
+bugprone-casting-through-void
+=============================
+
+A check detects usage of ``static_cast`` pointer to the other pointer throght
+``static_cast`` to ``void *`` in C++ code.
+
+Use of these casts can violate type safety and cause the program to access a
+variable that is actually of type ``X`` to be accessed as if it were of an
+unrelated type ``Z``.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 2125ebd7a213c15..fa95bffdc45f9cb 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -82,6 +82,7 @@ Clang-Tidy Checks
    :doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`,
    :doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes"
    :doc:`bugprone-branch-clone <bugprone/branch-clone>`,
+   :doc:`bugprone-casting-through-void <bugprone/casting-through-void>`, "Yes"
    :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
    :doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
    :doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
new file mode 100644
index 000000000000000..f9e8c57201ee802
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy %s bugprone-casting-through-void %t
+
+using T = void*;
+
+void test() {
+  int i = 100;
+  double d = 100;
+
+  static_cast<int *>(static_cast<void *>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not cast double * to int * through void * [bugprone-casting-through-void]
+
+  static_cast<int *>(static_cast<T>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not cast double * to int * through void * [bugprone-casting-through-void]
+
+  static_cast<int *>(static_cast<void *>(&i));
+
+  static_cast<void *>(static_cast<void *>(&i));
+}

>From 77d37e9a95191cfbeb7f4fe7504f86c6dfd0ad2e Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 18 Oct 2023 22:43:03 +0800
Subject: [PATCH 2/5] fix

---
 .../bugprone/CastingThroughVoidCheck.cpp       | 18 ++++++++----------
 .../docs/clang-tidy/checks/list.rst            |  2 +-
 .../checkers/bugprone/casting-through-void.cpp |  4 ++--
 3 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
index 7b9cd7dd51fc47f..f1d6c9170dbcbfe 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
@@ -26,21 +26,19 @@ void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) {
           hasSourceExpression(
               explicitCastExpr(hasSourceExpression(expr(
                                    hasType(qualType().bind("source_type")))),
-                               hasDestinationType(pointsTo(voidType())))))
-          .bind("cast"),
+                               hasDestinationType(pointsTo(voidType())))
+                  .bind("cast"))),
       this);
 }
 
 void CastingThroughVoidCheck::check(const MatchFinder::MatchResult &Result) {
-  ASTContext *Context = Result.Context;
-  const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
-  const auto *TT = Result.Nodes.getNodeAs<QualType>("target_type");
-  const auto *ST = Result.Nodes.getNodeAs<QualType>("source_type");
-  if (Context->hasSameType(*TT, *ST))
+  const auto TT = *Result.Nodes.getNodeAs<QualType>("target_type");
+  const auto ST = *Result.Nodes.getNodeAs<QualType>("source_type");
+  if (Result.Context->hasSameType(TT, ST))
     return;
-  diag(CE->getSourceRange().getBegin(), "do not cast %0 to %1 through void *",
-       DiagnosticIDs::Level::Warning)
-      << ST->getAsString() << TT->getAsString();
+  const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
+  diag(CE->getSourceRange().getBegin(), "do not cast %0 to %1 through 'void*'")
+      << ST << TT;
 }
 
 } // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index fa95bffdc45f9cb..0ce25772aa5b66b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -82,7 +82,7 @@ Clang-Tidy Checks
    :doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`,
    :doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes"
    :doc:`bugprone-branch-clone <bugprone/branch-clone>`,
-   :doc:`bugprone-casting-through-void <bugprone/casting-through-void>`, "Yes"
+   :doc:`bugprone-casting-through-void <bugprone/casting-through-void>`,
    :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
    :doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
    :doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
index f9e8c57201ee802..74265fce3f59068 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
@@ -7,10 +7,10 @@ void test() {
   double d = 100;
 
   static_cast<int *>(static_cast<void *>(&d));
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not cast double * to int * through void * [bugprone-casting-through-void]
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
 
   static_cast<int *>(static_cast<T>(&d));
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not cast double * to int * through void * [bugprone-casting-through-void]
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
 
   static_cast<int *>(static_cast<void *>(&i));
 

>From a432aed9e92e9cd3d4302c09e39fb4eac6dcd943 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 18 Oct 2023 23:30:20 +0800
Subject: [PATCH 3/5] add test

---
 .../bugprone/CastingThroughVoidCheck.cpp      |  7 +-
 .../bugprone/casting-through-void.cpp         | 81 ++++++++++++++++++-
 2 files changed, 83 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
index f1d6c9170dbcbfe..4ce4e3c773f6766 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
@@ -34,7 +34,12 @@ void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) {
 void CastingThroughVoidCheck::check(const MatchFinder::MatchResult &Result) {
   const auto TT = *Result.Nodes.getNodeAs<QualType>("target_type");
   const auto ST = *Result.Nodes.getNodeAs<QualType>("source_type");
-  if (Result.Context->hasSameType(TT, ST))
+  if (Result.Context->hasSameType(TT->getUnqualifiedDesugaredType(),
+                                  ST->getUnqualifiedDesugaredType()))
+    return;
+  if (Result.Context->hasSameType(
+          TT->getPointeeType()->getUnqualifiedDesugaredType(),
+          ST->getPointeeType()->getUnqualifiedDesugaredType()))
     return;
   const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
   diag(CE->getSourceRange().getBegin(), "do not cast %0 to %1 through 'void*'")
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
index 74265fce3f59068..4edb33310f45ec7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
@@ -1,11 +1,14 @@
 // RUN: %check_clang_tidy %s bugprone-casting-through-void %t
 
 using T = void*;
+using CT = const void*;
 
-void test() {
-  int i = 100;
-  double d = 100;
+int i = 100;
+double d = 100;
+const int ci = 100;
+const double cd = 100;
 
+void normal_test() {
   static_cast<int *>(static_cast<void *>(&d));
   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
 
@@ -13,6 +16,76 @@ void test() {
   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
 
   static_cast<int *>(static_cast<void *>(&i));
-
   static_cast<void *>(static_cast<void *>(&i));
 }
+
+void const_pointer_test() {
+  static_cast<int *const>(static_cast<void *>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void*' [bugprone-casting-through-void]
+
+  static_cast<int *const>(static_cast<T>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void*' [bugprone-casting-through-void]
+
+  static_cast<int *const>(static_cast<void *>(&i));
+  static_cast<void *const>(static_cast<void *>(&i));
+}
+
+void const_test() {
+  static_cast<const int *>(static_cast<const void *>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'void*' [bugprone-casting-through-void]
+
+  static_cast<const int *>(static_cast<const T>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'void*' [bugprone-casting-through-void]
+
+  static_cast<const int *>(static_cast<const void *>(&i));
+  static_cast<const void *>(static_cast<const void *>(&i));
+
+  static_cast<const int *>(static_cast<const void *>(&cd));
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'void*' [bugprone-casting-through-void]
+
+  static_cast<const int *>(static_cast<const CT>(&cd));
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'void*' [bugprone-casting-through-void]
+
+  static_cast<const int *>(static_cast<const void *>(&ci));
+  static_cast<const void *>(static_cast<const void *>(&ci));
+}
+
+
+void reinterpret_cast_test() {
+  static_cast<int *>(reinterpret_cast<void *>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
+  reinterpret_cast<int *>(static_cast<void *>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
+  reinterpret_cast<int *>(reinterpret_cast<void *>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
+
+  static_cast<int *>(reinterpret_cast<void *>(&i));
+  static_cast<void *>(reinterpret_cast<void *>(&i));
+  reinterpret_cast<int *>(reinterpret_cast<void *>(&i));
+  reinterpret_cast<void *>(reinterpret_cast<void *>(&i));
+  static_cast<int *>(reinterpret_cast<void *>(&i));
+  static_cast<void *>(reinterpret_cast<void *>(&i));
+}
+
+void c_style_cast_test() {
+  static_cast<int *>((void *)&d);
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
+  (int *)(void *)&d;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
+  static_cast<int *>((void *)&d);
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
+
+  static_cast<int *>(reinterpret_cast<void *>(&i));
+  static_cast<void *>(reinterpret_cast<void *>(&i));
+}
+
+struct A {
+   A(void*);
+};
+void cxx_functional_cast() {
+  A(static_cast<void*>(&i));
+}
+
+void bit_cast() {
+  __builtin_bit_cast(int *, static_cast<void *>(&i));
+}

>From 858aff0c29fb8946572c4dc749cfa99ac6f75320 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 18 Oct 2023 23:47:33 +0800
Subject: [PATCH 4/5] support __builtin_bit_cast

---
 .../clang-tidy/bugprone/CastingThroughVoidCheck.cpp    |  3 ++-
 .../clang-tidy/bugprone/CastingThroughVoidCheck.h      |  8 ++------
 clang-tools-extra/docs/ReleaseNotes.rst                |  4 ++--
 .../checks/bugprone/casting-through-void.rst           |  4 ++--
 .../checkers/bugprone/casting-through-void.cpp         |  2 +-
 clang/include/clang/ASTMatchers/ASTMatchers.h          | 10 ++++++++++
 6 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
index 4ce4e3c773f6766..4ac0eda72dc30ad 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp
@@ -27,7 +27,8 @@ void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) {
               explicitCastExpr(hasSourceExpression(expr(
                                    hasType(qualType().bind("source_type")))),
                                hasDestinationType(pointsTo(voidType())))
-                  .bind("cast"))),
+                  .bind("cast")),
+          unless(builtinBitCastExpr())),
       this);
 }
 
diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h
index 542b1c50dc782e7..369242036115814 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h
@@ -13,9 +13,8 @@
 
 namespace clang::tidy::bugprone {
 
-/// A check detects usage of ``static_cast`` pointer to the other pointer
-/// throght
-/// ``static_cast`` to ``void *`` in C++ code.
+/// A check detects usage of cast pointer to the other pointer throght cast to
+/// ``void *`` in C/C++ code.
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/casting-through-void.html
 class CastingThroughVoidCheck : public ClangTidyCheck {
@@ -24,9 +23,6 @@ class CastingThroughVoidCheck : public ClangTidyCheck {
       : ClangTidyCheck(Name, Context) {}
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
-  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
-  }
   std::optional<TraversalKind> getCheckTraversalKind() const override {
     return TK_IgnoreUnlessSpelledInSource;
   }
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3ceb844a036240c..08ba3ca79aa87ef 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -128,8 +128,8 @@ New checks
 - New :doc:`bugprone-casting-through-void
   <clang-tidy/checks/bugprone/casting-through-void>` check.
 
-  Detects usage of ``static_cast`` pointer to the other pointer throght
-  ``static_cast`` to ``void *`` in C++ code.
+  Detects usage of cast pointer to the other pointer throght cast to
+  ``void *`` in C/C++ code.
 
 - New :doc:`bugprone-compare-pointer-to-member-virtual-function
   <clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst
index 4a20d8eb9b41c8b..4c5e70533fa3bc6 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst
@@ -3,8 +3,8 @@
 bugprone-casting-through-void
 =============================
 
-A check detects usage of ``static_cast`` pointer to the other pointer throght
-``static_cast`` to ``void *`` in C++ code.
+A check detects usage of cast pointer to the other pointer throght cast to
+``void *`` in C/C++ code.
 
 Use of these casts can violate type safety and cause the program to access a
 variable that is actually of type ``X`` to be accessed as if it were of an
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
index 4edb33310f45ec7..8cf15c3b08cdb14 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
@@ -87,5 +87,5 @@ void cxx_functional_cast() {
 }
 
 void bit_cast() {
-  __builtin_bit_cast(int *, static_cast<void *>(&i));
+  __builtin_bit_cast(int *, static_cast<void *>(&d));
 }
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 82a26356c58f556..1dad8594ec92843 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2732,6 +2732,16 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr;
 extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFunctionalCastExpr>
     cxxFunctionalCastExpr;
 
+/// Matches a builtin bit cast expression.
+///
+/// Example: Matches __builtin_bit_cast(double, i) in
+/// \code
+///   int64_t i = 100;
+///   double d = __builtin_bit_cast(double, i);
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher<Stmt, BuiltinBitCastExpr>
+    builtinBitCastExpr;
+
 /// Matches functional cast expressions having N != 1 arguments
 ///
 /// Example: Matches Foo(bar, bar)

>From 01c3ab74d3c3f3828366fb9e472cb2e4c6b93466 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Thu, 19 Oct 2023 00:11:28 +0800
Subject: [PATCH 5/5] add functional cast test

---
 .../bugprone/casting-through-void.cpp         | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
index 8cf15c3b08cdb14..f36f51a88d183e2 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp
@@ -1,7 +1,7 @@
 // RUN: %check_clang_tidy %s bugprone-casting-through-void %t
 
-using T = void*;
-using CT = const void*;
+using V = void*;
+using CV = const void*;
 
 int i = 100;
 double d = 100;
@@ -12,7 +12,7 @@ void normal_test() {
   static_cast<int *>(static_cast<void *>(&d));
   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
 
-  static_cast<int *>(static_cast<T>(&d));
+  static_cast<int *>(static_cast<V>(&d));
   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void]
 
   static_cast<int *>(static_cast<void *>(&i));
@@ -23,7 +23,7 @@ void const_pointer_test() {
   static_cast<int *const>(static_cast<void *>(&d));
   // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void*' [bugprone-casting-through-void]
 
-  static_cast<int *const>(static_cast<T>(&d));
+  static_cast<int *const>(static_cast<V>(&d));
   // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void*' [bugprone-casting-through-void]
 
   static_cast<int *const>(static_cast<void *>(&i));
@@ -34,7 +34,7 @@ void const_test() {
   static_cast<const int *>(static_cast<const void *>(&d));
   // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'void*' [bugprone-casting-through-void]
 
-  static_cast<const int *>(static_cast<const T>(&d));
+  static_cast<const int *>(static_cast<const V>(&d));
   // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'void*' [bugprone-casting-through-void]
 
   static_cast<const int *>(static_cast<const void *>(&i));
@@ -43,7 +43,7 @@ void const_test() {
   static_cast<const int *>(static_cast<const void *>(&cd));
   // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'void*' [bugprone-casting-through-void]
 
-  static_cast<const int *>(static_cast<const CT>(&cd));
+  static_cast<const int *>(static_cast<const CV>(&cd));
   // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'void*' [bugprone-casting-through-void]
 
   static_cast<const int *>(static_cast<const void *>(&ci));
@@ -82,8 +82,13 @@ void c_style_cast_test() {
 struct A {
    A(void*);
 };
+using I = int *;
+using D = double *;
 void cxx_functional_cast() {
-  A(static_cast<void*>(&i));
+  A(static_cast<void*>(&d));
+  D(static_cast<void*>(&d));
+  I(static_cast<void*>(&d));
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not cast 'double *' to 'I' (aka 'int *') through 'void*' [bugprone-casting-through-void]
 }
 
 void bit_cast() {



More information about the cfe-commits mailing list