clang 22.0.0git
ProgramPoint.cpp
Go to the documentation of this file.
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
18
19using namespace clang;
20
22
24 const LocationContext *LC,
25 const ProgramPointTag *tag){
26 switch (K) {
27 default:
28 llvm_unreachable("Unhandled ProgramPoint kind");
30 return PreStmt(S, LC, tag);
32 return PostStmt(S, LC, tag);
34 return PreLoad(S, LC, tag);
36 return PostLoad(S, LC, tag);
38 return PreStore(S, LC, tag);
40 return PostLValue(S, LC, tag);
42 return PostStmtPurgeDeadSymbols(S, LC, tag);
44 return PreStmtPurgeDeadSymbols(S, LC, tag);
45 }
46}
47
48LLVM_DUMP_METHOD void ProgramPoint::dump() const {
49 return printJson(llvm::errs());
50}
51
53 switch (K) {
54 case BlockEdgeKind:
55 return "BlockEdge";
57 return "BlockEntrance";
58 case BlockExitKind:
59 return "BlockExit";
60 case PreStmtKind:
61 return "PreStmt";
63 return "PreStmtPurgeDeadSymbols";
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";
77 return "PostCondition";
78 case PostLValueKind:
79 return "PostLValue";
81 return "PostAllocatorCall";
83 return "PostInitializer";
84 case CallEnterKind:
85 return "CallEnter";
87 return "CallExitBegin";
88 case CallExitEndKind:
89 return "CallExitEnd";
91 return "FunctionExit";
93 return "PreImplicitCall";
95 return "PostImplicitCall";
96 case LoopExitKind:
97 return "LoopExit";
98 case EpsilonKind:
99 return "Epsilon";
100 }
101 llvm_unreachable("Unknown ProgramPoint kind");
102}
103
104std::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;
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:
123 case PostStmtKind:
124 case PreLoadKind:
125 case PostLoadKind:
126 case PreStoreKind:
127 case PostStoreKind:
129 case PostLValueKind:
131 if (const Stmt *S = castAs<StmtPoint>().getStmt())
132 return S->getBeginLoc();
133 return std::nullopt;
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;
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;
154 return castAs<ImplicitCallPoint>().getLocation();
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
167void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
168 const ASTContext &Context =
170 const SourceManager &SM = Context.getSourceManager();
171 const PrintingPolicy &PP = Context.getPrintingPolicy();
172 const bool AddQuotes = true;
173
174 Out << "\"kind\": \"";
175 switch (getKind()) {
177 Out << "BlockEntrance\""
178 << ", \"block_id\": "
179 << castAs<BlockEntrance>().getBlock()->getBlockID();
180 break;
181
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 }
197 llvm_unreachable("BlockExitKind");
198 break;
200 Out << "CallEnter\", \"callee_decl\": \"";
202 castAs<CallEnter>().getCalleeContext()->getDecl())
203 << '\"';
204 break;
206 Out << "CallExitBegin\"";
207 break;
209 Out << "CallExitEnd\"";
210 break;
212 Out << "EpsilonPoint\"";
213 break;
214
216 Out << "LoopExit\", \"stmt\": \""
217 << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"';
218 break;
219
221 ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
222 Out << "PreCall\", \"decl\": \""
224 << "\", \"location\": ";
226 break;
227 }
228
230 ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
231 Out << "PostCall\", \"decl\": \""
233 << "\", \"location\": ";
235 break;
236 }
237
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
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
357 StringRef Msg)
358 : Desc((MsgProvider + " : " + Msg).str()) {}
359
360StringRef SimpleProgramPointTag::getDebugTag() const { return Desc; }
Defines the clang::ASTContext interface.
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Expr * E
#define SM(sm)
Definition: OffloadArch.cpp:16
std::string Label
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
SourceManager & getSourceManager()
Definition: ASTContext.h:801
const LangOptions & getLangOpts() const
Definition: ASTContext.h:894
const clang::PrintingPolicy & getPrintingPolicy() const
Definition: ASTContext.h:793
static std::string getFunctionName(const Decl *D)
ASTContext & getASTContext() const
Represents a C++ base or member initializer.
Definition: DeclCXX.h:2369
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
Definition: DeclBase.cpp:251
Represents a member of a struct/union/class.
Definition: Decl.h:3157
Represents an implicit call event.
Definition: ProgramPoint.h:564
SourceLocation getLocation() const
Definition: ProgramPoint.h:572
const Decl * getDecl() const
Definition: ProgramPoint.h:571
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
std::string getQualifiedNameAsString() const
Definition: Decl.cpp:1680
Represents a point after we ran remove dead bindings AFTER processing the given statement.
Definition: ProgramPoint.h:494
Represents a point after we ran remove dead bindings BEFORE processing the given statement.
Definition: ProgramPoint.h:478
ProgramPoints can be "tagged" as representing points specific to a given analysis entity.
Definition: ProgramPoint.h:38
Kind getKind() const
Definition: ProgramPoint.h:162
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, const LocationContext *LC, const ProgramPointTag *tag)
static StringRef getProgramPointKindName(Kind K)
LLVM_DUMP_METHOD void dump() const
std::optional< SourceLocation > getSourceLocation() const
void printJson(llvm::raw_ostream &Out, const char *NL="\n") const
const LocationContext * getLocationContext() const
Definition: ProgramPoint.h:181
A (possibly-)qualified type.
Definition: TypeBase.h:937
QualType getLocalUnqualifiedType() const
Return this type with all of the instance-specific qualifiers removed, but without removing any quali...
Definition: TypeBase.h:1225
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:3160
StringRef getDebugTag() const override
The description of this program point which will be dumped for debugging purposes.
SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg)
This class handles loading and caching of source files into memory.
Stmt - This represents one statement.
Definition: Stmt.h:85
The JSON file list parser is used to communicate input to InstallAPI.
void printSourceLocationAsJson(raw_ostream &Out, SourceLocation Loc, const SourceManager &SM, bool AddBraces=true)
Definition: JsonSupport.h:82
const FunctionProtoType * T
Describes how types, statements, expressions, and declarations should be printed.
Definition: PrettyPrinter.h:57