diff options
-rw-r--r-- | clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp | 81 | ||||
-rw-r--r-- | clang-tools-extra/test/clang-tidy/misc-new-delete-overloads.cpp | 4 |
2 files changed, 43 insertions, 42 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp b/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp index c62ba86f6bc..8f40dc671f1 100644 --- a/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp @@ -98,32 +98,30 @@ bool areCorrespondingOverloads(const FunctionDecl *LHS, return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS); } -bool hasCorrespondingOverloadInOneClass(const CXXRecordDecl *RD, - const CXXMethodDecl *MD) { - // Check the methods in the given class and accessible to derived classes. - for (const auto *BMD : RD->methods()) - if (BMD->isOverloadedOperator() && BMD->getAccess() != AS_private && - areCorrespondingOverloads(MD, BMD)) - return true; - - // Check base classes. - for (const auto &BS : RD->bases()) - if (hasCorrespondingOverloadInOneClass(BS.getType()->getAsCXXRecordDecl(), - MD)) - return true; +bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD, + const CXXRecordDecl *RD = nullptr) { + if (RD) { + // Check the methods in the given class and accessible to derived classes. + for (const auto *BMD : RD->methods()) + if (BMD->isOverloadedOperator() && BMD->getAccess() != AS_private && + areCorrespondingOverloads(MD, BMD)) + return true; + } else { + // Get the parent class of the method; we do not need to care about checking + // the methods in this class as the caller has already done that by looking + // at the declaration contexts. + RD = MD->getParent(); + } - return false; -} -bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD) { - // Get the parent class of the method; we do not need to care about checking - // the methods in this class as the caller has already done that by looking - // at the declaration contexts. - const CXXRecordDecl *RD = MD->getParent(); - - for (const auto &BS : RD->bases()) - if (hasCorrespondingOverloadInOneClass(BS.getType()->getAsCXXRecordDecl(), - MD)) + for (const auto &BS : RD->bases()) { + // We can't say much about a dependent base class, but to avoid false + // positives assume it can have a corresponding overload. + if (BS.getType()->isDependentType()) return true; + if (const auto *BaseRD = BS.getType()->getAsCXXRecordDecl()) + if (hasCorrespondingOverloadInBaseClass(MD, BaseRD)) + return true; + } return false; } @@ -174,24 +172,23 @@ void NewDeleteOverloadsCheck::onEndOfTranslationUnit() { // to shard the overloads by declaration context to reduce the algorithmic // complexity when searching for corresponding free store functions. for (const auto *Overload : RP.second) { - const auto *Match = std::find_if( - RP.second.begin(), RP.second.end(), [&](const FunctionDecl *FD) { - if (FD == Overload) - return false; - // If the declaration contexts don't match, we don't - // need to check - // any further. - if (FD->getDeclContext() != Overload->getDeclContext()) - return false; - - // Since the declaration contexts match, see whether - // the current - // element is the corresponding operator. - if (!areCorrespondingOverloads(Overload, FD)) - return false; - - return true; - }); + const auto *Match = + std::find_if(RP.second.begin(), RP.second.end(), + [&Overload](const FunctionDecl *FD) { + if (FD == Overload) + return false; + // If the declaration contexts don't match, we don't + // need to check any further. + if (FD->getDeclContext() != Overload->getDeclContext()) + return false; + + // Since the declaration contexts match, see whether + // the current element is the corresponding operator. + if (!areCorrespondingOverloads(Overload, FD)) + return false; + + return true; + }); if (Match == RP.second.end()) { // Check to see if there is a corresponding overload in a base class diff --git a/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads.cpp b/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads.cpp index 32323a58cc8..3e60537ef65 100644 --- a/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads.cpp +++ b/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads.cpp @@ -75,3 +75,7 @@ struct H : G { // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope void *operator new(size_t) noexcept; // base class operator is inaccessible }; + +template <typename Base> struct Derived : Base { + void operator delete(void *); +}; |