Path: blob/main/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
213799 views
#include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h"12#include "clang/AST/CanonicalType.h"3#include "clang/AST/DeclCXX.h"4#include "clang/AST/Type.h"5#include "clang/ASTMatchers/ASTMatchers.h"6#include "clang/ASTMatchers/ASTMatchersMacros.h"7#include "clang/Basic/OperatorKinds.h"89namespace clang::dataflow {1011namespace {1213using ast_matchers::callee;14using ast_matchers::cxxMemberCallExpr;15using ast_matchers::cxxMethodDecl;16using ast_matchers::cxxOperatorCallExpr;17using ast_matchers::hasCanonicalType;18using ast_matchers::hasName;19using ast_matchers::hasOverloadedOperatorName;20using ast_matchers::ofClass;21using ast_matchers::parameterCountIs;22using ast_matchers::pointerType;23using ast_matchers::referenceType;24using ast_matchers::returns;2526CanQualType getLikeReturnType(QualType RT) {27if (!RT.isNull() && RT->isPointerType()) {28return RT->getPointeeType()29->getCanonicalTypeUnqualified()30.getUnqualifiedType();31}32return {};33}3435CanQualType valueLikeReturnType(QualType RT) {36if (!RT.isNull() && RT->isReferenceType()) {37return RT.getNonReferenceType()38->getCanonicalTypeUnqualified()39.getUnqualifiedType();40}41return {};42}4344CanQualType pointerLikeReturnType(const CXXRecordDecl &RD) {45// We may want to cache this search, but in current profiles it hasn't shown46// up as a hot spot (possibly because there aren't many hits, relatively).47CanQualType StarReturnType, ArrowReturnType;48for (const auto *MD : RD.methods()) {49// We only consider methods that are const and have zero parameters.50// It may be that there is a non-const overload for the method, but51// there should at least be a const overload as well.52if (!MD->isConst() || MD->getNumParams() != 0)53continue;54switch (MD->getOverloadedOperator()) {55case OO_Star:56StarReturnType = valueLikeReturnType(MD->getReturnType());57break;58case OO_Arrow:59ArrowReturnType = getLikeReturnType(MD->getReturnType());60break;61default:62break;63}64}65if (!StarReturnType.isNull() && !ArrowReturnType.isNull() &&66StarReturnType == ArrowReturnType)67return StarReturnType;6869return {};70}7172QualType findReturnType(const CXXRecordDecl &RD, StringRef MethodName) {73for (const auto *MD : RD.methods()) {74// We only consider methods that are const and have zero parameters.75// It may be that there is a non-const overload for the method, but76// there should at least be a const overload as well.77if (!MD->isConst() || MD->getNumParams() != 0 ||78MD->getOverloadedOperator() != OO_None)79continue;80clang::IdentifierInfo *II = MD->getIdentifier();81if (II && II->isStr(MethodName))82return MD->getReturnType();83}84return {};85}8687} // namespace88} // namespace clang::dataflow8990// AST_MATCHER macros create an "internal" namespace, so we put it in91// its own anonymous namespace instead of in clang::dataflow.92namespace {9394using clang::dataflow::findReturnType;95using clang::dataflow::getLikeReturnType;96using clang::dataflow::pointerLikeReturnType;97using clang::dataflow::valueLikeReturnType;9899AST_MATCHER_P(clang::CXXRecordDecl, smartPointerClassWithGetLike,100clang::StringRef, MethodName) {101auto RT = pointerLikeReturnType(Node);102if (RT.isNull())103return false;104return getLikeReturnType(findReturnType(Node, MethodName)) == RT;105}106107AST_MATCHER_P(clang::CXXRecordDecl, smartPointerClassWithValueLike,108clang::StringRef, MethodName) {109auto RT = pointerLikeReturnType(Node);110if (RT.isNull())111return false;112return valueLikeReturnType(findReturnType(Node, MethodName)) == RT;113}114115AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) {116auto RT = pointerLikeReturnType(Node);117if (RT.isNull())118return false;119return getLikeReturnType(findReturnType(Node, "get")) == RT ||120valueLikeReturnType(findReturnType(Node, "value")) == RT;121}122123AST_MATCHER(clang::CXXRecordDecl, pointerClass) {124return !pointerLikeReturnType(Node).isNull();125}126127} // namespace128129namespace clang::dataflow {130131ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar() {132return cxxOperatorCallExpr(133hasOverloadedOperatorName("*"),134callee(cxxMethodDecl(parameterCountIs(0),135returns(hasCanonicalType(referenceType())),136ofClass(smartPointerClassWithGetOrValue()))));137}138139ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() {140return cxxOperatorCallExpr(141hasOverloadedOperatorName("->"),142callee(cxxMethodDecl(parameterCountIs(0),143returns(hasCanonicalType(pointerType())),144ofClass(smartPointerClassWithGetOrValue()))));145}146147ast_matchers::StatementMatcher isPointerLikeOperatorStar() {148return cxxOperatorCallExpr(149hasOverloadedOperatorName("*"),150callee(cxxMethodDecl(parameterCountIs(0),151returns(hasCanonicalType(referenceType())),152ofClass(pointerClass()))));153}154155ast_matchers::StatementMatcher isPointerLikeOperatorArrow() {156return cxxOperatorCallExpr(157hasOverloadedOperatorName("->"),158callee(cxxMethodDecl(parameterCountIs(0),159returns(hasCanonicalType(pointerType())),160ofClass(pointerClass()))));161}162163ast_matchers::StatementMatcher164isSmartPointerLikeValueMethodCall(clang::StringRef MethodName) {165return cxxMemberCallExpr(callee(cxxMethodDecl(166parameterCountIs(0), returns(hasCanonicalType(referenceType())),167hasName(MethodName),168ofClass(smartPointerClassWithValueLike(MethodName)))));169}170171ast_matchers::StatementMatcher172isSmartPointerLikeGetMethodCall(clang::StringRef MethodName) {173return cxxMemberCallExpr(callee(cxxMethodDecl(174parameterCountIs(0), returns(hasCanonicalType(pointerType())),175hasName(MethodName), ofClass(smartPointerClassWithGetLike(MethodName)))));176}177178const FunctionDecl *179getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) {180const FunctionDecl *CanonicalCallee = nullptr;181const CXXMethodDecl *Callee =182cast_or_null<CXXMethodDecl>(CE->getDirectCallee());183if (Callee == nullptr)184return nullptr;185const CXXRecordDecl *RD = Callee->getParent();186if (RD == nullptr)187return nullptr;188for (const auto *MD : RD->methods()) {189if (MD->getOverloadedOperator() == OO_Star && MD->isConst() &&190MD->getNumParams() == 0 && MD->getReturnType()->isReferenceType()) {191CanonicalCallee = MD;192break;193}194}195return CanonicalCallee;196}197198} // namespace clang::dataflow199200201