[analyzer] Let ConstraintManager subclasses provide a more efficient checkNull.
authorJordan Rose <jordan_rose@apple.com>
Wed, 31 Oct 2012 16:44:55 +0000 (16:44 +0000)
committerJordan Rose <jordan_rose@apple.com>
Wed, 31 Oct 2012 16:44:55 +0000 (16:44 +0000)
Previously, every call to a ConstraintManager's isNull would do a full
assumeDual to test feasibility. Now, ConstraintManagers can override
checkNull if they have a cheaper way to do the same thing.
RangeConstraintManager can do this in less than half the work.

<rdar://problem/12608209>

llvm-svn: 167138

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

index adb4d3a..9af59e4 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/Support/SaveAndRestore.h"
 
 namespace llvm {
 class APSInt;
@@ -97,8 +98,12 @@ public:
   virtual void EndPath(ProgramStateRef state) {}
   
   /// Convenience method to query the state to see if a symbol is null or
-  /// not null, or neither assumption can be made.
-  ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym);
+  /// not null, or if neither assumption can be made.
+  ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) {
+    llvm::SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false);
+
+    return checkNull(State, Sym);
+  }
 
 protected:
   /// A flag to indicate that clients should be notified of assumptions.
@@ -115,6 +120,10 @@ protected:
   ///  ExprEngine to determine if the value should be replaced with a
   ///  conjured symbolic value in order to recover some precision.
   virtual bool canReasonAbout(SVal X) const = 0;
+
+  /// Returns whether or not a symbol is known to be null ("true"), known to be
+  /// non-null ("false"), or may be either ("underconstrained"). 
+  virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
 };
 
 ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr,
index 5dd1392..4dec526 100644 (file)
@@ -12,7 +12,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "llvm/Support/SaveAndRestore.h"
 
 using namespace clang;
 using namespace ento;
@@ -26,13 +25,8 @@ static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
   return loc::MemRegionVal(R);
 }
 
-/// Convenience method to query the state to see if a symbol is null or
-/// not null, or neither assumption can be made.
-ConditionTruthVal ConstraintManager::isNull(ProgramStateRef State,
-                                            SymbolRef Sym) {
-  // Disable recursive notification of clients.
-  llvm::SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false);
-  
+ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State,
+                                               SymbolRef Sym) {  
   QualType Ty = Sym->getType();
   DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym)
                                      : nonloc::SymbolVal(Sym);
index a4c841e..467abd0 100644 (file)
@@ -324,6 +324,7 @@ public:
                              const llvm::APSInt& Adjustment);
 
   const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const;
+  ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
 
   ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper);
 
@@ -347,6 +348,30 @@ const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
   return T ? T->getConcreteValue() : NULL;
 }
 
+ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
+                                                    SymbolRef Sym) {
+  const RangeSet *Ranges = State->get<ConstraintRange>(Sym);
+
+  // If we don't have any information about this symbol, it's underconstrained.
+  if (!Ranges)
+    return ConditionTruthVal();
+
+  // If we have a concrete value, see if it's zero.
+  if (const llvm::APSInt *Value = Ranges->getConcreteValue())
+    return *Value == 0;
+
+  BasicValueFactory &BV = getBasicVals();
+  APSIntType IntType = BV.getAPSIntType(Sym->getType());
+  llvm::APSInt Zero = IntType.getZeroValue();
+
+  // Check if zero is in the set of possible values.
+  if (Ranges->Intersect(BV, F, Zero, Zero).isEmpty())
+    return false;
+
+  // Zero is a possible value, but it is not the /only/ possible value.
+  return ConditionTruthVal();
+}
+
 /// Scan all symbols referenced by the constraints. If the symbol is not alive
 /// as marked in LSymbols, mark it as dead in DSymbols.
 ProgramStateRef