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/StaticAnalyzer/PathSensitive/GRState.h"
16 #include "clang/AST/ExprObjC.h"
17 #include "clang/Basic/IdentifierTable.h"
19 using namespace clang
;
25 //===----------------------------------------------------------------------===//
26 // Symbol iteration within an SVal.
27 //===----------------------------------------------------------------------===//
30 //===----------------------------------------------------------------------===//
32 //===----------------------------------------------------------------------===//
34 bool SVal::hasConjuredSymbol() const {
35 if (const nonloc::SymbolVal
* SV
= dyn_cast
<nonloc::SymbolVal
>(this)) {
36 SymbolRef sym
= SV
->getSymbol();
37 if (isa
<SymbolConjured
>(sym
))
41 if (const loc::MemRegionVal
*RV
= dyn_cast
<loc::MemRegionVal
>(this)) {
42 const MemRegion
*R
= RV
->getRegion();
43 if (const SymbolicRegion
*SR
= dyn_cast
<SymbolicRegion
>(R
)) {
44 SymbolRef sym
= SR
->getSymbol();
45 if (isa
<SymbolConjured
>(sym
))
53 const FunctionDecl
*SVal::getAsFunctionDecl() const {
54 if (const loc::MemRegionVal
* X
= dyn_cast
<loc::MemRegionVal
>(this)) {
55 const MemRegion
* R
= X
->getRegion();
56 if (const FunctionTextRegion
*CTR
= R
->getAs
<FunctionTextRegion
>())
57 return CTR
->getDecl();
63 /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
64 /// wraps a symbol, return that SymbolRef. Otherwise return 0.
65 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
66 SymbolRef
SVal::getAsLocSymbol() const {
67 if (const nonloc::LocAsInteger
*X
= dyn_cast
<nonloc::LocAsInteger
>(this))
68 return X
->getLoc().getAsLocSymbol();
70 if (const loc::MemRegionVal
*X
= dyn_cast
<loc::MemRegionVal
>(this)) {
71 const MemRegion
*R
= X
->StripCasts();
72 if (const SymbolicRegion
*SymR
= dyn_cast
<SymbolicRegion
>(R
))
73 return SymR
->getSymbol();
78 /// Get the symbol in the SVal or its base region.
79 SymbolRef
SVal::getLocSymbolInBase() const {
80 const loc::MemRegionVal
*X
= dyn_cast
<loc::MemRegionVal
>(this);
85 const MemRegion
*R
= X
->getRegion();
87 while (const SubRegion
*SR
= dyn_cast
<SubRegion
>(R
)) {
88 if (const SymbolicRegion
*SymR
= dyn_cast
<SymbolicRegion
>(SR
))
89 return SymR
->getSymbol();
91 R
= SR
->getSuperRegion();
97 /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
98 /// Otherwise return 0.
99 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
100 SymbolRef
SVal::getAsSymbol() const {
101 if (const nonloc::SymbolVal
*X
= dyn_cast
<nonloc::SymbolVal
>(this))
102 return X
->getSymbol();
104 if (const nonloc::SymExprVal
*X
= dyn_cast
<nonloc::SymExprVal
>(this))
105 if (SymbolRef Y
= dyn_cast
<SymbolData
>(X
->getSymbolicExpression()))
108 return getAsLocSymbol();
111 /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
112 /// return that expression. Otherwise return NULL.
113 const SymExpr
*SVal::getAsSymbolicExpression() const {
114 if (const nonloc::SymExprVal
*X
= dyn_cast
<nonloc::SymExprVal
>(this))
115 return X
->getSymbolicExpression();
117 return getAsSymbol();
120 const MemRegion
*SVal::getAsRegion() const {
121 if (const loc::MemRegionVal
*X
= dyn_cast
<loc::MemRegionVal
>(this))
122 return X
->getRegion();
124 if (const nonloc::LocAsInteger
*X
= dyn_cast
<nonloc::LocAsInteger
>(this)) {
125 return X
->getLoc().getAsRegion();
131 const MemRegion
*loc::MemRegionVal::StripCasts() const {
132 const MemRegion
*R
= getRegion();
133 return R
? R
->StripCasts() : NULL
;
136 bool SVal::symbol_iterator::operator==(const symbol_iterator
&X
) const {
140 bool SVal::symbol_iterator::operator!=(const symbol_iterator
&X
) const {
144 SVal::symbol_iterator::symbol_iterator(const SymExpr
*SE
) {
146 while (!isa
<SymbolData
>(itr
.back())) expand();
149 SVal::symbol_iterator
& SVal::symbol_iterator::operator++() {
150 assert(!itr
.empty() && "attempting to iterate on an 'end' iterator");
151 assert(isa
<SymbolData
>(itr
.back()));
154 while (!isa
<SymbolData
>(itr
.back())) expand();
158 SymbolRef
SVal::symbol_iterator::operator*() {
159 assert(!itr
.empty() && "attempting to dereference an 'end' iterator");
160 return cast
<SymbolData
>(itr
.back());
163 void SVal::symbol_iterator::expand() {
164 const SymExpr
*SE
= itr
.back();
167 if (const SymIntExpr
*SIE
= dyn_cast
<SymIntExpr
>(SE
)) {
168 itr
.push_back(SIE
->getLHS());
171 else if (const SymSymExpr
*SSE
= dyn_cast
<SymSymExpr
>(SE
)) {
172 itr
.push_back(SSE
->getLHS());
173 itr
.push_back(SSE
->getRHS());
177 assert(false && "unhandled expansion case");
180 const void *nonloc::LazyCompoundVal::getStore() const {
181 return static_cast<const LazyCompoundValData
*>(Data
)->getStore();
184 const TypedRegion
*nonloc::LazyCompoundVal::getRegion() const {
185 return static_cast<const LazyCompoundValData
*>(Data
)->getRegion();
188 //===----------------------------------------------------------------------===//
190 //===----------------------------------------------------------------------===//
192 nonloc::CompoundVal::iterator
nonloc::CompoundVal::begin() const {
193 return getValue()->begin();
196 nonloc::CompoundVal::iterator
nonloc::CompoundVal::end() const {
197 return getValue()->end();
200 //===----------------------------------------------------------------------===//
201 // Useful predicates.
202 //===----------------------------------------------------------------------===//
204 bool SVal::isConstant() const {
205 return isa
<nonloc::ConcreteInt
>(this) || isa
<loc::ConcreteInt
>(this);
208 bool SVal::isConstant(int I
) const {
209 if (isa
<loc::ConcreteInt
>(*this))
210 return cast
<loc::ConcreteInt
>(*this).getValue() == I
;
211 else if (isa
<nonloc::ConcreteInt
>(*this))
212 return cast
<nonloc::ConcreteInt
>(*this).getValue() == I
;
217 bool SVal::isZeroConstant() const {
218 return isConstant(0);
222 //===----------------------------------------------------------------------===//
223 // Transfer function dispatch for Non-Locs.
224 //===----------------------------------------------------------------------===//
226 SVal
nonloc::ConcreteInt::evalBinOp(SValBuilder
&svalBuilder
,
227 BinaryOperator::Opcode Op
,
228 const nonloc::ConcreteInt
& R
) const {
229 const llvm::APSInt
* X
=
230 svalBuilder
.getBasicValueFactory().evalAPSInt(Op
, getValue(), R
.getValue());
233 return nonloc::ConcreteInt(*X
);
235 return UndefinedVal();
239 nonloc::ConcreteInt::evalComplement(SValBuilder
&svalBuilder
) const {
240 return svalBuilder
.makeIntVal(~getValue());
244 nonloc::ConcreteInt::evalMinus(SValBuilder
&svalBuilder
) const {
245 return svalBuilder
.makeIntVal(-getValue());
248 //===----------------------------------------------------------------------===//
249 // Transfer function dispatch for Locs.
250 //===----------------------------------------------------------------------===//
252 SVal
loc::ConcreteInt::evalBinOp(BasicValueFactory
& BasicVals
,
253 BinaryOperator::Opcode Op
,
254 const loc::ConcreteInt
& R
) const {
256 assert (Op
== BO_Add
|| Op
== BO_Sub
||
257 (Op
>= BO_LT
&& Op
<= BO_NE
));
259 const llvm::APSInt
* X
= BasicVals
.evalAPSInt(Op
, getValue(), R
.getValue());
262 return loc::ConcreteInt(*X
);
264 return UndefinedVal();
267 //===----------------------------------------------------------------------===//
269 //===----------------------------------------------------------------------===//
271 void SVal::dump() const { dumpToStream(llvm::errs()); }
273 void SVal::dumpToStream(llvm::raw_ostream
& os
) const {
274 switch (getBaseKind()) {
279 cast
<NonLoc
>(this)->dumpToStream(os
);
282 cast
<Loc
>(this)->dumpToStream(os
);
288 assert (false && "Invalid SVal.");
292 void NonLoc::dumpToStream(llvm::raw_ostream
& os
) const {
293 switch (getSubKind()) {
294 case nonloc::ConcreteIntKind
: {
295 const nonloc::ConcreteInt
& C
= *cast
<nonloc::ConcreteInt
>(this);
296 if (C
.getValue().isUnsigned())
297 os
<< C
.getValue().getZExtValue();
299 os
<< C
.getValue().getSExtValue();
300 os
<< ' ' << (C
.getValue().isUnsigned() ? 'U' : 'S')
301 << C
.getValue().getBitWidth() << 'b';
304 case nonloc::SymbolValKind
:
305 os
<< '$' << cast
<nonloc::SymbolVal
>(this)->getSymbol();
307 case nonloc::SymExprValKind
: {
308 const nonloc::SymExprVal
& C
= *cast
<nonloc::SymExprVal
>(this);
309 const SymExpr
*SE
= C
.getSymbolicExpression();
313 case nonloc::LocAsIntegerKind
: {
314 const nonloc::LocAsInteger
& C
= *cast
<nonloc::LocAsInteger
>(this);
315 os
<< C
.getLoc() << " [as " << C
.getNumBits() << " bit integer]";
318 case nonloc::CompoundValKind
: {
319 const nonloc::CompoundVal
& C
= *cast
<nonloc::CompoundVal
>(this);
320 os
<< "compoundVal{";
322 for (nonloc::CompoundVal::iterator I
=C
.begin(), E
=C
.end(); I
!=E
; ++I
) {
324 os
<< ' '; first
= false;
329 (*I
).dumpToStream(os
);
334 case nonloc::LazyCompoundValKind
: {
335 const nonloc::LazyCompoundVal
&C
= *cast
<nonloc::LazyCompoundVal
>(this);
336 os
<< "lazyCompoundVal{" << const_cast<void *>(C
.getStore())
337 << ',' << C
.getRegion()
342 assert (false && "Pretty-printed not implemented for this NonLoc.");
347 void Loc::dumpToStream(llvm::raw_ostream
& os
) const {
348 switch (getSubKind()) {
349 case loc::ConcreteIntKind
:
350 os
<< cast
<loc::ConcreteInt
>(this)->getValue().getZExtValue() << " (Loc)";
352 case loc::GotoLabelKind
:
353 os
<< "&&" << cast
<loc::GotoLabel
>(this)->getLabel()->getID()->getName();
355 case loc::MemRegionKind
:
356 os
<< '&' << cast
<loc::MemRegionVal
>(this)->getRegion()->getString();
358 case loc::ObjCPropRefKind
: {
359 const ObjCPropertyRefExpr
*E
= cast
<loc::ObjCPropRef
>(this)->getPropRefExpr();
361 if (E
->isSuperReceiver())
363 else if (E
->getBase())
366 if (E
->isImplicitProperty())
367 os
<< E
->getImplicitPropertyGetter()->getSelector().getAsString();
369 os
<< E
->getExplicitProperty()->getName();
375 assert(false && "Pretty-printing not implemented for this Loc.");