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