[clang-tools-extra] Add note for base class to bugprone-throw-keyword-missing (PR #160751)

Aaron Puchert via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 25 12:48:59 PDT 2025


https://github.com/aaronpuchert updated https://github.com/llvm/llvm-project/pull/160751

>From d5013102389ca527f466f782271b6179159911d5 Mon Sep 17 00:00:00 2001
From: Aaron Puchert <aaron.puchert at sap.com>
Date: Thu, 25 Sep 2025 17:22:25 +0200
Subject: [PATCH] Add note for base class to bugprone-throw-keyword-missing

It might not always be clear which base the check found that has
"exception" in its name. So we add a note to point to that class.
Ideally we'd point to the `CXXBaseSpecifier`, but it seems we can't bind
to that.
---
 .../clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp      | 8 +++++++-
 clang-tools-extra/docs/ReleaseNotes.rst                   | 3 ++-
 .../checkers/bugprone/throw-keyword-missing.cpp           | 7 +++++--
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
index cafb4a3e5f0e5..9781f0a5ac9de 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
@@ -20,7 +20,8 @@ void ThrowKeywordMissingCheck::registerMatchers(MatchFinder *Finder) {
           hasType(cxxRecordDecl(anyOf(
               matchesName("[Ee]xception|EXCEPTION"),
               hasAnyBase(hasType(hasCanonicalType(recordType(hasDeclaration(
-                  cxxRecordDecl(matchesName("[Ee]xception|EXCEPTION")))))))))),
+                  cxxRecordDecl(matchesName("[Ee]xception|EXCEPTION"))
+                      .bind("base"))))))))),
           unless(anyOf(
               hasAncestor(
                   stmt(anyOf(cxxThrowExpr(), callExpr(), returnStmt()))),
@@ -39,6 +40,11 @@ void ThrowKeywordMissingCheck::check(const MatchFinder::MatchResult &Result) {
   diag(TemporaryExpr->getBeginLoc(), "suspicious exception object created but "
                                      "not thrown; did you mean 'throw %0'?")
       << TemporaryExpr->getType().getBaseTypeIdentifier()->getName();
+
+  if (const auto *BaseDecl = Result.Nodes.getNodeAs<Decl>("base"))
+    diag(BaseDecl->getLocation(),
+         "object type inherits from base class declared here",
+         DiagnosticIDs::Note);
 }
 
 } // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 8c7426c33d13b..d557006b31d25 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -267,7 +267,8 @@ Changes in existing checks
 
 - Improved :doc:`bugprone-throw-keyword-missing
   <clang-tidy/checks/bugprone/throw-keyword-missing>` check by only considering
-  the canonical types of base classes as written.
+  the canonical types of base classes as written and adding a note on the base
+  class that triggered the warning.
 
 - Improved :doc:`bugprone-unchecked-optional-access
   <clang-tidy/checks/bugprone/unchecked-optional-access>` check by supporting
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/throw-keyword-missing.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/throw-keyword-missing.cpp
index 6ddaf246a354e..0ae51780ccc00 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/throw-keyword-missing.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/throw-keyword-missing.cpp
@@ -20,6 +20,7 @@ typedef basic_string<char> string;
 typedef basic_string<wchar_t> wstring;
 
 // std::exception and std::runtime_error declaration.
+// CHECK-MESSAGES-DAG: [[#EXCEPTION_LINE:@LINE + 1]]:8
 struct exception {
   exception();
   exception(const exception &other);
@@ -50,12 +51,13 @@ struct RegularException {
 
 void stdExceptionNotTrownTest(int i) {
   if (i < 0)
-    // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception object created but not thrown; did you mean 'throw {{.*}}'? [bugprone-throw-keyword-missing]
+    // CHECK-MESSAGES-DAG: :[[@LINE+1]]:5: warning: suspicious exception object created but not thrown; did you mean 'throw {{.*}}'? [bugprone-throw-keyword-missing]
     std::exception();
 
   if (i > 0)
-    // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+    // CHECK-MESSAGES-DAG: :[[@LINE+1]]:5: warning: suspicious exception
     std::runtime_error("Unexpected argument");
+    // CHECK-MESSAGES: note: object type inherits from base class declared here
 }
 
 void stdExceptionThrownTest(int i) {
@@ -181,6 +183,7 @@ class RegularError : public ERROR_BASE {};
 void typedefTest() {
   // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: suspicious exception
   RegularError();
+  // CHECK-MESSAGES: :[[#EXCEPTION_LINE]]:8: note: object type inherits from base class declared here
 }
 
 struct ExceptionRAII {



More information about the cfe-commits mailing list