1//===- Facts.cpp - Lifetime Analysis Facts Implementation -------*- C++ -*-===//
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/Analyses/LifetimeSafety/Facts.h"
10#include "clang/AST/Decl.h"
11#include "clang/AST/DeclID.h"
12#include "clang/Analysis/Analyses/PostOrderCFGView.h"
13#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
14#include "llvm/ADT/STLFunctionalExtras.h"
15
16namespace clang::lifetimes::internal {
17
18void Fact::dump(llvm::raw_ostream &OS, const LoanManager &,
19 const OriginManager &) const {
20 OS << "Fact (Kind: " << static_cast<int>(K) << ")\n";
21}
22
23void IssueFact::dump(llvm::raw_ostream &OS, const LoanManager &LM,
24 const OriginManager &OM) const {
25 OS << "Issue (";
26 LM.getLoan(ID: getLoanID())->dump(OS);
27 OS << ", ToOrigin: ";
28 OM.dump(OID: getOriginID(), OS);
29 OS << ")\n";
30}
31
32void ExpireFact::dump(llvm::raw_ostream &OS, const LoanManager &LM,
33 const OriginManager &OM) const {
34 OS << "Expire (";
35 LM.getLoan(ID: getLoanID())->dump(OS);
36 if (auto OID = getOriginID()) {
37 OS << ", Origin: ";
38 OM.dump(OID: *OID, OS);
39 }
40 OS << ")\n";
41}
42
43void OriginFlowFact::dump(llvm::raw_ostream &OS, const LoanManager &,
44 const OriginManager &OM) const {
45 OS << "OriginFlow: \n";
46 OS << "\tDest: ";
47 OM.dump(OID: getDestOriginID(), OS);
48 OS << "\n";
49 OS << "\tSrc: ";
50 OM.dump(OID: getSrcOriginID(), OS);
51 OS << (getKillDest() ? "" : ", Merge");
52 OS << "\n";
53}
54
55void MovedOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &,
56 const OriginManager &OM) const {
57 OS << "MovedOrigins (";
58 OM.dump(OID: getMovedOrigin(), OS);
59 OS << ")\n";
60}
61
62void ReturnEscapeFact::dump(llvm::raw_ostream &OS, const LoanManager &,
63 const OriginManager &OM) const {
64 OS << "OriginEscapes (";
65 OM.dump(OID: getEscapedOriginID(), OS);
66 OS << ", via Return)\n";
67}
68
69void FieldEscapeFact::dump(llvm::raw_ostream &OS, const LoanManager &,
70 const OriginManager &OM) const {
71 OS << "OriginEscapes (";
72 OM.dump(OID: getEscapedOriginID(), OS);
73 OS << ", via Field)\n";
74}
75
76void GlobalEscapeFact::dump(llvm::raw_ostream &OS, const LoanManager &,
77 const OriginManager &OM) const {
78 OS << "OriginEscapes (";
79 OM.dump(OID: getEscapedOriginID(), OS);
80 OS << ", via Global)\n";
81}
82
83void UseFact::dump(llvm::raw_ostream &OS, const LoanManager &,
84 const OriginManager &OM) const {
85 OS << "Use (";
86 size_t NumUsedOrigins = getUsedOrigins()->getLength();
87 size_t I = 0;
88 for (const OriginList *Cur = getUsedOrigins(); Cur;
89 Cur = Cur->peelOuterOrigin(), ++I) {
90 OM.dump(OID: Cur->getOuterOriginID(), OS);
91 if (I < NumUsedOrigins - 1)
92 OS << ", ";
93 }
94 OS << ", " << (isWritten() ? "Write" : "Read") << ")\n";
95}
96
97void InvalidateOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &,
98 const OriginManager &OM) const {
99 OS << "InvalidateOrigin (";
100 OM.dump(OID: getInvalidatedOrigin(), OS);
101 OS << ")\n";
102}
103
104void TestPointFact::dump(llvm::raw_ostream &OS, const LoanManager &,
105 const OriginManager &) const {
106 OS << "TestPoint (Annotation: \"" << getAnnotation() << "\")\n";
107}
108
109llvm::StringMap<ProgramPoint> FactManager::getTestPoints() const {
110 llvm::StringMap<ProgramPoint> AnnotationToPointMap;
111 for (const auto &BlockFacts : BlockToFacts) {
112 for (const Fact *F : BlockFacts) {
113 if (const auto *TPF = F->getAs<TestPointFact>()) {
114 StringRef PointName = TPF->getAnnotation();
115 assert(!AnnotationToPointMap.contains(PointName) &&
116 "more than one test points with the same name");
117 AnnotationToPointMap[PointName] = F;
118 }
119 }
120 }
121 return AnnotationToPointMap;
122}
123
124void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const {
125 llvm::dbgs() << "==========================================\n";
126 llvm::dbgs() << " Lifetime Analysis Facts:\n";
127 llvm::dbgs() << "==========================================\n";
128 if (const Decl *D = AC.getDecl())
129 if (const auto *ND = dyn_cast<NamedDecl>(Val: D))
130 llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n";
131 // Print blocks in the order as they appear in code for a stable ordering.
132 for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) {
133 llvm::dbgs() << " Block B" << B->getBlockID() << ":\n";
134 for (const Fact *F : getFacts(B)) {
135 llvm::dbgs() << " ";
136 F->dump(OS&: llvm::dbgs(), LoanMgr, OriginMgr);
137 }
138 llvm::dbgs() << " End of Block\n";
139 }
140}
141
142llvm::ArrayRef<const Fact *>
143FactManager::getBlockContaining(ProgramPoint P) const {
144 for (const auto &BlockToFactsVec : BlockToFacts) {
145 for (const Fact *F : BlockToFactsVec)
146 if (F == P)
147 return BlockToFactsVec;
148 }
149 return {};
150}
151
152} // namespace clang::lifetimes::internal
153