brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.5 KiB · d87b2e6 Raw
200 lines · cpp
1#include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h"2 3#include "clang/AST/CanonicalType.h"4#include "clang/AST/DeclCXX.h"5#include "clang/AST/Type.h"6#include "clang/ASTMatchers/ASTMatchers.h"7#include "clang/ASTMatchers/ASTMatchersMacros.h"8#include "clang/Basic/OperatorKinds.h"9 10namespace clang::dataflow {11 12namespace {13 14using ast_matchers::callee;15using ast_matchers::cxxMemberCallExpr;16using ast_matchers::cxxMethodDecl;17using ast_matchers::cxxOperatorCallExpr;18using ast_matchers::hasCanonicalType;19using ast_matchers::hasName;20using ast_matchers::hasOverloadedOperatorName;21using ast_matchers::ofClass;22using ast_matchers::parameterCountIs;23using ast_matchers::pointerType;24using ast_matchers::referenceType;25using ast_matchers::returns;26 27CanQualType getLikeReturnType(QualType RT) {28  if (!RT.isNull() && RT->isPointerType()) {29    return RT->getPointeeType()30        ->getCanonicalTypeUnqualified()31        .getUnqualifiedType();32  }33  return {};34}35 36CanQualType valueLikeReturnType(QualType RT) {37  if (!RT.isNull() && RT->isReferenceType()) {38    return RT.getNonReferenceType()39        ->getCanonicalTypeUnqualified()40        .getUnqualifiedType();41  }42  return {};43}44 45CanQualType pointerLikeReturnType(const CXXRecordDecl &RD) {46  // We may want to cache this search, but in current profiles it hasn't shown47  // up as a hot spot (possibly because there aren't many hits, relatively).48  CanQualType StarReturnType, ArrowReturnType;49  for (const auto *MD : RD.methods()) {50    // We only consider methods that are const and have zero parameters.51    // It may be that there is a non-const overload for the method, but52    // there should at least be a const overload as well.53    if (!MD->isConst() || MD->getNumParams() != 0)54      continue;55    switch (MD->getOverloadedOperator()) {56    case OO_Star:57      StarReturnType = valueLikeReturnType(MD->getReturnType());58      break;59    case OO_Arrow:60      ArrowReturnType = getLikeReturnType(MD->getReturnType());61      break;62    default:63      break;64    }65  }66  if (!StarReturnType.isNull() && !ArrowReturnType.isNull() &&67      StarReturnType == ArrowReturnType)68    return StarReturnType;69 70  return {};71}72 73QualType findReturnType(const CXXRecordDecl &RD, StringRef MethodName) {74  for (const auto *MD : RD.methods()) {75    // We only consider methods that are const and have zero parameters.76    // It may be that there is a non-const overload for the method, but77    // there should at least be a const overload as well.78    if (!MD->isConst() || MD->getNumParams() != 0 ||79        MD->getOverloadedOperator() != OO_None)80      continue;81    clang::IdentifierInfo *II = MD->getIdentifier();82    if (II && II->isStr(MethodName))83      return MD->getReturnType();84  }85  return {};86}87 88} // namespace89} // namespace clang::dataflow90 91// AST_MATCHER macros create an "internal" namespace, so we put it in92// its own anonymous namespace instead of in clang::dataflow.93namespace {94 95using clang::dataflow::findReturnType;96using clang::dataflow::getLikeReturnType;97using clang::dataflow::pointerLikeReturnType;98using clang::dataflow::valueLikeReturnType;99 100AST_MATCHER_P(clang::CXXRecordDecl, smartPointerClassWithGetLike,101              clang::StringRef, MethodName) {102  auto RT = pointerLikeReturnType(Node);103  if (RT.isNull())104    return false;105  return getLikeReturnType(findReturnType(Node, MethodName)) == RT;106}107 108AST_MATCHER_P(clang::CXXRecordDecl, smartPointerClassWithValueLike,109              clang::StringRef, MethodName) {110  auto RT = pointerLikeReturnType(Node);111  if (RT.isNull())112    return false;113  return valueLikeReturnType(findReturnType(Node, MethodName)) == RT;114}115 116AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) {117  auto RT = pointerLikeReturnType(Node);118  if (RT.isNull())119    return false;120  return getLikeReturnType(findReturnType(Node, "get")) == RT ||121         valueLikeReturnType(findReturnType(Node, "value")) == RT;122}123 124AST_MATCHER(clang::CXXRecordDecl, pointerClass) {125  return !pointerLikeReturnType(Node).isNull();126}127 128} // namespace129 130namespace clang::dataflow {131 132ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar() {133  return cxxOperatorCallExpr(134      hasOverloadedOperatorName("*"),135      callee(cxxMethodDecl(parameterCountIs(0),136                           returns(hasCanonicalType(referenceType())),137                           ofClass(smartPointerClassWithGetOrValue()))));138}139 140ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() {141  return cxxOperatorCallExpr(142      hasOverloadedOperatorName("->"),143      callee(cxxMethodDecl(parameterCountIs(0),144                           returns(hasCanonicalType(pointerType())),145                           ofClass(smartPointerClassWithGetOrValue()))));146}147 148ast_matchers::StatementMatcher isPointerLikeOperatorStar() {149  return cxxOperatorCallExpr(150      hasOverloadedOperatorName("*"),151      callee(cxxMethodDecl(parameterCountIs(0),152                           returns(hasCanonicalType(referenceType())),153                           ofClass(pointerClass()))));154}155 156ast_matchers::StatementMatcher isPointerLikeOperatorArrow() {157  return cxxOperatorCallExpr(158      hasOverloadedOperatorName("->"),159      callee(cxxMethodDecl(parameterCountIs(0),160                           returns(hasCanonicalType(pointerType())),161                           ofClass(pointerClass()))));162}163 164ast_matchers::StatementMatcher165isSmartPointerLikeValueMethodCall(clang::StringRef MethodName) {166  return cxxMemberCallExpr(callee(cxxMethodDecl(167      parameterCountIs(0), returns(hasCanonicalType(referenceType())),168      hasName(MethodName),169      ofClass(smartPointerClassWithValueLike(MethodName)))));170}171 172ast_matchers::StatementMatcher173isSmartPointerLikeGetMethodCall(clang::StringRef MethodName) {174  return cxxMemberCallExpr(callee(cxxMethodDecl(175      parameterCountIs(0), returns(hasCanonicalType(pointerType())),176      hasName(MethodName), ofClass(smartPointerClassWithGetLike(MethodName)))));177}178 179const FunctionDecl *180getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) {181  const FunctionDecl *CanonicalCallee = nullptr;182  const CXXMethodDecl *Callee =183      cast_or_null<CXXMethodDecl>(CE->getDirectCallee());184  if (Callee == nullptr)185    return nullptr;186  const CXXRecordDecl *RD = Callee->getParent();187  if (RD == nullptr)188    return nullptr;189  for (const auto *MD : RD->methods()) {190    if (MD->getOverloadedOperator() == OO_Star && MD->isConst() &&191        MD->getNumParams() == 0 && MD->getReturnType()->isReferenceType()) {192      CanonicalCallee = MD;193      break;194    }195  }196  return CanonicalCallee;197}198 199} // namespace clang::dataflow200