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