1 //===- unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp -------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 10 #include "NoopAnalysis.h" 11 #include "TestingSupport.h" 12 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 13 #include "clang/Analysis/FlowSensitive/Value.h" 14 #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h" 15 #include "gmock/gmock.h" 16 #include "gtest/gtest.h" 17 #include <memory> 18 19 namespace { 20 21 using namespace clang; 22 using namespace dataflow; 23 using ::testing::ElementsAre; 24 using ::testing::Pair; 25 26 class EnvironmentTest : public ::testing::Test { 27 DataflowAnalysisContext Context; 28 29 protected: 30 EnvironmentTest() 31 : Context(std::make_unique<WatchedLiteralsSolver>()), Env(Context) {} 32 33 Environment Env; 34 }; 35 36 TEST_F(EnvironmentTest, MakeImplicationReturnsTrueGivenSameArgs) { 37 auto &X = Env.makeAtomicBoolValue(); 38 auto &XEqX = Env.makeImplication(X, X); 39 EXPECT_EQ(&XEqX, &Env.getBoolLiteralValue(true)); 40 } 41 42 TEST_F(EnvironmentTest, MakeIffReturnsTrueGivenSameArgs) { 43 auto &X = Env.makeAtomicBoolValue(); 44 auto &XEqX = Env.makeIff(X, X); 45 EXPECT_EQ(&XEqX, &Env.getBoolLiteralValue(true)); 46 } 47 48 TEST_F(EnvironmentTest, FlowCondition) { 49 EXPECT_TRUE(Env.flowConditionImplies(Env.getBoolLiteralValue(true))); 50 EXPECT_FALSE(Env.flowConditionImplies(Env.getBoolLiteralValue(false))); 51 52 auto &X = Env.makeAtomicBoolValue(); 53 EXPECT_FALSE(Env.flowConditionImplies(X)); 54 55 Env.addToFlowCondition(X); 56 EXPECT_TRUE(Env.flowConditionImplies(X)); 57 58 auto &NotX = Env.makeNot(X); 59 EXPECT_FALSE(Env.flowConditionImplies(NotX)); 60 } 61 62 TEST_F(EnvironmentTest, CreateValueRecursiveType) { 63 using namespace ast_matchers; 64 65 std::string Code = R"cc( 66 struct Recursive { 67 bool X; 68 Recursive *R; 69 }; 70 )cc"; 71 72 auto Unit = 73 tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"}); 74 auto &Context = Unit->getASTContext(); 75 76 ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U); 77 78 auto Results = 79 match(qualType(hasDeclaration(recordDecl( 80 hasName("Recursive"), 81 has(fieldDecl(hasName("R")).bind("field-r"))))) 82 .bind("target"), 83 Context); 84 const QualType *Ty = selectFirst<QualType>("target", Results); 85 const FieldDecl *R = selectFirst<FieldDecl>("field-r", Results); 86 ASSERT_TRUE(Ty != nullptr && !Ty->isNull()); 87 ASSERT_TRUE(R != nullptr); 88 89 // Verify that the struct and the field (`R`) with first appearance of the 90 // type is created successfully. 91 Value *Val = Env.createValue(*Ty); 92 ASSERT_NE(Val, nullptr); 93 StructValue *SVal = clang::dyn_cast<StructValue>(Val); 94 ASSERT_NE(SVal, nullptr); 95 Val = SVal->getChild(*R); 96 ASSERT_NE(Val, nullptr); 97 PointerValue *PV = clang::dyn_cast<PointerValue>(Val); 98 EXPECT_NE(PV, nullptr); 99 } 100 101 } // namespace 102