blob: 4b7d6054cd87778816813de9eb3f0491bb83ee15 [file] [log] [blame]
//== APSIntType.h - Simple record of the type of APSInts --------*- C++ -*--==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H
#include "llvm/ADT/APSInt.h"
#include <tuple>
namespace clang {
namespace ento {
/// 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; }
/// 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 an all-zero value for this type.
llvm::APSInt getZeroValue() const LLVM_READONLY {
return llvm::APSInt(BitWidth, IsUnsigned);
}
/// 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);
}
llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY {
return (llvm::APSInt(BitWidth, IsUnsigned) = RawValue);
}
/// Used to classify whether a value is representable using this type.
///
/// \see testInRange
enum RangeTestResultKind {
RTR_Below = -1, ///< Value is less than the minimum representable value.
RTR_Within = 0, ///< Value is representable using this type.
RTR_Above = 1 ///< Value is greater than the maximum representable value.
};
/// Tests whether a given value is losslessly representable using this type.
///
/// \param Val The value to test.
/// \param AllowMixedSign Whether or not to allow signedness conversions.
/// This determines whether -1s8 is considered in range
/// for 'unsigned char' (u8).
RangeTestResultKind testInRange(const llvm::APSInt &Val,
bool AllowMixedSign) const LLVM_READONLY;
bool operator==(const APSIntType &Other) const {
return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned;
}
/// 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 {
return std::tie(BitWidth, IsUnsigned) <
std::tie(Other.BitWidth, Other.IsUnsigned);
}
};
} // end ento namespace
} // end clang namespace
#endif