148f97e57SSam McCall #include "TestingSupport.h"
248f97e57SSam McCall #include "clang/ASTMatchers/ASTMatchers.h"
348f97e57SSam McCall #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
448f97e57SSam McCall #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
548f97e57SSam McCall #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
648f97e57SSam McCall #include "llvm/Testing/Support/Error.h"
748f97e57SSam McCall #include "gtest/gtest.h"
848f97e57SSam McCall
948f97e57SSam McCall namespace clang::dataflow::test {
1048f97e57SSam McCall namespace {
11a443b3d1SSam McCall using testing::HasSubstr;
1248f97e57SSam McCall
1348f97e57SSam McCall struct TestLattice {
1448f97e57SSam McCall int Elements = 0;
1548f97e57SSam McCall int Branches = 0;
1648f97e57SSam McCall int Joins = 0;
1748f97e57SSam McCall
joinclang::dataflow::test::__anond8cfe21d0111::TestLattice1848f97e57SSam McCall LatticeJoinEffect join(const TestLattice &Other) {
1948f97e57SSam McCall if (Joins < 3) {
2048f97e57SSam McCall ++Joins;
2148f97e57SSam McCall Elements += Other.Elements;
2248f97e57SSam McCall Branches += Other.Branches;
2348f97e57SSam McCall return LatticeJoinEffect::Changed;
2448f97e57SSam McCall }
2548f97e57SSam McCall return LatticeJoinEffect::Unchanged;
2648f97e57SSam McCall }
operator ==(const TestLattice & LHS,const TestLattice & RHS)2748f97e57SSam McCall friend bool operator==(const TestLattice &LHS, const TestLattice &RHS) {
2848f97e57SSam McCall return std::tie(LHS.Elements, LHS.Branches, LHS.Joins) ==
2948f97e57SSam McCall std::tie(RHS.Elements, RHS.Branches, RHS.Joins);
3048f97e57SSam McCall }
3148f97e57SSam McCall };
3248f97e57SSam McCall
3348f97e57SSam McCall class TestAnalysis : public DataflowAnalysis<TestAnalysis, TestLattice> {
3448f97e57SSam McCall public:
3548f97e57SSam McCall using DataflowAnalysis::DataflowAnalysis;
3648f97e57SSam McCall
initialElement()3748f97e57SSam McCall static TestLattice initialElement() { return TestLattice{}; }
transfer(const CFGElement &,TestLattice & L,Environment & E)3848f97e57SSam McCall void transfer(const CFGElement &, TestLattice &L, Environment &E) {
392cdb6b84SSamira Bazuzi E.getDataflowAnalysisContext().getOptions().Log->log(
402cdb6b84SSamira Bazuzi [](llvm::raw_ostream &OS) { OS << "transfer()"; });
4148f97e57SSam McCall ++L.Elements;
4248f97e57SSam McCall }
transferBranch(bool Branch,const Stmt * S,TestLattice & L,Environment & E)4348f97e57SSam McCall void transferBranch(bool Branch, const Stmt *S, TestLattice &L,
4448f97e57SSam McCall Environment &E) {
452cdb6b84SSamira Bazuzi E.getDataflowAnalysisContext().getOptions().Log->log(
462cdb6b84SSamira Bazuzi [&](llvm::raw_ostream &OS) {
4748f97e57SSam McCall OS << "transferBranch(" << Branch << ")";
4848f97e57SSam McCall });
4948f97e57SSam McCall ++L.Branches;
5048f97e57SSam McCall }
5148f97e57SSam McCall };
5248f97e57SSam McCall
5348f97e57SSam McCall class TestLogger : public Logger {
5448f97e57SSam McCall public:
TestLogger(std::string & S)5548f97e57SSam McCall TestLogger(std::string &S) : OS(S) {}
5648f97e57SSam McCall
5748f97e57SSam McCall private:
5848f97e57SSam McCall llvm::raw_string_ostream OS;
5948f97e57SSam McCall
beginAnalysis(const AdornedCFG &,TypeErasedDataflowAnalysis &)60*59ff3adcSmartinboehme void beginAnalysis(const AdornedCFG &,
6148f97e57SSam McCall TypeErasedDataflowAnalysis &) override {
6248f97e57SSam McCall logText("beginAnalysis()");
6348f97e57SSam McCall }
endAnalysis()6448f97e57SSam McCall void endAnalysis() override { logText("\nendAnalysis()"); }
6548f97e57SSam McCall
enterBlock(const CFGBlock & B,bool PostVisit)66ed65ced2Smartinboehme void enterBlock(const CFGBlock &B, bool PostVisit) override {
67ed65ced2Smartinboehme OS << "\nenterBlock(" << B.BlockID << ", " << (PostVisit ? "true" : "false")
68ed65ced2Smartinboehme << ")\n";
6948f97e57SSam McCall }
enterElement(const CFGElement & E)7048f97e57SSam McCall void enterElement(const CFGElement &E) override {
7148f97e57SSam McCall // we don't want the trailing \n
7248f97e57SSam McCall std::string S;
7348f97e57SSam McCall llvm::raw_string_ostream SS(S);
7448f97e57SSam McCall E.dumpToStream(SS);
7548f97e57SSam McCall
7648f97e57SSam McCall OS << "enterElement(" << llvm::StringRef(S).trim() << ")\n";
7748f97e57SSam McCall }
recordState(TypeErasedDataflowAnalysisState & S)7848f97e57SSam McCall void recordState(TypeErasedDataflowAnalysisState &S) override {
7948f97e57SSam McCall const TestLattice &L = llvm::any_cast<TestLattice>(S.Lattice.Value);
8048f97e57SSam McCall OS << "recordState(Elements=" << L.Elements << ", Branches=" << L.Branches
8148f97e57SSam McCall << ", Joins=" << L.Joins << ")\n";
8248f97e57SSam McCall }
8348f97e57SSam McCall /// Records that the analysis state for the current block is now final.
blockConverged()8448f97e57SSam McCall void blockConverged() override { logText("blockConverged()"); }
8548f97e57SSam McCall
logText(llvm::StringRef Text)8648f97e57SSam McCall void logText(llvm::StringRef Text) override { OS << Text << "\n"; }
8748f97e57SSam McCall };
8848f97e57SSam McCall
makeInputs()89a443b3d1SSam McCall AnalysisInputs<TestAnalysis> makeInputs() {
9048f97e57SSam McCall const char *Code = R"cpp(
9148f97e57SSam McCall int target(bool b, int p, int q) {
9248f97e57SSam McCall return b ? p : q;
9348f97e57SSam McCall }
9448f97e57SSam McCall )cpp";
95a443b3d1SSam McCall static const std::vector<std::string> Args = {
96a443b3d1SSam McCall "-fsyntax-only", "-fno-delayed-template-parsing", "-std=c++17"};
9748f97e57SSam McCall
9848f97e57SSam McCall auto Inputs = AnalysisInputs<TestAnalysis>(
9948f97e57SSam McCall Code, ast_matchers::hasName("target"),
10048f97e57SSam McCall [](ASTContext &C, Environment &) { return TestAnalysis(C); });
10148f97e57SSam McCall Inputs.ASTBuildArgs = Args;
102a443b3d1SSam McCall return Inputs;
103a443b3d1SSam McCall }
104a443b3d1SSam McCall
TEST(LoggerTest,Sequence)105a443b3d1SSam McCall TEST(LoggerTest, Sequence) {
106a443b3d1SSam McCall auto Inputs = makeInputs();
10748f97e57SSam McCall std::string Log;
10848f97e57SSam McCall TestLogger Logger(Log);
10948f97e57SSam McCall Inputs.BuiltinOptions.Log = &Logger;
11048f97e57SSam McCall
11148f97e57SSam McCall ASSERT_THAT_ERROR(checkDataflow<TestAnalysis>(std::move(Inputs),
11248f97e57SSam McCall [](const AnalysisOutputs &) {}),
11348f97e57SSam McCall llvm::Succeeded());
11448f97e57SSam McCall
11548f97e57SSam McCall EXPECT_EQ(Log, R"(beginAnalysis()
11648f97e57SSam McCall
117ed65ced2Smartinboehme enterBlock(4, false)
11848f97e57SSam McCall recordState(Elements=0, Branches=0, Joins=0)
11948f97e57SSam McCall enterElement(b)
12048f97e57SSam McCall transfer()
12148f97e57SSam McCall recordState(Elements=1, Branches=0, Joins=0)
12248f97e57SSam McCall enterElement(b (ImplicitCastExpr, LValueToRValue, _Bool))
12348f97e57SSam McCall transfer()
12448f97e57SSam McCall recordState(Elements=2, Branches=0, Joins=0)
125ccf1e322Smartinboehme recordState(Elements=2, Branches=0, Joins=0)
12648f97e57SSam McCall
127ed65ced2Smartinboehme enterBlock(2, false)
12848f97e57SSam McCall transferBranch(1)
12948f97e57SSam McCall recordState(Elements=2, Branches=1, Joins=0)
13048f97e57SSam McCall enterElement(p)
13148f97e57SSam McCall transfer()
13248f97e57SSam McCall recordState(Elements=3, Branches=1, Joins=0)
13348f97e57SSam McCall
1342c5a0d39SYitzhak Mandelbaum enterBlock(3, false)
1352c5a0d39SYitzhak Mandelbaum transferBranch(0)
1362c5a0d39SYitzhak Mandelbaum recordState(Elements=2, Branches=1, Joins=0)
1372c5a0d39SYitzhak Mandelbaum enterElement(q)
1382c5a0d39SYitzhak Mandelbaum transfer()
1392c5a0d39SYitzhak Mandelbaum recordState(Elements=3, Branches=1, Joins=0)
1402c5a0d39SYitzhak Mandelbaum
141ed65ced2Smartinboehme enterBlock(1, false)
14248f97e57SSam McCall recordState(Elements=6, Branches=2, Joins=1)
14348f97e57SSam McCall enterElement(b ? p : q)
14448f97e57SSam McCall transfer()
14548f97e57SSam McCall recordState(Elements=7, Branches=2, Joins=1)
14648f97e57SSam McCall enterElement(b ? p : q (ImplicitCastExpr, LValueToRValue, int))
14748f97e57SSam McCall transfer()
14848f97e57SSam McCall recordState(Elements=8, Branches=2, Joins=1)
14948f97e57SSam McCall enterElement(return b ? p : q;)
15048f97e57SSam McCall transfer()
15148f97e57SSam McCall recordState(Elements=9, Branches=2, Joins=1)
15248f97e57SSam McCall
153ed65ced2Smartinboehme enterBlock(0, false)
15448f97e57SSam McCall recordState(Elements=9, Branches=2, Joins=1)
15548f97e57SSam McCall
15648f97e57SSam McCall endAnalysis()
15748f97e57SSam McCall )");
15848f97e57SSam McCall }
15948f97e57SSam McCall
TEST(LoggerTest,HTML)160a443b3d1SSam McCall TEST(LoggerTest, HTML) {
161a443b3d1SSam McCall auto Inputs = makeInputs();
162a443b3d1SSam McCall std::vector<std::string> Logs;
163a443b3d1SSam McCall auto Logger = Logger::html([&]() {
164a443b3d1SSam McCall Logs.emplace_back();
165a443b3d1SSam McCall return std::make_unique<llvm::raw_string_ostream>(Logs.back());
166a443b3d1SSam McCall });
167a443b3d1SSam McCall Inputs.BuiltinOptions.Log = Logger.get();
168a443b3d1SSam McCall
169a443b3d1SSam McCall ASSERT_THAT_ERROR(checkDataflow<TestAnalysis>(std::move(Inputs),
170a443b3d1SSam McCall [](const AnalysisOutputs &) {}),
171a443b3d1SSam McCall llvm::Succeeded());
172a443b3d1SSam McCall
173a443b3d1SSam McCall // Simple smoke tests: we can't meaningfully test the behavior.
174a443b3d1SSam McCall ASSERT_THAT(Logs, testing::SizeIs(1));
175a443b3d1SSam McCall EXPECT_THAT(Logs[0], HasSubstr("function updateSelection")) << "embeds JS";
176a443b3d1SSam McCall EXPECT_THAT(Logs[0], HasSubstr("html {")) << "embeds CSS";
177a443b3d1SSam McCall EXPECT_THAT(Logs[0], HasSubstr("b (ImplicitCastExpr")) << "has CFG elements";
178a443b3d1SSam McCall EXPECT_THAT(Logs[0], HasSubstr("\"B3:1_B3.1\":"))
179a443b3d1SSam McCall << "has analysis point state";
180a443b3d1SSam McCall EXPECT_THAT(Logs[0], HasSubstr("transferBranch(0)")) << "has analysis logs";
181a443b3d1SSam McCall EXPECT_THAT(Logs[0], HasSubstr("LocToVal")) << "has built-in lattice dump";
182b56b15edSSam McCall EXPECT_THAT(Logs[0], HasSubstr("\"type\": \"int\"")) << "has value dump";
183a443b3d1SSam McCall }
184a443b3d1SSam McCall
18548f97e57SSam McCall } // namespace
18648f97e57SSam McCall } // namespace clang::dataflow::test
187