clang  3.7.0
PseudoConstantAnalysis.cpp
Go to the documentation of this file.
1 //== PseudoConstantAnalysis.cpp - Find Pseudoconstants in the AST-*- C++ -*-==//
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 // This file tracks the usage of variables in a Decl body to see if they are
11 // never written to, implying that they constant. This is useful in static
12 // analysis to see if a developer might have intended a variable to be const.
13 //
14 //===----------------------------------------------------------------------===//
15 
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/Expr.h"
19 #include "clang/AST/Stmt.h"
20 #include "llvm/ADT/SmallPtrSet.h"
21 #include <deque>
22 
23 using namespace clang;
24 
25 // The number of ValueDecls we want to keep track of by default (per-function)
26 #define VARDECL_SET_SIZE 256
27 typedef llvm::SmallPtrSet<const VarDecl*, VARDECL_SET_SIZE> VarDeclSet;
28 
30  DeclBody(DeclBody), Analyzed(false) {
31  NonConstantsImpl = new VarDeclSet;
32  UsedVarsImpl = new VarDeclSet;
33 }
34 
36  delete (VarDeclSet*)NonConstantsImpl;
37  delete (VarDeclSet*)UsedVarsImpl;
38 }
39 
40 // Returns true if the given ValueDecl is never written to in the given DeclBody
42  // Only local and static variables can be pseudoconstants
43  if (!VD->hasLocalStorage() && !VD->isStaticLocal())
44  return false;
45 
46  if (!Analyzed) {
47  RunAnalysis();
48  Analyzed = true;
49  }
50 
51  VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
52 
53  return !NonConstants->count(VD);
54 }
55 
56 // Returns true if the variable was used (self assignments don't count)
58  if (!Analyzed) {
59  RunAnalysis();
60  Analyzed = true;
61  }
62 
63  VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
64 
65  return UsedVars->count(VD);
66 }
67 
68 // Returns a Decl from a (Block)DeclRefExpr (if any)
69 const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) {
70  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
71  return DR->getDecl();
72  else
73  return nullptr;
74 }
75 
77  std::deque<const Stmt *> WorkList;
78  VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
79  VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
80 
81  // Start with the top level statement of the function
82  WorkList.push_back(DeclBody);
83 
84  while (!WorkList.empty()) {
85  const Stmt *Head = WorkList.front();
86  WorkList.pop_front();
87 
88  if (const Expr *Ex = dyn_cast<Expr>(Head))
89  Head = Ex->IgnoreParenCasts();
90 
91  switch (Head->getStmtClass()) {
92  // Case 1: Assignment operators modifying VarDecls
93  case Stmt::BinaryOperatorClass: {
94  const BinaryOperator *BO = cast<BinaryOperator>(Head);
95  // Look for a Decl on the LHS
96  const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts());
97  if (!LHSDecl)
98  break;
99 
100  // We found a binary operator with a DeclRefExpr on the LHS. We now check
101  // for any of the assignment operators, implying that this Decl is being
102  // written to.
103  switch (BO->getOpcode()) {
104  // Self-assignments don't count as use of a variable
105  case BO_Assign: {
106  // Look for a DeclRef on the RHS
107  const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts());
108 
109  // If the Decls match, we have self-assignment
110  if (LHSDecl == RHSDecl)
111  // Do not visit the children
112  continue;
113 
114  }
115  case BO_AddAssign:
116  case BO_SubAssign:
117  case BO_MulAssign:
118  case BO_DivAssign:
119  case BO_AndAssign:
120  case BO_OrAssign:
121  case BO_XorAssign:
122  case BO_ShlAssign:
123  case BO_ShrAssign: {
124  const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl);
125  // The DeclRefExpr is being assigned to - mark it as non-constant
126  if (VD)
127  NonConstants->insert(VD);
128  break;
129  }
130 
131  default:
132  break;
133  }
134  break;
135  }
136 
137  // Case 2: Pre/post increment/decrement and address of
138  case Stmt::UnaryOperatorClass: {
139  const UnaryOperator *UO = cast<UnaryOperator>(Head);
140 
141  // Look for a DeclRef in the subexpression
142  const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts());
143  if (!D)
144  break;
145 
146  // We found a unary operator with a DeclRef as a subexpression. We now
147  // check for any of the increment/decrement operators, as well as
148  // addressOf.
149  switch (UO->getOpcode()) {
150  case UO_PostDec:
151  case UO_PostInc:
152  case UO_PreDec:
153  case UO_PreInc:
154  // The DeclRef is being changed - mark it as non-constant
155  case UO_AddrOf: {
156  // If we are taking the address of the DeclRefExpr, assume it is
157  // non-constant.
158  const VarDecl *VD = dyn_cast<VarDecl>(D);
159  if (VD)
160  NonConstants->insert(VD);
161  break;
162  }
163 
164  default:
165  break;
166  }
167  break;
168  }
169 
170  // Case 3: Reference Declarations
171  case Stmt::DeclStmtClass: {
172  const DeclStmt *DS = cast<DeclStmt>(Head);
173  // Iterate over each decl and see if any of them contain reference decls
174  for (const auto *I : DS->decls()) {
175  // We only care about VarDecls
176  const VarDecl *VD = dyn_cast<VarDecl>(I);
177  if (!VD)
178  continue;
179 
180  // We found a VarDecl; make sure it is a reference type
181  if (!VD->getType().getTypePtr()->isReferenceType())
182  continue;
183 
184  // Try to find a Decl in the initializer
185  const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts());
186  if (!D)
187  break;
188 
189  // If the reference is to another var, add the var to the non-constant
190  // list
191  if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) {
192  NonConstants->insert(RefVD);
193  continue;
194  }
195  }
196  break;
197  }
198 
199  // Case 4: Variable references
200  case Stmt::DeclRefExprClass: {
201  const DeclRefExpr *DR = cast<DeclRefExpr>(Head);
202  if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
203  // Add the Decl to the used list
204  UsedVars->insert(VD);
205  continue;
206  }
207  break;
208  }
209 
210  // Case 5: Block expressions
211  case Stmt::BlockExprClass: {
212  const BlockExpr *B = cast<BlockExpr>(Head);
213  // Add the body of the block to the list
214  WorkList.push_back(B->getBody());
215  continue;
216  }
217 
218  default:
219  break;
220  } // switch (head->getStmtClass())
221 
222  // Add all substatements to the worklist
223  for (const Stmt *SubStmt : Head->children())
224  if (SubStmt)
225  WorkList.push_back(SubStmt);
226  } // while (!WorkList.empty())
227 }
llvm::SmallPtrSet< const VarDecl *, VARDECL_SET_SIZE > VarDeclSet
const Expr * getInit() const
Definition: Decl.h:1068
bool isReferenceType() const
Definition: Type.h:5241
const Stmt * getBody() const
Definition: Expr.cpp:1996
Expr * getLHS() const
Definition: Expr.h:2964
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:2918
Expr * IgnoreParenCasts() LLVM_READONLY
Definition: Expr.cpp:2439
bool isStaticLocal() const
Definition: Decl.h:904
QualType getType() const
Definition: Decl.h:538
Expr * getSubExpr() const
Definition: Expr.h:1699
PseudoConstantAnalysis(const Stmt *DeclBody)
bool wasReferenced(const VarDecl *VD)
ValueDecl * getDecl()
Definition: Expr.h:994
#define false
Definition: stdbool.h:33
const Type * getTypePtr() const
Definition: Type.h:5016
Opcode getOpcode() const
Definition: Expr.h:1696
bool isPseudoConstant(const VarDecl *VD)
decl_range decls()
Definition: Stmt.h:497
Opcode getOpcode() const
Definition: Expr.h:2961
Run one or more source code analyses.
Expr * getRHS() const
Definition: Expr.h:2966
A reference to a declared variable, function, enum, etc. [C99 6.5.1p2].
Definition: Expr.h:899
bool hasLocalStorage() const
Definition: Decl.h:887