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, 3600e9d534SWei Yi Tee GetOrCreateConjunctionReturnsSameExprGivenSameArgs) { 37ae60884dSStanislav Gatev auto &X = Context.createAtomicBoolValue(); 3800e9d534SWei Yi Tee auto &XAndX = Context.getOrCreateConjunction(X, X); 39ae60884dSStanislav Gatev EXPECT_EQ(&XAndX, &X); 40ae60884dSStanislav Gatev } 41ae60884dSStanislav Gatev 42ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest, 4300e9d534SWei Yi Tee GetOrCreateConjunctionReturnsSameExprOnSubsequentCalls) { 44ae60884dSStanislav Gatev auto &X = Context.createAtomicBoolValue(); 45ae60884dSStanislav Gatev auto &Y = Context.createAtomicBoolValue(); 4600e9d534SWei Yi Tee auto &XAndY1 = Context.getOrCreateConjunction(X, Y); 4700e9d534SWei Yi Tee auto &XAndY2 = Context.getOrCreateConjunction(X, Y); 48ae60884dSStanislav Gatev EXPECT_EQ(&XAndY1, &XAndY2); 49ae60884dSStanislav Gatev 5000e9d534SWei Yi Tee auto &YAndX = Context.getOrCreateConjunction(Y, X); 51ae60884dSStanislav Gatev EXPECT_EQ(&XAndY1, &YAndX); 52ae60884dSStanislav Gatev 53ae60884dSStanislav Gatev auto &Z = Context.createAtomicBoolValue(); 5400e9d534SWei Yi Tee auto &XAndZ = Context.getOrCreateConjunction(X, Z); 55ae60884dSStanislav Gatev EXPECT_NE(&XAndY1, &XAndZ); 56ae60884dSStanislav Gatev } 57ae60884dSStanislav Gatev 58ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest, 5900e9d534SWei Yi Tee GetOrCreateDisjunctionReturnsSameExprGivenSameArgs) { 60ae60884dSStanislav Gatev auto &X = Context.createAtomicBoolValue(); 6100e9d534SWei Yi Tee auto &XOrX = Context.getOrCreateDisjunction(X, X); 62ae60884dSStanislav Gatev EXPECT_EQ(&XOrX, &X); 63ae60884dSStanislav Gatev } 64ae60884dSStanislav Gatev 65ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest, 6600e9d534SWei Yi Tee GetOrCreateDisjunctionReturnsSameExprOnSubsequentCalls) { 67ae60884dSStanislav Gatev auto &X = Context.createAtomicBoolValue(); 68ae60884dSStanislav Gatev auto &Y = Context.createAtomicBoolValue(); 6900e9d534SWei Yi Tee auto &XOrY1 = Context.getOrCreateDisjunction(X, Y); 7000e9d534SWei Yi Tee auto &XOrY2 = Context.getOrCreateDisjunction(X, Y); 71ae60884dSStanislav Gatev EXPECT_EQ(&XOrY1, &XOrY2); 72ae60884dSStanislav Gatev 7300e9d534SWei Yi Tee auto &YOrX = Context.getOrCreateDisjunction(Y, X); 74ae60884dSStanislav Gatev EXPECT_EQ(&XOrY1, &YOrX); 75ae60884dSStanislav Gatev 76ae60884dSStanislav Gatev auto &Z = Context.createAtomicBoolValue(); 7700e9d534SWei Yi Tee auto &XOrZ = Context.getOrCreateDisjunction(X, Z); 78ae60884dSStanislav Gatev EXPECT_NE(&XOrY1, &XOrZ); 79ae60884dSStanislav Gatev } 80ae60884dSStanislav Gatev 81ae60884dSStanislav Gatev TEST_F(DataflowAnalysisContextTest, 8200e9d534SWei Yi Tee GetOrCreateNegationReturnsSameExprOnSubsequentCalls) { 83ae60884dSStanislav Gatev auto &X = Context.createAtomicBoolValue(); 8400e9d534SWei Yi Tee auto &NotX1 = Context.getOrCreateNegation(X); 8500e9d534SWei Yi Tee auto &NotX2 = Context.getOrCreateNegation(X); 86ae60884dSStanislav Gatev EXPECT_EQ(&NotX1, &NotX2); 87ae60884dSStanislav Gatev 88ae60884dSStanislav Gatev auto &Y = Context.createAtomicBoolValue(); 8900e9d534SWei Yi Tee auto &NotY = Context.getOrCreateNegation(Y); 90ae60884dSStanislav Gatev EXPECT_NE(&NotX1, &NotY); 91ae60884dSStanislav Gatev } 92ae60884dSStanislav Gatev 9300e9d534SWei Yi Tee TEST_F(DataflowAnalysisContextTest, 9400e9d534SWei Yi Tee GetOrCreateImplicationReturnsTrueGivenSameArgs) { 9500e9d534SWei Yi Tee auto &X = Context.createAtomicBoolValue(); 9600e9d534SWei Yi Tee auto &XImpliesX = Context.getOrCreateImplication(X, X); 9700e9d534SWei Yi Tee EXPECT_EQ(&XImpliesX, &Context.getBoolLiteralValue(true)); 9800e9d534SWei Yi Tee } 9900e9d534SWei Yi Tee 10000e9d534SWei Yi Tee TEST_F(DataflowAnalysisContextTest, 10100e9d534SWei Yi Tee GetOrCreateImplicationReturnsSameExprOnSubsequentCalls) { 10200e9d534SWei Yi Tee auto &X = Context.createAtomicBoolValue(); 10300e9d534SWei Yi Tee auto &Y = Context.createAtomicBoolValue(); 10400e9d534SWei Yi Tee auto &XImpliesY1 = Context.getOrCreateImplication(X, Y); 10500e9d534SWei Yi Tee auto &XImpliesY2 = Context.getOrCreateImplication(X, Y); 10600e9d534SWei Yi Tee EXPECT_EQ(&XImpliesY1, &XImpliesY2); 10700e9d534SWei Yi Tee 10800e9d534SWei Yi Tee auto &YImpliesX = Context.getOrCreateImplication(Y, X); 10900e9d534SWei Yi Tee EXPECT_NE(&XImpliesY1, &YImpliesX); 11000e9d534SWei Yi Tee 11100e9d534SWei Yi Tee auto &Z = Context.createAtomicBoolValue(); 11200e9d534SWei Yi Tee auto &XImpliesZ = Context.getOrCreateImplication(X, Z); 11300e9d534SWei Yi Tee EXPECT_NE(&XImpliesY1, &XImpliesZ); 11400e9d534SWei Yi Tee } 11500e9d534SWei Yi Tee 11600e9d534SWei Yi Tee TEST_F(DataflowAnalysisContextTest, GetOrCreateIffReturnsTrueGivenSameArgs) { 11700e9d534SWei Yi Tee auto &X = Context.createAtomicBoolValue(); 11800e9d534SWei Yi Tee auto &XIffX = Context.getOrCreateIff(X, X); 11900e9d534SWei Yi Tee EXPECT_EQ(&XIffX, &Context.getBoolLiteralValue(true)); 12000e9d534SWei Yi Tee } 12100e9d534SWei Yi Tee 12200e9d534SWei Yi Tee TEST_F(DataflowAnalysisContextTest, 12300e9d534SWei Yi Tee GetOrCreateIffReturnsSameExprOnSubsequentCalls) { 12400e9d534SWei Yi Tee auto &X = Context.createAtomicBoolValue(); 12500e9d534SWei Yi Tee auto &Y = Context.createAtomicBoolValue(); 12600e9d534SWei Yi Tee auto &XIffY1 = Context.getOrCreateIff(X, Y); 12700e9d534SWei Yi Tee auto &XIffY2 = Context.getOrCreateIff(X, Y); 12800e9d534SWei Yi Tee EXPECT_EQ(&XIffY1, &XIffY2); 12900e9d534SWei Yi Tee 13000e9d534SWei Yi Tee auto &YIffX = Context.getOrCreateIff(Y, X); 13100e9d534SWei Yi Tee EXPECT_EQ(&XIffY1, &YIffX); 13200e9d534SWei Yi Tee 13300e9d534SWei Yi Tee auto &Z = Context.createAtomicBoolValue(); 13400e9d534SWei Yi Tee auto &XIffZ = Context.getOrCreateIff(X, Z); 13500e9d534SWei Yi Tee EXPECT_NE(&XIffY1, &XIffZ); 13600e9d534SWei Yi Tee } 13700e9d534SWei 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( 21200e9d534SWei Yi Tee FC5, Context.getOrCreateDisjunction(C1, Context.getOrCreateNegation(C1))); 21358abe36aSEric Li EXPECT_TRUE(Context.flowConditionIsTautology(FC5)); 21458abe36aSEric Li } 21558abe36aSEric Li 216*0f65a3e6SWei Yi Tee TEST_F(DataflowAnalysisContextTest, EquivBoolVals) { 217*0f65a3e6SWei Yi Tee auto &X = Context.createAtomicBoolValue(); 218*0f65a3e6SWei Yi Tee auto &Y = Context.createAtomicBoolValue(); 219*0f65a3e6SWei Yi Tee auto &Z = Context.createAtomicBoolValue(); 220*0f65a3e6SWei Yi Tee auto &True = Context.getBoolLiteralValue(true); 221*0f65a3e6SWei Yi Tee auto &False = Context.getBoolLiteralValue(false); 222*0f65a3e6SWei Yi Tee 223*0f65a3e6SWei Yi Tee // X == X 224*0f65a3e6SWei Yi Tee EXPECT_TRUE(Context.equivalentBoolValues(X, X)); 225*0f65a3e6SWei Yi Tee // X != Y 226*0f65a3e6SWei Yi Tee EXPECT_FALSE(Context.equivalentBoolValues(X, Y)); 227*0f65a3e6SWei Yi Tee 228*0f65a3e6SWei Yi Tee // !X != X 229*0f65a3e6SWei Yi Tee EXPECT_FALSE(Context.equivalentBoolValues(Context.getOrCreateNegation(X), X)); 230*0f65a3e6SWei Yi Tee // !(!X) = X 231*0f65a3e6SWei Yi Tee EXPECT_TRUE(Context.equivalentBoolValues( 232*0f65a3e6SWei Yi Tee Context.getOrCreateNegation(Context.getOrCreateNegation(X)), X)); 233*0f65a3e6SWei Yi Tee 234*0f65a3e6SWei Yi Tee // (X || X) == X 235*0f65a3e6SWei Yi Tee EXPECT_TRUE( 236*0f65a3e6SWei Yi Tee Context.equivalentBoolValues(Context.getOrCreateDisjunction(X, X), X)); 237*0f65a3e6SWei Yi Tee // (X || Y) != X 238*0f65a3e6SWei Yi Tee EXPECT_FALSE( 239*0f65a3e6SWei Yi Tee Context.equivalentBoolValues(Context.getOrCreateDisjunction(X, Y), X)); 240*0f65a3e6SWei Yi Tee // (X || True) == True 241*0f65a3e6SWei Yi Tee EXPECT_TRUE(Context.equivalentBoolValues( 242*0f65a3e6SWei Yi Tee Context.getOrCreateDisjunction(X, True), True)); 243*0f65a3e6SWei Yi Tee // (X || False) == X 244*0f65a3e6SWei Yi Tee EXPECT_TRUE(Context.equivalentBoolValues( 245*0f65a3e6SWei Yi Tee Context.getOrCreateDisjunction(X, False), X)); 246*0f65a3e6SWei Yi Tee 247*0f65a3e6SWei Yi Tee // (X && X) == X 248*0f65a3e6SWei Yi Tee EXPECT_TRUE( 249*0f65a3e6SWei Yi Tee Context.equivalentBoolValues(Context.getOrCreateConjunction(X, X), X)); 250*0f65a3e6SWei Yi Tee // (X && Y) != X 251*0f65a3e6SWei Yi Tee EXPECT_FALSE( 252*0f65a3e6SWei Yi Tee Context.equivalentBoolValues(Context.getOrCreateConjunction(X, Y), X)); 253*0f65a3e6SWei Yi Tee // (X && True) == X 254*0f65a3e6SWei Yi Tee EXPECT_TRUE( 255*0f65a3e6SWei Yi Tee Context.equivalentBoolValues(Context.getOrCreateConjunction(X, True), X)); 256*0f65a3e6SWei Yi Tee // (X && False) == False 257*0f65a3e6SWei Yi Tee EXPECT_TRUE(Context.equivalentBoolValues( 258*0f65a3e6SWei Yi Tee Context.getOrCreateConjunction(X, False), False)); 259*0f65a3e6SWei Yi Tee 260*0f65a3e6SWei Yi Tee // (X || Y) == (Y || X) 261*0f65a3e6SWei Yi Tee EXPECT_TRUE( 262*0f65a3e6SWei Yi Tee Context.equivalentBoolValues(Context.getOrCreateDisjunction(X, Y), 263*0f65a3e6SWei Yi Tee Context.getOrCreateDisjunction(Y, X))); 264*0f65a3e6SWei Yi Tee // (X && Y) == (Y && X) 265*0f65a3e6SWei Yi Tee EXPECT_TRUE( 266*0f65a3e6SWei Yi Tee Context.equivalentBoolValues(Context.getOrCreateConjunction(X, Y), 267*0f65a3e6SWei Yi Tee Context.getOrCreateConjunction(Y, X))); 268*0f65a3e6SWei Yi Tee 269*0f65a3e6SWei Yi Tee // ((X || Y) || Z) == (X || (Y || Z)) 270*0f65a3e6SWei Yi Tee EXPECT_TRUE(Context.equivalentBoolValues( 271*0f65a3e6SWei Yi Tee Context.getOrCreateDisjunction(Context.getOrCreateDisjunction(X, Y), Z), 272*0f65a3e6SWei Yi Tee Context.getOrCreateDisjunction(X, Context.getOrCreateDisjunction(Y, Z)))); 273*0f65a3e6SWei Yi Tee // ((X && Y) && Z) == (X && (Y && Z)) 274*0f65a3e6SWei Yi Tee EXPECT_TRUE(Context.equivalentBoolValues( 275*0f65a3e6SWei Yi Tee Context.getOrCreateConjunction(Context.getOrCreateConjunction(X, Y), Z), 276*0f65a3e6SWei Yi Tee Context.getOrCreateConjunction(X, Context.getOrCreateConjunction(Y, Z)))); 277*0f65a3e6SWei Yi Tee } 278*0f65a3e6SWei Yi Tee 279ae60884dSStanislav Gatev } // namespace 280