1 //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines the PathDiagnostic-related interfaces.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
15 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
16 #include "clang/AST/Expr.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclObjC.h"
19 #include "clang/AST/ParentMap.h"
20 #include "clang/AST/StmtCXX.h"
21 #include "llvm/ADT/SmallString.h"
23 using namespace clang;
26 bool PathDiagnosticMacroPiece::containsEvent() const {
27 for (const_iterator I = begin(), E = end(); I!=E; ++I) {
28 if (isa<PathDiagnosticEventPiece>(*I))
31 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
32 if (MP->containsEvent())
39 static StringRef StripTrailingDots(StringRef s) {
40 for (StringRef::size_type i = s.size(); i != 0; --i)
42 return s.substr(0, i);
46 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
47 Kind k, DisplayHint hint)
48 : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
50 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
51 : kind(k), Hint(hint) {}
53 PathDiagnosticPiece::~PathDiagnosticPiece() {}
54 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
55 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
57 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
58 for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
61 PathDiagnostic::PathDiagnostic() : Size(0) {}
63 PathDiagnostic::~PathDiagnostic() {
64 for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
67 void PathDiagnostic::resetPath(bool deletePieces) {
71 for (iterator I=begin(), E=end(); I!=E; ++I)
78 PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc,
81 BugType(StripTrailingDots(bugtype)),
82 Desc(StripTrailingDots(desc)),
83 Category(StripTrailingDots(category)) {}
85 void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) {
86 // For now this simply forwards to HandlePathDiagnosticImpl. In the future
87 // we can use this indirection to control for multi-threaded access to
88 // the PathDiagnosticConsumer from multiple bug reporters.
89 HandlePathDiagnosticImpl(D);
92 //===----------------------------------------------------------------------===//
93 // PathDiagnosticLocation methods.
94 //===----------------------------------------------------------------------===//
96 static SourceLocation getValidSourceLocation(const Stmt* S,
97 LocationOrAnalysisContext LAC) {
98 SourceLocation L = S->getLocStart();
99 assert(!LAC.isNull() && "A valid LocationContext or AnalysisContext should "
100 "be passed to PathDiagnosticLocation upon creation.");
102 // S might be a temporary statement that does not have a location in the
103 // source code, so find an enclosing statement and use it's location.
107 if (LAC.is<const LocationContext*>())
108 PM = &LAC.get<const LocationContext*>()->getParentMap();
110 PM = &LAC.get<AnalysisContext*>()->getParentMap();
112 while (!L.isValid()) {
113 S = PM->getParent(S);
114 L = S->getLocStart();
121 PathDiagnosticLocation
122 PathDiagnosticLocation::createBegin(const Decl *D,
123 const SourceManager &SM) {
124 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
127 PathDiagnosticLocation
128 PathDiagnosticLocation::createBegin(const Stmt *S,
129 const SourceManager &SM,
130 LocationOrAnalysisContext LAC) {
131 return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
135 PathDiagnosticLocation
136 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
137 const SourceManager &SM) {
138 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
141 PathDiagnosticLocation
142 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
143 const SourceManager &SM) {
144 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
147 PathDiagnosticLocation
148 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
149 const SourceManager &SM) {
150 SourceLocation L = CS->getLBracLoc();
151 return PathDiagnosticLocation(L, SM, SingleLocK);
154 PathDiagnosticLocation
155 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
156 const SourceManager &SM) {
157 SourceLocation L = CS->getRBracLoc();
158 return PathDiagnosticLocation(L, SM, SingleLocK);
161 PathDiagnosticLocation
162 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
163 const SourceManager &SM) {
164 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
165 if (const CompoundStmt *CS =
166 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
167 if (!CS->body_empty()) {
168 SourceLocation Loc = (*CS->body_begin())->getLocStart();
169 return PathDiagnosticLocation(Loc, SM, SingleLocK);
172 return PathDiagnosticLocation();
175 PathDiagnosticLocation
176 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
177 const SourceManager &SM) {
178 SourceLocation L = LC->getDecl()->getBodyRBrace();
179 return PathDiagnosticLocation(L, SM, SingleLocK);
182 PathDiagnosticLocation
183 PathDiagnosticLocation::create(const ProgramPoint& P,
184 const SourceManager &SMng) {
187 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
188 const CFGBlock *BSrc = BE->getSrc();
189 S = BSrc->getTerminatorCondition();
191 else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
195 return PathDiagnosticLocation(S, SMng, P.getLocationContext());
198 return PathDiagnosticLocation();
201 PathDiagnosticLocation
202 PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
203 const SourceManager &SM) {
204 assert(N && "Cannot create a location with a null node.");
206 const ExplodedNode *NI = N;
209 ProgramPoint P = NI->getLocation();
210 const LocationContext *LC = P.getLocationContext();
211 if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
212 return PathDiagnosticLocation(PS->getStmt(), SM, LC);
213 else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
214 const Stmt *Term = BE->getSrc()->getTerminator();
216 return PathDiagnosticLocation(Term, SM, LC);
218 NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
221 return createDeclEnd(N->getLocationContext(), SM);
224 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
225 const PathDiagnosticLocation &PDL) {
226 FullSourceLoc L = PDL.asLocation();
227 return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
231 PathDiagnosticLocation::genLocation(SourceLocation L,
232 LocationOrAnalysisContext LAC) const {
234 // Note that we want a 'switch' here so that the compiler can warn us in
235 // case we add more cases.
241 return FullSourceLoc(getValidSourceLocation(S, LAC),
242 const_cast<SourceManager&>(*SM));
244 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
247 return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
251 PathDiagnosticLocation::genRange(LocationOrAnalysisContext LAC) const {
253 // Note that we want a 'switch' here so that the compiler can warn us in
254 // case we add more cases.
257 return PathDiagnosticRange(SourceRange(Loc,Loc), true);
261 const Stmt *S = asStmt();
262 switch (S->getStmtClass()) {
265 case Stmt::DeclStmtClass: {
266 const DeclStmt *DS = cast<DeclStmt>(S);
267 if (DS->isSingleDecl()) {
268 // Should always be the case, but we'll be defensive.
269 return SourceRange(DS->getLocStart(),
270 DS->getSingleDecl()->getLocation());
274 // FIXME: Provide better range information for different
276 case Stmt::IfStmtClass:
277 case Stmt::WhileStmtClass:
278 case Stmt::DoStmtClass:
279 case Stmt::ForStmtClass:
280 case Stmt::ChooseExprClass:
281 case Stmt::IndirectGotoStmtClass:
282 case Stmt::SwitchStmtClass:
283 case Stmt::BinaryConditionalOperatorClass:
284 case Stmt::ConditionalOperatorClass:
285 case Stmt::ObjCForCollectionStmtClass: {
286 SourceLocation L = getValidSourceLocation(S, LAC);
287 return SourceRange(L, L);
290 SourceRange R = S->getSourceRange();
296 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
297 return MD->getSourceRange();
298 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
299 if (Stmt *Body = FD->getBody())
300 return Body->getSourceRange();
303 SourceLocation L = D->getLocation();
304 return PathDiagnosticRange(SourceRange(L, L), true);
308 return SourceRange(Loc,Loc);
311 void PathDiagnosticLocation::flatten() {
317 else if (K == DeclK) {
324 //===----------------------------------------------------------------------===//
325 // FoldingSet profiling methods.
326 //===----------------------------------------------------------------------===//
328 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
329 ID.AddInteger(Range.getBegin().getRawEncoding());
330 ID.AddInteger(Range.getEnd().getRawEncoding());
331 ID.AddInteger(Loc.getRawEncoding());
335 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
336 ID.AddInteger((unsigned) getKind());
338 // FIXME: Add profiling support for code hints.
339 ID.AddInteger((unsigned) getDisplayHint());
340 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
341 ID.AddInteger(I->getBegin().getRawEncoding());
342 ID.AddInteger(I->getEnd().getRawEncoding());
346 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
347 PathDiagnosticPiece::Profile(ID);
351 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
352 PathDiagnosticPiece::Profile(ID);
353 for (const_iterator I = begin(), E = end(); I != E; ++I)
357 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
358 PathDiagnosticSpotPiece::Profile(ID);
359 for (const_iterator I = begin(), E = end(); I != E; ++I)
363 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
365 ID.AddString(BugType);
367 ID.AddString(Category);
368 for (const_iterator I = begin(), E = end(); I != E; ++I)
371 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)