154309b1cSJan Voung #include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h" 254309b1cSJan Voung 354309b1cSJan Voung #include "clang/AST/CanonicalType.h" 454309b1cSJan Voung #include "clang/AST/DeclCXX.h" 554309b1cSJan Voung #include "clang/ASTMatchers/ASTMatchers.h" 654309b1cSJan Voung #include "clang/ASTMatchers/ASTMatchersMacros.h" 754309b1cSJan Voung #include "clang/Basic/OperatorKinds.h" 854309b1cSJan Voung 954309b1cSJan Voung namespace clang::dataflow { 1054309b1cSJan Voung 1154309b1cSJan Voung namespace { 1254309b1cSJan Voung 1354309b1cSJan Voung using ast_matchers::callee; 1454309b1cSJan Voung using ast_matchers::cxxMemberCallExpr; 1554309b1cSJan Voung using ast_matchers::cxxMethodDecl; 1654309b1cSJan Voung using ast_matchers::cxxOperatorCallExpr; 1754309b1cSJan Voung using ast_matchers::hasName; 1854309b1cSJan Voung using ast_matchers::hasOverloadedOperatorName; 1954309b1cSJan Voung using ast_matchers::ofClass; 2054309b1cSJan Voung using ast_matchers::parameterCountIs; 2154309b1cSJan Voung using ast_matchers::pointerType; 2254309b1cSJan Voung using ast_matchers::referenceType; 2354309b1cSJan Voung using ast_matchers::returns; 2454309b1cSJan Voung 2554309b1cSJan Voung bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet, 2654309b1cSJan Voung bool &HasValue) { 2754309b1cSJan Voung // We may want to cache this search, but in current profiles it hasn't shown 2854309b1cSJan Voung // up as a hot spot (possibly because there aren't many hits, relatively). 2954309b1cSJan Voung bool HasArrow = false; 3054309b1cSJan Voung bool HasStar = false; 3154309b1cSJan Voung CanQualType StarReturnType, ArrowReturnType, GetReturnType, ValueReturnType; 3254309b1cSJan Voung for (const auto *MD : RD.methods()) { 3354309b1cSJan Voung // We only consider methods that are const and have zero parameters. 3454309b1cSJan Voung // It may be that there is a non-const overload for the method, but 3554309b1cSJan Voung // there should at least be a const overload as well. 3654309b1cSJan Voung if (!MD->isConst() || MD->getNumParams() != 0) 3754309b1cSJan Voung continue; 3854309b1cSJan Voung switch (MD->getOverloadedOperator()) { 3954309b1cSJan Voung case OO_Star: 4054309b1cSJan Voung if (MD->getReturnType()->isReferenceType()) { 4154309b1cSJan Voung HasStar = true; 4254309b1cSJan Voung StarReturnType = MD->getReturnType() 4354309b1cSJan Voung .getNonReferenceType() 4454309b1cSJan Voung ->getCanonicalTypeUnqualified(); 4554309b1cSJan Voung } 4654309b1cSJan Voung break; 4754309b1cSJan Voung case OO_Arrow: 4854309b1cSJan Voung if (MD->getReturnType()->isPointerType()) { 4954309b1cSJan Voung HasArrow = true; 5054309b1cSJan Voung ArrowReturnType = MD->getReturnType() 5154309b1cSJan Voung ->getPointeeType() 5254309b1cSJan Voung ->getCanonicalTypeUnqualified(); 5354309b1cSJan Voung } 5454309b1cSJan Voung break; 5554309b1cSJan Voung case OO_None: { 5654309b1cSJan Voung IdentifierInfo *II = MD->getIdentifier(); 5754309b1cSJan Voung if (II == nullptr) 5854309b1cSJan Voung continue; 5954309b1cSJan Voung if (II->isStr("get")) { 6054309b1cSJan Voung if (MD->getReturnType()->isPointerType()) { 6154309b1cSJan Voung HasGet = true; 6254309b1cSJan Voung GetReturnType = MD->getReturnType() 6354309b1cSJan Voung ->getPointeeType() 6454309b1cSJan Voung ->getCanonicalTypeUnqualified(); 6554309b1cSJan Voung } 6654309b1cSJan Voung } else if (II->isStr("value")) { 6754309b1cSJan Voung if (MD->getReturnType()->isReferenceType()) { 6854309b1cSJan Voung HasValue = true; 6954309b1cSJan Voung ValueReturnType = MD->getReturnType() 7054309b1cSJan Voung .getNonReferenceType() 7154309b1cSJan Voung ->getCanonicalTypeUnqualified(); 7254309b1cSJan Voung } 7354309b1cSJan Voung } 742d5dc5c2SJan Voung } break; 7554309b1cSJan Voung default: 7654309b1cSJan Voung break; 7754309b1cSJan Voung } 7854309b1cSJan Voung } 7954309b1cSJan Voung 8054309b1cSJan Voung if (!HasStar || !HasArrow || StarReturnType != ArrowReturnType) 8154309b1cSJan Voung return false; 8254309b1cSJan Voung HasGet = HasGet && (GetReturnType == StarReturnType); 8354309b1cSJan Voung HasValue = HasValue && (ValueReturnType == StarReturnType); 8454309b1cSJan Voung return true; 8554309b1cSJan Voung } 8654309b1cSJan Voung 8754309b1cSJan Voung } // namespace 8854309b1cSJan Voung } // namespace clang::dataflow 8954309b1cSJan Voung 9054309b1cSJan Voung // AST_MATCHER macros create an "internal" namespace, so we put it in 9154309b1cSJan Voung // its own anonymous namespace instead of in clang::dataflow. 9254309b1cSJan Voung namespace { 9354309b1cSJan Voung 9454309b1cSJan Voung AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGet) { 9554309b1cSJan Voung bool HasGet = false; 9654309b1cSJan Voung bool HasValue = false; 9754309b1cSJan Voung bool HasStarAndArrow = 9854309b1cSJan Voung clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); 9954309b1cSJan Voung return HasStarAndArrow && HasGet; 10054309b1cSJan Voung } 10154309b1cSJan Voung 10254309b1cSJan Voung AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithValue) { 10354309b1cSJan Voung bool HasGet = false; 10454309b1cSJan Voung bool HasValue = false; 10554309b1cSJan Voung bool HasStarAndArrow = 10654309b1cSJan Voung clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); 10754309b1cSJan Voung return HasStarAndArrow && HasValue; 10854309b1cSJan Voung } 10954309b1cSJan Voung 11054309b1cSJan Voung AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) { 11154309b1cSJan Voung bool HasGet = false; 11254309b1cSJan Voung bool HasValue = false; 11354309b1cSJan Voung bool HasStarAndArrow = 11454309b1cSJan Voung clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); 11554309b1cSJan Voung return HasStarAndArrow && (HasGet || HasValue); 11654309b1cSJan Voung } 11754309b1cSJan Voung 11854309b1cSJan Voung } // namespace 11954309b1cSJan Voung 12054309b1cSJan Voung namespace clang::dataflow { 12154309b1cSJan Voung 12254309b1cSJan Voung ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar() { 12354309b1cSJan Voung return cxxOperatorCallExpr( 12454309b1cSJan Voung hasOverloadedOperatorName("*"), 12554309b1cSJan Voung callee(cxxMethodDecl(parameterCountIs(0), returns(referenceType()), 12654309b1cSJan Voung ofClass(smartPointerClassWithGetOrValue())))); 12754309b1cSJan Voung } 12854309b1cSJan Voung 12954309b1cSJan Voung ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() { 13054309b1cSJan Voung return cxxOperatorCallExpr( 13154309b1cSJan Voung hasOverloadedOperatorName("->"), 13254309b1cSJan Voung callee(cxxMethodDecl(parameterCountIs(0), returns(pointerType()), 13354309b1cSJan Voung ofClass(smartPointerClassWithGetOrValue())))); 13454309b1cSJan Voung } 135*72a28a3bSJan Voung 13654309b1cSJan Voung ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall() { 13754309b1cSJan Voung return cxxMemberCallExpr(callee( 13854309b1cSJan Voung cxxMethodDecl(parameterCountIs(0), returns(referenceType()), 13954309b1cSJan Voung hasName("value"), ofClass(smartPointerClassWithValue())))); 14054309b1cSJan Voung } 14154309b1cSJan Voung 14254309b1cSJan Voung ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall() { 14354309b1cSJan Voung return cxxMemberCallExpr(callee( 14454309b1cSJan Voung cxxMethodDecl(parameterCountIs(0), returns(pointerType()), hasName("get"), 14554309b1cSJan Voung ofClass(smartPointerClassWithGet())))); 14654309b1cSJan Voung } 14754309b1cSJan Voung 148*72a28a3bSJan Voung const FunctionDecl * 149*72a28a3bSJan Voung getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) { 150*72a28a3bSJan Voung const FunctionDecl *CanonicalCallee = nullptr; 151*72a28a3bSJan Voung const CXXMethodDecl *Callee = 152*72a28a3bSJan Voung cast_or_null<CXXMethodDecl>(CE->getDirectCallee()); 153*72a28a3bSJan Voung if (Callee == nullptr) 154*72a28a3bSJan Voung return nullptr; 155*72a28a3bSJan Voung const CXXRecordDecl *RD = Callee->getParent(); 156*72a28a3bSJan Voung if (RD == nullptr) 157*72a28a3bSJan Voung return nullptr; 158*72a28a3bSJan Voung for (const auto *MD : RD->methods()) { 159*72a28a3bSJan Voung if (MD->getOverloadedOperator() == OO_Star && MD->isConst() && 160*72a28a3bSJan Voung MD->getNumParams() == 0 && MD->getReturnType()->isReferenceType()) { 161*72a28a3bSJan Voung CanonicalCallee = MD; 162*72a28a3bSJan Voung break; 163*72a28a3bSJan Voung } 164*72a28a3bSJan Voung } 165*72a28a3bSJan Voung return CanonicalCallee; 166*72a28a3bSJan Voung } 167*72a28a3bSJan Voung 16854309b1cSJan Voung } // namespace clang::dataflow 169