blob: ef78131dd72a3a639646d429283cb9bc0247b862 [file] [log] [blame]
//===- unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a test for the transferBranch function of the
// TypeErasedDataflowAnalysis.
//
//===----------------------------------------------------------------------===//
#include "TestingSupport.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/Error.h"
#include "llvm/Testing/Annotations/Annotations.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
#include <optional>
namespace clang::dataflow::test {
namespace {
using namespace ast_matchers;
struct TestLattice {
std::optional<bool> Branch;
static TestLattice bottom() { return {}; }
// Does not matter for this test, but we must provide some definition of join.
LatticeJoinEffect join(const TestLattice &Other) {
return LatticeJoinEffect::Unchanged;
}
friend bool operator==(const TestLattice &Lhs, const TestLattice &Rhs) {
return Lhs.Branch == Rhs.Branch;
}
};
class TestPropagationAnalysis
: public DataflowAnalysis<TestPropagationAnalysis, TestLattice> {
public:
explicit TestPropagationAnalysis(ASTContext &Context)
: DataflowAnalysis<TestPropagationAnalysis, TestLattice>(Context) {}
static TestLattice initialElement() { return TestLattice::bottom(); }
void transfer(const CFGElement &, TestLattice &, Environment &) {}
void transferBranch(bool Branch, const Stmt *S, TestLattice &L,
Environment &Env) {
L.Branch = Branch;
}
};
using ::testing::UnorderedElementsAre;
template <typename Matcher>
void runDataflow(llvm::StringRef Code, Matcher VerifyResults,
LangStandard::Kind Std = LangStandard::lang_cxx17,
llvm::StringRef TargetFun = "fun") {
using ast_matchers::hasName;
ASSERT_THAT_ERROR(
checkDataflow<TestPropagationAnalysis>(
AnalysisInputs<TestPropagationAnalysis>(
Code, hasName(TargetFun),
[](ASTContext &C, Environment &) {
return TestPropagationAnalysis(C);
})
.withASTBuildArgs(
{"-fsyntax-only", "-fno-delayed-template-parsing",
"-std=" +
std::string(LangStandard::getLangStandardForKind(Std)
.getName())}),
VerifyResults),
llvm::Succeeded());
}
template <typename LatticeT>
const LatticeT &getLatticeAtAnnotation(
const llvm::StringMap<DataflowAnalysisState<LatticeT>> &AnnotationStates,
llvm::StringRef Annotation) {
auto It = AnnotationStates.find(Annotation);
assert(It != AnnotationStates.end());
return It->getValue().Lattice;
}
TEST(TransferBranchTest, IfElse) {
std::string Code = R"(
void fun(int a) {
if (a > 0) {
(void)1;
// [[p]]
} else {
(void)0;
// [[q]]
}
}
)";
runDataflow(
Code,
[](const llvm::StringMap<DataflowAnalysisState<TestLattice>> &Results,
const AnalysisOutputs &) {
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p", "q"));
const TestLattice &LP = getLatticeAtAnnotation(Results, "p");
EXPECT_THAT(LP.Branch, std::make_optional(true));
const TestLattice &LQ = getLatticeAtAnnotation(Results, "q");
EXPECT_THAT(LQ.Branch, std::make_optional(false));
},
LangStandard::lang_cxx17);
}
} // namespace
} // namespace clang::dataflow::test