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 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" 20 #include <deque> 21 22 using namespace clang; 23 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; 27 PseudoConstantAnalysis(const Stmt * DeclBody)28PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) : 29 DeclBody(DeclBody), Analyzed(false) { 30 NonConstantsImpl = new VarDeclSet; 31 UsedVarsImpl = new VarDeclSet; 32 } 33 ~PseudoConstantAnalysis()34PseudoConstantAnalysis::~PseudoConstantAnalysis() { 35 delete (VarDeclSet*)NonConstantsImpl; 36 delete (VarDeclSet*)UsedVarsImpl; 37 } 38 39 // Returns true if the given ValueDecl is never written to in the given DeclBody isPseudoConstant(const VarDecl * VD)40bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) { 41 // Only local and static variables can be pseudoconstants 42 if (!VD->hasLocalStorage() && !VD->isStaticLocal()) 43 return false; 44 45 if (!Analyzed) { 46 RunAnalysis(); 47 Analyzed = true; 48 } 49 50 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; 51 52 return !NonConstants->count(VD); 53 } 54 55 // Returns true if the variable was used (self assignments don't count) wasReferenced(const VarDecl * VD)56bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) { 57 if (!Analyzed) { 58 RunAnalysis(); 59 Analyzed = true; 60 } 61 62 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; 63 64 return UsedVars->count(VD); 65 } 66 67 // Returns a Decl from a (Block)DeclRefExpr (if any) getDecl(const Expr * E)68const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) { 69 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) 70 return DR->getDecl(); 71 else if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(E)) 72 return BDR->getDecl(); 73 else 74 return 0; 75 } 76 RunAnalysis()77void PseudoConstantAnalysis::RunAnalysis() { 78 std::deque<const Stmt *> WorkList; 79 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; 80 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; 81 82 // Start with the top level statement of the function 83 WorkList.push_back(DeclBody); 84 85 while (!WorkList.empty()) { 86 const Stmt* Head = WorkList.front(); 87 WorkList.pop_front(); 88 89 if (const Expr *Ex = dyn_cast<Expr>(Head)) 90 Head = Ex->IgnoreParenCasts(); 91 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()); 98 if (!LHSDecl) 99 break; 100 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 103 // written to. 104 switch (BO->getOpcode()) { 105 // Self-assignments don't count as use of a variable 106 case BO_Assign: { 107 // Look for a DeclRef on the RHS 108 const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts()); 109 110 // If the Decls match, we have self-assignment 111 if (LHSDecl == RHSDecl) 112 // Do not visit the children 113 continue; 114 115 } 116 case BO_AddAssign: 117 case BO_SubAssign: 118 case BO_MulAssign: 119 case BO_DivAssign: 120 case BO_AndAssign: 121 case BO_OrAssign: 122 case BO_XorAssign: 123 case BO_ShlAssign: 124 case BO_ShrAssign: { 125 const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl); 126 // The DeclRefExpr is being assigned to - mark it as non-constant 127 if (VD) 128 NonConstants->insert(VD); 129 break; 130 } 131 132 default: 133 break; 134 } 135 break; 136 } 137 138 // Case 2: Pre/post increment/decrement and address of 139 case Stmt::UnaryOperatorClass: { 140 const UnaryOperator *UO = cast<UnaryOperator>(Head); 141 142 // Look for a DeclRef in the subexpression 143 const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts()); 144 if (!D) 145 break; 146 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 149 // addressOf. 150 switch (UO->getOpcode()) { 151 case UO_PostDec: 152 case UO_PostInc: 153 case UO_PreDec: 154 case UO_PreInc: 155 // The DeclRef is being changed - mark it as non-constant 156 case UO_AddrOf: { 157 // If we are taking the address of the DeclRefExpr, assume it is 158 // non-constant. 159 const VarDecl *VD = dyn_cast<VarDecl>(D); 160 if (VD) 161 NonConstants->insert(VD); 162 break; 163 } 164 165 default: 166 break; 167 } 168 break; 169 } 170 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); 179 if (!VD) 180 continue; 181 182 // We found a VarDecl; make sure it is a reference type 183 if (!VD->getType().getTypePtr()->isReferenceType()) 184 continue; 185 186 // Try to find a Decl in the initializer 187 const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts()); 188 if (!D) 189 break; 190 191 // If the reference is to another var, add the var to the non-constant 192 // list 193 if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) { 194 NonConstants->insert(RefVD); 195 continue; 196 } 197 } 198 break; 199 } 200 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); 207 continue; 208 } 209 break; 210 } 211 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); 218 continue; 219 } 220 break; 221 } 222 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()); 228 continue; 229 } 230 231 default: 232 break; 233 } // switch (head->getStmtClass()) 234 235 // Add all substatements to the worklist 236 for (Stmt::const_child_range I = Head->children(); I; ++I) 237 if (*I) 238 WorkList.push_back(*I); 239 } // while (!WorkList.empty()) 240 } 241