//===-- Logger.cpp --------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/Logger.h" #include "clang/Analysis/FlowSensitive/ControlFlowContext.h" #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "llvm/Support/WithColor.h" namespace clang::dataflow { Logger &Logger::null() { struct NullLogger final : Logger {}; static auto *Instance = new NullLogger(); return *Instance; } namespace { struct TextualLogger final : Logger { llvm::raw_ostream &OS; const CFG *CurrentCFG; const CFGBlock *CurrentBlock; const CFGElement *CurrentElement; unsigned CurrentElementIndex; bool ShowColors; llvm::DenseMap VisitCount; TypeErasedDataflowAnalysis *CurrentAnalysis; TextualLogger(llvm::raw_ostream &OS) : OS(OS), ShowColors(llvm::WithColor::defaultAutoDetectFunction()(OS)) {} virtual void beginAnalysis(const ControlFlowContext &CFG, TypeErasedDataflowAnalysis &Analysis) override { { llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true); OS << "=== Beginning data flow analysis ===\n"; } if (auto *D = CFG.getDecl()) { D->print(OS); OS << "\n"; D->dump(OS); } CurrentCFG = &CFG.getCFG(); CurrentCFG->print(OS, Analysis.getASTContext().getLangOpts(), ShowColors); CurrentAnalysis = &Analysis; } virtual void endAnalysis() override { llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true); unsigned Blocks = 0, Steps = 0; for (const auto &E : VisitCount) { ++Blocks; Steps += E.second; } llvm::errs() << "=== Finished analysis: " << Blocks << " blocks in " << Steps << " total steps ===\n"; } virtual void enterBlock(const CFGBlock &Block) override { unsigned Count = ++VisitCount[&Block]; { llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true); OS << "=== Entering block B" << Block.getBlockID() << " (iteration " << Count << ") ===\n"; } Block.print(OS, CurrentCFG, CurrentAnalysis->getASTContext().getLangOpts(), ShowColors); CurrentBlock = &Block; CurrentElement = nullptr; CurrentElementIndex = 0; } virtual void enterElement(const CFGElement &Element) override { ++CurrentElementIndex; CurrentElement = ∈ { llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN, /*Bold=*/true); OS << "Processing element B" << CurrentBlock->getBlockID() << "." << CurrentElementIndex << ": "; Element.dumpToStream(OS); } } void recordState(TypeErasedDataflowAnalysisState &State) override { { llvm::WithColor Subheader(OS, llvm::raw_ostream::Colors::CYAN, /*Bold=*/true); OS << "Computed state for B" << CurrentBlock->getBlockID() << "." << CurrentElementIndex << ":\n"; } // FIXME: currently the environment dump is verbose and unenlightening. // FIXME: dump the user-defined lattice, too. State.Env.dump(OS); OS << "\n"; } void blockConverged() override { OS << "B" << CurrentBlock->getBlockID() << " has converged!\n"; } virtual void logText(llvm::StringRef S) override { OS << S << "\n"; } }; } // namespace std::unique_ptr Logger::textual(llvm::raw_ostream &OS) { return std::make_unique(OS); } } // namespace clang::dataflow