clang-tools  8.0.0
DeclRefExprUtils.cpp
Go to the documentation of this file.
1 //===--- DeclRefExprUtils.cpp - clang-tidy---------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "DeclRefExprUtils.h"
11 #include "Matchers.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/DeclCXX.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 
16 namespace clang {
17 namespace tidy {
18 namespace utils {
19 namespace decl_ref_expr {
20 
21 using namespace ::clang::ast_matchers;
22 using llvm::SmallPtrSet;
23 
24 namespace {
25 
26 template <typename S> bool isSetDifferenceEmpty(const S &S1, const S &S2) {
27  for (const auto &E : S1)
28  if (S2.count(E) == 0)
29  return false;
30  return true;
31 }
32 
33 // Extracts all Nodes keyed by ID from Matches and inserts them into Nodes.
34 template <typename Node>
35 void extractNodesByIdTo(ArrayRef<BoundNodes> Matches, StringRef ID,
36  SmallPtrSet<const Node *, 16> &Nodes) {
37  for (const auto &Match : Matches)
38  Nodes.insert(Match.getNodeAs<Node>(ID));
39 }
40 
41 } // namespace
42 
43 // Finds all DeclRefExprs where a const method is called on VarDecl or VarDecl
44 // is the a const reference or value argument to a CallExpr or CXXConstructExpr.
45 SmallPtrSet<const DeclRefExpr *, 16>
46 constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt,
47  ASTContext &Context) {
48  auto DeclRefToVar =
49  declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef");
50  auto ConstMethodCallee = callee(cxxMethodDecl(isConst()));
51  // Match method call expressions where the variable is referenced as the this
52  // implicit object argument and opertor call expression for member operators
53  // where the variable is the 0-th argument.
54  auto Matches = match(
55  findAll(expr(anyOf(cxxMemberCallExpr(ConstMethodCallee, on(DeclRefToVar)),
56  cxxOperatorCallExpr(ConstMethodCallee,
57  hasArgument(0, DeclRefToVar))))),
58  Stmt, Context);
59  SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
60  extractNodesByIdTo(Matches, "declRef", DeclRefs);
61  auto ConstReferenceOrValue =
62  qualType(anyOf(referenceType(pointee(qualType(isConstQualified()))),
63  unless(anyOf(referenceType(), pointerType()))));
64  auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
65  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
66  Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
67  extractNodesByIdTo(Matches, "declRef", DeclRefs);
68  Matches =
69  match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
70  extractNodesByIdTo(Matches, "declRef", DeclRefs);
71  return DeclRefs;
72 }
73 
74 // Finds all DeclRefExprs where a const method is called on VarDecl or VarDecl
75 // is the a const reference or value argument to a CallExpr or CXXConstructExpr.
76 SmallPtrSet<const DeclRefExpr *, 16>
77 constReferenceDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl,
78  ASTContext &Context) {
79  auto DeclRefToVar =
80  declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef");
81  auto ConstMethodCallee = callee(cxxMethodDecl(isConst()));
82  // Match method call expressions where the variable is referenced as the this
83  // implicit object argument and opertor call expression for member operators
84  // where the variable is the 0-th argument.
85  auto Matches =
86  match(decl(forEachDescendant(expr(
87  anyOf(cxxMemberCallExpr(ConstMethodCallee, on(DeclRefToVar)),
88  cxxOperatorCallExpr(ConstMethodCallee,
89  hasArgument(0, DeclRefToVar)))))),
90  Decl, Context);
91  SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
92  extractNodesByIdTo(Matches, "declRef", DeclRefs);
93  auto ConstReferenceOrValue =
94  qualType(anyOf(referenceType(pointee(qualType(isConstQualified()))),
95  unless(anyOf(referenceType(), pointerType()))));
96  auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
97  DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
98  Matches = match(decl(forEachDescendant(callExpr(UsedAsConstRefOrValueArg))),
99  Decl, Context);
100  extractNodesByIdTo(Matches, "declRef", DeclRefs);
101  Matches =
102  match(decl(forEachDescendant(cxxConstructExpr(UsedAsConstRefOrValueArg))),
103  Decl, Context);
104  extractNodesByIdTo(Matches, "declRef", DeclRefs);
105  return DeclRefs;
106 }
107 
108 bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt,
109  ASTContext &Context) {
110  // Collect all DeclRefExprs to the loop variable and all CallExprs and
111  // CXXConstructExprs where the loop variable is used as argument to a const
112  // reference parameter.
113  // If the difference is empty it is safe for the loop variable to be a const
114  // reference.
115  auto AllDeclRefs = allDeclRefExprs(Var, Stmt, Context);
116  auto ConstReferenceDeclRefs = constReferenceDeclRefExprs(Var, Stmt, Context);
117  return isSetDifferenceEmpty(AllDeclRefs, ConstReferenceDeclRefs);
118 }
119 
120 SmallPtrSet<const DeclRefExpr *, 16>
121 allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context) {
122  auto Matches = match(
123  findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef")),
124  Stmt, Context);
125  SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
126  extractNodesByIdTo(Matches, "declRef", DeclRefs);
127  return DeclRefs;
128 }
129 
130 SmallPtrSet<const DeclRefExpr *, 16>
131 allDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, ASTContext &Context) {
132  auto Matches = match(
133  decl(forEachDescendant(
134  declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef"))),
135  Decl, Context);
136  SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
137  extractNodesByIdTo(Matches, "declRef", DeclRefs);
138  return DeclRefs;
139 }
140 
141 bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Decl &Decl,
142  ASTContext &Context) {
143  auto UsedAsConstRefArg = forEachArgumentWithParam(
144  declRefExpr(equalsNode(&DeclRef)),
145  parmVarDecl(hasType(matchers::isReferenceToConst())));
146  auto Matches = match(
147  decl(hasDescendant(
148  cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl(
149  isCopyConstructor())))
150  .bind("constructExpr"))),
151  Decl, Context);
152  return !Matches.empty();
153 }
154 
155 bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Decl &Decl,
156  ASTContext &Context) {
157  auto UsedAsConstRefArg = forEachArgumentWithParam(
158  declRefExpr(equalsNode(&DeclRef)),
159  parmVarDecl(hasType(matchers::isReferenceToConst())));
160  auto Matches = match(
161  decl(hasDescendant(
162  cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="),
163  callee(cxxMethodDecl(isCopyAssignmentOperator())))
164  .bind("operatorCallExpr"))),
165  Decl, Context);
166  return !Matches.empty();
167 }
168 
169 } // namespace decl_ref_expr
170 } // namespace utils
171 } // namespace tidy
172 } // namespace clang
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)
Returns true if all DeclRefExpr to the variable within Stmt do not modify it.
SmallPtrSet< const DeclRefExpr *, 16 > constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context)
Returns set of all DeclRefExprs to VarDecl within Stmt where VarDecl is guaranteed to be accessed in ...
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
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...
const DeclRefExpr * DeclRef