1 //===- unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp ---===//
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
7 //===----------------------------------------------------------------------===//
9 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
10 #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
17 using namespace clang
;
18 using namespace dataflow
;
20 class DataflowAnalysisContextTest
: public ::testing::Test
{
22 DataflowAnalysisContextTest()
23 : Context(std::make_unique
<WatchedLiteralsSolver
>()), A(Context
.arena()) {
26 DataflowAnalysisContext Context
;
30 TEST_F(DataflowAnalysisContextTest
, DistinctTopsNotEquivalent
) {
31 auto &X
= A
.makeTopValue();
32 auto &Y
= A
.makeTopValue();
33 EXPECT_FALSE(Context
.equivalentFormulas(X
.formula(), Y
.formula()));
36 TEST_F(DataflowAnalysisContextTest
, EmptyFlowCondition
) {
37 Atom FC
= A
.makeFlowConditionToken();
38 auto &C
= A
.makeAtomRef(A
.makeAtom());
39 EXPECT_FALSE(Context
.flowConditionImplies(FC
, C
));
42 TEST_F(DataflowAnalysisContextTest
, AddFlowConditionConstraint
) {
43 Atom FC
= A
.makeFlowConditionToken();
44 auto &C
= A
.makeAtomRef(A
.makeAtom());
45 Context
.addFlowConditionConstraint(FC
, C
);
46 EXPECT_TRUE(Context
.flowConditionImplies(FC
, C
));
49 TEST_F(DataflowAnalysisContextTest
, AddInvariant
) {
50 Atom FC
= A
.makeFlowConditionToken();
51 auto &C
= A
.makeAtomRef(A
.makeAtom());
52 Context
.addInvariant(C
);
53 EXPECT_TRUE(Context
.flowConditionImplies(FC
, C
));
56 TEST_F(DataflowAnalysisContextTest
, InvariantAndFCConstraintInteract
) {
57 Atom FC
= A
.makeFlowConditionToken();
58 auto &C
= A
.makeAtomRef(A
.makeAtom());
59 auto &D
= A
.makeAtomRef(A
.makeAtom());
60 Context
.addInvariant(A
.makeImplies(C
, D
));
61 Context
.addFlowConditionConstraint(FC
, C
);
62 EXPECT_TRUE(Context
.flowConditionImplies(FC
, D
));
65 TEST_F(DataflowAnalysisContextTest
, ForkFlowCondition
) {
66 Atom FC1
= A
.makeFlowConditionToken();
67 auto &C1
= A
.makeAtomRef(A
.makeAtom());
68 Context
.addFlowConditionConstraint(FC1
, C1
);
70 // Forked flow condition inherits the constraints of its parent flow
72 Atom FC2
= Context
.forkFlowCondition(FC1
);
73 EXPECT_TRUE(Context
.flowConditionImplies(FC2
, C1
));
75 // Adding a new constraint to the forked flow condition does not affect its
76 // parent flow condition.
77 auto &C2
= A
.makeAtomRef(A
.makeAtom());
78 Context
.addFlowConditionConstraint(FC2
, C2
);
79 EXPECT_TRUE(Context
.flowConditionImplies(FC2
, C2
));
80 EXPECT_FALSE(Context
.flowConditionImplies(FC1
, C2
));
83 TEST_F(DataflowAnalysisContextTest
, JoinFlowConditions
) {
84 auto &C1
= A
.makeAtomRef(A
.makeAtom());
85 auto &C2
= A
.makeAtomRef(A
.makeAtom());
86 auto &C3
= A
.makeAtomRef(A
.makeAtom());
88 Atom FC1
= A
.makeFlowConditionToken();
89 Context
.addFlowConditionConstraint(FC1
, C1
);
90 Context
.addFlowConditionConstraint(FC1
, C3
);
92 Atom FC2
= A
.makeFlowConditionToken();
93 Context
.addFlowConditionConstraint(FC2
, C2
);
94 Context
.addFlowConditionConstraint(FC2
, C3
);
96 Atom FC3
= Context
.joinFlowConditions(FC1
, FC2
);
97 EXPECT_FALSE(Context
.flowConditionImplies(FC3
, C1
));
98 EXPECT_FALSE(Context
.flowConditionImplies(FC3
, C2
));
99 EXPECT_TRUE(Context
.flowConditionImplies(FC3
, C3
));
102 TEST_F(DataflowAnalysisContextTest
, EquivBoolVals
) {
103 auto &X
= A
.makeAtomRef(A
.makeAtom());
104 auto &Y
= A
.makeAtomRef(A
.makeAtom());
105 auto &Z
= A
.makeAtomRef(A
.makeAtom());
106 auto &True
= A
.makeLiteral(true);
107 auto &False
= A
.makeLiteral(false);
110 EXPECT_TRUE(Context
.equivalentFormulas(X
, X
));
112 EXPECT_FALSE(Context
.equivalentFormulas(X
, Y
));
115 EXPECT_FALSE(Context
.equivalentFormulas(A
.makeNot(X
), X
));
117 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeNot(A
.makeNot(X
)), X
));
120 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeOr(X
, X
), X
));
122 EXPECT_FALSE(Context
.equivalentFormulas(A
.makeOr(X
, Y
), X
));
123 // (X || True) == True
124 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeOr(X
, True
), True
));
126 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeOr(X
, False
), X
));
129 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeAnd(X
, X
), X
));
131 EXPECT_FALSE(Context
.equivalentFormulas(A
.makeAnd(X
, Y
), X
));
133 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeAnd(X
, True
), X
));
134 // (X && False) == False
135 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeAnd(X
, False
), False
));
137 // (X || Y) == (Y || X)
138 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeOr(X
, Y
), A
.makeOr(Y
, X
)));
139 // (X && Y) == (Y && X)
140 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeAnd(X
, Y
), A
.makeAnd(Y
, X
)));
142 // ((X || Y) || Z) == (X || (Y || Z))
143 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeOr(A
.makeOr(X
, Y
), Z
),
144 A
.makeOr(X
, A
.makeOr(Y
, Z
))));
145 // ((X && Y) && Z) == (X && (Y && Z))
146 EXPECT_TRUE(Context
.equivalentFormulas(A
.makeAnd(A
.makeAnd(X
, Y
), Z
),
147 A
.makeAnd(X
, A
.makeAnd(Y
, Z
))));