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 void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const { 53 const ASTContext &Context = 54 getLocationContext()->getAnalysisDeclContext()->getASTContext(); 55 const SourceManager &SM = Context.getSourceManager(); 56 const PrintingPolicy &PP = Context.getPrintingPolicy(); 57 const bool AddQuotes = true; 58 59 Out << "\"kind\": \""; 60 switch (getKind()) { 61 case ProgramPoint::BlockEntranceKind: 62 Out << "BlockEntrance\"" 63 << ", \"block_id\": " 64 << castAs<BlockEntrance>().getBlock()->getBlockID(); 65 break; 66 67 case ProgramPoint::FunctionExitKind: { 68 auto FEP = getAs<FunctionExitPoint>(); 69 Out << "FunctionExit\"" 70 << ", \"block_id\": " << FEP->getBlock()->getBlockID() 71 << ", \"stmt_id\": "; 72 73 if (const ReturnStmt *RS = FEP->getStmt()) { 74 Out << RS->getID(Context) << ", \"stmt\": "; 75 RS->printJson(Out, nullptr, PP, AddQuotes); 76 } else { 77 Out << "null, \"stmt\": null"; 78 } 79 break; 80 } 81 case ProgramPoint::BlockExitKind: 82 llvm_unreachable("BlockExitKind"); 83 break; 84 case ProgramPoint::CallEnterKind: 85 Out << "CallEnter\", \"callee_decl\": \""; 86 Out << AnalysisDeclContext::getFunctionName( 87 castAs<CallEnter>().getCalleeContext()->getDecl()) 88 << '\"'; 89 break; 90 case ProgramPoint::CallExitBeginKind: 91 Out << "CallExitBegin\""; 92 break; 93 case ProgramPoint::CallExitEndKind: 94 Out << "CallExitEnd\""; 95 break; 96 case ProgramPoint::EpsilonKind: 97 Out << "EpsilonPoint\""; 98 break; 99 100 case ProgramPoint::LoopExitKind: 101 Out << "LoopExit\", \"stmt\": \"" 102 << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"'; 103 break; 104 105 case ProgramPoint::PreImplicitCallKind: { 106 ImplicitCallPoint PC = castAs<ImplicitCallPoint>(); 107 Out << "PreCall\", \"decl\": \"" 108 << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() 109 << "\", \"location\": "; 110 printSourceLocationAsJson(Out, PC.getLocation(), SM); 111 break; 112 } 113 114 case ProgramPoint::PostImplicitCallKind: { 115 ImplicitCallPoint PC = castAs<ImplicitCallPoint>(); 116 Out << "PostCall\", \"decl\": \"" 117 << PC.getDecl()->getAsFunction()->getQualifiedNameAsString() 118 << "\", \"location\": "; 119 printSourceLocationAsJson(Out, PC.getLocation(), SM); 120 break; 121 } 122 123 case ProgramPoint::PostInitializerKind: { 124 Out << "PostInitializer\", "; 125 const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer(); 126 if (const FieldDecl *FD = Init->getAnyMember()) { 127 Out << "\"field_decl\": \"" << *FD << '\"'; 128 } else { 129 Out << "\"type\": \""; 130 QualType Ty = Init->getTypeSourceInfo()->getType(); 131 Ty = Ty.getLocalUnqualifiedType(); 132 Ty.print(Out, Context.getLangOpts()); 133 Out << '\"'; 134 } 135 break; 136 } 137 138 case ProgramPoint::BlockEdgeKind: { 139 const BlockEdge &E = castAs<BlockEdge>(); 140 const Stmt *T = E.getSrc()->getTerminatorStmt(); 141 Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID() 142 << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": "; 143 144 if (!T) { 145 Out << "null, \"term_kind\": null"; 146 break; 147 } 148 149 E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(), 150 /*AddQuotes=*/true); 151 Out << ", \"location\": "; 152 printSourceLocationAsJson(Out, T->getBeginLoc(), SM); 153 154 Out << ", \"term_kind\": \""; 155 if (isa<SwitchStmt>(T)) { 156 Out << "SwitchStmt\", \"case\": "; 157 if (const Stmt *Label = E.getDst()->getLabel()) { 158 if (const auto *C = dyn_cast<CaseStmt>(Label)) { 159 Out << "{ \"lhs\": "; 160 if (const Stmt *LHS = C->getLHS()) { 161 LHS->printJson(Out, nullptr, PP, AddQuotes); 162 } else { 163 Out << "null"; 164 } 165 166 Out << ", \"rhs\": "; 167 if (const Stmt *RHS = C->getRHS()) { 168 RHS->printJson(Out, nullptr, PP, AddQuotes); 169 } else { 170 Out << "null"; 171 } 172 Out << " }"; 173 } else { 174 assert(isa<DefaultStmt>(Label)); 175 Out << "\"default\""; 176 } 177 } else { 178 Out << "\"implicit default\""; 179 } 180 } else if (isa<IndirectGotoStmt>(T)) { 181 // FIXME: More info. 182 Out << "IndirectGotoStmt\""; 183 } else { 184 Out << "Condition\", \"value\": " 185 << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false"); 186 } 187 break; 188 } 189 190 default: { 191 const Stmt *S = castAs<StmtPoint>().getStmt(); 192 assert(S != nullptr && "Expecting non-null Stmt"); 193 194 Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName() 195 << "\", \"stmt_id\": " << S->getID(Context) 196 << ", \"pointer\": \"" << (const void *)S << "\", "; 197 if (const auto *CS = dyn_cast<CastExpr>(S)) 198 Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", "; 199 200 Out << "\"pretty\": "; 201 202 S->printJson(Out, nullptr, PP, AddQuotes); 203 204 Out << ", \"location\": "; 205 printSourceLocationAsJson(Out, S->getBeginLoc(), SM); 206 207 Out << ", \"stmt_point_kind\": \""; 208 if (getAs<PreLoad>()) 209 Out << "PreLoad"; 210 else if (getAs<PreStore>()) 211 Out << "PreStore"; 212 else if (getAs<PostAllocatorCall>()) 213 Out << "PostAllocatorCall"; 214 else if (getAs<PostCondition>()) 215 Out << "PostCondition"; 216 else if (getAs<PostLoad>()) 217 Out << "PostLoad"; 218 else if (getAs<PostLValue>()) 219 Out << "PostLValue"; 220 else if (getAs<PostStore>()) 221 Out << "PostStore"; 222 else if (getAs<PostStmt>()) 223 Out << "PostStmt"; 224 else if (getAs<PostStmtPurgeDeadSymbols>()) 225 Out << "PostStmtPurgeDeadSymbols"; 226 else if (getAs<PreStmtPurgeDeadSymbols>()) 227 Out << "PreStmtPurgeDeadSymbols"; 228 else if (getAs<PreStmt>()) 229 Out << "PreStmt"; 230 else { 231 Out << "\nKind: '" << getKind(); 232 llvm_unreachable("' is unhandled StmtPoint kind!"); 233 } 234 235 Out << '\"'; 236 break; 237 } 238 } 239 } 240 241 SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider, 242 StringRef Msg) 243 : Desc((MsgProvider + " : " + Msg).str()) {} 244 245 StringRef SimpleProgramPointTag::getTagDescription() const { 246 return Desc; 247 } 248