brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.0 KiB · 6092554 Raw
196 lines · cpp
1#include "TestingSupport.h"2#include "clang/ASTMatchers/ASTMatchers.h"3#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"4#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"5#include "clang/Analysis/FlowSensitive/DataflowLattice.h"6#include "llvm/Testing/Support/Error.h"7#include "gtest/gtest.h"8 9namespace clang::dataflow::test {10namespace {11using testing::HasSubstr;12 13struct TestLattice {14  int Elements = 0;15  int Branches = 0;16  int Joins = 0;17 18  LatticeJoinEffect join(const TestLattice &Other) {19    if (Joins < 3) {20      ++Joins;21      Elements += Other.Elements;22      Branches += Other.Branches;23      return LatticeJoinEffect::Changed;24    }25    return LatticeJoinEffect::Unchanged;26  }27  friend bool operator==(const TestLattice &LHS, const TestLattice &RHS) {28    return std::tie(LHS.Elements, LHS.Branches, LHS.Joins) ==29           std::tie(RHS.Elements, RHS.Branches, RHS.Joins);30  }31};32 33class TestAnalysis : public DataflowAnalysis<TestAnalysis, TestLattice> {34public:35  using DataflowAnalysis::DataflowAnalysis;36 37  static TestLattice initialElement() { return TestLattice{}; }38  void transfer(const CFGElement &, TestLattice &L, Environment &E) {39    E.getDataflowAnalysisContext().getOptions().Log->log(40        [](llvm::raw_ostream &OS) { OS << "transfer()"; });41    ++L.Elements;42  }43  void transferBranch(bool Branch, const Stmt *S, TestLattice &L,44                      Environment &E) {45    E.getDataflowAnalysisContext().getOptions().Log->log(46        [&](llvm::raw_ostream &OS) {47          OS << "transferBranch(" << Branch << ")";48        });49    ++L.Branches;50  }51};52 53class TestLogger : public Logger {54public:55  TestLogger(std::string &S) : OS(S) {}56 57private:58  llvm::raw_string_ostream OS;59 60  void beginAnalysis(const AdornedCFG &,61                     TypeErasedDataflowAnalysis &) override {62    logText("beginAnalysis()");63  }64  void endAnalysis() override { logText("\nendAnalysis()"); }65 66  void enterBlock(const CFGBlock &B, bool PostVisit) override {67    OS << "\nenterBlock(" << B.BlockID << ", " << (PostVisit ? "true" : "false")68       << ")\n";69  }70  void enterElement(const CFGElement &E) override {71    // we don't want the trailing \n72    std::string S;73    llvm::raw_string_ostream SS(S);74    E.dumpToStream(SS);75 76    OS << "enterElement(" << llvm::StringRef(S).trim() << ")\n";77  }78  void recordState(TypeErasedDataflowAnalysisState &S) override {79    const TestLattice &L = llvm::any_cast<TestLattice>(S.Lattice.Value);80    OS << "recordState(Elements=" << L.Elements << ", Branches=" << L.Branches81       << ", Joins=" << L.Joins << ")\n";82  }83  /// Records that the analysis state for the current block is now final.84  void blockConverged() override { logText("blockConverged()"); }85 86  void logText(llvm::StringRef Text) override { OS << Text << "\n"; }87};88 89AnalysisInputs<TestAnalysis> makeInputs() {90  const char *Code = R"cpp(91int target(bool b, int p, int q) {92  return b ? p : q;93}94)cpp";95  static const std::vector<std::string> Args = {96      "-fsyntax-only", "-fno-delayed-template-parsing", "-std=c++17"};97 98  auto Inputs = AnalysisInputs<TestAnalysis>(99      Code, ast_matchers::hasName("target"),100      [](ASTContext &C, Environment &) { return TestAnalysis(C); });101  Inputs.ASTBuildArgs = Args;102  return Inputs;103}104 105TEST(LoggerTest, Sequence) {106  auto Inputs = makeInputs();107  std::string Log;108  TestLogger Logger(Log);109  Inputs.BuiltinOptions.Log = &Logger;110 111  ASSERT_THAT_ERROR(checkDataflow<TestAnalysis>(std::move(Inputs),112                                                [](const AnalysisOutputs &) {}),113                    llvm::Succeeded());114 115  EXPECT_EQ(Log, R"(beginAnalysis()116 117enterBlock(4, false)118recordState(Elements=0, Branches=0, Joins=0)119enterElement(b)120transfer()121recordState(Elements=1, Branches=0, Joins=0)122enterElement(b (ImplicitCastExpr, LValueToRValue, _Bool))123transfer()124recordState(Elements=2, Branches=0, Joins=0)125recordState(Elements=2, Branches=0, Joins=0)126 127enterBlock(2, false)128transferBranch(1)129recordState(Elements=2, Branches=1, Joins=0)130enterElement(p)131transfer()132recordState(Elements=3, Branches=1, Joins=0)133 134enterBlock(3, false)135transferBranch(0)136recordState(Elements=2, Branches=1, Joins=0)137enterElement(q)138transfer()139recordState(Elements=3, Branches=1, Joins=0)140 141enterBlock(1, false)142recordState(Elements=6, Branches=2, Joins=1)143enterElement(b ? p : q)144transfer()145recordState(Elements=7, Branches=2, Joins=1)146enterElement(b ? p : q (ImplicitCastExpr, LValueToRValue, int))147transfer()148recordState(Elements=8, Branches=2, Joins=1)149enterElement(return b ? p : q;)150transfer()151recordState(Elements=9, Branches=2, Joins=1)152enterElement([Parm: q] (Lifetime ends))153transfer()154recordState(Elements=10, Branches=2, Joins=1)155enterElement([Parm: p] (Lifetime ends))156transfer()157recordState(Elements=11, Branches=2, Joins=1)158enterElement([Parm: b] (Lifetime ends))159transfer()160recordState(Elements=12, Branches=2, Joins=1)161 162enterBlock(0, false)163recordState(Elements=12, Branches=2, Joins=1)164 165endAnalysis()166)");167}168 169TEST(LoggerTest, HTML) {170  auto Inputs = makeInputs();171  std::vector<std::string> Logs;172  auto Logger = Logger::html([&]() {173    Logs.emplace_back();174    return std::make_unique<llvm::raw_string_ostream>(Logs.back());175  });176  Inputs.BuiltinOptions.Log = Logger.get();177 178  ASSERT_THAT_ERROR(checkDataflow<TestAnalysis>(std::move(Inputs),179                                                [](const AnalysisOutputs &) {}),180                    llvm::Succeeded());181 182  // Simple smoke tests: we can't meaningfully test the behavior.183  ASSERT_THAT(Logs, testing::SizeIs(1));184  EXPECT_THAT(Logs[0], HasSubstr("function updateSelection")) << "embeds JS";185  EXPECT_THAT(Logs[0], HasSubstr("html {")) << "embeds CSS";186  EXPECT_THAT(Logs[0], HasSubstr("b (ImplicitCastExpr")) << "has CFG elements";187  EXPECT_THAT(Logs[0], HasSubstr("\"B3:1_B3.1\":"))188      << "has analysis point state";189  EXPECT_THAT(Logs[0], HasSubstr("transferBranch(0)")) << "has analysis logs";190  EXPECT_THAT(Logs[0], HasSubstr("LocToVal")) << "has built-in lattice dump";191  EXPECT_THAT(Logs[0], HasSubstr("\"type\": \"int\"")) << "has value dump";192}193 194} // namespace195} // namespace clang::dataflow::test196