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