1e8f7316fSTed Kremenek //==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/
2e8f7316fSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8f7316fSTed Kremenek //
7e8f7316fSTed Kremenek //===----------------------------------------------------------------------===//
8e8f7316fSTed Kremenek //
9e8f7316fSTed Kremenek // This file defines the interface ProgramPoint, which identifies a
10e8f7316fSTed Kremenek // distinct location in a function.
11e8f7316fSTed Kremenek //
12e8f7316fSTed Kremenek //===----------------------------------------------------------------------===//
13e8f7316fSTed Kremenek
14e8f7316fSTed Kremenek #include "clang/Analysis/ProgramPoint.h"
15*b36c19bcSReid Kleckner #include "clang/AST/ASTContext.h"
16ed035ff8SArtem Dergachev #include "clang/Basic/JsonSupport.h"
17e8f7316fSTed Kremenek
18e8f7316fSTed Kremenek using namespace clang;
19e8f7316fSTed Kremenek
~ProgramPointTag()20637d1e66SAngel Garcia Gomez ProgramPointTag::~ProgramPointTag() {}
21e8f7316fSTed Kremenek
getProgramPoint(const Stmt * S,ProgramPoint::Kind K,const LocationContext * LC,const ProgramPointTag * tag)228de8cfddSAnna Zaks ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
238de8cfddSAnna Zaks const LocationContext *LC,
248de8cfddSAnna Zaks const ProgramPointTag *tag){
258de8cfddSAnna Zaks switch (K) {
268de8cfddSAnna Zaks default:
278de8cfddSAnna Zaks llvm_unreachable("Unhandled ProgramPoint kind");
288de8cfddSAnna Zaks case ProgramPoint::PreStmtKind:
298de8cfddSAnna Zaks return PreStmt(S, LC, tag);
308de8cfddSAnna Zaks case ProgramPoint::PostStmtKind:
318de8cfddSAnna Zaks return PostStmt(S, LC, tag);
328de8cfddSAnna Zaks case ProgramPoint::PreLoadKind:
338de8cfddSAnna Zaks return PreLoad(S, LC, tag);
348de8cfddSAnna Zaks case ProgramPoint::PostLoadKind:
358de8cfddSAnna Zaks return PostLoad(S, LC, tag);
368de8cfddSAnna Zaks case ProgramPoint::PreStoreKind:
378de8cfddSAnna Zaks return PreStore(S, LC, tag);
388de8cfddSAnna Zaks case ProgramPoint::PostLValueKind:
398de8cfddSAnna Zaks return PostLValue(S, LC, tag);
407e53bd6fSAnna Zaks case ProgramPoint::PostStmtPurgeDeadSymbolsKind:
417e53bd6fSAnna Zaks return PostStmtPurgeDeadSymbols(S, LC, tag);
427e53bd6fSAnna Zaks case ProgramPoint::PreStmtPurgeDeadSymbolsKind:
437e53bd6fSAnna Zaks return PreStmtPurgeDeadSymbols(S, LC, tag);
448de8cfddSAnna Zaks }
458de8cfddSAnna Zaks }
468de8cfddSAnna Zaks
dump() const47407584c4SEric Fiselier LLVM_DUMP_METHOD void ProgramPoint::dump() const {
4813e491ccSCsaba Dabis return printJson(llvm::errs());
49407584c4SEric Fiselier }
50407584c4SEric Fiselier
printJson(llvm::raw_ostream & Out,const char * NL) const5113e491ccSCsaba Dabis void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
5227ec210fSGeorge Karpenkov const ASTContext &Context =
5327ec210fSGeorge Karpenkov getLocationContext()->getAnalysisDeclContext()->getASTContext();
5427ec210fSGeorge Karpenkov const SourceManager &SM = Context.getSourceManager();
559ee26c8dSCsaba Dabis const PrintingPolicy &PP = Context.getPrintingPolicy();
569ee26c8dSCsaba Dabis const bool AddQuotes = true;
5713e491ccSCsaba Dabis
5813e491ccSCsaba Dabis Out << "\"kind\": \"";
5927ec210fSGeorge Karpenkov switch (getKind()) {
6027ec210fSGeorge Karpenkov case ProgramPoint::BlockEntranceKind:
6113e491ccSCsaba Dabis Out << "BlockEntrance\""
6213e491ccSCsaba Dabis << ", \"block_id\": "
6327ec210fSGeorge Karpenkov << castAs<BlockEntrance>().getBlock()->getBlockID();
6427ec210fSGeorge Karpenkov break;
6527ec210fSGeorge Karpenkov
6627ec210fSGeorge Karpenkov case ProgramPoint::FunctionExitKind: {
6727ec210fSGeorge Karpenkov auto FEP = getAs<FunctionExitPoint>();
6813e491ccSCsaba Dabis Out << "FunctionExit\""
6913e491ccSCsaba Dabis << ", \"block_id\": " << FEP->getBlock()->getBlockID()
7013e491ccSCsaba Dabis << ", \"stmt_id\": ";
7113e491ccSCsaba Dabis
7227ec210fSGeorge Karpenkov if (const ReturnStmt *RS = FEP->getStmt()) {
739ee26c8dSCsaba Dabis Out << RS->getID(Context) << ", \"stmt\": ";
749ee26c8dSCsaba Dabis RS->printJson(Out, nullptr, PP, AddQuotes);
7513e491ccSCsaba Dabis } else {
7613e491ccSCsaba Dabis Out << "null, \"stmt\": null";
7727ec210fSGeorge Karpenkov }
7827ec210fSGeorge Karpenkov break;
7927ec210fSGeorge Karpenkov }
8027ec210fSGeorge Karpenkov case ProgramPoint::BlockExitKind:
8113e491ccSCsaba Dabis llvm_unreachable("BlockExitKind");
8227ec210fSGeorge Karpenkov break;
8327ec210fSGeorge Karpenkov case ProgramPoint::CallEnterKind:
8413e491ccSCsaba Dabis Out << "CallEnter\"";
8527ec210fSGeorge Karpenkov break;
8627ec210fSGeorge Karpenkov case ProgramPoint::CallExitBeginKind:
8713e491ccSCsaba Dabis Out << "CallExitBegin\"";
8827ec210fSGeorge Karpenkov break;
8927ec210fSGeorge Karpenkov case ProgramPoint::CallExitEndKind:
9013e491ccSCsaba Dabis Out << "CallExitEnd\"";
9127ec210fSGeorge Karpenkov break;
9227ec210fSGeorge Karpenkov case ProgramPoint::EpsilonKind:
9313e491ccSCsaba Dabis Out << "EpsilonPoint\"";
9427ec210fSGeorge Karpenkov break;
9527ec210fSGeorge Karpenkov
9613e491ccSCsaba Dabis case ProgramPoint::LoopExitKind:
9713e491ccSCsaba Dabis Out << "LoopExit\", \"stmt\": \""
9813e491ccSCsaba Dabis << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"';
9927ec210fSGeorge Karpenkov break;
10027ec210fSGeorge Karpenkov
10127ec210fSGeorge Karpenkov case ProgramPoint::PreImplicitCallKind: {
10227ec210fSGeorge Karpenkov ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
10302be6506SCsaba Dabis Out << "PreCall\", \"decl\": \""
104ed035ff8SArtem Dergachev << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
105ed035ff8SArtem Dergachev << "\", \"location\": ";
106ed035ff8SArtem Dergachev printSourceLocationAsJson(Out, PC.getLocation(), SM);
10727ec210fSGeorge Karpenkov break;
10827ec210fSGeorge Karpenkov }
10927ec210fSGeorge Karpenkov
11027ec210fSGeorge Karpenkov case ProgramPoint::PostImplicitCallKind: {
11127ec210fSGeorge Karpenkov ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
11202be6506SCsaba Dabis Out << "PostCall\", \"decl\": \""
113ed035ff8SArtem Dergachev << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
114ed035ff8SArtem Dergachev << "\", \"location\": ";
115ed035ff8SArtem Dergachev printSourceLocationAsJson(Out, PC.getLocation(), SM);
11627ec210fSGeorge Karpenkov break;
11727ec210fSGeorge Karpenkov }
11827ec210fSGeorge Karpenkov
11927ec210fSGeorge Karpenkov case ProgramPoint::PostInitializerKind: {
12013e491ccSCsaba Dabis Out << "PostInitializer\", ";
12127ec210fSGeorge Karpenkov const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer();
12213e491ccSCsaba Dabis if (const FieldDecl *FD = Init->getAnyMember()) {
12313e491ccSCsaba Dabis Out << "\"field_decl\": \"" << *FD << '\"';
12413e491ccSCsaba Dabis } else {
12513e491ccSCsaba Dabis Out << "\"type\": \"";
12627ec210fSGeorge Karpenkov QualType Ty = Init->getTypeSourceInfo()->getType();
12727ec210fSGeorge Karpenkov Ty = Ty.getLocalUnqualifiedType();
12827ec210fSGeorge Karpenkov Ty.print(Out, Context.getLangOpts());
12913e491ccSCsaba Dabis Out << '\"';
13027ec210fSGeorge Karpenkov }
13127ec210fSGeorge Karpenkov break;
13227ec210fSGeorge Karpenkov }
13327ec210fSGeorge Karpenkov
13427ec210fSGeorge Karpenkov case ProgramPoint::BlockEdgeKind: {
13527ec210fSGeorge Karpenkov const BlockEdge &E = castAs<BlockEdge>();
13613e491ccSCsaba Dabis const Stmt *T = E.getSrc()->getTerminatorStmt();
13713e491ccSCsaba Dabis Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID()
138dea605e0SCsaba Dabis << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": ";
13927ec210fSGeorge Karpenkov
140dea605e0SCsaba Dabis if (!T) {
141dea605e0SCsaba Dabis Out << "null, \"term_kind\": null";
142dea605e0SCsaba Dabis break;
143dea605e0SCsaba Dabis }
144dea605e0SCsaba Dabis
145dea605e0SCsaba Dabis E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(),
146dea605e0SCsaba Dabis /*AddQuotes=*/true);
147ed035ff8SArtem Dergachev Out << ", \"location\": ";
148ed035ff8SArtem Dergachev printSourceLocationAsJson(Out, T->getBeginLoc(), SM);
14927ec210fSGeorge Karpenkov
1509ee26c8dSCsaba Dabis Out << ", \"term_kind\": \"";
15127ec210fSGeorge Karpenkov if (isa<SwitchStmt>(T)) {
15213e491ccSCsaba Dabis Out << "SwitchStmt\", \"case\": ";
15313e491ccSCsaba Dabis if (const Stmt *Label = E.getDst()->getLabel()) {
15427ec210fSGeorge Karpenkov if (const auto *C = dyn_cast<CaseStmt>(Label)) {
15513e491ccSCsaba Dabis Out << "{ \"lhs\": ";
1569ee26c8dSCsaba Dabis if (const Stmt *LHS = C->getLHS()) {
1579ee26c8dSCsaba Dabis LHS->printJson(Out, nullptr, PP, AddQuotes);
1589ee26c8dSCsaba Dabis } else {
15913e491ccSCsaba Dabis Out << "null";
1609ee26c8dSCsaba Dabis }
1619ee26c8dSCsaba Dabis
16213e491ccSCsaba Dabis Out << ", \"rhs\": ";
1639ee26c8dSCsaba Dabis if (const Stmt *RHS = C->getRHS()) {
1649ee26c8dSCsaba Dabis RHS->printJson(Out, nullptr, PP, AddQuotes);
1659ee26c8dSCsaba Dabis } else {
16613e491ccSCsaba Dabis Out << "null";
1679ee26c8dSCsaba Dabis }
16813e491ccSCsaba Dabis Out << " }";
16927ec210fSGeorge Karpenkov } else {
17027ec210fSGeorge Karpenkov assert(isa<DefaultStmt>(Label));
17113e491ccSCsaba Dabis Out << "\"default\"";
17227ec210fSGeorge Karpenkov }
17327ec210fSGeorge Karpenkov } else {
17413e491ccSCsaba Dabis Out << "\"implicit default\"";
17527ec210fSGeorge Karpenkov }
17613e491ccSCsaba Dabis } else if (isa<IndirectGotoStmt>(T)) {
17713e491ccSCsaba Dabis // FIXME: More info.
17813e491ccSCsaba Dabis Out << "IndirectGotoStmt\"";
17913e491ccSCsaba Dabis } else {
18013e491ccSCsaba Dabis Out << "Condition\", \"value\": "
18113e491ccSCsaba Dabis << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false");
18227ec210fSGeorge Karpenkov }
18327ec210fSGeorge Karpenkov break;
18427ec210fSGeorge Karpenkov }
18527ec210fSGeorge Karpenkov
18627ec210fSGeorge Karpenkov default: {
18727ec210fSGeorge Karpenkov const Stmt *S = castAs<StmtPoint>().getStmt();
18827ec210fSGeorge Karpenkov assert(S != nullptr && "Expecting non-null Stmt");
18927ec210fSGeorge Karpenkov
19013e491ccSCsaba Dabis Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName()
19113e491ccSCsaba Dabis << "\", \"stmt_id\": " << S->getID(Context)
192d325196fSArtem Dergachev << ", \"pointer\": \"" << (const void *)S << "\", ";
193d325196fSArtem Dergachev if (const auto *CS = dyn_cast<CastExpr>(S))
194d325196fSArtem Dergachev Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", ";
195d325196fSArtem Dergachev
196d325196fSArtem Dergachev Out << "\"pretty\": ";
19713e491ccSCsaba Dabis
1989ee26c8dSCsaba Dabis S->printJson(Out, nullptr, PP, AddQuotes);
19913e491ccSCsaba Dabis
200ed035ff8SArtem Dergachev Out << ", \"location\": ";
201ed035ff8SArtem Dergachev printSourceLocationAsJson(Out, S->getBeginLoc(), SM);
20213e491ccSCsaba Dabis
203fa880e61SCsaba Dabis Out << ", \"stmt_point_kind\": \"";
204fa880e61SCsaba Dabis if (getAs<PreLoad>())
205fa880e61SCsaba Dabis Out << "PreLoad";
206fa880e61SCsaba Dabis else if (getAs<PreStore>())
207fa880e61SCsaba Dabis Out << "PreStore";
20827ec210fSGeorge Karpenkov else if (getAs<PostAllocatorCall>())
209fa880e61SCsaba Dabis Out << "PostAllocatorCall";
210fa880e61SCsaba Dabis else if (getAs<PostCondition>())
211fa880e61SCsaba Dabis Out << "PostCondition";
212fa880e61SCsaba Dabis else if (getAs<PostLoad>())
213fa880e61SCsaba Dabis Out << "PostLoad";
214fa880e61SCsaba Dabis else if (getAs<PostLValue>())
215fa880e61SCsaba Dabis Out << "PostLValue";
216fa880e61SCsaba Dabis else if (getAs<PostStore>())
217fa880e61SCsaba Dabis Out << "PostStore";
218fa880e61SCsaba Dabis else if (getAs<PostStmt>())
219fa880e61SCsaba Dabis Out << "PostStmt";
220fa880e61SCsaba Dabis else if (getAs<PostStmtPurgeDeadSymbols>())
221fa880e61SCsaba Dabis Out << "PostStmtPurgeDeadSymbols";
222fa880e61SCsaba Dabis else if (getAs<PreStmtPurgeDeadSymbols>())
223fa880e61SCsaba Dabis Out << "PreStmtPurgeDeadSymbols";
224fa880e61SCsaba Dabis else if (getAs<PreStmt>())
225fa880e61SCsaba Dabis Out << "PreStmt";
226fa880e61SCsaba Dabis else {
227fa880e61SCsaba Dabis Out << "\nKind: '" << getKind();
228fa880e61SCsaba Dabis llvm_unreachable("' is unhandled StmtPoint kind!");
229fa880e61SCsaba Dabis }
23027ec210fSGeorge Karpenkov
231fa880e61SCsaba Dabis Out << '\"';
23227ec210fSGeorge Karpenkov break;
23327ec210fSGeorge Karpenkov }
23427ec210fSGeorge Karpenkov }
23527ec210fSGeorge Karpenkov }
23627ec210fSGeorge Karpenkov
SimpleProgramPointTag(StringRef MsgProvider,StringRef Msg)2376a619222SAnton Yartsev SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider,
2386a619222SAnton Yartsev StringRef Msg)
2396a619222SAnton Yartsev : Desc((MsgProvider + " : " + Msg).str()) {}
240e8f7316fSTed Kremenek
getTagDescription() const241e8f7316fSTed Kremenek StringRef SimpleProgramPointTag::getTagDescription() const {
2426a619222SAnton Yartsev return Desc;
243e8f7316fSTed Kremenek }
244