blob: 42ebe9c2371fb696e71654521f401f8fe0c225fe [file] [log] [blame]
Tom Caredb34ab72010-08-23 19:51:57 +00001//== PseudoConstantAnalysis.cpp - Find Pseudoconstants in the AST-*- C++ -*-==//
Tom Care245adab2010-08-18 21:17:24 +00002//
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
Tom Caredb34ab72010-08-23 19:51:57 +000016#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
Tom Care245adab2010-08-18 21:17:24 +000017#include "clang/AST/Decl.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/Stmt.h"
20#include <deque>
21
22using namespace clang;
23
Tom Caredb34ab72010-08-23 19:51:57 +000024// The number of ValueDecls we want to keep track of by default (per-function)
25#define VARDECL_SET_SIZE 256
26typedef llvm::SmallPtrSet<const VarDecl*, VARDECL_SET_SIZE> VarDeclSet;
27
28PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) :
29 DeclBody(DeclBody), Analyzed(false) {
30 NonConstantsImpl = new VarDeclSet;
Tom Careef52bcb2010-08-24 21:09:07 +000031 UsedVarsImpl = new VarDeclSet;
Tom Caredb34ab72010-08-23 19:51:57 +000032}
33
34PseudoConstantAnalysis::~PseudoConstantAnalysis() {
35 delete (VarDeclSet*)NonConstantsImpl;
Tom Careef52bcb2010-08-24 21:09:07 +000036 delete (VarDeclSet*)UsedVarsImpl;
Tom Caredb34ab72010-08-23 19:51:57 +000037}
38
Tom Care245adab2010-08-18 21:17:24 +000039// Returns true if the given ValueDecl is never written to in the given DeclBody
Tom Caredb34ab72010-08-23 19:51:57 +000040bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) {
41 // Only local and static variables can be pseudoconstants
42 if (!VD->hasLocalStorage() && !VD->isStaticLocal())
43 return false;
44
Tom Care245adab2010-08-18 21:17:24 +000045 if (!Analyzed) {
46 RunAnalysis();
47 Analyzed = true;
48 }
49
Tom Caredb34ab72010-08-23 19:51:57 +000050 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
51
52 return !NonConstants->count(VD);
Tom Care245adab2010-08-18 21:17:24 +000053}
54
Tom Careef52bcb2010-08-24 21:09:07 +000055// Returns true if the variable was used (self assignments don't count)
56bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) {
57 if (!Analyzed) {
58 RunAnalysis();
59 Analyzed = true;
60 }
61
62 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
63
64 return UsedVars->count(VD);
65}
66
Tom Caredb34ab72010-08-23 19:51:57 +000067void PseudoConstantAnalysis::RunAnalysis() {
Tom Care245adab2010-08-18 21:17:24 +000068 std::deque<const Stmt *> WorkList;
Tom Caredb34ab72010-08-23 19:51:57 +000069 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
Tom Careef52bcb2010-08-24 21:09:07 +000070 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
Tom Care245adab2010-08-18 21:17:24 +000071
72 // Start with the top level statement of the function
73 WorkList.push_back(DeclBody);
74
75 while (!WorkList.empty()) {
76 const Stmt* Head = WorkList.front();
77 WorkList.pop_front();
78
79 switch (Head->getStmtClass()) {
80 // Case 1: Assignment operators modifying ValueDecl
81 case Stmt::BinaryOperatorClass: {
82 const BinaryOperator *BO = cast<BinaryOperator>(Head);
Tom Careef52bcb2010-08-24 21:09:07 +000083 const Expr *LHS = BO->getLHS()->IgnoreParenCasts();
Tom Care245adab2010-08-18 21:17:24 +000084 const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS);
85
86 // We only care about DeclRefExprs on the LHS
87 if (!DR)
88 break;
89
90 // We found a binary operator with a DeclRefExpr on the LHS. We now check
91 // for any of the assignment operators, implying that this Decl is being
92 // written to.
93 switch (BO->getOpcode()) {
John McCall2de56d12010-08-25 11:45:40 +000094 case BO_Assign: {
Tom Careef52bcb2010-08-24 21:09:07 +000095 const Expr *RHS = BO->getRHS()->IgnoreParenCasts();
96 if (const DeclRefExpr *RHSDecl = dyn_cast<DeclRefExpr>(RHS)) {
97 // Self-assignments don't count as use of a variable
98 if (DR->getDecl() == RHSDecl->getDecl())
99 // Do not visit the children
100 continue;
101 }
102
103 }
John McCall2de56d12010-08-25 11:45:40 +0000104 case BO_AddAssign:
105 case BO_SubAssign:
106 case BO_MulAssign:
107 case BO_DivAssign:
108 case BO_AndAssign:
109 case BO_OrAssign:
110 case BO_XorAssign:
111 case BO_ShlAssign:
112 case BO_ShrAssign: {
Tom Care245adab2010-08-18 21:17:24 +0000113 // The DeclRefExpr is being assigned to - mark it as non-constant
Tom Caredb34ab72010-08-23 19:51:57 +0000114 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
115 if (VD)
116 NonConstants->insert(VD);
117 break;
118 }
Tom Care245adab2010-08-18 21:17:24 +0000119
120 default:
121 break;
122 }
123 break;
124 }
125
126 // Case 2: Pre/post increment/decrement and address of
127 case Stmt::UnaryOperatorClass: {
128 const UnaryOperator *UO = cast<UnaryOperator>(Head);
129 const Expr *SubExpr = UO->getSubExpr()->IgnoreParenImpCasts();
130 const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SubExpr);
131
132 // We only care about DeclRefExprs in the subexpression
133 if (!DR)
134 break;
135
136 // We found a unary operator with a DeclRefExpr as a subexpression. We now
137 // check for any of the increment/decrement operators, as well as
138 // addressOf.
139 switch (UO->getOpcode()) {
John McCall2de56d12010-08-25 11:45:40 +0000140 case UO_PostDec:
141 case UO_PostInc:
142 case UO_PreDec:
143 case UO_PreInc:
Tom Care245adab2010-08-18 21:17:24 +0000144 // The DeclRefExpr is being changed - mark it as non-constant
John McCall2de56d12010-08-25 11:45:40 +0000145 case UO_AddrOf: {
Tom Care245adab2010-08-18 21:17:24 +0000146 // If we are taking the address of the DeclRefExpr, assume it is
147 // non-constant.
Tom Caredb34ab72010-08-23 19:51:57 +0000148 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
149 if (VD)
150 NonConstants->insert(VD);
151 break;
152 }
Tom Care245adab2010-08-18 21:17:24 +0000153
154 default:
155 break;
156 }
157 break;
158 }
159
Tom Caredb34ab72010-08-23 19:51:57 +0000160 // Case 3: Reference Declarations
161 case Stmt::DeclStmtClass: {
162 const DeclStmt *DS = cast<DeclStmt>(Head);
163 // Iterate over each decl and see if any of them contain reference decls
164 for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
165 I != E; ++I) {
166 // We only care about VarDecls
167 const VarDecl *VD = dyn_cast<VarDecl>(*I);
168 if (!VD)
169 continue;
170
171 // We found a VarDecl; make sure it is a reference type
172 if (!VD->getType().getTypePtr()->isReferenceType())
173 continue;
174
Tom Caredb34ab72010-08-23 19:51:57 +0000175 // If the reference is to another var, add the var to the non-constant
176 // list
Tom Careef52bcb2010-08-24 21:09:07 +0000177 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(VD->getInit()))
178 if (const VarDecl *RefVD = dyn_cast<VarDecl>(DR->getDecl())) {
Tom Caredb34ab72010-08-23 19:51:57 +0000179 NonConstants->insert(RefVD);
Tom Careef52bcb2010-08-24 21:09:07 +0000180 continue;
181 }
Tom Caredb34ab72010-08-23 19:51:57 +0000182 }
Tom Careef52bcb2010-08-24 21:09:07 +0000183 break;
184 }
185
186 // Case 4: Block variable references
187 case Stmt::BlockDeclRefExprClass: {
188 // Any block variables are assumed to be non-constant
189 const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(Head);
190 if (const VarDecl *VD = dyn_cast<VarDecl>(BDR->getDecl())) {
191 NonConstants->insert(VD);
192 UsedVars->insert(VD);
193 continue;
194 }
195 break;
196 }
197
198 // Case 5: Variable references
199 case Stmt::DeclRefExprClass: {
200 const DeclRefExpr *DR = cast<DeclRefExpr>(Head);
201 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
202 UsedVars->insert(VD);
203 continue;
204 }
205 break;
Tom Caredb34ab72010-08-23 19:51:57 +0000206 }
207
Tom Care245adab2010-08-18 21:17:24 +0000208 default:
209 break;
210 } // switch (head->getStmtClass())
211
212 // Add all substatements to the worklist
213 for (Stmt::const_child_iterator I = Head->child_begin(),
214 E = Head->child_end(); I != E; ++I)
215 if (*I)
216 WorkList.push_back(*I);
217 } // while (!WorkList.empty())
218}