1 //== PseudoConstantAnalysis.cpp - Find Pseudoconstants in the AST-*- C++ -*-==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
14 //===----------------------------------------------------------------------===//
16 #include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/Expr.h"
19 #include "clang/AST/Stmt.h"
22 using namespace clang;
24 // The number of ValueDecls we want to keep track of by default (per-function)
25 #define VARDECL_SET_SIZE 256
26 typedef llvm::SmallPtrSet<const VarDecl*, VARDECL_SET_SIZE> VarDeclSet;
28 PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) :
29 DeclBody(DeclBody), Analyzed(false) {
30 NonConstantsImpl = new VarDeclSet;
31 UsedVarsImpl = new VarDeclSet;
34 PseudoConstantAnalysis::~PseudoConstantAnalysis() {
35 delete (VarDeclSet*)NonConstantsImpl;
36 delete (VarDeclSet*)UsedVarsImpl;
39 // Returns true if the given ValueDecl is never written to in the given DeclBody
40 bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) {
41 // Only local and static variables can be pseudoconstants
42 if (!VD->hasLocalStorage() && !VD->isStaticLocal())
50 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
52 return !NonConstants->count(VD);
55 // Returns true if the variable was used (self assignments don't count)
56 bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) {
62 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
64 return UsedVars->count(VD);
67 // Returns a Decl from a (Block)DeclRefExpr (if any)
68 const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) {
69 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
71 else if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(E))
72 return BDR->getDecl();
77 void PseudoConstantAnalysis::RunAnalysis() {
78 std::deque<const Stmt *> WorkList;
79 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
80 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
82 // Start with the top level statement of the function
83 WorkList.push_back(DeclBody);
85 while (!WorkList.empty()) {
86 const Stmt *Head = WorkList.front();
89 if (const Expr *Ex = dyn_cast<Expr>(Head))
90 Head = Ex->IgnoreParenCasts();
92 switch (Head->getStmtClass()) {
93 // Case 1: Assignment operators modifying VarDecls
94 case Stmt::BinaryOperatorClass: {
95 const BinaryOperator *BO = cast<BinaryOperator>(Head);
96 // Look for a Decl on the LHS
97 const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts());
101 // We found a binary operator with a DeclRefExpr on the LHS. We now check
102 // for any of the assignment operators, implying that this Decl is being
104 switch (BO->getOpcode()) {
105 // Self-assignments don't count as use of a variable
107 // Look for a DeclRef on the RHS
108 const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts());
110 // If the Decls match, we have self-assignment
111 if (LHSDecl == RHSDecl)
112 // Do not visit the children
125 const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl);
126 // The DeclRefExpr is being assigned to - mark it as non-constant
128 NonConstants->insert(VD);
138 // Case 2: Pre/post increment/decrement and address of
139 case Stmt::UnaryOperatorClass: {
140 const UnaryOperator *UO = cast<UnaryOperator>(Head);
142 // Look for a DeclRef in the subexpression
143 const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts());
147 // We found a unary operator with a DeclRef as a subexpression. We now
148 // check for any of the increment/decrement operators, as well as
150 switch (UO->getOpcode()) {
155 // The DeclRef is being changed - mark it as non-constant
157 // If we are taking the address of the DeclRefExpr, assume it is
159 const VarDecl *VD = dyn_cast<VarDecl>(D);
161 NonConstants->insert(VD);
171 // Case 3: Reference Declarations
172 case Stmt::DeclStmtClass: {
173 const DeclStmt *DS = cast<DeclStmt>(Head);
174 // Iterate over each decl and see if any of them contain reference decls
175 for (DeclStmt::const_decl_iterator I = DS->decl_begin(),
176 E = DS->decl_end(); I != E; ++I) {
177 // We only care about VarDecls
178 const VarDecl *VD = dyn_cast<VarDecl>(*I);
182 // We found a VarDecl; make sure it is a reference type
183 if (!VD->getType().getTypePtr()->isReferenceType())
186 // Try to find a Decl in the initializer
187 const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts());
191 // If the reference is to another var, add the var to the non-constant
193 if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) {
194 NonConstants->insert(RefVD);
201 // Case 4: Block variable references
202 case Stmt::BlockDeclRefExprClass: {
203 const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(Head);
204 if (const VarDecl *VD = dyn_cast<VarDecl>(BDR->getDecl())) {
205 // Add the Decl to the used list
206 UsedVars->insert(VD);
212 // Case 5: Variable references
213 case Stmt::DeclRefExprClass: {
214 const DeclRefExpr *DR = cast<DeclRefExpr>(Head);
215 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
216 // Add the Decl to the used list
217 UsedVars->insert(VD);
223 // Case 6: Block expressions
224 case Stmt::BlockExprClass: {
225 const BlockExpr *B = cast<BlockExpr>(Head);
226 // Add the body of the block to the list
227 WorkList.push_back(B->getBody());
233 } // switch (head->getStmtClass())
235 // Add all substatements to the worklist
236 for (Stmt::const_child_range I = Head->children(); I; ++I)
238 WorkList.push_back(*I);
239 } // while (!WorkList.empty())