BugReporterVisitors.cpp revision b8989f27f116ff2400e92a52c067a69846119eb5
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 ; Last = 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 Last = Node; 148 break; 149 } 150 } 151 152 if (Node->getState()->getSVal(R) != V) 153 break; 154 } 155 156 if (!Node || !Last) { 157 satisfied = true; 158 return NULL; 159 } 160 161 StoreSite = Last; 162 } 163 164 if (StoreSite != N) 165 return NULL; 166 167 satisfied = true; 168 llvm::SmallString<256> sbuf; 169 llvm::raw_svector_ostream os(sbuf); 170 171 if (const PostStmt *PS = N->getLocationAs<PostStmt>()) { 172 if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { 173 174 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 175 os << "Variable '" << *VR->getDecl() << "' "; 176 } 177 else 178 return NULL; 179 180 if (isa<loc::ConcreteInt>(V)) { 181 bool b = false; 182 if (R->isBoundable()) { 183 if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { 184 if (TR->getValueType()->isObjCObjectPointerType()) { 185 os << "initialized to nil"; 186 b = true; 187 } 188 } 189 } 190 191 if (!b) 192 os << "initialized to a null pointer value"; 193 } 194 else if (isa<nonloc::ConcreteInt>(V)) { 195 os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue(); 196 } 197 else if (V.isUndef()) { 198 if (isa<VarRegion>(R)) { 199 const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); 200 if (VD->getInit()) 201 os << "initialized to a garbage value"; 202 else 203 os << "declared without an initial value"; 204 } 205 } 206 } 207 } 208 209 if (os.str().empty()) { 210 if (isa<loc::ConcreteInt>(V)) { 211 bool b = false; 212 if (R->isBoundable()) { 213 if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { 214 if (TR->getValueType()->isObjCObjectPointerType()) { 215 os << "nil object reference stored to "; 216 b = true; 217 } 218 } 219 } 220 221 if (!b) 222 os << "Null pointer value stored to "; 223 } 224 else if (V.isUndef()) { 225 os << "Uninitialized value stored to "; 226 } 227 else if (isa<nonloc::ConcreteInt>(V)) { 228 os << "The value " << cast<nonloc::ConcreteInt>(V).getValue() 229 << " is assigned to "; 230 } 231 else 232 return NULL; 233 234 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 235 os << '\'' << *VR->getDecl() << '\''; 236 } 237 else 238 return NULL; 239 } 240 241 // Construct a new PathDiagnosticPiece. 242 ProgramPoint P = N->getLocation(); 243 PathDiagnosticLocation L = 244 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 245 if (!L.isValid()) 246 return NULL; 247 return new PathDiagnosticEventPiece(L, os.str()); 248} 249 250void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const { 251 static int tag = 0; 252 ID.AddPointer(&tag); 253 ID.AddBoolean(Assumption); 254 ID.Add(Constraint); 255} 256 257PathDiagnosticPiece * 258TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, 259 const ExplodedNode *PrevN, 260 BugReporterContext &BRC, 261 BugReport &BR) { 262 if (isSatisfied) 263 return NULL; 264 265 // Check if in the previous state it was feasible for this constraint 266 // to *not* be true. 267 if (PrevN->getState()->assume(Constraint, !Assumption)) { 268 269 isSatisfied = true; 270 271 // As a sanity check, make sure that the negation of the constraint 272 // was infeasible in the current state. If it is feasible, we somehow 273 // missed the transition point. 274 if (N->getState()->assume(Constraint, !Assumption)) 275 return NULL; 276 277 // We found the transition point for the constraint. We now need to 278 // pretty-print the constraint. (work-in-progress) 279 std::string sbuf; 280 llvm::raw_string_ostream os(sbuf); 281 282 if (isa<Loc>(Constraint)) { 283 os << "Assuming pointer value is "; 284 os << (Assumption ? "non-null" : "null"); 285 } 286 287 if (os.str().empty()) 288 return NULL; 289 290 // Construct a new PathDiagnosticPiece. 291 ProgramPoint P = N->getLocation(); 292 PathDiagnosticLocation L = 293 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 294 if (!L.isValid()) 295 return NULL; 296 return new PathDiagnosticEventPiece(L, os.str()); 297 } 298 299 return NULL; 300} 301 302BugReporterVisitor * 303bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N, 304 const Stmt *S) { 305 if (!S || !N) 306 return 0; 307 308 ProgramStateManager &StateMgr = N->getState()->getStateManager(); 309 310 // Walk through nodes until we get one that matches the statement 311 // exactly. 312 while (N) { 313 const ProgramPoint &pp = N->getLocation(); 314 if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { 315 if (ps->getStmt() == S) 316 break; 317 } 318 N = N->getFirstPred(); 319 } 320 321 if (!N) 322 return 0; 323 324 const ProgramState *state = N->getState(); 325 326 // Walk through lvalue-to-rvalue conversions. 327 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) { 328 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 329 const VarRegion *R = 330 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 331 332 // What did we load? 333 SVal V = state->getSVal(loc::MemRegionVal(R)); 334 335 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V) 336 || V.isUndef()) { 337 return new FindLastStoreBRVisitor(V, R); 338 } 339 } 340 } 341 342 SVal V = state->getSValAsScalarOrLoc(S); 343 344 // Uncomment this to find cases where we aren't properly getting the 345 // base value that was dereferenced. 346 // assert(!V.isUnknownOrUndef()); 347 348 // Is it a symbolic value? 349 if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { 350 const SubRegion *R = cast<SubRegion>(L->getRegion()); 351 while (R && !isa<SymbolicRegion>(R)) { 352 R = dyn_cast<SubRegion>(R->getSuperRegion()); 353 } 354 355 if (R) { 356 assert(isa<SymbolicRegion>(R)); 357 return new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); 358 } 359 } 360 361 return 0; 362} 363 364BugReporterVisitor * 365FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N, 366 const MemRegion *R) { 367 assert(R && "The memory region is null."); 368 369 const ProgramState *state = N->getState(); 370 SVal V = state->getSVal(R); 371 if (V.isUnknown()) 372 return 0; 373 374 return new FindLastStoreBRVisitor(V, R); 375} 376 377 378PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, 379 const ExplodedNode *PrevN, 380 BugReporterContext &BRC, 381 BugReport &BR) { 382 const PostStmt *P = N->getLocationAs<PostStmt>(); 383 if (!P) 384 return 0; 385 const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); 386 if (!ME) 387 return 0; 388 const Expr *Receiver = ME->getInstanceReceiver(); 389 if (!Receiver) 390 return 0; 391 const ProgramState *state = N->getState(); 392 const SVal &V = state->getSVal(Receiver); 393 const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); 394 if (!DV) 395 return 0; 396 state = state->assume(*DV, true); 397 if (state) 398 return 0; 399 400 // The receiver was nil, and hence the method was skipped. 401 // Register a BugReporterVisitor to issue a message telling us how 402 // the receiver was null. 403 BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver)); 404 // Issue a message saying that the method was skipped. 405 PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), 406 N->getLocationContext()); 407 return new PathDiagnosticEventPiece(L, "No method actually called " 408 "because the receiver is nil"); 409} 410 411// Registers every VarDecl inside a Stmt with a last store visitor. 412void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, 413 const Stmt *S) { 414 const ExplodedNode *N = BR.getErrorNode(); 415 std::deque<const Stmt *> WorkList; 416 WorkList.push_back(S); 417 418 while (!WorkList.empty()) { 419 const Stmt *Head = WorkList.front(); 420 WorkList.pop_front(); 421 422 const ProgramState *state = N->getState(); 423 ProgramStateManager &StateMgr = state->getStateManager(); 424 425 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) { 426 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 427 const VarRegion *R = 428 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); 429 430 // What did we load? 431 SVal V = state->getSVal(S); 432 433 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) { 434 // Register a new visitor with the BugReport. 435 BR.addVisitor(new FindLastStoreBRVisitor(V, R)); 436 } 437 } 438 } 439 440 for (Stmt::const_child_iterator I = Head->child_begin(); 441 I != Head->child_end(); ++I) 442 WorkList.push_back(*I); 443 } 444} 445 446//===----------------------------------------------------------------------===// 447// Visitor that tries to report interesting diagnostics from conditions. 448//===----------------------------------------------------------------------===// 449PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, 450 const ExplodedNode *Prev, 451 BugReporterContext &BRC, 452 BugReport &BR) { 453 454 const ProgramPoint &progPoint = N->getLocation(); 455 456 const ProgramState *CurrentState = N->getState(); 457 const ProgramState *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(), 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, N->getLocationContext()); 486 if (tag == tags.second) 487 return VisitTrueTest(cast<Expr>(PS->getStmt()), false, 488 BRC, N->getLocationContext()); 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 BugReporterContext &BRC) { 502 const Expr *Cond = 0; 503 504 switch (Term->getStmtClass()) { 505 default: 506 return 0; 507 case Stmt::IfStmtClass: 508 Cond = cast<IfStmt>(Term)->getCond(); 509 break; 510 case Stmt::ConditionalOperatorClass: 511 Cond = cast<ConditionalOperator>(Term)->getCond(); 512 break; 513 } 514 515 assert(Cond); 516 assert(srcBlk->succ_size() == 2); 517 const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; 518 return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), 519 tookTrue, BRC, N->getLocationContext()); 520} 521 522PathDiagnosticPiece * 523ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 524 bool tookTrue, 525 BugReporterContext &BRC, 526 const LocationContext *LC) { 527 528 const Expr *Ex = Cond; 529 530 while (true) { 531 Ex = Ex->IgnoreParens(); 532 switch (Ex->getStmtClass()) { 533 default: 534 return 0; 535 case Stmt::BinaryOperatorClass: 536 return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, LC); 537 case Stmt::DeclRefExprClass: 538 return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, LC); 539 case Stmt::UnaryOperatorClass: { 540 const UnaryOperator *UO = cast<UnaryOperator>(Ex); 541 if (UO->getOpcode() == UO_LNot) { 542 tookTrue = !tookTrue; 543 Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext()); 544 continue; 545 } 546 return 0; 547 } 548 } 549 } 550} 551 552bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out, 553 BugReporterContext &BRC) { 554 const Expr *OriginalExpr = Ex; 555 Ex = Ex->IgnoreParenCasts(); 556 557 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { 558 const bool quotes = isa<VarDecl>(DR->getDecl()); 559 if (quotes) 560 Out << '\''; 561 Out << DR->getDecl()->getDeclName().getAsString(); 562 if (quotes) 563 Out << '\''; 564 return quotes; 565 } 566 567 if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) { 568 QualType OriginalTy = OriginalExpr->getType(); 569 if (OriginalTy->isPointerType()) { 570 if (IL->getValue() == 0) { 571 Out << "null"; 572 return false; 573 } 574 } 575 else if (OriginalTy->isObjCObjectPointerType()) { 576 if (IL->getValue() == 0) { 577 Out << "nil"; 578 return false; 579 } 580 } 581 582 Out << IL->getValue(); 583 return false; 584 } 585 586 return false; 587} 588 589PathDiagnosticPiece * 590ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 591 const BinaryOperator *BExpr, 592 const bool tookTrue, 593 BugReporterContext &BRC, 594 const LocationContext *LC) { 595 596 bool shouldInvert = false; 597 598 llvm::SmallString<128> LhsString, RhsString; 599 { 600 llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); 601 const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC); 602 const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC); 603 604 shouldInvert = !isVarLHS && isVarRHS; 605 } 606 607 if (LhsString.empty() || RhsString.empty()) 608 return 0; 609 610 // Should we invert the strings if the LHS is not a variable name? 611 612 llvm::SmallString<256> buf; 613 llvm::raw_svector_ostream Out(buf); 614 Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is "; 615 616 // Do we need to invert the opcode? 617 BinaryOperator::Opcode Op = BExpr->getOpcode(); 618 619 if (shouldInvert) 620 switch (Op) { 621 default: break; 622 case BO_LT: Op = BO_GT; break; 623 case BO_GT: Op = BO_LT; break; 624 case BO_LE: Op = BO_GE; break; 625 case BO_GE: Op = BO_LE; break; 626 } 627 628 if (!tookTrue) 629 switch (Op) { 630 case BO_EQ: Op = BO_NE; break; 631 case BO_NE: Op = BO_EQ; break; 632 case BO_LT: Op = BO_GE; break; 633 case BO_GT: Op = BO_LE; break; 634 case BO_LE: Op = BO_GT; break; 635 case BO_GE: Op = BO_LT; break; 636 default: 637 return 0; 638 } 639 640 switch (BExpr->getOpcode()) { 641 case BO_EQ: 642 Out << "equal to "; 643 break; 644 case BO_NE: 645 Out << "not equal to "; 646 break; 647 default: 648 Out << BinaryOperator::getOpcodeStr(Op) << ' '; 649 break; 650 } 651 652 Out << (shouldInvert ? LhsString : RhsString); 653 654 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); 655 return new PathDiagnosticEventPiece(Loc, Out.str()); 656} 657 658PathDiagnosticPiece * 659ConditionBRVisitor::VisitTrueTest(const Expr *Cond, 660 const DeclRefExpr *DR, 661 const bool tookTrue, 662 BugReporterContext &BRC, 663 const LocationContext *LC) { 664 665 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); 666 if (!VD) 667 return 0; 668 669 llvm::SmallString<256> Buf; 670 llvm::raw_svector_ostream Out(Buf); 671 672 Out << "Assuming '"; 673 VD->getDeclName().printName(Out); 674 Out << "' is "; 675 676 QualType VDTy = VD->getType(); 677 678 if (VDTy->isPointerType()) 679 Out << (tookTrue ? "non-null" : "null"); 680 else if (VDTy->isObjCObjectPointerType()) 681 Out << (tookTrue ? "non-nil" : "nil"); 682 else if (VDTy->isScalarType()) 683 Out << (tookTrue ? "not equal to 0" : "0"); 684 else 685 return 0; 686 687 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); 688 return new PathDiagnosticEventPiece(Loc, Out.str()); 689} 690