Consumed.cpp revision 52f717eba7eff69c97d64de5e3669f4a5ee57d5c
1//===- Consumed.cpp --------------------------------------------*- 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// A intra-procedural analysis for checking consumed properties. This is based, 11// in part, on research on linear types. 12// 13//===----------------------------------------------------------------------===// 14 15#include "clang/AST/ASTContext.h" 16#include "clang/AST/Attr.h" 17#include "clang/AST/DeclCXX.h" 18#include "clang/AST/ExprCXX.h" 19#include "clang/AST/RecursiveASTVisitor.h" 20#include "clang/AST/StmtVisitor.h" 21#include "clang/AST/StmtCXX.h" 22#include "clang/AST/Type.h" 23#include "clang/Analysis/Analyses/PostOrderCFGView.h" 24#include "clang/Analysis/AnalysisContext.h" 25#include "clang/Analysis/CFG.h" 26#include "clang/Analysis/Analyses/Consumed.h" 27#include "clang/Basic/OperatorKinds.h" 28#include "clang/Basic/SourceLocation.h" 29#include "llvm/ADT/DenseMap.h" 30#include "llvm/ADT/SmallVector.h" 31#include "llvm/Support/Compiler.h" 32#include "llvm/Support/raw_ostream.h" 33 34// TODO: Use information from tests in while-loop conditional. 35// TODO: Add notes about the actual and expected state for 36// TODO: Correctly identify unreachable blocks when chaining boolean operators. 37// TODO: Adjust the parser and AttributesList class to support lists of 38// identifiers. 39// TODO: Warn about unreachable code. 40// TODO: Switch to using a bitmap to track unreachable blocks. 41// TODO: Handle variable definitions, e.g. bool valid = x.isValid(); 42// if (valid) ...; (Deferred) 43// TODO: Take notes on state transitions to provide better warning messages. 44// (Deferred) 45// TODO: Test nested conditionals: A) Checking the same value multiple times, 46// and 2) Checking different values. (Deferred) 47 48using namespace clang; 49using namespace consumed; 50 51// Key method definition 52ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {} 53 54static SourceLocation getFirstStmtLoc(const CFGBlock *Block) { 55 // Find the source location of the first statement in the block, if the block 56 // is not empty. 57 for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end(); 58 BI != BE; ++BI) { 59 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) 60 return CS->getStmt()->getLocStart(); 61 } 62 63 // Block is empty. 64 // If we have one successor, return the first statement in that block 65 if (Block->succ_size() == 1 && *Block->succ_begin()) 66 return getFirstStmtLoc(*Block->succ_begin()); 67 68 return SourceLocation(); 69} 70 71static SourceLocation getLastStmtLoc(const CFGBlock *Block) { 72 // Find the source location of the last statement in the block, if the block 73 // is not empty. 74 if (const Stmt *StmtNode = Block->getTerminator()) { 75 return StmtNode->getLocStart(); 76 } else { 77 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(), 78 BE = Block->rend(); BI != BE; ++BI) { 79 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) 80 return CS->getStmt()->getLocStart(); 81 } 82 } 83 84 // If we have one successor, return the first statement in that block 85 SourceLocation Loc; 86 if (Block->succ_size() == 1 && *Block->succ_begin()) 87 Loc = getFirstStmtLoc(*Block->succ_begin()); 88 if (Loc.isValid()) 89 return Loc; 90 91 // If we have one predecessor, return the last statement in that block 92 if (Block->pred_size() == 1 && *Block->pred_begin()) 93 return getLastStmtLoc(*Block->pred_begin()); 94 95 return Loc; 96} 97 98static ConsumedState invertConsumedUnconsumed(ConsumedState State) { 99 switch (State) { 100 case CS_Unconsumed: 101 return CS_Consumed; 102 case CS_Consumed: 103 return CS_Unconsumed; 104 case CS_None: 105 return CS_None; 106 case CS_Unknown: 107 return CS_Unknown; 108 } 109 llvm_unreachable("invalid enum"); 110} 111 112static bool isCallableInState(const CallableWhenAttr *CWAttr, 113 ConsumedState State) { 114 115 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(), 116 E = CWAttr->callableState_end(); 117 118 for (; I != E; ++I) { 119 120 ConsumedState MappedAttrState = CS_None; 121 122 switch (*I) { 123 case CallableWhenAttr::Unknown: 124 MappedAttrState = CS_Unknown; 125 break; 126 127 case CallableWhenAttr::Unconsumed: 128 MappedAttrState = CS_Unconsumed; 129 break; 130 131 case CallableWhenAttr::Consumed: 132 MappedAttrState = CS_Consumed; 133 break; 134 } 135 136 if (MappedAttrState == State) 137 return true; 138 } 139 140 return false; 141} 142 143static bool isConsumableType(const QualType &QT) { 144 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) 145 return RD->hasAttr<ConsumableAttr>(); 146 else 147 return false; 148} 149 150static bool isKnownState(ConsumedState State) { 151 switch (State) { 152 case CS_Unconsumed: 153 case CS_Consumed: 154 return true; 155 case CS_None: 156 case CS_Unknown: 157 return false; 158 } 159 llvm_unreachable("invalid enum"); 160} 161 162static bool isTestingFunction(const FunctionDecl *FunDecl) { 163 return FunDecl->hasAttr<TestsTypestateAttr>(); 164} 165 166static ConsumedState mapConsumableAttrState(const QualType QT) { 167 assert(isConsumableType(QT)); 168 169 const ConsumableAttr *CAttr = 170 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>(); 171 172 switch (CAttr->getDefaultState()) { 173 case ConsumableAttr::Unknown: 174 return CS_Unknown; 175 case ConsumableAttr::Unconsumed: 176 return CS_Unconsumed; 177 case ConsumableAttr::Consumed: 178 return CS_Consumed; 179 } 180 llvm_unreachable("invalid enum"); 181} 182 183static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) { 184 switch (STAttr->getNewState()) { 185 case SetTypestateAttr::Unknown: 186 return CS_Unknown; 187 case SetTypestateAttr::Unconsumed: 188 return CS_Unconsumed; 189 case SetTypestateAttr::Consumed: 190 return CS_Consumed; 191 } 192 llvm_unreachable("invalid_enum"); 193} 194 195static ConsumedState 196mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) { 197 switch (RTSAttr->getState()) { 198 case ReturnTypestateAttr::Unknown: 199 return CS_Unknown; 200 case ReturnTypestateAttr::Unconsumed: 201 return CS_Unconsumed; 202 case ReturnTypestateAttr::Consumed: 203 return CS_Consumed; 204 } 205 llvm_unreachable("invalid enum"); 206} 207 208static StringRef stateToString(ConsumedState State) { 209 switch (State) { 210 case consumed::CS_None: 211 return "none"; 212 213 case consumed::CS_Unknown: 214 return "unknown"; 215 216 case consumed::CS_Unconsumed: 217 return "unconsumed"; 218 219 case consumed::CS_Consumed: 220 return "consumed"; 221 } 222 llvm_unreachable("invalid enum"); 223} 224 225static ConsumedState testsFor(const FunctionDecl *FunDecl) { 226 assert(isTestingFunction(FunDecl)); 227 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) { 228 case TestsTypestateAttr::Unconsumed: 229 return CS_Unconsumed; 230 case TestsTypestateAttr::Consumed: 231 return CS_Consumed; 232 } 233 llvm_unreachable("invalid enum"); 234} 235 236namespace { 237struct VarTestResult { 238 const VarDecl *Var; 239 ConsumedState TestsFor; 240}; 241} // end anonymous::VarTestResult 242 243namespace clang { 244namespace consumed { 245 246enum EffectiveOp { 247 EO_And, 248 EO_Or 249}; 250 251class PropagationInfo { 252 enum { 253 IT_None, 254 IT_State, 255 IT_Test, 256 IT_BinTest, 257 IT_Var 258 } InfoType; 259 260 struct BinTestTy { 261 const BinaryOperator *Source; 262 EffectiveOp EOp; 263 VarTestResult LTest; 264 VarTestResult RTest; 265 }; 266 267 union { 268 ConsumedState State; 269 VarTestResult Test; 270 const VarDecl *Var; 271 BinTestTy BinTest; 272 }; 273 274 QualType TempType; 275 276public: 277 PropagationInfo() : InfoType(IT_None) {} 278 279 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {} 280 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor) 281 : InfoType(IT_Test) { 282 283 Test.Var = Var; 284 Test.TestsFor = TestsFor; 285 } 286 287 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, 288 const VarTestResult <est, const VarTestResult &RTest) 289 : InfoType(IT_BinTest) { 290 291 BinTest.Source = Source; 292 BinTest.EOp = EOp; 293 BinTest.LTest = LTest; 294 BinTest.RTest = RTest; 295 } 296 297 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, 298 const VarDecl *LVar, ConsumedState LTestsFor, 299 const VarDecl *RVar, ConsumedState RTestsFor) 300 : InfoType(IT_BinTest) { 301 302 BinTest.Source = Source; 303 BinTest.EOp = EOp; 304 BinTest.LTest.Var = LVar; 305 BinTest.LTest.TestsFor = LTestsFor; 306 BinTest.RTest.Var = RVar; 307 BinTest.RTest.TestsFor = RTestsFor; 308 } 309 310 PropagationInfo(ConsumedState State, QualType TempType) 311 : InfoType(IT_State), State(State), TempType(TempType) {} 312 313 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {} 314 315 const ConsumedState & getState() const { 316 assert(InfoType == IT_State); 317 return State; 318 } 319 320 const QualType & getTempType() const { 321 assert(InfoType == IT_State); 322 return TempType; 323 } 324 325 const VarTestResult & getTest() const { 326 assert(InfoType == IT_Test); 327 return Test; 328 } 329 330 const VarTestResult & getLTest() const { 331 assert(InfoType == IT_BinTest); 332 return BinTest.LTest; 333 } 334 335 const VarTestResult & getRTest() const { 336 assert(InfoType == IT_BinTest); 337 return BinTest.RTest; 338 } 339 340 const VarDecl * getVar() const { 341 assert(InfoType == IT_Var); 342 return Var; 343 } 344 345 EffectiveOp testEffectiveOp() const { 346 assert(InfoType == IT_BinTest); 347 return BinTest.EOp; 348 } 349 350 const BinaryOperator * testSourceNode() const { 351 assert(InfoType == IT_BinTest); 352 return BinTest.Source; 353 } 354 355 bool isValid() const { return InfoType != IT_None; } 356 bool isState() const { return InfoType == IT_State; } 357 bool isTest() const { return InfoType == IT_Test; } 358 bool isBinTest() const { return InfoType == IT_BinTest; } 359 bool isVar() const { return InfoType == IT_Var; } 360 361 PropagationInfo invertTest() const { 362 assert(InfoType == IT_Test || InfoType == IT_BinTest); 363 364 if (InfoType == IT_Test) { 365 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor)); 366 367 } else if (InfoType == IT_BinTest) { 368 return PropagationInfo(BinTest.Source, 369 BinTest.EOp == EO_And ? EO_Or : EO_And, 370 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor), 371 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor)); 372 } else { 373 return PropagationInfo(); 374 } 375 } 376}; 377 378class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> { 379 380 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType; 381 typedef std::pair<const Stmt *, PropagationInfo> PairType; 382 typedef MapType::iterator InfoEntry; 383 typedef MapType::const_iterator ConstInfoEntry; 384 385 AnalysisDeclContext &AC; 386 ConsumedAnalyzer &Analyzer; 387 ConsumedStateMap *StateMap; 388 MapType PropagationMap; 389 void forwardInfo(const Stmt *From, const Stmt *To); 390 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl); 391 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun, 392 QualType ReturnType); 393 394public: 395 void checkCallability(const PropagationInfo &PInfo, 396 const FunctionDecl *FunDecl, 397 SourceLocation BlameLoc); 398 399 void Visit(const Stmt *StmtNode); 400 401 void VisitBinaryOperator(const BinaryOperator *BinOp); 402 void VisitCallExpr(const CallExpr *Call); 403 void VisitCastExpr(const CastExpr *Cast); 404 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp); 405 void VisitCXXConstructExpr(const CXXConstructExpr *Call); 406 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call); 407 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call); 408 void VisitDeclRefExpr(const DeclRefExpr *DeclRef); 409 void VisitDeclStmt(const DeclStmt *DelcS); 410 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp); 411 void VisitMemberExpr(const MemberExpr *MExpr); 412 void VisitParmVarDecl(const ParmVarDecl *Param); 413 void VisitReturnStmt(const ReturnStmt *Ret); 414 void VisitUnaryOperator(const UnaryOperator *UOp); 415 void VisitVarDecl(const VarDecl *Var); 416 417 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer, 418 ConsumedStateMap *StateMap) 419 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {} 420 421 PropagationInfo getInfo(const Stmt *StmtNode) const { 422 ConstInfoEntry Entry = PropagationMap.find(StmtNode); 423 424 if (Entry != PropagationMap.end()) 425 return Entry->second; 426 else 427 return PropagationInfo(); 428 } 429 430 void reset(ConsumedStateMap *NewStateMap) { 431 StateMap = NewStateMap; 432 } 433}; 434 435void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo, 436 const FunctionDecl *FunDecl, 437 SourceLocation BlameLoc) { 438 439 if (!FunDecl->hasAttr<CallableWhenAttr>()) 440 return; 441 442 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>(); 443 444 if (PInfo.isVar()) { 445 const VarDecl *Var = PInfo.getVar(); 446 ConsumedState VarState = StateMap->getState(Var); 447 448 assert(VarState != CS_None && "Invalid state"); 449 450 if (isCallableInState(CWAttr, VarState)) 451 return; 452 453 Analyzer.WarningsHandler.warnUseInInvalidState( 454 FunDecl->getNameAsString(), Var->getNameAsString(), 455 stateToString(VarState), BlameLoc); 456 457 } else if (PInfo.isState()) { 458 459 assert(PInfo.getState() != CS_None && "Invalid state"); 460 461 if (isCallableInState(CWAttr, PInfo.getState())) 462 return; 463 464 Analyzer.WarningsHandler.warnUseOfTempInInvalidState( 465 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc); 466 } 467} 468 469void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) { 470 InfoEntry Entry = PropagationMap.find(From); 471 472 if (Entry != PropagationMap.end()) 473 PropagationMap.insert(PairType(To, Entry->second)); 474} 475 476bool ConsumedStmtVisitor::isLikeMoveAssignment( 477 const CXXMethodDecl *MethodDecl) { 478 479 return MethodDecl->isMoveAssignmentOperator() || 480 (MethodDecl->getOverloadedOperator() == OO_Equal && 481 MethodDecl->getNumParams() == 1 && 482 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType()); 483} 484 485void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call, 486 const FunctionDecl *Fun, 487 QualType ReturnType) { 488 if (isConsumableType(ReturnType)) { 489 490 ConsumedState ReturnState; 491 492 if (Fun->hasAttr<ReturnTypestateAttr>()) 493 ReturnState = mapReturnTypestateAttrState( 494 Fun->getAttr<ReturnTypestateAttr>()); 495 else 496 ReturnState = mapConsumableAttrState(ReturnType); 497 498 PropagationMap.insert(PairType(Call, 499 PropagationInfo(ReturnState, ReturnType))); 500 } 501} 502 503void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) { 504 505 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode); 506 507 for (Stmt::const_child_iterator CI = StmtNode->child_begin(), 508 CE = StmtNode->child_end(); CI != CE; ++CI) { 509 510 PropagationMap.erase(*CI); 511 } 512} 513 514void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) { 515 switch (BinOp->getOpcode()) { 516 case BO_LAnd: 517 case BO_LOr : { 518 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()), 519 REntry = PropagationMap.find(BinOp->getRHS()); 520 521 VarTestResult LTest, RTest; 522 523 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) { 524 LTest = LEntry->second.getTest(); 525 526 } else { 527 LTest.Var = NULL; 528 LTest.TestsFor = CS_None; 529 } 530 531 if (REntry != PropagationMap.end() && REntry->second.isTest()) { 532 RTest = REntry->second.getTest(); 533 534 } else { 535 RTest.Var = NULL; 536 RTest.TestsFor = CS_None; 537 } 538 539 if (!(LTest.Var == NULL && RTest.Var == NULL)) 540 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp, 541 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest))); 542 543 break; 544 } 545 546 case BO_PtrMemD: 547 case BO_PtrMemI: 548 forwardInfo(BinOp->getLHS(), BinOp); 549 break; 550 551 default: 552 break; 553 } 554} 555 556void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) { 557 if (const FunctionDecl *FunDecl = 558 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) { 559 560 // Special case for the std::move function. 561 // TODO: Make this more specific. (Deferred) 562 if (FunDecl->getNameAsString() == "move") { 563 InfoEntry Entry = PropagationMap.find(Call->getArg(0)); 564 565 if (Entry != PropagationMap.end()) { 566 PropagationMap.insert(PairType(Call, Entry->second)); 567 } 568 569 return; 570 } 571 572 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams(); 573 574 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) { 575 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType(); 576 577 InfoEntry Entry = PropagationMap.find(Call->getArg(Index)); 578 579 if (Entry == PropagationMap.end() || !Entry->second.isVar()) { 580 continue; 581 } 582 583 PropagationInfo PInfo = Entry->second; 584 585 if (ParamType->isRValueReferenceType() || 586 (ParamType->isLValueReferenceType() && 587 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) { 588 589 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed); 590 591 } else if (!(ParamType.isConstQualified() || 592 ((ParamType->isReferenceType() || 593 ParamType->isPointerType()) && 594 ParamType->getPointeeType().isConstQualified()))) { 595 596 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown); 597 } 598 } 599 600 QualType RetType = FunDecl->getCallResultType(); 601 if (RetType->isReferenceType()) 602 RetType = RetType->getPointeeType(); 603 604 propagateReturnType(Call, FunDecl, RetType); 605 } 606} 607 608void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) { 609 forwardInfo(Cast->getSubExpr(), Cast); 610} 611 612void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr( 613 const CXXBindTemporaryExpr *Temp) { 614 615 forwardInfo(Temp->getSubExpr(), Temp); 616} 617 618void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) { 619 CXXConstructorDecl *Constructor = Call->getConstructor(); 620 621 ASTContext &CurrContext = AC.getASTContext(); 622 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType(); 623 624 if (isConsumableType(ThisType)) { 625 if (Constructor->isDefaultConstructor()) { 626 627 PropagationMap.insert(PairType(Call, 628 PropagationInfo(consumed::CS_Consumed, ThisType))); 629 630 } else if (Constructor->isMoveConstructor()) { 631 632 PropagationInfo PInfo = 633 PropagationMap.find(Call->getArg(0))->second; 634 635 if (PInfo.isVar()) { 636 const VarDecl* Var = PInfo.getVar(); 637 638 PropagationMap.insert(PairType(Call, 639 PropagationInfo(StateMap->getState(Var), ThisType))); 640 641 StateMap->setState(Var, consumed::CS_Consumed); 642 643 } else { 644 PropagationMap.insert(PairType(Call, PInfo)); 645 } 646 647 } else if (Constructor->isCopyConstructor()) { 648 MapType::iterator Entry = PropagationMap.find(Call->getArg(0)); 649 650 if (Entry != PropagationMap.end()) 651 PropagationMap.insert(PairType(Call, Entry->second)); 652 653 } else { 654 propagateReturnType(Call, Constructor, ThisType); 655 } 656 } 657} 658 659 660void ConsumedStmtVisitor::VisitCXXMemberCallExpr( 661 const CXXMemberCallExpr *Call) { 662 663 VisitCallExpr(Call); 664 665 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens()); 666 667 if (Entry != PropagationMap.end()) { 668 PropagationInfo PInfo = Entry->second; 669 const CXXMethodDecl *MethodDecl = Call->getMethodDecl(); 670 671 checkCallability(PInfo, MethodDecl, Call->getExprLoc()); 672 673 if (PInfo.isVar()) { 674 if (isTestingFunction(MethodDecl)) 675 PropagationMap.insert(PairType(Call, 676 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl)))); 677 else if (MethodDecl->hasAttr<SetTypestateAttr>()) 678 StateMap->setState(PInfo.getVar(), 679 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>())); 680 } 681 } 682} 683 684void ConsumedStmtVisitor::VisitCXXOperatorCallExpr( 685 const CXXOperatorCallExpr *Call) { 686 687 const FunctionDecl *FunDecl = 688 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee()); 689 690 if (!FunDecl) return; 691 692 if (isa<CXXMethodDecl>(FunDecl) && 693 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) { 694 695 InfoEntry LEntry = PropagationMap.find(Call->getArg(0)); 696 InfoEntry REntry = PropagationMap.find(Call->getArg(1)); 697 698 PropagationInfo LPInfo, RPInfo; 699 700 if (LEntry != PropagationMap.end() && 701 REntry != PropagationMap.end()) { 702 703 LPInfo = LEntry->second; 704 RPInfo = REntry->second; 705 706 if (LPInfo.isVar() && RPInfo.isVar()) { 707 StateMap->setState(LPInfo.getVar(), 708 StateMap->getState(RPInfo.getVar())); 709 710 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed); 711 712 PropagationMap.insert(PairType(Call, LPInfo)); 713 714 } else if (LPInfo.isVar() && !RPInfo.isVar()) { 715 StateMap->setState(LPInfo.getVar(), RPInfo.getState()); 716 717 PropagationMap.insert(PairType(Call, LPInfo)); 718 719 } else if (!LPInfo.isVar() && RPInfo.isVar()) { 720 PropagationMap.insert(PairType(Call, 721 PropagationInfo(StateMap->getState(RPInfo.getVar()), 722 LPInfo.getTempType()))); 723 724 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed); 725 726 } else { 727 PropagationMap.insert(PairType(Call, RPInfo)); 728 } 729 730 } else if (LEntry != PropagationMap.end() && 731 REntry == PropagationMap.end()) { 732 733 LPInfo = LEntry->second; 734 735 if (LPInfo.isVar()) { 736 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown); 737 738 PropagationMap.insert(PairType(Call, LPInfo)); 739 740 } else if (LPInfo.isState()) { 741 PropagationMap.insert(PairType(Call, 742 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType()))); 743 } 744 745 } else if (LEntry == PropagationMap.end() && 746 REntry != PropagationMap.end()) { 747 748 if (REntry->second.isVar()) 749 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed); 750 } 751 752 } else { 753 754 VisitCallExpr(Call); 755 756 InfoEntry Entry = PropagationMap.find(Call->getArg(0)); 757 758 if (Entry != PropagationMap.end()) { 759 PropagationInfo PInfo = Entry->second; 760 761 checkCallability(PInfo, FunDecl, Call->getExprLoc()); 762 763 if (PInfo.isVar()) { 764 if (isTestingFunction(FunDecl)) 765 PropagationMap.insert(PairType(Call, 766 PropagationInfo(PInfo.getVar(), testsFor(FunDecl)))); 767 else if (FunDecl->hasAttr<SetTypestateAttr>()) 768 StateMap->setState(PInfo.getVar(), 769 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>())); 770 } 771 } 772 } 773} 774 775void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) { 776 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) 777 if (StateMap->getState(Var) != consumed::CS_None) 778 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var))); 779} 780 781void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) { 782 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(), 783 DE = DeclS->decl_end(); DI != DE; ++DI) { 784 785 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI)); 786 } 787 788 if (DeclS->isSingleDecl()) 789 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl())) 790 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var))); 791} 792 793void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr( 794 const MaterializeTemporaryExpr *Temp) { 795 796 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr()); 797 798 if (Entry != PropagationMap.end()) 799 PropagationMap.insert(PairType(Temp, Entry->second)); 800} 801 802void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) { 803 forwardInfo(MExpr->getBase(), MExpr); 804} 805 806 807void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) { 808 QualType ParamType = Param->getType(); 809 ConsumedState ParamState = consumed::CS_None; 810 811 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) && 812 isConsumableType(ParamType)) 813 ParamState = mapConsumableAttrState(ParamType); 814 else if (ParamType->isReferenceType() && 815 isConsumableType(ParamType->getPointeeType())) 816 ParamState = consumed::CS_Unknown; 817 818 if (ParamState) 819 StateMap->setState(Param, ParamState); 820} 821 822void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) { 823 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) { 824 InfoEntry Entry = PropagationMap.find(Ret->getRetValue()); 825 826 if (Entry != PropagationMap.end()) { 827 assert(Entry->second.isState() || Entry->second.isVar()); 828 829 ConsumedState RetState = Entry->second.isState() ? 830 Entry->second.getState() : StateMap->getState(Entry->second.getVar()); 831 832 if (RetState != ExpectedState) 833 Analyzer.WarningsHandler.warnReturnTypestateMismatch( 834 Ret->getReturnLoc(), stateToString(ExpectedState), 835 stateToString(RetState)); 836 } 837 } 838} 839 840void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) { 841 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens()); 842 if (Entry == PropagationMap.end()) return; 843 844 switch (UOp->getOpcode()) { 845 case UO_AddrOf: 846 PropagationMap.insert(PairType(UOp, Entry->second)); 847 break; 848 849 case UO_LNot: 850 if (Entry->second.isTest() || Entry->second.isBinTest()) 851 PropagationMap.insert(PairType(UOp, Entry->second.invertTest())); 852 break; 853 854 default: 855 break; 856 } 857} 858 859// TODO: See if I need to check for reference types here. 860void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) { 861 if (isConsumableType(Var->getType())) { 862 if (Var->hasInit()) { 863 PropagationInfo PInfo = 864 PropagationMap.find(Var->getInit())->second; 865 866 StateMap->setState(Var, PInfo.isVar() ? 867 StateMap->getState(PInfo.getVar()) : PInfo.getState()); 868 869 } else { 870 StateMap->setState(Var, consumed::CS_Unknown); 871 } 872 } 873} 874}} // end clang::consumed::ConsumedStmtVisitor 875 876namespace clang { 877namespace consumed { 878 879void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, 880 ConsumedStateMap *ThenStates, 881 ConsumedStateMap *ElseStates) { 882 883 ConsumedState VarState = ThenStates->getState(Test.Var); 884 885 if (VarState == CS_Unknown) { 886 ThenStates->setState(Test.Var, Test.TestsFor); 887 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor)); 888 889 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) { 890 ThenStates->markUnreachable(); 891 892 } else if (VarState == Test.TestsFor) { 893 ElseStates->markUnreachable(); 894 } 895} 896 897void splitVarStateForIfBinOp(const PropagationInfo &PInfo, 898 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) { 899 900 const VarTestResult <est = PInfo.getLTest(), 901 &RTest = PInfo.getRTest(); 902 903 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None, 904 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None; 905 906 if (LTest.Var) { 907 if (PInfo.testEffectiveOp() == EO_And) { 908 if (LState == CS_Unknown) { 909 ThenStates->setState(LTest.Var, LTest.TestsFor); 910 911 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) { 912 ThenStates->markUnreachable(); 913 914 } else if (LState == LTest.TestsFor && isKnownState(RState)) { 915 if (RState == RTest.TestsFor) 916 ElseStates->markUnreachable(); 917 else 918 ThenStates->markUnreachable(); 919 } 920 921 } else { 922 if (LState == CS_Unknown) { 923 ElseStates->setState(LTest.Var, 924 invertConsumedUnconsumed(LTest.TestsFor)); 925 926 } else if (LState == LTest.TestsFor) { 927 ElseStates->markUnreachable(); 928 929 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) && 930 isKnownState(RState)) { 931 932 if (RState == RTest.TestsFor) 933 ElseStates->markUnreachable(); 934 else 935 ThenStates->markUnreachable(); 936 } 937 } 938 } 939 940 if (RTest.Var) { 941 if (PInfo.testEffectiveOp() == EO_And) { 942 if (RState == CS_Unknown) 943 ThenStates->setState(RTest.Var, RTest.TestsFor); 944 else if (RState == invertConsumedUnconsumed(RTest.TestsFor)) 945 ThenStates->markUnreachable(); 946 947 } else { 948 if (RState == CS_Unknown) 949 ElseStates->setState(RTest.Var, 950 invertConsumedUnconsumed(RTest.TestsFor)); 951 else if (RState == RTest.TestsFor) 952 ElseStates->markUnreachable(); 953 } 954 } 955} 956 957bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock, 958 const CFGBlock *TargetBlock) { 959 960 assert(CurrBlock && "Block pointer must not be NULL"); 961 assert(TargetBlock && "TargetBlock pointer must not be NULL"); 962 963 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()]; 964 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(), 965 PE = TargetBlock->pred_end(); PI != PE; ++PI) { 966 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] ) 967 return false; 968 } 969 return true; 970} 971 972void ConsumedBlockInfo::addInfo(const CFGBlock *Block, 973 ConsumedStateMap *StateMap, 974 bool &AlreadyOwned) { 975 976 assert(Block && "Block pointer must not be NULL"); 977 978 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 979 980 if (Entry) { 981 Entry->intersect(StateMap); 982 983 } else if (AlreadyOwned) { 984 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap); 985 986 } else { 987 StateMapsArray[Block->getBlockID()] = StateMap; 988 AlreadyOwned = true; 989 } 990} 991 992void ConsumedBlockInfo::addInfo(const CFGBlock *Block, 993 ConsumedStateMap *StateMap) { 994 995 assert(Block != NULL && "Block pointer must not be NULL"); 996 997 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 998 999 if (Entry) { 1000 Entry->intersect(StateMap); 1001 delete StateMap; 1002 1003 } else { 1004 StateMapsArray[Block->getBlockID()] = StateMap; 1005 } 1006} 1007 1008ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) { 1009 assert(Block && "Block pointer must not be NULL"); 1010 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info"); 1011 1012 return StateMapsArray[Block->getBlockID()]; 1013} 1014 1015void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) { 1016 unsigned int BlockID = Block->getBlockID(); 1017 delete StateMapsArray[BlockID]; 1018 StateMapsArray[BlockID] = NULL; 1019} 1020 1021ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) { 1022 assert(Block && "Block pointer must not be NULL"); 1023 1024 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()]; 1025 if (isBackEdgeTarget(Block)) { 1026 return new ConsumedStateMap(*StateMap); 1027 } else { 1028 StateMapsArray[Block->getBlockID()] = NULL; 1029 return StateMap; 1030 } 1031} 1032 1033bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) { 1034 assert(From && "From block must not be NULL"); 1035 assert(To && "From block must not be NULL"); 1036 1037 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()]; 1038} 1039 1040bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) { 1041 assert(Block != NULL && "Block pointer must not be NULL"); 1042 1043 // Anything with less than two predecessors can't be the target of a back 1044 // edge. 1045 if (Block->pred_size() < 2) 1046 return false; 1047 1048 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()]; 1049 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(), 1050 PE = Block->pred_end(); PI != PE; ++PI) { 1051 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()]) 1052 return true; 1053 } 1054 return false; 1055} 1056 1057ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const { 1058 MapType::const_iterator Entry = Map.find(Var); 1059 1060 if (Entry != Map.end()) { 1061 return Entry->second; 1062 1063 } else { 1064 return CS_None; 1065 } 1066} 1067 1068void ConsumedStateMap::intersect(const ConsumedStateMap *Other) { 1069 ConsumedState LocalState; 1070 1071 if (this->From && this->From == Other->From && !Other->Reachable) { 1072 this->markUnreachable(); 1073 return; 1074 } 1075 1076 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end(); 1077 DMI != DME; ++DMI) { 1078 1079 LocalState = this->getState(DMI->first); 1080 1081 if (LocalState == CS_None) 1082 continue; 1083 1084 if (LocalState != DMI->second) 1085 Map[DMI->first] = CS_Unknown; 1086 } 1087} 1088 1089void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead, 1090 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates, 1091 ConsumedWarningsHandlerBase &WarningsHandler) { 1092 1093 ConsumedState LocalState; 1094 SourceLocation BlameLoc = getLastStmtLoc(LoopBack); 1095 1096 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(), 1097 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) { 1098 1099 LocalState = this->getState(DMI->first); 1100 1101 if (LocalState == CS_None) 1102 continue; 1103 1104 if (LocalState != DMI->second) { 1105 Map[DMI->first] = CS_Unknown; 1106 WarningsHandler.warnLoopStateMismatch( 1107 BlameLoc, DMI->first->getNameAsString()); 1108 } 1109 } 1110} 1111 1112void ConsumedStateMap::markUnreachable() { 1113 this->Reachable = false; 1114 Map.clear(); 1115} 1116 1117void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) { 1118 Map[Var] = State; 1119} 1120 1121void ConsumedStateMap::remove(const VarDecl *Var) { 1122 Map.erase(Var); 1123} 1124 1125bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const { 1126 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end(); 1127 DMI != DME; ++DMI) { 1128 1129 if (this->getState(DMI->first) != DMI->second) 1130 return true; 1131 } 1132 1133 return false; 1134} 1135 1136void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC, 1137 const FunctionDecl *D) { 1138 QualType ReturnType; 1139 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { 1140 ASTContext &CurrContext = AC.getASTContext(); 1141 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType(); 1142 } else 1143 ReturnType = D->getCallResultType(); 1144 1145 if (D->hasAttr<ReturnTypestateAttr>()) { 1146 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>(); 1147 1148 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); 1149 if (!RD || !RD->hasAttr<ConsumableAttr>()) { 1150 // FIXME: This should be removed when template instantiation propagates 1151 // attributes at template specialization definition, not 1152 // declaration. When it is removed the test needs to be enabled 1153 // in SemaDeclAttr.cpp. 1154 WarningsHandler.warnReturnTypestateForUnconsumableType( 1155 RTSAttr->getLocation(), ReturnType.getAsString()); 1156 ExpectedReturnState = CS_None; 1157 } else 1158 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr); 1159 } else if (isConsumableType(ReturnType)) 1160 ExpectedReturnState = mapConsumableAttrState(ReturnType); 1161 else 1162 ExpectedReturnState = CS_None; 1163} 1164 1165bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock, 1166 const ConsumedStmtVisitor &Visitor) { 1167 1168 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates); 1169 PropagationInfo PInfo; 1170 1171 if (const IfStmt *IfNode = 1172 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) { 1173 1174 const Stmt *Cond = IfNode->getCond(); 1175 1176 PInfo = Visitor.getInfo(Cond); 1177 if (!PInfo.isValid() && isa<BinaryOperator>(Cond)) 1178 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS()); 1179 1180 if (PInfo.isTest()) { 1181 CurrStates->setSource(Cond); 1182 FalseStates->setSource(Cond); 1183 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates); 1184 1185 } else if (PInfo.isBinTest()) { 1186 CurrStates->setSource(PInfo.testSourceNode()); 1187 FalseStates->setSource(PInfo.testSourceNode()); 1188 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates); 1189 1190 } else { 1191 delete FalseStates; 1192 return false; 1193 } 1194 1195 } else if (const BinaryOperator *BinOp = 1196 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) { 1197 1198 PInfo = Visitor.getInfo(BinOp->getLHS()); 1199 if (!PInfo.isTest()) { 1200 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) { 1201 PInfo = Visitor.getInfo(BinOp->getRHS()); 1202 1203 if (!PInfo.isTest()) { 1204 delete FalseStates; 1205 return false; 1206 } 1207 1208 } else { 1209 delete FalseStates; 1210 return false; 1211 } 1212 } 1213 1214 CurrStates->setSource(BinOp); 1215 FalseStates->setSource(BinOp); 1216 1217 const VarTestResult &Test = PInfo.getTest(); 1218 ConsumedState VarState = CurrStates->getState(Test.Var); 1219 1220 if (BinOp->getOpcode() == BO_LAnd) { 1221 if (VarState == CS_Unknown) 1222 CurrStates->setState(Test.Var, Test.TestsFor); 1223 else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) 1224 CurrStates->markUnreachable(); 1225 1226 } else if (BinOp->getOpcode() == BO_LOr) { 1227 if (VarState == CS_Unknown) 1228 FalseStates->setState(Test.Var, 1229 invertConsumedUnconsumed(Test.TestsFor)); 1230 else if (VarState == Test.TestsFor) 1231 FalseStates->markUnreachable(); 1232 } 1233 1234 } else { 1235 delete FalseStates; 1236 return false; 1237 } 1238 1239 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(); 1240 1241 if (*SI) 1242 BlockInfo.addInfo(*SI, CurrStates); 1243 else 1244 delete CurrStates; 1245 1246 if (*++SI) 1247 BlockInfo.addInfo(*SI, FalseStates); 1248 else 1249 delete FalseStates; 1250 1251 CurrStates = NULL; 1252 return true; 1253} 1254 1255void ConsumedAnalyzer::run(AnalysisDeclContext &AC) { 1256 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl()); 1257 if (!D) 1258 return; 1259 1260 CFG *CFGraph = AC.getCFG(); 1261 if (!CFGraph) 1262 return; 1263 1264 determineExpectedReturnState(AC, D); 1265 1266 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>(); 1267 // AC.getCFG()->viewCFG(LangOptions()); 1268 1269 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph); 1270 1271 CurrStates = new ConsumedStateMap(); 1272 ConsumedStmtVisitor Visitor(AC, *this, CurrStates); 1273 1274 // Add all trackable parameters to the state map. 1275 for (FunctionDecl::param_const_iterator PI = D->param_begin(), 1276 PE = D->param_end(); PI != PE; ++PI) { 1277 Visitor.VisitParmVarDecl(*PI); 1278 } 1279 1280 // Visit all of the function's basic blocks. 1281 for (PostOrderCFGView::iterator I = SortedGraph->begin(), 1282 E = SortedGraph->end(); I != E; ++I) { 1283 1284 const CFGBlock *CurrBlock = *I; 1285 1286 if (CurrStates == NULL) 1287 CurrStates = BlockInfo.getInfo(CurrBlock); 1288 1289 if (!CurrStates) { 1290 continue; 1291 1292 } else if (!CurrStates->isReachable()) { 1293 delete CurrStates; 1294 CurrStates = NULL; 1295 continue; 1296 } 1297 1298 Visitor.reset(CurrStates); 1299 1300 // Visit all of the basic block's statements. 1301 for (CFGBlock::const_iterator BI = CurrBlock->begin(), 1302 BE = CurrBlock->end(); BI != BE; ++BI) { 1303 1304 switch (BI->getKind()) { 1305 case CFGElement::Statement: 1306 Visitor.Visit(BI->castAs<CFGStmt>().getStmt()); 1307 break; 1308 1309 case CFGElement::TemporaryDtor: { 1310 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>(); 1311 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr(); 1312 PropagationInfo PInfo = Visitor.getInfo(BTE); 1313 1314 if (PInfo.isValid()) 1315 Visitor.checkCallability(PInfo, 1316 DTor.getDestructorDecl(AC.getASTContext()), 1317 BTE->getExprLoc()); 1318 break; 1319 } 1320 1321 case CFGElement::AutomaticObjectDtor: { 1322 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>(); 1323 1324 const VarDecl *Var = DTor.getVarDecl(); 1325 ConsumedState VarState = CurrStates->getState(Var); 1326 1327 if (VarState != CS_None) { 1328 PropagationInfo PInfo(Var); 1329 1330 Visitor.checkCallability(PInfo, 1331 DTor.getDestructorDecl(AC.getASTContext()), 1332 getLastStmtLoc(CurrBlock)); 1333 1334 CurrStates->remove(Var); 1335 } 1336 break; 1337 } 1338 1339 default: 1340 break; 1341 } 1342 } 1343 1344 // TODO: Handle other forms of branching with precision, including while- 1345 // and for-loops. (Deferred) 1346 if (!splitState(CurrBlock, Visitor)) { 1347 CurrStates->setSource(NULL); 1348 1349 if (CurrBlock->succ_size() > 1 || 1350 (CurrBlock->succ_size() == 1 && 1351 (*CurrBlock->succ_begin())->pred_size() > 1)) { 1352 1353 bool OwnershipTaken = false; 1354 1355 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), 1356 SE = CurrBlock->succ_end(); SI != SE; ++SI) { 1357 1358 if (*SI == NULL) continue; 1359 1360 if (BlockInfo.isBackEdge(CurrBlock, *SI)) { 1361 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock, 1362 CurrStates, 1363 WarningsHandler); 1364 1365 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock)) 1366 BlockInfo.discardInfo(*SI); 1367 } else { 1368 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken); 1369 } 1370 } 1371 1372 if (!OwnershipTaken) 1373 delete CurrStates; 1374 1375 CurrStates = NULL; 1376 } 1377 } 1378 } // End of block iterator. 1379 1380 // Delete the last existing state map. 1381 delete CurrStates; 1382 1383 WarningsHandler.emitDiagnostics(); 1384} 1385}} // end namespace clang::consumed 1386