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