clang API Documentation

RangeConstraintManager.cpp
Go to the documentation of this file.
00001 //== RangeConstraintManager.cpp - Manage range constraints.------*- C++ -*--==//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines RangeConstraintManager, a class that tracks simple
00011 //  equality and inequality constraints on symbolic values of ProgramState.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "SimpleConstraintManager.h"
00016 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
00017 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
00018 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
00019 #include "llvm/ADT/FoldingSet.h"
00020 #include "llvm/ADT/ImmutableSet.h"
00021 #include "llvm/Support/Debug.h"
00022 #include "llvm/Support/raw_ostream.h"
00023 
00024 using namespace clang;
00025 using namespace ento;
00026 
00027 /// A Range represents the closed range [from, to].  The caller must
00028 /// guarantee that from <= to.  Note that Range is immutable, so as not
00029 /// to subvert RangeSet's immutability.
00030 namespace {
00031 class Range : public std::pair<const llvm::APSInt*,
00032                                                 const llvm::APSInt*> {
00033 public:
00034   Range(const llvm::APSInt &from, const llvm::APSInt &to)
00035     : std::pair<const llvm::APSInt*, const llvm::APSInt*>(&from, &to) {
00036     assert(from <= to);
00037   }
00038   bool Includes(const llvm::APSInt &v) const {
00039     return *first <= v && v <= *second;
00040   }
00041   const llvm::APSInt &From() const {
00042     return *first;
00043   }
00044   const llvm::APSInt &To() const {
00045     return *second;
00046   }
00047   const llvm::APSInt *getConcreteValue() const {
00048     return &From() == &To() ? &From() : NULL;
00049   }
00050 
00051   void Profile(llvm::FoldingSetNodeID &ID) const {
00052     ID.AddPointer(&From());
00053     ID.AddPointer(&To());
00054   }
00055 };
00056 
00057 
00058 class RangeTrait : public llvm::ImutContainerInfo<Range> {
00059 public:
00060   // When comparing if one Range is less than another, we should compare
00061   // the actual APSInt values instead of their pointers.  This keeps the order
00062   // consistent (instead of comparing by pointer values) and can potentially
00063   // be used to speed up some of the operations in RangeSet.
00064   static inline bool isLess(key_type_ref lhs, key_type_ref rhs) {
00065     return *lhs.first < *rhs.first || (!(*rhs.first < *lhs.first) &&
00066                                        *lhs.second < *rhs.second);
00067   }
00068 };
00069 
00070 /// RangeSet contains a set of ranges. If the set is empty, then
00071 ///  there the value of a symbol is overly constrained and there are no
00072 ///  possible values for that symbol.
00073 class RangeSet {
00074   typedef llvm::ImmutableSet<Range, RangeTrait> PrimRangeSet;
00075   PrimRangeSet ranges; // no need to make const, since it is an
00076                        // ImmutableSet - this allows default operator=
00077                        // to work.
00078 public:
00079   typedef PrimRangeSet::Factory Factory;
00080   typedef PrimRangeSet::iterator iterator;
00081 
00082   RangeSet(PrimRangeSet RS) : ranges(RS) {}
00083 
00084   iterator begin() const { return ranges.begin(); }
00085   iterator end() const { return ranges.end(); }
00086 
00087   bool isEmpty() const { return ranges.isEmpty(); }
00088 
00089   /// Construct a new RangeSet representing '{ [from, to] }'.
00090   RangeSet(Factory &F, const llvm::APSInt &from, const llvm::APSInt &to)
00091     : ranges(F.add(F.getEmptySet(), Range(from, to))) {}
00092 
00093   /// Profile - Generates a hash profile of this RangeSet for use
00094   ///  by FoldingSet.
00095   void Profile(llvm::FoldingSetNodeID &ID) const { ranges.Profile(ID); }
00096 
00097   /// getConcreteValue - If a symbol is contrained to equal a specific integer
00098   ///  constant then this method returns that value.  Otherwise, it returns
00099   ///  NULL.
00100   const llvm::APSInt* getConcreteValue() const {
00101     return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : 0;
00102   }
00103 
00104 private:
00105   void IntersectInRange(BasicValueFactory &BV, Factory &F,
00106                         const llvm::APSInt &Lower,
00107                         const llvm::APSInt &Upper,
00108                         PrimRangeSet &newRanges,
00109                         PrimRangeSet::iterator &i,
00110                         PrimRangeSet::iterator &e) const {
00111     // There are six cases for each range R in the set:
00112     //   1. R is entirely before the intersection range.
00113     //   2. R is entirely after the intersection range.
00114     //   3. R contains the entire intersection range.
00115     //   4. R starts before the intersection range and ends in the middle.
00116     //   5. R starts in the middle of the intersection range and ends after it.
00117     //   6. R is entirely contained in the intersection range.
00118     // These correspond to each of the conditions below.
00119     for (/* i = begin(), e = end() */; i != e; ++i) {
00120       if (i->To() < Lower) {
00121         continue;
00122       }
00123       if (i->From() > Upper) {
00124         break;
00125       }
00126 
00127       if (i->Includes(Lower)) {
00128         if (i->Includes(Upper)) {
00129           newRanges = F.add(newRanges, Range(BV.getValue(Lower),
00130                                              BV.getValue(Upper)));
00131           break;
00132         } else
00133           newRanges = F.add(newRanges, Range(BV.getValue(Lower), i->To()));
00134       } else {
00135         if (i->Includes(Upper)) {
00136           newRanges = F.add(newRanges, Range(i->From(), BV.getValue(Upper)));
00137           break;
00138         } else
00139           newRanges = F.add(newRanges, *i);
00140       }
00141     }
00142   }
00143 
00144   const llvm::APSInt &getMinValue() const {
00145     assert(!isEmpty());
00146     return ranges.begin()->From();
00147   }
00148 
00149   bool pin(llvm::APSInt &Lower, llvm::APSInt &Upper) const {
00150     // This function has nine cases, the cartesian product of range-testing
00151     // both the upper and lower bounds against the symbol's type.
00152     // Each case requires a different pinning operation.
00153     // The function returns false if the described range is entirely outside
00154     // the range of values for the associated symbol.
00155     APSIntType Type(getMinValue());
00156     APSIntType::RangeTestResultKind LowerTest = Type.testInRange(Lower, true);
00157     APSIntType::RangeTestResultKind UpperTest = Type.testInRange(Upper, true);
00158 
00159     switch (LowerTest) {
00160     case APSIntType::RTR_Below:
00161       switch (UpperTest) {
00162       case APSIntType::RTR_Below:
00163         // The entire range is outside the symbol's set of possible values.
00164         // If this is a conventionally-ordered range, the state is infeasible.
00165         if (Lower < Upper)
00166           return false;
00167 
00168         // However, if the range wraps around, it spans all possible values.
00169         Lower = Type.getMinValue();
00170         Upper = Type.getMaxValue();
00171         break;
00172       case APSIntType::RTR_Within:
00173         // The range starts below what's possible but ends within it. Pin.
00174         Lower = Type.getMinValue();
00175         Type.apply(Upper);
00176         break;
00177       case APSIntType::RTR_Above:
00178         // The range spans all possible values for the symbol. Pin.
00179         Lower = Type.getMinValue();
00180         Upper = Type.getMaxValue();
00181         break;
00182       }
00183       break;
00184     case APSIntType::RTR_Within:
00185       switch (UpperTest) {
00186       case APSIntType::RTR_Below:
00187         // The range wraps around, but all lower values are not possible.
00188         Type.apply(Lower);
00189         Upper = Type.getMaxValue();
00190         break;
00191       case APSIntType::RTR_Within:
00192         // The range may or may not wrap around, but both limits are valid.
00193         Type.apply(Lower);
00194         Type.apply(Upper);
00195         break;
00196       case APSIntType::RTR_Above:
00197         // The range starts within what's possible but ends above it. Pin.
00198         Type.apply(Lower);
00199         Upper = Type.getMaxValue();
00200         break;
00201       }
00202       break;
00203     case APSIntType::RTR_Above:
00204       switch (UpperTest) {
00205       case APSIntType::RTR_Below:
00206         // The range wraps but is outside the symbol's set of possible values.
00207         return false;
00208       case APSIntType::RTR_Within:
00209         // The range starts above what's possible but ends within it (wrap).
00210         Lower = Type.getMinValue();
00211         Type.apply(Upper);
00212         break;
00213       case APSIntType::RTR_Above:
00214         // The entire range is outside the symbol's set of possible values.
00215         // If this is a conventionally-ordered range, the state is infeasible.
00216         if (Lower < Upper)
00217           return false;
00218 
00219         // However, if the range wraps around, it spans all possible values.
00220         Lower = Type.getMinValue();
00221         Upper = Type.getMaxValue();
00222         break;
00223       }
00224       break;
00225     }
00226 
00227     return true;
00228   }
00229 
00230 public:
00231   // Returns a set containing the values in the receiving set, intersected with
00232   // the closed range [Lower, Upper]. Unlike the Range type, this range uses
00233   // modular arithmetic, corresponding to the common treatment of C integer
00234   // overflow. Thus, if the Lower bound is greater than the Upper bound, the
00235   // range is taken to wrap around. This is equivalent to taking the
00236   // intersection with the two ranges [Min, Upper] and [Lower, Max],
00237   // or, alternatively, /removing/ all integers between Upper and Lower.
00238   RangeSet Intersect(BasicValueFactory &BV, Factory &F,
00239                      llvm::APSInt Lower, llvm::APSInt Upper) const {
00240     if (!pin(Lower, Upper))
00241       return F.getEmptySet();
00242 
00243     PrimRangeSet newRanges = F.getEmptySet();
00244 
00245     PrimRangeSet::iterator i = begin(), e = end();
00246     if (Lower <= Upper)
00247       IntersectInRange(BV, F, Lower, Upper, newRanges, i, e);
00248     else {
00249       // The order of the next two statements is important!
00250       // IntersectInRange() does not reset the iteration state for i and e.
00251       // Therefore, the lower range most be handled first.
00252       IntersectInRange(BV, F, BV.getMinValue(Upper), Upper, newRanges, i, e);
00253       IntersectInRange(BV, F, Lower, BV.getMaxValue(Lower), newRanges, i, e);
00254     }
00255 
00256     return newRanges;
00257   }
00258 
00259   void print(raw_ostream &os) const {
00260     bool isFirst = true;
00261     os << "{ ";
00262     for (iterator i = begin(), e = end(); i != e; ++i) {
00263       if (isFirst)
00264         isFirst = false;
00265       else
00266         os << ", ";
00267 
00268       os << '[' << i->From().toString(10) << ", " << i->To().toString(10)
00269          << ']';
00270     }
00271     os << " }";
00272   }
00273 
00274   bool operator==(const RangeSet &other) const {
00275     return ranges == other.ranges;
00276   }
00277 };
00278 } // end anonymous namespace
00279 
00280 REGISTER_TRAIT_WITH_PROGRAMSTATE(ConstraintRange,
00281                                  CLANG_ENTO_PROGRAMSTATE_MAP(SymbolRef,
00282                                                              RangeSet))
00283 
00284 namespace {
00285 class RangeConstraintManager : public SimpleConstraintManager{
00286   RangeSet GetRange(ProgramStateRef state, SymbolRef sym);
00287 public:
00288   RangeConstraintManager(SubEngine *subengine, SValBuilder &SVB)
00289     : SimpleConstraintManager(subengine, SVB) {}
00290 
00291   ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym,
00292                              const llvm::APSInt& Int,
00293                              const llvm::APSInt& Adjustment);
00294 
00295   ProgramStateRef assumeSymEQ(ProgramStateRef state, SymbolRef sym,
00296                              const llvm::APSInt& Int,
00297                              const llvm::APSInt& Adjustment);
00298 
00299   ProgramStateRef assumeSymLT(ProgramStateRef state, SymbolRef sym,
00300                              const llvm::APSInt& Int,
00301                              const llvm::APSInt& Adjustment);
00302 
00303   ProgramStateRef assumeSymGT(ProgramStateRef state, SymbolRef sym,
00304                              const llvm::APSInt& Int,
00305                              const llvm::APSInt& Adjustment);
00306 
00307   ProgramStateRef assumeSymGE(ProgramStateRef state, SymbolRef sym,
00308                              const llvm::APSInt& Int,
00309                              const llvm::APSInt& Adjustment);
00310 
00311   ProgramStateRef assumeSymLE(ProgramStateRef state, SymbolRef sym,
00312                              const llvm::APSInt& Int,
00313                              const llvm::APSInt& Adjustment);
00314 
00315   const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const;
00316   ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
00317 
00318   ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper);
00319 
00320   void print(ProgramStateRef St, raw_ostream &Out,
00321              const char* nl, const char *sep);
00322 
00323 private:
00324   RangeSet::Factory F;
00325 };
00326 
00327 } // end anonymous namespace
00328 
00329 ConstraintManager *
00330 ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
00331   return new RangeConstraintManager(Eng, StMgr.getSValBuilder());
00332 }
00333 
00334 const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
00335                                                       SymbolRef sym) const {
00336   const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym);
00337   return T ? T->getConcreteValue() : NULL;
00338 }
00339 
00340 ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
00341                                                     SymbolRef Sym) {
00342   const RangeSet *Ranges = State->get<ConstraintRange>(Sym);
00343 
00344   // If we don't have any information about this symbol, it's underconstrained.
00345   if (!Ranges)
00346     return ConditionTruthVal();
00347 
00348   // If we have a concrete value, see if it's zero.
00349   if (const llvm::APSInt *Value = Ranges->getConcreteValue())
00350     return *Value == 0;
00351 
00352   BasicValueFactory &BV = getBasicVals();
00353   APSIntType IntType = BV.getAPSIntType(Sym->getType());
00354   llvm::APSInt Zero = IntType.getZeroValue();
00355 
00356   // Check if zero is in the set of possible values.
00357   if (Ranges->Intersect(BV, F, Zero, Zero).isEmpty())
00358     return false;
00359 
00360   // Zero is a possible value, but it is not the /only/ possible value.
00361   return ConditionTruthVal();
00362 }
00363 
00364 /// Scan all symbols referenced by the constraints. If the symbol is not alive
00365 /// as marked in LSymbols, mark it as dead in DSymbols.
00366 ProgramStateRef 
00367 RangeConstraintManager::removeDeadBindings(ProgramStateRef state,
00368                                            SymbolReaper& SymReaper) {
00369 
00370   ConstraintRangeTy CR = state->get<ConstraintRange>();
00371   ConstraintRangeTy::Factory& CRFactory = state->get_context<ConstraintRange>();
00372 
00373   for (ConstraintRangeTy::iterator I = CR.begin(), E = CR.end(); I != E; ++I) {
00374     SymbolRef sym = I.getKey();
00375     if (SymReaper.maybeDead(sym))
00376       CR = CRFactory.remove(CR, sym);
00377   }
00378 
00379   return state->set<ConstraintRange>(CR);
00380 }
00381 
00382 RangeSet
00383 RangeConstraintManager::GetRange(ProgramStateRef state, SymbolRef sym) {
00384   if (ConstraintRangeTy::data_type* V = state->get<ConstraintRange>(sym))
00385     return *V;
00386 
00387   // Lazily generate a new RangeSet representing all possible values for the
00388   // given symbol type.
00389   BasicValueFactory &BV = getBasicVals();
00390   QualType T = sym->getType();
00391 
00392   RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T));
00393 
00394   // Special case: references are known to be non-zero.
00395   if (T->isReferenceType()) {
00396     APSIntType IntType = BV.getAPSIntType(T);
00397     Result = Result.Intersect(BV, F, ++IntType.getZeroValue(),
00398                                      --IntType.getZeroValue());
00399   }
00400 
00401   return Result;
00402 }
00403 
00404 //===------------------------------------------------------------------------===
00405 // assumeSymX methods: public interface for RangeConstraintManager.
00406 //===------------------------------------------------------------------------===/
00407 
00408 // The syntax for ranges below is mathematical, using [x, y] for closed ranges
00409 // and (x, y) for open ranges. These ranges are modular, corresponding with
00410 // a common treatment of C integer overflow. This means that these methods
00411 // do not have to worry about overflow; RangeSet::Intersect can handle such a
00412 // "wraparound" range.
00413 // As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1,
00414 // UINT_MAX, 0, 1, and 2.
00415 
00416 ProgramStateRef 
00417 RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
00418                                     const llvm::APSInt &Int,
00419                                     const llvm::APSInt &Adjustment) {
00420   // Before we do any real work, see if the value can even show up.
00421   APSIntType AdjustmentType(Adjustment);
00422   if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
00423     return St;
00424 
00425   llvm::APSInt Lower = AdjustmentType.convert(Int) - Adjustment;
00426   llvm::APSInt Upper = Lower;
00427   --Lower;
00428   ++Upper;
00429 
00430   // [Int-Adjustment+1, Int-Adjustment-1]
00431   // Notice that the lower bound is greater than the upper bound.
00432   RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Upper, Lower);
00433   return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
00434 }
00435 
00436 ProgramStateRef 
00437 RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
00438                                     const llvm::APSInt &Int,
00439                                     const llvm::APSInt &Adjustment) {
00440   // Before we do any real work, see if the value can even show up.
00441   APSIntType AdjustmentType(Adjustment);
00442   if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
00443     return NULL;
00444 
00445   // [Int-Adjustment, Int-Adjustment]
00446   llvm::APSInt AdjInt = AdjustmentType.convert(Int) - Adjustment;
00447   RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, AdjInt, AdjInt);
00448   return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
00449 }
00450 
00451 ProgramStateRef 
00452 RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
00453                                     const llvm::APSInt &Int,
00454                                     const llvm::APSInt &Adjustment) {
00455   // Before we do any real work, see if the value can even show up.
00456   APSIntType AdjustmentType(Adjustment);
00457   switch (AdjustmentType.testInRange(Int, true)) {
00458   case APSIntType::RTR_Below:
00459     return NULL;
00460   case APSIntType::RTR_Within:
00461     break;
00462   case APSIntType::RTR_Above:
00463     return St;
00464   }
00465 
00466   // Special case for Int == Min. This is always false.
00467   llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
00468   llvm::APSInt Min = AdjustmentType.getMinValue();
00469   if (ComparisonVal == Min)
00470     return NULL;
00471 
00472   llvm::APSInt Lower = Min-Adjustment;
00473   llvm::APSInt Upper = ComparisonVal-Adjustment;
00474   --Upper;
00475 
00476   RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
00477   return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
00478 }
00479 
00480 ProgramStateRef 
00481 RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
00482                                     const llvm::APSInt &Int,
00483                                     const llvm::APSInt &Adjustment) {
00484   // Before we do any real work, see if the value can even show up.
00485   APSIntType AdjustmentType(Adjustment);
00486   switch (AdjustmentType.testInRange(Int, true)) {
00487   case APSIntType::RTR_Below:
00488     return St;
00489   case APSIntType::RTR_Within:
00490     break;
00491   case APSIntType::RTR_Above:
00492     return NULL;
00493   }
00494 
00495   // Special case for Int == Max. This is always false.
00496   llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
00497   llvm::APSInt Max = AdjustmentType.getMaxValue();
00498   if (ComparisonVal == Max)
00499     return NULL;
00500 
00501   llvm::APSInt Lower = ComparisonVal-Adjustment;
00502   llvm::APSInt Upper = Max-Adjustment;
00503   ++Lower;
00504 
00505   RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
00506   return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
00507 }
00508 
00509 ProgramStateRef 
00510 RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
00511                                     const llvm::APSInt &Int,
00512                                     const llvm::APSInt &Adjustment) {
00513   // Before we do any real work, see if the value can even show up.
00514   APSIntType AdjustmentType(Adjustment);
00515   switch (AdjustmentType.testInRange(Int, true)) {
00516   case APSIntType::RTR_Below:
00517     return St;
00518   case APSIntType::RTR_Within:
00519     break;
00520   case APSIntType::RTR_Above:
00521     return NULL;
00522   }
00523 
00524   // Special case for Int == Min. This is always feasible.
00525   llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
00526   llvm::APSInt Min = AdjustmentType.getMinValue();
00527   if (ComparisonVal == Min)
00528     return St;
00529 
00530   llvm::APSInt Max = AdjustmentType.getMaxValue();
00531   llvm::APSInt Lower = ComparisonVal-Adjustment;
00532   llvm::APSInt Upper = Max-Adjustment;
00533 
00534   RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
00535   return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
00536 }
00537 
00538 ProgramStateRef 
00539 RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
00540                                     const llvm::APSInt &Int,
00541                                     const llvm::APSInt &Adjustment) {
00542   // Before we do any real work, see if the value can even show up.
00543   APSIntType AdjustmentType(Adjustment);
00544   switch (AdjustmentType.testInRange(Int, true)) {
00545   case APSIntType::RTR_Below:
00546     return NULL;
00547   case APSIntType::RTR_Within:
00548     break;
00549   case APSIntType::RTR_Above:
00550     return St;
00551   }
00552 
00553   // Special case for Int == Max. This is always feasible.
00554   llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
00555   llvm::APSInt Max = AdjustmentType.getMaxValue();
00556   if (ComparisonVal == Max)
00557     return St;
00558 
00559   llvm::APSInt Min = AdjustmentType.getMinValue();
00560   llvm::APSInt Lower = Min-Adjustment;
00561   llvm::APSInt Upper = ComparisonVal-Adjustment;
00562 
00563   RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
00564   return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
00565 }
00566 
00567 //===------------------------------------------------------------------------===
00568 // Pretty-printing.
00569 //===------------------------------------------------------------------------===/
00570 
00571 void RangeConstraintManager::print(ProgramStateRef St, raw_ostream &Out,
00572                                    const char* nl, const char *sep) {
00573 
00574   ConstraintRangeTy Ranges = St->get<ConstraintRange>();
00575 
00576   if (Ranges.isEmpty()) {
00577     Out << nl << sep << "Ranges are empty." << nl;
00578     return;
00579   }
00580 
00581   Out << nl << sep << "Ranges of symbol values:";
00582   for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){
00583     Out << nl << ' ' << I.getKey() << " : ";
00584     I.getData().print(Out);
00585   }
00586   Out << nl;
00587 }