]> granicus.if.org Git - clang/commitdiff
[analyzer] Add an abstraction for the bit width and signedness of an APSInt. No funct...
authorJordy Rose <jediknil@belkadan.com>
Tue, 8 May 2012 03:26:58 +0000 (03:26 +0000)
committerJordy Rose <jediknil@belkadan.com>
Tue, 8 May 2012 03:26:58 +0000 (03:26 +0000)
There are more parts of the analyzer that could use the convenience of APSIntType, particularly the constraint engine, but that needs a fair amount of rewriting to handle mixed-type constraints anyway.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156360 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h [new file with mode: 0644]
include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp

diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
new file mode 100644 (file)
index 0000000..dcb7779
--- /dev/null
@@ -0,0 +1,86 @@
+//== APSIntType.h - Simple record of the type of APSInts --------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_CORE_APSINTTYPE_H
+#define LLVM_CLANG_SA_CORE_APSINTTYPE_H
+
+#include "llvm/ADT/APSInt.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief A record of the "type" of an APSInt, used for conversions.
+class APSIntType {
+  uint32_t BitWidth;
+  bool IsUnsigned;
+
+public:
+  APSIntType(uint32_t Width, bool Unsigned)
+    : BitWidth(Width), IsUnsigned(Unsigned) {}
+
+  /* implicit */ APSIntType(const llvm::APSInt &Value)
+    : BitWidth(Value.getBitWidth()), IsUnsigned(Value.isUnsigned()) {}
+
+  uint32_t getBitWidth() const { return BitWidth; }
+  bool isUnsigned() const { return IsUnsigned; }
+
+  /// \brief Convert a given APSInt, in place, to match this type.
+  ///
+  /// This behaves like a C cast: converting 255u8 (0xFF) to s16 gives
+  /// 255 (0x00FF), and converting -1s8 (0xFF) to u16 gives 65535 (0xFFFF).
+  void apply(llvm::APSInt &Value) const {
+    // Note the order here. We extend first to preserve the sign, if this value
+    // is signed, /then/ match the signedness of the result type.
+    Value = Value.extOrTrunc(BitWidth);
+    Value.setIsUnsigned(IsUnsigned);
+  }
+
+  /// Convert and return a new APSInt with the given value, but this
+  /// type's bit width and signedness.
+  ///
+  /// \see apply
+  llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY {
+    llvm::APSInt Result(Value, Value.isUnsigned());
+    apply(Result);
+    return Result;
+  }
+
+  /// Returns the minimum value for this type.
+  llvm::APSInt getMinValue() const LLVM_READONLY {
+    return llvm::APSInt::getMinValue(BitWidth, IsUnsigned);
+  }
+
+  /// Returns the maximum value for this type.
+  llvm::APSInt getMaxValue() const LLVM_READONLY {
+    return llvm::APSInt::getMaxValue(BitWidth, IsUnsigned);
+  }
+
+  bool operator==(const APSIntType &Other) const {
+    return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned;
+  }
+
+  /// \brief Provide an ordering for finding a common conversion type.
+  ///
+  /// Unsigned integers are considered to be better conversion types than
+  /// signed integers of the same width.
+  bool operator<(const APSIntType &Other) const {
+    if (BitWidth < Other.BitWidth)
+      return true;
+    if (BitWidth > Other.BitWidth)
+      return false;
+    if (!IsUnsigned && Other.IsUnsigned)
+      return true;
+    return false;
+  }
+};
+    
+} // end ento namespace
+} // end clang namespace
+
+#endif
index 9a699f9b7c9c8583a44cf17c6919c08b973bc96a..b4a9de76f4d140585157362b7f4b3d34cef05b40 100644 (file)
@@ -16,6 +16,7 @@
 #ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
 #define LLVM_CLANG_GR_BASICVALUEFACTORY_H
 
+#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 
@@ -86,28 +87,30 @@ public:
   const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
   const llvm::APSInt& getValue(uint64_t X, QualType T);
 
+  /// Returns the type of the APSInt used to store values of the given QualType.
+  APSIntType getAPSIntType(QualType T) const {
+    assert(T->isIntegerType() || Loc::isLocType(T));
+    return APSIntType(Ctx.getTypeSize(T),
+                      !T->isSignedIntegerOrEnumerationType());
+  }
+
   /// Convert - Create a new persistent APSInt with the same value as 'From'
   ///  but with the bitwidth and signedness of 'To'.
   const llvm::APSInt &Convert(const llvm::APSInt& To,
                               const llvm::APSInt& From) {
-
-    if (To.isUnsigned() == From.isUnsigned() &&
-        To.getBitWidth() == From.getBitWidth())
+    APSIntType TargetType(To);
+    if (TargetType == APSIntType(From))
       return From;
 
-    return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned());
+    return getValue(TargetType.convert(From));
   }
   
   const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) {
-    assert(T->isIntegerType() || Loc::isLocType(T));
-    unsigned bitwidth = Ctx.getTypeSize(T);
-    bool isUnsigned 
-      = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
-    
-    if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth())
+    APSIntType TargetType = getAPSIntType(T);
+    if (TargetType == APSIntType(From))
       return From;
     
-    return getValue(From.getSExtValue(), bitwidth, isUnsigned);
+    return getValue(TargetType.convert(From));
   }
 
   const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
@@ -116,25 +119,19 @@ public:
   }
 
   inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
-    return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned()));
+    return getValue(APSIntType(v).getMaxValue());
   }
 
   inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
-    return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned()));
+    return getValue(APSIntType(v).getMinValue());
   }
 
   inline const llvm::APSInt& getMaxValue(QualType T) {
-    assert(T->isIntegerType() || Loc::isLocType(T));
-    bool isUnsigned 
-      = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
-    return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
+    return getValue(getAPSIntType(T).getMaxValue());
   }
 
   inline const llvm::APSInt& getMinValue(QualType T) {
-    assert(T->isIntegerType() || Loc::isLocType(T));
-    bool isUnsigned 
-      = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
-    return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
+    return getValue(getAPSIntType(T).getMinValue());
   }
 
   inline const llvm::APSInt& Add1(const llvm::APSInt& V) {
index 9c5590bf1ce0841a8d1008728ee25eac44060c15..2e37be0c6b5e270158e2a1f3e51243d9e6699727 100644 (file)
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 
@@ -106,9 +107,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
     return UnknownVal();
 
   llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
-  i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() || 
-                  Loc::isLocType(castTy));
-  i = i.extOrTrunc(Context.getTypeSize(castTy));
+  BasicVals.getAPSIntType(castTy).apply(i);
 
   if (isLocType)
     return makeIntLocVal(i);
@@ -139,9 +138,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
       return makeLocAsInteger(val, BitWidth);
 
     llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
-    i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() || 
-                    Loc::isLocType(castTy));
-    i = i.extOrTrunc(BitWidth);
+    BasicVals.getAPSIntType(castTy).apply(i);
     return makeIntVal(i);
   }
 
@@ -341,8 +338,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
         case nonloc::ConcreteIntKind: {
           // Transform the integer into a location and compare.
           llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
-          i.setIsUnsigned(true);
-          i = i.extOrTrunc(Context.getTypeSize(Context.VoidPtrTy));
+          BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
           return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
         }
         default:
@@ -365,23 +361,16 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
         llvm::APSInt RHSValue = *KnownRHSValue;
         if (BinaryOperator::isComparisonOp(op)) {
           // We're looking for a type big enough to compare the two values.
-          uint32_t LeftWidth = LHSValue.getBitWidth();
-          uint32_t RightWidth = RHSValue.getBitWidth();
-
-          // Based on the conversion rules of [C99 6.3.1.8] and the example
-          // in SemaExpr's handleIntegerConversion().
-          if (LeftWidth > RightWidth)
-            RHSValue = RHSValue.extend(LeftWidth);
-          else if (LeftWidth < RightWidth)
-            LHSValue = LHSValue.extend(RightWidth);
-          else if (LHSValue.isUnsigned() != RHSValue.isUnsigned()) {
-            LHSValue.setIsUnsigned(true);
-            RHSValue.setIsUnsigned(true);
-          }
+          // FIXME: This is not correct. char + short will result in a promotion
+          // to int. Unfortunately we have lost types by this point.
+          APSIntType CompareType = std::max(APSIntType(LHSValue),
+                                            APSIntType(RHSValue));
+          CompareType.apply(LHSValue);
+          CompareType.apply(RHSValue);
         } else if (!BinaryOperator::isShiftOp(op)) {
-          // FIXME: These values don't need to be persistent.
-          LHSValue = BasicVals.Convert(resultTy, LHSValue);
-          RHSValue = BasicVals.Convert(resultTy, RHSValue);          
+          APSIntType IntType = BasicVals.getAPSIntType(resultTy);
+          IntType.apply(LHSValue);
+          IntType.apply(RHSValue);
         }
 
         const llvm::APSInt *Result =
@@ -490,12 +479,9 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
               // (such as x+1U+2LL). The rules for implicit conversions should
               // choose a reasonable type to preserve the expression, and will
               // at least match how the value is going to be used.
-
-              // FIXME: These values don't need to be persistent.
-              const llvm::APSInt &first =
-                  BasicVals.Convert(resultTy, symIntExpr->getRHS());
-              const llvm::APSInt &second =
-                  BasicVals.Convert(resultTy, *RHSValue);
+              APSIntType IntType = BasicVals.getAPSIntType(resultTy);
+              const llvm::APSInt &first = IntType.convert(symIntExpr->getRHS());
+              const llvm::APSInt &second = IntType.convert(*RHSValue);
 
               const llvm::APSInt *newRHS;
               if (lop == op)