1 //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the PathDiagnostic-related interfaces.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
15 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/AST/Expr.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/ParentMap.h"
21 #include "clang/AST/StmtCXX.h"
22 #include "llvm/ADT/SmallString.h"
23
24 using namespace clang;
25 using namespace ento;
26
containsEvent() const27 bool PathDiagnosticMacroPiece::containsEvent() const {
28 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
29 I!=E; ++I) {
30 if (isa<PathDiagnosticEventPiece>(*I))
31 return true;
32 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
33 if (MP->containsEvent())
34 return true;
35 }
36 return false;
37 }
38
StripTrailingDots(StringRef s)39 static StringRef StripTrailingDots(StringRef s) {
40 for (StringRef::size_type i = s.size(); i != 0; --i)
41 if (s[i - 1] != '.')
42 return s.substr(0, i);
43 return "";
44 }
45
PathDiagnosticPiece(StringRef s,Kind k,DisplayHint hint)46 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
47 Kind k, DisplayHint hint)
48 : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
49
PathDiagnosticPiece(Kind k,DisplayHint hint)50 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
51 : kind(k), Hint(hint) {}
52
~PathDiagnosticPiece()53 PathDiagnosticPiece::~PathDiagnosticPiece() {}
~PathDiagnosticEventPiece()54 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
~PathDiagnosticCallPiece()55 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
~PathDiagnosticControlFlowPiece()56 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
~PathDiagnosticMacroPiece()57 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
58
59
~PathPieces()60 PathPieces::~PathPieces() {}
~PathDiagnostic()61 PathDiagnostic::~PathDiagnostic() {}
62
PathDiagnostic(const Decl * declWithIssue,StringRef bugtype,StringRef desc,StringRef category)63 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
64 StringRef bugtype, StringRef desc,
65 StringRef category)
66 : DeclWithIssue(declWithIssue),
67 BugType(StripTrailingDots(bugtype)),
68 Desc(StripTrailingDots(desc)),
69 Category(StripTrailingDots(category)),
70 path(pathImpl) {}
71
anchor()72 void PathDiagnosticConsumer::anchor() { }
73
~PathDiagnosticConsumer()74 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
75 // Delete the contents of the FoldingSet if it isn't empty already.
76 for (llvm::FoldingSet<PathDiagnostic>::iterator it =
77 Diags.begin(), et = Diags.end() ; it != et ; ++it) {
78 delete &*it;
79 }
80 }
81
HandlePathDiagnostic(PathDiagnostic * D)82 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
83 llvm::OwningPtr<PathDiagnostic> OwningD(D);
84
85 if (!D || D->path.empty())
86 return;
87
88 // We need to flatten the locations (convert Stmt* to locations) because
89 // the referenced statements may be freed by the time the diagnostics
90 // are emitted.
91 D->flattenLocations();
92
93 // If the PathDiagnosticConsumer does not support diagnostics that
94 // cross file boundaries, prune out such diagnostics now.
95 if (!supportsCrossFileDiagnostics()) {
96 // Verify that the entire path is from the same FileID.
97 FileID FID;
98 const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
99 llvm::SmallVector<const PathPieces *, 5> WorkList;
100 WorkList.push_back(&D->path);
101
102 while (!WorkList.empty()) {
103 const PathPieces &path = *WorkList.back();
104 WorkList.pop_back();
105
106 for (PathPieces::const_iterator I = path.begin(), E = path.end();
107 I != E; ++I) {
108 const PathDiagnosticPiece *piece = I->getPtr();
109 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
110
111 if (FID.isInvalid()) {
112 FID = SMgr.getFileID(L);
113 } else if (SMgr.getFileID(L) != FID)
114 return; // FIXME: Emit a warning?
115
116 // Check the source ranges.
117 for (PathDiagnosticPiece::range_iterator RI = piece->ranges_begin(),
118 RE = piece->ranges_end();
119 RI != RE; ++RI) {
120 SourceLocation L = SMgr.getExpansionLoc(RI->getBegin());
121 if (!L.isFileID() || SMgr.getFileID(L) != FID)
122 return; // FIXME: Emit a warning?
123 L = SMgr.getExpansionLoc(RI->getEnd());
124 if (!L.isFileID() || SMgr.getFileID(L) != FID)
125 return; // FIXME: Emit a warning?
126 }
127
128 if (const PathDiagnosticCallPiece *call =
129 dyn_cast<PathDiagnosticCallPiece>(piece)) {
130 WorkList.push_back(&call->path);
131 }
132 else if (const PathDiagnosticMacroPiece *macro =
133 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
134 WorkList.push_back(¯o->subPieces);
135 }
136 }
137 }
138
139 if (FID.isInvalid())
140 return; // FIXME: Emit a warning?
141 }
142
143 // Profile the node to see if we already have something matching it
144 llvm::FoldingSetNodeID profile;
145 D->Profile(profile);
146 void *InsertPos = 0;
147
148 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
149 // Keep the PathDiagnostic with the shorter path.
150 const unsigned orig_size = orig->full_size();
151 const unsigned new_size = D->full_size();
152
153 if (orig_size <= new_size) {
154 bool shouldKeepOriginal = true;
155 if (orig_size == new_size) {
156 // Here we break ties in a fairly arbitrary, but deterministic, way.
157 llvm::FoldingSetNodeID fullProfile, fullProfileOrig;
158 D->FullProfile(fullProfile);
159 orig->FullProfile(fullProfileOrig);
160 if (fullProfile.ComputeHash() < fullProfileOrig.ComputeHash())
161 shouldKeepOriginal = false;
162 }
163
164 if (shouldKeepOriginal)
165 return;
166 }
167 Diags.RemoveNode(orig);
168 delete orig;
169 }
170
171 Diags.InsertNode(OwningD.take());
172 }
173
174
175 namespace {
176 struct CompareDiagnostics {
177 // Compare if 'X' is "<" than 'Y'.
operator ()__anone89849870111::CompareDiagnostics178 bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
179 // First compare by location
180 const FullSourceLoc &XLoc = X->getLocation().asLocation();
181 const FullSourceLoc &YLoc = Y->getLocation().asLocation();
182 if (XLoc < YLoc)
183 return true;
184 if (XLoc != YLoc)
185 return false;
186
187 // Next, compare by bug type.
188 StringRef XBugType = X->getBugType();
189 StringRef YBugType = Y->getBugType();
190 if (XBugType < YBugType)
191 return true;
192 if (XBugType != YBugType)
193 return false;
194
195 // Next, compare by bug description.
196 StringRef XDesc = X->getDescription();
197 StringRef YDesc = Y->getDescription();
198 if (XDesc < YDesc)
199 return true;
200 if (XDesc != YDesc)
201 return false;
202
203 // FIXME: Further refine by comparing PathDiagnosticPieces?
204 return false;
205 }
206 };
207 }
208
209 void
FlushDiagnostics(SmallVectorImpl<std::string> * Files)210 PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) {
211 if (flushed)
212 return;
213
214 flushed = true;
215
216 std::vector<const PathDiagnostic *> BatchDiags;
217 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
218 et = Diags.end(); it != et; ++it) {
219 BatchDiags.push_back(&*it);
220 }
221
222 // Clear out the FoldingSet.
223 Diags.clear();
224
225 // Sort the diagnostics so that they are always emitted in a deterministic
226 // order.
227 if (!BatchDiags.empty())
228 std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
229
230 FlushDiagnosticsImpl(BatchDiags, Files);
231
232 // Delete the flushed diagnostics.
233 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
234 et = BatchDiags.end(); it != et; ++it) {
235 const PathDiagnostic *D = *it;
236 delete D;
237 }
238 }
239
240 //===----------------------------------------------------------------------===//
241 // PathDiagnosticLocation methods.
242 //===----------------------------------------------------------------------===//
243
getValidSourceLocation(const Stmt * S,LocationOrAnalysisDeclContext LAC)244 static SourceLocation getValidSourceLocation(const Stmt* S,
245 LocationOrAnalysisDeclContext LAC) {
246 SourceLocation L = S->getLocStart();
247 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
248 "be passed to PathDiagnosticLocation upon creation.");
249
250 // S might be a temporary statement that does not have a location in the
251 // source code, so find an enclosing statement and use it's location.
252 if (!L.isValid()) {
253
254 ParentMap *PM = 0;
255 if (LAC.is<const LocationContext*>())
256 PM = &LAC.get<const LocationContext*>()->getParentMap();
257 else
258 PM = &LAC.get<AnalysisDeclContext*>()->getParentMap();
259
260 while (!L.isValid()) {
261 S = PM->getParent(S);
262 L = S->getLocStart();
263 }
264 }
265
266 return L;
267 }
268
269 PathDiagnosticLocation
createBegin(const Decl * D,const SourceManager & SM)270 PathDiagnosticLocation::createBegin(const Decl *D,
271 const SourceManager &SM) {
272 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
273 }
274
275 PathDiagnosticLocation
createBegin(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)276 PathDiagnosticLocation::createBegin(const Stmt *S,
277 const SourceManager &SM,
278 LocationOrAnalysisDeclContext LAC) {
279 return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
280 SM, SingleLocK);
281 }
282
283 PathDiagnosticLocation
createOperatorLoc(const BinaryOperator * BO,const SourceManager & SM)284 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
285 const SourceManager &SM) {
286 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
287 }
288
289 PathDiagnosticLocation
createMemberLoc(const MemberExpr * ME,const SourceManager & SM)290 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
291 const SourceManager &SM) {
292 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
293 }
294
295 PathDiagnosticLocation
createBeginBrace(const CompoundStmt * CS,const SourceManager & SM)296 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
297 const SourceManager &SM) {
298 SourceLocation L = CS->getLBracLoc();
299 return PathDiagnosticLocation(L, SM, SingleLocK);
300 }
301
302 PathDiagnosticLocation
createEndBrace(const CompoundStmt * CS,const SourceManager & SM)303 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
304 const SourceManager &SM) {
305 SourceLocation L = CS->getRBracLoc();
306 return PathDiagnosticLocation(L, SM, SingleLocK);
307 }
308
309 PathDiagnosticLocation
createDeclBegin(const LocationContext * LC,const SourceManager & SM)310 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
311 const SourceManager &SM) {
312 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
313 if (const CompoundStmt *CS =
314 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
315 if (!CS->body_empty()) {
316 SourceLocation Loc = (*CS->body_begin())->getLocStart();
317 return PathDiagnosticLocation(Loc, SM, SingleLocK);
318 }
319
320 return PathDiagnosticLocation();
321 }
322
323 PathDiagnosticLocation
createDeclEnd(const LocationContext * LC,const SourceManager & SM)324 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
325 const SourceManager &SM) {
326 SourceLocation L = LC->getDecl()->getBodyRBrace();
327 return PathDiagnosticLocation(L, SM, SingleLocK);
328 }
329
330 PathDiagnosticLocation
create(const ProgramPoint & P,const SourceManager & SMng)331 PathDiagnosticLocation::create(const ProgramPoint& P,
332 const SourceManager &SMng) {
333
334 const Stmt* S = 0;
335 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
336 const CFGBlock *BSrc = BE->getSrc();
337 S = BSrc->getTerminatorCondition();
338 }
339 else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
340 S = PS->getStmt();
341 }
342
343 return PathDiagnosticLocation(S, SMng, P.getLocationContext());
344 }
345
346 PathDiagnosticLocation
createEndOfPath(const ExplodedNode * N,const SourceManager & SM)347 PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
348 const SourceManager &SM) {
349 assert(N && "Cannot create a location with a null node.");
350
351 const ExplodedNode *NI = N;
352
353 while (NI) {
354 ProgramPoint P = NI->getLocation();
355 const LocationContext *LC = P.getLocationContext();
356 if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
357 return PathDiagnosticLocation(PS->getStmt(), SM, LC);
358 else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
359 const Stmt *Term = BE->getSrc()->getTerminator();
360 if (Term) {
361 return PathDiagnosticLocation(Term, SM, LC);
362 }
363 }
364 NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
365 }
366
367 return createDeclEnd(N->getLocationContext(), SM);
368 }
369
createSingleLocation(const PathDiagnosticLocation & PDL)370 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
371 const PathDiagnosticLocation &PDL) {
372 FullSourceLoc L = PDL.asLocation();
373 return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
374 }
375
376 FullSourceLoc
genLocation(SourceLocation L,LocationOrAnalysisDeclContext LAC) const377 PathDiagnosticLocation::genLocation(SourceLocation L,
378 LocationOrAnalysisDeclContext LAC) const {
379 assert(isValid());
380 // Note that we want a 'switch' here so that the compiler can warn us in
381 // case we add more cases.
382 switch (K) {
383 case SingleLocK:
384 case RangeK:
385 break;
386 case StmtK:
387 // Defensive checking.
388 if (!S)
389 break;
390 return FullSourceLoc(getValidSourceLocation(S, LAC),
391 const_cast<SourceManager&>(*SM));
392 case DeclK:
393 // Defensive checking.
394 if (!D)
395 break;
396 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
397 }
398
399 return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
400 }
401
402 PathDiagnosticRange
genRange(LocationOrAnalysisDeclContext LAC) const403 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
404 assert(isValid());
405 // Note that we want a 'switch' here so that the compiler can warn us in
406 // case we add more cases.
407 switch (K) {
408 case SingleLocK:
409 return PathDiagnosticRange(SourceRange(Loc,Loc), true);
410 case RangeK:
411 break;
412 case StmtK: {
413 const Stmt *S = asStmt();
414 switch (S->getStmtClass()) {
415 default:
416 break;
417 case Stmt::DeclStmtClass: {
418 const DeclStmt *DS = cast<DeclStmt>(S);
419 if (DS->isSingleDecl()) {
420 // Should always be the case, but we'll be defensive.
421 return SourceRange(DS->getLocStart(),
422 DS->getSingleDecl()->getLocation());
423 }
424 break;
425 }
426 // FIXME: Provide better range information for different
427 // terminators.
428 case Stmt::IfStmtClass:
429 case Stmt::WhileStmtClass:
430 case Stmt::DoStmtClass:
431 case Stmt::ForStmtClass:
432 case Stmt::ChooseExprClass:
433 case Stmt::IndirectGotoStmtClass:
434 case Stmt::SwitchStmtClass:
435 case Stmt::BinaryConditionalOperatorClass:
436 case Stmt::ConditionalOperatorClass:
437 case Stmt::ObjCForCollectionStmtClass: {
438 SourceLocation L = getValidSourceLocation(S, LAC);
439 return SourceRange(L, L);
440 }
441 }
442 SourceRange R = S->getSourceRange();
443 if (R.isValid())
444 return R;
445 break;
446 }
447 case DeclK:
448 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
449 return MD->getSourceRange();
450 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
451 if (Stmt *Body = FD->getBody())
452 return Body->getSourceRange();
453 }
454 else {
455 SourceLocation L = D->getLocation();
456 return PathDiagnosticRange(SourceRange(L, L), true);
457 }
458 }
459
460 return SourceRange(Loc,Loc);
461 }
462
flatten()463 void PathDiagnosticLocation::flatten() {
464 if (K == StmtK) {
465 K = RangeK;
466 S = 0;
467 D = 0;
468 }
469 else if (K == DeclK) {
470 K = SingleLocK;
471 S = 0;
472 D = 0;
473 }
474 }
475
getLocation() const476 PathDiagnosticLocation PathDiagnostic::getLocation() const {
477 assert(path.size() > 0 &&
478 "getLocation() requires a non-empty PathDiagnostic.");
479
480 PathDiagnosticPiece *p = path.rbegin()->getPtr();
481
482 while (true) {
483 if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) {
484 assert(!cp->path.empty());
485 p = cp->path.rbegin()->getPtr();
486 continue;
487 }
488 break;
489 }
490
491 return p->getLocation();
492 }
493
494 //===----------------------------------------------------------------------===//
495 // Manipulation of PathDiagnosticCallPieces.
496 //===----------------------------------------------------------------------===//
497
getLastStmtLoc(const ExplodedNode * N,const SourceManager & SM)498 static PathDiagnosticLocation getLastStmtLoc(const ExplodedNode *N,
499 const SourceManager &SM) {
500 while (N) {
501 ProgramPoint PP = N->getLocation();
502 if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP))
503 return PathDiagnosticLocation(SP->getStmt(), SM, PP.getLocationContext());
504 if (N->pred_empty())
505 break;
506 N = *N->pred_begin();
507 }
508 return PathDiagnosticLocation();
509 }
510
511 PathDiagnosticCallPiece *
construct(const ExplodedNode * N,const CallExit & CE,const SourceManager & SM)512 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
513 const CallExit &CE,
514 const SourceManager &SM) {
515 const Decl *caller = CE.getLocationContext()->getParent()->getDecl();
516 PathDiagnosticLocation pos = getLastStmtLoc(N, SM);
517 return new PathDiagnosticCallPiece(caller, pos);
518 }
519
520 PathDiagnosticCallPiece *
construct(PathPieces & path,const Decl * caller)521 PathDiagnosticCallPiece::construct(PathPieces &path,
522 const Decl *caller) {
523 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
524 path.clear();
525 path.push_front(C);
526 return C;
527 }
528
setCallee(const CallEnter & CE,const SourceManager & SM)529 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
530 const SourceManager &SM) {
531 const Decl *D = CE.getCalleeContext()->getDecl();
532 Callee = D;
533 callEnter = PathDiagnosticLocation(CE.getCallExpr(), SM,
534 CE.getLocationContext());
535 callEnterWithin = PathDiagnosticLocation::createBegin(D, SM);
536 }
537
538 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallEnterEvent() const539 PathDiagnosticCallPiece::getCallEnterEvent() const {
540 if (!Callee)
541 return 0;
542 SmallString<256> buf;
543 llvm::raw_svector_ostream Out(buf);
544 if (isa<BlockDecl>(Callee))
545 Out << "Calling anonymous block";
546 else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
547 Out << "Calling '" << *ND << "'";
548 StringRef msg = Out.str();
549 if (msg.empty())
550 return 0;
551 return new PathDiagnosticEventPiece(callEnter, msg);
552 }
553
554 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallEnterWithinCallerEvent() const555 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
556 SmallString<256> buf;
557 llvm::raw_svector_ostream Out(buf);
558 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
559 Out << "Entered call from '" << *ND << "'";
560 else
561 Out << "Entered call";
562 StringRef msg = Out.str();
563 if (msg.empty())
564 return 0;
565 return new PathDiagnosticEventPiece(callEnterWithin, msg);
566 }
567
568 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
getCallExitEvent() const569 PathDiagnosticCallPiece::getCallExitEvent() const {
570 if (NoExit)
571 return 0;
572 SmallString<256> buf;
573 llvm::raw_svector_ostream Out(buf);
574 if (!CallStackMessage.empty())
575 Out << CallStackMessage;
576 else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
577 Out << "Returning from '" << *ND << "'";
578 else
579 Out << "Returning to caller";
580 return new PathDiagnosticEventPiece(callReturn, Out.str());
581 }
582
compute_path_size(const PathPieces & pieces,unsigned & size)583 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
584 for (PathPieces::const_iterator it = pieces.begin(),
585 et = pieces.end(); it != et; ++it) {
586 const PathDiagnosticPiece *piece = it->getPtr();
587 if (const PathDiagnosticCallPiece *cp =
588 dyn_cast<PathDiagnosticCallPiece>(piece)) {
589 compute_path_size(cp->path, size);
590 }
591 else
592 ++size;
593 }
594 }
595
full_size()596 unsigned PathDiagnostic::full_size() {
597 unsigned size = 0;
598 compute_path_size(path, size);
599 return size;
600 }
601
602 //===----------------------------------------------------------------------===//
603 // FoldingSet profiling methods.
604 //===----------------------------------------------------------------------===//
605
Profile(llvm::FoldingSetNodeID & ID) const606 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
607 ID.AddInteger(Range.getBegin().getRawEncoding());
608 ID.AddInteger(Range.getEnd().getRawEncoding());
609 ID.AddInteger(Loc.getRawEncoding());
610 return;
611 }
612
Profile(llvm::FoldingSetNodeID & ID) const613 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
614 ID.AddInteger((unsigned) getKind());
615 ID.AddString(str);
616 // FIXME: Add profiling support for code hints.
617 ID.AddInteger((unsigned) getDisplayHint());
618 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
619 ID.AddInteger(I->getBegin().getRawEncoding());
620 ID.AddInteger(I->getEnd().getRawEncoding());
621 }
622 }
623
Profile(llvm::FoldingSetNodeID & ID) const624 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
625 PathDiagnosticPiece::Profile(ID);
626 for (PathPieces::const_iterator it = path.begin(),
627 et = path.end(); it != et; ++it) {
628 ID.Add(**it);
629 }
630 }
631
Profile(llvm::FoldingSetNodeID & ID) const632 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
633 PathDiagnosticPiece::Profile(ID);
634 ID.Add(Pos);
635 }
636
Profile(llvm::FoldingSetNodeID & ID) const637 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
638 PathDiagnosticPiece::Profile(ID);
639 for (const_iterator I = begin(), E = end(); I != E; ++I)
640 ID.Add(*I);
641 }
642
Profile(llvm::FoldingSetNodeID & ID) const643 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
644 PathDiagnosticSpotPiece::Profile(ID);
645 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
646 I != E; ++I)
647 ID.Add(**I);
648 }
649
Profile(llvm::FoldingSetNodeID & ID) const650 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
651 if (!path.empty())
652 getLocation().Profile(ID);
653 ID.AddString(BugType);
654 ID.AddString(Desc);
655 ID.AddString(Category);
656 }
657
FullProfile(llvm::FoldingSetNodeID & ID) const658 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
659 Profile(ID);
660 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
661 ID.Add(**I);
662 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
663 ID.AddString(*I);
664 }
665
~StackHintGenerator()666 StackHintGenerator::~StackHintGenerator() {}
667
getMessage(const ExplodedNode * N)668 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
669 ProgramPoint P = N->getLocation();
670 const CallExit *CExit = dyn_cast<CallExit>(&P);
671 assert(CExit && "Stack Hints should be constructed at CallExit points.");
672
673 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CExit->getStmt());
674 if (!CE)
675 return "";
676
677 // Get the successor node to make sure the return statement is evaluated and
678 // CE is set to the result value.
679 N = *N->succ_begin();
680 if (!N)
681 return getMessageForSymbolNotFound();
682
683 // Check if one of the parameters are set to the interesting symbol.
684 ProgramStateRef State = N->getState();
685 const LocationContext *LCtx = N->getLocationContext();
686 unsigned ArgIndex = 0;
687 for (CallExpr::const_arg_iterator I = CE->arg_begin(),
688 E = CE->arg_end(); I != E; ++I, ++ArgIndex){
689 SVal SV = State->getSVal(*I, LCtx);
690
691 // Check if the variable corresponding to the symbol is passed by value.
692 SymbolRef AS = SV.getAsLocSymbol();
693 if (AS == Sym) {
694 return getMessageForArg(*I, ArgIndex);
695 }
696
697 // Check if the parameter is a pointer to the symbol.
698 if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
699 SVal PSV = State->getSVal(Reg->getRegion());
700 SymbolRef AS = PSV.getAsLocSymbol();
701 if (AS == Sym) {
702 return getMessageForArg(*I, ArgIndex);
703 }
704 }
705 }
706
707 // Check if we are returning the interesting symbol.
708 SVal SV = State->getSVal(CE, LCtx);
709 SymbolRef RetSym = SV.getAsLocSymbol();
710 if (RetSym == Sym) {
711 return getMessageForReturn(CE);
712 }
713
714 return getMessageForSymbolNotFound();
715 }
716
717 /// TODO: This is copied from clang diagnostics. Maybe we could just move it to
718 /// some common place. (Same as HandleOrdinalModifier.)
printOrdinal(unsigned ValNo,llvm::raw_svector_ostream & Out)719 void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
720 llvm::raw_svector_ostream &Out) {
721 assert(ValNo != 0 && "ValNo must be strictly positive!");
722
723 // We could use text forms for the first N ordinals, but the numeric
724 // forms are actually nicer in diagnostics because they stand out.
725 Out << ValNo;
726
727 // It is critically important that we do this perfectly for
728 // user-written sequences with over 100 elements.
729 switch (ValNo % 100) {
730 case 11:
731 case 12:
732 case 13:
733 Out << "th"; return;
734 default:
735 switch (ValNo % 10) {
736 case 1: Out << "st"; return;
737 case 2: Out << "nd"; return;
738 case 3: Out << "rd"; return;
739 default: Out << "th"; return;
740 }
741 }
742 }
743
getMessageForArg(const Expr * ArgE,unsigned ArgIndex)744 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
745 unsigned ArgIndex) {
746 SmallString<200> buf;
747 llvm::raw_svector_ostream os(buf);
748
749 os << Msg << " via ";
750 // Printed parameters start at 1, not 0.
751 printOrdinal(++ArgIndex, os);
752 os << " parameter";
753
754 return os.str();
755 }
756