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