131 lines
4.5 KiB
C++
131 lines
4.5 KiB
C++
|
//===- unittests/StaticAnalyzer/RangeSetTest.cpp ----------------------===//
|
||
|
//
|
||
|
// 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
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "clang/Basic/Builtins.h"
|
||
|
#include "clang/Basic/FileManager.h"
|
||
|
#include "clang/Basic/SourceManager.h"
|
||
|
#include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
|
||
|
#include "clang/Tooling/Tooling.h"
|
||
|
#include "gtest/gtest.h"
|
||
|
|
||
|
namespace clang {
|
||
|
namespace ento {
|
||
|
namespace {
|
||
|
|
||
|
// TestCase contains to lists of ranges.
|
||
|
// Original one has to be negated.
|
||
|
// Expected one has to be compared to negated original range.
|
||
|
template <typename T> struct TestCase {
|
||
|
RangeSet original;
|
||
|
RangeSet expected;
|
||
|
|
||
|
TestCase(BasicValueFactory &BVF, RangeSet::Factory &F,
|
||
|
const std::initializer_list<T> &originalList,
|
||
|
const std::initializer_list<T> &expectedList)
|
||
|
: original(createRangeSetFromList(BVF, F, originalList)),
|
||
|
expected(createRangeSetFromList(BVF, F, expectedList)) {}
|
||
|
|
||
|
private:
|
||
|
RangeSet createRangeSetFromList(BasicValueFactory &BVF, RangeSet::Factory &F,
|
||
|
const std::initializer_list<T> rangeList) {
|
||
|
llvm::APSInt from(sizeof(T) * 8, std::is_unsigned<T>::value);
|
||
|
llvm::APSInt to = from;
|
||
|
RangeSet rangeSet = F.getEmptySet();
|
||
|
for (auto it = rangeList.begin(); it != rangeList.end(); it += 2) {
|
||
|
from = *it;
|
||
|
to = *(it + 1);
|
||
|
rangeSet = rangeSet.addRange(
|
||
|
F, RangeSet(F, BVF.getValue(from), BVF.getValue(to)));
|
||
|
}
|
||
|
return rangeSet;
|
||
|
}
|
||
|
|
||
|
void printNegate(const TestCase &TestCase) {
|
||
|
TestCase.original.print(llvm::dbgs());
|
||
|
llvm::dbgs() << " => ";
|
||
|
TestCase.expected.print(llvm::dbgs());
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class RangeSetTest : public testing::Test {
|
||
|
protected:
|
||
|
// Init block
|
||
|
std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCode("struct foo;");
|
||
|
ASTContext &context = AST->getASTContext();
|
||
|
llvm::BumpPtrAllocator alloc;
|
||
|
BasicValueFactory BVF{context, alloc};
|
||
|
RangeSet::Factory F;
|
||
|
// End init block
|
||
|
|
||
|
template <typename T> void checkNegate() {
|
||
|
using type = T;
|
||
|
|
||
|
// Use next values of the range {MIN, A, B, MID, C, D, MAX}.
|
||
|
|
||
|
// MID is a value in the middle of the range
|
||
|
// which unary minus does not affect on,
|
||
|
// e.g. int8/int32(0), uint8(128), uint32(2147483648).
|
||
|
|
||
|
constexpr type MIN = std::numeric_limits<type>::min();
|
||
|
constexpr type MAX = std::numeric_limits<type>::max();
|
||
|
constexpr type MID = std::is_signed<type>::value
|
||
|
? 0
|
||
|
: ~(static_cast<type>(-1) / static_cast<type>(2));
|
||
|
constexpr type A = MID - static_cast<type>(42 + 42);
|
||
|
constexpr type B = MID - static_cast<type>(42);
|
||
|
constexpr type C = -B;
|
||
|
constexpr type D = -A;
|
||
|
|
||
|
static_assert(MIN < A && A < B && B < MID && MID < C && C < D && D < MAX,
|
||
|
"Values shall be in an ascending order");
|
||
|
|
||
|
// Left {[x, y], [x, y]} is what shall be negated.
|
||
|
// Right {[x, y], [x, y]} is what shall be compared to a negation result.
|
||
|
TestCase<type> cases[] = {
|
||
|
{BVF, F, {MIN, A}, {MIN, MIN, D, MAX}},
|
||
|
{BVF, F, {MIN, C}, {MIN, MIN, B, MAX}},
|
||
|
{BVF, F, {MIN, MID}, {MIN, MIN, MID, MAX}},
|
||
|
{BVF, F, {MIN, MAX}, {MIN, MAX}},
|
||
|
{BVF, F, {A, D}, {A, D}},
|
||
|
{BVF, F, {A, B}, {C, D}},
|
||
|
{BVF, F, {MIN, A, D, MAX}, {MIN, A, D, MAX}},
|
||
|
{BVF, F, {MIN, B, MID, D}, {MIN, MIN, A, MID, C, MAX}},
|
||
|
{BVF, F, {MIN, MID, C, D}, {MIN, MIN, A, B, MID, MAX}},
|
||
|
{BVF, F, {MIN, MID, C, MAX}, {MIN, B, MID, MAX}},
|
||
|
{BVF, F, {A, MID, D, MAX}, {MIN + 1, A, MID, D}},
|
||
|
{BVF, F, {A, A}, {D, D}},
|
||
|
{BVF, F, {MID, MID}, {MID, MID}},
|
||
|
{BVF, F, {MAX, MAX}, {MIN + 1, MIN + 1}},
|
||
|
};
|
||
|
|
||
|
for (const auto &c : cases) {
|
||
|
// Negate original and check with expected.
|
||
|
RangeSet negatedFromOriginal = c.original.Negate(BVF, F);
|
||
|
EXPECT_EQ(negatedFromOriginal, c.expected);
|
||
|
// Negate negated back and check with original.
|
||
|
RangeSet negatedBackward = negatedFromOriginal.Negate(BVF, F);
|
||
|
EXPECT_EQ(negatedBackward, c.original);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
TEST_F(RangeSetTest, RangeSetNegateTest) {
|
||
|
checkNegate<int8_t>();
|
||
|
checkNegate<uint8_t>();
|
||
|
checkNegate<int16_t>();
|
||
|
checkNegate<uint16_t>();
|
||
|
checkNegate<int32_t>();
|
||
|
checkNegate<uint32_t>();
|
||
|
checkNegate<int64_t>();
|
||
|
checkNegate<uint64_t>();
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
} // namespace ento
|
||
|
} // namespace clang
|