clang-tools  3.9.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 bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt,
75  ASTContext &Context) {
76  // Collect all DeclRefExprs to the loop variable and all CallExprs and
77  // CXXConstructExprs where the loop variable is used as argument to a const
78  // reference parameter.
79  // If the difference is empty it is safe for the loop variable to be a const
80  // reference.
81  auto AllDeclRefs = allDeclRefExprs(Var, Stmt, Context);
82  auto ConstReferenceDeclRefs = constReferenceDeclRefExprs(Var, Stmt, Context);
83  return isSetDifferenceEmpty(AllDeclRefs, ConstReferenceDeclRefs);
84 }
85 
86 SmallPtrSet<const DeclRefExpr *, 16>
87 allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context) {
88  auto Matches = match(
89  findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef")),
90  Stmt, Context);
91  SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
92  extractNodesByIdTo(Matches, "declRef", DeclRefs);
93  return DeclRefs;
94 }
95 
96 bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Stmt &Stmt,
97  ASTContext &Context) {
98  auto UsedAsConstRefArg = forEachArgumentWithParam(
99  declRefExpr(equalsNode(&DeclRef)),
100  parmVarDecl(hasType(matchers::isReferenceToConst())));
101  auto Matches = match(
102  stmt(hasDescendant(
103  cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl(
104  isCopyConstructor())))
105  .bind("constructExpr"))),
106  Stmt, Context);
107  return !Matches.empty();
108 }
109 
110 bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Stmt &Stmt,
111  ASTContext &Context) {
112  auto UsedAsConstRefArg = forEachArgumentWithParam(
113  declRefExpr(equalsNode(&DeclRef)),
114  parmVarDecl(hasType(matchers::isReferenceToConst())));
115  auto Matches = match(
116  stmt(hasDescendant(
117  cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="))
118  .bind("operatorCallExpr"))),
119  Stmt, Context);
120  return !Matches.empty();
121 }
122 
123 } // namespace decl_ref_expr
124 } // namespace utils
125 } // namespace tidy
126 } // namespace clang
SmallPtrSet< const DeclRefExpr *, 16 > allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context)
bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt, ASTContext &Context)
Returns true if all DeclRefExpr to the variable within Stmt do not modify it.
bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Stmt &Stmt, ASTContext &Context)
bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Stmt &Stmt, ASTContext &Context)
SmallPtrSet< const DeclRefExpr *, 16 > constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context)
ClangTidyContext & Context
Definition: ClangTidy.cpp:93