Skip to content

Commit f9679a2

Browse files
committed
Don't look into base class aliases in bugprone-throw-keyword-missing
The check confusingly fires on non-exception classes if any base class has an alias in an exception class. In our case, the exception had an alias for an allocator interface, so every allocator inheriting from that interface was treated as an exception type. (But only when the header for the exception was included.) The reason behind this is the odd (but documented) behavior of isDerivedFrom and similar matchers: it does not only iterate through the bases as written, but through all relevant nodes to check them for being a base. This makes the matcher also finds aliases of the base classes. Only going through the bases as written can be done with `hasAnyBase`. However, that doesn't cover the class itself, and we have to check it separately. Since we're no longer looking through aliases via the matcher, and because we're apparently interested in the canonical type, we check that (see the test with "typedef std::exception ERROR_BASE;").
1 parent 1fda257 commit f9679a2

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ namespace clang::tidy::bugprone {
1717
void ThrowKeywordMissingCheck::registerMatchers(MatchFinder *Finder) {
1818
Finder->addMatcher(
1919
cxxConstructExpr(
20-
hasType(cxxRecordDecl(
21-
isSameOrDerivedFrom(matchesName("[Ee]xception|EXCEPTION")))),
20+
hasType(cxxRecordDecl(anyOf(
21+
matchesName("[Ee]xception|EXCEPTION"),
22+
hasAnyBase(hasType(hasCanonicalType(recordType(hasDeclaration(
23+
cxxRecordDecl(matchesName("[Ee]xception|EXCEPTION")))))))))),
2224
unless(anyOf(
2325
hasAncestor(
2426
stmt(anyOf(cxxThrowExpr(), callExpr(), returnStmt()))),

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ Changes in existing checks
260260
namespace are treated as the tag or the data part of a user-defined
261261
tagged union respectively.
262262

263+
- Improved :doc:`bugprone-throw-keyword-missing
264+
<clang-tidy/checks/bugprone/throw-keyword-missing>` check by only considering
265+
the canonical types of base classes as written.
266+
263267
- Improved :doc:`bugprone-unchecked-optional-access
264268
<clang-tidy/checks/bugprone/unchecked-optional-access>` check by supporting
265269
``NullableValue::makeValue`` and ``NullableValue::makeValueInplace`` to

clang-tools-extra/test/clang-tidy/checkers/bugprone/throw-keyword-missing.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,18 @@ struct runtime_error : public exception {
3232

3333
} // namespace std
3434

35-
// The usage of this class should never emit a warning.
35+
// The usage of these classes should never emit a warning.
3636
struct RegularClass {};
37+
struct RegularDerived : public RegularClass {};
3738

3839
// Class name contains the substring "exception", in certain cases using this class should emit a warning.
3940
struct RegularException {
4041
RegularException() {}
4142

4243
// Constructors with a single argument are treated differently (cxxFunctionalCastExpr).
4344
RegularException(int) {}
45+
46+
typedef RegularClass RegularAlias;
4447
};
4548

4649
// --------------
@@ -68,6 +71,10 @@ void regularClassNotThrownTest(int i) {
6871
RegularClass();
6972
}
7073

74+
void regularClassWithAliasNotThrownTest(int i) {
75+
RegularDerived();
76+
}
77+
7178
void regularClassThrownTest(int i) {
7279
if (i < 0)
7380
throw RegularClass();

0 commit comments

Comments
 (0)