20using llvm::SmallPtrSet;
24 return llvm::none_of(S1, [&S2](
const auto &E) {
return !S2.contains(E); });
28template <
typename Node>
30 SmallPtrSet<const Node *, 16> &Nodes) {
31 for (
const auto &Match : Matches)
32 Nodes.insert(Match.getNodeAs<Node>(ID));
38 A = A.getCanonicalType();
39 B = B.getCanonicalType();
47 const CXXMethodDecl &O) {
48 if (D.getNumParams() != O.getNumParams())
50 for (
int I = 0, E = D.getNumParams(); I < E; ++I)
52 O.getParamDecl(I)->getType()))
62 const DeclContext::lookup_result LookupResult =
63 D.getParent()->lookup(D.getNameInfo().getName());
64 if (LookupResult.isSingleResult()) {
68 for (
const Decl *Overload : LookupResult) {
69 const auto *O = dyn_cast<CXXMethodDecl>(Overload);
70 if (O && !O->isDeleted() && O->isConst() &&
71 O->getRefQualifier() == D.getRefQualifier() &&
81 assert(A->isPointerType() || A->isReferenceType());
82 assert(B->isPointerType() || B->isReferenceType());
122 assert(!M.isConst());
127 if (ConstOverload ==
nullptr)
131 const QualType CallTy = M.getReturnType().getCanonicalType();
132 const QualType OverloadTy = ConstOverload->getReturnType().getCanonicalType();
133 if (CallTy->isReferenceType()) {
134 return OverloadTy->isReferenceType() &&
137 if (CallTy->isPointerType()) {
138 return OverloadTy->isPointerType() &&
163AST_MATCHER_P(DeclRefExpr, doesNotMutateObject,
int, Indirections) {
175 StackEntry(
const Expr *E,
int Indirections)
176 : E(E), Indirections(Indirections) {}
184 llvm::SmallVector<StackEntry, 4> Stack;
185 Stack.emplace_back(&Node, Indirections);
186 ASTContext &Ctx = Finder->getASTContext();
188 while (!Stack.empty()) {
189 const StackEntry Entry = Stack.back();
194 QualType Ty = Entry.E->getType().getCanonicalType();
195 for (int I = 0; I < Entry.Indirections; ++I) {
196 assert(Ty->isPointerType());
197 Ty = Ty->getPointeeType().getCanonicalType();
199 if (Ty->isVoidType() || Ty.isConstQualified())
204 const DynTypedNodeList Parents = Ctx.getParents(*
Entry.E);
208 for (
const auto &Parent : Parents) {
209 if (Parent.get<CompoundStmt>()) {
213 const Expr *
const P = Parent.get<Expr>();
227 if (isa<ParenExpr>(
P) || isa<MaterializeTemporaryExpr>(
P)) {
228 Stack.emplace_back(
P, Entry.Indirections);
231 if (
const auto *
const Cast = dyn_cast<CastExpr>(
P)) {
232 switch (Cast->getCastKind()) {
237 case CK_BaseToDerived:
238 case CK_DerivedToBase:
239 case CK_UncheckedDerivedToBase:
241 case CK_BaseToDerivedMemberPointer:
242 case CK_DerivedToBaseMemberPointer:
243 Stack.emplace_back(Cast, Entry.Indirections);
246 case CK_PointerToBoolean:
249 case CK_LValueToRValue: {
251 if (Entry.Indirections == 0)
253 Stack.emplace_back(Cast, Entry.Indirections);
261 if (
const auto *
const Member = dyn_cast<MemberExpr>(
P)) {
262 if (
const auto *
const Method =
263 dyn_cast<CXXMethodDecl>(Member->getMemberDecl())) {
271 const auto MemberParents = Ctx.getParents(*Member);
272 assert(MemberParents.size() == 1);
273 const auto *
Call = MemberParents[0].get<CallExpr>();
276 assert(Call !=
nullptr &&
"member function has to be called");
279 Method->getReturnType().getCanonicalType()->isPointerType()
286 Stack.emplace_back(Member, 0);
289 if (
const auto *
const OpCall = dyn_cast<CXXOperatorCallExpr>(
P)) {
292 if (OpCall->getNumArgs() == 0 || OpCall->getArg(0) != Entry.E)
294 const auto *
const Method =
295 dyn_cast_or_null<CXXMethodDecl>(OpCall->getDirectCallee());
297 if (Method ==
nullptr) {
310 Method->getReturnType().getCanonicalType()->isPointerType() ? 1
317 if (
const auto *
const Op = dyn_cast<UnaryOperator>(
P)) {
318 switch (Op->getOpcode()) {
320 Stack.emplace_back(Op, Entry.Indirections + 1);
323 assert(Entry.Indirections > 0);
324 Stack.emplace_back(Op, Entry.Indirections - 1);
343SmallPtrSet<const DeclRefExpr *, 16>
345 ASTContext &Context,
int Indirections) {
346 auto Matches = match(findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl))),
347 doesNotMutateObject(Indirections))
350 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
357 ASTContext &Context,
int Indirections) {
364 auto ConstReferenceDeclRefs =
369SmallPtrSet<const DeclRefExpr *, 16>
371 auto Matches = match(
372 findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind(
"declRef")),
374 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
379SmallPtrSet<const DeclRefExpr *, 16>
381 auto Matches = match(
382 decl(forEachDescendant(
383 declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind(
"declRef"))),
385 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
391 ASTContext &Context) {
392 auto UsedAsConstRefArg = forEachArgumentWithParam(
393 declRefExpr(equalsNode(&DeclRef)),
394 parmVarDecl(hasType(matchers::isReferenceToConst())));
395 auto Matches = match(
397 cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl(
398 isCopyConstructor())))
399 .bind(
"constructExpr"))),
401 return !Matches.empty();
405 ASTContext &Context) {
406 auto UsedAsConstRefArg = forEachArgumentWithParam(
407 declRefExpr(equalsNode(&DeclRef)),
408 parmVarDecl(hasType(matchers::isReferenceToConst())));
409 auto Matches = match(
411 cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName(
"="),
412 callee(cxxMethodDecl(isCopyAssignmentOperator())))
413 .bind(
"operatorCallExpr"))),
415 return !Matches.empty();
SmallPtrSet< const DeclRefExpr *, 16 > constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context, int Indirections)
Returns set of all DeclRefExprs to VarDecl within Stmt where VarDecl is guaranteed to be accessed in ...