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/Core/PathSensitive/ProgramState.h"
16 #include "clang/AST/ExprObjC.h"
17 #include "clang/Basic/IdentifierTable.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include "clang/AST/DeclCXX.h"
20 using namespace clang;
24 //===----------------------------------------------------------------------===//
25 // Symbol iteration within an SVal.
26 //===----------------------------------------------------------------------===//
29 //===----------------------------------------------------------------------===//
31 //===----------------------------------------------------------------------===//
33 bool SVal::hasConjuredSymbol() const {
34 if (Optional<nonloc::SymbolVal> SV = getAs<nonloc::SymbolVal>()) {
35 SymbolRef sym = SV->getSymbol();
36 if (isa<SymbolConjured>(sym))
40 if (Optional<loc::MemRegionVal> RV = getAs<loc::MemRegionVal>()) {
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 (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
54 const MemRegion* R = X->getRegion();
55 if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>())
56 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
60 if (auto X = getAs<nonloc::PointerToMember>()) {
61 if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(X->getDecl()))
67 /// \brief If this SVal is a location (subclasses Loc) and wraps a symbol,
68 /// return that SymbolRef. Otherwise return 0.
70 /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
71 /// region. If that is the case, gets the underlining region.
72 /// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic,
73 /// the first symbolic parent region is returned.
74 SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const {
75 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
76 if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
77 return X->getLoc().getAsLocSymbol();
79 if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
80 const MemRegion *R = X->getRegion();
81 if (const SymbolicRegion *SymR = IncludeBaseRegions ?
82 R->getSymbolicBase() :
83 dyn_cast<SymbolicRegion>(R->StripCasts()))
84 return SymR->getSymbol();
89 /// Get the symbol in the SVal or its base region.
90 SymbolRef SVal::getLocSymbolInBase() const {
91 Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
96 const MemRegion *R = X->getRegion();
98 while (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
99 if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SR))
100 return SymR->getSymbol();
102 R = SR->getSuperRegion();
108 // TODO: The next 3 functions have to be simplified.
110 /// \brief If this SVal wraps a symbol return that SymbolRef.
111 /// Otherwise, return 0.
113 /// Casts are ignored during lookup.
114 /// \param IncludeBaseRegions The boolean that controls whether the search
115 /// should continue to the base regions if the region is not symbolic.
116 SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const {
117 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
118 if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
119 return X->getSymbol();
121 return getAsLocSymbol(IncludeBaseRegions);
124 /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
125 /// return that expression. Otherwise return NULL.
126 const SymExpr *SVal::getAsSymbolicExpression() const {
127 if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
128 return X->getSymbol();
130 return getAsSymbol();
133 const SymExpr* SVal::getAsSymExpr() const {
134 const SymExpr* Sym = getAsSymbol();
136 Sym = getAsSymbolicExpression();
140 const MemRegion *SVal::getAsRegion() const {
141 if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
142 return X->getRegion();
144 if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
145 return X->getLoc().getAsRegion();
150 const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const {
151 const MemRegion *R = getRegion();
152 return R ? R->StripCasts(StripBaseCasts) : nullptr;
155 const void *nonloc::LazyCompoundVal::getStore() const {
156 return static_cast<const LazyCompoundValData*>(Data)->getStore();
159 const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const {
160 return static_cast<const LazyCompoundValData*>(Data)->getRegion();
163 const DeclaratorDecl *nonloc::PointerToMember::getDecl() const {
164 const auto PTMD = this->getPTMData();
168 const DeclaratorDecl *DD = nullptr;
169 if (PTMD.is<const DeclaratorDecl *>())
170 DD = PTMD.get<const DeclaratorDecl *>();
172 DD = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl();
177 //===----------------------------------------------------------------------===//
179 //===----------------------------------------------------------------------===//
181 nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
182 return getValue()->begin();
185 nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
186 return getValue()->end();
189 nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const {
190 const PTMDataType PTMD = getPTMData();
191 if (PTMD.is<const DeclaratorDecl *>())
192 return nonloc::PointerToMember::iterator();
193 return PTMD.get<const PointerToMemberData *>()->begin();
196 nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const {
197 const PTMDataType PTMD = getPTMData();
198 if (PTMD.is<const DeclaratorDecl *>())
199 return nonloc::PointerToMember::iterator();
200 return PTMD.get<const PointerToMemberData *>()->end();
203 //===----------------------------------------------------------------------===//
204 // Useful predicates.
205 //===----------------------------------------------------------------------===//
207 bool SVal::isConstant() const {
208 return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>();
211 bool SVal::isConstant(int I) const {
212 if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
213 return LV->getValue() == I;
214 if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
215 return NV->getValue() == I;
219 bool SVal::isZeroConstant() const {
220 return isConstant(0);
224 //===----------------------------------------------------------------------===//
225 // Transfer function dispatch for Non-Locs.
226 //===----------------------------------------------------------------------===//
228 SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder,
229 BinaryOperator::Opcode Op,
230 const nonloc::ConcreteInt& R) const {
231 const llvm::APSInt* X =
232 svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue());
235 return nonloc::ConcreteInt(*X);
237 return UndefinedVal();
241 nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const {
242 return svalBuilder.makeIntVal(~getValue());
246 nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const {
247 return svalBuilder.makeIntVal(-getValue());
250 //===----------------------------------------------------------------------===//
251 // Transfer function dispatch for Locs.
252 //===----------------------------------------------------------------------===//
254 SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
255 BinaryOperator::Opcode Op,
256 const loc::ConcreteInt& R) const {
258 assert(BinaryOperator::isComparisonOp(Op) || Op == BO_Sub);
260 const llvm::APSInt *X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
263 return nonloc::ConcreteInt(*X);
265 return UndefinedVal();
268 //===----------------------------------------------------------------------===//
270 //===----------------------------------------------------------------------===//
272 LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); }
274 void SVal::dumpToStream(raw_ostream &os) const {
275 switch (getBaseKind()) {
280 castAs<NonLoc>().dumpToStream(os);
283 castAs<Loc>().dumpToStream(os);
285 case UndefinedValKind:
291 void NonLoc::dumpToStream(raw_ostream &os) const {
292 switch (getSubKind()) {
293 case nonloc::ConcreteIntKind: {
294 const nonloc::ConcreteInt& C = castAs<nonloc::ConcreteInt>();
295 if (C.getValue().isUnsigned())
296 os << C.getValue().getZExtValue();
298 os << C.getValue().getSExtValue();
299 os << ' ' << (C.getValue().isUnsigned() ? 'U' : 'S')
300 << C.getValue().getBitWidth() << 'b';
303 case nonloc::SymbolValKind: {
304 os << castAs<nonloc::SymbolVal>().getSymbol();
307 case nonloc::LocAsIntegerKind: {
308 const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>();
309 os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
312 case nonloc::CompoundValKind: {
313 const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>();
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 = castAs<nonloc::LazyCompoundVal>();
330 os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
331 << ',' << C.getRegion()
335 case nonloc::PointerToMemberKind: {
336 os << "pointerToMember{";
337 const nonloc::PointerToMember &CastRes =
338 castAs<nonloc::PointerToMember>();
339 if (CastRes.getDecl())
340 os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|";
342 for (const auto &I : CastRes) {
344 os << ' '; first = false;
349 os << (*I).getType().getAsString();
356 assert (false && "Pretty-printed not implemented for this NonLoc.");
361 void Loc::dumpToStream(raw_ostream &os) const {
362 switch (getSubKind()) {
363 case loc::ConcreteIntKind:
364 os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)";
366 case loc::GotoLabelKind:
367 os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
369 case loc::MemRegionValKind:
370 os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
373 llvm_unreachable("Pretty-printing not implemented for this Loc.");