blob: 8f24c432b157932c92c0982f6f5f7d5b0e504c2b [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 Care967fea62010-08-25 22:37:26 +000067// Returns a Decl from a (Block)DeclRefExpr (if any)
68const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) {
69 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
70 return DR->getDecl();
71 else if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(E))
72 return BDR->getDecl();
73 else
74 return 0;
75}
76
Tom Caredb34ab72010-08-23 19:51:57 +000077void PseudoConstantAnalysis::RunAnalysis() {
Tom Care245adab2010-08-18 21:17:24 +000078 std::deque<const Stmt *> WorkList;
Tom Caredb34ab72010-08-23 19:51:57 +000079 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
Tom Careef52bcb2010-08-24 21:09:07 +000080 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
Tom Care245adab2010-08-18 21:17:24 +000081
82 // Start with the top level statement of the function
83 WorkList.push_back(DeclBody);
84
85 while (!WorkList.empty()) {
Ted Kremenek9c378f72011-08-12 23:37:29 +000086 const Stmt *Head = WorkList.front();
Tom Care245adab2010-08-18 21:17:24 +000087 WorkList.pop_front();
88
Ted Kremenek892697d2010-12-16 07:46:53 +000089 if (const Expr *Ex = dyn_cast<Expr>(Head))
90 Head = Ex->IgnoreParenCasts();
91
Tom Care245adab2010-08-18 21:17:24 +000092 switch (Head->getStmtClass()) {
Tom Care967fea62010-08-25 22:37:26 +000093 // Case 1: Assignment operators modifying VarDecls
Tom Care245adab2010-08-18 21:17:24 +000094 case Stmt::BinaryOperatorClass: {
95 const BinaryOperator *BO = cast<BinaryOperator>(Head);
Tom Care967fea62010-08-25 22:37:26 +000096 // Look for a Decl on the LHS
97 const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts());
Tom Care967fea62010-08-25 22:37:26 +000098 if (!LHSDecl)
Tom Care245adab2010-08-18 21:17:24 +000099 break;
100
101 // We found a binary operator with a DeclRefExpr on the LHS. We now check
102 // for any of the assignment operators, implying that this Decl is being
103 // written to.
104 switch (BO->getOpcode()) {
Tom Care967fea62010-08-25 22:37:26 +0000105 // Self-assignments don't count as use of a variable
John McCall2de56d12010-08-25 11:45:40 +0000106 case BO_Assign: {
Tom Care967fea62010-08-25 22:37:26 +0000107 // Look for a DeclRef on the RHS
108 const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts());
109
110 // If the Decls match, we have self-assignment
111 if (LHSDecl == RHSDecl)
112 // Do not visit the children
113 continue;
Tom Careef52bcb2010-08-24 21:09:07 +0000114
115 }
John McCall2de56d12010-08-25 11:45:40 +0000116 case BO_AddAssign:
117 case BO_SubAssign:
118 case BO_MulAssign:
119 case BO_DivAssign:
120 case BO_AndAssign:
121 case BO_OrAssign:
122 case BO_XorAssign:
123 case BO_ShlAssign:
124 case BO_ShrAssign: {
Tom Care967fea62010-08-25 22:37:26 +0000125 const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl);
Tom Care245adab2010-08-18 21:17:24 +0000126 // The DeclRefExpr is being assigned to - mark it as non-constant
Tom Caredb34ab72010-08-23 19:51:57 +0000127 if (VD)
128 NonConstants->insert(VD);
129 break;
130 }
Tom Care245adab2010-08-18 21:17:24 +0000131
132 default:
133 break;
134 }
135 break;
136 }
137
138 // Case 2: Pre/post increment/decrement and address of
139 case Stmt::UnaryOperatorClass: {
140 const UnaryOperator *UO = cast<UnaryOperator>(Head);
Tom Care245adab2010-08-18 21:17:24 +0000141
Tom Care967fea62010-08-25 22:37:26 +0000142 // Look for a DeclRef in the subexpression
143 const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts());
Tom Care916d0542010-08-25 22:46:03 +0000144 if (!D)
145 break;
Tom Care245adab2010-08-18 21:17:24 +0000146
Tom Care967fea62010-08-25 22:37:26 +0000147 // We found a unary operator with a DeclRef as a subexpression. We now
Tom Care245adab2010-08-18 21:17:24 +0000148 // check for any of the increment/decrement operators, as well as
149 // addressOf.
150 switch (UO->getOpcode()) {
John McCall2de56d12010-08-25 11:45:40 +0000151 case UO_PostDec:
152 case UO_PostInc:
153 case UO_PreDec:
154 case UO_PreInc:
Tom Care967fea62010-08-25 22:37:26 +0000155 // The DeclRef is being changed - mark it as non-constant
John McCall2de56d12010-08-25 11:45:40 +0000156 case UO_AddrOf: {
Tom Care245adab2010-08-18 21:17:24 +0000157 // If we are taking the address of the DeclRefExpr, assume it is
158 // non-constant.
Tom Care967fea62010-08-25 22:37:26 +0000159 const VarDecl *VD = dyn_cast<VarDecl>(D);
Tom Caredb34ab72010-08-23 19:51:57 +0000160 if (VD)
161 NonConstants->insert(VD);
162 break;
163 }
Tom Care245adab2010-08-18 21:17:24 +0000164
165 default:
166 break;
167 }
168 break;
169 }
170
Tom Caredb34ab72010-08-23 19:51:57 +0000171 // Case 3: Reference Declarations
172 case Stmt::DeclStmtClass: {
173 const DeclStmt *DS = cast<DeclStmt>(Head);
174 // Iterate over each decl and see if any of them contain reference decls
Tom Care967fea62010-08-25 22:37:26 +0000175 for (DeclStmt::const_decl_iterator I = DS->decl_begin(),
176 E = DS->decl_end(); I != E; ++I) {
Tom Caredb34ab72010-08-23 19:51:57 +0000177 // We only care about VarDecls
178 const VarDecl *VD = dyn_cast<VarDecl>(*I);
179 if (!VD)
180 continue;
181
182 // We found a VarDecl; make sure it is a reference type
183 if (!VD->getType().getTypePtr()->isReferenceType())
184 continue;
185
Tom Care967fea62010-08-25 22:37:26 +0000186 // Try to find a Decl in the initializer
187 const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts());
Tom Care916d0542010-08-25 22:46:03 +0000188 if (!D)
189 break;
Tom Care967fea62010-08-25 22:37:26 +0000190
Tom Caredb34ab72010-08-23 19:51:57 +0000191 // If the reference is to another var, add the var to the non-constant
192 // list
Tom Care967fea62010-08-25 22:37:26 +0000193 if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) {
194 NonConstants->insert(RefVD);
195 continue;
196 }
Tom Caredb34ab72010-08-23 19:51:57 +0000197 }
Tom Careef52bcb2010-08-24 21:09:07 +0000198 break;
199 }
200
201 // Case 4: Block variable references
202 case Stmt::BlockDeclRefExprClass: {
Tom Careef52bcb2010-08-24 21:09:07 +0000203 const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(Head);
204 if (const VarDecl *VD = dyn_cast<VarDecl>(BDR->getDecl())) {
Tom Care967fea62010-08-25 22:37:26 +0000205 // Add the Decl to the used list
Tom Careef52bcb2010-08-24 21:09:07 +0000206 UsedVars->insert(VD);
207 continue;
208 }
209 break;
210 }
211
212 // Case 5: Variable references
213 case Stmt::DeclRefExprClass: {
214 const DeclRefExpr *DR = cast<DeclRefExpr>(Head);
215 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
Tom Care967fea62010-08-25 22:37:26 +0000216 // Add the Decl to the used list
Tom Careef52bcb2010-08-24 21:09:07 +0000217 UsedVars->insert(VD);
218 continue;
219 }
220 break;
Tom Caredb34ab72010-08-23 19:51:57 +0000221 }
222
Tom Care967fea62010-08-25 22:37:26 +0000223 // Case 6: Block expressions
224 case Stmt::BlockExprClass: {
225 const BlockExpr *B = cast<BlockExpr>(Head);
226 // Add the body of the block to the list
227 WorkList.push_back(B->getBody());
228 continue;
229 }
230
Ted Kremenek892697d2010-12-16 07:46:53 +0000231 default:
232 break;
Tom Care245adab2010-08-18 21:17:24 +0000233 } // switch (head->getStmtClass())
234
235 // Add all substatements to the worklist
John McCall7502c1d2011-02-13 04:07:26 +0000236 for (Stmt::const_child_range I = Head->children(); I; ++I)
Tom Care245adab2010-08-18 21:17:24 +0000237 if (*I)
238 WorkList.push_back(*I);
239 } // while (!WorkList.empty())
240}