2
2
3
3
#include " clang/AST/CanonicalType.h"
4
4
#include " clang/AST/DeclCXX.h"
5
+ #include " clang/AST/Type.h"
5
6
#include " clang/ASTMatchers/ASTMatchers.h"
6
7
#include " clang/ASTMatchers/ASTMatchersMacros.h"
7
8
#include " clang/Basic/OperatorKinds.h"
@@ -23,13 +24,28 @@ using ast_matchers::pointerType;
23
24
using ast_matchers::referenceType;
24
25
using ast_matchers::returns;
25
26
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) {
28
46
// We may want to cache this search, but in current profiles it hasn't shown
29
47
// 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;
33
49
for (const auto *MD : RD.methods ()) {
34
50
// We only consider methods that are const and have zero parameters.
35
51
// 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,
38
54
continue ;
39
55
switch (MD->getOverloadedOperator ()) {
40
56
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 ());
48
58
break ;
49
59
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 ());
57
61
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 ;
80
62
default :
81
63
break ;
82
64
}
83
65
}
66
+ if (!StarReturnType.isNull () && !ArrowReturnType.isNull () &&
67
+ StarReturnType == ArrowReturnType)
68
+ return StarReturnType;
84
69
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 {};
90
86
}
91
87
92
88
} // namespace
@@ -96,36 +92,37 @@ bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet,
96
92
// its own anonymous namespace instead of in clang::dataflow.
97
93
namespace {
98
94
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;
105
106
}
106
107
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 ;
113
114
}
114
115
115
116
AST_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 ;
121
122
}
122
123
123
124
AST_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 ();
129
126
}
130
127
131
128
} // namespace
@@ -164,16 +161,19 @@ ast_matchers::StatementMatcher isPointerLikeOperatorArrow() {
164
161
ofClass (pointerClass ()))));
165
162
}
166
163
167
- ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall () {
164
+ ast_matchers::StatementMatcher
165
+ isSmartPointerLikeValueMethodCall (clang::StringRef MethodName) {
168
166
return cxxMemberCallExpr (callee (cxxMethodDecl (
169
167
parameterCountIs (0 ), returns (hasCanonicalType (referenceType ())),
170
- hasName (" value" ), ofClass (smartPointerClassWithValue ()))));
168
+ hasName (MethodName),
169
+ ofClass (smartPointerClassWithValueLike (MethodName)))));
171
170
}
172
171
173
- ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall () {
172
+ ast_matchers::StatementMatcher
173
+ isSmartPointerLikeGetMethodCall (clang::StringRef MethodName) {
174
174
return cxxMemberCallExpr (callee (cxxMethodDecl (
175
175
parameterCountIs (0 ), returns (hasCanonicalType (pointerType ())),
176
- hasName (" get " ), ofClass (smartPointerClassWithGet ( )))));
176
+ hasName (MethodName ), ofClass (smartPointerClassWithGetLike (MethodName )))));
177
177
}
178
178
179
179
const FunctionDecl *
0 commit comments