1 | //==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- 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 | // This file defines the interface ProgramPoint, which identifies a |
10 | // distinct location in a function. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/Analysis/ProgramPoint.h" |
15 | #include "clang/AST/ASTContext.h" |
16 | #include "clang/Basic/JsonSupport.h" |
17 | |
18 | using namespace clang; |
19 | |
20 | ProgramPointTag::~ProgramPointTag() {} |
21 | |
22 | ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K, |
23 | const LocationContext *LC, |
24 | const ProgramPointTag *tag){ |
25 | switch (K) { |
26 | default: |
27 | llvm_unreachable("Unhandled ProgramPoint kind" ); |
28 | case ProgramPoint::PreStmtKind: |
29 | return PreStmt(S, LC, tag); |
30 | case ProgramPoint::PostStmtKind: |
31 | return PostStmt(S, LC, tag); |
32 | case ProgramPoint::PreLoadKind: |
33 | return PreLoad(S, LC, tag); |
34 | case ProgramPoint::PostLoadKind: |
35 | return PostLoad(S, LC, tag); |
36 | case ProgramPoint::PreStoreKind: |
37 | return PreStore(S, LC, tag); |
38 | case ProgramPoint::PostLValueKind: |
39 | return PostLValue(S, LC, tag); |
40 | case ProgramPoint::PostStmtPurgeDeadSymbolsKind: |
41 | return PostStmtPurgeDeadSymbols(S, LC, tag); |
42 | case ProgramPoint::PreStmtPurgeDeadSymbolsKind: |
43 | return PreStmtPurgeDeadSymbols(S, LC, tag); |
44 | } |
45 | } |
46 | |
47 | LLVM_DUMP_METHOD void ProgramPoint::dump() const { |
48 | return printJson(Out&: llvm::errs()); |
49 | } |
50 | |
51 | void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const { |
52 | const ASTContext &Context = |
53 | getLocationContext()->getAnalysisDeclContext()->getASTContext(); |
54 | const SourceManager &SM = Context.getSourceManager(); |
55 | const PrintingPolicy &PP = Context.getPrintingPolicy(); |
56 | const bool AddQuotes = true; |
57 | |
58 | Out << "\"kind\": \"" ; |
59 | switch (getKind()) { |
60 | case ProgramPoint::BlockEntranceKind: |
61 | Out << "BlockEntrance\"" |
62 | << ", \"block_id\": " |
63 | << castAs<BlockEntrance>().getBlock()->getBlockID(); |
64 | break; |
65 | |
66 | case ProgramPoint::FunctionExitKind: { |
67 | auto FEP = getAs<FunctionExitPoint>(); |
68 | Out << "FunctionExit\"" |
69 | << ", \"block_id\": " << FEP->getBlock()->getBlockID() |
70 | << ", \"stmt_id\": " ; |
71 | |
72 | if (const ReturnStmt *RS = FEP->getStmt()) { |
73 | Out << RS->getID(Context) << ", \"stmt\": " ; |
74 | RS->printJson(Out, Helper: nullptr, Policy: PP, AddQuotes); |
75 | } else { |
76 | Out << "null, \"stmt\": null" ; |
77 | } |
78 | break; |
79 | } |
80 | case ProgramPoint::BlockExitKind: |
81 | llvm_unreachable("BlockExitKind" ); |
82 | break; |
83 | case ProgramPoint::CallEnterKind: |
84 | Out << "CallEnter\"" ; |
85 | break; |
86 | case ProgramPoint::CallExitBeginKind: |
87 | Out << "CallExitBegin\"" ; |
88 | break; |
89 | case ProgramPoint::CallExitEndKind: |
90 | Out << "CallExitEnd\"" ; |
91 | break; |
92 | case ProgramPoint::EpsilonKind: |
93 | Out << "EpsilonPoint\"" ; |
94 | break; |
95 | |
96 | case ProgramPoint::LoopExitKind: |
97 | Out << "LoopExit\", \"stmt\": \"" |
98 | << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"'; |
99 | break; |
100 | |
101 | case ProgramPoint::PreImplicitCallKind: { |
102 | ImplicitCallPoint PC = castAs<ImplicitCallPoint>(); |
103 | Out << "PreCall\", \"decl\": \"" |
104 | << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() |
105 | << "\", \"location\": " ; |
106 | printSourceLocationAsJson(Out, Loc: PC.getLocation(), SM); |
107 | break; |
108 | } |
109 | |
110 | case ProgramPoint::PostImplicitCallKind: { |
111 | ImplicitCallPoint PC = castAs<ImplicitCallPoint>(); |
112 | Out << "PostCall\", \"decl\": \"" |
113 | << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() |
114 | << "\", \"location\": " ; |
115 | printSourceLocationAsJson(Out, Loc: PC.getLocation(), SM); |
116 | break; |
117 | } |
118 | |
119 | case ProgramPoint::PostInitializerKind: { |
120 | Out << "PostInitializer\", " ; |
121 | const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer(); |
122 | if (const FieldDecl *FD = Init->getAnyMember()) { |
123 | Out << "\"field_decl\": \"" << *FD << '\"'; |
124 | } else { |
125 | Out << "\"type\": \"" ; |
126 | QualType Ty = Init->getTypeSourceInfo()->getType(); |
127 | Ty = Ty.getLocalUnqualifiedType(); |
128 | Ty.print(OS&: Out, Policy: Context.getLangOpts()); |
129 | Out << '\"'; |
130 | } |
131 | break; |
132 | } |
133 | |
134 | case ProgramPoint::BlockEdgeKind: { |
135 | const BlockEdge &E = castAs<BlockEdge>(); |
136 | const Stmt *T = E.getSrc()->getTerminatorStmt(); |
137 | Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID() |
138 | << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": " ; |
139 | |
140 | if (!T) { |
141 | Out << "null, \"term_kind\": null" ; |
142 | break; |
143 | } |
144 | |
145 | E.getSrc()->printTerminatorJson(Out, LO: Context.getLangOpts(), |
146 | /*AddQuotes=*/true); |
147 | Out << ", \"location\": " ; |
148 | printSourceLocationAsJson(Out, Loc: T->getBeginLoc(), SM); |
149 | |
150 | Out << ", \"term_kind\": \"" ; |
151 | if (isa<SwitchStmt>(Val: T)) { |
152 | Out << "SwitchStmt\", \"case\": " ; |
153 | if (const Stmt *Label = E.getDst()->getLabel()) { |
154 | if (const auto *C = dyn_cast<CaseStmt>(Val: Label)) { |
155 | Out << "{ \"lhs\": " ; |
156 | if (const Stmt *LHS = C->getLHS()) { |
157 | LHS->printJson(Out, Helper: nullptr, Policy: PP, AddQuotes); |
158 | } else { |
159 | Out << "null" ; |
160 | } |
161 | |
162 | Out << ", \"rhs\": " ; |
163 | if (const Stmt *RHS = C->getRHS()) { |
164 | RHS->printJson(Out, Helper: nullptr, Policy: PP, AddQuotes); |
165 | } else { |
166 | Out << "null" ; |
167 | } |
168 | Out << " }" ; |
169 | } else { |
170 | assert(isa<DefaultStmt>(Label)); |
171 | Out << "\"default\"" ; |
172 | } |
173 | } else { |
174 | Out << "\"implicit default\"" ; |
175 | } |
176 | } else if (isa<IndirectGotoStmt>(Val: T)) { |
177 | // FIXME: More info. |
178 | Out << "IndirectGotoStmt\"" ; |
179 | } else { |
180 | Out << "Condition\", \"value\": " |
181 | << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false" ); |
182 | } |
183 | break; |
184 | } |
185 | |
186 | default: { |
187 | const Stmt *S = castAs<StmtPoint>().getStmt(); |
188 | assert(S != nullptr && "Expecting non-null Stmt" ); |
189 | |
190 | Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName() |
191 | << "\", \"stmt_id\": " << S->getID(Context) |
192 | << ", \"pointer\": \"" << (const void *)S << "\", " ; |
193 | if (const auto *CS = dyn_cast<CastExpr>(Val: S)) |
194 | Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", " ; |
195 | |
196 | Out << "\"pretty\": " ; |
197 | |
198 | S->printJson(Out, Helper: nullptr, Policy: PP, AddQuotes); |
199 | |
200 | Out << ", \"location\": " ; |
201 | printSourceLocationAsJson(Out, Loc: S->getBeginLoc(), SM); |
202 | |
203 | Out << ", \"stmt_point_kind\": \"" ; |
204 | if (getAs<PreLoad>()) |
205 | Out << "PreLoad" ; |
206 | else if (getAs<PreStore>()) |
207 | Out << "PreStore" ; |
208 | else if (getAs<PostAllocatorCall>()) |
209 | Out << "PostAllocatorCall" ; |
210 | else if (getAs<PostCondition>()) |
211 | Out << "PostCondition" ; |
212 | else if (getAs<PostLoad>()) |
213 | Out << "PostLoad" ; |
214 | else if (getAs<PostLValue>()) |
215 | Out << "PostLValue" ; |
216 | else if (getAs<PostStore>()) |
217 | Out << "PostStore" ; |
218 | else if (getAs<PostStmt>()) |
219 | Out << "PostStmt" ; |
220 | else if (getAs<PostStmtPurgeDeadSymbols>()) |
221 | Out << "PostStmtPurgeDeadSymbols" ; |
222 | else if (getAs<PreStmtPurgeDeadSymbols>()) |
223 | Out << "PreStmtPurgeDeadSymbols" ; |
224 | else if (getAs<PreStmt>()) |
225 | Out << "PreStmt" ; |
226 | else { |
227 | Out << "\nKind: '" << getKind(); |
228 | llvm_unreachable("' is unhandled StmtPoint kind!" ); |
229 | } |
230 | |
231 | Out << '\"'; |
232 | break; |
233 | } |
234 | } |
235 | } |
236 | |
237 | SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider, |
238 | StringRef Msg) |
239 | : Desc((MsgProvider + " : " + Msg).str()) {} |
240 | |
241 | StringRef SimpleProgramPointTag::getTagDescription() const { |
242 | return Desc; |
243 | } |
244 | |