11#include "clang/AST/ASTContext.h"
12#include "clang/AST/DeclCXX.h"
13#include "clang/AST/ExprCXX.h"
14#include "clang/ASTMatchers/ASTMatchFinder.h"
20using llvm::SmallPtrSet;
24template <
typename S>
bool isSetDifferenceEmpty(
const S &S1,
const S &S2) {
32template <
typename Node>
33void extractNodesByIdTo(ArrayRef<BoundNodes> Matches, StringRef
ID,
34 SmallPtrSet<const Node *, 16> &Nodes) {
35 for (
const auto &Match : Matches)
36 Nodes.insert(Match.getNodeAs<
Node>(
ID));
56AST_MATCHER_P(DeclRefExpr, doesNotMutateObject,
int, Indirections) {
69 StackEntry(
const Expr *
E,
int Indirections)
70 :
E(
E), Indirections(Indirections) {}
78 llvm::SmallVector<StackEntry, 4> Stack;
79 Stack.emplace_back(&
Node, Indirections);
80 ASTContext &Ctx = Finder->getASTContext();
82 while (!Stack.empty()) {
83 const StackEntry
Entry = Stack.back();
88 QualType Ty =
Entry.E->getType().getCanonicalType();
89 for (
int I = 0; I <
Entry.Indirections; ++I) {
90 assert(Ty->isPointerType());
91 Ty = Ty->getPointeeType().getCanonicalType();
93 if (Ty.isConstQualified())
98 const DynTypedNodeList Parents = Ctx.getParents(*
Entry.E);
102 for (
const auto &
Parent : Parents) {
103 if (
Parent.get<CompoundStmt>()) {
107 const Expr *
const P =
Parent.get<Expr>();
121 if (isa<ParenExpr>(P) || isa<MaterializeTemporaryExpr>(P)) {
122 Stack.emplace_back(P,
Entry.Indirections);
125 if (
const auto *
const Cast = dyn_cast<CastExpr>(P)) {
126 switch (Cast->getCastKind()) {
131 case CK_BaseToDerived:
132 case CK_DerivedToBase:
133 case CK_UncheckedDerivedToBase:
135 case CK_BaseToDerivedMemberPointer:
136 case CK_DerivedToBaseMemberPointer:
137 Stack.emplace_back(Cast,
Entry.Indirections);
140 case CK_PointerToBoolean:
143 case CK_LValueToRValue: {
145 if (
Entry.Indirections == 0)
147 Stack.emplace_back(Cast,
Entry.Indirections);
155 if (
const auto *
const Member = dyn_cast<MemberExpr>(P)) {
156 if (
const auto *
const Method =
157 dyn_cast<CXXMethodDecl>(Member->getMemberDecl())) {
158 if (Method->isConst() || Method->isStatic()) {
164 Stack.emplace_back(Member, 0);
168 if (
const auto *
const Op = dyn_cast<UnaryOperator>(P)) {
169 switch (Op->getOpcode()) {
171 Stack.emplace_back(Op,
Entry.Indirections + 1);
174 assert(
Entry.Indirections > 0);
175 Stack.emplace_back(Op,
Entry.Indirections - 1);
194SmallPtrSet<const DeclRefExpr *, 16>
196 ASTContext &Context,
int Indirections) {
197 auto Matches = match(findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl))),
198 doesNotMutateObject(Indirections))
201 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
202 extractNodesByIdTo(Matches,
"declRef", DeclRefs);
208 ASTContext &Context,
int Indirections) {
215 auto ConstReferenceDeclRefs =
217 return isSetDifferenceEmpty(AllDeclRefs, ConstReferenceDeclRefs);
220SmallPtrSet<const DeclRefExpr *, 16>
222 auto Matches = match(
223 findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind(
"declRef")),
225 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
226 extractNodesByIdTo(Matches,
"declRef", DeclRefs);
230SmallPtrSet<const DeclRefExpr *, 16>
232 auto Matches = match(
233 decl(forEachDescendant(
234 declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind(
"declRef"))),
236 SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
237 extractNodesByIdTo(Matches,
"declRef", DeclRefs);
242 ASTContext &Context) {
243 auto UsedAsConstRefArg = forEachArgumentWithParam(
244 declRefExpr(equalsNode(&
DeclRef)),
245 parmVarDecl(hasType(matchers::isReferenceToConst())));
246 auto Matches = match(
248 cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl(
249 isCopyConstructor())))
250 .bind(
"constructExpr"))),
252 return !Matches.empty();
256 ASTContext &Context) {
257 auto UsedAsConstRefArg = forEachArgumentWithParam(
258 declRefExpr(equalsNode(&
DeclRef)),
259 parmVarDecl(hasType(matchers::isReferenceToConst())));
260 auto Matches = match(
262 cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName(
"="),
263 callee(cxxMethodDecl(isCopyAssignmentOperator())))
264 .bind(
"operatorCallExpr"))),
266 return !Matches.empty();
const FunctionDecl * Decl
::clang::DynTypedNode Node
const DeclRefExpr * DeclRef
AST_MATCHER_P(UserDefinedLiteral, hasLiteral, clang::ast_matchers::internal::Matcher< Expr >, InnerMatcher)
SmallPtrSet< const DeclRefExpr *, 16 > allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context)
Returns set of all DeclRefExprs to VarDecl within Stmt.
bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Decl &Decl, ASTContext &Context)
Returns true if DeclRefExpr is the argument of a copy-constructor call expression within Decl.
bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt, ASTContext &Context, int Indirections)
Returns true if all DeclRefExpr to the variable within Stmt do not modify it.
bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Decl &Decl, ASTContext &Context)
Returns true if DeclRefExpr is the argument of a copy-assignment operator CallExpr within Decl.
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 ...