BugReporterVisitors.cpp revision 4ee7c9cedc015bc161fa290aa558356b9bcf1bfa
1// BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- 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 a set of BugReporter "visitors" which can be used to
11//  enhance the diagnostics reported for a bug.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/Expr.h"
16#include "clang/AST/ExprObjC.h"
17#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
18#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22
23using namespace clang;
24using namespace ento;
25
26//===----------------------------------------------------------------------===//
27// Utility functions.
28//===----------------------------------------------------------------------===//
29
30const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
31  // Pattern match for a few useful cases (do something smarter later):
32  //   a[0], p->f, *p
33  const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
34
35  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
36    if (U->getOpcode() == UO_Deref)
37      return U->getSubExpr()->IgnoreParenCasts();
38  }
39  else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
40    return ME->getBase()->IgnoreParenCasts();
41  }
42  else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
43    return AE->getBase();
44  }
45
46  return NULL;
47}
48
49const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) {
50  const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
51  if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
52    return BE->getRHS();
53  return NULL;
54}
55
56const Stmt *bugreporter::GetCalleeExpr(const ExplodedNode *N) {
57  // Callee is checked as a PreVisit to the CallExpr.
58  const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
59  if (const CallExpr *CE = dyn_cast<CallExpr>(S))
60    return CE->getCallee();
61  return NULL;
62}
63
64const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) {
65  const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
66  if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
67    return RS->getRetValue();
68  return NULL;
69}
70
71//===----------------------------------------------------------------------===//
72// Definitions for bug reporter visitors.
73//===----------------------------------------------------------------------===//
74
75namespace {
76class FindLastStoreBRVisitor : public BugReporterVisitor {
77  const MemRegion *R;
78  SVal V;
79  bool satisfied;
80  const ExplodedNode *StoreSite;
81public:
82  FindLastStoreBRVisitor(SVal v, const MemRegion *r)
83  : R(r), V(v), satisfied(false), StoreSite(0) {}
84
85  virtual void Profile(llvm::FoldingSetNodeID &ID) const {
86    static int tag = 0;
87    ID.AddPointer(&tag);
88    ID.AddPointer(R);
89    ID.Add(V);
90  }
91
92  PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
93                                 const ExplodedNode *PrevN,
94                                 BugReporterContext &BRC) {
95
96    if (satisfied)
97      return NULL;
98
99    if (!StoreSite) {
100      const ExplodedNode *Node = N, *Last = NULL;
101
102      for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
103
104        if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
105          if (const PostStmt *P = Node->getLocationAs<PostStmt>())
106            if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
107              if (DS->getSingleDecl() == VR->getDecl()) {
108                Last = Node;
109                break;
110              }
111        }
112
113        if (Node->getState()->getSVal(R) != V)
114          break;
115      }
116
117      if (!Node || !Last) {
118        satisfied = true;
119        return NULL;
120      }
121
122      StoreSite = Last;
123    }
124
125    if (StoreSite != N)
126      return NULL;
127
128    satisfied = true;
129    llvm::SmallString<256> sbuf;
130    llvm::raw_svector_ostream os(sbuf);
131
132    if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
133      if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
134
135        if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
136          os << "Variable '" << VR->getDecl() << "' ";
137        }
138        else
139          return NULL;
140
141        if (isa<loc::ConcreteInt>(V)) {
142          bool b = false;
143          if (R->isBoundable()) {
144            if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
145              if (TR->getValueType()->isObjCObjectPointerType()) {
146                os << "initialized to nil";
147                b = true;
148              }
149            }
150          }
151
152          if (!b)
153            os << "initialized to a null pointer value";
154        }
155        else if (isa<nonloc::ConcreteInt>(V)) {
156          os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
157        }
158        else if (V.isUndef()) {
159          if (isa<VarRegion>(R)) {
160            const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
161            if (VD->getInit())
162              os << "initialized to a garbage value";
163            else
164              os << "declared without an initial value";
165          }
166        }
167      }
168    }
169
170    if (os.str().empty()) {
171      if (isa<loc::ConcreteInt>(V)) {
172        bool b = false;
173        if (R->isBoundable()) {
174          if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
175            if (TR->getValueType()->isObjCObjectPointerType()) {
176              os << "nil object reference stored to ";
177              b = true;
178            }
179          }
180        }
181
182        if (!b)
183          os << "Null pointer value stored to ";
184      }
185      else if (V.isUndef()) {
186        os << "Uninitialized value stored to ";
187      }
188      else if (isa<nonloc::ConcreteInt>(V)) {
189        os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
190           << " is assigned to ";
191      }
192      else
193        return NULL;
194
195      if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
196        os << '\'' << VR->getDecl() << '\'';
197      }
198      else
199        return NULL;
200    }
201
202    // FIXME: Refactor this into BugReporterContext.
203    const Stmt *S = 0;
204    ProgramPoint P = N->getLocation();
205
206    if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
207      const CFGBlock *BSrc = BE->getSrc();
208      S = BSrc->getTerminatorCondition();
209    }
210    else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
211      S = PS->getStmt();
212    }
213
214    if (!S)
215      return NULL;
216
217    // Construct a new PathDiagnosticPiece.
218    PathDiagnosticLocation L(S, BRC.getSourceManager());
219    return new PathDiagnosticEventPiece(L, os.str());
220  }
221};
222
223
224static void registerFindLastStore(BugReporterContext &BRC, const MemRegion *R,
225                                  SVal V) {
226  BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
227}
228
229class TrackConstraintBRVisitor : public BugReporterVisitor {
230  DefinedSVal Constraint;
231  const bool Assumption;
232  bool isSatisfied;
233public:
234  TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
235  : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
236
237  void Profile(llvm::FoldingSetNodeID &ID) const {
238    static int tag = 0;
239    ID.AddPointer(&tag);
240    ID.AddBoolean(Assumption);
241    ID.Add(Constraint);
242  }
243
244  PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
245                                 const ExplodedNode *PrevN,
246                                 BugReporterContext &BRC) {
247    if (isSatisfied)
248      return NULL;
249
250    // Check if in the previous state it was feasible for this constraint
251    // to *not* be true.
252    if (PrevN->getState()->assume(Constraint, !Assumption)) {
253
254      isSatisfied = true;
255
256      // As a sanity check, make sure that the negation of the constraint
257      // was infeasible in the current state.  If it is feasible, we somehow
258      // missed the transition point.
259      if (N->getState()->assume(Constraint, !Assumption))
260        return NULL;
261
262      // We found the transition point for the constraint.  We now need to
263      // pretty-print the constraint. (work-in-progress)
264      std::string sbuf;
265      llvm::raw_string_ostream os(sbuf);
266
267      if (isa<Loc>(Constraint)) {
268        os << "Assuming pointer value is ";
269        os << (Assumption ? "non-null" : "null");
270      }
271
272      if (os.str().empty())
273        return NULL;
274
275      // FIXME: Refactor this into BugReporterContext.
276      const Stmt *S = 0;
277      ProgramPoint P = N->getLocation();
278
279      if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
280        const CFGBlock *BSrc = BE->getSrc();
281        S = BSrc->getTerminatorCondition();
282      }
283      else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
284        S = PS->getStmt();
285      }
286
287      if (!S)
288        return NULL;
289
290      // Construct a new PathDiagnosticPiece.
291      PathDiagnosticLocation L(S, BRC.getSourceManager());
292      return new PathDiagnosticEventPiece(L, os.str());
293    }
294
295    return NULL;
296  }
297};
298} // end anonymous namespace
299
300static void registerTrackConstraint(BugReporterContext &BRC,
301                                    DefinedSVal Constraint,
302                                    bool Assumption) {
303  BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
304}
305
306void bugreporter::registerTrackNullOrUndefValue(BugReporterContext &BRC,
307                                                const void *data,
308                                                const ExplodedNode *N) {
309
310  const Stmt *S = static_cast<const Stmt*>(data);
311
312  if (!S)
313    return;
314
315  ProgramStateManager &StateMgr = BRC.getStateManager();
316
317  // Walk through nodes until we get one that matches the statement
318  // exactly.
319  while (N) {
320    const ProgramPoint &pp = N->getLocation();
321    if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
322      if (ps->getStmt() == S)
323        break;
324    }
325    N = *N->pred_begin();
326  }
327
328  if (!N)
329    return;
330
331  const ProgramState *state = N->getState();
332
333  // Walk through lvalue-to-rvalue conversions.
334  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
335    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
336      const VarRegion *R =
337        StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
338
339      // What did we load?
340      SVal V = state->getSVal(loc::MemRegionVal(R));
341
342      if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
343          || V.isUndef()) {
344        ::registerFindLastStore(BRC, R, V);
345      }
346    }
347  }
348
349  SVal V = state->getSValAsScalarOrLoc(S);
350
351  // Uncomment this to find cases where we aren't properly getting the
352  // base value that was dereferenced.
353  // assert(!V.isUnknownOrUndef());
354
355  // Is it a symbolic value?
356  if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
357    const SubRegion *R = cast<SubRegion>(L->getRegion());
358    while (R && !isa<SymbolicRegion>(R)) {
359      R = dyn_cast<SubRegion>(R->getSuperRegion());
360    }
361
362    if (R) {
363      assert(isa<SymbolicRegion>(R));
364      registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
365    }
366  }
367}
368
369void bugreporter::registerFindLastStore(BugReporterContext &BRC,
370                                        const void *data,
371                                        const ExplodedNode *N) {
372
373  const MemRegion *R = static_cast<const MemRegion*>(data);
374
375  if (!R)
376    return;
377
378  const ProgramState *state = N->getState();
379  SVal V = state->getSVal(R);
380
381  if (V.isUnknown())
382    return;
383
384  BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
385}
386
387
388namespace {
389class NilReceiverVisitor : public BugReporterVisitor {
390public:
391  NilReceiverVisitor() {}
392
393  void Profile(llvm::FoldingSetNodeID &ID) const {
394    static int x = 0;
395    ID.AddPointer(&x);
396  }
397
398  PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
399                                 const ExplodedNode *PrevN,
400                                 BugReporterContext &BRC) {
401
402    const PostStmt *P = N->getLocationAs<PostStmt>();
403    if (!P)
404      return 0;
405    const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
406    if (!ME)
407      return 0;
408    const Expr *Receiver = ME->getInstanceReceiver();
409    if (!Receiver)
410      return 0;
411    const ProgramState *state = N->getState();
412    const SVal &V = state->getSVal(Receiver);
413    const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
414    if (!DV)
415      return 0;
416    state = state->assume(*DV, true);
417    if (state)
418      return 0;
419
420    // The receiver was nil, and hence the method was skipped.
421    // Register a BugReporterVisitor to issue a message telling us how
422    // the receiver was null.
423    bugreporter::registerTrackNullOrUndefValue(BRC, Receiver, N);
424    // Issue a message saying that the method was skipped.
425    PathDiagnosticLocation L(Receiver, BRC.getSourceManager());
426    return new PathDiagnosticEventPiece(L, "No method actually called "
427                                           "because the receiver is nil");
428  }
429};
430} // end anonymous namespace
431
432void bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) {
433  BRC.addVisitor(new NilReceiverVisitor());
434}
435
436// Registers every VarDecl inside a Stmt with a last store vistor.
437void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC,
438                                                   const void *stmt,
439                                                   const ExplodedNode *N) {
440  const Stmt *S = static_cast<const Stmt *>(stmt);
441
442  std::deque<const Stmt *> WorkList;
443
444  WorkList.push_back(S);
445
446  while (!WorkList.empty()) {
447    const Stmt *Head = WorkList.front();
448    WorkList.pop_front();
449
450    ProgramStateManager &StateMgr = BRC.getStateManager();
451    const ProgramState *state = N->getState();
452
453    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) {
454      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
455        const VarRegion *R =
456        StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
457
458        // What did we load?
459        SVal V = state->getSVal(S);
460
461        if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) {
462          ::registerFindLastStore(BRC, R, V);
463        }
464      }
465    }
466
467    for (Stmt::const_child_iterator I = Head->child_begin();
468        I != Head->child_end(); ++I)
469      WorkList.push_back(*I);
470  }
471}
472
473//===----------------------------------------------------------------------===//
474// Visitor that tries to report interesting diagnostics from conditions.
475//===----------------------------------------------------------------------===//
476
477namespace {
478class ConditionVisitor : public BugReporterVisitor {
479public:
480  void Profile(llvm::FoldingSetNodeID &ID) const {
481    static int x = 0;
482    ID.AddPointer(&x);
483  }
484
485  virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
486                                         const ExplodedNode *Prev,
487                                         BugReporterContext &BRC);
488
489  PathDiagnosticPiece *VisitTerminator(const Stmt *Term,
490                                       const ProgramState *CurrentState,
491                                       const ProgramState *PrevState,
492                                       const CFGBlock *srcBlk,
493                                       const CFGBlock *dstBlk,
494                                       BugReporterContext &BRC);
495
496  PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
497                                     bool tookTrue,
498                                     BugReporterContext &BRC);
499
500  PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
501                                     const DeclRefExpr *DR,
502                                     const bool tookTrue,
503                                     BugReporterContext &BRC);
504
505  PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
506                                     const BinaryOperator *BExpr,
507                                     const bool tookTrue,
508                                     BugReporterContext &BRC);
509
510  void patternMatch(const Expr *Ex,
511                    llvm::raw_ostream &Out,
512                    BugReporterContext &BRC);
513};
514}
515
516PathDiagnosticPiece *ConditionVisitor::VisitNode(const ExplodedNode *N,
517                                                 const ExplodedNode *Prev,
518                                                 BugReporterContext &BRC) {
519
520  const ProgramPoint &progPoint = N->getLocation();
521
522  const ProgramState *CurrentState = N->getState();
523  const ProgramState *PrevState = Prev->getState();
524
525  // Compare the GDMs of the state, because that is where constraints
526  // are managed.  Note that ensure that we only look at nodes that
527  // were generated by the analyzer engine proper, not checkers.
528  if (CurrentState->getGDM().getRoot() ==
529      PrevState->getGDM().getRoot())
530    return 0;
531
532  // If an assumption was made on a branch, it should be caught
533  // here by looking at the state transition.
534  if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) {
535    const CFGBlock *srcBlk = BE->getSrc();
536    if (const Stmt *term = srcBlk->getTerminator())
537      return VisitTerminator(term, CurrentState, PrevState,
538                             srcBlk, BE->getDst(), BRC);
539    return 0;
540  }
541
542  if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) {
543    // FIXME: Assuming that BugReporter is a GRBugReporter is a layering
544    // violation.
545    const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
546      cast<GRBugReporter>(BRC.getBugReporter()).
547        getEngine().getEagerlyAssumeTags();
548
549    const ProgramPointTag *tag = PS->getTag();
550    if (tag == tags.first)
551      return VisitTrueTest(cast<Expr>(PS->getStmt()), true, BRC);
552    if (tag == tags.second)
553      return VisitTrueTest(cast<Expr>(PS->getStmt()), false, BRC);
554
555    return 0;
556  }
557
558  return 0;
559}
560
561PathDiagnosticPiece *
562ConditionVisitor::VisitTerminator(const Stmt *Term,
563                                  const ProgramState *CurrentState,
564                                  const ProgramState *PrevState,
565                                  const CFGBlock *srcBlk,
566                                  const CFGBlock *dstBlk,
567                                  BugReporterContext &BRC) {
568
569  const Expr *Cond = 0;
570
571  switch (Term->getStmtClass()) {
572  default:
573    return 0;
574  case Stmt::IfStmtClass:
575    Cond = cast<IfStmt>(Term)->getCond();
576    break;
577  case Stmt::ConditionalOperatorClass:
578    Cond = cast<ConditionalOperator>(Term)->getCond();
579    break;
580  }
581
582  assert(Cond);
583  assert(srcBlk->succ_size() == 2);
584  const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk;
585  return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()),
586                       tookTrue, BRC);
587}
588
589PathDiagnosticPiece *
590ConditionVisitor::VisitTrueTest(const Expr *Cond,
591                                bool tookTrue,
592                                BugReporterContext &BRC) {
593
594  const Expr *Ex = Cond;
595
596  while (true) {
597    Ex = Ex->IgnoreParens();
598    switch (Ex->getStmtClass()) {
599      default:
600        return 0;
601      case Stmt::BinaryOperatorClass:
602        return VisitTrueTest(Cond, cast<BinaryOperator>(Cond), tookTrue, BRC);
603      case Stmt::DeclRefExprClass:
604        return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC);
605      case Stmt::UnaryOperatorClass: {
606        const UnaryOperator *UO = cast<UnaryOperator>(Ex);
607        if (UO->getOpcode() == UO_LNot) {
608          tookTrue = !tookTrue;
609          Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext());
610          continue;
611        }
612        return 0;
613      }
614    }
615  }
616}
617
618void ConditionVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out,
619                                    BugReporterContext &BRC) {
620  const Expr *OriginalExpr = Ex;
621  Ex = Ex->IgnoreParenCasts();
622
623  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
624    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
625      Out << VD->getDeclName().getAsString();
626    return;
627  }
628
629  if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) {
630    QualType OriginalTy = OriginalExpr->getType();
631    if (OriginalTy->isPointerType()) {
632      if (IL->getValue() == 0) {
633        Out << "null";
634        return;
635      }
636    }
637    else if (OriginalTy->isObjCObjectPointerType()) {
638      if (IL->getValue() == 0) {
639        Out << "nil";
640        return;
641      }
642    }
643
644    Out << IL->getValue();
645    return;
646  }
647}
648
649PathDiagnosticPiece *
650ConditionVisitor::VisitTrueTest(const Expr *Cond,
651                                const BinaryOperator *BExpr,
652                                const bool tookTrue,
653                                BugReporterContext &BRC) {
654
655  llvm::SmallString<128> LhsString, RhsString;
656  {
657    llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
658    patternMatch(BExpr->getLHS(), OutLHS, BRC);
659    patternMatch(BExpr->getRHS(), OutRHS, BRC);
660  }
661
662  if (LhsString.empty() || RhsString.empty())
663    return 0;
664
665  llvm::SmallString<256> buf;
666  llvm::raw_svector_ostream Out(buf);
667  Out << "Assuming " << LhsString << " is ";
668
669  // Do we need to invert the opcode?
670  BinaryOperator::Opcode Op = BExpr->getOpcode();
671
672  if (!tookTrue)
673    switch (Op) {
674      case BO_EQ: Op = BO_NE; break;
675      case BO_NE: Op = BO_EQ; break;
676      case BO_LT: Op = BO_GE; break;
677      case BO_GT: Op = BO_LE; break;
678      case BO_LE: Op = BO_GT; break;
679      case BO_GE: Op = BO_LT; break;
680      default:
681        return 0;
682    }
683
684  switch (BExpr->getOpcode()) {
685    case BO_EQ:
686      Out << "equal to ";
687      break;
688    case BO_NE:
689      Out << "not equal to ";
690      break;
691    default:
692      Out << BinaryOperator::getOpcodeStr(Op) << ' ';
693      break;
694  }
695
696  Out << RhsString;
697
698  PathDiagnosticLocation Loc(Cond, BRC.getSourceManager());
699  return new PathDiagnosticEventPiece(Loc, Out.str());
700}
701
702PathDiagnosticPiece *
703ConditionVisitor::VisitTrueTest(const Expr *Cond,
704                                const DeclRefExpr *DR,
705                                const bool tookTrue,
706                                BugReporterContext &BRC) {
707
708  const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
709  if (!VD)
710    return 0;
711
712  llvm::SmallString<256> Buf;
713  llvm::raw_svector_ostream Out(Buf);
714
715  Out << "Assuming '";
716  VD->getDeclName().printName(Out);
717  Out << "' is ";
718
719  QualType VDTy = VD->getType();
720
721  if (VDTy->isPointerType())
722    Out << (tookTrue ? "non-null" : "null");
723  else if (VDTy->isObjCObjectPointerType())
724    Out << (tookTrue ? "non-nil" : "nil");
725  else if (VDTy->isScalarType())
726    Out << (tookTrue ? "not equal to 0" : "0");
727  else
728    return 0;
729
730  PathDiagnosticLocation Loc(Cond, BRC.getSourceManager());
731  return new PathDiagnosticEventPiece(Loc, Out.str());
732}
733
734void bugreporter::registerConditionVisitor(BugReporterContext &BRC) {
735  BRC.addVisitor(new ConditionVisitor());
736}
737
738