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