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