1//===- unittests/StaticAnalyzer/RangeSetTest.cpp ----------------------===//
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#include "clang/Basic/Builtins.h"
10#include "clang/Basic/FileManager.h"
11#include "clang/Basic/SourceManager.h"
12#include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
13#include "clang/Tooling/Tooling.h"
14#include "llvm/ADT/APSInt.h"
15#include "llvm/Support/raw_ostream.h"
16#include "gtest/gtest.h"
17
18using namespace clang;
19using namespace ento;
20
21namespace clang {
22namespace ento {
23
24template <class RangeOrSet> static std::string toString(const RangeOrSet &Obj) {
25 std::string ObjRepresentation;
26 llvm::raw_string_ostream SS(ObjRepresentation);
27 Obj.dump(SS);
28 return SS.str();
29}
30LLVM_ATTRIBUTE_UNUSED static std::string toString(const llvm::APSInt &Point) {
31 return toString(I: Point, Radix: 10);
32}
33// We need it here for better fail diagnostics from gtest.
34LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS,
35 const RangeSet &Set) {
36 return OS << toString(Obj: Set);
37}
38// We need it here for better fail diagnostics from gtest.
39LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS,
40 const Range &R) {
41 return OS << toString(Obj: R);
42}
43LLVM_ATTRIBUTE_UNUSED static std::ostream &operator<<(std::ostream &OS,
44 APSIntType Ty) {
45 return OS << (Ty.isUnsigned() ? "u" : "s") << Ty.getBitWidth();
46}
47
48} // namespace ento
49} // namespace clang
50
51namespace {
52
53template <class T> constexpr bool is_signed_v = std::is_signed<T>::value;
54
55template <typename T> struct TestValues {
56 static constexpr T MIN = std::numeric_limits<T>::min();
57 static constexpr T MAX = std::numeric_limits<T>::max();
58 // MID is a value in the middle of the range
59 // which unary minus does not affect on,
60 // e.g. int8/int32(0), uint8(128), uint32(2147483648).
61 static constexpr T MID =
62 is_signed_v<T> ? 0 : ~(static_cast<T>(-1) / static_cast<T>(2));
63 static constexpr T A = MID - (MAX - MID) / 3 * 2;
64 static constexpr T B = MID - (MAX - MID) / 3;
65 static constexpr T C = -B;
66 static constexpr T D = -A;
67
68 static_assert(MIN < A && A < B && B < MID && MID < C && C < D && D < MAX,
69 "Values shall be in an ascending order");
70 // Clear bits in low bytes by the given amount.
71 template <T Value, size_t Bytes>
72 static constexpr T ClearLowBytes =
73 static_cast<T>(static_cast<uint64_t>(Value)
74 << ((Bytes >= CHAR_BIT) ? 0 : Bytes) * CHAR_BIT);
75
76 template <T Value, typename Base>
77 static constexpr T TruncZeroOf = ClearLowBytes<Value + 1, sizeof(Base)>;
78
79 // Random number with active bits in every byte. 0xAAAA'AAAA
80 static constexpr T XAAA = static_cast<T>(
81 0b10101010'10101010'10101010'10101010'10101010'10101010'10101010'10101010);
82 template <typename Base>
83 static constexpr T XAAATruncZeroOf = TruncZeroOf<XAAA, Base>; // 0xAAAA'AB00
84
85 // Random number with active bits in every byte. 0x5555'5555
86 static constexpr T X555 = static_cast<T>(
87 0b01010101'01010101'01010101'01010101'01010101'01010101'01010101'01010101);
88 template <typename Base>
89 static constexpr T X555TruncZeroOf = TruncZeroOf<X555, Base>; // 0x5555'5600
90
91// Silence 'warning C4309: 'initializing': truncation of constant value'
92// in RangeSetCastToPromotionConversionTest.
93#if defined(_MSC_VER) && !defined(__clang__)
94#pragma warning(push)
95#pragma warning(disable : 4309)
96#endif
97 // Numbers for ranges with the same bits in the lowest byte.
98 // 0xAAAA'AA2A
99 static constexpr T FromA = ClearLowBytes<XAAA, sizeof(T) - 1> + 42;
100 static constexpr T ToA = FromA + 2; // 0xAAAA'AA2C
101 // 0x5555'552A
102 static constexpr T FromB = ClearLowBytes<X555, sizeof(T) - 1> + 42;
103 static constexpr T ToB = FromB + 2; // 0x5555'552C
104
105#if defined(_MSC_VER) && !defined(__clang__)
106#pragma warning(pop)
107#endif
108};
109
110template <typename T>
111static constexpr APSIntType APSIntTy =
112 APSIntType(sizeof(T) * CHAR_BIT, !is_signed_v<T>);
113
114template <typename BaseType> class RangeSetTest : public testing::Test {
115public:
116 // Init block
117 std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCode(Code: "struct foo;");
118 ASTContext &Context = AST->getASTContext();
119 llvm::BumpPtrAllocator Arena;
120 BasicValueFactory BVF{Context, Arena};
121 RangeSet::Factory F{BVF};
122 // End init block
123
124 using Self = RangeSetTest<BaseType>;
125 template <typename T> using RawRangeT = std::pair<T, T>;
126 template <typename T>
127 using RawRangeSetT = std::initializer_list<RawRangeT<T>>;
128 using RawRange = RawRangeT<BaseType>;
129 using RawRangeSet = RawRangeSetT<BaseType>;
130
131 template <typename T> const llvm::APSInt &from(T X) {
132 static llvm::APSInt Int = APSIntTy<T>.getZeroValue();
133 Int = X;
134 return BVF.getValue(X: Int);
135 }
136
137 template <typename T> Range from(const RawRangeT<T> &Init) {
138 return Range(from(Init.first), from(Init.second));
139 }
140
141 template <typename T>
142 RangeSet from(RawRangeSetT<T> Init, APSIntType Ty = APSIntTy<BaseType>) {
143 RangeSet RangeSet = F.getEmptySet();
144 for (const auto &Raw : Init) {
145 RangeSet = F.add(RangeSet, from(Raw));
146 }
147 return RangeSet;
148 }
149
150 template <class F, class... RawArgTypes>
151 void wrap(F ActualFunction, RawArgTypes &&... Args) {
152 (this->*ActualFunction)(from(std::forward<RawArgTypes>(Args))...);
153 }
154
155 void checkNegateImpl(RangeSet Original, RangeSet Expected) {
156 RangeSet NegatedFromOriginal = F.negate(What: Original);
157 EXPECT_EQ(NegatedFromOriginal, Expected);
158 // Negate negated back and check with original.
159 RangeSet NegatedBackward = F.negate(What: NegatedFromOriginal);
160 EXPECT_EQ(NegatedBackward, Original);
161 }
162
163 void checkNegate(RawRangeSet RawOriginal, RawRangeSet RawExpected) {
164 wrap(&Self::checkNegateImpl, RawOriginal, RawExpected);
165 }
166
167 template <class PointOrSet>
168 void checkIntersectImpl(RangeSet LHS, PointOrSet RHS, RangeSet Expected) {
169 RangeSet Result = F.intersect(LHS, RHS);
170 EXPECT_EQ(Result, Expected)
171 << "while intersecting " << toString(Obj: LHS) << " and " << toString(RHS);
172 }
173
174 void checkIntersectRangeImpl(RangeSet LHS, const llvm::APSInt &Lower,
175 const llvm::APSInt &Upper, RangeSet Expected) {
176 RangeSet Result = F.intersect(What: LHS, Lower, Upper);
177 EXPECT_EQ(Result, Expected)
178 << "while intersecting " << toString(Obj: LHS) << " and [" << toString(Point: Lower)
179 << ", " << toString(Point: Upper) << "]";
180 }
181
182 void checkIntersect(RawRangeSet RawLHS, RawRangeSet RawRHS,
183 RawRangeSet RawExpected) {
184 wrap(&Self::checkIntersectImpl<RangeSet>, RawLHS, RawRHS, RawExpected);
185 }
186
187 void checkIntersect(RawRangeSet RawLHS, BaseType RawRHS,
188 RawRangeSet RawExpected) {
189 wrap(&Self::checkIntersectImpl<const llvm::APSInt &>, RawLHS, RawRHS,
190 RawExpected);
191 }
192
193 void checkIntersect(RawRangeSet RawLHS, BaseType RawLower, BaseType RawUpper,
194 RawRangeSet RawExpected) {
195 wrap(&Self::checkIntersectRangeImpl, RawLHS, RawLower, RawUpper,
196 RawExpected);
197 }
198
199 void checkContainsImpl(RangeSet LHS, const llvm::APSInt &RHS, bool Expected) {
200 bool Result = LHS.contains(Point: RHS);
201 EXPECT_EQ(Result, Expected)
202 << toString(Obj: LHS) << (Result ? " contains " : " doesn't contain ")
203 << toString(Point: RHS);
204 }
205
206 void checkContains(RawRangeSet RawLHS, BaseType RawRHS, bool Expected) {
207 checkContainsImpl(LHS: from(RawLHS), RHS: from(RawRHS), Expected);
208 }
209
210 template <class RHSType>
211 void checkAddImpl(RangeSet LHS, RHSType RHS, RangeSet Expected) {
212 RangeSet Result = F.add(LHS, RHS);
213 EXPECT_EQ(Result, Expected)
214 << "while adding " << toString(Obj: LHS) << " and " << toString(RHS);
215 }
216
217 void checkAdd(RawRangeSet RawLHS, RawRange RawRHS, RawRangeSet RawExpected) {
218 wrap(&Self::checkAddImpl<Range>, RawLHS, RawRHS, RawExpected);
219 }
220
221 void checkAdd(RawRangeSet RawLHS, RawRangeSet RawRHS,
222 RawRangeSet RawExpected) {
223 wrap(&Self::checkAddImpl<RangeSet>, RawLHS, RawRHS, RawExpected);
224 }
225
226 void checkAdd(RawRangeSet RawLHS, BaseType RawRHS, RawRangeSet RawExpected) {
227 wrap(&Self::checkAddImpl<const llvm::APSInt &>, RawLHS, RawRHS,
228 RawExpected);
229 }
230
231 template <class RHSType>
232 void checkUniteImpl(RangeSet LHS, RHSType RHS, RangeSet Expected) {
233 RangeSet Result = F.unite(LHS, RHS);
234 EXPECT_EQ(Result, Expected)
235 << "while uniting " << toString(Obj: LHS) << " and " << toString(RHS);
236 }
237
238 void checkUnite(RawRangeSet RawLHS, RawRange RawRHS,
239 RawRangeSet RawExpected) {
240 wrap(&Self::checkUniteImpl<Range>, RawLHS, RawRHS, RawExpected);
241 }
242
243 void checkUnite(RawRangeSet RawLHS, RawRangeSet RawRHS,
244 RawRangeSet RawExpected) {
245 wrap(&Self::checkUniteImpl<RangeSet>, RawLHS, RawRHS, RawExpected);
246 }
247
248 void checkUnite(RawRangeSet RawLHS, BaseType RawRHS,
249 RawRangeSet RawExpected) {
250 wrap(&Self::checkUniteImpl<const llvm::APSInt &>, RawLHS, RawRHS,
251 RawExpected);
252 }
253
254 void checkDeleteImpl(const llvm::APSInt &Point, RangeSet From,
255 RangeSet Expected) {
256 RangeSet Result = F.deletePoint(From, Point);
257 EXPECT_EQ(Result, Expected)
258 << "while deleting " << toString(Point) << " from " << toString(Obj: From);
259 }
260
261 void checkDelete(BaseType Point, RawRangeSet RawFrom,
262 RawRangeSet RawExpected) {
263 wrap(&Self::checkDeleteImpl, Point, RawFrom, RawExpected);
264 }
265
266 void checkCastToImpl(RangeSet What, APSIntType Ty, RangeSet Expected) {
267 RangeSet Result = F.castTo(What, Ty);
268 EXPECT_EQ(Result, Expected)
269 << "while casting " << toString(Obj: What) << " to " << Ty;
270 }
271
272 template <typename From, typename To>
273 void checkCastTo(RawRangeSetT<From> What, RawRangeSetT<To> Expected) {
274 static constexpr APSIntType FromTy = APSIntTy<From>;
275 static constexpr APSIntType ToTy = APSIntTy<To>;
276 this->checkCastToImpl(from(What, FromTy), ToTy, from(Expected, ToTy));
277 }
278};
279
280using IntTypes = ::testing::Types<int8_t, uint8_t, int16_t, uint16_t, int32_t,
281 uint32_t, int64_t, uint64_t>;
282TYPED_TEST_SUITE(RangeSetTest, IntTypes, );
283
284TYPED_TEST(RangeSetTest, RangeSetNegateTest) {
285 using TV = TestValues<TypeParam>;
286 constexpr auto MIN = TV::MIN;
287 constexpr auto MAX = TV::MAX;
288 constexpr auto MID = TV::MID;
289 constexpr auto A = TV::A;
290 constexpr auto B = TV::B;
291 constexpr auto C = TV::C;
292 constexpr auto D = TV::D;
293
294 this->checkNegate({{MIN, A}}, {{MIN, MIN}, {D, MAX}});
295 this->checkNegate({{MIN, C}}, {{MIN, MIN}, {B, MAX}});
296 this->checkNegate({{MIN, MID}}, {{MIN, MIN}, {MID, MAX}});
297 this->checkNegate({{MIN, MAX}}, {{MIN, MAX}});
298 this->checkNegate({{A, D}}, {{A, D}});
299 this->checkNegate({{A, B}}, {{C, D}});
300 this->checkNegate({{MIN, A}, {D, MAX}}, {{MIN, A}, {D, MAX}});
301 this->checkNegate({{MIN, B}, {MID, D}}, {{MIN, MIN}, {A, MID}, {C, MAX}});
302 this->checkNegate({{MIN, MID}, {C, D}}, {{MIN, MIN}, {A, B}, {MID, MAX}});
303 this->checkNegate({{MIN, MID}, {C, MAX}}, {{MIN, B}, {MID, MAX}});
304 this->checkNegate({{A, MID}, {D, MAX}}, {{MIN + 1, A}, {MID, D}});
305 this->checkNegate({{A, A}}, {{D, D}});
306 this->checkNegate({{MID, MID}}, {{MID, MID}});
307 this->checkNegate({{MAX, MAX}}, {{MIN + 1, MIN + 1}});
308}
309
310TYPED_TEST(RangeSetTest, RangeSetPointIntersectTest) {
311 // Check that we can correctly intersect empty sets.
312 this->checkIntersect({}, 42, {});
313 // Check that intersection with itself produces the same set.
314 this->checkIntersect({{42, 42}}, 42, {{42, 42}});
315 // Check more general cases.
316 this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 42, {});
317 this->checkIntersect({{0, 10}, {20, 30}, {30, 60}}, 42, {{42, 42}});
318}
319
320TYPED_TEST(RangeSetTest, RangeSetRangeIntersectTest) {
321 using TV = TestValues<TypeParam>;
322 constexpr auto MIN = TV::MIN;
323 constexpr auto MAX = TV::MAX;
324
325 // Check that we can correctly intersect empty sets.
326 this->checkIntersect({}, 10, 20, {});
327 this->checkIntersect({}, 20, 10, {});
328 // Check that intersection with itself produces the same set.
329 this->checkIntersect({{10, 20}}, 10, 20, {{10, 20}});
330 this->checkIntersect({{MIN, 10}, {20, MAX}}, 20, 10, {{MIN, 10}, {20, MAX}});
331 // Check non-overlapping range intersections.
332 this->checkIntersect({{10, 20}}, 21, 9, {});
333 this->checkIntersect({{MIN, 9}, {21, MAX}}, 10, 20, {});
334 // Check more general cases.
335 this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 10, 35,
336 {{10, 10}, {20, 30}, {30, 35}});
337 this->checkIntersect({{0, 10}, {20, 30}, {30, 40}, {50, 60}}, 35, 10,
338 {{0, 10}, {35, 40}, {50, 60}});
339}
340
341TYPED_TEST(RangeSetTest, RangeSetGenericIntersectTest) {
342 // Check that we can correctly intersect empty sets.
343 this->checkIntersect({}, {}, {});
344 this->checkIntersect({}, {{0, 10}}, {});
345 this->checkIntersect({{0, 10}}, {}, {});
346
347 this->checkIntersect({{0, 10}}, {{4, 6}}, {{4, 6}});
348 this->checkIntersect({{0, 10}}, {{4, 20}}, {{4, 10}});
349 // Check that intersection with points works as expected.
350 this->checkIntersect({{0, 10}}, {{4, 4}}, {{4, 4}});
351 // All ranges are closed, check that intersection with edge points works as
352 // expected.
353 this->checkIntersect({{0, 10}}, {{10, 10}}, {{10, 10}});
354
355 // Let's check that we can skip some intervals and partially intersect
356 // other intervals.
357 this->checkIntersect({{0, 2}, {4, 5}, {6, 9}, {10, 11}, {12, 12}, {13, 15}},
358 {{8, 14}, {20, 30}},
359 {{8, 9}, {10, 11}, {12, 12}, {13, 14}});
360 // Check more generic case.
361 this->checkIntersect(
362 {{0, 1}, {2, 3}, {5, 6}, {7, 15}, {25, 30}},
363 {{4, 10}, {11, 11}, {12, 16}, {17, 17}, {19, 20}, {21, 23}, {24, 27}},
364 {{5, 6}, {7, 10}, {11, 11}, {12, 15}, {25, 27}});
365}
366
367TYPED_TEST(RangeSetTest, RangeSetContainsTest) {
368 // Check with an empty set.
369 this->checkContains({}, 10, false);
370 // Check contains with sets of size one:
371 // * when the whole range is less
372 this->checkContains({{0, 5}}, 10, false);
373 // * when the whole range is greater
374 this->checkContains({{20, 25}}, 10, false);
375 // * when the range is just the point we are looking for
376 this->checkContains({{10, 10}}, 10, true);
377 // * when the range starts with the point
378 this->checkContains({{10, 15}}, 10, true);
379 // * when the range ends with the point
380 this->checkContains({{5, 10}}, 10, true);
381 // * when the range has the point somewhere in the middle
382 this->checkContains({{0, 25}}, 10, true);
383 // Check similar cases, but with larger sets.
384 this->checkContains({{0, 5}, {10, 10}, {15, 20}}, 10, true);
385 this->checkContains({{0, 5}, {10, 12}, {15, 20}}, 10, true);
386 this->checkContains({{0, 5}, {5, 7}, {8, 10}, {12, 41}}, 10, true);
387
388 using TV = TestValues<TypeParam>;
389 constexpr auto MIN = TV::MIN;
390 constexpr auto MAX = TV::MAX;
391 constexpr auto MID = TV::MID;
392
393 this->checkContains({{MIN, MAX}}, 0, true);
394 this->checkContains({{MIN, MAX}}, MID, true);
395 this->checkContains({{MIN, MAX}}, -10, true);
396 this->checkContains({{MIN, MAX}}, 10, true);
397}
398
399TYPED_TEST(RangeSetTest, RangeSetAddTest) {
400 // Check adding single points
401 this->checkAdd({}, 10, {{10, 10}});
402 this->checkAdd({{0, 5}}, 10, {{0, 5}, {10, 10}});
403 this->checkAdd({{0, 5}, {30, 40}}, 10, {{0, 5}, {10, 10}, {30, 40}});
404
405 // Check adding single ranges.
406 this->checkAdd({}, {10, 20}, {{10, 20}});
407 this->checkAdd({{0, 5}}, {10, 20}, {{0, 5}, {10, 20}});
408 this->checkAdd({{0, 5}, {30, 40}}, {10, 20}, {{0, 5}, {10, 20}, {30, 40}});
409
410 // Check adding whole sets of ranges.
411 this->checkAdd({{0, 5}}, {{10, 20}}, {{0, 5}, {10, 20}});
412 // Check that ordering of ranges is as expected.
413 this->checkAdd({{0, 5}, {30, 40}}, {{10, 20}}, {{0, 5}, {10, 20}, {30, 40}});
414 this->checkAdd({{0, 5}, {30, 40}}, {{10, 20}, {50, 60}},
415 {{0, 5}, {10, 20}, {30, 40}, {50, 60}});
416 this->checkAdd({{10, 20}, {50, 60}}, {{0, 5}, {30, 40}, {70, 80}},
417 {{0, 5}, {10, 20}, {30, 40}, {50, 60}, {70, 80}});
418}
419
420TYPED_TEST(RangeSetTest, RangeSetDeletePointTest) {
421 using TV = TestValues<TypeParam>;
422 constexpr auto MIN = TV::MIN;
423 constexpr auto MAX = TV::MAX;
424 constexpr auto MID = TV::MID;
425
426 this->checkDelete(MID, {{MIN, MAX}}, {{MIN, MID - 1}, {MID + 1, MAX}});
427 // Check that delete works with an empty set.
428 this->checkDelete(10, {}, {});
429 // Check that delete can remove entire ranges.
430 this->checkDelete(10, {{10, 10}}, {});
431 this->checkDelete(10, {{0, 5}, {10, 10}, {20, 30}}, {{0, 5}, {20, 30}});
432 // Check that delete can split existing ranges into two.
433 this->checkDelete(10, {{0, 5}, {7, 15}, {20, 30}},
434 {{0, 5}, {7, 9}, {11, 15}, {20, 30}});
435 // Check that delete of the point not from the range set works as expected.
436 this->checkDelete(10, {{0, 5}, {20, 30}}, {{0, 5}, {20, 30}});
437}
438
439TYPED_TEST(RangeSetTest, RangeSetUniteTest) {
440 using TV = TestValues<TypeParam>;
441 constexpr auto MIN = TV::MIN;
442 constexpr auto MAX = TV::MAX;
443 constexpr auto MID = TV::MID;
444 constexpr auto A = TV::A;
445 constexpr auto B = TV::B;
446 constexpr auto C = TV::C;
447 constexpr auto D = TV::D;
448
449 // LHS and RHS is empty.
450 // RHS =>
451 // LHS => =
452 // ___________________ ___________________
453 this->checkUnite({}, {}, {});
454
455 // RHS is empty.
456 // RHS =>
457 // LHS => _____ = _____
458 // ______/_____\______ ______/_____\______
459 this->checkUnite({{A, B}}, {}, {{A, B}});
460 this->checkUnite({{A, B}, {C, D}}, {}, {{A, B}, {C, D}});
461 this->checkUnite({{MIN, MIN}}, {}, {{MIN, MIN}});
462 this->checkUnite({{MAX, MAX}}, {}, {{MAX, MAX}});
463 this->checkUnite({{MIN, MIN}, {MAX, MAX}}, {}, {{MIN, MIN}, {MAX, MAX}});
464
465 // LHS is empty.
466 // RHS => ___
467 // LHS => / \ = _____
468 // ______/_____\______ ______/_____\______
469 this->checkUnite({}, B, {{B, B}});
470 this->checkUnite({}, {B, C}, {{B, C}});
471 this->checkUnite({}, {{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}});
472 this->checkUnite({}, {{MIN, MIN}}, {{MIN, MIN}});
473 this->checkUnite({}, {{MAX, MAX}}, {{MAX, MAX}});
474 this->checkUnite({}, {{MIN, MIN}, {MAX, MAX}}, {{MIN, MIN}, {MAX, MAX}});
475
476 // RHS is detached from LHS.
477 // RHS => ___
478 // LHS => ___ / \ = ___ _____
479 // __/___\___/_____\__ __/___\___/_____\__
480 this->checkUnite({{A, C}}, D, {{A, C}, {D, D}});
481 this->checkUnite({{MID, C}, {D, MAX}}, A, {{A, A}, {MID, C}, {D, MAX}});
482 this->checkUnite({{A, B}}, {MID, D}, {{A, B}, {MID, D}});
483 this->checkUnite({{MIN, A}, {D, MAX}}, {B, C}, {{MIN, A}, {B, C}, {D, MAX}});
484 this->checkUnite({{B, MID}, {D, MAX}}, {{MIN, A}, {C, C}},
485 {{MIN, A}, {B, MID}, {C, C}, {D, MAX}});
486 this->checkUnite({{MIN, A}, {C, C}}, {{B, MID}, {D, MAX}},
487 {{MIN, A}, {B, MID}, {C, C}, {D, MAX}});
488 this->checkUnite({{A, B}}, {{MAX, MAX}}, {{A, B}, {MAX, MAX}});
489 this->checkUnite({{MIN, MIN}}, {A, B}, {{MIN, MIN}, {A, B}});
490 this->checkUnite({{MIN, MIN}}, {MAX, MAX}, {{MIN, MIN}, {MAX, MAX}});
491
492 // RHS is inside LHS.
493 // RHS => ___
494 // LHS => ___/___\___ = ___________
495 // ___/__/_____\__\___ ___/___________\___
496 this->checkUnite({{A, C}}, MID, {{A, C}});
497 this->checkUnite({{A, D}}, {B, C}, {{A, D}});
498 this->checkUnite({{MIN, MAX}}, {B, C}, {{MIN, MAX}});
499
500 // RHS wraps LHS.
501 // RHS => _________
502 // LHS => / _____ \ = ___________
503 // ___/__/_____\__\___ ___/___________\___
504 this->checkUnite({{MID, MID}}, {A, D}, {{A, D}});
505 this->checkUnite({{B, C}}, {A, D}, {{A, D}});
506 this->checkUnite({{A, B}}, {MIN, MAX}, {{MIN, MAX}});
507
508 // RHS equals to LHS.
509 // RHS => _________
510 // LHS => /_________\ = ___________
511 // ___/___________\___ ___/___________\___
512 this->checkUnite({{MIN, MIN}}, MIN, {{MIN, MIN}});
513 this->checkUnite({{A, B}}, {A, B}, {{A, B}});
514 this->checkUnite({{MAX, MAX}}, {{MAX, MAX}}, {{MAX, MAX}});
515 this->checkUnite({{MIN, MIN}}, {{MIN, MIN}}, {{MIN, MIN}});
516 this->checkUnite({{MIN, MIN}, {MAX, MAX}}, {{MIN, MIN}, {MAX, MAX}},
517 {{MIN, MIN}, {MAX, MAX}});
518
519 // RHS edge is MIN and attached and inside LHS.
520 // RHS => _____
521 // LHS => /_____\_____ = ___________
522 // /_______\____\___ /___________\___
523 this->checkUnite({{MIN, A}}, {MIN, B}, {{MIN, B}});
524
525 // RHS edge is MIN and attached and outsude LHS.
526 // RHS => __________
527 // LHS => /______ \ = ___________
528 // /_______\____\___ /___________\___
529 this->checkUnite({{MIN, B}}, {MIN, A}, {{MIN, B}});
530
531 // RHS intersects right of LHS.
532 // RHS => ______
533 // LHS => ___/____ \ = ___________
534 // ___/__/_____\__\___ ___/___________\___
535 this->checkUnite({{A, C}}, C, {{A, C}});
536 this->checkUnite({{A, C}}, {B, D}, {{A, D}});
537
538 // RHS intersects left of LHS.
539 // RHS => ______
540 // LHS => / ____\___ = ___________
541 // ___/__/_____\__\___ ___/___________\___
542 this->checkUnite({{B, D}}, B, {{B, D}});
543 this->checkUnite({{B, D}}, {A, C}, {{A, D}});
544 this->checkUnite({{MID, MAX}}, {MIN, MID}, {{MIN, MAX}});
545
546 // RHS adjacent to LHS on right.
547 // RHS => _____
548 // LHS => ______ / \ = _______________
549 // _/______\/_______\_ _/_______________\_
550 this->checkUnite({{A, B - 1}}, B, {{A, B}});
551 this->checkUnite({{A, C}}, {C + 1, D}, {{A, D}});
552 this->checkUnite({{MIN, MID}}, {MID + 1, MAX}, {{MIN, MAX}});
553
554 // RHS adjacent to LHS on left.
555 // RHS => _____
556 // LHS => / \ ______ = _______________
557 // _/_______\/______\_ _/_______________\_
558 this->checkUnite({{B + 1, C}}, B, {{B, C}});
559 this->checkUnite({{B, D}}, {A, B - 1}, {{A, D}});
560
561 // RHS adjacent to LHS in between.
562 // RHS => ___
563 // LHS => ___ / \ ___ = _______________
564 // _/___\/_____\/___\_ _/_______________\_
565 this->checkUnite({{A, MID - 1}, {MID + 1, D}}, MID, {{A, D}});
566 this->checkUnite({{MIN, A}, {D, MAX}}, {A + 1, D - 1}, {{MIN, MAX}});
567
568 // RHS adjacent to LHS on the outside.
569 // RHS => __ __
570 // LHS => / \ ___ / \ = _______________
571 // _/____\/___\/____\_ _/_______________\_
572 this->checkUnite({{C, C}}, {{A, C - 1}, {C + 1, D}}, {{A, D}});
573 this->checkUnite({{B, MID}}, {{A, B - 1}, {MID + 1, D}}, {{A, D}});
574
575 // RHS wraps two subranges of LHS.
576 // RHS => ___________
577 // LHS => / ___ ___ \ = _____________
578 // __/_/___\_/___\_\__ __/_____________\__
579 this->checkUnite({{B, B}, {MID, MID}, {C, C}}, {{A, D}}, {{A, D}});
580 this->checkUnite({{A, B}, {MID, C}}, {{MIN, D}}, {{MIN, D}});
581
582 // RHS intersects two subranges of LHS.
583 // RHS => _________
584 // LHS => __/__ _\__ = _______________
585 // _/_/___\____/__\_\_ _/_______________\_
586 this->checkUnite({{MIN, B}, {C, MAX}}, {{A, D}}, {{MIN, MAX}});
587 this->checkUnite({{A, MID}, {C, MAX}}, {{B, D}}, {{A, MAX}});
588
589 // Multiple intersections.
590
591 // clang-format off
592 // RHS =>
593 // LHS => /\ /\ = __ __
594 // _/__\_/__\_/\_/\_/\_ _/__\_/__\_/\_/\_/\_
595 this->checkUnite({{MID, C}, {C + 2, D - 2}, {D, MAX}},
596 {{MIN, A}, {A + 2, B}},
597 {{MIN, A}, {A + 2, B}, {MID, C}, {C + 2, D - 2}, {D, MAX}});
598 this->checkUnite({{B, B}, {C, C}, {MAX, MAX}},
599 {{MIN, MIN}, {A, A}},
600 {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {MAX, MAX}});
601
602 // RHS =>
603 // LHS => /\ /\ = __ __
604 // _/\_/\_/\__/__\_/__\_ _/\_/\_/\_/__\_/__\_
605 this->checkUnite({{MIN, A}, {A + 2, B}, {MID, C}},
606 {{C + 2, D - 2}, {D, MAX}},
607 {{MIN, A}, {A + 2, B}, {MID, C}, {C + 2, D - 2}, {D, MAX}});
608 this->checkUnite({{MIN, MIN}, {A, A}, {B, B}},
609 {{C, C}, {MAX, MAX}},
610 {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {MAX, MAX}});
611
612 // RHS =>
613 // LHS => _ /\ _ /\ _ /\ =
614 // _/_\_/__\_/_\_/__\_/_\_/__\_
615 //
616 // RSLT => _ __ _ __ _ __
617 // _/_\_/__\_/_\_/__\_/_\_/__\_
618 this->checkUnite({{MIN, A}, {B + 2, MID}, {C + 2, D}},
619 {{A + 2, B}, {MID + 2, C}, {D + 2, MAX}},
620 {{MIN, A}, {A + 2, B}, {B + 2, MID}, {MID + 2, C}, {C + 2, D}, {D + 2, MAX}});
621 this->checkUnite({{MIN, MIN}, {B, B}, {D, D}},
622 {{A, A}, {C, C}, {MAX, MAX}},
623 {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {D, D}, {MAX, MAX}});
624
625 // RHS =>
626 // LHS => /\ _ /\ _ /\ _ =
627 // _/__\_/_\_/__\_/_\_/__\_/_\_
628 //
629 // RSLT => __ _ __ _ __ _
630 // _/__\_/_\_/__\_/_\_/__\_/_\_
631 this->checkUnite({{A + 2, B}, {MID + 2, C}, {D + 2, MAX}},
632 {{MIN, A}, {B + 2, MID}, {C + 2, D}},
633 {{MIN, A}, {A + 2, B}, {B + 2, MID}, {MID + 2, C}, {C + 2, D}, {D + 2, MAX}});
634 this->checkUnite({{A, A}, {C, C}, {MAX, MAX}},
635 {{MIN, MIN}, {B, B}, {D, D}},
636 {{MIN, MIN}, {A, A}, {B, B}, {C, C}, {D, D}, {MAX, MAX}});
637
638 // RHS => _ __ _
639 // LHS => /_\ /_ \ _ / \ = ___ ____________
640 // _/___\_/__\_\/_\/___\_ _/___\_/____________\_
641 this->checkUnite({{MIN, A}, {B, C}, {D, MAX}},
642 {{MIN, A}, {B, C - 2}, {C + 1, D - 1}},
643 {{MIN, A}, {B, MAX}});
644 this->checkUnite({{A, A}, {B, MID}, {D, D}},
645 {{A, A}, {B, B}, {MID + 1, D - 1}},
646 {{A, A}, {B, D}});
647
648 // RHS => ___ ___
649 // LHS => /\ _/_ \_ / _ \ /\ =
650 // _/\_/__\//__\ /\\_/_/_\_\_/__\_
651 //
652 // RSLT => ___________ _____ __
653 // _/\_/___________\_/_____\_/__\_
654 this->checkUnite({{MIN, MIN}, {B, MID}, {MID + 1, C}, {C + 4, D - 1}},
655 {{A, B - 1}, {B + 1, C - 1}, {C + 2, D}, {MAX - 1, MAX}},
656 {{MIN, MIN}, {A, C}, {C + 2, D}, {MAX - 1, MAX}});
657 // clang-format on
658}
659
660template <typename From, typename To> struct CastType {
661 using FromType = From;
662 using ToType = To;
663};
664
665template <typename Type>
666class RangeSetCastToNoopTest : public RangeSetTest<typename Type::FromType> {};
667template <typename Type>
668class RangeSetCastToPromotionTest
669 : public RangeSetTest<typename Type::FromType> {};
670template <typename Type>
671class RangeSetCastToTruncationTest
672 : public RangeSetTest<typename Type::FromType> {};
673template <typename Type>
674class RangeSetCastToConversionTest
675 : public RangeSetTest<typename Type::FromType> {};
676template <typename Type>
677class RangeSetCastToPromotionConversionTest
678 : public RangeSetTest<typename Type::FromType> {};
679template <typename Type>
680class RangeSetCastToTruncationConversionTest
681 : public RangeSetTest<typename Type::FromType> {};
682
683using NoopCastTypes =
684 ::testing::Types<CastType<int8_t, int8_t>, CastType<uint8_t, uint8_t>,
685 CastType<int16_t, int16_t>, CastType<uint16_t, uint16_t>,
686 CastType<int32_t, int32_t>, CastType<uint32_t, uint32_t>,
687 CastType<int64_t, int64_t>, CastType<uint64_t, uint64_t>>;
688
689using PromotionCastTypes =
690 ::testing::Types<CastType<int8_t, int16_t>, CastType<int8_t, int32_t>,
691 CastType<int8_t, int64_t>, CastType<uint8_t, uint16_t>,
692 CastType<uint8_t, uint32_t>, CastType<uint8_t, uint64_t>,
693 CastType<int16_t, int32_t>, CastType<int16_t, int64_t>,
694 CastType<uint16_t, uint32_t>, CastType<uint16_t, uint64_t>,
695 CastType<int32_t, int64_t>, CastType<uint32_t, uint64_t>>;
696
697using TruncationCastTypes =
698 ::testing::Types<CastType<int16_t, int8_t>, CastType<uint16_t, uint8_t>,
699 CastType<int32_t, int16_t>, CastType<int32_t, int8_t>,
700 CastType<uint32_t, uint16_t>, CastType<uint32_t, uint8_t>,
701 CastType<int64_t, int32_t>, CastType<int64_t, int16_t>,
702 CastType<int64_t, int8_t>, CastType<uint64_t, uint32_t>,
703 CastType<uint64_t, uint16_t>, CastType<uint64_t, uint8_t>>;
704
705using ConversionCastTypes =
706 ::testing::Types<CastType<int8_t, uint8_t>, CastType<uint8_t, int8_t>,
707 CastType<int16_t, uint16_t>, CastType<uint16_t, int16_t>,
708 CastType<int32_t, uint32_t>, CastType<uint32_t, int32_t>,
709 CastType<int64_t, uint64_t>, CastType<uint64_t, int64_t>>;
710
711using PromotionConversionCastTypes =
712 ::testing::Types<CastType<int8_t, uint16_t>, CastType<int8_t, uint32_t>,
713 CastType<int8_t, uint64_t>, CastType<uint8_t, int16_t>,
714 CastType<uint8_t, int32_t>, CastType<uint8_t, int64_t>,
715 CastType<int16_t, uint32_t>, CastType<int16_t, uint64_t>,
716 CastType<uint16_t, int32_t>, CastType<uint16_t, int64_t>,
717 CastType<int32_t, uint64_t>, CastType<uint32_t, int64_t>>;
718
719using TruncationConversionCastTypes =
720 ::testing::Types<CastType<int16_t, uint8_t>, CastType<uint16_t, int8_t>,
721 CastType<int32_t, uint16_t>, CastType<int32_t, uint8_t>,
722 CastType<uint32_t, int16_t>, CastType<uint32_t, int8_t>,
723 CastType<int64_t, uint32_t>, CastType<int64_t, uint16_t>,
724 CastType<int64_t, uint8_t>, CastType<uint64_t, int32_t>,
725 CastType<uint64_t, int16_t>, CastType<uint64_t, int8_t>>;
726
727TYPED_TEST_SUITE(RangeSetCastToNoopTest, NoopCastTypes, );
728TYPED_TEST_SUITE(RangeSetCastToPromotionTest, PromotionCastTypes, );
729TYPED_TEST_SUITE(RangeSetCastToTruncationTest, TruncationCastTypes, );
730TYPED_TEST_SUITE(RangeSetCastToConversionTest, ConversionCastTypes, );
731TYPED_TEST_SUITE(RangeSetCastToPromotionConversionTest,
732 PromotionConversionCastTypes, );
733TYPED_TEST_SUITE(RangeSetCastToTruncationConversionTest,
734 TruncationConversionCastTypes, );
735
736TYPED_TEST(RangeSetCastToNoopTest, RangeSetCastToNoopTest) {
737 // Just to reduce the verbosity.
738 using F = typename TypeParam::FromType; // From
739 using T = typename TypeParam::ToType; // To
740
741 using TV = TestValues<F>;
742 constexpr auto MIN = TV::MIN;
743 constexpr auto MAX = TV::MAX;
744 constexpr auto MID = TV::MID;
745 constexpr auto B = TV::B;
746 constexpr auto C = TV::C;
747 // One point
748 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
749 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
750 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
751 this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
752 this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
753 // Two points
754 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
755 {{MIN, MIN}, {MAX, MAX}});
756 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
757 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
758 {{MID, MID}, {MAX, MAX}});
759 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
760 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
761 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
762 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
763 // One range
764 this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}});
765 this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}});
766 this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}});
767 this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}});
768 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
769 this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}});
770 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
771 this->template checkCastTo<F, T>({{B, C}}, {{B, C}});
772 // Two ranges
773 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}});
774 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{B, MID}, {C, MAX}});
775 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MIN, B}, {MID, C}});
776}
777
778TYPED_TEST(RangeSetCastToPromotionTest, Test) {
779 // Just to reduce the verbosity.
780 using F = typename TypeParam::FromType; // From
781 using T = typename TypeParam::ToType; // To
782
783 using TV = TestValues<F>;
784 constexpr auto MIN = TV::MIN;
785 constexpr auto MAX = TV::MAX;
786 constexpr auto MID = TV::MID;
787 constexpr auto B = TV::B;
788 constexpr auto C = TV::C;
789 // One point
790 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
791 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
792 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
793 this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
794 this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
795 // Two points
796 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
797 {{MIN, MIN}, {MAX, MAX}});
798 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
799 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
800 {{MID, MID}, {MAX, MAX}});
801 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
802 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
803 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
804 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
805 // One range
806 this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}});
807 this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}});
808 this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}});
809 this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}});
810 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
811 this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}});
812 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
813 this->template checkCastTo<F, T>({{B, C}}, {{B, C}});
814 // Two ranges
815 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{MIN, B}, {C, MAX}});
816 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{B, MID}, {C, MAX}});
817 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MIN, B}, {MID, C}});
818}
819
820TYPED_TEST(RangeSetCastToTruncationTest, Test) {
821 // Just to reduce the verbosity.
822 using F = typename TypeParam::FromType; // From
823 using T = typename TypeParam::ToType; // To
824
825 using TV = TestValues<F>;
826 constexpr auto MIN = TV::MIN;
827 constexpr auto MAX = TV::MAX;
828 constexpr auto MID = TV::MID;
829 constexpr auto B = TV::B;
830 constexpr auto C = TV::C;
831 // One point
832 //
833 // NOTE: We can't use ToMIN, ToMAX, ... everywhere. That would be incorrect:
834 // int16(-32768, 32767) -> int8(-128, 127),
835 // aka (MIN, MAX) -> (ToMIN, ToMAX) // OK.
836 // int16(-32768, -32768) -> int8(-128, -128),
837 // aka (MIN, MIN) -> (ToMIN, ToMIN) // NOK.
838 // int16(-32768,-32768) -> int8(0, 0),
839 // aka (MIN, MIN) -> ((int8)MIN, (int8)MIN) // OK.
840 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
841 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
842 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
843 this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
844 this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
845 // Two points
846 // Use `if constexpr` here.
847 if (is_signed_v<F>) {
848 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}});
849 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, {{MAX, MID}});
850 } else {
851 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
852 {{MIN, MIN}, {MAX, MAX}});
853 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
854 {{MID, MID}, {MAX, MAX}});
855 }
856 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
857 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
858 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
859 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
860 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
861 // One range
862 constexpr auto ToMIN = TestValues<T>::MIN;
863 constexpr auto ToMAX = TestValues<T>::MAX;
864 this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}});
865 this->template checkCastTo<F, T>({{MIN, MID}}, {{ToMIN, ToMAX}});
866 this->template checkCastTo<F, T>({{MID, MAX}}, {{ToMIN, ToMAX}});
867 this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, ToMAX}});
868 this->template checkCastTo<F, T>({{C, MAX}}, {{ToMIN, ToMAX}});
869 this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, ToMAX}});
870 this->template checkCastTo<F, T>({{MIN, B}}, {{ToMIN, ToMAX}});
871 this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, ToMAX}});
872 // Two ranges
873 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{ToMIN, ToMAX}});
874 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{ToMIN, ToMAX}});
875 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{ToMIN, ToMAX}});
876 constexpr auto XAAA = TV::XAAA;
877 constexpr auto X555 = TV::X555;
878 constexpr auto ZA = TV::template XAAATruncZeroOf<T>;
879 constexpr auto Z5 = TV::template X555TruncZeroOf<T>;
880 this->template checkCastTo<F, T>({{XAAA, ZA}, {X555, Z5}},
881 {{ToMIN, 0}, {X555, ToMAX}});
882 // Use `if constexpr` here.
883 if (is_signed_v<F>) {
884 // One range
885 this->template checkCastTo<F, T>({{XAAA, ZA}}, {{XAAA, 0}});
886 // Two ranges
887 this->template checkCastTo<F, T>({{XAAA, ZA}, {1, 42}}, {{XAAA, 42}});
888 } else {
889 // One range
890 this->template checkCastTo<F, T>({{XAAA, ZA}}, {{0, 0}, {XAAA, ToMAX}});
891 // Two ranges
892 this->template checkCastTo<F, T>({{1, 42}, {XAAA, ZA}},
893 {{0, 42}, {XAAA, ToMAX}});
894 }
895 constexpr auto FromA = TV::FromA;
896 constexpr auto ToA = TV::ToA;
897 constexpr auto FromB = TV::FromB;
898 constexpr auto ToB = TV::ToB;
899 // int16 -> int8
900 // (0x00'01, 0x00'05)U(0xFF'01, 0xFF'05) casts to
901 // (0x01, 0x05)U(0x01, 0x05) unites to
902 // (0x01, 0x05)
903 this->template checkCastTo<F, T>({{FromA, ToA}, {FromB, ToB}},
904 {{FromA, ToA}});
905}
906
907TYPED_TEST(RangeSetCastToConversionTest, Test) {
908 // Just to reduce the verbosity.
909 using F = typename TypeParam::FromType; // From
910 using T = typename TypeParam::ToType; // To
911
912 using TV = TestValues<F>;
913 constexpr auto MIN = TV::MIN;
914 constexpr auto MAX = TV::MAX;
915 constexpr auto MID = TV::MID;
916 constexpr auto B = TV::B;
917 constexpr auto C = TV::C;
918 // One point
919 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
920 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
921 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
922 this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
923 this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
924 // Two points
925 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}});
926 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
927 {{MID, MID}, {MAX, MAX}});
928 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
929 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
930 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
931 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
932 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
933 // One range
934 constexpr auto ToMIN = TestValues<T>::MIN;
935 constexpr auto ToMAX = TestValues<T>::MAX;
936 this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}});
937 this->template checkCastTo<F, T>({{MIN, MID}},
938 {{ToMIN, ToMIN}, {MIN, ToMAX}});
939 this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}});
940 this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, MAX}, {B, ToMAX}});
941 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
942 this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, C}, {MIN, ToMAX}});
943 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
944 this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, C}, {B, ToMAX}});
945 // Two ranges
946 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{C, B}});
947 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}},
948 {{MID, MID}, {C, MAX}, {B, ToMAX}});
949 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{MID, C}, {MIN, B}});
950}
951
952TYPED_TEST(RangeSetCastToPromotionConversionTest, Test) {
953 // Just to reduce the verbosity.
954 using F = typename TypeParam::FromType; // From
955 using T = typename TypeParam::ToType; // To
956
957 using TV = TestValues<F>;
958 constexpr auto MIN = TV::MIN;
959 constexpr auto MAX = TV::MAX;
960 constexpr auto MID = TV::MID;
961 constexpr auto B = TV::B;
962 constexpr auto C = TV::C;
963 // One point
964 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
965 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
966 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
967 this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
968 this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
969 // Two points
970 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
971 {{MAX, MAX}, {MIN, MIN}});
972 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
973 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
974 {{MID, MID}, {MAX, MAX}});
975 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
976 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
977 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
978 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
979
980 // Use `if constexpr` here.
981 if (is_signed_v<F>) {
982 // One range
983 this->template checkCastTo<F, T>({{MIN, MAX}}, {{0, MAX}, {MIN, -1}});
984 this->template checkCastTo<F, T>({{MIN, MID}}, {{0, 0}, {MIN, -1}});
985 this->template checkCastTo<F, T>({{MID, MAX}}, {{0, MAX}});
986 this->template checkCastTo<F, T>({{B, MAX}}, {{0, MAX}, {B, -1}});
987 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
988 this->template checkCastTo<F, T>({{MIN, C}}, {{0, C}, {MIN, -1}});
989 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
990 this->template checkCastTo<F, T>({{B, C}}, {{0, C}, {B, -1}});
991 // Two ranges
992 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}},
993 {{C, MAX}, {MIN, B}});
994 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}},
995 {{0, 0}, {C, MAX}, {B, -1}});
996 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{0, C}, {MIN, B}});
997 } else {
998 // One range
999 this->template checkCastTo<F, T>({{MIN, MAX}}, {{MIN, MAX}});
1000 this->template checkCastTo<F, T>({{MIN, MID}}, {{MIN, MID}});
1001 this->template checkCastTo<F, T>({{MID, MAX}}, {{MID, MAX}});
1002 this->template checkCastTo<F, T>({{B, MAX}}, {{B, MAX}});
1003 this->template checkCastTo<F, T>({{C, MAX}}, {{C, MAX}});
1004 this->template checkCastTo<F, T>({{MIN, C}}, {{MIN, C}});
1005 this->template checkCastTo<F, T>({{MIN, B}}, {{MIN, B}});
1006 this->template checkCastTo<F, T>({{B, C}}, {{B, C}});
1007 // Two ranges
1008 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}},
1009 {{MIN, B}, {C, MAX}});
1010 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}},
1011 {{B, MID}, {C, MAX}});
1012 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}},
1013 {{MIN, B}, {MID, C}});
1014 }
1015}
1016
1017TYPED_TEST(RangeSetCastToTruncationConversionTest, Test) {
1018 // Just to reduce the verbosity.
1019 using F = typename TypeParam::FromType; // From
1020 using T = typename TypeParam::ToType; // To
1021
1022 using TV = TestValues<F>;
1023 constexpr auto MIN = TV::MIN;
1024 constexpr auto MAX = TV::MAX;
1025 constexpr auto MID = TV::MID;
1026 constexpr auto B = TV::B;
1027 constexpr auto C = TV::C;
1028 // One point
1029 this->template checkCastTo<F, T>({{MIN, MIN}}, {{MIN, MIN}});
1030 this->template checkCastTo<F, T>({{MAX, MAX}}, {{MAX, MAX}});
1031 this->template checkCastTo<F, T>({{MID, MID}}, {{MID, MID}});
1032 this->template checkCastTo<F, T>({{B, B}}, {{B, B}});
1033 this->template checkCastTo<F, T>({{C, C}}, {{C, C}});
1034 // Two points
1035 // Use `if constexpr` here.
1036 if (is_signed_v<F>) {
1037 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}},
1038 {{MIN, MIN}, {MAX, MAX}});
1039 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}},
1040 {{MID, MID}, {MAX, MAX}});
1041 } else {
1042 this->template checkCastTo<F, T>({{MIN, MIN}, {MAX, MAX}}, {{MAX, MIN}});
1043 this->template checkCastTo<F, T>({{MID, MID}, {MAX, MAX}}, {{MAX, MIN}});
1044 }
1045 this->template checkCastTo<F, T>({{MIN, MIN}, {B, B}}, {{MIN, MIN}, {B, B}});
1046 this->template checkCastTo<F, T>({{C, C}, {MAX, MAX}}, {{C, C}, {MAX, MAX}});
1047 this->template checkCastTo<F, T>({{MID, MID}, {C, C}}, {{MID, MID}, {C, C}});
1048 this->template checkCastTo<F, T>({{B, B}, {MID, MID}}, {{B, B}, {MID, MID}});
1049 this->template checkCastTo<F, T>({{B, B}, {C, C}}, {{B, B}, {C, C}});
1050 // One range
1051 constexpr auto ToMIN = TestValues<T>::MIN;
1052 constexpr auto ToMAX = TestValues<T>::MAX;
1053 this->template checkCastTo<F, T>({{MIN, MAX}}, {{ToMIN, ToMAX}});
1054 this->template checkCastTo<F, T>({{MIN, MID}}, {{ToMIN, ToMAX}});
1055 this->template checkCastTo<F, T>({{MID, MAX}}, {{ToMIN, ToMAX}});
1056 this->template checkCastTo<F, T>({{B, MAX}}, {{ToMIN, ToMAX}});
1057 this->template checkCastTo<F, T>({{C, MAX}}, {{ToMIN, ToMAX}});
1058 this->template checkCastTo<F, T>({{MIN, C}}, {{ToMIN, ToMAX}});
1059 this->template checkCastTo<F, T>({{MIN, B}}, {{ToMIN, ToMAX}});
1060 this->template checkCastTo<F, T>({{B, C}}, {{ToMIN, ToMAX}});
1061 // Two ranges
1062 this->template checkCastTo<F, T>({{MIN, B}, {C, MAX}}, {{ToMIN, ToMAX}});
1063 this->template checkCastTo<F, T>({{B, MID}, {C, MAX}}, {{ToMIN, ToMAX}});
1064 this->template checkCastTo<F, T>({{MIN, B}, {MID, C}}, {{ToMIN, ToMAX}});
1065 constexpr auto XAAA = TV::XAAA;
1066 constexpr auto X555 = TV::X555;
1067 constexpr auto ZA = TV::template XAAATruncZeroOf<T>;
1068 constexpr auto Z5 = TV::template X555TruncZeroOf<T>;
1069 this->template checkCastTo<F, T>({{XAAA, ZA}, {X555, Z5}},
1070 {{ToMIN, 0}, {X555, ToMAX}});
1071 // Use `if constexpr` here.
1072 if (is_signed_v<F>) {
1073 // One range
1074 this->template checkCastTo<F, T>({{XAAA, ZA}}, {{0, 0}, {XAAA, ToMAX}});
1075 // Two ranges
1076 this->template checkCastTo<F, T>({{XAAA, ZA}, {1, 42}},
1077 {{0, 42}, {XAAA, ToMAX}});
1078 } else {
1079 // One range
1080 this->template checkCastTo<F, T>({{XAAA, ZA}}, {{XAAA, 0}});
1081 // Two ranges
1082 this->template checkCastTo<F, T>({{1, 42}, {XAAA, ZA}}, {{XAAA, 42}});
1083 }
1084 constexpr auto FromA = TV::FromA;
1085 constexpr auto ToA = TV::ToA;
1086 constexpr auto FromB = TV::FromB;
1087 constexpr auto ToB = TV::ToB;
1088 this->template checkCastTo<F, T>({{FromA, ToA}, {FromB, ToB}},
1089 {{FromA, ToA}});
1090}
1091
1092} // namespace
1093

source code of clang/unittests/StaticAnalyzer/RangeSetTest.cpp