[clang-tools-extra] [clang-tidy] Add `bugprone-virtual-arithmetic` check (PR #91951)

via cfe-commits cfe-commits at lists.llvm.org
Wed May 29 00:22:58 PDT 2024


https://github.com/Discookie updated https://github.com/llvm/llvm-project/pull/91951

>From 69cbd3da19eb0f8eb6758782b46daf99b5b79ea4 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Mon, 6 May 2024 06:11:58 +0000
Subject: [PATCH 01/11] Add `bugprone-virtual-arithmetic` check

Finds pointer arithmetic on classes that declare a virtual function.
---
 .../bugprone/BugproneTidyModule.cpp           |  3 ++
 .../clang-tidy/bugprone/CMakeLists.txt        |  1 +
 .../bugprone/VirtualArithmeticCheck.cpp       | 46 +++++++++++++++++
 .../bugprone/VirtualArithmeticCheck.h         | 30 +++++++++++
 .../checks/bugprone/virtual-arithmetic.rst    | 50 +++++++++++++++++++
 .../docs/clang-tidy/checks/list.rst           |  1 +
 .../checkers/bugprone/virtual-arithmetic.cpp  | 45 +++++++++++++++++
 7 files changed, 176 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 1b92d2e60cc17..813f6720074ae 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -91,6 +91,7 @@
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
 #include "UseAfterMoveCheck.h"
+#include "VirtualArithmeticCheck.h"
 #include "VirtualNearMissCheck.h"
 
 namespace clang::tidy {
@@ -254,6 +255,8 @@ class BugproneModule : public ClangTidyModule {
     CheckFactories.registerCheck<UnusedReturnValueCheck>(
         "bugprone-unused-return-value");
     CheckFactories.registerCheck<UseAfterMoveCheck>("bugprone-use-after-move");
+    CheckFactories.registerCheck<VirtualArithmeticCheck>(
+        "bugprone-virtual-arithmetic");
     CheckFactories.registerCheck<VirtualNearMissCheck>(
         "bugprone-virtual-near-miss");
   }
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 2d303191f8865..ec1f3231e7990 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -87,6 +87,7 @@ add_clang_library(clangTidyBugproneModule
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
   UseAfterMoveCheck.cpp
+  VirtualArithmeticCheck.cpp
   VirtualNearMissCheck.cpp
 
   LINK_LIBS
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
new file mode 100644
index 0000000000000..57347af2b5881
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
@@ -0,0 +1,46 @@
+//===--- VirtualArithmeticCheck.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 "VirtualArithmeticCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+void VirtualArithmeticCheck::registerMatchers(MatchFinder *Finder) {
+  const auto PointerExprWithVirtualMethod =
+      expr(hasType(pointerType(pointee(hasDeclaration(
+               cxxRecordDecl(hasMethod(isVirtualAsWritten())))))))
+          .bind("pointer");
+
+  const auto ArraySubscript =
+      arraySubscriptExpr(hasBase(PointerExprWithVirtualMethod));
+
+  const auto BinaryOperators =
+      binaryOperator(hasAnyOperatorName("+", "-", "+=", "-="),
+                     hasEitherOperand(PointerExprWithVirtualMethod));
+
+  const auto UnaryOperators =
+      unaryOperator(hasAnyOperatorName("++", "--"),
+                    hasUnaryOperand(PointerExprWithVirtualMethod));
+
+  Finder->addMatcher(
+      expr(anyOf(ArraySubscript, BinaryOperators, UnaryOperators)), this);
+}
+
+void VirtualArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *PointerExpr = Result.Nodes.getNodeAs<Expr>("pointer");
+
+  diag(PointerExpr->getBeginLoc(),
+       "pointer arithmetic on class that declares a virtual function, "
+       "undefined behavior if the pointee is a different class");
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
new file mode 100644
index 0000000000000..6a5f86a391747
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
@@ -0,0 +1,30 @@
+//===--- VirtualArithmeticCheck.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_VIRTUAL_ARITHMETIC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Finds pointer arithmetic on classes that declare a virtual function.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/virtual-arithmetic.html
+class VirtualArithmeticCheck : public ClangTidyCheck {
+public:
+  VirtualArithmeticCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
new file mode 100644
index 0000000000000..69d43e13392be
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
@@ -0,0 +1,50 @@
+.. title:: clang-tidy - bugprone-virtual-arithmetic
+
+bugprone-virtual-arithmetic
+===========================
+
+Warn if pointer arithmetic is performed on a class that declares a
+virtual function.
+
+Pointer arithmetic on polymorphic objects where the pointer's static type is 
+different from its dynamic type is undefined behavior.
+Finding pointers where the static type contains a virtual member function is a
+good heuristic, as the pointer is likely to point to a different, derived class.
+
+This check corresponds to the SEI Cert rule `CTR56-CPP: Do not use pointer arithmetic on polymorphic objects <https://wiki.sei.cmu.edu/confluence/display/cplusplus/CTR56-CPP.+Do+not+use+pointer+arithmetic+on+polymorphic+objects>`_.
+
+Example:
+
+.. code-block:: c++
+
+  struct Base {
+    virtual void ~Base();
+  };
+
+  struct Derived : public Base {};
+
+  void foo() {
+    Base *b = new Derived[10];
+
+    b += 1;
+    // warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class
+
+    delete[] static_cast<Derived*>(b);
+  }
+
+Classes that do not declare a new virtual function are excluded,
+as they make up the majority of false positives.
+
+.. code-block:: c++
+
+  void bar() {
+    Base *b = new Base[10];
+    b += 1; // warning, as Base has a virtual destructor
+
+    delete[] b;
+
+    Derived *d = new Derived[10];
+    d += 1; // no warning, as Derived overrides the destructor
+
+    delete[] d;
+  }
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 5cdaf9e35b6ac..ba1e5cafa6e47 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -157,6 +157,7 @@ Clang-Tidy Checks
    :doc:`bugprone-unused-raii <bugprone/unused-raii>`, "Yes"
    :doc:`bugprone-unused-return-value <bugprone/unused-return-value>`,
    :doc:`bugprone-use-after-move <bugprone/use-after-move>`,
+   :doc:`bugprone-virtual-arithmetic <bugprone/virtual-arithmetic>`,
    :doc:`bugprone-virtual-near-miss <bugprone/virtual-near-miss>`, "Yes"
    :doc:`cert-dcl50-cpp <cert/dcl50-cpp>`,
    :doc:`cert-dcl58-cpp <cert/dcl58-cpp>`,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
new file mode 100644
index 0000000000000..d772112293cbc
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
@@ -0,0 +1,45 @@
+// RUN: %check_clang_tidy %s bugprone-virtual-arithmetic %t
+
+class Base {
+public:  
+  virtual ~Base() {}
+};
+
+class Derived : public Base {};
+
+void operators() {
+  Base *b = new Derived[10];
+
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+  b = b + 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+  b++;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+  b[1];
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+  delete[] static_cast<Derived*>(b);
+}
+
+void subclassWarnings() {
+  Base *b = new Base[10];
+
+  // False positive that's impossible to distinguish without
+  // path-sensitive analysis, but the code is bug-prone regardless.
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+  delete[] b;
+
+  // Common false positive is a class that overrides all parent functions.
+  Derived *d = new Derived[10];
+
+  d += 1;
+  // no-warning
+
+  delete[] d;
+}
\ No newline at end of file

>From 47068bd748cfb6f1b74b006d0f9918103f936a34 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Mon, 13 May 2024 09:43:46 +0000
Subject: [PATCH 02/11] Display the classname that has the virtual function

Useful for reports within template instantiations.
---
 .../bugprone/VirtualArithmeticCheck.cpp       |  7 ++++--
 .../checkers/bugprone/virtual-arithmetic.cpp  | 24 +++++++++++++++----
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
index 57347af2b5881..dec43ae9bd8ca 100644
--- a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
@@ -37,10 +37,13 @@ void VirtualArithmeticCheck::registerMatchers(MatchFinder *Finder) {
 
 void VirtualArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *PointerExpr = Result.Nodes.getNodeAs<Expr>("pointer");
+  const CXXRecordDecl *PointeeType =
+      PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
 
   diag(PointerExpr->getBeginLoc(),
-       "pointer arithmetic on class that declares a virtual function, "
-       "undefined behavior if the pointee is a different class");
+       "pointer arithmetic on class '%0' that declares a virtual function, "
+       "undefined behavior if the pointee is a different class")
+      << PointeeType->getName();
 }
 
 } // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
index d772112293cbc..d89e75186c60f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
@@ -11,16 +11,16 @@ void operators() {
   Base *b = new Derived[10];
 
   b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
 
   b = b + 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
 
   b++;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
 
   b[1];
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
 
   delete[] static_cast<Derived*>(b);
 }
@@ -31,7 +31,7 @@ void subclassWarnings() {
   // False positive that's impossible to distinguish without
   // path-sensitive analysis, but the code is bug-prone regardless.
   b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
 
   delete[] b;
 
@@ -42,4 +42,18 @@ void subclassWarnings() {
   // no-warning
 
   delete[] d;
+}
+
+template <typename T>
+void templateWarning(T *t) {
+  // FIXME: Show the location of the template instantiation in diagnostic.
+  t += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+}
+
+void functionArgument(Base *b) {
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+
+  templateWarning(b);
 }
\ No newline at end of file

>From df2e3f1d40b674a8a49b678bf3403a5a4cb5e08b Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Thu, 23 May 2024 11:26:50 +0000
Subject: [PATCH 03/11] Rename check to
 `bugprone-pointer-arithmetic-on-polymorphic-object`

---
 .../clang-tidy/bugprone/BugproneTidyModule.cpp   |  6 +++---
 .../clang-tidy/bugprone/CMakeLists.txt           |  2 +-
 ...ointerArithmeticOnPolymorphicObjectCheck.cpp} | 14 ++++++++------
 ... PointerArithmeticOnPolymorphicObjectCheck.h} | 15 ++++++++-------
 ...pointer-arithmetic-on-polymorphic-object.rst} | 10 +++++-----
 .../docs/clang-tidy/checks/list.rst              |  2 +-
 ...pointer-arithmetic-on-polymorphic-object.cpp} | 16 ++++++++--------
 7 files changed, 34 insertions(+), 31 deletions(-)
 rename clang-tools-extra/clang-tidy/bugprone/{VirtualArithmeticCheck.cpp => PointerArithmeticOnPolymorphicObjectCheck.cpp} (74%)
 rename clang-tools-extra/clang-tidy/bugprone/{VirtualArithmeticCheck.h => PointerArithmeticOnPolymorphicObjectCheck.h} (52%)
 rename clang-tools-extra/docs/clang-tidy/checks/bugprone/{virtual-arithmetic.rst => pointer-arithmetic-on-polymorphic-object.rst} (88%)
 rename clang-tools-extra/test/clang-tidy/checkers/bugprone/{virtual-arithmetic.cpp => pointer-arithmetic-on-polymorphic-object.cpp} (56%)

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 813f6720074ae..689eb92a3d8d1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -51,6 +51,7 @@
 #include "NotNullTerminatedResultCheck.h"
 #include "OptionalValueConversionCheck.h"
 #include "ParentVirtualCallCheck.h"
+#include "PointerArithmeticOnPolymorphicObjectCheck.h"
 #include "PosixReturnCheck.h"
 #include "RedundantBranchConditionCheck.h"
 #include "ReservedIdentifierCheck.h"
@@ -91,7 +92,6 @@
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
 #include "UseAfterMoveCheck.h"
-#include "VirtualArithmeticCheck.h"
 #include "VirtualNearMissCheck.h"
 
 namespace clang::tidy {
@@ -172,6 +172,8 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-multiple-statement-macro");
     CheckFactories.registerCheck<OptionalValueConversionCheck>(
         "bugprone-optional-value-conversion");
+    CheckFactories.registerCheck<PointerArithmeticOnPolymorphicObjectCheck>(
+        "bugprone-pointer-arithmetic-on-polymorphic-object");
     CheckFactories.registerCheck<RedundantBranchConditionCheck>(
         "bugprone-redundant-branch-condition");
     CheckFactories.registerCheck<cppcoreguidelines::NarrowingConversionsCheck>(
@@ -255,8 +257,6 @@ class BugproneModule : public ClangTidyModule {
     CheckFactories.registerCheck<UnusedReturnValueCheck>(
         "bugprone-unused-return-value");
     CheckFactories.registerCheck<UseAfterMoveCheck>("bugprone-use-after-move");
-    CheckFactories.registerCheck<VirtualArithmeticCheck>(
-        "bugprone-virtual-arithmetic");
     CheckFactories.registerCheck<VirtualNearMissCheck>(
         "bugprone-virtual-near-miss");
   }
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index ec1f3231e7990..cb0d8ae98bac5 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -48,6 +48,7 @@ add_clang_library(clangTidyBugproneModule
   NotNullTerminatedResultCheck.cpp
   OptionalValueConversionCheck.cpp
   ParentVirtualCallCheck.cpp
+  PointerArithmeticOnPolymorphicObjectCheck.cpp
   PosixReturnCheck.cpp
   RedundantBranchConditionCheck.cpp
   ReservedIdentifierCheck.cpp
@@ -87,7 +88,6 @@ add_clang_library(clangTidyBugproneModule
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
   UseAfterMoveCheck.cpp
-  VirtualArithmeticCheck.cpp
   VirtualNearMissCheck.cpp
 
   LINK_LIBS
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
similarity index 74%
rename from clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
rename to clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index dec43ae9bd8ca..918c38b416f66 100644
--- a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -1,4 +1,4 @@
-//===--- VirtualArithmeticCheck.cpp - clang-tidy---------------------------===//
+//===--- PointerArithmeticOnPolymorphicObjectCheck.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.
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "VirtualArithmeticCheck.h"
+#include "PointerArithmeticOnPolymorphicObjectCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 
@@ -14,7 +14,8 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::bugprone {
 
-void VirtualArithmeticCheck::registerMatchers(MatchFinder *Finder) {
+void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
+    MatchFinder *Finder) {
   const auto PointerExprWithVirtualMethod =
       expr(hasType(pointerType(pointee(hasDeclaration(
                cxxRecordDecl(hasMethod(isVirtualAsWritten())))))))
@@ -35,14 +36,15 @@ void VirtualArithmeticCheck::registerMatchers(MatchFinder *Finder) {
       expr(anyOf(ArraySubscript, BinaryOperators, UnaryOperators)), this);
 }
 
-void VirtualArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
+void PointerArithmeticOnPolymorphicObjectCheck::check(
+    const MatchFinder::MatchResult &Result) {
   const auto *PointerExpr = Result.Nodes.getNodeAs<Expr>("pointer");
   const CXXRecordDecl *PointeeType =
       PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
 
   diag(PointerExpr->getBeginLoc(),
-       "pointer arithmetic on class '%0' that declares a virtual function, "
-       "undefined behavior if the pointee is a different class")
+       "pointer arithmetic on polymorphic class '%0' that declares a virtual "
+       "function, undefined behavior if the pointee is a different class")
       << PointeeType->getName();
 }
 
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
similarity index 52%
rename from clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
rename to clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
index 6a5f86a391747..0277d2b53af7b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
@@ -1,4 +1,4 @@
-//===--- VirtualArithmeticCheck.h - clang-tidy-------------------*- C++ -*-===//
+//===--- PointerArithmeticOnPolymorphicObjectCheck.h ------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H
 
 #include "../ClangTidyCheck.h"
 
@@ -16,10 +16,11 @@ namespace clang::tidy::bugprone {
 /// Finds pointer arithmetic on classes that declare a virtual function.
 ///
 /// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/virtual-arithmetic.html
-class VirtualArithmeticCheck : public ClangTidyCheck {
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.html
+class PointerArithmeticOnPolymorphicObjectCheck : public ClangTidyCheck {
 public:
-  VirtualArithmeticCheck(StringRef Name, ClangTidyContext *Context)
+  PointerArithmeticOnPolymorphicObjectCheck(StringRef Name,
+                                            ClangTidyContext *Context)
       : ClangTidyCheck(Name, Context) {}
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@@ -27,4 +28,4 @@ class VirtualArithmeticCheck : public ClangTidyCheck {
 
 } // namespace clang::tidy::bugprone
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
similarity index 88%
rename from clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
rename to clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
index 69d43e13392be..a3fa06918bbb3 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - bugprone-virtual-arithmetic
+.. title:: clang-tidy - bugprone-pointer-arithmetic-on-polymorphic-object
 
-bugprone-virtual-arithmetic
-===========================
+bugprone-pointer-arithmetic-on-polymorphic-object
+=================================================
 
 Warn if pointer arithmetic is performed on a class that declares a
 virtual function.
@@ -11,8 +11,6 @@ different from its dynamic type is undefined behavior.
 Finding pointers where the static type contains a virtual member function is a
 good heuristic, as the pointer is likely to point to a different, derived class.
 
-This check corresponds to the SEI Cert rule `CTR56-CPP: Do not use pointer arithmetic on polymorphic objects <https://wiki.sei.cmu.edu/confluence/display/cplusplus/CTR56-CPP.+Do+not+use+pointer+arithmetic+on+polymorphic+objects>`_.
-
 Example:
 
 .. code-block:: c++
@@ -48,3 +46,5 @@ as they make up the majority of false positives.
 
     delete[] d;
   }
+
+This check corresponds to the SEI Cert rule `CTR56-CPP: Do not use pointer arithmetic on polymorphic objects <https://wiki.sei.cmu.edu/confluence/display/cplusplus/CTR56-CPP.+Do+not+use+pointer+arithmetic+on+polymorphic+objects>`_.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index ba1e5cafa6e47..80e4112a3b780 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -157,7 +157,7 @@ Clang-Tidy Checks
    :doc:`bugprone-unused-raii <bugprone/unused-raii>`, "Yes"
    :doc:`bugprone-unused-return-value <bugprone/unused-return-value>`,
    :doc:`bugprone-use-after-move <bugprone/use-after-move>`,
-   :doc:`bugprone-virtual-arithmetic <bugprone/virtual-arithmetic>`,
+   :doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
    :doc:`bugprone-virtual-near-miss <bugprone/virtual-near-miss>`, "Yes"
    :doc:`cert-dcl50-cpp <cert/dcl50-cpp>`,
    :doc:`cert-dcl58-cpp <cert/dcl58-cpp>`,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
similarity index 56%
rename from clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
index d89e75186c60f..c5c92d2ccd9ce 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-virtual-arithmetic %t
+// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t
 
 class Base {
 public:  
@@ -11,16 +11,16 @@ void operators() {
   Base *b = new Derived[10];
 
   b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b = b + 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b++;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b[1];
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   delete[] static_cast<Derived*>(b);
 }
@@ -31,7 +31,7 @@ void subclassWarnings() {
   // False positive that's impossible to distinguish without
   // path-sensitive analysis, but the code is bug-prone regardless.
   b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
 
   delete[] b;
 
@@ -48,12 +48,12 @@ template <typename T>
 void templateWarning(T *t) {
   // FIXME: Show the location of the template instantiation in diagnostic.
   t += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
 }
 
 void functionArgument(Base *b) {
   b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
 
   templateWarning(b);
 }
\ No newline at end of file

>From fe0d5a7a5f24f75e7eb6e19c69e8d8ea37d7491f Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:10:38 +0000
Subject: [PATCH 04/11] Add `MatchInheritedVirtualFunctions` option

---
 ...nterArithmeticOnPolymorphicObjectCheck.cpp |  39 +++++--
 ...ointerArithmeticOnPolymorphicObjectCheck.h |  10 +-
 clang-tools-extra/docs/ReleaseNotes.rst       |   5 +
 ...inter-arithmetic-on-polymorphic-object.rst |  48 +++++----
 ...r-arithmetic-on-polymorphic-object-all.cpp | 100 ++++++++++++++++++
 ...hmetic-on-polymorphic-object-decl-only.cpp |  98 +++++++++++++++++
 ...inter-arithmetic-on-polymorphic-object.cpp |  59 -----------
 7 files changed, 267 insertions(+), 92 deletions(-)
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
 delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 918c38b416f66..6d4fc67a4b79e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -14,23 +14,42 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::bugprone {
 
+PointerArithmeticOnPolymorphicObjectCheck::
+    PointerArithmeticOnPolymorphicObjectCheck(StringRef Name,
+                                              ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      MatchInheritedVirtualFunctions(
+          Options.get("MatchInheritedVirtualFunctions", false)) {}
+
+void PointerArithmeticOnPolymorphicObjectCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "MatchInheritedVirtualFunctions", true);
+}
+
 void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
     MatchFinder *Finder) {
+  const auto PolymorphicPointerExpr =
+      expr(hasType(pointerType(
+               pointee(hasDeclaration(cxxRecordDecl(hasMethod(isVirtual())))))))
+          .bind("pointer");
+
   const auto PointerExprWithVirtualMethod =
-      expr(hasType(pointerType(pointee(hasDeclaration(
-               cxxRecordDecl(hasMethod(isVirtualAsWritten())))))))
+      expr(hasType(pointerType(pointee(hasDeclaration(cxxRecordDecl(
+               hasMethod(anyOf(isVirtualAsWritten(), isPure()))))))))
           .bind("pointer");
 
-  const auto ArraySubscript =
-      arraySubscriptExpr(hasBase(PointerExprWithVirtualMethod));
+  const auto SelectedPointerExpr = MatchInheritedVirtualFunctions
+                                       ? PolymorphicPointerExpr
+                                       : PointerExprWithVirtualMethod;
+
+  const auto ArraySubscript = arraySubscriptExpr(hasBase(SelectedPointerExpr));
 
   const auto BinaryOperators =
       binaryOperator(hasAnyOperatorName("+", "-", "+=", "-="),
-                     hasEitherOperand(PointerExprWithVirtualMethod));
+                     hasEitherOperand(SelectedPointerExpr));
 
-  const auto UnaryOperators =
-      unaryOperator(hasAnyOperatorName("++", "--"),
-                    hasUnaryOperand(PointerExprWithVirtualMethod));
+  const auto UnaryOperators = unaryOperator(
+      hasAnyOperatorName("++", "--"), hasUnaryOperand(SelectedPointerExpr));
 
   Finder->addMatcher(
       expr(anyOf(ArraySubscript, BinaryOperators, UnaryOperators)), this);
@@ -43,8 +62,8 @@ void PointerArithmeticOnPolymorphicObjectCheck::check(
       PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
 
   diag(PointerExpr->getBeginLoc(),
-       "pointer arithmetic on polymorphic class '%0' that declares a virtual "
-       "function, undefined behavior if the pointee is a different class")
+       "pointer arithmetic on polymorphic class '%0', "
+       "undefined behavior if the pointee is a different class")
       << PointeeType->getName();
 }
 
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
index 0277d2b53af7b..0144b840b3429 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
@@ -13,17 +13,21 @@
 
 namespace clang::tidy::bugprone {
 
-/// Finds pointer arithmetic on classes that declare a virtual function.
+/// Finds pointer arithmetic performed on classes that declare a
+/// virtual function.
 ///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.html
 class PointerArithmeticOnPolymorphicObjectCheck : public ClangTidyCheck {
 public:
   PointerArithmeticOnPolymorphicObjectCheck(StringRef Name,
-                                            ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context) {}
+                                            ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  const bool MatchInheritedVirtualFunctions;
 };
 
 } // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index d59da3a61b7b6..cc7038488b228 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -126,6 +126,11 @@ New checks
   reference. This may cause use-after-free errors if the caller uses xvalues as
   arguments.
 
+- New :doc:`bugprone-pointer-arithmetic-on-polymorphic-object
+  <clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object>` check.
+
+  Finds pointer arithmetic performed on classes that declare a virtual function.
+
 - New :doc:`bugprone-suspicious-stringview-data-usage
   <clang-tidy/checks/bugprone/suspicious-stringview-data-usage>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
index a3fa06918bbb3..ac782d20a043f 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
@@ -3,8 +3,7 @@
 bugprone-pointer-arithmetic-on-polymorphic-object
 =================================================
 
-Warn if pointer arithmetic is performed on a class that declares a
-virtual function.
+Finds pointer arithmetic performed on classes that declare a virtual function.
 
 Pointer arithmetic on polymorphic objects where the pointer's static type is 
 different from its dynamic type is undefined behavior.
@@ -25,26 +24,35 @@ Example:
     Base *b = new Derived[10];
 
     b += 1;
-    // warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class
+    // warning: pointer arithmetic on class that declares a virtual function,
+    // undefined behavior if the pointee is a different class
 
     delete[] static_cast<Derived*>(b);
   }
 
-Classes that do not declare a new virtual function are excluded,
-as they make up the majority of false positives.
-
-.. code-block:: c++
-
-  void bar() {
-    Base *b = new Base[10];
-    b += 1; // warning, as Base has a virtual destructor
-
-    delete[] b;
-
-    Derived *d = new Derived[10];
-    d += 1; // no warning, as Derived overrides the destructor
-
-    delete[] d;
-  }
-
 This check corresponds to the SEI Cert rule `CTR56-CPP: Do not use pointer arithmetic on polymorphic objects <https://wiki.sei.cmu.edu/confluence/display/cplusplus/CTR56-CPP.+Do+not+use+pointer+arithmetic+on+polymorphic+objects>`_.
+
+Options
+-------
+
+.. option:: MatchInheritedVirtualFunctions
+
+  When ``true``, all classes with a virtual function are considered,
+  even if the function is inherited.
+  Classes that do not declare a new virtual function are excluded
+  by default, as they make up the majority of false positives.
+
+  .. code-block:: c++
+  
+    void bar() {
+      Base *b = new Base[10];
+      b += 1; // warning, as Base declares a virtual destructor
+  
+      delete[] b;
+  
+      Derived *d = new Derived[10]; // Derived overrides the destructor, and
+                                    // declares no other virtual functions
+      d += 1; // warning only if MatchVirtualDeclarationsOnly is set to true
+  
+      delete[] d;
+    }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
new file mode 100644
index 0000000000000..2498c292b0027
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
@@ -0,0 +1,100 @@
+// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: {bugprone-pointer-arithmetic-on-polymorphic-object.MatchInheritedVirtualFunctions: true}}"
+
+class Base {
+public:  
+  virtual ~Base() {}
+};
+
+class Derived : public Base {};
+
+class AbstractBase {
+public:
+  virtual void f() = 0;
+  virtual ~AbstractBase() {}
+};
+
+class AbstractInherited : public AbstractBase {};
+
+class AbstractOverride : public AbstractInherited {
+public:
+  void f() override {}
+};
+
+void operators() {
+  Base *b = new Derived[10];
+
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+  b = b + 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+  b++;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+  b[1];
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+  delete[] static_cast<Derived*>(b);
+}
+
+void subclassWarnings() {
+  Base *b = new Base[10];
+
+  // False positive that's impossible to distinguish without
+  // path-sensitive analysis, but the code is bug-prone regardless.
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+  delete[] b;
+
+  // Common false positive is a class that overrides all parent functions.
+  // Matched due to the check configuration.
+  Derived *d = new Derived[10];
+
+  d += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+
+  delete[] d;
+}
+
+void abstractWarnings() {
+  // Classes with an abstract member funtion are always matched.
+  AbstractBase *ab = new AbstractOverride[10];
+
+  ab += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractBase'
+
+  delete[] static_cast<AbstractOverride*>(ab);
+
+  AbstractInherited *ai = new AbstractOverride[10];
+
+  ai += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractInherited'
+
+  delete[] static_cast<AbstractOverride*>(ai);
+
+  // Matched due to the check configuration.
+  AbstractOverride *ao = new AbstractOverride[10];
+
+  ao += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractOverride'
+
+  delete[] ao;
+}
+
+template <typename T>
+void templateWarning(T *t) {
+  // FIXME: Show the location of the template instantiation in diagnostic.
+  t += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+}
+
+void functionArgument(Base *b) {
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+  templateWarning(b);
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
new file mode 100644
index 0000000000000..4d5583c31d34e
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
@@ -0,0 +1,98 @@
+// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t
+
+class Base {
+public:  
+  virtual ~Base() {}
+};
+
+class Derived : public Base {};
+
+class AbstractBase {
+public:
+  virtual void f() = 0;
+  virtual ~AbstractBase() {}
+};
+
+class AbstractInherited : public AbstractBase {};
+
+class AbstractOverride : public AbstractInherited {
+public:
+  void f() override {}
+};
+
+void operators() {
+  Base *b = new Derived[10];
+
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+  b = b + 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+  b++;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+  b[1];
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+  delete[] static_cast<Derived*>(b);
+}
+
+void subclassWarnings() {
+  Base *b = new Base[10];
+
+  // False positive that's impossible to distinguish without
+  // path-sensitive analysis, but the code is bug-prone regardless.
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+  delete[] b;
+
+  // Common false positive is a class that overrides all parent functions.
+  Derived *d = new Derived[10];
+
+  d += 1;
+  // no-warning
+
+  delete[] d;
+}
+
+void abstractWarnings() {
+  // Classes with an abstract member funtion are always matched.
+  AbstractBase *ab = new AbstractOverride[10];
+
+  ab += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractBase'
+
+  delete[] static_cast<AbstractOverride*>(ab);
+
+  AbstractInherited *ai = new AbstractOverride[10];
+
+  // FIXME: Match abstract functions that were not overridden.
+  ai += 1;
+  // no-warning
+
+  delete[] static_cast<AbstractOverride*>(ai);
+
+  // If all abstract member functions are overridden, the class is not matched.
+  AbstractOverride *ao = new AbstractOverride[10];
+
+  ao += 1;
+  // no-warning
+
+  delete[] ao;
+}
+
+template <typename T>
+void templateWarning(T *t) {
+  // FIXME: Show the location of the template instantiation in diagnostic.
+  t += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+}
+
+void functionArgument(Base *b) {
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+  templateWarning(b);
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
deleted file mode 100644
index c5c92d2ccd9ce..0000000000000
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t
-
-class Base {
-public:  
-  virtual ~Base() {}
-};
-
-class Derived : public Base {};
-
-void operators() {
-  Base *b = new Derived[10];
-
-  b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
-
-  b = b + 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
-
-  b++;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
-
-  b[1];
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
-
-  delete[] static_cast<Derived*>(b);
-}
-
-void subclassWarnings() {
-  Base *b = new Base[10];
-
-  // False positive that's impossible to distinguish without
-  // path-sensitive analysis, but the code is bug-prone regardless.
-  b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
-
-  delete[] b;
-
-  // Common false positive is a class that overrides all parent functions.
-  Derived *d = new Derived[10];
-
-  d += 1;
-  // no-warning
-
-  delete[] d;
-}
-
-template <typename T>
-void templateWarning(T *t) {
-  // FIXME: Show the location of the template instantiation in diagnostic.
-  t += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
-}
-
-void functionArgument(Base *b) {
-  b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
-
-  templateWarning(b);
-}
\ No newline at end of file

>From f37392270da0540da49666cb09aeb971739fd2d8 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:11:55 +0000
Subject: [PATCH 05/11] Restrict to C++

---
 .../bugprone/PointerArithmeticOnPolymorphicObjectCheck.h       | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
index 0144b840b3429..057691a3d57c7 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
@@ -25,6 +25,9 @@ class PointerArithmeticOnPolymorphicObjectCheck : public ClangTidyCheck {
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   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;
+  }
 
 private:
   const bool MatchInheritedVirtualFunctions;

>From a29c9cdfc1c88aa8778c8acf9b0c7abe8ed7b786 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:42:05 +0000
Subject: [PATCH 06/11] Update check message and comments

---
 ...PointerArithmeticOnPolymorphicObjectCheck.cpp |  2 +-
 .../pointer-arithmetic-on-polymorphic-object.rst |  3 ++-
 ...nter-arithmetic-on-polymorphic-object-all.cpp | 16 +++++++++-------
 ...rithmetic-on-polymorphic-object-decl-only.cpp | 16 +++++++++-------
 4 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 6d4fc67a4b79e..b994cab8c2a3b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -62,7 +62,7 @@ void PointerArithmeticOnPolymorphicObjectCheck::check(
       PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
 
   diag(PointerExpr->getBeginLoc(),
-       "pointer arithmetic on polymorphic class '%0', "
+       "pointer arithmetic on polymorphic class '%0', which can result in "
        "undefined behavior if the pointee is a different class")
       << PointeeType->getName();
 }
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
index ac782d20a043f..598c14be04021 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
@@ -25,7 +25,8 @@ Example:
 
     b += 1;
     // warning: pointer arithmetic on class that declares a virtual function,
-    // undefined behavior if the pointee is a different class
+    //          which can result in undefined behavior if the pointee is a
+    //          different class
 
     delete[] static_cast<Derived*>(b);
   }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
index 2498c292b0027..de731b5b7ead7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
@@ -15,7 +15,9 @@ class AbstractBase {
   virtual ~AbstractBase() {}
 };
 
-class AbstractInherited : public AbstractBase {};
+class AbstractInherited : public AbstractBase {
+  void f() override = 0;
+};
 
 class AbstractOverride : public AbstractInherited {
 public:
@@ -26,16 +28,16 @@ void operators() {
   Base *b = new Derived[10];
 
   b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b = b + 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b++;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b[1];
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   delete[] static_cast<Derived*>(b);
 }
@@ -51,7 +53,7 @@ void subclassWarnings() {
   delete[] b;
 
   // Common false positive is a class that overrides all parent functions.
-  // Matched due to the check configuration.
+  // Is a warning because of the check configuration.
   Derived *d = new Derived[10];
 
   d += 1;
@@ -76,7 +78,7 @@ void abstractWarnings() {
 
   delete[] static_cast<AbstractOverride*>(ai);
 
-  // Matched due to the check configuration.
+  // Is a warning because of the check configuration.
   AbstractOverride *ao = new AbstractOverride[10];
 
   ao += 1;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
index 4d5583c31d34e..e511d7dc644d8 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
@@ -13,7 +13,10 @@ class AbstractBase {
   virtual ~AbstractBase() {}
 };
 
-class AbstractInherited : public AbstractBase {};
+class AbstractInherited : public AbstractBase {
+  // FIXME: Check pure virtual functions transitively, not just explicit delete.
+  void f() override = 0;
+};
 
 class AbstractOverride : public AbstractInherited {
 public:
@@ -24,16 +27,16 @@ void operators() {
   Base *b = new Derived[10];
 
   b += 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b = b + 1;
-  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b++;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   b[1];
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
   delete[] static_cast<Derived*>(b);
 }
@@ -68,9 +71,8 @@ void abstractWarnings() {
 
   AbstractInherited *ai = new AbstractOverride[10];
 
-  // FIXME: Match abstract functions that were not overridden.
   ai += 1;
-  // no-warning
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractInherited'
 
   delete[] static_cast<AbstractOverride*>(ai);
 

>From 914f349c07b9aff0e5dfc4ba527b6bd8c9294881 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:43:10 +0000
Subject: [PATCH 07/11] Add support for type aliases

---
 ...nterArithmeticOnPolymorphicObjectCheck.cpp | 10 ++++++----
 ...r-arithmetic-on-polymorphic-object-all.cpp | 20 +++++++++++++++++++
 ...hmetic-on-polymorphic-object-decl-only.cpp | 20 +++++++++++++++++++
 3 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index b994cab8c2a3b..16946000e2041 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -29,13 +29,15 @@ void PointerArithmeticOnPolymorphicObjectCheck::storeOptions(
 void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
     MatchFinder *Finder) {
   const auto PolymorphicPointerExpr =
-      expr(hasType(pointerType(
-               pointee(hasDeclaration(cxxRecordDecl(hasMethod(isVirtual())))))))
+      expr(hasType(hasCanonicalType(
+               pointerType(pointee(hasCanonicalType(hasDeclaration(
+                   cxxRecordDecl(cxxRecordDecl(hasMethod(isVirtual()))))))))))
           .bind("pointer");
 
   const auto PointerExprWithVirtualMethod =
-      expr(hasType(pointerType(pointee(hasDeclaration(cxxRecordDecl(
-               hasMethod(anyOf(isVirtualAsWritten(), isPure()))))))))
+      expr(hasType(hasCanonicalType(pointerType(
+               pointee(hasCanonicalType(hasDeclaration(cxxRecordDecl(
+                   hasMethod(anyOf(isVirtualAsWritten(), isPure()))))))))))
           .bind("pointer");
 
   const auto SelectedPointerExpr = MatchInheritedVirtualFunctions
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
index de731b5b7ead7..bdacf09576c93 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
@@ -100,3 +100,23 @@ void functionArgument(Base *b) {
 
   templateWarning(b);
 }
+
+using BaseAlias = Base;
+using DerivedAlias = Derived;
+
+using BasePtr = Base*;
+using DerivedPtr = Derived*;
+
+void typeAliases(BaseAlias *b, DerivedAlias *d, BasePtr bp, DerivedPtr dp) {
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+  d += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+
+  bp += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+  dp += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
index e511d7dc644d8..a7b3c8a19f05d 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
@@ -98,3 +98,23 @@ void functionArgument(Base *b) {
 
   templateWarning(b);
 }
+
+using BaseAlias = Base;
+using DerivedAlias = Derived;
+
+using BasePtr = Base*;
+using DerivedPtr = Derived*;
+
+void typeAliases(BaseAlias *b, DerivedAlias *d, BasePtr bp, DerivedPtr dp) {
+  b += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+  d += 1;
+  // no-warning
+
+  bp += 1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+  dp += 1;
+  // no-warning
+}

>From 801d7ec82550b41fd56ae34966ec5dcfb73112be Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:46:47 +0000
Subject: [PATCH 08/11] Add tests for prefix `++`

---
 .../bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp  | 3 +++
 .../pointer-arithmetic-on-polymorphic-object-decl-only.cpp     | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
index bdacf09576c93..5bf96b44b56b9 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
@@ -36,6 +36,9 @@ void operators() {
   b++;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
+  --b;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
   b[1];
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
index a7b3c8a19f05d..3718c622596cc 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
@@ -35,6 +35,9 @@ void operators() {
   b++;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 
+  --b;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
   b[1];
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
 

>From e5dc6b21cd9e810a0446c788518e690b3c5eff51 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:57:18 +0000
Subject: [PATCH 09/11] Add comment about the UB's cause

---
 .../bugprone/pointer-arithmetic-on-polymorphic-object.rst      | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
index 598c14be04021..b22676f5284d6 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
@@ -6,7 +6,8 @@ bugprone-pointer-arithmetic-on-polymorphic-object
 Finds pointer arithmetic performed on classes that declare a virtual function.
 
 Pointer arithmetic on polymorphic objects where the pointer's static type is 
-different from its dynamic type is undefined behavior.
+different from its dynamic type is undefined behavior, as the two types can
+have different sizes.
 Finding pointers where the static type contains a virtual member function is a
 good heuristic, as the pointer is likely to point to a different, derived class.
 

>From dc7e63cb7e462adafde499849633e7bf92829755 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 04:04:25 +0000
Subject: [PATCH 10/11] Exclude final classes

---
 ...nterArithmeticOnPolymorphicObjectCheck.cpp |  6 ++++--
 ...r-arithmetic-on-polymorphic-object-all.cpp | 21 ++++++++++++++++++-
 ...hmetic-on-polymorphic-object-decl-only.cpp | 21 ++++++++++++++++++-
 3 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 16946000e2041..81cbcfec8d43d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -31,13 +31,15 @@ void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
   const auto PolymorphicPointerExpr =
       expr(hasType(hasCanonicalType(
                pointerType(pointee(hasCanonicalType(hasDeclaration(
-                   cxxRecordDecl(cxxRecordDecl(hasMethod(isVirtual()))))))))))
+                   cxxRecordDecl(cxxRecordDecl(hasMethod(isVirtual())),
+                                 unless(isFinal())))))))))
           .bind("pointer");
 
   const auto PointerExprWithVirtualMethod =
       expr(hasType(hasCanonicalType(pointerType(
                pointee(hasCanonicalType(hasDeclaration(cxxRecordDecl(
-                   hasMethod(anyOf(isVirtualAsWritten(), isPure()))))))))))
+                   hasMethod(anyOf(isVirtualAsWritten(), isPure())),
+                   unless(isFinal())))))))))
           .bind("pointer");
 
   const auto SelectedPointerExpr = MatchInheritedVirtualFunctions
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
index 5bf96b44b56b9..d8213416295ac 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
@@ -9,6 +9,8 @@ class Base {
 
 class Derived : public Base {};
 
+class FinalDerived final : public Base {};
+
 class AbstractBase {
 public:
   virtual void f() = 0;
@@ -63,6 +65,14 @@ void subclassWarnings() {
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
 
   delete[] d;
+
+  // Final classes cannot have a dynamic type.
+  FinalDerived *fd = new FinalDerived[10];
+
+  fd += 1;
+  // no-warning
+
+  delete[] fd;
 }
 
 void abstractWarnings() {
@@ -106,20 +116,29 @@ void functionArgument(Base *b) {
 
 using BaseAlias = Base;
 using DerivedAlias = Derived;
+using FinalDerivedAlias = FinalDerived;
 
 using BasePtr = Base*;
 using DerivedPtr = Derived*;
+using FinalDerivedPtr = FinalDerived*;
 
-void typeAliases(BaseAlias *b, DerivedAlias *d, BasePtr bp, DerivedPtr dp) {
+void typeAliases(BaseAlias *b, DerivedAlias *d, FinalDerivedAlias *fd,
+                 BasePtr bp, DerivedPtr dp, FinalDerivedPtr fdp) {
   b += 1;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
 
   d += 1;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
 
+  fd += 1;
+  // no-warning
+
   bp += 1;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
 
   dp += 1;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+
+  fdp += 1;
+  // no-warning
 }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
index 3718c622596cc..c6cd9d843c7e9 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
@@ -7,6 +7,8 @@ class Base {
 
 class Derived : public Base {};
 
+class FinalDerived final : public Base {};
+
 class AbstractBase {
 public:
   virtual void f() = 0;
@@ -61,6 +63,14 @@ void subclassWarnings() {
   // no-warning
 
   delete[] d;
+
+  // Final classes cannot have a dynamic type.
+  FinalDerived *fd = new FinalDerived[10];
+
+  fd += 1;
+  // no-warning
+
+  delete[] fd;
 }
 
 void abstractWarnings() {
@@ -104,20 +114,29 @@ void functionArgument(Base *b) {
 
 using BaseAlias = Base;
 using DerivedAlias = Derived;
+using FinalDerivedAlias = FinalDerived;
 
 using BasePtr = Base*;
 using DerivedPtr = Derived*;
+using FinalDerivedPtr = FinalDerived*;
 
-void typeAliases(BaseAlias *b, DerivedAlias *d, BasePtr bp, DerivedPtr dp) {
+void typeAliases(BaseAlias *b, DerivedAlias *d, FinalDerivedAlias *fd,
+                 BasePtr bp, DerivedPtr dp, FinalDerivedPtr fdp) {
   b += 1;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
 
   d += 1;
   // no-warning
 
+  fd += 1;
+  // no-warning
+
   bp += 1;
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
 
   dp += 1;
   // no-warning
+
+  fdp += 1;
+  // no-warning
 }

>From 6415b14afba91e9f0d0e4ce54455fb3c6ecbdde9 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 07:22:37 +0000
Subject: [PATCH 11/11] Add CERT alias

---
 clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index b06a903f92b3e..29a73ac89cf01 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -10,6 +10,7 @@
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
 #include "../bugprone/BadSignalToKillThreadCheck.h"
+#include "../bugprone/PointerArithmeticOnPolymorphicObjectCheck.h"
 #include "../bugprone/ReservedIdentifierCheck.h"
 #include "../bugprone/SignalHandlerCheck.h"
 #include "../bugprone/SignedCharMisuseCheck.h"
@@ -237,6 +238,10 @@ class CERTModule : public ClangTidyModule {
     // CON
     CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
         "cert-con54-cpp");
+    // CTR
+    CheckFactories
+        .registerCheck<bugprone::PointerArithmeticOnPolymorphicObjectCheck>(
+            "cert-ctr56-cpp");
     // DCL
     CheckFactories.registerCheck<VariadicFunctionDefCheck>("cert-dcl50-cpp");
     CheckFactories.registerCheck<bugprone::ReservedIdentifierCheck>(



More information about the cfe-commits mailing list