diff options
| author | Alexander Kornienko <alexfh@google.com> | 2017-11-24 14:16:29 +0000 |
|---|---|---|
| committer | Alexander Kornienko <alexfh@google.com> | 2017-11-24 14:16:29 +0000 |
| commit | d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4 (patch) | |
| tree | c43c0be034454ea297f0ccdc84302e9636abed63 /clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp | |
| parent | 70cdb5b3914803ca89a96a867a47936d049a4b32 (diff) | |
| download | bcm5719-llvm-d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4.tar.gz bcm5719-llvm-d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4.zip | |
[clang-tidy] Move a few more checks from misc to bugprone.
Summary:
clang_tidy/rename_check.py misc-assert-side-effect bugprone-assert-side-effect
clang_tidy/rename_check.py misc-bool-pointer-implicit-conversion bugprone-bool-pointer-implicit-conversion
clang_tidy/rename_check.py misc-fold-init-type bugprone-fold-init-type
clang_tidy/rename_check.py misc-forward-declaration-namespace bugprone-forward-declaration-namespace
clang_tidy/rename_check.py misc-inaccurate-erase bugprone-inaccurate-erase
clang_tidy/rename_check.py misc-move-forwarding-reference bugprone-move-forwarding-reference
clang_tidy/rename_check.py misc-multiple-statement-macro bugprone-multiple-statement-macro
clang_tidy/rename_check.py misc-use-after-move bugprone-use-after-move
clang_tidy/rename_check.py misc-virtual-near-miss bugprone-virtual-near-miss
Manually fixed a reference to UseAfterMoveCheck in the hicpp module.
Manually fixed header guards.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nemanjai, mgorny, javed.absar, xazax.hun, kbarton, cfe-commits
Differential Revision: https://reviews.llvm.org/D40426
llvm-svn: 318950
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp | 274 |
1 files changed, 0 insertions, 274 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp b/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp deleted file mode 100644 index fd74bb6692e..00000000000 --- a/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp +++ /dev/null @@ -1,274 +0,0 @@ -//===--- VirtualNearMissCheck.cpp - clang-tidy-----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "VirtualNearMissCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); } - -AST_MATCHER(CXXMethodDecl, isOverloadedOperator) { - return Node.isOverloadedOperator(); -} - -/// Finds out if the given method overrides some method. -static bool isOverrideMethod(const CXXMethodDecl *MD) { - return MD->size_overridden_methods() > 0 || MD->hasAttr<OverrideAttr>(); -} - -/// Checks whether the return types are covariant, according to -/// C++[class.virtual]p7. -/// -/// Similar with clang::Sema::CheckOverridingFunctionReturnType. -/// \returns true if the return types of BaseMD and DerivedMD are covariant. -static bool checkOverridingFunctionReturnType(const ASTContext *Context, - const CXXMethodDecl *BaseMD, - const CXXMethodDecl *DerivedMD) { - QualType BaseReturnTy = BaseMD->getType() - ->getAs<FunctionType>() - ->getReturnType() - .getCanonicalType(); - QualType DerivedReturnTy = DerivedMD->getType() - ->getAs<FunctionType>() - ->getReturnType() - .getCanonicalType(); - - if (DerivedReturnTy->isDependentType() || BaseReturnTy->isDependentType()) - return false; - - // Check if return types are identical. - if (Context->hasSameType(DerivedReturnTy, BaseReturnTy)) - return true; - - /// Check if the return types are covariant. - - // Both types must be pointers or references to classes. - if (!(BaseReturnTy->isPointerType() && DerivedReturnTy->isPointerType()) && - !(BaseReturnTy->isReferenceType() && DerivedReturnTy->isReferenceType())) - return false; - - /// 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().getCanonicalType(); - QualType BTy = BaseReturnTy->getPointeeType().getCanonicalType(); - - const CXXRecordDecl *DRD = DTy->getAsCXXRecordDecl(); - const CXXRecordDecl *BRD = BTy->getAsCXXRecordDecl(); - if (DRD == nullptr || BRD == nullptr) - return false; - - if (!DRD->hasDefinition() || !BRD->hasDefinition()) - return false; - - if (DRD == BRD) - return true; - - if (!Context->hasSameUnqualifiedType(DTy, BTy)) { - // Begin checking whether the conversion from D to B is valid. - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - - // Check whether D is derived from B, and fill in a CXXBasePaths object. - if (!DRD->isDerivedFrom(BRD, Paths)) - return false; - - // Check ambiguity. - if (Paths.isAmbiguous(Context->getCanonicalType(BTy).getUnqualifiedType())) - return false; - - // Check accessibility. - // FIXME: We currently only support checking if B is accessible base class - // of D, or D is the same class which DerivedMD is in. - bool IsItself = - DRD->getCanonicalDecl() == DerivedMD->getParent()->getCanonicalDecl(); - bool HasPublicAccess = false; - for (const auto &Path : Paths) { - if (Path.Access == AS_public) - HasPublicAccess = true; - } - if (!HasPublicAccess && !IsItself) - return false; - // End checking conversion from D to B. - } - - // Both pointers or references should have the same cv-qualification. - if (DerivedReturnTy.getLocalCVRQualifiers() != - BaseReturnTy.getLocalCVRQualifiers()) - return false; - - // The class type D should have the same cv-qualification as or less - // cv-qualification than the class type B. - if (DTy.isMoreQualifiedThan(BTy)) - return false; - - return true; -} - -/// \returns decayed type for arrays and functions. -static QualType getDecayedType(QualType Type) { - if (const auto *Decayed = Type->getAs<DecayedType>()) - return Decayed->getDecayedType(); - return Type; -} - -/// \returns true if the param types are the same. -static bool checkParamTypes(const CXXMethodDecl *BaseMD, - const CXXMethodDecl *DerivedMD) { - unsigned NumParamA = BaseMD->getNumParams(); - unsigned NumParamB = DerivedMD->getNumParams(); - if (NumParamA != NumParamB) - return false; - - for (unsigned I = 0; I < NumParamA; I++) { - if (getDecayedType(BaseMD->getParamDecl(I)->getType().getCanonicalType()) != - getDecayedType( - DerivedMD->getParamDecl(I)->getType().getCanonicalType())) - return false; - } - return true; -} - -/// \returns true if derived method can override base method except for the -/// name. -static bool checkOverrideWithoutName(const ASTContext *Context, - const CXXMethodDecl *BaseMD, - const CXXMethodDecl *DerivedMD) { - if (BaseMD->isStatic() != DerivedMD->isStatic()) - return false; - - if (BaseMD->getType() == DerivedMD->getType()) - return true; - - // Now the function types are not identical. Then check if the return types - // are covariant and if the param types are the same. - if (!checkOverridingFunctionReturnType(Context, BaseMD, DerivedMD)) - return false; - return checkParamTypes(BaseMD, DerivedMD); -} - -/// Check whether BaseMD overrides DerivedMD. -/// -/// Prerequisite: the class which BaseMD is in should be a base class of that -/// DerivedMD is in. -static bool checkOverrideByDerivedMethod(const CXXMethodDecl *BaseMD, - const CXXMethodDecl *DerivedMD) { - for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(), - E = DerivedMD->end_overridden_methods(); - I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - if (BaseMD->getCanonicalDecl() == OverriddenMD->getCanonicalDecl()) - return true; - } - - return false; -} - -bool VirtualNearMissCheck::isPossibleToBeOverridden( - const CXXMethodDecl *BaseMD) { - auto Iter = PossibleMap.find(BaseMD); - if (Iter != PossibleMap.end()) - return Iter->second; - - bool IsPossible = !BaseMD->isImplicit() && !isa<CXXConstructorDecl>(BaseMD) && - !isa<CXXDestructorDecl>(BaseMD) && BaseMD->isVirtual() && - !BaseMD->isOverloadedOperator() && - !isa<CXXConversionDecl>(BaseMD); - PossibleMap[BaseMD] = IsPossible; - return IsPossible; -} - -bool VirtualNearMissCheck::isOverriddenByDerivedClass( - const CXXMethodDecl *BaseMD, const CXXRecordDecl *DerivedRD) { - auto Key = std::make_pair(BaseMD, DerivedRD); - auto Iter = OverriddenMap.find(Key); - if (Iter != OverriddenMap.end()) - return Iter->second; - - bool IsOverridden = false; - for (const CXXMethodDecl *DerivedMD : DerivedRD->methods()) { - if (!isOverrideMethod(DerivedMD)) - continue; - - if (checkOverrideByDerivedMethod(BaseMD, DerivedMD)) { - IsOverridden = true; - break; - } - } - OverriddenMap[Key] = IsOverridden; - return IsOverridden; -} - -void VirtualNearMissCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus) - return; - - Finder->addMatcher( - cxxMethodDecl( - unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(), - cxxDestructorDecl(), cxxConversionDecl(), isStatic(), - isOverloadedOperator()))) - .bind("method"), - this); -} - -void VirtualNearMissCheck::check(const MatchFinder::MatchResult &Result) { - const auto *DerivedMD = Result.Nodes.getNodeAs<CXXMethodDecl>("method"); - assert(DerivedMD); - - const ASTContext *Context = Result.Context; - - const auto *DerivedRD = DerivedMD->getParent()->getDefinition(); - assert(DerivedRD); - - for (const auto &BaseSpec : DerivedRD->bases()) { - if (const auto *BaseRD = BaseSpec.getType()->getAsCXXRecordDecl()) { - for (const auto *BaseMD : BaseRD->methods()) { - if (!isPossibleToBeOverridden(BaseMD)) - continue; - - if (isOverriddenByDerivedClass(BaseMD, DerivedRD)) - continue; - - unsigned EditDistance = BaseMD->getName().edit_distance( - DerivedMD->getName(), EditDistanceThreshold); - if (EditDistance > 0 && EditDistance <= EditDistanceThreshold) { - if (checkOverrideWithoutName(Context, BaseMD, DerivedMD)) { - // A "virtual near miss" is found. - auto Range = CharSourceRange::getTokenRange( - SourceRange(DerivedMD->getLocation())); - - bool ApplyFix = !BaseMD->isTemplateInstantiation() && - !DerivedMD->isTemplateInstantiation(); - auto Diag = - diag(DerivedMD->getLocStart(), - "method '%0' has a similar name and the same signature as " - "virtual method '%1'; did you mean to override it?") - << DerivedMD->getQualifiedNameAsString() - << BaseMD->getQualifiedNameAsString(); - if (ApplyFix) - Diag << FixItHint::CreateReplacement(Range, BaseMD->getName()); - } - } - } - } - } -} - -} // namespace misc -} // namespace tidy -} // namespace clang |

