xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/ProgramPoint.cpp (revision e25152834cdf3b353892835a4f3b157e066a8ed4)
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