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 "TestingSupport.h"
11 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
12 #include "clang/Analysis/FlowSensitive/NoopAnalysis.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:
EnvironmentTest()30   EnvironmentTest()
31       : Context(std::make_unique<WatchedLiteralsSolver>()), Env(Context) {}
32 
33   Environment Env;
34 };
35 
TEST_F(EnvironmentTest,FlowCondition)36 TEST_F(EnvironmentTest, FlowCondition) {
37   EXPECT_TRUE(Env.flowConditionImplies(Env.getBoolLiteralValue(true)));
38   EXPECT_FALSE(Env.flowConditionImplies(Env.getBoolLiteralValue(false)));
39 
40   auto &X = Env.makeAtomicBoolValue();
41   EXPECT_FALSE(Env.flowConditionImplies(X));
42 
43   Env.addToFlowCondition(X);
44   EXPECT_TRUE(Env.flowConditionImplies(X));
45 
46   auto &NotX = Env.makeNot(X);
47   EXPECT_FALSE(Env.flowConditionImplies(NotX));
48 }
49 
TEST_F(EnvironmentTest,CreateValueRecursiveType)50 TEST_F(EnvironmentTest, CreateValueRecursiveType) {
51   using namespace ast_matchers;
52 
53   std::string Code = R"cc(
54     struct Recursive {
55       bool X;
56       Recursive *R;
57     };
58   )cc";
59 
60   auto Unit =
61       tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
62   auto &Context = Unit->getASTContext();
63 
64   ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
65 
66   auto Results =
67       match(qualType(hasDeclaration(recordDecl(
68                          hasName("Recursive"),
69                          has(fieldDecl(hasName("R")).bind("field-r")))))
70                 .bind("target"),
71             Context);
72   const QualType *Ty = selectFirst<QualType>("target", Results);
73   const FieldDecl *R = selectFirst<FieldDecl>("field-r", Results);
74   ASSERT_TRUE(Ty != nullptr && !Ty->isNull());
75   ASSERT_TRUE(R != nullptr);
76 
77   // Verify that the struct and the field (`R`) with first appearance of the
78   // type is created successfully.
79   Value *Val = Env.createValue(*Ty);
80   ASSERT_NE(Val, nullptr);
81   StructValue *SVal = clang::dyn_cast<StructValue>(Val);
82   ASSERT_NE(SVal, nullptr);
83   Val = SVal->getChild(*R);
84   ASSERT_NE(Val, nullptr);
85   PointerValue *PV = clang::dyn_cast<PointerValue>(Val);
86   EXPECT_NE(PV, nullptr);
87 }
88 
89 } // namespace
90