xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/TransferBranchTest.cpp (revision 6b991ba486b64f09e7d90ebc1fc2118ab48c8bff)
1 //===- unittests/Analysis/FlowSensitive/SignAnalysisTest.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 //  This file defines a test for the transferBranch function of the
10 //  TypeErasedDataflowAnalysis.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "TestingSupport.h"
15 #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Testing/Annotations/Annotations.h"
19 #include "llvm/Testing/Support/Error.h"
20 #include "gtest/gtest.h"
21 #include <optional>
22 
23 namespace clang::dataflow::test {
24 namespace {
25 
26 using namespace ast_matchers;
27 
28 struct TestLattice {
29   std::optional<bool> Branch;
bottomclang::dataflow::test::__anonbe4d82700111::TestLattice30   static TestLattice bottom() { return {}; }
31 
32   // Does not matter for this test, but we must provide some definition of join.
joinclang::dataflow::test::__anonbe4d82700111::TestLattice33   LatticeJoinEffect join(const TestLattice &Other) {
34     return LatticeJoinEffect::Unchanged;
35   }
operator ==(const TestLattice & Lhs,const TestLattice & Rhs)36   friend bool operator==(const TestLattice &Lhs, const TestLattice &Rhs) {
37     return Lhs.Branch == Rhs.Branch;
38   }
39 };
40 
41 class TestPropagationAnalysis
42     : public DataflowAnalysis<TestPropagationAnalysis, TestLattice> {
43 public:
TestPropagationAnalysis(ASTContext & Context)44   explicit TestPropagationAnalysis(ASTContext &Context)
45       : DataflowAnalysis<TestPropagationAnalysis, TestLattice>(Context) {}
initialElement()46   static TestLattice initialElement() { return TestLattice::bottom(); }
transfer(const CFGElement &,TestLattice &,Environment &)47   void transfer(const CFGElement &, TestLattice &, Environment &) {}
transferBranch(bool Branch,const Stmt * S,TestLattice & L,Environment & Env)48   void transferBranch(bool Branch, const Stmt *S, TestLattice &L,
49                       Environment &Env) {
50     L.Branch = Branch;
51   }
52 };
53 
54 using ::testing::UnorderedElementsAre;
55 
56 template <typename Matcher>
runDataflow(llvm::StringRef Code,Matcher VerifyResults,LangStandard::Kind Std=LangStandard::lang_cxx17,llvm::StringRef TargetFun="fun")57 void runDataflow(llvm::StringRef Code, Matcher VerifyResults,
58                  LangStandard::Kind Std = LangStandard::lang_cxx17,
59                  llvm::StringRef TargetFun = "fun") {
60   using ast_matchers::hasName;
61   ASSERT_THAT_ERROR(
62       checkDataflow<TestPropagationAnalysis>(
63           AnalysisInputs<TestPropagationAnalysis>(
64               Code, hasName(TargetFun),
65               [](ASTContext &C, Environment &) {
66                 return TestPropagationAnalysis(C);
67               })
68               .withASTBuildArgs(
69                   {"-fsyntax-only", "-fno-delayed-template-parsing",
70                    "-std=" +
71                        std::string(LangStandard::getLangStandardForKind(Std)
72                                        .getName())}),
73           VerifyResults),
74       llvm::Succeeded());
75 }
76 
77 template <typename LatticeT>
getLatticeAtAnnotation(const llvm::StringMap<DataflowAnalysisState<LatticeT>> & AnnotationStates,llvm::StringRef Annotation)78 const LatticeT &getLatticeAtAnnotation(
79     const llvm::StringMap<DataflowAnalysisState<LatticeT>> &AnnotationStates,
80     llvm::StringRef Annotation) {
81   auto It = AnnotationStates.find(Annotation);
82   assert(It != AnnotationStates.end());
83   return It->getValue().Lattice;
84 }
85 
TEST(TransferBranchTest,IfElse)86 TEST(TransferBranchTest, IfElse) {
87   std::string Code = R"(
88     void fun(int a) {
89       if (a > 0) {
90         (void)1;
91         // [[p]]
92       } else {
93         (void)0;
94         // [[q]]
95       }
96     }
97   )";
98   runDataflow(
99       Code,
100       [](const llvm::StringMap<DataflowAnalysisState<TestLattice>> &Results,
101          const AnalysisOutputs &) {
102         ASSERT_THAT(Results.keys(), UnorderedElementsAre("p", "q"));
103 
104         const TestLattice &LP = getLatticeAtAnnotation(Results, "p");
105         EXPECT_THAT(LP.Branch, std::make_optional(true));
106 
107         const TestLattice &LQ = getLatticeAtAnnotation(Results, "q");
108         EXPECT_THAT(LQ.Branch, std::make_optional(false));
109       },
110       LangStandard::lang_cxx17);
111 }
112 
113 } // namespace
114 } // namespace clang::dataflow::test
115