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