361 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the interface ProgramPoint, which identifies a10// 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 19using namespace clang;20 21ProgramPointTag::~ProgramPointTag() {}22 23ProgramPoint 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 48LLVM_DUMP_METHOD void ProgramPoint::dump() const {49 return printJson(llvm::errs());50}51 52StringRef 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 104std::optional<SourceLocation> ProgramPoint::getSourceLocation() const {105 switch (getKind()) {106 case BlockEdgeKind:107 // If needed, the source and or destination beginning can be used to get108 // 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 167void 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 356SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider,357 StringRef Msg)358 : Desc((MsgProvider + " : " + Msg).str()) {}359 360StringRef SimpleProgramPointTag::getDebugTag() const { return Desc; }361