Index: clang-tools-extra/trunk/clang-tidy/misc/VirtualNearMissCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/VirtualNearMissCheck.h +++ clang-tools-extra/trunk/clang-tidy/misc/VirtualNearMissCheck.h @@ -34,7 +34,7 @@ private: /// Check if the given method is possible to be overridden by some other - /// method. + /// method. Operators and destructors are excluded. /// /// Results are memoized in PossibleMap. bool isPossibleToBeOverridden(const CXXMethodDecl *BaseMD); Index: clang-tools-extra/trunk/clang-tidy/misc/VirtualNearMissCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/misc/VirtualNearMissCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/VirtualNearMissCheck.cpp @@ -45,31 +45,20 @@ return true; /// Check if the return types are covariant. - /// BTy is the class type in return type of BaseMD. For example, - /// B* Base::md() - /// While BRD is the declaration of B. - QualType BTy, DTy; - const CXXRecordDecl *BRD, *DRD; // Both types must be pointers or references to classes. - if (const auto *DerivedPT = DerivedReturnTy->getAs()) { - if (const auto *BasePT = BaseReturnTy->getAs()) { - DTy = DerivedPT->getPointeeType(); - BTy = BasePT->getPointeeType(); - } - } else if (const auto *DerivedRT = DerivedReturnTy->getAs()) { - if (const auto *BaseRT = BaseReturnTy->getAs()) { - DTy = DerivedRT->getPointeeType(); - BTy = BaseRT->getPointeeType(); - } - } - - // The return types aren't either both pointers or references to a class type. - if (DTy.isNull()) + if (!(BaseReturnTy->isPointerType() && DerivedReturnTy->isPointerType()) && + !(BaseReturnTy->isReferenceType() && DerivedReturnTy->isReferenceType())) return false; - DRD = DTy->getAsCXXRecordDecl(); - BRD = BTy->getAsCXXRecordDecl(); + /// BTy is the class type in return type of BaseMD. For example, + /// B* Base::md() + /// While BRD is the declaration of B. + QualType DTy = DerivedReturnTy->getPointeeType(); + QualType BTy = BaseReturnTy->getPointeeType(); + + const CXXRecordDecl *DRD = DTy->getAsCXXRecordDecl(); + const CXXRecordDecl *BRD = BTy->getAsCXXRecordDecl(); if (DRD == nullptr || BRD == nullptr) return false; @@ -116,6 +105,13 @@ return true; } +/// \returns decayed type for arrays and functions. +static QualType getDecayedType(QualType Type) { + if (const auto *Decayed = Type->getAs()) + return Decayed->getDecayedType(); + return Type; +} + /// \returns true if the param types are the same. static bool checkParamTypes(const CXXMethodDecl *BaseMD, const CXXMethodDecl *DerivedMD) { @@ -125,8 +121,8 @@ return false; for (unsigned I = 0; I < NumParamA; I++) { - if (BaseMD->getParamDecl(I)->getType() != - DerivedMD->getParamDecl(I)->getType()) + if (getDecayedType(BaseMD->getParamDecl(I)->getType()) != + getDecayedType(DerivedMD->getParamDecl(I)->getType())) return false; } return true; @@ -137,15 +133,9 @@ static bool checkOverrideWithoutName(const ASTContext *Context, const CXXMethodDecl *BaseMD, const CXXMethodDecl *DerivedMD) { - if (BaseMD->getTypeQualifiers() != DerivedMD->getTypeQualifiers()) - return false; - if (BaseMD->isStatic() != DerivedMD->isStatic()) return false; - if (BaseMD->getAccess() != DerivedMD->getAccess()) - return false; - if (BaseMD->getType() == DerivedMD->getType()) return true; @@ -187,7 +177,8 @@ return Iter->second; bool IsPossible = !BaseMD->isImplicit() && !isa(BaseMD) && - BaseMD->isVirtual(); + !isa(BaseMD) && BaseMD->isVirtual() && + !BaseMD->isOverloadedOperator(); PossibleMap[Id] = IsPossible; return IsPossible; } @@ -218,19 +209,23 @@ if (!getLangOpts().CPlusPlus) return; - Finder->addMatcher(cxxMethodDecl(unless(anyOf(isOverride(), isImplicit(), - cxxConstructorDecl()))) - .bind("method"), - this); + Finder->addMatcher( + cxxMethodDecl(unless(anyOf(isOverride(), isImplicit(), + cxxConstructorDecl(), cxxDestructorDecl()))) + .bind("method"), + this); } void VirtualNearMissCheck::check(const MatchFinder::MatchResult &Result) { const auto *DerivedMD = Result.Nodes.getNodeAs("method"); - assert(DerivedMD != nullptr); + assert(DerivedMD); if (DerivedMD->isStatic()) return; + if (DerivedMD->isOverloadedOperator()) + return; + const ASTContext *Context = Result.Context; const auto *DerivedRD = DerivedMD->getParent(); Index: clang-tools-extra/trunk/test/clang-tidy/misc-virtual-near-miss.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/misc-virtual-near-miss.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-virtual-near-miss.cpp @@ -3,6 +3,8 @@ struct Base { virtual void func(); virtual void gunk(); + virtual ~Base(); + virtual Base &operator=(const Base &); }; struct Derived : Base { @@ -20,6 +22,8 @@ void fun(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Derived::fun' has {{.*}} 'Base::func' + + Derived &operator==(const Base &); // Should not warn: operators are ignored. }; class Father { @@ -36,6 +40,7 @@ static void method(); virtual int method(int argc, const char **argv); virtual int method(int argc) const; + virtual int decay(const char *str); }; class Child : private Father, private Mother { @@ -47,7 +52,8 @@ int methoe(int x, char **strs); // Should not warn: parameter types don't match. - int methoe(int x); // Should not warn: method is not const. + int methoe(int x); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::methoe' has {{.*}} 'Mother::method' void methof(int x, const char **strs); // Should not warn: return types don't match. @@ -60,6 +66,10 @@ virtual Derived &&generat(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::generat' has {{.*}} 'Father::generate' + int decaz(const char str[]); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::decaz' has {{.*}} 'Mother::decay' + private: - void funk(); // Should not warn: access qualifers don't match. + void funk(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::funk' has {{.*}} 'Father::func' };