xref: /llvm-project/clang/lib/Analysis/FlowSensitive/Logger.cpp (revision e6cd409fc6396cb13c59b4a5190abc4b856f22a5)
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) 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() << " (iteration "
65          << Count << ") ===\n";
66     }
67     Block.print(OS, CurrentCFG, CurrentAnalysis->getASTContext().getLangOpts(),
68                 ShowColors);
69     CurrentBlock = &Block;
70     CurrentElement = nullptr;
71     CurrentElementIndex = 0;
72   }
73   virtual void enterElement(const CFGElement &Element) override {
74     ++CurrentElementIndex;
75     CurrentElement = &Element;
76     {
77       llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN,
78                                 /*Bold=*/true);
79       OS << "Processing element B" << CurrentBlock->getBlockID() << "."
80          << CurrentElementIndex << ": ";
81       Element.dumpToStream(OS);
82     }
83   }
84   void recordState(TypeErasedDataflowAnalysisState &State) override {
85     {
86       llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN,
87                                 /*Bold=*/true);
88       OS << "Computed state for B" << CurrentBlock->getBlockID() << "."
89          << CurrentElementIndex << ":\n";
90     }
91     // FIXME: currently the environment dump is verbose and unenlightening.
92     // FIXME: dump the user-defined lattice, too.
93     State.Env.dump(OS);
94     OS << "\n";
95   }
96   void blockConverged() override {
97     OS << "B" << CurrentBlock->getBlockID() << " has converged!\n";
98   }
99   virtual void logText(llvm::StringRef S) override { OS << S << "\n"; }
100 };
101 } // namespace
102 
103 std::unique_ptr<Logger> Logger::textual(llvm::raw_ostream &OS) {
104   return std::make_unique<TextualLogger>(OS);
105 }
106 
107 } // namespace clang::dataflow
108