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 <deque> 00021 00022 using namespace clang; 00023 00024 // The number of ValueDecls we want to keep track of by default (per-function) 00025 #define VARDECL_SET_SIZE 256 00026 typedef llvm::SmallPtrSet<const VarDecl*, VARDECL_SET_SIZE> VarDeclSet; 00027 00028 PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) : 00029 DeclBody(DeclBody), Analyzed(false) { 00030 NonConstantsImpl = new VarDeclSet; 00031 UsedVarsImpl = new VarDeclSet; 00032 } 00033 00034 PseudoConstantAnalysis::~PseudoConstantAnalysis() { 00035 delete (VarDeclSet*)NonConstantsImpl; 00036 delete (VarDeclSet*)UsedVarsImpl; 00037 } 00038 00039 // Returns true if the given ValueDecl is never written to in the given DeclBody 00040 bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) { 00041 // Only local and static variables can be pseudoconstants 00042 if (!VD->hasLocalStorage() && !VD->isStaticLocal()) 00043 return false; 00044 00045 if (!Analyzed) { 00046 RunAnalysis(); 00047 Analyzed = true; 00048 } 00049 00050 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; 00051 00052 return !NonConstants->count(VD); 00053 } 00054 00055 // Returns true if the variable was used (self assignments don't count) 00056 bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) { 00057 if (!Analyzed) { 00058 RunAnalysis(); 00059 Analyzed = true; 00060 } 00061 00062 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; 00063 00064 return UsedVars->count(VD); 00065 } 00066 00067 // Returns a Decl from a (Block)DeclRefExpr (if any) 00068 const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) { 00069 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) 00070 return DR->getDecl(); 00071 else 00072 return 0; 00073 } 00074 00075 void PseudoConstantAnalysis::RunAnalysis() { 00076 std::deque<const Stmt *> WorkList; 00077 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; 00078 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; 00079 00080 // Start with the top level statement of the function 00081 WorkList.push_back(DeclBody); 00082 00083 while (!WorkList.empty()) { 00084 const Stmt *Head = WorkList.front(); 00085 WorkList.pop_front(); 00086 00087 if (const Expr *Ex = dyn_cast<Expr>(Head)) 00088 Head = Ex->IgnoreParenCasts(); 00089 00090 switch (Head->getStmtClass()) { 00091 // Case 1: Assignment operators modifying VarDecls 00092 case Stmt::BinaryOperatorClass: { 00093 const BinaryOperator *BO = cast<BinaryOperator>(Head); 00094 // Look for a Decl on the LHS 00095 const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts()); 00096 if (!LHSDecl) 00097 break; 00098 00099 // We found a binary operator with a DeclRefExpr on the LHS. We now check 00100 // for any of the assignment operators, implying that this Decl is being 00101 // written to. 00102 switch (BO->getOpcode()) { 00103 // Self-assignments don't count as use of a variable 00104 case BO_Assign: { 00105 // Look for a DeclRef on the RHS 00106 const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts()); 00107 00108 // If the Decls match, we have self-assignment 00109 if (LHSDecl == RHSDecl) 00110 // Do not visit the children 00111 continue; 00112 00113 } 00114 case BO_AddAssign: 00115 case BO_SubAssign: 00116 case BO_MulAssign: 00117 case BO_DivAssign: 00118 case BO_AndAssign: 00119 case BO_OrAssign: 00120 case BO_XorAssign: 00121 case BO_ShlAssign: 00122 case BO_ShrAssign: { 00123 const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl); 00124 // The DeclRefExpr is being assigned to - mark it as non-constant 00125 if (VD) 00126 NonConstants->insert(VD); 00127 break; 00128 } 00129 00130 default: 00131 break; 00132 } 00133 break; 00134 } 00135 00136 // Case 2: Pre/post increment/decrement and address of 00137 case Stmt::UnaryOperatorClass: { 00138 const UnaryOperator *UO = cast<UnaryOperator>(Head); 00139 00140 // Look for a DeclRef in the subexpression 00141 const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts()); 00142 if (!D) 00143 break; 00144 00145 // We found a unary operator with a DeclRef as a subexpression. We now 00146 // check for any of the increment/decrement operators, as well as 00147 // addressOf. 00148 switch (UO->getOpcode()) { 00149 case UO_PostDec: 00150 case UO_PostInc: 00151 case UO_PreDec: 00152 case UO_PreInc: 00153 // The DeclRef is being changed - mark it as non-constant 00154 case UO_AddrOf: { 00155 // If we are taking the address of the DeclRefExpr, assume it is 00156 // non-constant. 00157 const VarDecl *VD = dyn_cast<VarDecl>(D); 00158 if (VD) 00159 NonConstants->insert(VD); 00160 break; 00161 } 00162 00163 default: 00164 break; 00165 } 00166 break; 00167 } 00168 00169 // Case 3: Reference Declarations 00170 case Stmt::DeclStmtClass: { 00171 const DeclStmt *DS = cast<DeclStmt>(Head); 00172 // Iterate over each decl and see if any of them contain reference decls 00173 for (DeclStmt::const_decl_iterator I = DS->decl_begin(), 00174 E = DS->decl_end(); I != E; ++I) { 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 }