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