22
33#include " clang/AST/CanonicalType.h"
44#include " clang/AST/DeclCXX.h"
5+ #include " clang/AST/Type.h"
56#include " clang/ASTMatchers/ASTMatchers.h"
67#include " clang/ASTMatchers/ASTMatchersMacros.h"
78#include " clang/Basic/OperatorKinds.h"
@@ -23,13 +24,28 @@ using ast_matchers::pointerType;
2324using ast_matchers::referenceType;
2425using ast_matchers::returns;
2526
26- bool hasSmartPointerClassShape (const CXXRecordDecl &RD, bool &HasGet,
27- bool &HasValue) {
27+ CanQualType getLikeReturnType (QualType RT) {
28+ if (!RT.isNull () && RT->isPointerType ()) {
29+ return RT->getPointeeType ()
30+ ->getCanonicalTypeUnqualified ()
31+ .getUnqualifiedType ();
32+ }
33+ return {};
34+ }
35+
36+ CanQualType valueLikeReturnType (QualType RT) {
37+ if (!RT.isNull () && RT->isReferenceType ()) {
38+ return RT.getNonReferenceType ()
39+ ->getCanonicalTypeUnqualified ()
40+ .getUnqualifiedType ();
41+ }
42+ return {};
43+ }
44+
45+ CanQualType pointerLikeReturnType (const CXXRecordDecl &RD) {
2846 // We may want to cache this search, but in current profiles it hasn't shown
2947 // up as a hot spot (possibly because there aren't many hits, relatively).
30- bool HasArrow = false ;
31- bool HasStar = false ;
32- CanQualType StarReturnType, ArrowReturnType, GetReturnType, ValueReturnType;
48+ CanQualType StarReturnType, ArrowReturnType;
3349 for (const auto *MD : RD.methods ()) {
3450 // We only consider methods that are const and have zero parameters.
3551 // It may be that there is a non-const overload for the method, but
@@ -38,55 +54,35 @@ bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet,
3854 continue ;
3955 switch (MD->getOverloadedOperator ()) {
4056 case OO_Star:
41- if (MD->getReturnType ()->isReferenceType ()) {
42- HasStar = true ;
43- StarReturnType = MD->getReturnType ()
44- .getNonReferenceType ()
45- ->getCanonicalTypeUnqualified ()
46- .getUnqualifiedType ();
47- }
57+ StarReturnType = valueLikeReturnType (MD->getReturnType ());
4858 break ;
4959 case OO_Arrow:
50- if (MD->getReturnType ()->isPointerType ()) {
51- HasArrow = true ;
52- ArrowReturnType = MD->getReturnType ()
53- ->getPointeeType ()
54- ->getCanonicalTypeUnqualified ()
55- .getUnqualifiedType ();
56- }
60+ ArrowReturnType = getLikeReturnType (MD->getReturnType ());
5761 break ;
58- case OO_None: {
59- IdentifierInfo *II = MD->getIdentifier ();
60- if (II == nullptr )
61- continue ;
62- if (II->isStr (" get" )) {
63- if (MD->getReturnType ()->isPointerType ()) {
64- HasGet = true ;
65- GetReturnType = MD->getReturnType ()
66- ->getPointeeType ()
67- ->getCanonicalTypeUnqualified ()
68- .getUnqualifiedType ();
69- }
70- } else if (II->isStr (" value" )) {
71- if (MD->getReturnType ()->isReferenceType ()) {
72- HasValue = true ;
73- ValueReturnType = MD->getReturnType ()
74- .getNonReferenceType ()
75- ->getCanonicalTypeUnqualified ()
76- .getUnqualifiedType ();
77- }
78- }
79- } break ;
8062 default :
8163 break ;
8264 }
8365 }
66+ if (!StarReturnType.isNull () && !ArrowReturnType.isNull () &&
67+ StarReturnType == ArrowReturnType)
68+ return StarReturnType;
8469
85- if (!HasStar || !HasArrow || StarReturnType != ArrowReturnType)
86- return false ;
87- HasGet = HasGet && (GetReturnType == StarReturnType);
88- HasValue = HasValue && (ValueReturnType == StarReturnType);
89- return true ;
70+ return {};
71+ }
72+
73+ QualType 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, but
77+ // 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 {};
9086}
9187
9288} // namespace
@@ -96,36 +92,37 @@ bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet,
9692// its own anonymous namespace instead of in clang::dataflow.
9793namespace {
9894
99- AST_MATCHER (clang::CXXRecordDecl, smartPointerClassWithGet) {
100- bool HasGet = false ;
101- bool HasValue = false ;
102- bool HasStarAndArrow =
103- clang::dataflow::hasSmartPointerClassShape (Node, HasGet, HasValue);
104- return HasStarAndArrow && HasGet;
95+ using clang::dataflow::findReturnType;
96+ using clang::dataflow::getLikeReturnType;
97+ using clang::dataflow::pointerLikeReturnType;
98+ using clang::dataflow::valueLikeReturnType;
99+
100+ AST_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;
105106}
106107
107- AST_MATCHER (clang::CXXRecordDecl, smartPointerClassWithValue) {
108- bool HasGet = false ;
109- bool HasValue = false ;
110- bool HasStarAndArrow =
111- clang::dataflow::hasSmartPointerClassShape (Node, HasGet, HasValue) ;
112- return HasStarAndArrow && HasValue ;
108+ AST_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 ;
113114}
114115
115116AST_MATCHER (clang::CXXRecordDecl, smartPointerClassWithGetOrValue) {
116- bool HasGet = false ;
117- bool HasValue = false ;
118- bool HasStarAndArrow =
119- clang::dataflow::hasSmartPointerClassShape ( Node, HasGet, HasValue);
120- return HasStarAndArrow && (HasGet || HasValue) ;
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 ;
121122}
122123
123124AST_MATCHER (clang::CXXRecordDecl, pointerClass) {
124- bool HasGet = false ;
125- bool HasValue = false ;
126- bool HasStarAndArrow =
127- clang::dataflow::hasSmartPointerClassShape (Node, HasGet, HasValue);
128- return HasStarAndArrow;
125+ return !pointerLikeReturnType (Node).isNull ();
129126}
130127
131128} // namespace
@@ -164,16 +161,19 @@ ast_matchers::StatementMatcher isPointerLikeOperatorArrow() {
164161 ofClass (pointerClass ()))));
165162}
166163
167- ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall () {
164+ ast_matchers::StatementMatcher
165+ isSmartPointerLikeValueMethodCall (clang::StringRef MethodName) {
168166 return cxxMemberCallExpr (callee (cxxMethodDecl (
169167 parameterCountIs (0 ), returns (hasCanonicalType (referenceType ())),
170- hasName (" value" ), ofClass (smartPointerClassWithValue ()))));
168+ hasName (MethodName),
169+ ofClass (smartPointerClassWithValueLike (MethodName)))));
171170}
172171
173- ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall () {
172+ ast_matchers::StatementMatcher
173+ isSmartPointerLikeGetMethodCall (clang::StringRef MethodName) {
174174 return cxxMemberCallExpr (callee (cxxMethodDecl (
175175 parameterCountIs (0 ), returns (hasCanonicalType (pointerType ())),
176- hasName (" get " ), ofClass (smartPointerClassWithGet ( )))));
176+ hasName (MethodName ), ofClass (smartPointerClassWithGetLike (MethodName )))));
177177}
178178
179179const FunctionDecl *
0 commit comments