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