xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/ProgramPoint.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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/Analysis/AnalysisDeclContext.h"
17 #include "clang/Basic/JsonSupport.h"
18 
19 using namespace clang;
20 
21 ProgramPointTag::~ProgramPointTag() {}
22 
23 ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
24                                            const LocationContext *LC,
25                                            const ProgramPointTag *tag){
26   switch (K) {
27     default:
28       llvm_unreachable("Unhandled ProgramPoint kind");
29     case ProgramPoint::PreStmtKind:
30       return PreStmt(S, LC, tag);
31     case ProgramPoint::PostStmtKind:
32       return PostStmt(S, LC, tag);
33     case ProgramPoint::PreLoadKind:
34       return PreLoad(S, LC, tag);
35     case ProgramPoint::PostLoadKind:
36       return PostLoad(S, LC, tag);
37     case ProgramPoint::PreStoreKind:
38       return PreStore(S, LC, tag);
39     case ProgramPoint::PostLValueKind:
40       return PostLValue(S, LC, tag);
41     case ProgramPoint::PostStmtPurgeDeadSymbolsKind:
42       return PostStmtPurgeDeadSymbols(S, LC, tag);
43     case ProgramPoint::PreStmtPurgeDeadSymbolsKind:
44       return PreStmtPurgeDeadSymbols(S, LC, tag);
45   }
46 }
47 
48 LLVM_DUMP_METHOD void ProgramPoint::dump() const {
49   return printJson(llvm::errs());
50 }
51 
52 StringRef ProgramPoint::getProgramPointKindName(Kind K) {
53   switch (K) {
54   case BlockEdgeKind:
55     return "BlockEdge";
56   case BlockEntranceKind:
57     return "BlockEntrance";
58   case BlockExitKind:
59     return "BlockExit";
60   case PreStmtKind:
61     return "PreStmt";
62   case PreStmtPurgeDeadSymbolsKind:
63     return "PreStmtPurgeDeadSymbols";
64   case PostStmtPurgeDeadSymbolsKind:
65     return "PostStmtPurgeDeadSymbols";
66   case PostStmtKind:
67     return "PostStmt";
68   case PreLoadKind:
69     return "PreLoad";
70   case PostLoadKind:
71     return "PostLoad";
72   case PreStoreKind:
73     return "PreStore";
74   case PostStoreKind:
75     return "PostStore";
76   case PostConditionKind:
77     return "PostCondition";
78   case PostLValueKind:
79     return "PostLValue";
80   case PostAllocatorCallKind:
81     return "PostAllocatorCall";
82   case PostInitializerKind:
83     return "PostInitializer";
84   case CallEnterKind:
85     return "CallEnter";
86   case CallExitBeginKind:
87     return "CallExitBegin";
88   case CallExitEndKind:
89     return "CallExitEnd";
90   case FunctionExitKind:
91     return "FunctionExit";
92   case PreImplicitCallKind:
93     return "PreImplicitCall";
94   case PostImplicitCallKind:
95     return "PostImplicitCall";
96   case LoopExitKind:
97     return "LoopExit";
98   case EpsilonKind:
99     return "Epsilon";
100   }
101   llvm_unreachable("Unknown ProgramPoint kind");
102 }
103 
104 std::optional<SourceLocation> ProgramPoint::getSourceLocation() const {
105   switch (getKind()) {
106   case BlockEdgeKind:
107     // If needed, the source and or destination beginning can be used to get
108     // source location.
109     return std::nullopt;
110   case BlockEntranceKind:
111     // If needed, first statement of the block can be used.
112     return std::nullopt;
113   case BlockExitKind:
114     if (const auto *B = castAs<BlockExit>().getBlock()) {
115       if (const auto *T = B->getTerminatorStmt()) {
116         return T->getBeginLoc();
117       }
118     }
119     return std::nullopt;
120   case PreStmtKind:
121   case PreStmtPurgeDeadSymbolsKind:
122   case PostStmtPurgeDeadSymbolsKind:
123   case PostStmtKind:
124   case PreLoadKind:
125   case PostLoadKind:
126   case PreStoreKind:
127   case PostStoreKind:
128   case PostConditionKind:
129   case PostLValueKind:
130   case PostAllocatorCallKind:
131     if (const Stmt *S = castAs<StmtPoint>().getStmt())
132       return S->getBeginLoc();
133     return std::nullopt;
134   case PostInitializerKind:
135     if (const auto *Init = castAs<PostInitializer>().getInitializer())
136       return Init->getSourceLocation();
137     return std::nullopt;
138   case CallEnterKind:
139     if (const Stmt *S = castAs<CallEnter>().getCallExpr())
140       return S->getBeginLoc();
141     return std::nullopt;
142   case CallExitBeginKind:
143     if (const Stmt *S = castAs<CallExitBegin>().getReturnStmt())
144       return S->getBeginLoc();
145     return std::nullopt;
146   case CallExitEndKind:
147     return std::nullopt;
148   case FunctionExitKind:
149     if (const auto *B = castAs<FunctionExitPoint>().getBlock();
150         B && B->getTerminatorStmt())
151       return B->getTerminatorStmt()->getBeginLoc();
152     return std::nullopt;
153   case PreImplicitCallKind:
154     return castAs<ImplicitCallPoint>().getLocation();
155   case PostImplicitCallKind:
156     return castAs<ImplicitCallPoint>().getLocation();
157   case LoopExitKind:
158     if (const Stmt *S = castAs<LoopExit>().getLoopStmt())
159       return S->getBeginLoc();
160     return std::nullopt;
161   case EpsilonKind:
162     return std::nullopt;
163   }
164   llvm_unreachable("Unknown ProgramPoint kind");
165 }
166 
167 void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
168   const ASTContext &Context =
169       getLocationContext()->getAnalysisDeclContext()->getASTContext();
170   const SourceManager &SM = Context.getSourceManager();
171   const PrintingPolicy &PP = Context.getPrintingPolicy();
172   const bool AddQuotes = true;
173 
174   Out << "\"kind\": \"";
175   switch (getKind()) {
176   case ProgramPoint::BlockEntranceKind:
177     Out << "BlockEntrance\""
178         << ", \"block_id\": "
179         << castAs<BlockEntrance>().getBlock()->getBlockID();
180     break;
181 
182   case ProgramPoint::FunctionExitKind: {
183     auto FEP = getAs<FunctionExitPoint>();
184     Out << "FunctionExit\""
185         << ", \"block_id\": " << FEP->getBlock()->getBlockID()
186         << ", \"stmt_id\": ";
187 
188     if (const ReturnStmt *RS = FEP->getStmt()) {
189       Out << RS->getID(Context) << ", \"stmt\": ";
190       RS->printJson(Out, nullptr, PP, AddQuotes);
191     } else {
192       Out << "null, \"stmt\": null";
193     }
194     break;
195   }
196   case ProgramPoint::BlockExitKind:
197     llvm_unreachable("BlockExitKind");
198     break;
199   case ProgramPoint::CallEnterKind:
200     Out << "CallEnter\", \"callee_decl\": \"";
201     Out << AnalysisDeclContext::getFunctionName(
202                castAs<CallEnter>().getCalleeContext()->getDecl())
203         << '\"';
204     break;
205   case ProgramPoint::CallExitBeginKind:
206     Out << "CallExitBegin\"";
207     break;
208   case ProgramPoint::CallExitEndKind:
209     Out << "CallExitEnd\"";
210     break;
211   case ProgramPoint::EpsilonKind:
212     Out << "EpsilonPoint\"";
213     break;
214 
215   case ProgramPoint::LoopExitKind:
216     Out << "LoopExit\", \"stmt\": \""
217         << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"';
218     break;
219 
220   case ProgramPoint::PreImplicitCallKind: {
221     ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
222     Out << "PreCall\", \"decl\": \""
223         << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
224         << "\", \"location\": ";
225     printSourceLocationAsJson(Out, PC.getLocation(), SM);
226     break;
227   }
228 
229   case ProgramPoint::PostImplicitCallKind: {
230     ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
231     Out << "PostCall\", \"decl\": \""
232         << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
233         << "\", \"location\": ";
234     printSourceLocationAsJson(Out, PC.getLocation(), SM);
235     break;
236   }
237 
238   case ProgramPoint::PostInitializerKind: {
239     Out << "PostInitializer\", ";
240     const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer();
241     if (const FieldDecl *FD = Init->getAnyMember()) {
242       Out << "\"field_decl\": \"" << *FD << '\"';
243     } else {
244       Out << "\"type\": \"";
245       QualType Ty = Init->getTypeSourceInfo()->getType();
246       Ty = Ty.getLocalUnqualifiedType();
247       Ty.print(Out, Context.getLangOpts());
248       Out << '\"';
249     }
250     break;
251   }
252 
253   case ProgramPoint::BlockEdgeKind: {
254     const BlockEdge &E = castAs<BlockEdge>();
255     const Stmt *T = E.getSrc()->getTerminatorStmt();
256     Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID()
257         << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": ";
258 
259     if (!T) {
260       Out << "null, \"term_kind\": null";
261       break;
262     }
263 
264     E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(),
265                                     /*AddQuotes=*/true);
266     Out << ", \"location\": ";
267     printSourceLocationAsJson(Out, T->getBeginLoc(), SM);
268 
269     Out << ", \"term_kind\": \"";
270     if (isa<SwitchStmt>(T)) {
271       Out << "SwitchStmt\", \"case\": ";
272       if (const Stmt *Label = E.getDst()->getLabel()) {
273         if (const auto *C = dyn_cast<CaseStmt>(Label)) {
274           Out << "{ \"lhs\": ";
275           if (const Stmt *LHS = C->getLHS()) {
276             LHS->printJson(Out, nullptr, PP, AddQuotes);
277           } else {
278             Out << "null";
279           }
280 
281           Out << ", \"rhs\": ";
282           if (const Stmt *RHS = C->getRHS()) {
283             RHS->printJson(Out, nullptr, PP, AddQuotes);
284           } else {
285             Out << "null";
286           }
287           Out << " }";
288         } else {
289           assert(isa<DefaultStmt>(Label));
290           Out << "\"default\"";
291         }
292       } else {
293         Out << "\"implicit default\"";
294       }
295     } else if (isa<IndirectGotoStmt>(T)) {
296       // FIXME: More info.
297       Out << "IndirectGotoStmt\"";
298     } else {
299       Out << "Condition\", \"value\": "
300           << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false");
301     }
302     break;
303   }
304 
305   default: {
306     const Stmt *S = castAs<StmtPoint>().getStmt();
307     assert(S != nullptr && "Expecting non-null Stmt");
308 
309     Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName()
310         << "\", \"stmt_id\": " << S->getID(Context)
311         << ", \"pointer\": \"" << (const void *)S << "\", ";
312     if (const auto *CS = dyn_cast<CastExpr>(S))
313       Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", ";
314 
315     Out << "\"pretty\": ";
316 
317     S->printJson(Out, nullptr, PP, AddQuotes);
318 
319     Out << ", \"location\": ";
320     printSourceLocationAsJson(Out, S->getBeginLoc(), SM);
321 
322     Out << ", \"stmt_point_kind\": \"";
323     if (getAs<PreLoad>())
324       Out << "PreLoad";
325     else if (getAs<PreStore>())
326       Out << "PreStore";
327     else if (getAs<PostAllocatorCall>())
328       Out << "PostAllocatorCall";
329     else if (getAs<PostCondition>())
330       Out << "PostCondition";
331     else if (getAs<PostLoad>())
332       Out << "PostLoad";
333     else if (getAs<PostLValue>())
334       Out << "PostLValue";
335     else if (getAs<PostStore>())
336       Out << "PostStore";
337     else if (getAs<PostStmt>())
338       Out << "PostStmt";
339     else if (getAs<PostStmtPurgeDeadSymbols>())
340       Out << "PostStmtPurgeDeadSymbols";
341     else if (getAs<PreStmtPurgeDeadSymbols>())
342       Out << "PreStmtPurgeDeadSymbols";
343     else if (getAs<PreStmt>())
344       Out << "PreStmt";
345     else {
346       Out << "\nKind: '" << getKind();
347       llvm_unreachable("' is unhandled StmtPoint kind!");
348     }
349 
350     Out << '\"';
351     break;
352   }
353   }
354 }
355 
356 SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider,
357                                              StringRef Msg)
358   : Desc((MsgProvider + " : " + Msg).str()) {}
359 
360 StringRef SimpleProgramPointTag::getDebugTag() const { return Desc; }
361