blob: 614f676fb19341196c82541e326e6d05971c2af5 [file] [log] [blame]
Tom Caree332c3b2010-08-23 19:51:57 +00001//== PseudoConstantAnalysis.cpp - Find Pseudoconstants in the AST-*- C++ -*-==//
Tom Careb9933f32010-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 Caree332c3b2010-08-23 19:51:57 +000016#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
Tom Careb9933f32010-08-18 21:17:24 +000017#include "clang/AST/Decl.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/Stmt.h"
Benjamin Kramer1ea8e092012-07-04 17:04:04 +000020#include "llvm/ADT/SmallPtrSet.h"
Tom Careb9933f32010-08-18 21:17:24 +000021#include <deque>
22
23using namespace clang;
24
Matthias Braun1d030072016-01-30 01:27:06 +000025typedef llvm::SmallPtrSet<const VarDecl*, 32> VarDeclSet;
Tom Caree332c3b2010-08-23 19:51:57 +000026
27PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) :
28 DeclBody(DeclBody), Analyzed(false) {
29 NonConstantsImpl = new VarDeclSet;
Tom Carea4603112010-08-24 21:09:07 +000030 UsedVarsImpl = new VarDeclSet;
Tom Caree332c3b2010-08-23 19:51:57 +000031}
32
33PseudoConstantAnalysis::~PseudoConstantAnalysis() {
34 delete (VarDeclSet*)NonConstantsImpl;
Tom Carea4603112010-08-24 21:09:07 +000035 delete (VarDeclSet*)UsedVarsImpl;
Tom Caree332c3b2010-08-23 19:51:57 +000036}
37
Tom Careb9933f32010-08-18 21:17:24 +000038// Returns true if the given ValueDecl is never written to in the given DeclBody
Tom Caree332c3b2010-08-23 19:51:57 +000039bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) {
40 // Only local and static variables can be pseudoconstants
41 if (!VD->hasLocalStorage() && !VD->isStaticLocal())
42 return false;
43
Tom Careb9933f32010-08-18 21:17:24 +000044 if (!Analyzed) {
45 RunAnalysis();
46 Analyzed = true;
47 }
48
Tom Caree332c3b2010-08-23 19:51:57 +000049 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
50
51 return !NonConstants->count(VD);
Tom Careb9933f32010-08-18 21:17:24 +000052}
53
Tom Carea4603112010-08-24 21:09:07 +000054// Returns true if the variable was used (self assignments don't count)
55bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) {
56 if (!Analyzed) {
57 RunAnalysis();
58 Analyzed = true;
59 }
60
61 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
62
63 return UsedVars->count(VD);
64}
65
Tom Care82b2a1d2010-08-25 22:37:26 +000066// Returns a Decl from a (Block)DeclRefExpr (if any)
67const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) {
68 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
69 return DR->getDecl();
Tom Care82b2a1d2010-08-25 22:37:26 +000070 else
Craig Topper25542942014-05-20 04:30:07 +000071 return nullptr;
Tom Care82b2a1d2010-08-25 22:37:26 +000072}
73
Tom Caree332c3b2010-08-23 19:51:57 +000074void PseudoConstantAnalysis::RunAnalysis() {
Tom Careb9933f32010-08-18 21:17:24 +000075 std::deque<const Stmt *> WorkList;
Tom Caree332c3b2010-08-23 19:51:57 +000076 VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
Tom Carea4603112010-08-24 21:09:07 +000077 VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
Tom Careb9933f32010-08-18 21:17:24 +000078
79 // Start with the top level statement of the function
80 WorkList.push_back(DeclBody);
81
82 while (!WorkList.empty()) {
Ted Kremenek5ef32db2011-08-12 23:37:29 +000083 const Stmt *Head = WorkList.front();
Tom Careb9933f32010-08-18 21:17:24 +000084 WorkList.pop_front();
85
Ted Kremenek8219b822010-12-16 07:46:53 +000086 if (const Expr *Ex = dyn_cast<Expr>(Head))
87 Head = Ex->IgnoreParenCasts();
88
Tom Careb9933f32010-08-18 21:17:24 +000089 switch (Head->getStmtClass()) {
Tom Care82b2a1d2010-08-25 22:37:26 +000090 // Case 1: Assignment operators modifying VarDecls
Tom Careb9933f32010-08-18 21:17:24 +000091 case Stmt::BinaryOperatorClass: {
92 const BinaryOperator *BO = cast<BinaryOperator>(Head);
Tom Care82b2a1d2010-08-25 22:37:26 +000093 // Look for a Decl on the LHS
94 const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts());
Tom Care82b2a1d2010-08-25 22:37:26 +000095 if (!LHSDecl)
Tom Careb9933f32010-08-18 21:17:24 +000096 break;
97
98 // We found a binary operator with a DeclRefExpr on the LHS. We now check
99 // for any of the assignment operators, implying that this Decl is being
100 // written to.
101 switch (BO->getOpcode()) {
Tom Care82b2a1d2010-08-25 22:37:26 +0000102 // Self-assignments don't count as use of a variable
John McCalle3027922010-08-25 11:45:40 +0000103 case BO_Assign: {
Tom Care82b2a1d2010-08-25 22:37:26 +0000104 // Look for a DeclRef on the RHS
105 const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts());
106
107 // If the Decls match, we have self-assignment
108 if (LHSDecl == RHSDecl)
109 // Do not visit the children
110 continue;
Tom Carea4603112010-08-24 21:09:07 +0000111
112 }
John McCalle3027922010-08-25 11:45:40 +0000113 case BO_AddAssign:
114 case BO_SubAssign:
115 case BO_MulAssign:
116 case BO_DivAssign:
117 case BO_AndAssign:
118 case BO_OrAssign:
119 case BO_XorAssign:
120 case BO_ShlAssign:
121 case BO_ShrAssign: {
Tom Care82b2a1d2010-08-25 22:37:26 +0000122 const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl);
Tom Careb9933f32010-08-18 21:17:24 +0000123 // The DeclRefExpr is being assigned to - mark it as non-constant
Tom Caree332c3b2010-08-23 19:51:57 +0000124 if (VD)
125 NonConstants->insert(VD);
126 break;
127 }
Tom Careb9933f32010-08-18 21:17:24 +0000128
129 default:
130 break;
131 }
132 break;
133 }
134
135 // Case 2: Pre/post increment/decrement and address of
136 case Stmt::UnaryOperatorClass: {
137 const UnaryOperator *UO = cast<UnaryOperator>(Head);
Tom Careb9933f32010-08-18 21:17:24 +0000138
Tom Care82b2a1d2010-08-25 22:37:26 +0000139 // Look for a DeclRef in the subexpression
140 const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts());
Tom Care9a68bcc2010-08-25 22:46:03 +0000141 if (!D)
142 break;
Tom Careb9933f32010-08-18 21:17:24 +0000143
Tom Care82b2a1d2010-08-25 22:37:26 +0000144 // We found a unary operator with a DeclRef as a subexpression. We now
Tom Careb9933f32010-08-18 21:17:24 +0000145 // check for any of the increment/decrement operators, as well as
146 // addressOf.
147 switch (UO->getOpcode()) {
John McCalle3027922010-08-25 11:45:40 +0000148 case UO_PostDec:
149 case UO_PostInc:
150 case UO_PreDec:
151 case UO_PreInc:
Tom Care82b2a1d2010-08-25 22:37:26 +0000152 // The DeclRef is being changed - mark it as non-constant
John McCalle3027922010-08-25 11:45:40 +0000153 case UO_AddrOf: {
Tom Careb9933f32010-08-18 21:17:24 +0000154 // If we are taking the address of the DeclRefExpr, assume it is
155 // non-constant.
Tom Care82b2a1d2010-08-25 22:37:26 +0000156 const VarDecl *VD = dyn_cast<VarDecl>(D);
Tom Caree332c3b2010-08-23 19:51:57 +0000157 if (VD)
158 NonConstants->insert(VD);
159 break;
160 }
Tom Careb9933f32010-08-18 21:17:24 +0000161
162 default:
163 break;
164 }
165 break;
166 }
167
Tom Caree332c3b2010-08-23 19:51:57 +0000168 // Case 3: Reference Declarations
169 case Stmt::DeclStmtClass: {
170 const DeclStmt *DS = cast<DeclStmt>(Head);
171 // Iterate over each decl and see if any of them contain reference decls
Aaron Ballman535bbcc2014-03-14 17:01:24 +0000172 for (const auto *I : DS->decls()) {
Tom Caree332c3b2010-08-23 19:51:57 +0000173 // We only care about VarDecls
Aaron Ballman535bbcc2014-03-14 17:01:24 +0000174 const VarDecl *VD = dyn_cast<VarDecl>(I);
Tom Caree332c3b2010-08-23 19:51:57 +0000175 if (!VD)
176 continue;
177
178 // We found a VarDecl; make sure it is a reference type
179 if (!VD->getType().getTypePtr()->isReferenceType())
180 continue;
181
Tom Care82b2a1d2010-08-25 22:37:26 +0000182 // Try to find a Decl in the initializer
183 const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts());
Tom Care9a68bcc2010-08-25 22:46:03 +0000184 if (!D)
185 break;
Tom Care82b2a1d2010-08-25 22:37:26 +0000186
Tom Caree332c3b2010-08-23 19:51:57 +0000187 // If the reference is to another var, add the var to the non-constant
188 // list
Tom Care82b2a1d2010-08-25 22:37:26 +0000189 if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) {
190 NonConstants->insert(RefVD);
191 continue;
192 }
Tom Caree332c3b2010-08-23 19:51:57 +0000193 }
Tom Carea4603112010-08-24 21:09:07 +0000194 break;
195 }
196
John McCall113bee02012-03-10 09:33:50 +0000197 // Case 4: Variable references
Tom Carea4603112010-08-24 21:09:07 +0000198 case Stmt::DeclRefExprClass: {
199 const DeclRefExpr *DR = cast<DeclRefExpr>(Head);
200 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
Tom Care82b2a1d2010-08-25 22:37:26 +0000201 // Add the Decl to the used list
Tom Carea4603112010-08-24 21:09:07 +0000202 UsedVars->insert(VD);
203 continue;
204 }
205 break;
Tom Caree332c3b2010-08-23 19:51:57 +0000206 }
207
John McCall113bee02012-03-10 09:33:50 +0000208 // Case 5: Block expressions
Tom Care82b2a1d2010-08-25 22:37:26 +0000209 case Stmt::BlockExprClass: {
210 const BlockExpr *B = cast<BlockExpr>(Head);
211 // Add the body of the block to the list
212 WorkList.push_back(B->getBody());
213 continue;
214 }
215
Ted Kremenek8219b822010-12-16 07:46:53 +0000216 default:
217 break;
Tom Careb9933f32010-08-18 21:17:24 +0000218 } // switch (head->getStmtClass())
219
220 // Add all substatements to the worklist
Benjamin Kramer642f1732015-07-02 21:03:14 +0000221 for (const Stmt *SubStmt : Head->children())
222 if (SubStmt)
223 WorkList.push_back(SubStmt);
Tom Careb9933f32010-08-18 21:17:24 +0000224 } // while (!WorkList.empty())
225}