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