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()))
63 const DeclContext::lookup_result LookupResult =
64 D.getParent()->lookup(D.getNameInfo().getName());
65 if (LookupResult.isSingleResult()) {
69 for (
const Decl *Overload : LookupResult) {
70 const auto *O = dyn_cast<CXXMethodDecl>(Overload);
71 if (O && !O->isDeleted() && O->isConst() &&
72 O->getRefQualifier() == D.getRefQualifier() &&
82 assert(A->isPointerType() || A->isReferenceType());
83 assert(B->isPointerType() || B->isReferenceType());
123 assert(!M.isConst());
128 if (ConstOverload ==
nullptr) {
133 const QualType CallTy = M.getReturnType().getCanonicalType();
134 const QualType OverloadTy = ConstOverload->getReturnType().getCanonicalType();
135 if (CallTy->isReferenceType()) {
136 return OverloadTy->isReferenceType() &&
139 if (CallTy->isPointerType()) {
140 return OverloadTy->isPointerType() &&
165AST_MATCHER_P(DeclRefExpr, doesNotMutateObject,
int, Indirections) {
177 StackEntry(
const Expr *E,
int Indirections)
178 : E(E), Indirections(Indirections) {}
186 llvm::SmallVector<StackEntry, 4> Stack;
187 Stack.emplace_back(&Node, Indirections);
188 ASTContext &Ctx = Finder->getASTContext();
190 while (!Stack.empty()) {
191 const StackEntry Entry = Stack.back();
196 QualType Ty = Entry.E->getType().getCanonicalType();
197 for (int I = 0; I < Entry.Indirections; ++I) {
198 assert(Ty->isPointerType());
199 Ty = Ty->getPointeeType().getCanonicalType();
201 if (Ty->isVoidType() || Ty.isConstQualified())
206 const DynTypedNodeList Parents = Ctx.getParents(*
Entry.E);
210 for (
const auto &Parent : Parents) {
211 if (Parent.get<CompoundStmt>()) {
215 const Expr *
const P = Parent.get<Expr>();
229 if (isa<ParenExpr>(
P) || isa<MaterializeTemporaryExpr>(
P)) {
230 Stack.emplace_back(
P, Entry.Indirections);
233 if (
const auto *
const Cast = dyn_cast<CastExpr>(
P)) {
234 switch (Cast->getCastKind()) {
239 case CK_BaseToDerived:
240 case CK_DerivedToBase:
241 case CK_UncheckedDerivedToBase:
243 case CK_BaseToDerivedMemberPointer:
244 case CK_DerivedToBaseMemberPointer:
245 Stack.emplace_back(Cast, Entry.Indirections);
248 case CK_PointerToBoolean:
251 case CK_LValueToRValue: {
253 if (Entry.Indirections == 0)
255 Stack.emplace_back(Cast, Entry.Indirections);
263 if (
const auto *
const Member = dyn_cast<MemberExpr>(
P)) {
264 if (
const auto *
const Method =
265 dyn_cast<CXXMethodDecl>(Member->getMemberDecl())) {
273 const auto MemberParents = Ctx.getParents(*Member);
274 assert(MemberParents.size() == 1);
275 const auto *
Call = MemberParents[0].get<CallExpr>();
278 assert(Call !=
nullptr &&
"member function has to be called");
281 Method->getReturnType().getCanonicalType()->isPointerType()
288 Stack.emplace_back(Member, 0);
291 if (
const auto *
const OpCall = dyn_cast<CXXOperatorCallExpr>(
P)) {
294 if (OpCall->getNumArgs() == 0 || OpCall->getArg(0) != Entry.E) {
297 const auto *
const Method =
298 dyn_cast_or_null<CXXMethodDecl>(OpCall->getDirectCallee());
300 if (Method ==
nullptr) {
314 Method->getReturnType().getCanonicalType()->isPointerType() ? 1
321 if (
const auto *
const Op = dyn_cast<UnaryOperator>(
P)) {
322 switch (Op->getOpcode()) {
324 Stack.emplace_back(Op, Entry.Indirections + 1);
327 assert(Entry.Indirections > 0);
328 Stack.emplace_back(Op, Entry.Indirections - 1);
347SmallPtrSet<const DeclRefExpr *, 16>
349 ASTContext &Context,
int Indirections) {
350 auto Matches = match(findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl))),
351 doesNotMutateObject(Indirections))
354 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
361 ASTContext &Context,
int Indirections) {
368 auto ConstReferenceDeclRefs =
373SmallPtrSet<const DeclRefExpr *, 16>
375 auto Matches = match(
376 findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind(
"declRef")),
378 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
383SmallPtrSet<const DeclRefExpr *, 16>
385 auto Matches = match(
386 decl(forEachDescendant(
387 declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind(
"declRef"))),
389 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
395 ASTContext &Context) {
396 auto UsedAsConstRefArg = forEachArgumentWithParam(
397 declRefExpr(equalsNode(&DeclRef)),
398 parmVarDecl(hasType(matchers::isReferenceToConst())));
399 auto Matches = match(
401 cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl(
402 isCopyConstructor())))
403 .bind(
"constructExpr"))),
405 return !Matches.empty();
409 ASTContext &Context) {
410 auto UsedAsConstRefArg = forEachArgumentWithParam(
411 declRefExpr(equalsNode(&DeclRef)),
412 parmVarDecl(hasType(matchers::isReferenceToConst())));
413 auto Matches = match(
415 cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName(
"="),
416 callee(cxxMethodDecl(isCopyAssignmentOperator())))
417 .bind(
"operatorCallExpr"))),
419 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 ...