-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Don't look into base class aliases in bugprone-throw-keyword-missing #160725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't look into base class aliases in bugprone-throw-keyword-missing #160725
Conversation
@llvm/pr-subscribers-clang-tools-extra @llvm/pr-subscribers-clang-tidy Author: Aaron Puchert (aaronpuchert) ChangesThe 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 Full diff: https://github.com/llvm/llvm-project/pull/160725.diff 2 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
index 89eafb15f2652..091e28f0519af 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
@@ -18,7 +18,10 @@ void ThrowKeywordMissingCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
cxxConstructExpr(
hasType(cxxRecordDecl(
- isSameOrDerivedFrom(matchesName("[Ee]xception|EXCEPTION")))),
+ anyOf(matchesName("[Ee]xception$|EXCEPTION$"),
+ hasAnyBase(hasType(hasCanonicalType(
+ recordType(hasDeclaration(cxxRecordDecl(
+ matchesName("[Ee]xception|EXCEPTION")))))))))),
unless(anyOf(
hasAncestor(
stmt(anyOf(cxxThrowExpr(), callExpr(), returnStmt()))),
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 bafd3d19b5a31..6ddaf246a354e 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
@@ -32,8 +32,9 @@ struct runtime_error : public exception {
} // namespace std
-// The usage of this class should never emit a warning.
+// The usage of these classes should never emit a warning.
struct RegularClass {};
+struct RegularDerived : public RegularClass {};
// Class name contains the substring "exception", in certain cases using this class should emit a warning.
struct RegularException {
@@ -41,6 +42,8 @@ struct RegularException {
// Constructors with a single argument are treated differently (cxxFunctionalCastExpr).
RegularException(int) {}
+
+ typedef RegularClass RegularAlias;
};
// --------------
@@ -68,6 +71,10 @@ void regularClassNotThrownTest(int i) {
RegularClass();
}
+void regularClassWithAliasNotThrownTest(int i) {
+ RegularDerived();
+}
+
void regularClassThrownTest(int i) {
if (i < 0)
throw RegularClass();
|
c9d06e0
to
1c523e7
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
1c523e7
to
600d240
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a release note in clang-tools-extra/docs/ReleaseNotes.rst
, keeping lexicographical order.
The rest LGTM
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;").
600d240
to
f9679a2
Compare
…lvm#160725) 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;").
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;").