10b57cec5SDimitry Andric //==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the interface ProgramPoint, which identifies a
100b57cec5SDimitry Andric // distinct location in a function.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "clang/Analysis/ProgramPoint.h"
15*5ffd83dbSDimitry Andric #include "clang/AST/ASTContext.h"
160b57cec5SDimitry Andric #include "clang/Basic/JsonSupport.h"
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric using namespace clang;
190b57cec5SDimitry Andric
~ProgramPointTag()200b57cec5SDimitry Andric ProgramPointTag::~ProgramPointTag() {}
210b57cec5SDimitry Andric
getProgramPoint(const Stmt * S,ProgramPoint::Kind K,const LocationContext * LC,const ProgramPointTag * tag)220b57cec5SDimitry Andric ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
230b57cec5SDimitry Andric const LocationContext *LC,
240b57cec5SDimitry Andric const ProgramPointTag *tag){
250b57cec5SDimitry Andric switch (K) {
260b57cec5SDimitry Andric default:
270b57cec5SDimitry Andric llvm_unreachable("Unhandled ProgramPoint kind");
280b57cec5SDimitry Andric case ProgramPoint::PreStmtKind:
290b57cec5SDimitry Andric return PreStmt(S, LC, tag);
300b57cec5SDimitry Andric case ProgramPoint::PostStmtKind:
310b57cec5SDimitry Andric return PostStmt(S, LC, tag);
320b57cec5SDimitry Andric case ProgramPoint::PreLoadKind:
330b57cec5SDimitry Andric return PreLoad(S, LC, tag);
340b57cec5SDimitry Andric case ProgramPoint::PostLoadKind:
350b57cec5SDimitry Andric return PostLoad(S, LC, tag);
360b57cec5SDimitry Andric case ProgramPoint::PreStoreKind:
370b57cec5SDimitry Andric return PreStore(S, LC, tag);
380b57cec5SDimitry Andric case ProgramPoint::PostLValueKind:
390b57cec5SDimitry Andric return PostLValue(S, LC, tag);
400b57cec5SDimitry Andric case ProgramPoint::PostStmtPurgeDeadSymbolsKind:
410b57cec5SDimitry Andric return PostStmtPurgeDeadSymbols(S, LC, tag);
420b57cec5SDimitry Andric case ProgramPoint::PreStmtPurgeDeadSymbolsKind:
430b57cec5SDimitry Andric return PreStmtPurgeDeadSymbols(S, LC, tag);
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric
dump() const470b57cec5SDimitry Andric LLVM_DUMP_METHOD void ProgramPoint::dump() const {
480b57cec5SDimitry Andric return printJson(llvm::errs());
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
printJson(llvm::raw_ostream & Out,const char * NL) const510b57cec5SDimitry Andric void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
520b57cec5SDimitry Andric const ASTContext &Context =
530b57cec5SDimitry Andric getLocationContext()->getAnalysisDeclContext()->getASTContext();
540b57cec5SDimitry Andric const SourceManager &SM = Context.getSourceManager();
550b57cec5SDimitry Andric const PrintingPolicy &PP = Context.getPrintingPolicy();
560b57cec5SDimitry Andric const bool AddQuotes = true;
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric Out << "\"kind\": \"";
590b57cec5SDimitry Andric switch (getKind()) {
600b57cec5SDimitry Andric case ProgramPoint::BlockEntranceKind:
610b57cec5SDimitry Andric Out << "BlockEntrance\""
620b57cec5SDimitry Andric << ", \"block_id\": "
630b57cec5SDimitry Andric << castAs<BlockEntrance>().getBlock()->getBlockID();
640b57cec5SDimitry Andric break;
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric case ProgramPoint::FunctionExitKind: {
670b57cec5SDimitry Andric auto FEP = getAs<FunctionExitPoint>();
680b57cec5SDimitry Andric Out << "FunctionExit\""
690b57cec5SDimitry Andric << ", \"block_id\": " << FEP->getBlock()->getBlockID()
700b57cec5SDimitry Andric << ", \"stmt_id\": ";
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric if (const ReturnStmt *RS = FEP->getStmt()) {
730b57cec5SDimitry Andric Out << RS->getID(Context) << ", \"stmt\": ";
740b57cec5SDimitry Andric RS->printJson(Out, nullptr, PP, AddQuotes);
750b57cec5SDimitry Andric } else {
760b57cec5SDimitry Andric Out << "null, \"stmt\": null";
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric break;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric case ProgramPoint::BlockExitKind:
810b57cec5SDimitry Andric llvm_unreachable("BlockExitKind");
820b57cec5SDimitry Andric break;
830b57cec5SDimitry Andric case ProgramPoint::CallEnterKind:
840b57cec5SDimitry Andric Out << "CallEnter\"";
850b57cec5SDimitry Andric break;
860b57cec5SDimitry Andric case ProgramPoint::CallExitBeginKind:
870b57cec5SDimitry Andric Out << "CallExitBegin\"";
880b57cec5SDimitry Andric break;
890b57cec5SDimitry Andric case ProgramPoint::CallExitEndKind:
900b57cec5SDimitry Andric Out << "CallExitEnd\"";
910b57cec5SDimitry Andric break;
920b57cec5SDimitry Andric case ProgramPoint::EpsilonKind:
930b57cec5SDimitry Andric Out << "EpsilonPoint\"";
940b57cec5SDimitry Andric break;
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric case ProgramPoint::LoopExitKind:
970b57cec5SDimitry Andric Out << "LoopExit\", \"stmt\": \""
980b57cec5SDimitry Andric << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"';
990b57cec5SDimitry Andric break;
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric case ProgramPoint::PreImplicitCallKind: {
1020b57cec5SDimitry Andric ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
1030b57cec5SDimitry Andric Out << "PreCall\", \"decl\": \""
1040b57cec5SDimitry Andric << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
1050b57cec5SDimitry Andric << "\", \"location\": ";
1060b57cec5SDimitry Andric printSourceLocationAsJson(Out, PC.getLocation(), SM);
1070b57cec5SDimitry Andric break;
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric
1100b57cec5SDimitry Andric case ProgramPoint::PostImplicitCallKind: {
1110b57cec5SDimitry Andric ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
1120b57cec5SDimitry Andric Out << "PostCall\", \"decl\": \""
1130b57cec5SDimitry Andric << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
1140b57cec5SDimitry Andric << "\", \"location\": ";
1150b57cec5SDimitry Andric printSourceLocationAsJson(Out, PC.getLocation(), SM);
1160b57cec5SDimitry Andric break;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric case ProgramPoint::PostInitializerKind: {
1200b57cec5SDimitry Andric Out << "PostInitializer\", ";
1210b57cec5SDimitry Andric const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer();
1220b57cec5SDimitry Andric if (const FieldDecl *FD = Init->getAnyMember()) {
1230b57cec5SDimitry Andric Out << "\"field_decl\": \"" << *FD << '\"';
1240b57cec5SDimitry Andric } else {
1250b57cec5SDimitry Andric Out << "\"type\": \"";
1260b57cec5SDimitry Andric QualType Ty = Init->getTypeSourceInfo()->getType();
1270b57cec5SDimitry Andric Ty = Ty.getLocalUnqualifiedType();
1280b57cec5SDimitry Andric Ty.print(Out, Context.getLangOpts());
1290b57cec5SDimitry Andric Out << '\"';
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric break;
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric case ProgramPoint::BlockEdgeKind: {
1350b57cec5SDimitry Andric const BlockEdge &E = castAs<BlockEdge>();
1360b57cec5SDimitry Andric const Stmt *T = E.getSrc()->getTerminatorStmt();
1370b57cec5SDimitry Andric Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID()
1380b57cec5SDimitry Andric << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": ";
1390b57cec5SDimitry Andric
1400b57cec5SDimitry Andric if (!T) {
1410b57cec5SDimitry Andric Out << "null, \"term_kind\": null";
1420b57cec5SDimitry Andric break;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(),
1460b57cec5SDimitry Andric /*AddQuotes=*/true);
1470b57cec5SDimitry Andric Out << ", \"location\": ";
1480b57cec5SDimitry Andric printSourceLocationAsJson(Out, T->getBeginLoc(), SM);
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric Out << ", \"term_kind\": \"";
1510b57cec5SDimitry Andric if (isa<SwitchStmt>(T)) {
1520b57cec5SDimitry Andric Out << "SwitchStmt\", \"case\": ";
1530b57cec5SDimitry Andric if (const Stmt *Label = E.getDst()->getLabel()) {
1540b57cec5SDimitry Andric if (const auto *C = dyn_cast<CaseStmt>(Label)) {
1550b57cec5SDimitry Andric Out << "{ \"lhs\": ";
1560b57cec5SDimitry Andric if (const Stmt *LHS = C->getLHS()) {
1570b57cec5SDimitry Andric LHS->printJson(Out, nullptr, PP, AddQuotes);
1580b57cec5SDimitry Andric } else {
1590b57cec5SDimitry Andric Out << "null";
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric Out << ", \"rhs\": ";
1630b57cec5SDimitry Andric if (const Stmt *RHS = C->getRHS()) {
1640b57cec5SDimitry Andric RHS->printJson(Out, nullptr, PP, AddQuotes);
1650b57cec5SDimitry Andric } else {
1660b57cec5SDimitry Andric Out << "null";
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric Out << " }";
1690b57cec5SDimitry Andric } else {
1700b57cec5SDimitry Andric assert(isa<DefaultStmt>(Label));
1710b57cec5SDimitry Andric Out << "\"default\"";
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric } else {
1740b57cec5SDimitry Andric Out << "\"implicit default\"";
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric } else if (isa<IndirectGotoStmt>(T)) {
1770b57cec5SDimitry Andric // FIXME: More info.
1780b57cec5SDimitry Andric Out << "IndirectGotoStmt\"";
1790b57cec5SDimitry Andric } else {
1800b57cec5SDimitry Andric Out << "Condition\", \"value\": "
1810b57cec5SDimitry Andric << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false");
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric break;
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric
1860b57cec5SDimitry Andric default: {
1870b57cec5SDimitry Andric const Stmt *S = castAs<StmtPoint>().getStmt();
1880b57cec5SDimitry Andric assert(S != nullptr && "Expecting non-null Stmt");
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andric Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName()
1910b57cec5SDimitry Andric << "\", \"stmt_id\": " << S->getID(Context)
192a7dea167SDimitry Andric << ", \"pointer\": \"" << (const void *)S << "\", ";
193a7dea167SDimitry Andric if (const auto *CS = dyn_cast<CastExpr>(S))
194a7dea167SDimitry Andric Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", ";
195a7dea167SDimitry Andric
196a7dea167SDimitry Andric Out << "\"pretty\": ";
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric S->printJson(Out, nullptr, PP, AddQuotes);
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric Out << ", \"location\": ";
2010b57cec5SDimitry Andric printSourceLocationAsJson(Out, S->getBeginLoc(), SM);
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric Out << ", \"stmt_point_kind\": \"";
2040b57cec5SDimitry Andric if (getAs<PreLoad>())
2050b57cec5SDimitry Andric Out << "PreLoad";
2060b57cec5SDimitry Andric else if (getAs<PreStore>())
2070b57cec5SDimitry Andric Out << "PreStore";
2080b57cec5SDimitry Andric else if (getAs<PostAllocatorCall>())
2090b57cec5SDimitry Andric Out << "PostAllocatorCall";
2100b57cec5SDimitry Andric else if (getAs<PostCondition>())
2110b57cec5SDimitry Andric Out << "PostCondition";
2120b57cec5SDimitry Andric else if (getAs<PostLoad>())
2130b57cec5SDimitry Andric Out << "PostLoad";
2140b57cec5SDimitry Andric else if (getAs<PostLValue>())
2150b57cec5SDimitry Andric Out << "PostLValue";
2160b57cec5SDimitry Andric else if (getAs<PostStore>())
2170b57cec5SDimitry Andric Out << "PostStore";
2180b57cec5SDimitry Andric else if (getAs<PostStmt>())
2190b57cec5SDimitry Andric Out << "PostStmt";
2200b57cec5SDimitry Andric else if (getAs<PostStmtPurgeDeadSymbols>())
2210b57cec5SDimitry Andric Out << "PostStmtPurgeDeadSymbols";
2220b57cec5SDimitry Andric else if (getAs<PreStmtPurgeDeadSymbols>())
2230b57cec5SDimitry Andric Out << "PreStmtPurgeDeadSymbols";
2240b57cec5SDimitry Andric else if (getAs<PreStmt>())
2250b57cec5SDimitry Andric Out << "PreStmt";
2260b57cec5SDimitry Andric else {
2270b57cec5SDimitry Andric Out << "\nKind: '" << getKind();
2280b57cec5SDimitry Andric llvm_unreachable("' is unhandled StmtPoint kind!");
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric
2310b57cec5SDimitry Andric Out << '\"';
2320b57cec5SDimitry Andric break;
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric
SimpleProgramPointTag(StringRef MsgProvider,StringRef Msg)2370b57cec5SDimitry Andric SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider,
2380b57cec5SDimitry Andric StringRef Msg)
2390b57cec5SDimitry Andric : Desc((MsgProvider + " : " + Msg).str()) {}
2400b57cec5SDimitry Andric
getTagDescription() const2410b57cec5SDimitry Andric StringRef SimpleProgramPointTag::getTagDescription() const {
2420b57cec5SDimitry Andric return Desc;
2430b57cec5SDimitry Andric }
244