//==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/ // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the interface ProgramPoint, which identifies a // distinct location in a function. // //===----------------------------------------------------------------------===// #include "clang/Analysis/ProgramPoint.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/JsonSupport.h" using namespace clang; ProgramPointTag::~ProgramPointTag() {} ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K, const LocationContext *LC, const ProgramPointTag *tag){ switch (K) { default: llvm_unreachable("Unhandled ProgramPoint kind"); case ProgramPoint::PreStmtKind: return PreStmt(S, LC, tag); case ProgramPoint::PostStmtKind: return PostStmt(S, LC, tag); case ProgramPoint::PreLoadKind: return PreLoad(S, LC, tag); case ProgramPoint::PostLoadKind: return PostLoad(S, LC, tag); case ProgramPoint::PreStoreKind: return PreStore(S, LC, tag); case ProgramPoint::PostLValueKind: return PostLValue(S, LC, tag); case ProgramPoint::PostStmtPurgeDeadSymbolsKind: return PostStmtPurgeDeadSymbols(S, LC, tag); case ProgramPoint::PreStmtPurgeDeadSymbolsKind: return PreStmtPurgeDeadSymbols(S, LC, tag); } } LLVM_DUMP_METHOD void ProgramPoint::dump() const { return printJson(llvm::errs()); } void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const { const ASTContext &Context = getLocationContext()->getAnalysisDeclContext()->getASTContext(); const SourceManager &SM = Context.getSourceManager(); const PrintingPolicy &PP = Context.getPrintingPolicy(); const bool AddQuotes = true; Out << "\"kind\": \""; switch (getKind()) { case ProgramPoint::BlockEntranceKind: Out << "BlockEntrance\"" << ", \"block_id\": " << castAs().getBlock()->getBlockID(); break; case ProgramPoint::FunctionExitKind: { auto FEP = getAs(); Out << "FunctionExit\"" << ", \"block_id\": " << FEP->getBlock()->getBlockID() << ", \"stmt_id\": "; if (const ReturnStmt *RS = FEP->getStmt()) { Out << RS->getID(Context) << ", \"stmt\": "; RS->printJson(Out, nullptr, PP, AddQuotes); } else { Out << "null, \"stmt\": null"; } break; } case ProgramPoint::BlockExitKind: llvm_unreachable("BlockExitKind"); break; case ProgramPoint::CallEnterKind: Out << "CallEnter\""; break; case ProgramPoint::CallExitBeginKind: Out << "CallExitBegin\""; break; case ProgramPoint::CallExitEndKind: Out << "CallExitEnd\""; break; case ProgramPoint::EpsilonKind: Out << "EpsilonPoint\""; break; case ProgramPoint::LoopExitKind: Out << "LoopExit\", \"stmt\": \"" << castAs().getLoopStmt()->getStmtClassName() << '\"'; break; case ProgramPoint::PreImplicitCallKind: { ImplicitCallPoint PC = castAs(); Out << "PreCall\", \"decl\": \"" << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() << "\", \"location\": "; printSourceLocationAsJson(Out, PC.getLocation(), SM); break; } case ProgramPoint::PostImplicitCallKind: { ImplicitCallPoint PC = castAs(); Out << "PostCall\", \"decl\": \"" << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() << "\", \"location\": "; printSourceLocationAsJson(Out, PC.getLocation(), SM); break; } case ProgramPoint::PostInitializerKind: { Out << "PostInitializer\", "; const CXXCtorInitializer *Init = castAs().getInitializer(); if (const FieldDecl *FD = Init->getAnyMember()) { Out << "\"field_decl\": \"" << *FD << '\"'; } else { Out << "\"type\": \""; QualType Ty = Init->getTypeSourceInfo()->getType(); Ty = Ty.getLocalUnqualifiedType(); Ty.print(Out, Context.getLangOpts()); Out << '\"'; } break; } case ProgramPoint::BlockEdgeKind: { const BlockEdge &E = castAs(); const Stmt *T = E.getSrc()->getTerminatorStmt(); Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID() << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": "; if (!T) { Out << "null, \"term_kind\": null"; break; } E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(), /*AddQuotes=*/true); Out << ", \"location\": "; printSourceLocationAsJson(Out, T->getBeginLoc(), SM); Out << ", \"term_kind\": \""; if (isa(T)) { Out << "SwitchStmt\", \"case\": "; if (const Stmt *Label = E.getDst()->getLabel()) { if (const auto *C = dyn_cast(Label)) { Out << "{ \"lhs\": "; if (const Stmt *LHS = C->getLHS()) { LHS->printJson(Out, nullptr, PP, AddQuotes); } else { Out << "null"; } Out << ", \"rhs\": "; if (const Stmt *RHS = C->getRHS()) { RHS->printJson(Out, nullptr, PP, AddQuotes); } else { Out << "null"; } Out << " }"; } else { assert(isa(Label)); Out << "\"default\""; } } else { Out << "\"implicit default\""; } } else if (isa(T)) { // FIXME: More info. Out << "IndirectGotoStmt\""; } else { Out << "Condition\", \"value\": " << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false"); } break; } default: { const Stmt *S = castAs().getStmt(); assert(S != nullptr && "Expecting non-null Stmt"); Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName() << "\", \"stmt_id\": " << S->getID(Context) << ", \"pointer\": \"" << (const void *)S << "\", "; if (const auto *CS = dyn_cast(S)) Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", "; Out << "\"pretty\": "; S->printJson(Out, nullptr, PP, AddQuotes); Out << ", \"location\": "; printSourceLocationAsJson(Out, S->getBeginLoc(), SM); Out << ", \"stmt_point_kind\": \""; if (getAs()) Out << "PreLoad"; else if (getAs()) Out << "PreStore"; else if (getAs()) Out << "PostAllocatorCall"; else if (getAs()) Out << "PostCondition"; else if (getAs()) Out << "PostLoad"; else if (getAs()) Out << "PostLValue"; else if (getAs()) Out << "PostStore"; else if (getAs()) Out << "PostStmt"; else if (getAs()) Out << "PostStmtPurgeDeadSymbols"; else if (getAs()) Out << "PreStmtPurgeDeadSymbols"; else if (getAs()) Out << "PreStmt"; else { Out << "\nKind: '" << getKind(); llvm_unreachable("' is unhandled StmtPoint kind!"); } Out << '\"'; break; } } } SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg) : Desc((MsgProvider + " : " + Msg).str()) {} StringRef SimpleProgramPointTag::getTagDescription() const { return Desc; }