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