1 //= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- C++ -*-==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines SVal, Loc, and NonLoc, classes that represent
11 // abstract r-values for use with path-sensitive value tracking.
13 //===----------------------------------------------------------------------===//
15 #include "clang/GR/PathSensitive/GRState.h"
16 #include "clang/Basic/IdentifierTable.h"
18 using namespace clang
;
24 //===----------------------------------------------------------------------===//
25 // Symbol iteration within an SVal.
26 //===----------------------------------------------------------------------===//
29 //===----------------------------------------------------------------------===//
31 //===----------------------------------------------------------------------===//
33 bool SVal::hasConjuredSymbol() const {
34 if (const nonloc::SymbolVal
* SV
= dyn_cast
<nonloc::SymbolVal
>(this)) {
35 SymbolRef sym
= SV
->getSymbol();
36 if (isa
<SymbolConjured
>(sym
))
40 if (const loc::MemRegionVal
*RV
= dyn_cast
<loc::MemRegionVal
>(this)) {
41 const MemRegion
*R
= RV
->getRegion();
42 if (const SymbolicRegion
*SR
= dyn_cast
<SymbolicRegion
>(R
)) {
43 SymbolRef sym
= SR
->getSymbol();
44 if (isa
<SymbolConjured
>(sym
))
52 const FunctionDecl
*SVal::getAsFunctionDecl() const {
53 if (const loc::MemRegionVal
* X
= dyn_cast
<loc::MemRegionVal
>(this)) {
54 const MemRegion
* R
= X
->getRegion();
55 if (const FunctionTextRegion
*CTR
= R
->getAs
<FunctionTextRegion
>())
56 return CTR
->getDecl();
62 /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
63 /// wraps a symbol, return that SymbolRef. Otherwise return 0.
64 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
65 SymbolRef
SVal::getAsLocSymbol() const {
66 if (const nonloc::LocAsInteger
*X
= dyn_cast
<nonloc::LocAsInteger
>(this))
67 return X
->getLoc().getAsLocSymbol();
69 if (const loc::MemRegionVal
*X
= dyn_cast
<loc::MemRegionVal
>(this)) {
70 const MemRegion
*R
= X
->StripCasts();
71 if (const SymbolicRegion
*SymR
= dyn_cast
<SymbolicRegion
>(R
))
72 return SymR
->getSymbol();
77 /// Get the symbol in the SVal or its base region.
78 SymbolRef
SVal::getLocSymbolInBase() const {
79 const loc::MemRegionVal
*X
= dyn_cast
<loc::MemRegionVal
>(this);
84 const MemRegion
*R
= X
->getRegion();
86 while (const SubRegion
*SR
= dyn_cast
<SubRegion
>(R
)) {
87 if (const SymbolicRegion
*SymR
= dyn_cast
<SymbolicRegion
>(SR
))
88 return SymR
->getSymbol();
90 R
= SR
->getSuperRegion();
96 /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
97 /// Otherwise return 0.
98 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
99 SymbolRef
SVal::getAsSymbol() const {
100 if (const nonloc::SymbolVal
*X
= dyn_cast
<nonloc::SymbolVal
>(this))
101 return X
->getSymbol();
103 if (const nonloc::SymExprVal
*X
= dyn_cast
<nonloc::SymExprVal
>(this))
104 if (SymbolRef Y
= dyn_cast
<SymbolData
>(X
->getSymbolicExpression()))
107 return getAsLocSymbol();
110 /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
111 /// return that expression. Otherwise return NULL.
112 const SymExpr
*SVal::getAsSymbolicExpression() const {
113 if (const nonloc::SymExprVal
*X
= dyn_cast
<nonloc::SymExprVal
>(this))
114 return X
->getSymbolicExpression();
116 return getAsSymbol();
119 const MemRegion
*SVal::getAsRegion() const {
120 if (const loc::MemRegionVal
*X
= dyn_cast
<loc::MemRegionVal
>(this))
121 return X
->getRegion();
123 if (const nonloc::LocAsInteger
*X
= dyn_cast
<nonloc::LocAsInteger
>(this)) {
124 return X
->getLoc().getAsRegion();
130 const MemRegion
*loc::MemRegionVal::StripCasts() const {
131 const MemRegion
*R
= getRegion();
132 return R
? R
->StripCasts() : NULL
;
135 bool SVal::symbol_iterator::operator==(const symbol_iterator
&X
) const {
139 bool SVal::symbol_iterator::operator!=(const symbol_iterator
&X
) const {
143 SVal::symbol_iterator::symbol_iterator(const SymExpr
*SE
) {
145 while (!isa
<SymbolData
>(itr
.back())) expand();
148 SVal::symbol_iterator
& SVal::symbol_iterator::operator++() {
149 assert(!itr
.empty() && "attempting to iterate on an 'end' iterator");
150 assert(isa
<SymbolData
>(itr
.back()));
153 while (!isa
<SymbolData
>(itr
.back())) expand();
157 SymbolRef
SVal::symbol_iterator::operator*() {
158 assert(!itr
.empty() && "attempting to dereference an 'end' iterator");
159 return cast
<SymbolData
>(itr
.back());
162 void SVal::symbol_iterator::expand() {
163 const SymExpr
*SE
= itr
.back();
166 if (const SymIntExpr
*SIE
= dyn_cast
<SymIntExpr
>(SE
)) {
167 itr
.push_back(SIE
->getLHS());
170 else if (const SymSymExpr
*SSE
= dyn_cast
<SymSymExpr
>(SE
)) {
171 itr
.push_back(SSE
->getLHS());
172 itr
.push_back(SSE
->getRHS());
176 assert(false && "unhandled expansion case");
179 const void *nonloc::LazyCompoundVal::getStore() const {
180 return static_cast<const LazyCompoundValData
*>(Data
)->getStore();
183 const TypedRegion
*nonloc::LazyCompoundVal::getRegion() const {
184 return static_cast<const LazyCompoundValData
*>(Data
)->getRegion();
187 //===----------------------------------------------------------------------===//
189 //===----------------------------------------------------------------------===//
191 nonloc::CompoundVal::iterator
nonloc::CompoundVal::begin() const {
192 return getValue()->begin();
195 nonloc::CompoundVal::iterator
nonloc::CompoundVal::end() const {
196 return getValue()->end();
199 //===----------------------------------------------------------------------===//
200 // Useful predicates.
201 //===----------------------------------------------------------------------===//
203 bool SVal::isConstant() const {
204 return isa
<nonloc::ConcreteInt
>(this) || isa
<loc::ConcreteInt
>(this);
207 bool SVal::isConstant(int I
) const {
208 if (isa
<loc::ConcreteInt
>(*this))
209 return cast
<loc::ConcreteInt
>(*this).getValue() == I
;
210 else if (isa
<nonloc::ConcreteInt
>(*this))
211 return cast
<nonloc::ConcreteInt
>(*this).getValue() == I
;
216 bool SVal::isZeroConstant() const {
217 return isConstant(0);
221 //===----------------------------------------------------------------------===//
222 // Transfer function dispatch for Non-Locs.
223 //===----------------------------------------------------------------------===//
225 SVal
nonloc::ConcreteInt::evalBinOp(SValBuilder
&svalBuilder
,
226 BinaryOperator::Opcode Op
,
227 const nonloc::ConcreteInt
& R
) const {
228 const llvm::APSInt
* X
=
229 svalBuilder
.getBasicValueFactory().evalAPSInt(Op
, getValue(), R
.getValue());
232 return nonloc::ConcreteInt(*X
);
234 return UndefinedVal();
238 nonloc::ConcreteInt::evalComplement(SValBuilder
&svalBuilder
) const {
239 return svalBuilder
.makeIntVal(~getValue());
243 nonloc::ConcreteInt::evalMinus(SValBuilder
&svalBuilder
) const {
244 return svalBuilder
.makeIntVal(-getValue());
247 //===----------------------------------------------------------------------===//
248 // Transfer function dispatch for Locs.
249 //===----------------------------------------------------------------------===//
251 SVal
loc::ConcreteInt::evalBinOp(BasicValueFactory
& BasicVals
,
252 BinaryOperator::Opcode Op
,
253 const loc::ConcreteInt
& R
) const {
255 assert (Op
== BO_Add
|| Op
== BO_Sub
||
256 (Op
>= BO_LT
&& Op
<= BO_NE
));
258 const llvm::APSInt
* X
= BasicVals
.evalAPSInt(Op
, getValue(), R
.getValue());
261 return loc::ConcreteInt(*X
);
263 return UndefinedVal();
266 //===----------------------------------------------------------------------===//
268 //===----------------------------------------------------------------------===//
270 void SVal::dump() const { dumpToStream(llvm::errs()); }
272 void SVal::dumpToStream(llvm::raw_ostream
& os
) const {
273 switch (getBaseKind()) {
278 cast
<NonLoc
>(this)->dumpToStream(os
);
281 cast
<Loc
>(this)->dumpToStream(os
);
287 assert (false && "Invalid SVal.");
291 void NonLoc::dumpToStream(llvm::raw_ostream
& os
) const {
292 switch (getSubKind()) {
293 case nonloc::ConcreteIntKind
:
294 os
<< cast
<nonloc::ConcreteInt
>(this)->getValue().getZExtValue();
295 if (cast
<nonloc::ConcreteInt
>(this)->getValue().isUnsigned())
298 case nonloc::SymbolValKind
:
299 os
<< '$' << cast
<nonloc::SymbolVal
>(this)->getSymbol();
301 case nonloc::SymExprValKind
: {
302 const nonloc::SymExprVal
& C
= *cast
<nonloc::SymExprVal
>(this);
303 const SymExpr
*SE
= C
.getSymbolicExpression();
307 case nonloc::LocAsIntegerKind
: {
308 const nonloc::LocAsInteger
& C
= *cast
<nonloc::LocAsInteger
>(this);
309 os
<< C
.getLoc() << " [as " << C
.getNumBits() << " bit integer]";
312 case nonloc::CompoundValKind
: {
313 const nonloc::CompoundVal
& C
= *cast
<nonloc::CompoundVal
>(this);
314 os
<< "compoundVal{";
316 for (nonloc::CompoundVal::iterator I
=C
.begin(), E
=C
.end(); I
!=E
; ++I
) {
318 os
<< ' '; first
= false;
323 (*I
).dumpToStream(os
);
328 case nonloc::LazyCompoundValKind
: {
329 const nonloc::LazyCompoundVal
&C
= *cast
<nonloc::LazyCompoundVal
>(this);
330 os
<< "lazyCompoundVal{" << const_cast<void *>(C
.getStore())
331 << ',' << C
.getRegion()
336 assert (false && "Pretty-printed not implemented for this NonLoc.");
341 void Loc::dumpToStream(llvm::raw_ostream
& os
) const {
342 switch (getSubKind()) {
343 case loc::ConcreteIntKind
:
344 os
<< cast
<loc::ConcreteInt
>(this)->getValue().getZExtValue() << " (Loc)";
346 case loc::GotoLabelKind
:
347 os
<< "&&" << cast
<loc::GotoLabel
>(this)->getLabel()->getID()->getName();
349 case loc::MemRegionKind
:
350 os
<< '&' << cast
<loc::MemRegionVal
>(this)->getRegion()->getString();
353 assert(false && "Pretty-printing not implemented for this Loc.");