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