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