1*0b57cec5SDimitry Andric //==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/ 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file defines the interface ProgramPoint, which identifies a 10*0b57cec5SDimitry Andric // distinct location in a function. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "clang/Analysis/ProgramPoint.h" 15*0b57cec5SDimitry Andric #include "clang/Basic/JsonSupport.h" 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric using namespace clang; 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric ProgramPointTag::~ProgramPointTag() {} 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K, 22*0b57cec5SDimitry Andric const LocationContext *LC, 23*0b57cec5SDimitry Andric const ProgramPointTag *tag){ 24*0b57cec5SDimitry Andric switch (K) { 25*0b57cec5SDimitry Andric default: 26*0b57cec5SDimitry Andric llvm_unreachable("Unhandled ProgramPoint kind"); 27*0b57cec5SDimitry Andric case ProgramPoint::PreStmtKind: 28*0b57cec5SDimitry Andric return PreStmt(S, LC, tag); 29*0b57cec5SDimitry Andric case ProgramPoint::PostStmtKind: 30*0b57cec5SDimitry Andric return PostStmt(S, LC, tag); 31*0b57cec5SDimitry Andric case ProgramPoint::PreLoadKind: 32*0b57cec5SDimitry Andric return PreLoad(S, LC, tag); 33*0b57cec5SDimitry Andric case ProgramPoint::PostLoadKind: 34*0b57cec5SDimitry Andric return PostLoad(S, LC, tag); 35*0b57cec5SDimitry Andric case ProgramPoint::PreStoreKind: 36*0b57cec5SDimitry Andric return PreStore(S, LC, tag); 37*0b57cec5SDimitry Andric case ProgramPoint::PostLValueKind: 38*0b57cec5SDimitry Andric return PostLValue(S, LC, tag); 39*0b57cec5SDimitry Andric case ProgramPoint::PostStmtPurgeDeadSymbolsKind: 40*0b57cec5SDimitry Andric return PostStmtPurgeDeadSymbols(S, LC, tag); 41*0b57cec5SDimitry Andric case ProgramPoint::PreStmtPurgeDeadSymbolsKind: 42*0b57cec5SDimitry Andric return PreStmtPurgeDeadSymbols(S, LC, tag); 43*0b57cec5SDimitry Andric } 44*0b57cec5SDimitry Andric } 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void ProgramPoint::dump() const { 47*0b57cec5SDimitry Andric return printJson(llvm::errs()); 48*0b57cec5SDimitry Andric } 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const { 51*0b57cec5SDimitry Andric const ASTContext &Context = 52*0b57cec5SDimitry Andric getLocationContext()->getAnalysisDeclContext()->getASTContext(); 53*0b57cec5SDimitry Andric const SourceManager &SM = Context.getSourceManager(); 54*0b57cec5SDimitry Andric const PrintingPolicy &PP = Context.getPrintingPolicy(); 55*0b57cec5SDimitry Andric const bool AddQuotes = true; 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric Out << "\"kind\": \""; 58*0b57cec5SDimitry Andric switch (getKind()) { 59*0b57cec5SDimitry Andric case ProgramPoint::BlockEntranceKind: 60*0b57cec5SDimitry Andric Out << "BlockEntrance\"" 61*0b57cec5SDimitry Andric << ", \"block_id\": " 62*0b57cec5SDimitry Andric << castAs<BlockEntrance>().getBlock()->getBlockID(); 63*0b57cec5SDimitry Andric break; 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric case ProgramPoint::FunctionExitKind: { 66*0b57cec5SDimitry Andric auto FEP = getAs<FunctionExitPoint>(); 67*0b57cec5SDimitry Andric Out << "FunctionExit\"" 68*0b57cec5SDimitry Andric << ", \"block_id\": " << FEP->getBlock()->getBlockID() 69*0b57cec5SDimitry Andric << ", \"stmt_id\": "; 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric if (const ReturnStmt *RS = FEP->getStmt()) { 72*0b57cec5SDimitry Andric Out << RS->getID(Context) << ", \"stmt\": "; 73*0b57cec5SDimitry Andric RS->printJson(Out, nullptr, PP, AddQuotes); 74*0b57cec5SDimitry Andric } else { 75*0b57cec5SDimitry Andric Out << "null, \"stmt\": null"; 76*0b57cec5SDimitry Andric } 77*0b57cec5SDimitry Andric break; 78*0b57cec5SDimitry Andric } 79*0b57cec5SDimitry Andric case ProgramPoint::BlockExitKind: 80*0b57cec5SDimitry Andric llvm_unreachable("BlockExitKind"); 81*0b57cec5SDimitry Andric break; 82*0b57cec5SDimitry Andric case ProgramPoint::CallEnterKind: 83*0b57cec5SDimitry Andric Out << "CallEnter\""; 84*0b57cec5SDimitry Andric break; 85*0b57cec5SDimitry Andric case ProgramPoint::CallExitBeginKind: 86*0b57cec5SDimitry Andric Out << "CallExitBegin\""; 87*0b57cec5SDimitry Andric break; 88*0b57cec5SDimitry Andric case ProgramPoint::CallExitEndKind: 89*0b57cec5SDimitry Andric Out << "CallExitEnd\""; 90*0b57cec5SDimitry Andric break; 91*0b57cec5SDimitry Andric case ProgramPoint::EpsilonKind: 92*0b57cec5SDimitry Andric Out << "EpsilonPoint\""; 93*0b57cec5SDimitry Andric break; 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric case ProgramPoint::LoopExitKind: 96*0b57cec5SDimitry Andric Out << "LoopExit\", \"stmt\": \"" 97*0b57cec5SDimitry Andric << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"'; 98*0b57cec5SDimitry Andric break; 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric case ProgramPoint::PreImplicitCallKind: { 101*0b57cec5SDimitry Andric ImplicitCallPoint PC = castAs<ImplicitCallPoint>(); 102*0b57cec5SDimitry Andric Out << "PreCall\", \"decl\": \"" 103*0b57cec5SDimitry Andric << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() 104*0b57cec5SDimitry Andric << "\", \"location\": "; 105*0b57cec5SDimitry Andric printSourceLocationAsJson(Out, PC.getLocation(), SM); 106*0b57cec5SDimitry Andric break; 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric case ProgramPoint::PostImplicitCallKind: { 110*0b57cec5SDimitry Andric ImplicitCallPoint PC = castAs<ImplicitCallPoint>(); 111*0b57cec5SDimitry Andric Out << "PostCall\", \"decl\": \"" 112*0b57cec5SDimitry Andric << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() 113*0b57cec5SDimitry Andric << "\", \"location\": "; 114*0b57cec5SDimitry Andric printSourceLocationAsJson(Out, PC.getLocation(), SM); 115*0b57cec5SDimitry Andric break; 116*0b57cec5SDimitry Andric } 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric case ProgramPoint::PostInitializerKind: { 119*0b57cec5SDimitry Andric Out << "PostInitializer\", "; 120*0b57cec5SDimitry Andric const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer(); 121*0b57cec5SDimitry Andric if (const FieldDecl *FD = Init->getAnyMember()) { 122*0b57cec5SDimitry Andric Out << "\"field_decl\": \"" << *FD << '\"'; 123*0b57cec5SDimitry Andric } else { 124*0b57cec5SDimitry Andric Out << "\"type\": \""; 125*0b57cec5SDimitry Andric QualType Ty = Init->getTypeSourceInfo()->getType(); 126*0b57cec5SDimitry Andric Ty = Ty.getLocalUnqualifiedType(); 127*0b57cec5SDimitry Andric Ty.print(Out, Context.getLangOpts()); 128*0b57cec5SDimitry Andric Out << '\"'; 129*0b57cec5SDimitry Andric } 130*0b57cec5SDimitry Andric break; 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric case ProgramPoint::BlockEdgeKind: { 134*0b57cec5SDimitry Andric const BlockEdge &E = castAs<BlockEdge>(); 135*0b57cec5SDimitry Andric const Stmt *T = E.getSrc()->getTerminatorStmt(); 136*0b57cec5SDimitry Andric Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID() 137*0b57cec5SDimitry Andric << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": "; 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric if (!T) { 140*0b57cec5SDimitry Andric Out << "null, \"term_kind\": null"; 141*0b57cec5SDimitry Andric break; 142*0b57cec5SDimitry Andric } 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(), 145*0b57cec5SDimitry Andric /*AddQuotes=*/true); 146*0b57cec5SDimitry Andric Out << ", \"location\": "; 147*0b57cec5SDimitry Andric printSourceLocationAsJson(Out, T->getBeginLoc(), SM); 148*0b57cec5SDimitry Andric 149*0b57cec5SDimitry Andric Out << ", \"term_kind\": \""; 150*0b57cec5SDimitry Andric if (isa<SwitchStmt>(T)) { 151*0b57cec5SDimitry Andric Out << "SwitchStmt\", \"case\": "; 152*0b57cec5SDimitry Andric if (const Stmt *Label = E.getDst()->getLabel()) { 153*0b57cec5SDimitry Andric if (const auto *C = dyn_cast<CaseStmt>(Label)) { 154*0b57cec5SDimitry Andric Out << "{ \"lhs\": "; 155*0b57cec5SDimitry Andric if (const Stmt *LHS = C->getLHS()) { 156*0b57cec5SDimitry Andric LHS->printJson(Out, nullptr, PP, AddQuotes); 157*0b57cec5SDimitry Andric } else { 158*0b57cec5SDimitry Andric Out << "null"; 159*0b57cec5SDimitry Andric } 160*0b57cec5SDimitry Andric 161*0b57cec5SDimitry Andric Out << ", \"rhs\": "; 162*0b57cec5SDimitry Andric if (const Stmt *RHS = C->getRHS()) { 163*0b57cec5SDimitry Andric RHS->printJson(Out, nullptr, PP, AddQuotes); 164*0b57cec5SDimitry Andric } else { 165*0b57cec5SDimitry Andric Out << "null"; 166*0b57cec5SDimitry Andric } 167*0b57cec5SDimitry Andric Out << " }"; 168*0b57cec5SDimitry Andric } else { 169*0b57cec5SDimitry Andric assert(isa<DefaultStmt>(Label)); 170*0b57cec5SDimitry Andric Out << "\"default\""; 171*0b57cec5SDimitry Andric } 172*0b57cec5SDimitry Andric } else { 173*0b57cec5SDimitry Andric Out << "\"implicit default\""; 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric } else if (isa<IndirectGotoStmt>(T)) { 176*0b57cec5SDimitry Andric // FIXME: More info. 177*0b57cec5SDimitry Andric Out << "IndirectGotoStmt\""; 178*0b57cec5SDimitry Andric } else { 179*0b57cec5SDimitry Andric Out << "Condition\", \"value\": " 180*0b57cec5SDimitry Andric << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false"); 181*0b57cec5SDimitry Andric } 182*0b57cec5SDimitry Andric break; 183*0b57cec5SDimitry Andric } 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric default: { 186*0b57cec5SDimitry Andric const Stmt *S = castAs<StmtPoint>().getStmt(); 187*0b57cec5SDimitry Andric assert(S != nullptr && "Expecting non-null Stmt"); 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName() 190*0b57cec5SDimitry Andric << "\", \"stmt_id\": " << S->getID(Context) 191*0b57cec5SDimitry Andric << ", \"pointer\": \"" << (const void *)S << "\", \"pretty\": "; 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric S->printJson(Out, nullptr, PP, AddQuotes); 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric Out << ", \"location\": "; 196*0b57cec5SDimitry Andric printSourceLocationAsJson(Out, S->getBeginLoc(), SM); 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric Out << ", \"stmt_point_kind\": \""; 199*0b57cec5SDimitry Andric if (getAs<PreLoad>()) 200*0b57cec5SDimitry Andric Out << "PreLoad"; 201*0b57cec5SDimitry Andric else if (getAs<PreStore>()) 202*0b57cec5SDimitry Andric Out << "PreStore"; 203*0b57cec5SDimitry Andric else if (getAs<PostAllocatorCall>()) 204*0b57cec5SDimitry Andric Out << "PostAllocatorCall"; 205*0b57cec5SDimitry Andric else if (getAs<PostCondition>()) 206*0b57cec5SDimitry Andric Out << "PostCondition"; 207*0b57cec5SDimitry Andric else if (getAs<PostLoad>()) 208*0b57cec5SDimitry Andric Out << "PostLoad"; 209*0b57cec5SDimitry Andric else if (getAs<PostLValue>()) 210*0b57cec5SDimitry Andric Out << "PostLValue"; 211*0b57cec5SDimitry Andric else if (getAs<PostStore>()) 212*0b57cec5SDimitry Andric Out << "PostStore"; 213*0b57cec5SDimitry Andric else if (getAs<PostStmt>()) 214*0b57cec5SDimitry Andric Out << "PostStmt"; 215*0b57cec5SDimitry Andric else if (getAs<PostStmtPurgeDeadSymbols>()) 216*0b57cec5SDimitry Andric Out << "PostStmtPurgeDeadSymbols"; 217*0b57cec5SDimitry Andric else if (getAs<PreStmtPurgeDeadSymbols>()) 218*0b57cec5SDimitry Andric Out << "PreStmtPurgeDeadSymbols"; 219*0b57cec5SDimitry Andric else if (getAs<PreStmt>()) 220*0b57cec5SDimitry Andric Out << "PreStmt"; 221*0b57cec5SDimitry Andric else { 222*0b57cec5SDimitry Andric Out << "\nKind: '" << getKind(); 223*0b57cec5SDimitry Andric llvm_unreachable("' is unhandled StmtPoint kind!"); 224*0b57cec5SDimitry Andric } 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric Out << '\"'; 227*0b57cec5SDimitry Andric break; 228*0b57cec5SDimitry Andric } 229*0b57cec5SDimitry Andric } 230*0b57cec5SDimitry Andric } 231*0b57cec5SDimitry Andric 232*0b57cec5SDimitry Andric SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider, 233*0b57cec5SDimitry Andric StringRef Msg) 234*0b57cec5SDimitry Andric : Desc((MsgProvider + " : " + Msg).str()) {} 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric StringRef SimpleProgramPointTag::getTagDescription() const { 237*0b57cec5SDimitry Andric return Desc; 238*0b57cec5SDimitry Andric } 239