1//===-- Logger.cpp --------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/Analysis/FlowSensitive/Logger.h"
10#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
11#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h"
12#include "llvm/Support/WithColor.h"
13
14namespace clang::dataflow {
15
16Logger &Logger::null() {
17  struct NullLogger final : Logger {};
18  static auto *Instance = new NullLogger();
19  return *Instance;
20}
21
22namespace {
23struct TextualLogger final : Logger {
24  llvm::raw_ostream &OS;
25  const CFG *CurrentCFG;
26  const CFGBlock *CurrentBlock;
27  const CFGElement *CurrentElement;
28  unsigned CurrentElementIndex;
29  bool ShowColors;
30  llvm::DenseMap<const CFGBlock *, unsigned> VisitCount;
31  TypeErasedDataflowAnalysis *CurrentAnalysis;
32
33  TextualLogger(llvm::raw_ostream &OS)
34      : OS(OS), ShowColors(llvm::WithColor::defaultAutoDetectFunction()(OS)) {}
35
36  virtual void beginAnalysis(const ControlFlowContext &CFG,
37                             TypeErasedDataflowAnalysis &Analysis) override {
38    {
39      llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
40      OS << "=== Beginning data flow analysis ===\n";
41    }
42    auto &D = CFG.getDecl();
43    D.print(OS);
44    OS << "\n";
45    D.dump(OS);
46    CurrentCFG = &CFG.getCFG();
47    CurrentCFG->print(OS, Analysis.getASTContext().getLangOpts(), ShowColors);
48    CurrentAnalysis = &Analysis;
49  }
50  virtual void endAnalysis() override {
51    llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
52    unsigned Blocks = 0, Steps = 0;
53    for (const auto &E : VisitCount) {
54      ++Blocks;
55      Steps += E.second;
56    }
57    llvm::errs() << "=== Finished analysis: " << Blocks << " blocks in "
58                 << Steps << " total steps ===\n";
59  }
60  virtual void enterBlock(const CFGBlock &Block, bool PostVisit) override {
61    unsigned Count = ++VisitCount[&Block];
62    {
63      llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
64      OS << "=== Entering block B" << Block.getBlockID();
65      if (PostVisit)
66        OS << " (post-visit)";
67      else
68        OS << " (iteration " << Count << ")";
69      OS << " ===\n";
70    }
71    Block.print(OS, CurrentCFG, CurrentAnalysis->getASTContext().getLangOpts(),
72                ShowColors);
73    CurrentBlock = &Block;
74    CurrentElement = nullptr;
75    CurrentElementIndex = 0;
76  }
77  virtual void enterElement(const CFGElement &Element) override {
78    ++CurrentElementIndex;
79    CurrentElement = &Element;
80    {
81      llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN,
82                                /*Bold=*/true);
83      OS << "Processing element B" << CurrentBlock->getBlockID() << "."
84         << CurrentElementIndex << ": ";
85      Element.dumpToStream(OS);
86    }
87  }
88  void recordState(TypeErasedDataflowAnalysisState &State) override {
89    {
90      llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN,
91                                /*Bold=*/true);
92      OS << "Computed state for B" << CurrentBlock->getBlockID() << "."
93         << CurrentElementIndex << ":\n";
94    }
95    // FIXME: currently the environment dump is verbose and unenlightening.
96    // FIXME: dump the user-defined lattice, too.
97    State.Env.dump(OS);
98    OS << "\n";
99  }
100  void blockConverged() override {
101    OS << "B" << CurrentBlock->getBlockID() << " has converged!\n";
102  }
103  virtual void logText(llvm::StringRef S) override { OS << S << "\n"; }
104};
105} // namespace
106
107std::unique_ptr<Logger> Logger::textual(llvm::raw_ostream &OS) {
108  return std::make_unique<TextualLogger>(OS);
109}
110
111} // namespace clang::dataflow
112