Consumed.cpp revision cd0f6d7600a691ad81dab308e9905fb0cce1df4d
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 const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset); 576 QualType ParamType = Param->getType(); 577 578 InfoEntry Entry = PropagationMap.find(Call->getArg(Index)); 579 580 if (Entry == PropagationMap.end() || !Entry->second.isVar()) { 581 continue; 582 } 583 584 PropagationInfo PInfo = Entry->second; 585 586 if (ParamType->isRValueReferenceType() || 587 (ParamType->isLValueReferenceType() && 588 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) { 589 590 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed); 591 592 } else if (Param->hasAttr<ReturnTypestateAttr>()) { 593 StateMap->setState(PInfo.getVar(), 594 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>())); 595 596 } else if (!(ParamType.isConstQualified() || 597 ((ParamType->isReferenceType() || 598 ParamType->isPointerType()) && 599 ParamType->getPointeeType().isConstQualified()))) { 600 601 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown); 602 } 603 } 604 605 QualType RetType = FunDecl->getCallResultType(); 606 if (RetType->isReferenceType()) 607 RetType = RetType->getPointeeType(); 608 609 propagateReturnType(Call, FunDecl, RetType); 610 } 611} 612 613void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) { 614 forwardInfo(Cast->getSubExpr(), Cast); 615} 616 617void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr( 618 const CXXBindTemporaryExpr *Temp) { 619 620 forwardInfo(Temp->getSubExpr(), Temp); 621} 622 623void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) { 624 CXXConstructorDecl *Constructor = Call->getConstructor(); 625 626 ASTContext &CurrContext = AC.getASTContext(); 627 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType(); 628 629 if (isConsumableType(ThisType)) { 630 if (Constructor->isDefaultConstructor()) { 631 632 PropagationMap.insert(PairType(Call, 633 PropagationInfo(consumed::CS_Consumed, ThisType))); 634 635 } else if (Constructor->isMoveConstructor()) { 636 637 PropagationInfo PInfo = 638 PropagationMap.find(Call->getArg(0))->second; 639 640 if (PInfo.isVar()) { 641 const VarDecl* Var = PInfo.getVar(); 642 643 PropagationMap.insert(PairType(Call, 644 PropagationInfo(StateMap->getState(Var), ThisType))); 645 646 StateMap->setState(Var, consumed::CS_Consumed); 647 648 } else { 649 PropagationMap.insert(PairType(Call, PInfo)); 650 } 651 652 } else if (Constructor->isCopyConstructor()) { 653 MapType::iterator Entry = PropagationMap.find(Call->getArg(0)); 654 655 if (Entry != PropagationMap.end()) 656 PropagationMap.insert(PairType(Call, Entry->second)); 657 658 } else { 659 propagateReturnType(Call, Constructor, ThisType); 660 } 661 } 662} 663 664 665void ConsumedStmtVisitor::VisitCXXMemberCallExpr( 666 const CXXMemberCallExpr *Call) { 667 668 VisitCallExpr(Call); 669 670 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens()); 671 672 if (Entry != PropagationMap.end()) { 673 PropagationInfo PInfo = Entry->second; 674 const CXXMethodDecl *MethodDecl = Call->getMethodDecl(); 675 676 checkCallability(PInfo, MethodDecl, Call->getExprLoc()); 677 678 if (PInfo.isVar()) { 679 if (isTestingFunction(MethodDecl)) 680 PropagationMap.insert(PairType(Call, 681 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl)))); 682 else if (MethodDecl->hasAttr<SetTypestateAttr>()) 683 StateMap->setState(PInfo.getVar(), 684 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>())); 685 } 686 } 687} 688 689void ConsumedStmtVisitor::VisitCXXOperatorCallExpr( 690 const CXXOperatorCallExpr *Call) { 691 692 const FunctionDecl *FunDecl = 693 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee()); 694 695 if (!FunDecl) return; 696 697 if (isa<CXXMethodDecl>(FunDecl) && 698 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) { 699 700 InfoEntry LEntry = PropagationMap.find(Call->getArg(0)); 701 InfoEntry REntry = PropagationMap.find(Call->getArg(1)); 702 703 PropagationInfo LPInfo, RPInfo; 704 705 if (LEntry != PropagationMap.end() && 706 REntry != PropagationMap.end()) { 707 708 LPInfo = LEntry->second; 709 RPInfo = REntry->second; 710 711 if (LPInfo.isVar() && RPInfo.isVar()) { 712 StateMap->setState(LPInfo.getVar(), 713 StateMap->getState(RPInfo.getVar())); 714 715 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed); 716 717 PropagationMap.insert(PairType(Call, LPInfo)); 718 719 } else if (LPInfo.isVar() && !RPInfo.isVar()) { 720 StateMap->setState(LPInfo.getVar(), RPInfo.getState()); 721 722 PropagationMap.insert(PairType(Call, LPInfo)); 723 724 } else if (!LPInfo.isVar() && RPInfo.isVar()) { 725 PropagationMap.insert(PairType(Call, 726 PropagationInfo(StateMap->getState(RPInfo.getVar()), 727 LPInfo.getTempType()))); 728 729 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed); 730 731 } else { 732 PropagationMap.insert(PairType(Call, RPInfo)); 733 } 734 735 } else if (LEntry != PropagationMap.end() && 736 REntry == PropagationMap.end()) { 737 738 LPInfo = LEntry->second; 739 740 if (LPInfo.isVar()) { 741 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown); 742 743 PropagationMap.insert(PairType(Call, LPInfo)); 744 745 } else if (LPInfo.isState()) { 746 PropagationMap.insert(PairType(Call, 747 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType()))); 748 } 749 750 } else if (LEntry == PropagationMap.end() && 751 REntry != PropagationMap.end()) { 752 753 if (REntry->second.isVar()) 754 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed); 755 } 756 757 } else { 758 759 VisitCallExpr(Call); 760 761 InfoEntry Entry = PropagationMap.find(Call->getArg(0)); 762 763 if (Entry != PropagationMap.end()) { 764 PropagationInfo PInfo = Entry->second; 765 766 checkCallability(PInfo, FunDecl, Call->getExprLoc()); 767 768 if (PInfo.isVar()) { 769 if (isTestingFunction(FunDecl)) 770 PropagationMap.insert(PairType(Call, 771 PropagationInfo(PInfo.getVar(), testsFor(FunDecl)))); 772 else if (FunDecl->hasAttr<SetTypestateAttr>()) 773 StateMap->setState(PInfo.getVar(), 774 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>())); 775 } 776 } 777 } 778} 779 780void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) { 781 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) 782 if (StateMap->getState(Var) != consumed::CS_None) 783 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var))); 784} 785 786void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) { 787 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(), 788 DE = DeclS->decl_end(); DI != DE; ++DI) { 789 790 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI)); 791 } 792 793 if (DeclS->isSingleDecl()) 794 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl())) 795 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var))); 796} 797 798void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr( 799 const MaterializeTemporaryExpr *Temp) { 800 801 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr()); 802 803 if (Entry != PropagationMap.end()) 804 PropagationMap.insert(PairType(Temp, Entry->second)); 805} 806 807void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) { 808 forwardInfo(MExpr->getBase(), MExpr); 809} 810 811 812void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) { 813 QualType ParamType = Param->getType(); 814 ConsumedState ParamState = consumed::CS_None; 815 816 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) && 817 isConsumableType(ParamType)) 818 ParamState = mapConsumableAttrState(ParamType); 819 else if (ParamType->isReferenceType() && 820 isConsumableType(ParamType->getPointeeType())) 821 ParamState = consumed::CS_Unknown; 822 823 if (ParamState) 824 StateMap->setState(Param, ParamState); 825} 826 827void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) { 828 ConsumedState ExpectedState = Analyzer.getExpectedReturnState(); 829 830 if (ExpectedState != CS_None) { 831 InfoEntry Entry = PropagationMap.find(Ret->getRetValue()); 832 833 if (Entry != PropagationMap.end()) { 834 assert(Entry->second.isState() || Entry->second.isVar()); 835 836 ConsumedState RetState = Entry->second.isState() ? 837 Entry->second.getState() : StateMap->getState(Entry->second.getVar()); 838 839 if (RetState != ExpectedState) 840 Analyzer.WarningsHandler.warnReturnTypestateMismatch( 841 Ret->getReturnLoc(), stateToString(ExpectedState), 842 stateToString(RetState)); 843 } 844 } 845 846 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(), 847 Analyzer.WarningsHandler); 848} 849 850void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) { 851 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens()); 852 if (Entry == PropagationMap.end()) return; 853 854 switch (UOp->getOpcode()) { 855 case UO_AddrOf: 856 PropagationMap.insert(PairType(UOp, Entry->second)); 857 break; 858 859 case UO_LNot: 860 if (Entry->second.isTest() || Entry->second.isBinTest()) 861 PropagationMap.insert(PairType(UOp, Entry->second.invertTest())); 862 break; 863 864 default: 865 break; 866 } 867} 868 869// TODO: See if I need to check for reference types here. 870void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) { 871 if (isConsumableType(Var->getType())) { 872 if (Var->hasInit()) { 873 PropagationInfo PInfo = 874 PropagationMap.find(Var->getInit())->second; 875 876 StateMap->setState(Var, PInfo.isVar() ? 877 StateMap->getState(PInfo.getVar()) : PInfo.getState()); 878 879 } else { 880 StateMap->setState(Var, consumed::CS_Unknown); 881 } 882 } 883} 884}} // end clang::consumed::ConsumedStmtVisitor 885 886namespace clang { 887namespace consumed { 888 889void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, 890 ConsumedStateMap *ThenStates, 891 ConsumedStateMap *ElseStates) { 892 893 ConsumedState VarState = ThenStates->getState(Test.Var); 894 895 if (VarState == CS_Unknown) { 896 ThenStates->setState(Test.Var, Test.TestsFor); 897 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor)); 898 899 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) { 900 ThenStates->markUnreachable(); 901 902 } else if (VarState == Test.TestsFor) { 903 ElseStates->markUnreachable(); 904 } 905} 906 907void splitVarStateForIfBinOp(const PropagationInfo &PInfo, 908 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) { 909 910 const VarTestResult <est = PInfo.getLTest(), 911 &RTest = PInfo.getRTest(); 912 913 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None, 914 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None; 915 916 if (LTest.Var) { 917 if (PInfo.testEffectiveOp() == EO_And) { 918 if (LState == CS_Unknown) { 919 ThenStates->setState(LTest.Var, LTest.TestsFor); 920 921 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) { 922 ThenStates->markUnreachable(); 923 924 } else if (LState == LTest.TestsFor && isKnownState(RState)) { 925 if (RState == RTest.TestsFor) 926 ElseStates->markUnreachable(); 927 else 928 ThenStates->markUnreachable(); 929 } 930 931 } else { 932 if (LState == CS_Unknown) { 933 ElseStates->setState(LTest.Var, 934 invertConsumedUnconsumed(LTest.TestsFor)); 935 936 } else if (LState == LTest.TestsFor) { 937 ElseStates->markUnreachable(); 938 939 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) && 940 isKnownState(RState)) { 941 942 if (RState == RTest.TestsFor) 943 ElseStates->markUnreachable(); 944 else 945 ThenStates->markUnreachable(); 946 } 947 } 948 } 949 950 if (RTest.Var) { 951 if (PInfo.testEffectiveOp() == EO_And) { 952 if (RState == CS_Unknown) 953 ThenStates->setState(RTest.Var, RTest.TestsFor); 954 else if (RState == invertConsumedUnconsumed(RTest.TestsFor)) 955 ThenStates->markUnreachable(); 956 957 } else { 958 if (RState == CS_Unknown) 959 ElseStates->setState(RTest.Var, 960 invertConsumedUnconsumed(RTest.TestsFor)); 961 else if (RState == RTest.TestsFor) 962 ElseStates->markUnreachable(); 963 } 964 } 965} 966 967bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock, 968 const CFGBlock *TargetBlock) { 969 970 assert(CurrBlock && "Block pointer must not be NULL"); 971 assert(TargetBlock && "TargetBlock pointer must not be NULL"); 972 973 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()]; 974 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(), 975 PE = TargetBlock->pred_end(); PI != PE; ++PI) { 976 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] ) 977 return false; 978 } 979 return true; 980} 981 982void ConsumedBlockInfo::addInfo(const CFGBlock *Block, 983 ConsumedStateMap *StateMap, 984 bool &AlreadyOwned) { 985 986 assert(Block && "Block pointer must not be NULL"); 987 988 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 989 990 if (Entry) { 991 Entry->intersect(StateMap); 992 993 } else if (AlreadyOwned) { 994 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap); 995 996 } else { 997 StateMapsArray[Block->getBlockID()] = StateMap; 998 AlreadyOwned = true; 999 } 1000} 1001 1002void ConsumedBlockInfo::addInfo(const CFGBlock *Block, 1003 ConsumedStateMap *StateMap) { 1004 1005 assert(Block != NULL && "Block pointer must not be NULL"); 1006 1007 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 1008 1009 if (Entry) { 1010 Entry->intersect(StateMap); 1011 delete StateMap; 1012 1013 } else { 1014 StateMapsArray[Block->getBlockID()] = StateMap; 1015 } 1016} 1017 1018ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) { 1019 assert(Block && "Block pointer must not be NULL"); 1020 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info"); 1021 1022 return StateMapsArray[Block->getBlockID()]; 1023} 1024 1025void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) { 1026 unsigned int BlockID = Block->getBlockID(); 1027 delete StateMapsArray[BlockID]; 1028 StateMapsArray[BlockID] = NULL; 1029} 1030 1031ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) { 1032 assert(Block && "Block pointer must not be NULL"); 1033 1034 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()]; 1035 if (isBackEdgeTarget(Block)) { 1036 return new ConsumedStateMap(*StateMap); 1037 } else { 1038 StateMapsArray[Block->getBlockID()] = NULL; 1039 return StateMap; 1040 } 1041} 1042 1043bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) { 1044 assert(From && "From block must not be NULL"); 1045 assert(To && "From block must not be NULL"); 1046 1047 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()]; 1048} 1049 1050bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) { 1051 assert(Block != NULL && "Block pointer must not be NULL"); 1052 1053 // Anything with less than two predecessors can't be the target of a back 1054 // edge. 1055 if (Block->pred_size() < 2) 1056 return false; 1057 1058 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()]; 1059 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(), 1060 PE = Block->pred_end(); PI != PE; ++PI) { 1061 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()]) 1062 return true; 1063 } 1064 return false; 1065} 1066 1067void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc, 1068 ConsumedWarningsHandlerBase &WarningsHandler) const { 1069 1070 ConsumedState ExpectedState; 1071 1072 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME; 1073 ++DMI) { 1074 1075 if (isa<ParmVarDecl>(DMI->first)) { 1076 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first); 1077 1078 if (!Param->hasAttr<ReturnTypestateAttr>()) continue; 1079 1080 ExpectedState = 1081 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()); 1082 1083 if (DMI->second != ExpectedState) { 1084 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc, 1085 Param->getNameAsString(), stateToString(ExpectedState), 1086 stateToString(DMI->second)); 1087 } 1088 } 1089 } 1090} 1091 1092ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const { 1093 MapType::const_iterator Entry = Map.find(Var); 1094 1095 if (Entry != Map.end()) { 1096 return Entry->second; 1097 1098 } else { 1099 return CS_None; 1100 } 1101} 1102 1103void ConsumedStateMap::intersect(const ConsumedStateMap *Other) { 1104 ConsumedState LocalState; 1105 1106 if (this->From && this->From == Other->From && !Other->Reachable) { 1107 this->markUnreachable(); 1108 return; 1109 } 1110 1111 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end(); 1112 DMI != DME; ++DMI) { 1113 1114 LocalState = this->getState(DMI->first); 1115 1116 if (LocalState == CS_None) 1117 continue; 1118 1119 if (LocalState != DMI->second) 1120 Map[DMI->first] = CS_Unknown; 1121 } 1122} 1123 1124void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead, 1125 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates, 1126 ConsumedWarningsHandlerBase &WarningsHandler) { 1127 1128 ConsumedState LocalState; 1129 SourceLocation BlameLoc = getLastStmtLoc(LoopBack); 1130 1131 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(), 1132 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) { 1133 1134 LocalState = this->getState(DMI->first); 1135 1136 if (LocalState == CS_None) 1137 continue; 1138 1139 if (LocalState != DMI->second) { 1140 Map[DMI->first] = CS_Unknown; 1141 WarningsHandler.warnLoopStateMismatch( 1142 BlameLoc, DMI->first->getNameAsString()); 1143 } 1144 } 1145} 1146 1147void ConsumedStateMap::markUnreachable() { 1148 this->Reachable = false; 1149 Map.clear(); 1150} 1151 1152void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) { 1153 Map[Var] = State; 1154} 1155 1156void ConsumedStateMap::remove(const VarDecl *Var) { 1157 Map.erase(Var); 1158} 1159 1160bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const { 1161 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end(); 1162 DMI != DME; ++DMI) { 1163 1164 if (this->getState(DMI->first) != DMI->second) 1165 return true; 1166 } 1167 1168 return false; 1169} 1170 1171void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC, 1172 const FunctionDecl *D) { 1173 QualType ReturnType; 1174 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { 1175 ASTContext &CurrContext = AC.getASTContext(); 1176 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType(); 1177 } else 1178 ReturnType = D->getCallResultType(); 1179 1180 if (D->hasAttr<ReturnTypestateAttr>()) { 1181 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>(); 1182 1183 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); 1184 if (!RD || !RD->hasAttr<ConsumableAttr>()) { 1185 // FIXME: This should be removed when template instantiation propagates 1186 // attributes at template specialization definition, not 1187 // declaration. When it is removed the test needs to be enabled 1188 // in SemaDeclAttr.cpp. 1189 WarningsHandler.warnReturnTypestateForUnconsumableType( 1190 RTSAttr->getLocation(), ReturnType.getAsString()); 1191 ExpectedReturnState = CS_None; 1192 } else 1193 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr); 1194 } else if (isConsumableType(ReturnType)) 1195 ExpectedReturnState = mapConsumableAttrState(ReturnType); 1196 else 1197 ExpectedReturnState = CS_None; 1198} 1199 1200bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock, 1201 const ConsumedStmtVisitor &Visitor) { 1202 1203 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates); 1204 PropagationInfo PInfo; 1205 1206 if (const IfStmt *IfNode = 1207 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) { 1208 1209 const Stmt *Cond = IfNode->getCond(); 1210 1211 PInfo = Visitor.getInfo(Cond); 1212 if (!PInfo.isValid() && isa<BinaryOperator>(Cond)) 1213 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS()); 1214 1215 if (PInfo.isTest()) { 1216 CurrStates->setSource(Cond); 1217 FalseStates->setSource(Cond); 1218 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates); 1219 1220 } else if (PInfo.isBinTest()) { 1221 CurrStates->setSource(PInfo.testSourceNode()); 1222 FalseStates->setSource(PInfo.testSourceNode()); 1223 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates); 1224 1225 } else { 1226 delete FalseStates; 1227 return false; 1228 } 1229 1230 } else if (const BinaryOperator *BinOp = 1231 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) { 1232 1233 PInfo = Visitor.getInfo(BinOp->getLHS()); 1234 if (!PInfo.isTest()) { 1235 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) { 1236 PInfo = Visitor.getInfo(BinOp->getRHS()); 1237 1238 if (!PInfo.isTest()) { 1239 delete FalseStates; 1240 return false; 1241 } 1242 1243 } else { 1244 delete FalseStates; 1245 return false; 1246 } 1247 } 1248 1249 CurrStates->setSource(BinOp); 1250 FalseStates->setSource(BinOp); 1251 1252 const VarTestResult &Test = PInfo.getTest(); 1253 ConsumedState VarState = CurrStates->getState(Test.Var); 1254 1255 if (BinOp->getOpcode() == BO_LAnd) { 1256 if (VarState == CS_Unknown) 1257 CurrStates->setState(Test.Var, Test.TestsFor); 1258 else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) 1259 CurrStates->markUnreachable(); 1260 1261 } else if (BinOp->getOpcode() == BO_LOr) { 1262 if (VarState == CS_Unknown) 1263 FalseStates->setState(Test.Var, 1264 invertConsumedUnconsumed(Test.TestsFor)); 1265 else if (VarState == Test.TestsFor) 1266 FalseStates->markUnreachable(); 1267 } 1268 1269 } else { 1270 delete FalseStates; 1271 return false; 1272 } 1273 1274 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(); 1275 1276 if (*SI) 1277 BlockInfo.addInfo(*SI, CurrStates); 1278 else 1279 delete CurrStates; 1280 1281 if (*++SI) 1282 BlockInfo.addInfo(*SI, FalseStates); 1283 else 1284 delete FalseStates; 1285 1286 CurrStates = NULL; 1287 return true; 1288} 1289 1290void ConsumedAnalyzer::run(AnalysisDeclContext &AC) { 1291 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl()); 1292 if (!D) 1293 return; 1294 1295 CFG *CFGraph = AC.getCFG(); 1296 if (!CFGraph) 1297 return; 1298 1299 determineExpectedReturnState(AC, D); 1300 1301 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>(); 1302 // AC.getCFG()->viewCFG(LangOptions()); 1303 1304 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph); 1305 1306 CurrStates = new ConsumedStateMap(); 1307 ConsumedStmtVisitor Visitor(AC, *this, CurrStates); 1308 1309 // Add all trackable parameters to the state map. 1310 for (FunctionDecl::param_const_iterator PI = D->param_begin(), 1311 PE = D->param_end(); PI != PE; ++PI) { 1312 Visitor.VisitParmVarDecl(*PI); 1313 } 1314 1315 // Visit all of the function's basic blocks. 1316 for (PostOrderCFGView::iterator I = SortedGraph->begin(), 1317 E = SortedGraph->end(); I != E; ++I) { 1318 1319 const CFGBlock *CurrBlock = *I; 1320 1321 if (CurrStates == NULL) 1322 CurrStates = BlockInfo.getInfo(CurrBlock); 1323 1324 if (!CurrStates) { 1325 continue; 1326 1327 } else if (!CurrStates->isReachable()) { 1328 delete CurrStates; 1329 CurrStates = NULL; 1330 continue; 1331 } 1332 1333 Visitor.reset(CurrStates); 1334 1335 // Visit all of the basic block's statements. 1336 for (CFGBlock::const_iterator BI = CurrBlock->begin(), 1337 BE = CurrBlock->end(); BI != BE; ++BI) { 1338 1339 switch (BI->getKind()) { 1340 case CFGElement::Statement: 1341 Visitor.Visit(BI->castAs<CFGStmt>().getStmt()); 1342 break; 1343 1344 case CFGElement::TemporaryDtor: { 1345 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>(); 1346 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr(); 1347 PropagationInfo PInfo = Visitor.getInfo(BTE); 1348 1349 if (PInfo.isValid()) 1350 Visitor.checkCallability(PInfo, 1351 DTor.getDestructorDecl(AC.getASTContext()), 1352 BTE->getExprLoc()); 1353 break; 1354 } 1355 1356 case CFGElement::AutomaticObjectDtor: { 1357 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>(); 1358 1359 const VarDecl *Var = DTor.getVarDecl(); 1360 ConsumedState VarState = CurrStates->getState(Var); 1361 1362 if (VarState != CS_None) { 1363 PropagationInfo PInfo(Var); 1364 1365 Visitor.checkCallability(PInfo, 1366 DTor.getDestructorDecl(AC.getASTContext()), 1367 getLastStmtLoc(CurrBlock)); 1368 1369 CurrStates->remove(Var); 1370 } 1371 break; 1372 } 1373 1374 default: 1375 break; 1376 } 1377 } 1378 1379 // TODO: Handle other forms of branching with precision, including while- 1380 // and for-loops. (Deferred) 1381 if (!splitState(CurrBlock, Visitor)) { 1382 CurrStates->setSource(NULL); 1383 1384 if (CurrBlock->succ_size() > 1 || 1385 (CurrBlock->succ_size() == 1 && 1386 (*CurrBlock->succ_begin())->pred_size() > 1)) { 1387 1388 bool OwnershipTaken = false; 1389 1390 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), 1391 SE = CurrBlock->succ_end(); SI != SE; ++SI) { 1392 1393 if (*SI == NULL) continue; 1394 1395 if (BlockInfo.isBackEdge(CurrBlock, *SI)) { 1396 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock, 1397 CurrStates, 1398 WarningsHandler); 1399 1400 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock)) 1401 BlockInfo.discardInfo(*SI); 1402 } else { 1403 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken); 1404 } 1405 } 1406 1407 if (!OwnershipTaken) 1408 delete CurrStates; 1409 1410 CurrStates = NULL; 1411 } 1412 } 1413 1414 if (CurrBlock == &AC.getCFG()->getExit() && 1415 D->getCallResultType()->isVoidType()) 1416 CurrStates->checkParamsForReturnTypestate(D->getLocation(), 1417 WarningsHandler); 1418 } // End of block iterator. 1419 1420 // Delete the last existing state map. 1421 delete CurrStates; 1422 1423 WarningsHandler.emitDiagnostics(); 1424} 1425}} // end namespace clang::consumed 1426