1 //==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the interface ProgramPoint, which identifies a
10 // distinct location in a function.
12 //===----------------------------------------------------------------------===//
14 #include "clang/Analysis/ProgramPoint.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/Basic/JsonSupport.h"
18 using namespace clang
;
20 ProgramPointTag::~ProgramPointTag() {}
22 ProgramPoint
ProgramPoint::getProgramPoint(const Stmt
*S
, ProgramPoint::Kind K
,
23 const LocationContext
*LC
,
24 const ProgramPointTag
*tag
){
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
);
47 LLVM_DUMP_METHOD
void ProgramPoint::dump() const {
48 return printJson(llvm::errs());
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;
58 Out
<< "\"kind\": \"";
60 case ProgramPoint::BlockEntranceKind
:
61 Out
<< "BlockEntrance\""
63 << castAs
<BlockEntrance
>().getBlock()->getBlockID();
66 case ProgramPoint::FunctionExitKind
: {
67 auto FEP
= getAs
<FunctionExitPoint
>();
68 Out
<< "FunctionExit\""
69 << ", \"block_id\": " << FEP
->getBlock()->getBlockID()
72 if (const ReturnStmt
*RS
= FEP
->getStmt()) {
73 Out
<< RS
->getID(Context
) << ", \"stmt\": ";
74 RS
->printJson(Out
, nullptr, PP
, AddQuotes
);
76 Out
<< "null, \"stmt\": null";
80 case ProgramPoint::BlockExitKind
:
81 llvm_unreachable("BlockExitKind");
83 case ProgramPoint::CallEnterKind
:
86 case ProgramPoint::CallExitBeginKind
:
87 Out
<< "CallExitBegin\"";
89 case ProgramPoint::CallExitEndKind
:
90 Out
<< "CallExitEnd\"";
92 case ProgramPoint::EpsilonKind
:
93 Out
<< "EpsilonPoint\"";
96 case ProgramPoint::LoopExitKind
:
97 Out
<< "LoopExit\", \"stmt\": \""
98 << castAs
<LoopExit
>().getLoopStmt()->getStmtClassName() << '\"';
101 case ProgramPoint::PreImplicitCallKind
: {
102 ImplicitCallPoint PC
= castAs
<ImplicitCallPoint
>();
103 Out
<< "PreCall\", \"decl\": \""
104 << PC
.getDecl()->getAsFunction()->getQualifiedNameAsString()
105 << "\", \"location\": ";
106 printSourceLocationAsJson(Out
, PC
.getLocation(), SM
);
110 case ProgramPoint::PostImplicitCallKind
: {
111 ImplicitCallPoint PC
= castAs
<ImplicitCallPoint
>();
112 Out
<< "PostCall\", \"decl\": \""
113 << PC
.getDecl()->getAsFunction()->getQualifiedNameAsString()
114 << "\", \"location\": ";
115 printSourceLocationAsJson(Out
, PC
.getLocation(), SM
);
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
<< '\"';
125 Out
<< "\"type\": \"";
126 QualType Ty
= Init
->getTypeSourceInfo()->getType();
127 Ty
= Ty
.getLocalUnqualifiedType();
128 Ty
.print(Out
, Context
.getLangOpts());
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\": ";
141 Out
<< "null, \"term_kind\": null";
145 E
.getSrc()->printTerminatorJson(Out
, Context
.getLangOpts(),
147 Out
<< ", \"location\": ";
148 printSourceLocationAsJson(Out
, T
->getBeginLoc(), SM
);
150 Out
<< ", \"term_kind\": \"";
151 if (isa
<SwitchStmt
>(T
)) {
152 Out
<< "SwitchStmt\", \"case\": ";
153 if (const Stmt
*Label
= E
.getDst()->getLabel()) {
154 if (const auto *C
= dyn_cast
<CaseStmt
>(Label
)) {
155 Out
<< "{ \"lhs\": ";
156 if (const Stmt
*LHS
= C
->getLHS()) {
157 LHS
->printJson(Out
, nullptr, PP
, AddQuotes
);
162 Out
<< ", \"rhs\": ";
163 if (const Stmt
*RHS
= C
->getRHS()) {
164 RHS
->printJson(Out
, nullptr, PP
, AddQuotes
);
170 assert(isa
<DefaultStmt
>(Label
));
171 Out
<< "\"default\"";
174 Out
<< "\"implicit default\"";
176 } else if (isa
<IndirectGotoStmt
>(T
)) {
178 Out
<< "IndirectGotoStmt\"";
180 Out
<< "Condition\", \"value\": "
181 << (*E
.getSrc()->succ_begin() == E
.getDst() ? "true" : "false");
187 const Stmt
*S
= castAs
<StmtPoint
>().getStmt();
188 assert(S
!= nullptr && "Expecting non-null Stmt");
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
>(S
))
194 Out
<< "\"cast_kind\": \"" << CS
->getCastKindName() << "\", ";
196 Out
<< "\"pretty\": ";
198 S
->printJson(Out
, nullptr, PP
, AddQuotes
);
200 Out
<< ", \"location\": ";
201 printSourceLocationAsJson(Out
, S
->getBeginLoc(), SM
);
203 Out
<< ", \"stmt_point_kind\": \"";
204 if (getAs
<PreLoad
>())
206 else if (getAs
<PreStore
>())
208 else if (getAs
<PostAllocatorCall
>())
209 Out
<< "PostAllocatorCall";
210 else if (getAs
<PostCondition
>())
211 Out
<< "PostCondition";
212 else if (getAs
<PostLoad
>())
214 else if (getAs
<PostLValue
>())
216 else if (getAs
<PostStore
>())
218 else if (getAs
<PostStmt
>())
220 else if (getAs
<PostStmtPurgeDeadSymbols
>())
221 Out
<< "PostStmtPurgeDeadSymbols";
222 else if (getAs
<PreStmtPurgeDeadSymbols
>())
223 Out
<< "PreStmtPurgeDeadSymbols";
224 else if (getAs
<PreStmt
>())
227 Out
<< "\nKind: '" << getKind();
228 llvm_unreachable("' is unhandled StmtPoint kind!");
237 SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider
,
239 : Desc((MsgProvider
+ " : " + Msg
).str()) {}
241 StringRef
SimpleProgramPointTag::getTagDescription() const {