101 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ComparePointerToMemberVirtualFunctionCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/DeclCXX.h"12#include "clang/AST/OperationKinds.h"13#include "clang/AST/Type.h"14#include "clang/ASTMatchers/ASTMatchFinder.h"15#include "clang/ASTMatchers/ASTMatchers.h"16#include "clang/ASTMatchers/ASTMatchersMacros.h"17#include "clang/Basic/DiagnosticIDs.h"18#include "llvm/ADT/SmallVector.h"19 20using namespace clang::ast_matchers;21 22namespace clang::tidy::bugprone {23 24namespace {25 26AST_MATCHER(CXXMethodDecl, isVirtual) { return Node.isVirtual(); }27 28static constexpr llvm::StringLiteral ErrorMsg =29 "comparing a pointer to member virtual function with other pointer is "30 "unspecified behavior, only compare it with a null-pointer constant for "31 "equality.";32 33} // namespace34 35void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(36 MatchFinder *Finder) {37 auto DirectMemberVirtualFunctionPointer = unaryOperator(38 allOf(hasOperatorName("&"),39 hasUnaryOperand(declRefExpr(to(cxxMethodDecl(isVirtual()))))));40 auto IndirectMemberPointer =41 ignoringImpCasts(declRefExpr().bind("indirect_member_pointer"));42 43 Finder->addMatcher(44 binaryOperator(45 allOf(hasAnyOperatorName("==", "!="),46 hasEitherOperand(47 hasType(memberPointerType(pointee(functionType())))),48 anyOf(hasEitherOperand(DirectMemberVirtualFunctionPointer),49 hasEitherOperand(IndirectMemberPointer)),50 unless(hasEitherOperand(51 castExpr(hasCastKind(CK_NullToMemberPointer))))))52 .bind("binary_operator"),53 this);54}55 56void ComparePointerToMemberVirtualFunctionCheck::check(57 const MatchFinder::MatchResult &Result) {58 const auto *BO = Result.Nodes.getNodeAs<BinaryOperator>("binary_operator");59 const auto *DRE =60 Result.Nodes.getNodeAs<DeclRefExpr>("indirect_member_pointer");61 62 if (DRE == nullptr) {63 // compare with pointer to member virtual function.64 diag(BO->getOperatorLoc(), ErrorMsg);65 return;66 }67 // compare with variable which type is pointer to member function.68 llvm::SmallVector<SourceLocation, 12U> SameSignatureVirtualMethods{};69 const auto *MPT = cast<MemberPointerType>(DRE->getType().getCanonicalType());70 const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();71 if (RD == nullptr)72 return;73 74 constexpr bool StopVisit = false;75 76 auto VisitSameSignatureVirtualMethods =77 [&](const CXXRecordDecl *CurrentRecordDecl) -> bool {78 bool Ret = !StopVisit;79 for (const auto *MD : CurrentRecordDecl->methods()) {80 if (MD->isVirtual() && MD->getType() == MPT->getPointeeType()) {81 SameSignatureVirtualMethods.push_back(MD->getBeginLoc());82 Ret = StopVisit;83 }84 }85 return Ret;86 };87 88 if (StopVisit != VisitSameSignatureVirtualMethods(RD)) {89 RD->forallBases(VisitSameSignatureVirtualMethods);90 }91 92 if (!SameSignatureVirtualMethods.empty()) {93 diag(BO->getOperatorLoc(), ErrorMsg);94 for (const auto Loc : SameSignatureVirtualMethods)95 diag(Loc, "potential member virtual function is declared here.",96 DiagnosticIDs::Note);97 }98}99 100} // namespace clang::tidy::bugprone101