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