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