xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Logger.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===-- Logger.cpp --------------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Logger.h"
10*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/AdornedCFG.h"
1106c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h"
1206c3fb27SDimitry Andric #include "llvm/Support/WithColor.h"
1306c3fb27SDimitry Andric 
1406c3fb27SDimitry Andric namespace clang::dataflow {
1506c3fb27SDimitry Andric 
1606c3fb27SDimitry Andric Logger &Logger::null() {
1706c3fb27SDimitry Andric   struct NullLogger final : Logger {};
1806c3fb27SDimitry Andric   static auto *Instance = new NullLogger();
1906c3fb27SDimitry Andric   return *Instance;
2006c3fb27SDimitry Andric }
2106c3fb27SDimitry Andric 
2206c3fb27SDimitry Andric namespace {
2306c3fb27SDimitry Andric struct TextualLogger final : Logger {
2406c3fb27SDimitry Andric   llvm::raw_ostream &OS;
2506c3fb27SDimitry Andric   const CFG *CurrentCFG;
2606c3fb27SDimitry Andric   const CFGBlock *CurrentBlock;
2706c3fb27SDimitry Andric   const CFGElement *CurrentElement;
2806c3fb27SDimitry Andric   unsigned CurrentElementIndex;
2906c3fb27SDimitry Andric   bool ShowColors;
3006c3fb27SDimitry Andric   llvm::DenseMap<const CFGBlock *, unsigned> VisitCount;
3106c3fb27SDimitry Andric   TypeErasedDataflowAnalysis *CurrentAnalysis;
3206c3fb27SDimitry Andric 
3306c3fb27SDimitry Andric   TextualLogger(llvm::raw_ostream &OS)
3406c3fb27SDimitry Andric       : OS(OS), ShowColors(llvm::WithColor::defaultAutoDetectFunction()(OS)) {}
3506c3fb27SDimitry Andric 
36*0fca6ea1SDimitry Andric   virtual void beginAnalysis(const AdornedCFG &ACFG,
3706c3fb27SDimitry Andric                              TypeErasedDataflowAnalysis &Analysis) override {
3806c3fb27SDimitry Andric     {
3906c3fb27SDimitry Andric       llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
4006c3fb27SDimitry Andric       OS << "=== Beginning data flow analysis ===\n";
4106c3fb27SDimitry Andric     }
42*0fca6ea1SDimitry Andric     auto &D = ACFG.getDecl();
435f757f3fSDimitry Andric     D.print(OS);
4406c3fb27SDimitry Andric     OS << "\n";
455f757f3fSDimitry Andric     D.dump(OS);
46*0fca6ea1SDimitry Andric     CurrentCFG = &ACFG.getCFG();
4706c3fb27SDimitry Andric     CurrentCFG->print(OS, Analysis.getASTContext().getLangOpts(), ShowColors);
4806c3fb27SDimitry Andric     CurrentAnalysis = &Analysis;
4906c3fb27SDimitry Andric   }
5006c3fb27SDimitry Andric   virtual void endAnalysis() override {
5106c3fb27SDimitry Andric     llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
5206c3fb27SDimitry Andric     unsigned Blocks = 0, Steps = 0;
5306c3fb27SDimitry Andric     for (const auto &E : VisitCount) {
5406c3fb27SDimitry Andric       ++Blocks;
5506c3fb27SDimitry Andric       Steps += E.second;
5606c3fb27SDimitry Andric     }
5706c3fb27SDimitry Andric     llvm::errs() << "=== Finished analysis: " << Blocks << " blocks in "
5806c3fb27SDimitry Andric                  << Steps << " total steps ===\n";
5906c3fb27SDimitry Andric   }
605f757f3fSDimitry Andric   virtual void enterBlock(const CFGBlock &Block, bool PostVisit) override {
6106c3fb27SDimitry Andric     unsigned Count = ++VisitCount[&Block];
6206c3fb27SDimitry Andric     {
6306c3fb27SDimitry Andric       llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true);
645f757f3fSDimitry Andric       OS << "=== Entering block B" << Block.getBlockID();
655f757f3fSDimitry Andric       if (PostVisit)
665f757f3fSDimitry Andric         OS << " (post-visit)";
675f757f3fSDimitry Andric       else
685f757f3fSDimitry Andric         OS << " (iteration " << Count << ")";
695f757f3fSDimitry Andric       OS << " ===\n";
7006c3fb27SDimitry Andric     }
7106c3fb27SDimitry Andric     Block.print(OS, CurrentCFG, CurrentAnalysis->getASTContext().getLangOpts(),
7206c3fb27SDimitry Andric                 ShowColors);
7306c3fb27SDimitry Andric     CurrentBlock = &Block;
7406c3fb27SDimitry Andric     CurrentElement = nullptr;
7506c3fb27SDimitry Andric     CurrentElementIndex = 0;
7606c3fb27SDimitry Andric   }
7706c3fb27SDimitry Andric   virtual void enterElement(const CFGElement &Element) override {
7806c3fb27SDimitry Andric     ++CurrentElementIndex;
7906c3fb27SDimitry Andric     CurrentElement = &Element;
8006c3fb27SDimitry Andric     {
8106c3fb27SDimitry Andric       llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN,
8206c3fb27SDimitry Andric                                 /*Bold=*/true);
8306c3fb27SDimitry Andric       OS << "Processing element B" << CurrentBlock->getBlockID() << "."
8406c3fb27SDimitry Andric          << CurrentElementIndex << ": ";
8506c3fb27SDimitry Andric       Element.dumpToStream(OS);
8606c3fb27SDimitry Andric     }
8706c3fb27SDimitry Andric   }
8806c3fb27SDimitry Andric   void recordState(TypeErasedDataflowAnalysisState &State) override {
8906c3fb27SDimitry Andric     {
9006c3fb27SDimitry Andric       llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN,
9106c3fb27SDimitry Andric                                 /*Bold=*/true);
9206c3fb27SDimitry Andric       OS << "Computed state for B" << CurrentBlock->getBlockID() << "."
9306c3fb27SDimitry Andric          << CurrentElementIndex << ":\n";
9406c3fb27SDimitry Andric     }
9506c3fb27SDimitry Andric     // FIXME: currently the environment dump is verbose and unenlightening.
9606c3fb27SDimitry Andric     // FIXME: dump the user-defined lattice, too.
9706c3fb27SDimitry Andric     State.Env.dump(OS);
9806c3fb27SDimitry Andric     OS << "\n";
9906c3fb27SDimitry Andric   }
10006c3fb27SDimitry Andric   void blockConverged() override {
10106c3fb27SDimitry Andric     OS << "B" << CurrentBlock->getBlockID() << " has converged!\n";
10206c3fb27SDimitry Andric   }
10306c3fb27SDimitry Andric   virtual void logText(llvm::StringRef S) override { OS << S << "\n"; }
10406c3fb27SDimitry Andric };
10506c3fb27SDimitry Andric } // namespace
10606c3fb27SDimitry Andric 
10706c3fb27SDimitry Andric std::unique_ptr<Logger> Logger::textual(llvm::raw_ostream &OS) {
10806c3fb27SDimitry Andric   return std::make_unique<TextualLogger>(OS);
10906c3fb27SDimitry Andric }
11006c3fb27SDimitry Andric 
11106c3fb27SDimitry Andric } // namespace clang::dataflow
112