blob: a169f89fe1fc09cb58c17121c9e0ddcbc7e43213 [file] [log] [blame]
Tom Care245adab2010-08-18 21:17:24 +00001//== PsuedoConstantAnalysis.cpp - Find Psuedoconstants in the AST-*- C++ -*-==//
2//
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
16#include "clang/Analysis/Analyses/PsuedoConstantAnalysis.h"
17#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
24// Returns true if the given ValueDecl is never written to in the given DeclBody
25bool PsuedoConstantAnalysis::isPsuedoConstant(const ValueDecl *VD) {
26 if (!Analyzed) {
27 RunAnalysis();
28 Analyzed = true;
29 }
30
31 return !NonConstants.count(VD);
32}
33
34void PsuedoConstantAnalysis::RunAnalysis() {
35 std::deque<const Stmt *> WorkList;
36
37 // Start with the top level statement of the function
38 WorkList.push_back(DeclBody);
39
40 while (!WorkList.empty()) {
41 const Stmt* Head = WorkList.front();
42 WorkList.pop_front();
43
44 switch (Head->getStmtClass()) {
45 // Case 1: Assignment operators modifying ValueDecl
46 case Stmt::BinaryOperatorClass: {
47 const BinaryOperator *BO = cast<BinaryOperator>(Head);
48 const Expr *LHS = BO->getLHS()->IgnoreParenImpCasts();
49 const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS);
50
51 // We only care about DeclRefExprs on the LHS
52 if (!DR)
53 break;
54
55 // We found a binary operator with a DeclRefExpr on the LHS. We now check
56 // for any of the assignment operators, implying that this Decl is being
57 // written to.
58 switch (BO->getOpcode()) {
59 case BinaryOperator::Assign:
60 case BinaryOperator::AddAssign:
61 case BinaryOperator::SubAssign:
62 case BinaryOperator::MulAssign:
63 case BinaryOperator::DivAssign:
64 case BinaryOperator::AndAssign:
65 case BinaryOperator::OrAssign:
66 case BinaryOperator::XorAssign:
67 case BinaryOperator::ShlAssign:
68 case BinaryOperator::ShrAssign:
69 // The DeclRefExpr is being assigned to - mark it as non-constant
70 NonConstants.insert(DR->getDecl());
71 continue; // Continue without looking at children
72
73 default:
74 break;
75 }
76 break;
77 }
78
79 // Case 2: Pre/post increment/decrement and address of
80 case Stmt::UnaryOperatorClass: {
81 const UnaryOperator *UO = cast<UnaryOperator>(Head);
82 const Expr *SubExpr = UO->getSubExpr()->IgnoreParenImpCasts();
83 const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SubExpr);
84
85 // We only care about DeclRefExprs in the subexpression
86 if (!DR)
87 break;
88
89 // We found a unary operator with a DeclRefExpr as a subexpression. We now
90 // check for any of the increment/decrement operators, as well as
91 // addressOf.
92 switch (UO->getOpcode()) {
93 case UnaryOperator::PostDec:
94 case UnaryOperator::PostInc:
95 case UnaryOperator::PreDec:
96 case UnaryOperator::PreInc:
97 // The DeclRefExpr is being changed - mark it as non-constant
98 case UnaryOperator::AddrOf:
99 // If we are taking the address of the DeclRefExpr, assume it is
100 // non-constant.
101 NonConstants.insert(DR->getDecl());
102
103 default:
104 break;
105 }
106 break;
107 }
108
109 default:
110 break;
111 } // switch (head->getStmtClass())
112
113 // Add all substatements to the worklist
114 for (Stmt::const_child_iterator I = Head->child_begin(),
115 E = Head->child_end(); I != E; ++I)
116 if (*I)
117 WorkList.push_back(*I);
118 } // while (!WorkList.empty())
119}