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