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