Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp
213799 views
1
#include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h"
2
3
#include "clang/AST/CanonicalType.h"
4
#include "clang/AST/DeclCXX.h"
5
#include "clang/AST/Type.h"
6
#include "clang/ASTMatchers/ASTMatchers.h"
7
#include "clang/ASTMatchers/ASTMatchersMacros.h"
8
#include "clang/Basic/OperatorKinds.h"
9
10
namespace clang::dataflow {
11
12
namespace {
13
14
using ast_matchers::callee;
15
using ast_matchers::cxxMemberCallExpr;
16
using ast_matchers::cxxMethodDecl;
17
using ast_matchers::cxxOperatorCallExpr;
18
using ast_matchers::hasCanonicalType;
19
using ast_matchers::hasName;
20
using ast_matchers::hasOverloadedOperatorName;
21
using ast_matchers::ofClass;
22
using ast_matchers::parameterCountIs;
23
using ast_matchers::pointerType;
24
using ast_matchers::referenceType;
25
using ast_matchers::returns;
26
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) {
46
// We may want to cache this search, but in current profiles it hasn't shown
47
// up as a hot spot (possibly because there aren't many hits, relatively).
48
CanQualType StarReturnType, ArrowReturnType;
49
for (const auto *MD : RD.methods()) {
50
// We only consider methods that are const and have zero parameters.
51
// It may be that there is a non-const overload for the method, but
52
// there should at least be a const overload as well.
53
if (!MD->isConst() || MD->getNumParams() != 0)
54
continue;
55
switch (MD->getOverloadedOperator()) {
56
case OO_Star:
57
StarReturnType = valueLikeReturnType(MD->getReturnType());
58
break;
59
case OO_Arrow:
60
ArrowReturnType = getLikeReturnType(MD->getReturnType());
61
break;
62
default:
63
break;
64
}
65
}
66
if (!StarReturnType.isNull() && !ArrowReturnType.isNull() &&
67
StarReturnType == ArrowReturnType)
68
return StarReturnType;
69
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 {};
86
}
87
88
} // namespace
89
} // namespace clang::dataflow
90
91
// AST_MATCHER macros create an "internal" namespace, so we put it in
92
// its own anonymous namespace instead of in clang::dataflow.
93
namespace {
94
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;
106
}
107
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;
114
}
115
116
AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) {
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;
122
}
123
124
AST_MATCHER(clang::CXXRecordDecl, pointerClass) {
125
return !pointerLikeReturnType(Node).isNull();
126
}
127
128
} // namespace
129
130
namespace clang::dataflow {
131
132
ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar() {
133
return cxxOperatorCallExpr(
134
hasOverloadedOperatorName("*"),
135
callee(cxxMethodDecl(parameterCountIs(0),
136
returns(hasCanonicalType(referenceType())),
137
ofClass(smartPointerClassWithGetOrValue()))));
138
}
139
140
ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() {
141
return cxxOperatorCallExpr(
142
hasOverloadedOperatorName("->"),
143
callee(cxxMethodDecl(parameterCountIs(0),
144
returns(hasCanonicalType(pointerType())),
145
ofClass(smartPointerClassWithGetOrValue()))));
146
}
147
148
ast_matchers::StatementMatcher isPointerLikeOperatorStar() {
149
return cxxOperatorCallExpr(
150
hasOverloadedOperatorName("*"),
151
callee(cxxMethodDecl(parameterCountIs(0),
152
returns(hasCanonicalType(referenceType())),
153
ofClass(pointerClass()))));
154
}
155
156
ast_matchers::StatementMatcher isPointerLikeOperatorArrow() {
157
return cxxOperatorCallExpr(
158
hasOverloadedOperatorName("->"),
159
callee(cxxMethodDecl(parameterCountIs(0),
160
returns(hasCanonicalType(pointerType())),
161
ofClass(pointerClass()))));
162
}
163
164
ast_matchers::StatementMatcher
165
isSmartPointerLikeValueMethodCall(clang::StringRef MethodName) {
166
return cxxMemberCallExpr(callee(cxxMethodDecl(
167
parameterCountIs(0), returns(hasCanonicalType(referenceType())),
168
hasName(MethodName),
169
ofClass(smartPointerClassWithValueLike(MethodName)))));
170
}
171
172
ast_matchers::StatementMatcher
173
isSmartPointerLikeGetMethodCall(clang::StringRef MethodName) {
174
return cxxMemberCallExpr(callee(cxxMethodDecl(
175
parameterCountIs(0), returns(hasCanonicalType(pointerType())),
176
hasName(MethodName), ofClass(smartPointerClassWithGetLike(MethodName)))));
177
}
178
179
const FunctionDecl *
180
getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE) {
181
const FunctionDecl *CanonicalCallee = nullptr;
182
const CXXMethodDecl *Callee =
183
cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
184
if (Callee == nullptr)
185
return nullptr;
186
const CXXRecordDecl *RD = Callee->getParent();
187
if (RD == nullptr)
188
return nullptr;
189
for (const auto *MD : RD->methods()) {
190
if (MD->getOverloadedOperator() == OO_Star && MD->isConst() &&
191
MD->getNumParams() == 0 && MD->getReturnType()->isReferenceType()) {
192
CanonicalCallee = MD;
193
break;
194
}
195
}
196
return CanonicalCallee;
197
}
198
199
} // namespace clang::dataflow
200
201