1 | //== APSIntType.h - Simple record of the type of APSInts --------*- C++ -*--==// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H |
10 | #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSINTTYPE_H |
11 | |
12 | #include "llvm/ADT/APSInt.h" |
13 | #include <tuple> |
14 | |
15 | namespace clang { |
16 | namespace ento { |
17 | |
18 | /// A record of the "type" of an APSInt, used for conversions. |
19 | class APSIntType { |
20 | uint32_t BitWidth; |
21 | bool IsUnsigned; |
22 | |
23 | public: |
24 | constexpr APSIntType(uint32_t Width, bool Unsigned) |
25 | : BitWidth(Width), IsUnsigned(Unsigned) {} |
26 | |
27 | /* implicit */ APSIntType(const llvm::APSInt &Value) |
28 | : BitWidth(Value.getBitWidth()), IsUnsigned(Value.isUnsigned()) {} |
29 | |
30 | uint32_t getBitWidth() const { return BitWidth; } |
31 | bool isUnsigned() const { return IsUnsigned; } |
32 | |
33 | /// Convert a given APSInt, in place, to match this type. |
34 | /// |
35 | /// This behaves like a C cast: converting 255u8 (0xFF) to s16 gives |
36 | /// 255 (0x00FF), and converting -1s8 (0xFF) to u16 gives 65535 (0xFFFF). |
37 | void apply(llvm::APSInt &Value) const { |
38 | // Note the order here. We extend first to preserve the sign, if this value |
39 | // is signed, /then/ match the signedness of the result type. |
40 | Value = Value.extOrTrunc(width: BitWidth); |
41 | Value.setIsUnsigned(IsUnsigned); |
42 | } |
43 | |
44 | /// Convert and return a new APSInt with the given value, but this |
45 | /// type's bit width and signedness. |
46 | /// |
47 | /// \see apply |
48 | llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY { |
49 | llvm::APSInt Result(Value, Value.isUnsigned()); |
50 | apply(Value&: Result); |
51 | return Result; |
52 | } |
53 | |
54 | /// Returns an all-zero value for this type. |
55 | llvm::APSInt getZeroValue() const LLVM_READONLY { |
56 | return llvm::APSInt(BitWidth, IsUnsigned); |
57 | } |
58 | |
59 | /// Returns the minimum value for this type. |
60 | llvm::APSInt getMinValue() const LLVM_READONLY { |
61 | return llvm::APSInt::getMinValue(numBits: BitWidth, Unsigned: IsUnsigned); |
62 | } |
63 | |
64 | /// Returns the maximum value for this type. |
65 | llvm::APSInt getMaxValue() const LLVM_READONLY { |
66 | return llvm::APSInt::getMaxValue(numBits: BitWidth, Unsigned: IsUnsigned); |
67 | } |
68 | |
69 | llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY { |
70 | return (llvm::APSInt(BitWidth, IsUnsigned) = RawValue); |
71 | } |
72 | |
73 | /// Used to classify whether a value is representable using this type. |
74 | /// |
75 | /// \see testInRange |
76 | enum RangeTestResultKind { |
77 | RTR_Below = -1, ///< Value is less than the minimum representable value. |
78 | RTR_Within = 0, ///< Value is representable using this type. |
79 | RTR_Above = 1 ///< Value is greater than the maximum representable value. |
80 | }; |
81 | |
82 | /// Tests whether a given value is losslessly representable using this type. |
83 | /// |
84 | /// \param Val The value to test. |
85 | /// \param AllowMixedSign Whether or not to allow signedness conversions. |
86 | /// This determines whether -1s8 is considered in range |
87 | /// for 'unsigned char' (u8). |
88 | RangeTestResultKind testInRange(const llvm::APSInt &Val, |
89 | bool AllowMixedSign) const LLVM_READONLY; |
90 | |
91 | bool operator==(const APSIntType &Other) const { |
92 | return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned; |
93 | } |
94 | |
95 | /// Provide an ordering for finding a common conversion type. |
96 | /// |
97 | /// Unsigned integers are considered to be better conversion types than |
98 | /// signed integers of the same width. |
99 | bool operator<(const APSIntType &Other) const { |
100 | return std::tie(args: BitWidth, args: IsUnsigned) < |
101 | std::tie(args: Other.BitWidth, args: Other.IsUnsigned); |
102 | } |
103 | }; |
104 | |
105 | } // end ento namespace |
106 | } // end clang namespace |
107 | |
108 | #endif |
109 | |