20using llvm::SmallPtrSet;
31template <
typename Node>
33 SmallPtrSet<const Node *, 16> &Nodes) {
34 for (
const auto &Match : Matches)
35 Nodes.insert(Match.getNodeAs<Node>(ID));
41 A = A.getCanonicalType();
42 B = B.getCanonicalType();
50 const CXXMethodDecl &O) {
51 if (D.getNumParams() != O.getNumParams())
53 for (
int I = 0, E = D.getNumParams(); I < E; ++I) {
55 O.getParamDecl(I)->getType()))
66 DeclContext::lookup_result LookupResult =
67 D.getParent()->lookup(D.getNameInfo().getName());
68 if (LookupResult.isSingleResult()) {
72 for (
const Decl *Overload : LookupResult) {
73 const auto *O = dyn_cast<CXXMethodDecl>(Overload);
74 if (O && !O->isDeleted() && O->isConst() &&
75 O->getRefQualifier() == D.getRefQualifier() &&
85 assert(A->isPointerType() || A->isReferenceType());
86 assert(B->isPointerType() || B->isReferenceType());
126 assert(!M.isConst());
131 if (ConstOverload ==
nullptr) {
136 const QualType CallTy = M.getReturnType().getCanonicalType();
137 const QualType OverloadTy = ConstOverload->getReturnType().getCanonicalType();
138 if (CallTy->isReferenceType()) {
139 return OverloadTy->isReferenceType() &&
142 if (CallTy->isPointerType()) {
143 return OverloadTy->isPointerType() &&
168AST_MATCHER_P(DeclRefExpr, doesNotMutateObject,
int, Indirections) {
180 StackEntry(
const Expr *E,
int Indirections)
181 : E(E), Indirections(Indirections) {}
189 llvm::SmallVector<StackEntry, 4> Stack;
190 Stack.emplace_back(&Node, Indirections);
191 ASTContext &Ctx = Finder->getASTContext();
193 while (!Stack.empty()) {
194 const StackEntry Entry = Stack.back();
199 QualType Ty = Entry.E->getType().getCanonicalType();
200 for (int I = 0; I < Entry.Indirections; ++I) {
201 assert(Ty->isPointerType());
202 Ty = Ty->getPointeeType().getCanonicalType();
204 if (Ty->isVoidType() || Ty.isConstQualified())
209 const DynTypedNodeList Parents = Ctx.getParents(*
Entry.E);
213 for (
const auto &Parent : Parents) {
214 if (Parent.get<CompoundStmt>()) {
218 const Expr *
const P = Parent.get<Expr>();
232 if (isa<ParenExpr>(
P) || isa<MaterializeTemporaryExpr>(
P)) {
233 Stack.emplace_back(
P, Entry.Indirections);
236 if (
const auto *
const Cast = dyn_cast<CastExpr>(
P)) {
237 switch (Cast->getCastKind()) {
242 case CK_BaseToDerived:
243 case CK_DerivedToBase:
244 case CK_UncheckedDerivedToBase:
246 case CK_BaseToDerivedMemberPointer:
247 case CK_DerivedToBaseMemberPointer:
248 Stack.emplace_back(Cast, Entry.Indirections);
251 case CK_PointerToBoolean:
254 case CK_LValueToRValue: {
256 if (Entry.Indirections == 0)
258 Stack.emplace_back(Cast, Entry.Indirections);
266 if (
const auto *
const Member = dyn_cast<MemberExpr>(
P)) {
267 if (
const auto *
const Method =
268 dyn_cast<CXXMethodDecl>(Member->getMemberDecl())) {
276 const auto MemberParents = Ctx.getParents(*Member);
277 assert(MemberParents.size() == 1);
278 const auto *
Call = MemberParents[0].get<CallExpr>();
281 assert(Call !=
nullptr &&
"member function has to be called");
284 Method->getReturnType().getCanonicalType()->isPointerType()
291 Stack.emplace_back(Member, 0);
294 if (
const auto *
const OpCall = dyn_cast<CXXOperatorCallExpr>(
P)) {
297 if (OpCall->getNumArgs() == 0 || OpCall->getArg(0) != Entry.E) {
300 const auto *
const Method =
301 dyn_cast_or_null<CXXMethodDecl>(OpCall->getDirectCallee());
303 if (Method ==
nullptr) {
317 Method->getReturnType().getCanonicalType()->isPointerType() ? 1
324 if (
const auto *
const Op = dyn_cast<UnaryOperator>(
P)) {
325 switch (Op->getOpcode()) {
327 Stack.emplace_back(Op, Entry.Indirections + 1);
330 assert(Entry.Indirections > 0);
331 Stack.emplace_back(Op, Entry.Indirections - 1);
350SmallPtrSet<const DeclRefExpr *, 16>
352 ASTContext &Context,
int Indirections) {
353 auto Matches = match(findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl))),
354 doesNotMutateObject(Indirections))
357 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
364 ASTContext &Context,
int Indirections) {
371 auto ConstReferenceDeclRefs =
376SmallPtrSet<const DeclRefExpr *, 16>
378 auto Matches = match(
379 findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind(
"declRef")),
381 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
386SmallPtrSet<const DeclRefExpr *, 16>
388 auto Matches = match(
389 decl(forEachDescendant(
390 declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind(
"declRef"))),
392 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
398 ASTContext &Context) {
399 auto UsedAsConstRefArg = forEachArgumentWithParam(
400 declRefExpr(equalsNode(&DeclRef)),
401 parmVarDecl(hasType(matchers::isReferenceToConst())));
402 auto Matches = match(
404 cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl(
405 isCopyConstructor())))
406 .bind(
"constructExpr"))),
408 return !Matches.empty();
412 ASTContext &Context) {
413 auto UsedAsConstRefArg = forEachArgumentWithParam(
414 declRefExpr(equalsNode(&DeclRef)),
415 parmVarDecl(hasType(matchers::isReferenceToConst())));
416 auto Matches = match(
418 cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName(
"="),
419 callee(cxxMethodDecl(isCopyAssignmentOperator())))
420 .bind(
"operatorCallExpr"))),
422 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 ...