1ae60884dSStanislav Gatev //===- unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp ---===//
2ae60884dSStanislav Gatev //
3ae60884dSStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ae60884dSStanislav Gatev // See https://llvm.org/LICENSE.txt for license information.
5ae60884dSStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ae60884dSStanislav Gatev //
7ae60884dSStanislav Gatev //===----------------------------------------------------------------------===//
8ae60884dSStanislav Gatev 
9ae60884dSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
10ae60884dSStanislav Gatev #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
11ae60884dSStanislav Gatev #include "gmock/gmock.h"
12ae60884dSStanislav Gatev #include "gtest/gtest.h"
13ae60884dSStanislav Gatev #include <memory>
14ae60884dSStanislav Gatev 
15ae60884dSStanislav Gatev namespace {
16ae60884dSStanislav Gatev 
17ae60884dSStanislav Gatev using namespace clang;
18ae60884dSStanislav Gatev using namespace dataflow;
19ae60884dSStanislav Gatev 
20ae60884dSStanislav Gatev class DataflowAnalysisContextTest : public ::testing::Test {
21ae60884dSStanislav Gatev protected:
22ae60884dSStanislav Gatev   DataflowAnalysisContextTest()
23ae60884dSStanislav Gatev       : Context(std::make_unique<WatchedLiteralsSolver>()) {}
24ae60884dSStanislav Gatev 
25ae60884dSStanislav Gatev   DataflowAnalysisContext Context;
26ae60884dSStanislav Gatev };
27ae60884dSStanislav Gatev 
28ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest,
29ae60884dSStanislav Gatev        CreateAtomicBoolValueReturnsDistinctValues) {
30ae60884dSStanislav Gatev   auto &X = Context.createAtomicBoolValue();
31ae60884dSStanislav Gatev   auto &Y = Context.createAtomicBoolValue();
32ae60884dSStanislav Gatev   EXPECT_NE(&X, &Y);
33ae60884dSStanislav Gatev }
34ae60884dSStanislav Gatev 
35ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest,
36*00e9d534SWei Yi Tee        GetOrCreateConjunctionReturnsSameExprGivenSameArgs) {
37ae60884dSStanislav Gatev   auto &X = Context.createAtomicBoolValue();
38*00e9d534SWei Yi Tee   auto &XAndX = Context.getOrCreateConjunction(X, X);
39ae60884dSStanislav Gatev   EXPECT_EQ(&XAndX, &X);
40ae60884dSStanislav Gatev }
41ae60884dSStanislav Gatev 
42ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest,
43*00e9d534SWei Yi Tee        GetOrCreateConjunctionReturnsSameExprOnSubsequentCalls) {
44ae60884dSStanislav Gatev   auto &X = Context.createAtomicBoolValue();
45ae60884dSStanislav Gatev   auto &Y = Context.createAtomicBoolValue();
46*00e9d534SWei Yi Tee   auto &XAndY1 = Context.getOrCreateConjunction(X, Y);
47*00e9d534SWei Yi Tee   auto &XAndY2 = Context.getOrCreateConjunction(X, Y);
48ae60884dSStanislav Gatev   EXPECT_EQ(&XAndY1, &XAndY2);
49ae60884dSStanislav Gatev 
50*00e9d534SWei Yi Tee   auto &YAndX = Context.getOrCreateConjunction(Y, X);
51ae60884dSStanislav Gatev   EXPECT_EQ(&XAndY1, &YAndX);
52ae60884dSStanislav Gatev 
53ae60884dSStanislav Gatev   auto &Z = Context.createAtomicBoolValue();
54*00e9d534SWei Yi Tee   auto &XAndZ = Context.getOrCreateConjunction(X, Z);
55ae60884dSStanislav Gatev   EXPECT_NE(&XAndY1, &XAndZ);
56ae60884dSStanislav Gatev }
57ae60884dSStanislav Gatev 
58ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest,
59*00e9d534SWei Yi Tee        GetOrCreateDisjunctionReturnsSameExprGivenSameArgs) {
60ae60884dSStanislav Gatev   auto &X = Context.createAtomicBoolValue();
61*00e9d534SWei Yi Tee   auto &XOrX = Context.getOrCreateDisjunction(X, X);
62ae60884dSStanislav Gatev   EXPECT_EQ(&XOrX, &X);
63ae60884dSStanislav Gatev }
64ae60884dSStanislav Gatev 
65ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest,
66*00e9d534SWei Yi Tee        GetOrCreateDisjunctionReturnsSameExprOnSubsequentCalls) {
67ae60884dSStanislav Gatev   auto &X = Context.createAtomicBoolValue();
68ae60884dSStanislav Gatev   auto &Y = Context.createAtomicBoolValue();
69*00e9d534SWei Yi Tee   auto &XOrY1 = Context.getOrCreateDisjunction(X, Y);
70*00e9d534SWei Yi Tee   auto &XOrY2 = Context.getOrCreateDisjunction(X, Y);
71ae60884dSStanislav Gatev   EXPECT_EQ(&XOrY1, &XOrY2);
72ae60884dSStanislav Gatev 
73*00e9d534SWei Yi Tee   auto &YOrX = Context.getOrCreateDisjunction(Y, X);
74ae60884dSStanislav Gatev   EXPECT_EQ(&XOrY1, &YOrX);
75ae60884dSStanislav Gatev 
76ae60884dSStanislav Gatev   auto &Z = Context.createAtomicBoolValue();
77*00e9d534SWei Yi Tee   auto &XOrZ = Context.getOrCreateDisjunction(X, Z);
78ae60884dSStanislav Gatev   EXPECT_NE(&XOrY1, &XOrZ);
79ae60884dSStanislav Gatev }
80ae60884dSStanislav Gatev 
81ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest,
82*00e9d534SWei Yi Tee        GetOrCreateNegationReturnsSameExprOnSubsequentCalls) {
83ae60884dSStanislav Gatev   auto &X = Context.createAtomicBoolValue();
84*00e9d534SWei Yi Tee   auto &NotX1 = Context.getOrCreateNegation(X);
85*00e9d534SWei Yi Tee   auto &NotX2 = Context.getOrCreateNegation(X);
86ae60884dSStanislav Gatev   EXPECT_EQ(&NotX1, &NotX2);
87ae60884dSStanislav Gatev 
88ae60884dSStanislav Gatev   auto &Y = Context.createAtomicBoolValue();
89*00e9d534SWei Yi Tee   auto &NotY = Context.getOrCreateNegation(Y);
90ae60884dSStanislav Gatev   EXPECT_NE(&NotX1, &NotY);
91ae60884dSStanislav Gatev }
92ae60884dSStanislav Gatev 
93*00e9d534SWei Yi Tee TEST_F(DataflowAnalysisContextTest,
94*00e9d534SWei Yi Tee        GetOrCreateImplicationReturnsTrueGivenSameArgs) {
95*00e9d534SWei Yi Tee   auto &X = Context.createAtomicBoolValue();
96*00e9d534SWei Yi Tee   auto &XImpliesX = Context.getOrCreateImplication(X, X);
97*00e9d534SWei Yi Tee   EXPECT_EQ(&XImpliesX, &Context.getBoolLiteralValue(true));
98*00e9d534SWei Yi Tee }
99*00e9d534SWei Yi Tee 
100*00e9d534SWei Yi Tee TEST_F(DataflowAnalysisContextTest,
101*00e9d534SWei Yi Tee        GetOrCreateImplicationReturnsSameExprOnSubsequentCalls) {
102*00e9d534SWei Yi Tee   auto &X = Context.createAtomicBoolValue();
103*00e9d534SWei Yi Tee   auto &Y = Context.createAtomicBoolValue();
104*00e9d534SWei Yi Tee   auto &XImpliesY1 = Context.getOrCreateImplication(X, Y);
105*00e9d534SWei Yi Tee   auto &XImpliesY2 = Context.getOrCreateImplication(X, Y);
106*00e9d534SWei Yi Tee   EXPECT_EQ(&XImpliesY1, &XImpliesY2);
107*00e9d534SWei Yi Tee 
108*00e9d534SWei Yi Tee   auto &YImpliesX = Context.getOrCreateImplication(Y, X);
109*00e9d534SWei Yi Tee   EXPECT_NE(&XImpliesY1, &YImpliesX);
110*00e9d534SWei Yi Tee 
111*00e9d534SWei Yi Tee   auto &Z = Context.createAtomicBoolValue();
112*00e9d534SWei Yi Tee   auto &XImpliesZ = Context.getOrCreateImplication(X, Z);
113*00e9d534SWei Yi Tee   EXPECT_NE(&XImpliesY1, &XImpliesZ);
114*00e9d534SWei Yi Tee }
115*00e9d534SWei Yi Tee 
116*00e9d534SWei Yi Tee TEST_F(DataflowAnalysisContextTest, GetOrCreateIffReturnsTrueGivenSameArgs) {
117*00e9d534SWei Yi Tee   auto &X = Context.createAtomicBoolValue();
118*00e9d534SWei Yi Tee   auto &XIffX = Context.getOrCreateIff(X, X);
119*00e9d534SWei Yi Tee   EXPECT_EQ(&XIffX, &Context.getBoolLiteralValue(true));
120*00e9d534SWei Yi Tee }
121*00e9d534SWei Yi Tee 
122*00e9d534SWei Yi Tee TEST_F(DataflowAnalysisContextTest,
123*00e9d534SWei Yi Tee        GetOrCreateIffReturnsSameExprOnSubsequentCalls) {
124*00e9d534SWei Yi Tee   auto &X = Context.createAtomicBoolValue();
125*00e9d534SWei Yi Tee   auto &Y = Context.createAtomicBoolValue();
126*00e9d534SWei Yi Tee   auto &XIffY1 = Context.getOrCreateIff(X, Y);
127*00e9d534SWei Yi Tee   auto &XIffY2 = Context.getOrCreateIff(X, Y);
128*00e9d534SWei Yi Tee   EXPECT_EQ(&XIffY1, &XIffY2);
129*00e9d534SWei Yi Tee 
130*00e9d534SWei Yi Tee   auto &YIffX = Context.getOrCreateIff(Y, X);
131*00e9d534SWei Yi Tee   EXPECT_EQ(&XIffY1, &YIffX);
132*00e9d534SWei Yi Tee 
133*00e9d534SWei Yi Tee   auto &Z = Context.createAtomicBoolValue();
134*00e9d534SWei Yi Tee   auto &XIffZ = Context.getOrCreateIff(X, Z);
135*00e9d534SWei Yi Tee   EXPECT_NE(&XIffY1, &XIffZ);
136*00e9d534SWei Yi Tee }
137*00e9d534SWei Yi Tee 
138955a05a2SStanislav Gatev TEST_F(DataflowAnalysisContextTest, EmptyFlowCondition) {
139955a05a2SStanislav Gatev   auto &FC = Context.makeFlowConditionToken();
140955a05a2SStanislav Gatev   auto &C = Context.createAtomicBoolValue();
141955a05a2SStanislav Gatev   EXPECT_FALSE(Context.flowConditionImplies(FC, C));
142955a05a2SStanislav Gatev }
143955a05a2SStanislav Gatev 
144955a05a2SStanislav Gatev TEST_F(DataflowAnalysisContextTest, AddFlowConditionConstraint) {
145955a05a2SStanislav Gatev   auto &FC = Context.makeFlowConditionToken();
146955a05a2SStanislav Gatev   auto &C = Context.createAtomicBoolValue();
147955a05a2SStanislav Gatev   Context.addFlowConditionConstraint(FC, C);
148955a05a2SStanislav Gatev   EXPECT_TRUE(Context.flowConditionImplies(FC, C));
149955a05a2SStanislav Gatev }
150955a05a2SStanislav Gatev 
151955a05a2SStanislav Gatev TEST_F(DataflowAnalysisContextTest, ForkFlowCondition) {
152955a05a2SStanislav Gatev   auto &FC1 = Context.makeFlowConditionToken();
153955a05a2SStanislav Gatev   auto &C1 = Context.createAtomicBoolValue();
154955a05a2SStanislav Gatev   Context.addFlowConditionConstraint(FC1, C1);
155955a05a2SStanislav Gatev 
156955a05a2SStanislav Gatev   // Forked flow condition inherits the constraints of its parent flow
157955a05a2SStanislav Gatev   // condition.
158955a05a2SStanislav Gatev   auto &FC2 = Context.forkFlowCondition(FC1);
159955a05a2SStanislav Gatev   EXPECT_TRUE(Context.flowConditionImplies(FC2, C1));
160955a05a2SStanislav Gatev 
161955a05a2SStanislav Gatev   // Adding a new constraint to the forked flow condition does not affect its
162955a05a2SStanislav Gatev   // parent flow condition.
163955a05a2SStanislav Gatev   auto &C2 = Context.createAtomicBoolValue();
164955a05a2SStanislav Gatev   Context.addFlowConditionConstraint(FC2, C2);
165955a05a2SStanislav Gatev   EXPECT_TRUE(Context.flowConditionImplies(FC2, C2));
166955a05a2SStanislav Gatev   EXPECT_FALSE(Context.flowConditionImplies(FC1, C2));
167955a05a2SStanislav Gatev }
168955a05a2SStanislav Gatev 
169955a05a2SStanislav Gatev TEST_F(DataflowAnalysisContextTest, JoinFlowConditions) {
170955a05a2SStanislav Gatev   auto &C1 = Context.createAtomicBoolValue();
171955a05a2SStanislav Gatev   auto &C2 = Context.createAtomicBoolValue();
172955a05a2SStanislav Gatev   auto &C3 = Context.createAtomicBoolValue();
173955a05a2SStanislav Gatev 
174955a05a2SStanislav Gatev   auto &FC1 = Context.makeFlowConditionToken();
175955a05a2SStanislav Gatev   Context.addFlowConditionConstraint(FC1, C1);
176955a05a2SStanislav Gatev   Context.addFlowConditionConstraint(FC1, C3);
177955a05a2SStanislav Gatev 
178955a05a2SStanislav Gatev   auto &FC2 = Context.makeFlowConditionToken();
179955a05a2SStanislav Gatev   Context.addFlowConditionConstraint(FC2, C2);
180955a05a2SStanislav Gatev   Context.addFlowConditionConstraint(FC2, C3);
181955a05a2SStanislav Gatev 
182955a05a2SStanislav Gatev   auto &FC3 = Context.joinFlowConditions(FC1, FC2);
183955a05a2SStanislav Gatev   EXPECT_FALSE(Context.flowConditionImplies(FC3, C1));
184955a05a2SStanislav Gatev   EXPECT_FALSE(Context.flowConditionImplies(FC3, C2));
185955a05a2SStanislav Gatev   EXPECT_TRUE(Context.flowConditionImplies(FC3, C3));
186955a05a2SStanislav Gatev }
187955a05a2SStanislav Gatev 
18858abe36aSEric Li TEST_F(DataflowAnalysisContextTest, FlowConditionTautologies) {
18958abe36aSEric Li   // Fresh flow condition with empty/no constraints is always true.
19058abe36aSEric Li   auto &FC1 = Context.makeFlowConditionToken();
19158abe36aSEric Li   EXPECT_TRUE(Context.flowConditionIsTautology(FC1));
19258abe36aSEric Li 
19358abe36aSEric Li   // Literal `true` is always true.
19458abe36aSEric Li   auto &FC2 = Context.makeFlowConditionToken();
19558abe36aSEric Li   Context.addFlowConditionConstraint(FC2, Context.getBoolLiteralValue(true));
19658abe36aSEric Li   EXPECT_TRUE(Context.flowConditionIsTautology(FC2));
19758abe36aSEric Li 
19858abe36aSEric Li   // Literal `false` is never true.
19958abe36aSEric Li   auto &FC3 = Context.makeFlowConditionToken();
20058abe36aSEric Li   Context.addFlowConditionConstraint(FC3, Context.getBoolLiteralValue(false));
20158abe36aSEric Li   EXPECT_FALSE(Context.flowConditionIsTautology(FC3));
20258abe36aSEric Li 
20358abe36aSEric Li   // We can't prove that an arbitrary bool A is always true...
20458abe36aSEric Li   auto &C1 = Context.createAtomicBoolValue();
20558abe36aSEric Li   auto &FC4 = Context.makeFlowConditionToken();
20658abe36aSEric Li   Context.addFlowConditionConstraint(FC4, C1);
20758abe36aSEric Li   EXPECT_FALSE(Context.flowConditionIsTautology(FC4));
20858abe36aSEric Li 
20958abe36aSEric Li   // ... but we can prove A || !A is true.
21058abe36aSEric Li   auto &FC5 = Context.makeFlowConditionToken();
21158abe36aSEric Li   Context.addFlowConditionConstraint(
212*00e9d534SWei Yi Tee       FC5, Context.getOrCreateDisjunction(C1, Context.getOrCreateNegation(C1)));
21358abe36aSEric Li   EXPECT_TRUE(Context.flowConditionIsTautology(FC5));
21458abe36aSEric Li }
21558abe36aSEric Li 
216ae60884dSStanislav Gatev } // namespace
217