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