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