178 lines
4.9 KiB
C++
178 lines
4.9 KiB
C++
|
//===- unittests/Analysis/FlowSensitive/SimplifyConstraintsTest.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/Analysis/FlowSensitive/SimplifyConstraints.h"
|
||
|
#include "TestingSupport.h"
|
||
|
#include "clang/Analysis/FlowSensitive/Arena.h"
|
||
|
#include "gmock/gmock.h"
|
||
|
#include "gtest/gtest.h"
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
using namespace clang;
|
||
|
using namespace dataflow;
|
||
|
|
||
|
using ::testing::ElementsAre;
|
||
|
using ::testing::IsEmpty;
|
||
|
|
||
|
class SimplifyConstraintsTest : public ::testing::Test {
|
||
|
protected:
|
||
|
llvm::SetVector<const Formula *> parse(StringRef Lines) {
|
||
|
std::vector<const Formula *> formulas = test::parseFormulas(A, Lines);
|
||
|
llvm::SetVector<const Formula *> Constraints(formulas.begin(),
|
||
|
formulas.end());
|
||
|
return Constraints;
|
||
|
}
|
||
|
|
||
|
llvm::SetVector<const Formula *> simplify(StringRef Lines,
|
||
|
SimplifyConstraintsInfo &Info) {
|
||
|
llvm::SetVector<const Formula *> Constraints = parse(Lines);
|
||
|
simplifyConstraints(Constraints, A, &Info);
|
||
|
return Constraints;
|
||
|
}
|
||
|
|
||
|
Arena A;
|
||
|
};
|
||
|
|
||
|
void printConstraints(const llvm::SetVector<const Formula *> &Constraints,
|
||
|
raw_ostream &OS) {
|
||
|
if (Constraints.empty()) {
|
||
|
OS << "empty";
|
||
|
return;
|
||
|
}
|
||
|
for (const auto *Constraint : Constraints) {
|
||
|
Constraint->print(OS);
|
||
|
OS << "\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::string
|
||
|
constraintsToString(const llvm::SetVector<const Formula *> &Constraints) {
|
||
|
std::string Str;
|
||
|
llvm::raw_string_ostream OS(Str);
|
||
|
printConstraints(Constraints, OS);
|
||
|
return Str;
|
||
|
}
|
||
|
|
||
|
MATCHER_P(EqualsConstraints, Constraints,
|
||
|
"constraints are: " + constraintsToString(Constraints)) {
|
||
|
if (arg == Constraints)
|
||
|
return true;
|
||
|
|
||
|
if (result_listener->stream()) {
|
||
|
llvm::raw_os_ostream OS(*result_listener->stream());
|
||
|
OS << "constraints are: ";
|
||
|
printConstraints(arg, OS);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
TEST_F(SimplifyConstraintsTest, TriviallySatisfiable) {
|
||
|
SimplifyConstraintsInfo Info;
|
||
|
EXPECT_THAT(simplify(R"(
|
||
|
V0
|
||
|
)",
|
||
|
Info),
|
||
|
EqualsConstraints(parse("")));
|
||
|
EXPECT_THAT(Info.EquivalentAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.TrueAtoms, ElementsAre(Atom(0)));
|
||
|
EXPECT_THAT(Info.FalseAtoms, IsEmpty());
|
||
|
}
|
||
|
|
||
|
TEST_F(SimplifyConstraintsTest, SimpleContradiction) {
|
||
|
SimplifyConstraintsInfo Info;
|
||
|
EXPECT_THAT(simplify(R"(
|
||
|
V0
|
||
|
!V0
|
||
|
)",
|
||
|
Info),
|
||
|
EqualsConstraints(parse("false")));
|
||
|
EXPECT_THAT(Info.EquivalentAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.TrueAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.FalseAtoms, IsEmpty());
|
||
|
}
|
||
|
|
||
|
TEST_F(SimplifyConstraintsTest, ContradictionThroughEquivalence) {
|
||
|
SimplifyConstraintsInfo Info;
|
||
|
EXPECT_THAT(simplify(R"(
|
||
|
(V0 = V1)
|
||
|
V0
|
||
|
!V1
|
||
|
)",
|
||
|
Info),
|
||
|
EqualsConstraints(parse("false")));
|
||
|
EXPECT_THAT(Info.EquivalentAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.TrueAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.FalseAtoms, IsEmpty());
|
||
|
}
|
||
|
|
||
|
TEST_F(SimplifyConstraintsTest, EquivalenceChain) {
|
||
|
SimplifyConstraintsInfo Info;
|
||
|
EXPECT_THAT(simplify(R"(
|
||
|
(V0 | V3)
|
||
|
(V1 = V2)
|
||
|
(V2 = V3)
|
||
|
)",
|
||
|
Info),
|
||
|
EqualsConstraints(parse("(V0 | V1)")));
|
||
|
EXPECT_THAT(Info.EquivalentAtoms,
|
||
|
ElementsAre(ElementsAre(Atom(1), Atom(2), Atom(3))));
|
||
|
EXPECT_THAT(Info.TrueAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.FalseAtoms, IsEmpty());
|
||
|
}
|
||
|
|
||
|
TEST_F(SimplifyConstraintsTest, TrueAndFalseAtomsSimplifyOtherExpressions) {
|
||
|
SimplifyConstraintsInfo Info;
|
||
|
EXPECT_THAT(simplify(R"(
|
||
|
V0
|
||
|
!V1
|
||
|
(V0 & (V2 => V3))
|
||
|
(V1 | (V4 => V5))
|
||
|
)",
|
||
|
Info),
|
||
|
EqualsConstraints(parse(R"(
|
||
|
(V2 => V3)
|
||
|
(V4 => V5)
|
||
|
)")));
|
||
|
EXPECT_THAT(Info.EquivalentAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.TrueAtoms, ElementsAre(Atom(0)));
|
||
|
EXPECT_THAT(Info.FalseAtoms, ElementsAre(Atom(1)));
|
||
|
}
|
||
|
|
||
|
TEST_F(SimplifyConstraintsTest, TrueAtomUnlocksEquivalenceChain) {
|
||
|
SimplifyConstraintsInfo Info;
|
||
|
EXPECT_THAT(simplify(R"(
|
||
|
V0
|
||
|
(V0 & (V1 = V2))
|
||
|
(V0 & (V2 = V3))
|
||
|
)",
|
||
|
Info),
|
||
|
EqualsConstraints(parse("")));
|
||
|
EXPECT_THAT(Info.EquivalentAtoms,
|
||
|
ElementsAre(ElementsAre(Atom(1), Atom(2), Atom(3))));
|
||
|
EXPECT_THAT(Info.TrueAtoms, ElementsAre(Atom(0)));
|
||
|
EXPECT_THAT(Info.FalseAtoms, IsEmpty());
|
||
|
}
|
||
|
|
||
|
TEST_F(SimplifyConstraintsTest, TopLevelAndSplitIntoMultipleConstraints) {
|
||
|
SimplifyConstraintsInfo Info;
|
||
|
EXPECT_THAT(simplify(R"(
|
||
|
((V0 => V1) & (V2 => V3))
|
||
|
)",
|
||
|
Info),
|
||
|
EqualsConstraints(parse(R"(
|
||
|
(V0 => V1)
|
||
|
(V2 => V3)
|
||
|
)")));
|
||
|
EXPECT_THAT(Info.EquivalentAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.TrueAtoms, IsEmpty());
|
||
|
EXPECT_THAT(Info.FalseAtoms, IsEmpty());
|
||
|
}
|
||
|
|
||
|
} // namespace
|