brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.5 KiB · 9067f43 Raw
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