clang API Documentation
00001 //== PseudoConstantAnalysis.cpp - Find Pseudoconstants in the AST-*- C++ -*-==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file tracks the usage of variables in a Decl body to see if they are 00011 // never written to, implying that they constant. This is useful in static 00012 // analysis to see if a developer might have intended a variable to be const. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" 00017 #include "clang/AST/Decl.h" 00018 #include "clang/AST/Expr.h" 00019 #include "clang/AST/Stmt.h" 00020 #include "llvm/ADT/SmallPtrSet.h" 00021 #include <deque> 00022 00023 using namespace clang; 00024 00025 // The number of ValueDecls we want to keep track of by default (per-function) 00026 #define VARDECL_SET_SIZE 256 00027 typedef llvm::SmallPtrSet<const VarDecl*, VARDECL_SET_SIZE> VarDeclSet; 00028 00029 PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) : 00030 DeclBody(DeclBody), Analyzed(false) { 00031 NonConstantsImpl = new VarDeclSet; 00032 UsedVarsImpl = new VarDeclSet; 00033 } 00034 00035 PseudoConstantAnalysis::~PseudoConstantAnalysis() { 00036 delete (VarDeclSet*)NonConstantsImpl; 00037 delete (VarDeclSet*)UsedVarsImpl; 00038 } 00039 00040 // Returns true if the given ValueDecl is never written to in the given DeclBody 00041 bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) { 00042 // Only local and static variables can be pseudoconstants 00043 if (!VD->hasLocalStorage() && !VD->isStaticLocal()) 00044 return false; 00045 00046 if (!Analyzed) { 00047 RunAnalysis(); 00048 Analyzed = true; 00049 } 00050 00051 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; 00052 00053 return !NonConstants->count(VD); 00054 } 00055 00056 // Returns true if the variable was used (self assignments don't count) 00057 bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) { 00058 if (!Analyzed) { 00059 RunAnalysis(); 00060 Analyzed = true; 00061 } 00062 00063 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; 00064 00065 return UsedVars->count(VD); 00066 } 00067 00068 // Returns a Decl from a (Block)DeclRefExpr (if any) 00069 const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) { 00070 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) 00071 return DR->getDecl(); 00072 else 00073 return nullptr; 00074 } 00075 00076 void PseudoConstantAnalysis::RunAnalysis() { 00077 std::deque<const Stmt *> WorkList; 00078 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; 00079 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; 00080 00081 // Start with the top level statement of the function 00082 WorkList.push_back(DeclBody); 00083 00084 while (!WorkList.empty()) { 00085 const Stmt *Head = WorkList.front(); 00086 WorkList.pop_front(); 00087 00088 if (const Expr *Ex = dyn_cast<Expr>(Head)) 00089 Head = Ex->IgnoreParenCasts(); 00090 00091 switch (Head->getStmtClass()) { 00092 // Case 1: Assignment operators modifying VarDecls 00093 case Stmt::BinaryOperatorClass: { 00094 const BinaryOperator *BO = cast<BinaryOperator>(Head); 00095 // Look for a Decl on the LHS 00096 const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts()); 00097 if (!LHSDecl) 00098 break; 00099 00100 // We found a binary operator with a DeclRefExpr on the LHS. We now check 00101 // for any of the assignment operators, implying that this Decl is being 00102 // written to. 00103 switch (BO->getOpcode()) { 00104 // Self-assignments don't count as use of a variable 00105 case BO_Assign: { 00106 // Look for a DeclRef on the RHS 00107 const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts()); 00108 00109 // If the Decls match, we have self-assignment 00110 if (LHSDecl == RHSDecl) 00111 // Do not visit the children 00112 continue; 00113 00114 } 00115 case BO_AddAssign: 00116 case BO_SubAssign: 00117 case BO_MulAssign: 00118 case BO_DivAssign: 00119 case BO_AndAssign: 00120 case BO_OrAssign: 00121 case BO_XorAssign: 00122 case BO_ShlAssign: 00123 case BO_ShrAssign: { 00124 const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl); 00125 // The DeclRefExpr is being assigned to - mark it as non-constant 00126 if (VD) 00127 NonConstants->insert(VD); 00128 break; 00129 } 00130 00131 default: 00132 break; 00133 } 00134 break; 00135 } 00136 00137 // Case 2: Pre/post increment/decrement and address of 00138 case Stmt::UnaryOperatorClass: { 00139 const UnaryOperator *UO = cast<UnaryOperator>(Head); 00140 00141 // Look for a DeclRef in the subexpression 00142 const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts()); 00143 if (!D) 00144 break; 00145 00146 // We found a unary operator with a DeclRef as a subexpression. We now 00147 // check for any of the increment/decrement operators, as well as 00148 // addressOf. 00149 switch (UO->getOpcode()) { 00150 case UO_PostDec: 00151 case UO_PostInc: 00152 case UO_PreDec: 00153 case UO_PreInc: 00154 // The DeclRef is being changed - mark it as non-constant 00155 case UO_AddrOf: { 00156 // If we are taking the address of the DeclRefExpr, assume it is 00157 // non-constant. 00158 const VarDecl *VD = dyn_cast<VarDecl>(D); 00159 if (VD) 00160 NonConstants->insert(VD); 00161 break; 00162 } 00163 00164 default: 00165 break; 00166 } 00167 break; 00168 } 00169 00170 // Case 3: Reference Declarations 00171 case Stmt::DeclStmtClass: { 00172 const DeclStmt *DS = cast<DeclStmt>(Head); 00173 // Iterate over each decl and see if any of them contain reference decls 00174 for (const auto *I : DS->decls()) { 00175 // We only care about VarDecls 00176 const VarDecl *VD = dyn_cast<VarDecl>(I); 00177 if (!VD) 00178 continue; 00179 00180 // We found a VarDecl; make sure it is a reference type 00181 if (!VD->getType().getTypePtr()->isReferenceType()) 00182 continue; 00183 00184 // Try to find a Decl in the initializer 00185 const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts()); 00186 if (!D) 00187 break; 00188 00189 // If the reference is to another var, add the var to the non-constant 00190 // list 00191 if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) { 00192 NonConstants->insert(RefVD); 00193 continue; 00194 } 00195 } 00196 break; 00197 } 00198 00199 // Case 4: Variable references 00200 case Stmt::DeclRefExprClass: { 00201 const DeclRefExpr *DR = cast<DeclRefExpr>(Head); 00202 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 00203 // Add the Decl to the used list 00204 UsedVars->insert(VD); 00205 continue; 00206 } 00207 break; 00208 } 00209 00210 // Case 5: Block expressions 00211 case Stmt::BlockExprClass: { 00212 const BlockExpr *B = cast<BlockExpr>(Head); 00213 // Add the body of the block to the list 00214 WorkList.push_back(B->getBody()); 00215 continue; 00216 } 00217 00218 default: 00219 break; 00220 } // switch (head->getStmtClass()) 00221 00222 // Add all substatements to the worklist 00223 for (Stmt::const_child_range I = Head->children(); I; ++I) 00224 if (*I) 00225 WorkList.push_back(*I); 00226 } // while (!WorkList.empty()) 00227 }