================ @@ -0,0 +1,134 @@ +#include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h" + +#include "clang/AST/CanonicalType.h" +#include "clang/AST/DeclCXX.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/OperatorKinds.h" + +namespace clang::dataflow { + +namespace { + +using ast_matchers::callee; +using ast_matchers::cxxMemberCallExpr; +using ast_matchers::cxxMethodDecl; +using ast_matchers::cxxOperatorCallExpr; +using ast_matchers::hasName; +using ast_matchers::hasOverloadedOperatorName; +using ast_matchers::ofClass; +using ast_matchers::parameterCountIs; +using ast_matchers::pointerType; +using ast_matchers::referenceType; +using ast_matchers::returns; + +bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet, + bool &HasValue) { + // We may want to cache this search, but in current profiles it hasn't shown + // up as a hot spot (possibly because there aren't many hits, relatively). + bool HasArrow = false; + bool HasStar = false; + CanQualType StarReturnType, ArrowReturnType, GetReturnType, ValueReturnType; + for (const auto *MD : RD.methods()) { + // We only consider methods that are const and have zero parameters. + // It may be that there is a non-const overload for the method, but + // there should at least be a const overload as well. + if (!MD->isConst() || MD->getNumParams() != 0) { + continue; + } + if (MD->getOverloadedOperator() == OO_Star && + MD->getReturnType()->isReferenceType()) { + HasStar = true; + StarReturnType = MD->getReturnType() + .getNonReferenceType() + ->getCanonicalTypeUnqualified(); + } else if (MD->getOverloadedOperator() == OO_Arrow && + MD->getReturnType()->isPointerType()) { + HasArrow = true; + ArrowReturnType = + MD->getReturnType()->getPointeeType()->getCanonicalTypeUnqualified(); + } else { + IdentifierInfo *II = MD->getIdentifier(); + if (II == nullptr) + continue; + if (II->isStr("get") && MD->getReturnType()->isPointerType()) { + HasGet = true; + GetReturnType = MD->getReturnType() + ->getPointeeType() + ->getCanonicalTypeUnqualified(); + } else if (II->isStr("value") && MD->getReturnType()->isReferenceType()) { + HasValue = true; + ValueReturnType = MD->getReturnType() + .getNonReferenceType() + ->getCanonicalTypeUnqualified(); + } + } + } + + if (!HasStar || !HasArrow || StarReturnType != ArrowReturnType) + return false; + HasGet = HasGet && (GetReturnType == StarReturnType); + HasValue = HasValue && (ValueReturnType == StarReturnType); + return true; +} + +} // namespace +} // namespace clang::dataflow + +// AST_MATCHER macros create an "internal" namespace, so we put it in +// its own anonymous namespace instead of in clang::dataflow. +namespace { + +AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGet) { + bool HasGet = false; + bool HasValue = false; + bool HasStarAndArrow = + clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); + return HasStarAndArrow && HasGet; +} + +AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithValue) { + bool HasGet = false; + bool HasValue = false; + bool HasStarAndArrow = + clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); + return HasStarAndArrow && HasValue; +} + +AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) { + bool HasGet = false; + bool HasValue = false; + bool HasStarAndArrow = + clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); + return HasStarAndArrow && (HasGet || HasValue); +} + +} // namespace + +namespace clang::dataflow { + +ast_matchers::internal::Matcher<Stmt> isSmartPointerLikeOperatorStar() { ---------------- ymand wrote:
I'm pretty sure our choice to use matchers in our analyses _in general_ is costly, but I don't think that this particular use of matchers will likely have much impact. That said, jvoung -- do any of our performance benchmarks exercise these cases? I would expect that code with heavy use of smart pointers could see some impact from repeatedly computing `smartPointerClassWithGetOrValue`. But, I agree that we should only optimize if we have evidence of it being a problem. https://github.com/llvm/llvm-project/pull/120102 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits