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