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/AST/ASTContext.h" 16 #include "clang/Analysis/AnalysisDeclContext.h" 17 #include "clang/Basic/JsonSupport.h" 18 19 using namespace clang; 20 21 ProgramPointTag::~ProgramPointTag() {} 22 23 ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K, 24 const LocationContext *LC, 25 const ProgramPointTag *tag){ 26 switch (K) { 27 default: 28 llvm_unreachable("Unhandled ProgramPoint kind"); 29 case ProgramPoint::PreStmtKind: 30 return PreStmt(S, LC, tag); 31 case ProgramPoint::PostStmtKind: 32 return PostStmt(S, LC, tag); 33 case ProgramPoint::PreLoadKind: 34 return PreLoad(S, LC, tag); 35 case ProgramPoint::PostLoadKind: 36 return PostLoad(S, LC, tag); 37 case ProgramPoint::PreStoreKind: 38 return PreStore(S, LC, tag); 39 case ProgramPoint::PostLValueKind: 40 return PostLValue(S, LC, tag); 41 case ProgramPoint::PostStmtPurgeDeadSymbolsKind: 42 return PostStmtPurgeDeadSymbols(S, LC, tag); 43 case ProgramPoint::PreStmtPurgeDeadSymbolsKind: 44 return PreStmtPurgeDeadSymbols(S, LC, tag); 45 } 46 } 47 48 LLVM_DUMP_METHOD void ProgramPoint::dump() const { 49 return printJson(llvm::errs()); 50 } 51 52 StringRef ProgramPoint::getProgramPointKindName(Kind K) { 53 switch (K) { 54 case BlockEdgeKind: 55 return "BlockEdge"; 56 case BlockEntranceKind: 57 return "BlockEntrance"; 58 case BlockExitKind: 59 return "BlockExit"; 60 case PreStmtKind: 61 return "PreStmt"; 62 case PreStmtPurgeDeadSymbolsKind: 63 return "PreStmtPurgeDeadSymbols"; 64 case PostStmtPurgeDeadSymbolsKind: 65 return "PostStmtPurgeDeadSymbols"; 66 case PostStmtKind: 67 return "PostStmt"; 68 case PreLoadKind: 69 return "PreLoad"; 70 case PostLoadKind: 71 return "PostLoad"; 72 case PreStoreKind: 73 return "PreStore"; 74 case PostStoreKind: 75 return "PostStore"; 76 case PostConditionKind: 77 return "PostCondition"; 78 case PostLValueKind: 79 return "PostLValue"; 80 case PostAllocatorCallKind: 81 return "PostAllocatorCall"; 82 case PostInitializerKind: 83 return "PostInitializer"; 84 case CallEnterKind: 85 return "CallEnter"; 86 case CallExitBeginKind: 87 return "CallExitBegin"; 88 case CallExitEndKind: 89 return "CallExitEnd"; 90 case FunctionExitKind: 91 return "FunctionExit"; 92 case PreImplicitCallKind: 93 return "PreImplicitCall"; 94 case PostImplicitCallKind: 95 return "PostImplicitCall"; 96 case LoopExitKind: 97 return "LoopExit"; 98 case EpsilonKind: 99 return "Epsilon"; 100 } 101 llvm_unreachable("Unknown ProgramPoint kind"); 102 } 103 104 std::optional<SourceLocation> ProgramPoint::getSourceLocation() const { 105 switch (getKind()) { 106 case BlockEdgeKind: 107 // If needed, the source and or destination beginning can be used to get 108 // source location. 109 return std::nullopt; 110 case BlockEntranceKind: 111 // If needed, first statement of the block can be used. 112 return std::nullopt; 113 case BlockExitKind: 114 if (const auto *B = castAs<BlockExit>().getBlock()) { 115 if (const auto *T = B->getTerminatorStmt()) { 116 return T->getBeginLoc(); 117 } 118 } 119 return std::nullopt; 120 case PreStmtKind: 121 case PreStmtPurgeDeadSymbolsKind: 122 case PostStmtPurgeDeadSymbolsKind: 123 case PostStmtKind: 124 case PreLoadKind: 125 case PostLoadKind: 126 case PreStoreKind: 127 case PostStoreKind: 128 case PostConditionKind: 129 case PostLValueKind: 130 case PostAllocatorCallKind: 131 if (const Stmt *S = castAs<StmtPoint>().getStmt()) 132 return S->getBeginLoc(); 133 return std::nullopt; 134 case PostInitializerKind: 135 if (const auto *Init = castAs<PostInitializer>().getInitializer()) 136 return Init->getSourceLocation(); 137 return std::nullopt; 138 case CallEnterKind: 139 if (const Stmt *S = castAs<CallEnter>().getCallExpr()) 140 return S->getBeginLoc(); 141 return std::nullopt; 142 case CallExitBeginKind: 143 if (const Stmt *S = castAs<CallExitBegin>().getReturnStmt()) 144 return S->getBeginLoc(); 145 return std::nullopt; 146 case CallExitEndKind: 147 return std::nullopt; 148 case FunctionExitKind: 149 if (const auto *B = castAs<FunctionExitPoint>().getBlock(); 150 B && B->getTerminatorStmt()) 151 return B->getTerminatorStmt()->getBeginLoc(); 152 return std::nullopt; 153 case PreImplicitCallKind: 154 return castAs<ImplicitCallPoint>().getLocation(); 155 case PostImplicitCallKind: 156 return castAs<ImplicitCallPoint>().getLocation(); 157 case LoopExitKind: 158 if (const Stmt *S = castAs<LoopExit>().getLoopStmt()) 159 return S->getBeginLoc(); 160 return std::nullopt; 161 case EpsilonKind: 162 return std::nullopt; 163 } 164 llvm_unreachable("Unknown ProgramPoint kind"); 165 } 166 167 void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const { 168 const ASTContext &Context = 169 getLocationContext()->getAnalysisDeclContext()->getASTContext(); 170 const SourceManager &SM = Context.getSourceManager(); 171 const PrintingPolicy &PP = Context.getPrintingPolicy(); 172 const bool AddQuotes = true; 173 174 Out << "\"kind\": \""; 175 switch (getKind()) { 176 case ProgramPoint::BlockEntranceKind: 177 Out << "BlockEntrance\"" 178 << ", \"block_id\": " 179 << castAs<BlockEntrance>().getBlock()->getBlockID(); 180 break; 181 182 case ProgramPoint::FunctionExitKind: { 183 auto FEP = getAs<FunctionExitPoint>(); 184 Out << "FunctionExit\"" 185 << ", \"block_id\": " << FEP->getBlock()->getBlockID() 186 << ", \"stmt_id\": "; 187 188 if (const ReturnStmt *RS = FEP->getStmt()) { 189 Out << RS->getID(Context) << ", \"stmt\": "; 190 RS->printJson(Out, nullptr, PP, AddQuotes); 191 } else { 192 Out << "null, \"stmt\": null"; 193 } 194 break; 195 } 196 case ProgramPoint::BlockExitKind: 197 llvm_unreachable("BlockExitKind"); 198 break; 199 case ProgramPoint::CallEnterKind: 200 Out << "CallEnter\", \"callee_decl\": \""; 201 Out << AnalysisDeclContext::getFunctionName( 202 castAs<CallEnter>().getCalleeContext()->getDecl()) 203 << '\"'; 204 break; 205 case ProgramPoint::CallExitBeginKind: 206 Out << "CallExitBegin\""; 207 break; 208 case ProgramPoint::CallExitEndKind: 209 Out << "CallExitEnd\""; 210 break; 211 case ProgramPoint::EpsilonKind: 212 Out << "EpsilonPoint\""; 213 break; 214 215 case ProgramPoint::LoopExitKind: 216 Out << "LoopExit\", \"stmt\": \"" 217 << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"'; 218 break; 219 220 case ProgramPoint::PreImplicitCallKind: { 221 ImplicitCallPoint PC = castAs<ImplicitCallPoint>(); 222 Out << "PreCall\", \"decl\": \"" 223 << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() 224 << "\", \"location\": "; 225 printSourceLocationAsJson(Out, PC.getLocation(), SM); 226 break; 227 } 228 229 case ProgramPoint::PostImplicitCallKind: { 230 ImplicitCallPoint PC = castAs<ImplicitCallPoint>(); 231 Out << "PostCall\", \"decl\": \"" 232 << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() 233 << "\", \"location\": "; 234 printSourceLocationAsJson(Out, PC.getLocation(), SM); 235 break; 236 } 237 238 case ProgramPoint::PostInitializerKind: { 239 Out << "PostInitializer\", "; 240 const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer(); 241 if (const FieldDecl *FD = Init->getAnyMember()) { 242 Out << "\"field_decl\": \"" << *FD << '\"'; 243 } else { 244 Out << "\"type\": \""; 245 QualType Ty = Init->getTypeSourceInfo()->getType(); 246 Ty = Ty.getLocalUnqualifiedType(); 247 Ty.print(Out, Context.getLangOpts()); 248 Out << '\"'; 249 } 250 break; 251 } 252 253 case ProgramPoint::BlockEdgeKind: { 254 const BlockEdge &E = castAs<BlockEdge>(); 255 const Stmt *T = E.getSrc()->getTerminatorStmt(); 256 Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID() 257 << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": "; 258 259 if (!T) { 260 Out << "null, \"term_kind\": null"; 261 break; 262 } 263 264 E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(), 265 /*AddQuotes=*/true); 266 Out << ", \"location\": "; 267 printSourceLocationAsJson(Out, T->getBeginLoc(), SM); 268 269 Out << ", \"term_kind\": \""; 270 if (isa<SwitchStmt>(T)) { 271 Out << "SwitchStmt\", \"case\": "; 272 if (const Stmt *Label = E.getDst()->getLabel()) { 273 if (const auto *C = dyn_cast<CaseStmt>(Label)) { 274 Out << "{ \"lhs\": "; 275 if (const Stmt *LHS = C->getLHS()) { 276 LHS->printJson(Out, nullptr, PP, AddQuotes); 277 } else { 278 Out << "null"; 279 } 280 281 Out << ", \"rhs\": "; 282 if (const Stmt *RHS = C->getRHS()) { 283 RHS->printJson(Out, nullptr, PP, AddQuotes); 284 } else { 285 Out << "null"; 286 } 287 Out << " }"; 288 } else { 289 assert(isa<DefaultStmt>(Label)); 290 Out << "\"default\""; 291 } 292 } else { 293 Out << "\"implicit default\""; 294 } 295 } else if (isa<IndirectGotoStmt>(T)) { 296 // FIXME: More info. 297 Out << "IndirectGotoStmt\""; 298 } else { 299 Out << "Condition\", \"value\": " 300 << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false"); 301 } 302 break; 303 } 304 305 default: { 306 const Stmt *S = castAs<StmtPoint>().getStmt(); 307 assert(S != nullptr && "Expecting non-null Stmt"); 308 309 Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName() 310 << "\", \"stmt_id\": " << S->getID(Context) 311 << ", \"pointer\": \"" << (const void *)S << "\", "; 312 if (const auto *CS = dyn_cast<CastExpr>(S)) 313 Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", "; 314 315 Out << "\"pretty\": "; 316 317 S->printJson(Out, nullptr, PP, AddQuotes); 318 319 Out << ", \"location\": "; 320 printSourceLocationAsJson(Out, S->getBeginLoc(), SM); 321 322 Out << ", \"stmt_point_kind\": \""; 323 if (getAs<PreLoad>()) 324 Out << "PreLoad"; 325 else if (getAs<PreStore>()) 326 Out << "PreStore"; 327 else if (getAs<PostAllocatorCall>()) 328 Out << "PostAllocatorCall"; 329 else if (getAs<PostCondition>()) 330 Out << "PostCondition"; 331 else if (getAs<PostLoad>()) 332 Out << "PostLoad"; 333 else if (getAs<PostLValue>()) 334 Out << "PostLValue"; 335 else if (getAs<PostStore>()) 336 Out << "PostStore"; 337 else if (getAs<PostStmt>()) 338 Out << "PostStmt"; 339 else if (getAs<PostStmtPurgeDeadSymbols>()) 340 Out << "PostStmtPurgeDeadSymbols"; 341 else if (getAs<PreStmtPurgeDeadSymbols>()) 342 Out << "PreStmtPurgeDeadSymbols"; 343 else if (getAs<PreStmt>()) 344 Out << "PreStmt"; 345 else { 346 Out << "\nKind: '" << getKind(); 347 llvm_unreachable("' is unhandled StmtPoint kind!"); 348 } 349 350 Out << '\"'; 351 break; 352 } 353 } 354 } 355 356 SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider, 357 StringRef Msg) 358 : Desc((MsgProvider + " : " + Msg).str()) {} 359 360 StringRef SimpleProgramPointTag::getDebugTag() const { return Desc; } 361