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 = ∈ 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