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 (OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true); |
40 | OS << "=== Beginning data flow analysis ===\n" ; |
41 | } |
42 | auto &D = ACFG.getDecl(); |
43 | D.print(Out&: OS); |
44 | OS << "\n" ; |
45 | D.dump(Out&: OS); |
46 | CurrentCFG = &ACFG.getCFG(); |
47 | CurrentCFG->print(OS, LO: Analysis.getASTContext().getLangOpts(), ShowColors); |
48 | CurrentAnalysis = &Analysis; |
49 | } |
50 | virtual void endAnalysis() override { |
51 | llvm::WithColor (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 (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, cfg: CurrentCFG, LO: 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 (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 (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>(args&: OS); |
109 | } |
110 | |
111 | } // namespace clang::dataflow |
112 | |