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     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 
107 std::unique_ptr<Logger> Logger::textual(llvm::raw_ostream &OS) {
108   return std::make_unique<TextualLogger>(OS);
109 }
110 
111 } // namespace clang::dataflow
112