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