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