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