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 
14 namespace clang::dataflow {
15 
16 Logger &Logger::null() {
17   struct NullLogger final : Logger {};
18   static auto *Instance = new NullLogger();
19   return *Instance;
20 }
21 
22 namespace {
23 struct 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     if (auto *D = CFG.getDecl()) {
43       D->print(OS);
44       OS << "\n";
45       D->dump(OS);
46     }
47     CurrentCFG = &CFG.getCFG();
48     CurrentCFG->print(OS, Analysis.getASTContext().getLangOpts(), ShowColors);
49     CurrentAnalysis = &Analysis;
50   }
51   virtual void endAnalysis() override {
52     llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
53     unsigned Blocks = 0, Steps = 0;
54     for (const auto &E : VisitCount) {
55       ++Blocks;
56       Steps += E.second;
57     }
58     llvm::errs() << "=== Finished analysis: " << Blocks << " blocks in "
59                  << Steps << " total steps ===\n";
60   }
61   virtual void enterBlock(const CFGBlock &Block) override {
62     unsigned Count = ++VisitCount[&Block];
63     {
64       llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
65       OS << "=== Entering block B" << Block.getBlockID() << " (iteration "
66          << Count << ") ===\n";
67     }
68     Block.print(OS, CurrentCFG, CurrentAnalysis->getASTContext().getLangOpts(),
69                 ShowColors);
70     CurrentBlock = &Block;
71     CurrentElement = nullptr;
72     CurrentElementIndex = 0;
73   }
74   virtual void enterElement(const CFGElement &Element) override {
75     ++CurrentElementIndex;
76     CurrentElement = &Element;
77     {
78       llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN,
79                                 /*Bold=*/true);
80       OS << "Processing element B" << CurrentBlock->getBlockID() << "."
81          << CurrentElementIndex << ": ";
82       Element.dumpToStream(OS);
83     }
84   }
85   void recordState(TypeErasedDataflowAnalysisState &State) override {
86     {
87       llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN,
88                                 /*Bold=*/true);
89       OS << "Computed state for B" << CurrentBlock->getBlockID() << "."
90          << CurrentElementIndex << ":\n";
91     }
92     // FIXME: currently the environment dump is verbose and unenlightening.
93     // FIXME: dump the user-defined lattice, too.
94     State.Env.dump(OS);
95     OS << "\n";
96   }
97   void blockConverged() override {
98     OS << "B" << CurrentBlock->getBlockID() << " has converged!\n";
99   }
100   virtual void logText(llvm::StringRef S) override { OS << S << "\n"; }
101 };
102 } // namespace
103 
104 std::unique_ptr<Logger> Logger::textual(llvm::raw_ostream &OS) {
105   return std::make_unique<TextualLogger>(OS);
106 }
107 
108 } // namespace clang::dataflow
109