PseudoConstantAnalysis.cpp 6.7 KB

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