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 25 using namespace clang; 26 using namespace ento; 27 28 //===----------------------------------------------------------------------===// 29 // Utility functions. 30 //===----------------------------------------------------------------------===// 31 32 const 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 51 const 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 58 const 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 66 const 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 77 PathDiagnosticPiece* 78 BugReporterVisitor::getEndPath(BugReporterContext &BRC, 79 const ExplodedNode *EndPathNode, 80 BugReport &BR) { 81 return 0; 82 } 83 84 PathDiagnosticPiece* 85 BugReporterVisitor::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 106 void 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 113 PathDiagnosticPiece *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 236 void 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 243 PathDiagnosticPiece * 244 TrackConstraintBRVisitor::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 288 BugReporterVisitor * 289 bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N, 290 const Stmt *S) { 291 if (!S || !N) 292 return 0; 293 294 ProgramStateManager &StateMgr = N->getState()->getStateManager(); 295 296 // Walk through nodes until we get one that matches the statement 297 // exactly. 298 while (N) { 299 const ProgramPoint &pp = N->getLocation(); 300 if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { 301 if (ps->getStmt() == S) 302 break; 303 } 304 N = N->getFirstPred(); 305 } 306 307 if (!N) 308 return 0; 309 310 ProgramStateRef state = N->getState(); 311 312 // Walk through lvalue-to-rvalue conversions. 313 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) { 314 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 315 const VarRegion *R = 316 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 317 318 // What did we load? 319 SVal V = state->getSVal(loc::MemRegionVal(R)); 320 321 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V) 322 || V.isUndef()) { 323 return new FindLastStoreBRVisitor(V, R); 324 } 325 } 326 } 327 328 SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); 329 330 // Uncomment this to find cases where we aren't properly getting the 331 // base value that was dereferenced. 332 // assert(!V.isUnknownOrUndef()); 333 334 // Is it a symbolic value? 335 if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { 336 const SubRegion *R = cast<SubRegion>(L->getRegion()); 337 while (R && !isa<SymbolicRegion>(R)) { 338 R = dyn_cast<SubRegion>(R->getSuperRegion()); 339 } 340 341 if (R) { 342 assert(isa<SymbolicRegion>(R)); 343 return new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); 344 } 345 } 346 347 return 0; 348 } 349 350 BugReporterVisitor * 351 FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N, 352 const MemRegion *R) { 353 assert(R && "The memory region is null."); 354 355 ProgramStateRef state = N->getState(); 356 SVal V = state->getSVal(R); 357 if (V.isUnknown()) 358 return 0; 359 360 return new FindLastStoreBRVisitor(V, R); 361 } 362 363 364 PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, 365 const ExplodedNode *PrevN, 366 BugReporterContext &BRC, 367 BugReport &BR) { 368 const PostStmt *P = N->getLocationAs<PostStmt>(); 369 if (!P) 370 return 0; 371 const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); 372 if (!ME) 373 return 0; 374 const Expr *Receiver = ME->getInstanceReceiver(); 375 if (!Receiver) 376 return 0; 377 ProgramStateRef state = N->getState(); 378 const SVal &V = state->getSVal(Receiver, N->getLocationContext()); 379 const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); 380 if (!DV) 381 return 0; 382 state = state->assume(*DV, true); 383 if (state) 384 return 0; 385 386 // The receiver was nil, and hence the method was skipped. 387 // Register a BugReporterVisitor to issue a message telling us how 388 // the receiver was null. 389 BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver)); 390 // Issue a message saying that the method was skipped. 391 PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), 392 N->getLocationContext()); 393 return new PathDiagnosticEventPiece(L, "No method actually called " 394 "because the receiver is nil"); 395 } 396 397 // Registers every VarDecl inside a Stmt with a last store visitor. 398 void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, 399 const Stmt *S) { 400 const ExplodedNode *N = BR.getErrorNode(); 401 std::deque<const Stmt *> WorkList; 402 WorkList.push_back(S); 403 404 while (!WorkList.empty()) { 405 const Stmt *Head = WorkList.front(); 406 WorkList.pop_front(); 407 408 ProgramStateRef state = N->getState(); 409 ProgramStateManager &StateMgr = state->getStateManager(); 410 411 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) { 412 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 413 const VarRegion *R = 414 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 415 416 // What did we load? 417 SVal V = state->getSVal(S, N->getLocationContext()); 418 419 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) { 420 // Register a new visitor with the BugReport. 421 BR.addVisitor(new FindLastStoreBRVisitor(V, R)); 422 } 423 } 424 } 425 426 for (Stmt::const_child_iterator I = Head->child_begin(); 427 I != Head->child_end(); ++I) 428 WorkList.push_back(*I); 429 } 430 } 431 432 //===----------------------------------------------------------------------===// 433 // Visitor that tries to report interesting diagnostics from conditions. 434 //===----------------------------------------------------------------------===// 435 PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, 436 const ExplodedNode *Prev, 437 BugReporterContext &BRC, 438 BugReport &BR) { 439 440 const ProgramPoint &progPoint = N->getLocation(); 441 442 ProgramStateRef CurrentState = N->getState(); 443 ProgramStateRef PrevState = Prev->getState(); 444 445 // Compare the GDMs of the state, because that is where constraints 446 // are managed. Note that ensure that we only look at nodes that 447 // were generated by the analyzer engine proper, not checkers. 448 if (CurrentState->getGDM().getRoot() == 449 PrevState->getGDM().getRoot()) 450 return 0; 451 452 // If an assumption was made on a branch, it should be caught 453 // here by looking at the state transition. 454 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) { 455 const CFGBlock *srcBlk = BE->getSrc(); 456 if (const Stmt *term = srcBlk->getTerminator()) 457 return VisitTerminator(term, N, srcBlk, BE->getDst(), BRC); 458 return 0; 459 } 460 461 if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) { 462 // FIXME: Assuming that BugReporter is a GRBugReporter is a layering 463 // violation. 464 const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags = 465 cast<GRBugReporter>(BRC.getBugReporter()). 466 getEngine().getEagerlyAssumeTags(); 467 468 const ProgramPointTag *tag = PS->getTag(); 469 if (tag == tags.first) 470 return VisitTrueTest(cast<Expr>(PS->getStmt()), true, 471 BRC, N->getLocationContext()); 472 if (tag == tags.second) 473 return VisitTrueTest(cast<Expr>(PS->getStmt()), false, 474 BRC, N->getLocationContext()); 475 476 return 0; 477 } 478 479 return 0; 480 } 481 482 PathDiagnosticPiece * 483 ConditionBRVisitor::VisitTerminator(const Stmt *Term, 484 const ExplodedNode *N, 485 const CFGBlock *srcBlk, 486 const CFGBlock *dstBlk, 487 BugReporterContext &BRC) { 488 const Expr *Cond = 0; 489 490 switch (Term->getStmtClass()) { 491 default: 492 return 0; 493 case Stmt::IfStmtClass: 494 Cond = cast<IfStmt>(Term)->getCond(); 495 break; 496 case Stmt::ConditionalOperatorClass: 497 Cond = cast<ConditionalOperator>(Term)->getCond(); 498 break; 499 } 500 501 assert(Cond); 502 assert(srcBlk->succ_size() == 2); 503 const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; 504 return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), 505 tookTrue, BRC, N->getLocationContext()); 506 } 507 508 PathDiagnosticPiece * 509 ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 510 bool tookTrue, 511 BugReporterContext &BRC, 512 const LocationContext *LC) { 513 514 const Expr *Ex = Cond; 515 516 while (true) { 517 Ex = Ex->IgnoreParens(); 518 switch (Ex->getStmtClass()) { 519 default: 520 return 0; 521 case Stmt::BinaryOperatorClass: 522 return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, LC); 523 case Stmt::DeclRefExprClass: 524 return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, LC); 525 case Stmt::UnaryOperatorClass: { 526 const UnaryOperator *UO = cast<UnaryOperator>(Ex); 527 if (UO->getOpcode() == UO_LNot) { 528 tookTrue = !tookTrue; 529 Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext()); 530 continue; 531 } 532 return 0; 533 } 534 } 535 } 536 } 537 538 bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out, 539 BugReporterContext &BRC) { 540 const Expr *OriginalExpr = Ex; 541 Ex = Ex->IgnoreParenCasts(); 542 543 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { 544 const bool quotes = isa<VarDecl>(DR->getDecl()); 545 if (quotes) 546 Out << '\''; 547 Out << DR->getDecl()->getDeclName().getAsString(); 548 if (quotes) 549 Out << '\''; 550 return quotes; 551 } 552 553 if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) { 554 QualType OriginalTy = OriginalExpr->getType(); 555 if (OriginalTy->isPointerType()) { 556 if (IL->getValue() == 0) { 557 Out << "null"; 558 return false; 559 } 560 } 561 else if (OriginalTy->isObjCObjectPointerType()) { 562 if (IL->getValue() == 0) { 563 Out << "nil"; 564 return false; 565 } 566 } 567 568 Out << IL->getValue(); 569 return false; 570 } 571 572 return false; 573 } 574 575 PathDiagnosticPiece * 576 ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 577 const BinaryOperator *BExpr, 578 const bool tookTrue, 579 BugReporterContext &BRC, 580 const LocationContext *LC) { 581 582 bool shouldInvert = false; 583 584 SmallString<128> LhsString, RhsString; 585 { 586 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); 587 const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC); 588 const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC); 589 590 shouldInvert = !isVarLHS && isVarRHS; 591 } 592 593 BinaryOperator::Opcode Op = BExpr->getOpcode(); 594 595 if (BinaryOperator::isAssignmentOp(Op)) { 596 // For assignment operators, all that we care about is that the LHS 597 // evaluates to "true" or "false". 598 return VisitConditionVariable(LhsString, BExpr->getLHS(), tookTrue, 599 BRC, LC); 600 } 601 602 // For non-assignment operations, we require that we can understand 603 // both the LHS and RHS. 604 if (LhsString.empty() || RhsString.empty()) 605 return 0; 606 607 // Should we invert the strings if the LHS is not a variable name? 608 SmallString<256> buf; 609 llvm::raw_svector_ostream Out(buf); 610 Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is "; 611 612 // Do we need to invert the opcode? 613 if (shouldInvert) 614 switch (Op) { 615 default: break; 616 case BO_LT: Op = BO_GT; break; 617 case BO_GT: Op = BO_LT; break; 618 case BO_LE: Op = BO_GE; break; 619 case BO_GE: Op = BO_LE; break; 620 } 621 622 if (!tookTrue) 623 switch (Op) { 624 case BO_EQ: Op = BO_NE; break; 625 case BO_NE: Op = BO_EQ; break; 626 case BO_LT: Op = BO_GE; break; 627 case BO_GT: Op = BO_LE; break; 628 case BO_LE: Op = BO_GT; break; 629 case BO_GE: Op = BO_LT; break; 630 default: 631 return 0; 632 } 633 634 switch (Op) { 635 case BO_EQ: 636 Out << "equal to "; 637 break; 638 case BO_NE: 639 Out << "not equal to "; 640 break; 641 default: 642 Out << BinaryOperator::getOpcodeStr(Op) << ' '; 643 break; 644 } 645 646 Out << (shouldInvert ? LhsString : RhsString); 647 648 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); 649 return new PathDiagnosticEventPiece(Loc, Out.str()); 650 } 651 652 PathDiagnosticPiece * 653 ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, 654 const Expr *CondVarExpr, 655 const bool tookTrue, 656 BugReporterContext &BRC, 657 const LocationContext *LC) { 658 SmallString<256> buf; 659 llvm::raw_svector_ostream Out(buf); 660 Out << "Assuming " << LhsString << " is "; 661 662 QualType Ty = CondVarExpr->getType(); 663 664 if (Ty->isPointerType()) 665 Out << (tookTrue ? "not null" : "null"); 666 else if (Ty->isObjCObjectPointerType()) 667 Out << (tookTrue ? "not nil" : "nil"); 668 else if (Ty->isBooleanType()) 669 Out << (tookTrue ? "true" : "false"); 670 else if (Ty->isIntegerType()) 671 Out << (tookTrue ? "non-zero" : "zero"); 672 else 673 return 0; 674 675 PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LC); 676 return new PathDiagnosticEventPiece(Loc, Out.str()); 677 } 678 679 PathDiagnosticPiece * 680 ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 681 const DeclRefExpr *DR, 682 const bool tookTrue, 683 BugReporterContext &BRC, 684 const LocationContext *LC) { 685 686 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); 687 if (!VD) 688 return 0; 689 690 SmallString<256> Buf; 691 llvm::raw_svector_ostream Out(Buf); 692 693 Out << "Assuming '"; 694 VD->getDeclName().printName(Out); 695 Out << "' is "; 696 697 QualType VDTy = VD->getType(); 698 699 if (VDTy->isPointerType()) 700 Out << (tookTrue ? "non-null" : "null"); 701 else if (VDTy->isObjCObjectPointerType()) 702 Out << (tookTrue ? "non-nil" : "nil"); 703 else if (VDTy->isScalarType()) 704 Out << (tookTrue ? "not equal to 0" : "0"); 705 else 706 return 0; 707 708 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); 709 return new PathDiagnosticEventPiece(Loc, Out.str()); 710 } 711 712 static PathDiagnosticLocation getLastStmtLoc(const ExplodedNode *N, 713 const SourceManager &SM) { 714 while (N) { 715 ProgramPoint PP = N->getLocation(); 716 if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) 717 return PathDiagnosticLocation(SP->getStmt(), SM, PP.getLocationContext()); 718 if (N->pred_empty()) 719 break; 720 N = *N->pred_begin(); 721 } 722 return PathDiagnosticLocation(); 723 } 724 725 PathDiagnosticPiece * 726 CallEnterExitBRVisitor::VisitNode(const ExplodedNode *N, 727 const ExplodedNode *PrevN, 728 BugReporterContext &BRC, 729 BugReport &BR) { 730 ProgramPoint PP = N->getLocation(); 731 SmallString<256> buf; 732 llvm::raw_svector_ostream Out(buf); 733 PathDiagnosticLocation pos; 734 735 if (const CallEnter *CEnter = dyn_cast<CallEnter>(&PP)) { 736 const Decl *callee = CEnter->getCalleeContext()->getDecl(); 737 pos = PathDiagnosticLocation(CEnter->getCallExpr(), BRC.getSourceManager(), 738 PP.getLocationContext()); 739 if (isa<BlockDecl>(callee)) 740 Out << "Entering call to block"; 741 else if (const NamedDecl *ND = dyn_cast<NamedDecl>(callee)) 742 Out << "Entering call to '" << *ND << "'"; 743 StringRef msg = Out.str(); 744 if (msg.empty()) 745 return 0; 746 return new PathDiagnosticCallEnterPiece(pos, msg); 747 } 748 else if (const CallExit *CExit = dyn_cast<CallExit>(&PP)) { 749 const Decl *caller = CExit->getLocationContext()->getParent()->getDecl(); 750 pos = getLastStmtLoc(PrevN, BRC.getSourceManager()); 751 if (const NamedDecl *ND = dyn_cast<NamedDecl>(caller)) 752 Out << "Returning to '" << *ND << "'"; 753 else 754 Out << "Returning to caller"; 755 return new PathDiagnosticCallExitPiece(pos, Out.str()); 756 } 757 758 return 0; 759 } 760