blob: 314ce7cfd8636d7278f1b64322821a06fb25d07e [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"
Benjamin Kramer478851c2012-07-04 17:04:04 +000020#include "llvm/ADT/SmallPtrSet.h"
Tom Care245adab2010-08-18 21:17:24 +000021#include <deque>
22
23using namespace clang;
24
Tom Caredb34ab72010-08-23 19:51:57 +000025// 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;
Tom Careef52bcb2010-08-24 21:09:07 +000032 UsedVarsImpl = new VarDeclSet;
Tom Caredb34ab72010-08-23 19:51:57 +000033}
34
35PseudoConstantAnalysis::~PseudoConstantAnalysis() {
36 delete (VarDeclSet*)NonConstantsImpl;
Tom Careef52bcb2010-08-24 21:09:07 +000037 delete (VarDeclSet*)UsedVarsImpl;
Tom Caredb34ab72010-08-23 19:51:57 +000038}
39
Tom Care245adab2010-08-18 21:17:24 +000040// Returns true if the given ValueDecl is never written to in the given DeclBody
Tom Caredb34ab72010-08-23 19:51:57 +000041bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) {
42 // Only local and static variables can be pseudoconstants
43 if (!VD->hasLocalStorage() && !VD->isStaticLocal())
44 return false;
45
Tom Care245adab2010-08-18 21:17:24 +000046 if (!Analyzed) {
47 RunAnalysis();
48 Analyzed = true;
49 }
50
Tom Caredb34ab72010-08-23 19:51:57 +000051 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
52
53 return !NonConstants->count(VD);
Tom Care245adab2010-08-18 21:17:24 +000054}
55
Tom Careef52bcb2010-08-24 21:09:07 +000056// 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
Tom Care967fea62010-08-25 22:37:26 +000068// 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();
Tom Care967fea62010-08-25 22:37:26 +000072 else
73 return 0;
74}
75
Tom Caredb34ab72010-08-23 19:51:57 +000076void PseudoConstantAnalysis::RunAnalysis() {
Tom Care245adab2010-08-18 21:17:24 +000077 std::deque<const Stmt *> WorkList;
Tom Caredb34ab72010-08-23 19:51:57 +000078 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
Tom Careef52bcb2010-08-24 21:09:07 +000079 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
Tom Care245adab2010-08-18 21:17:24 +000080
81 // Start with the top level statement of the function
82 WorkList.push_back(DeclBody);
83
84 while (!WorkList.empty()) {
Ted Kremenek9c378f72011-08-12 23:37:29 +000085 const Stmt *Head = WorkList.front();
Tom Care245adab2010-08-18 21:17:24 +000086 WorkList.pop_front();
87
Ted Kremenek892697d2010-12-16 07:46:53 +000088 if (const Expr *Ex = dyn_cast<Expr>(Head))
89 Head = Ex->IgnoreParenCasts();
90
Tom Care245adab2010-08-18 21:17:24 +000091 switch (Head->getStmtClass()) {
Tom Care967fea62010-08-25 22:37:26 +000092 // Case 1: Assignment operators modifying VarDecls
Tom Care245adab2010-08-18 21:17:24 +000093 case Stmt::BinaryOperatorClass: {
94 const BinaryOperator *BO = cast<BinaryOperator>(Head);
Tom Care967fea62010-08-25 22:37:26 +000095 // Look for a Decl on the LHS
96 const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts());
Tom Care967fea62010-08-25 22:37:26 +000097 if (!LHSDecl)
Tom Care245adab2010-08-18 21:17:24 +000098 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()) {
Tom Care967fea62010-08-25 22:37:26 +0000104 // Self-assignments don't count as use of a variable
John McCall2de56d12010-08-25 11:45:40 +0000105 case BO_Assign: {
Tom Care967fea62010-08-25 22:37:26 +0000106 // 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;
Tom Careef52bcb2010-08-24 21:09:07 +0000113
114 }
John McCall2de56d12010-08-25 11:45:40 +0000115 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: {
Tom Care967fea62010-08-25 22:37:26 +0000124 const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl);
Tom Care245adab2010-08-18 21:17:24 +0000125 // The DeclRefExpr is being assigned to - mark it as non-constant
Tom Caredb34ab72010-08-23 19:51:57 +0000126 if (VD)
127 NonConstants->insert(VD);
128 break;
129 }
Tom Care245adab2010-08-18 21:17:24 +0000130
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);
Tom Care245adab2010-08-18 21:17:24 +0000140
Tom Care967fea62010-08-25 22:37:26 +0000141 // Look for a DeclRef in the subexpression
142 const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts());
Tom Care916d0542010-08-25 22:46:03 +0000143 if (!D)
144 break;
Tom Care245adab2010-08-18 21:17:24 +0000145
Tom Care967fea62010-08-25 22:37:26 +0000146 // We found a unary operator with a DeclRef as a subexpression. We now
Tom Care245adab2010-08-18 21:17:24 +0000147 // check for any of the increment/decrement operators, as well as
148 // addressOf.
149 switch (UO->getOpcode()) {
John McCall2de56d12010-08-25 11:45:40 +0000150 case UO_PostDec:
151 case UO_PostInc:
152 case UO_PreDec:
153 case UO_PreInc:
Tom Care967fea62010-08-25 22:37:26 +0000154 // The DeclRef is being changed - mark it as non-constant
John McCall2de56d12010-08-25 11:45:40 +0000155 case UO_AddrOf: {
Tom Care245adab2010-08-18 21:17:24 +0000156 // If we are taking the address of the DeclRefExpr, assume it is
157 // non-constant.
Tom Care967fea62010-08-25 22:37:26 +0000158 const VarDecl *VD = dyn_cast<VarDecl>(D);
Tom Caredb34ab72010-08-23 19:51:57 +0000159 if (VD)
160 NonConstants->insert(VD);
161 break;
162 }
Tom Care245adab2010-08-18 21:17:24 +0000163
164 default:
165 break;
166 }
167 break;
168 }
169
Tom Caredb34ab72010-08-23 19:51:57 +0000170 // 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
Stephen Hines651f13c2014-04-23 16:59:28 -0700174 for (const auto *I : DS->decls()) {
Tom Caredb34ab72010-08-23 19:51:57 +0000175 // We only care about VarDecls
Stephen Hines651f13c2014-04-23 16:59:28 -0700176 const VarDecl *VD = dyn_cast<VarDecl>(I);
Tom Caredb34ab72010-08-23 19:51:57 +0000177 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
Tom Care967fea62010-08-25 22:37:26 +0000184 // Try to find a Decl in the initializer
185 const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts());
Tom Care916d0542010-08-25 22:46:03 +0000186 if (!D)
187 break;
Tom Care967fea62010-08-25 22:37:26 +0000188
Tom Caredb34ab72010-08-23 19:51:57 +0000189 // If the reference is to another var, add the var to the non-constant
190 // list
Tom Care967fea62010-08-25 22:37:26 +0000191 if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) {
192 NonConstants->insert(RefVD);
193 continue;
194 }
Tom Caredb34ab72010-08-23 19:51:57 +0000195 }
Tom Careef52bcb2010-08-24 21:09:07 +0000196 break;
197 }
198
John McCallf4b88a42012-03-10 09:33:50 +0000199 // Case 4: Variable references
Tom Careef52bcb2010-08-24 21:09:07 +0000200 case Stmt::DeclRefExprClass: {
201 const DeclRefExpr *DR = cast<DeclRefExpr>(Head);
202 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
Tom Care967fea62010-08-25 22:37:26 +0000203 // Add the Decl to the used list
Tom Careef52bcb2010-08-24 21:09:07 +0000204 UsedVars->insert(VD);
205 continue;
206 }
207 break;
Tom Caredb34ab72010-08-23 19:51:57 +0000208 }
209
John McCallf4b88a42012-03-10 09:33:50 +0000210 // Case 5: Block expressions
Tom Care967fea62010-08-25 22:37:26 +0000211 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
Ted Kremenek892697d2010-12-16 07:46:53 +0000218 default:
219 break;
Tom Care245adab2010-08-18 21:17:24 +0000220 } // switch (head->getStmtClass())
221
222 // Add all substatements to the worklist
John McCall7502c1d2011-02-13 04:07:26 +0000223 for (Stmt::const_child_range I = Head->children(); I; ++I)
Tom Care245adab2010-08-18 21:17:24 +0000224 if (*I)
225 WorkList.push_back(*I);
226 } // while (!WorkList.empty())
227}