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