1259701Sdim//===- Consumed.cpp --------------------------------------------*- C++ --*-===// 2259701Sdim// 3259701Sdim// The LLVM Compiler Infrastructure 4259701Sdim// 5259701Sdim// This file is distributed under the University of Illinois Open Source 6259701Sdim// License. See LICENSE.TXT for details. 7259701Sdim// 8259701Sdim//===----------------------------------------------------------------------===// 9259701Sdim// 10259701Sdim// A intra-procedural analysis for checking consumed properties. This is based, 11259701Sdim// in part, on research on linear types. 12259701Sdim// 13259701Sdim//===----------------------------------------------------------------------===// 14259701Sdim 15259701Sdim#include "clang/AST/ASTContext.h" 16259701Sdim#include "clang/AST/Attr.h" 17259701Sdim#include "clang/AST/DeclCXX.h" 18259701Sdim#include "clang/AST/ExprCXX.h" 19259701Sdim#include "clang/AST/RecursiveASTVisitor.h" 20259701Sdim#include "clang/AST/StmtVisitor.h" 21259701Sdim#include "clang/AST/StmtCXX.h" 22259701Sdim#include "clang/AST/Type.h" 23259701Sdim#include "clang/Analysis/Analyses/PostOrderCFGView.h" 24259701Sdim#include "clang/Analysis/AnalysisContext.h" 25259701Sdim#include "clang/Analysis/CFG.h" 26259701Sdim#include "clang/Analysis/Analyses/Consumed.h" 27259701Sdim#include "clang/Basic/OperatorKinds.h" 28259701Sdim#include "clang/Basic/SourceLocation.h" 29259701Sdim#include "llvm/ADT/DenseMap.h" 30259701Sdim#include "llvm/ADT/OwningPtr.h" 31259701Sdim#include "llvm/ADT/SmallVector.h" 32259701Sdim#include "llvm/Support/Compiler.h" 33259701Sdim#include "llvm/Support/raw_ostream.h" 34259701Sdim 35259701Sdim// TODO: Adjust states of args to constructors in the same way that arguments to 36259701Sdim// function calls are handled. 37259701Sdim// TODO: Use information from tests in for- and while-loop conditional. 38259701Sdim// TODO: Add notes about the actual and expected state for 39259701Sdim// TODO: Correctly identify unreachable blocks when chaining boolean operators. 40259701Sdim// TODO: Adjust the parser and AttributesList class to support lists of 41259701Sdim// identifiers. 42259701Sdim// TODO: Warn about unreachable code. 43259701Sdim// TODO: Switch to using a bitmap to track unreachable blocks. 44259701Sdim// TODO: Handle variable definitions, e.g. bool valid = x.isValid(); 45259701Sdim// if (valid) ...; (Deferred) 46259701Sdim// TODO: Take notes on state transitions to provide better warning messages. 47259701Sdim// (Deferred) 48259701Sdim// TODO: Test nested conditionals: A) Checking the same value multiple times, 49259701Sdim// and 2) Checking different values. (Deferred) 50259701Sdim 51259701Sdimusing namespace clang; 52259701Sdimusing namespace consumed; 53259701Sdim 54259701Sdim// Key method definition 55259701SdimConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {} 56259701Sdim 57259701Sdimstatic SourceLocation getFirstStmtLoc(const CFGBlock *Block) { 58259701Sdim // Find the source location of the first statement in the block, if the block 59259701Sdim // is not empty. 60259701Sdim for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end(); 61259701Sdim BI != BE; ++BI) { 62259701Sdim if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) 63259701Sdim return CS->getStmt()->getLocStart(); 64259701Sdim } 65259701Sdim 66259701Sdim // Block is empty. 67259701Sdim // If we have one successor, return the first statement in that block 68259701Sdim if (Block->succ_size() == 1 && *Block->succ_begin()) 69259701Sdim return getFirstStmtLoc(*Block->succ_begin()); 70259701Sdim 71259701Sdim return SourceLocation(); 72259701Sdim} 73259701Sdim 74259701Sdimstatic SourceLocation getLastStmtLoc(const CFGBlock *Block) { 75259701Sdim // Find the source location of the last statement in the block, if the block 76259701Sdim // is not empty. 77259701Sdim if (const Stmt *StmtNode = Block->getTerminator()) { 78259701Sdim return StmtNode->getLocStart(); 79259701Sdim } else { 80259701Sdim for (CFGBlock::const_reverse_iterator BI = Block->rbegin(), 81259701Sdim BE = Block->rend(); BI != BE; ++BI) { 82259701Sdim if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) 83259701Sdim return CS->getStmt()->getLocStart(); 84259701Sdim } 85259701Sdim } 86259701Sdim 87259701Sdim // If we have one successor, return the first statement in that block 88259701Sdim SourceLocation Loc; 89259701Sdim if (Block->succ_size() == 1 && *Block->succ_begin()) 90259701Sdim Loc = getFirstStmtLoc(*Block->succ_begin()); 91259701Sdim if (Loc.isValid()) 92259701Sdim return Loc; 93259701Sdim 94259701Sdim // If we have one predecessor, return the last statement in that block 95259701Sdim if (Block->pred_size() == 1 && *Block->pred_begin()) 96259701Sdim return getLastStmtLoc(*Block->pred_begin()); 97259701Sdim 98259701Sdim return Loc; 99259701Sdim} 100259701Sdim 101259701Sdimstatic ConsumedState invertConsumedUnconsumed(ConsumedState State) { 102259701Sdim switch (State) { 103259701Sdim case CS_Unconsumed: 104259701Sdim return CS_Consumed; 105259701Sdim case CS_Consumed: 106259701Sdim return CS_Unconsumed; 107259701Sdim case CS_None: 108259701Sdim return CS_None; 109259701Sdim case CS_Unknown: 110259701Sdim return CS_Unknown; 111259701Sdim } 112259701Sdim llvm_unreachable("invalid enum"); 113259701Sdim} 114259701Sdim 115259701Sdimstatic bool isCallableInState(const CallableWhenAttr *CWAttr, 116259701Sdim ConsumedState State) { 117259701Sdim 118259701Sdim CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(), 119259701Sdim E = CWAttr->callableState_end(); 120259701Sdim 121259701Sdim for (; I != E; ++I) { 122259701Sdim 123259701Sdim ConsumedState MappedAttrState = CS_None; 124259701Sdim 125259701Sdim switch (*I) { 126259701Sdim case CallableWhenAttr::Unknown: 127259701Sdim MappedAttrState = CS_Unknown; 128259701Sdim break; 129259701Sdim 130259701Sdim case CallableWhenAttr::Unconsumed: 131259701Sdim MappedAttrState = CS_Unconsumed; 132259701Sdim break; 133259701Sdim 134259701Sdim case CallableWhenAttr::Consumed: 135259701Sdim MappedAttrState = CS_Consumed; 136259701Sdim break; 137259701Sdim } 138259701Sdim 139259701Sdim if (MappedAttrState == State) 140259701Sdim return true; 141259701Sdim } 142259701Sdim 143259701Sdim return false; 144259701Sdim} 145259701Sdim 146259701Sdimstatic bool isConsumableType(const QualType &QT) { 147259701Sdim if (QT->isPointerType() || QT->isReferenceType()) 148259701Sdim return false; 149259701Sdim 150259701Sdim if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) 151259701Sdim return RD->hasAttr<ConsumableAttr>(); 152259701Sdim 153259701Sdim return false; 154259701Sdim} 155259701Sdim 156259701Sdimstatic bool isKnownState(ConsumedState State) { 157259701Sdim switch (State) { 158259701Sdim case CS_Unconsumed: 159259701Sdim case CS_Consumed: 160259701Sdim return true; 161259701Sdim case CS_None: 162259701Sdim case CS_Unknown: 163259701Sdim return false; 164259701Sdim } 165259701Sdim llvm_unreachable("invalid enum"); 166259701Sdim} 167259701Sdim 168259701Sdimstatic bool isRValueRefish(QualType ParamType) { 169259701Sdim return ParamType->isRValueReferenceType() || 170259701Sdim (ParamType->isLValueReferenceType() && 171259701Sdim !cast<LValueReferenceType>( 172259701Sdim ParamType.getCanonicalType())->isSpelledAsLValue()); 173259701Sdim} 174259701Sdim 175259701Sdimstatic bool isTestingFunction(const FunctionDecl *FunDecl) { 176259701Sdim return FunDecl->hasAttr<TestTypestateAttr>(); 177259701Sdim} 178259701Sdim 179259701Sdimstatic bool isValueType(QualType ParamType) { 180259701Sdim return !(ParamType->isPointerType() || ParamType->isReferenceType()); 181259701Sdim} 182259701Sdim 183259701Sdimstatic ConsumedState mapConsumableAttrState(const QualType QT) { 184259701Sdim assert(isConsumableType(QT)); 185259701Sdim 186259701Sdim const ConsumableAttr *CAttr = 187259701Sdim QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>(); 188259701Sdim 189259701Sdim switch (CAttr->getDefaultState()) { 190259701Sdim case ConsumableAttr::Unknown: 191259701Sdim return CS_Unknown; 192259701Sdim case ConsumableAttr::Unconsumed: 193259701Sdim return CS_Unconsumed; 194259701Sdim case ConsumableAttr::Consumed: 195259701Sdim return CS_Consumed; 196259701Sdim } 197259701Sdim llvm_unreachable("invalid enum"); 198259701Sdim} 199259701Sdim 200259701Sdimstatic ConsumedState 201259701SdimmapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) { 202259701Sdim switch (PTAttr->getParamState()) { 203259701Sdim case ParamTypestateAttr::Unknown: 204259701Sdim return CS_Unknown; 205259701Sdim case ParamTypestateAttr::Unconsumed: 206259701Sdim return CS_Unconsumed; 207259701Sdim case ParamTypestateAttr::Consumed: 208259701Sdim return CS_Consumed; 209259701Sdim } 210259701Sdim llvm_unreachable("invalid_enum"); 211259701Sdim} 212259701Sdim 213259701Sdimstatic ConsumedState 214259701SdimmapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) { 215259701Sdim switch (RTSAttr->getState()) { 216259701Sdim case ReturnTypestateAttr::Unknown: 217259701Sdim return CS_Unknown; 218259701Sdim case ReturnTypestateAttr::Unconsumed: 219259701Sdim return CS_Unconsumed; 220259701Sdim case ReturnTypestateAttr::Consumed: 221259701Sdim return CS_Consumed; 222259701Sdim } 223259701Sdim llvm_unreachable("invalid enum"); 224259701Sdim} 225259701Sdim 226259701Sdimstatic ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) { 227259701Sdim switch (STAttr->getNewState()) { 228259701Sdim case SetTypestateAttr::Unknown: 229259701Sdim return CS_Unknown; 230259701Sdim case SetTypestateAttr::Unconsumed: 231259701Sdim return CS_Unconsumed; 232259701Sdim case SetTypestateAttr::Consumed: 233259701Sdim return CS_Consumed; 234259701Sdim } 235259701Sdim llvm_unreachable("invalid_enum"); 236259701Sdim} 237259701Sdim 238259701Sdimstatic StringRef stateToString(ConsumedState State) { 239259701Sdim switch (State) { 240259701Sdim case consumed::CS_None: 241259701Sdim return "none"; 242259701Sdim 243259701Sdim case consumed::CS_Unknown: 244259701Sdim return "unknown"; 245259701Sdim 246259701Sdim case consumed::CS_Unconsumed: 247259701Sdim return "unconsumed"; 248259701Sdim 249259701Sdim case consumed::CS_Consumed: 250259701Sdim return "consumed"; 251259701Sdim } 252259701Sdim llvm_unreachable("invalid enum"); 253259701Sdim} 254259701Sdim 255259701Sdimstatic ConsumedState testsFor(const FunctionDecl *FunDecl) { 256259701Sdim assert(isTestingFunction(FunDecl)); 257259701Sdim switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) { 258259701Sdim case TestTypestateAttr::Unconsumed: 259259701Sdim return CS_Unconsumed; 260259701Sdim case TestTypestateAttr::Consumed: 261259701Sdim return CS_Consumed; 262259701Sdim } 263259701Sdim llvm_unreachable("invalid enum"); 264259701Sdim} 265259701Sdim 266259701Sdimnamespace { 267259701Sdimstruct VarTestResult { 268259701Sdim const VarDecl *Var; 269259701Sdim ConsumedState TestsFor; 270259701Sdim}; 271259701Sdim} // end anonymous::VarTestResult 272259701Sdim 273259701Sdimnamespace clang { 274259701Sdimnamespace consumed { 275259701Sdim 276259701Sdimenum EffectiveOp { 277259701Sdim EO_And, 278259701Sdim EO_Or 279259701Sdim}; 280259701Sdim 281259701Sdimclass PropagationInfo { 282259701Sdim enum { 283259701Sdim IT_None, 284259701Sdim IT_State, 285259701Sdim IT_VarTest, 286259701Sdim IT_BinTest, 287259701Sdim IT_Var, 288259701Sdim IT_Tmp 289259701Sdim } InfoType; 290259701Sdim 291259701Sdim struct BinTestTy { 292259701Sdim const BinaryOperator *Source; 293259701Sdim EffectiveOp EOp; 294259701Sdim VarTestResult LTest; 295259701Sdim VarTestResult RTest; 296259701Sdim }; 297259701Sdim 298259701Sdim union { 299259701Sdim ConsumedState State; 300259701Sdim VarTestResult VarTest; 301259701Sdim const VarDecl *Var; 302259701Sdim const CXXBindTemporaryExpr *Tmp; 303259701Sdim BinTestTy BinTest; 304259701Sdim }; 305259701Sdim 306259701Sdimpublic: 307259701Sdim PropagationInfo() : InfoType(IT_None) {} 308259701Sdim 309259701Sdim PropagationInfo(const VarTestResult &VarTest) 310259701Sdim : InfoType(IT_VarTest), VarTest(VarTest) {} 311259701Sdim 312259701Sdim PropagationInfo(const VarDecl *Var, ConsumedState TestsFor) 313259701Sdim : InfoType(IT_VarTest) { 314259701Sdim 315259701Sdim VarTest.Var = Var; 316259701Sdim VarTest.TestsFor = TestsFor; 317259701Sdim } 318259701Sdim 319259701Sdim PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, 320259701Sdim const VarTestResult <est, const VarTestResult &RTest) 321259701Sdim : InfoType(IT_BinTest) { 322259701Sdim 323259701Sdim BinTest.Source = Source; 324259701Sdim BinTest.EOp = EOp; 325259701Sdim BinTest.LTest = LTest; 326259701Sdim BinTest.RTest = RTest; 327259701Sdim } 328259701Sdim 329259701Sdim PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, 330259701Sdim const VarDecl *LVar, ConsumedState LTestsFor, 331259701Sdim const VarDecl *RVar, ConsumedState RTestsFor) 332259701Sdim : InfoType(IT_BinTest) { 333259701Sdim 334259701Sdim BinTest.Source = Source; 335259701Sdim BinTest.EOp = EOp; 336259701Sdim BinTest.LTest.Var = LVar; 337259701Sdim BinTest.LTest.TestsFor = LTestsFor; 338259701Sdim BinTest.RTest.Var = RVar; 339259701Sdim BinTest.RTest.TestsFor = RTestsFor; 340259701Sdim } 341259701Sdim 342259701Sdim PropagationInfo(ConsumedState State) 343259701Sdim : InfoType(IT_State), State(State) {} 344259701Sdim 345259701Sdim PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {} 346259701Sdim PropagationInfo(const CXXBindTemporaryExpr *Tmp) 347259701Sdim : InfoType(IT_Tmp), Tmp(Tmp) {} 348259701Sdim 349259701Sdim const ConsumedState & getState() const { 350259701Sdim assert(InfoType == IT_State); 351259701Sdim return State; 352259701Sdim } 353259701Sdim 354259701Sdim const VarTestResult & getVarTest() const { 355259701Sdim assert(InfoType == IT_VarTest); 356259701Sdim return VarTest; 357259701Sdim } 358259701Sdim 359259701Sdim const VarTestResult & getLTest() const { 360259701Sdim assert(InfoType == IT_BinTest); 361259701Sdim return BinTest.LTest; 362259701Sdim } 363259701Sdim 364259701Sdim const VarTestResult & getRTest() const { 365259701Sdim assert(InfoType == IT_BinTest); 366259701Sdim return BinTest.RTest; 367259701Sdim } 368259701Sdim 369259701Sdim const VarDecl * getVar() const { 370259701Sdim assert(InfoType == IT_Var); 371259701Sdim return Var; 372259701Sdim } 373259701Sdim 374259701Sdim const CXXBindTemporaryExpr * getTmp() const { 375259701Sdim assert(InfoType == IT_Tmp); 376259701Sdim return Tmp; 377259701Sdim } 378259701Sdim 379259701Sdim ConsumedState getAsState(const ConsumedStateMap *StateMap) const { 380259701Sdim assert(isVar() || isTmp() || isState()); 381259701Sdim 382259701Sdim if (isVar()) 383259701Sdim return StateMap->getState(Var); 384259701Sdim else if (isTmp()) 385259701Sdim return StateMap->getState(Tmp); 386259701Sdim else if (isState()) 387259701Sdim return State; 388259701Sdim else 389259701Sdim return CS_None; 390259701Sdim } 391259701Sdim 392259701Sdim EffectiveOp testEffectiveOp() const { 393259701Sdim assert(InfoType == IT_BinTest); 394259701Sdim return BinTest.EOp; 395259701Sdim } 396259701Sdim 397259701Sdim const BinaryOperator * testSourceNode() const { 398259701Sdim assert(InfoType == IT_BinTest); 399259701Sdim return BinTest.Source; 400259701Sdim } 401259701Sdim 402259701Sdim inline bool isValid() const { return InfoType != IT_None; } 403259701Sdim inline bool isState() const { return InfoType == IT_State; } 404259701Sdim inline bool isVarTest() const { return InfoType == IT_VarTest; } 405259701Sdim inline bool isBinTest() const { return InfoType == IT_BinTest; } 406259701Sdim inline bool isVar() const { return InfoType == IT_Var; } 407259701Sdim inline bool isTmp() const { return InfoType == IT_Tmp; } 408259701Sdim 409259701Sdim bool isTest() const { 410259701Sdim return InfoType == IT_VarTest || InfoType == IT_BinTest; 411259701Sdim } 412259701Sdim 413259701Sdim bool isPointerToValue() const { 414259701Sdim return InfoType == IT_Var || InfoType == IT_Tmp; 415259701Sdim } 416259701Sdim 417259701Sdim PropagationInfo invertTest() const { 418259701Sdim assert(InfoType == IT_VarTest || InfoType == IT_BinTest); 419259701Sdim 420259701Sdim if (InfoType == IT_VarTest) { 421259701Sdim return PropagationInfo(VarTest.Var, 422259701Sdim invertConsumedUnconsumed(VarTest.TestsFor)); 423259701Sdim 424259701Sdim } else if (InfoType == IT_BinTest) { 425259701Sdim return PropagationInfo(BinTest.Source, 426259701Sdim BinTest.EOp == EO_And ? EO_Or : EO_And, 427259701Sdim BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor), 428259701Sdim BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor)); 429259701Sdim } else { 430259701Sdim return PropagationInfo(); 431259701Sdim } 432259701Sdim } 433259701Sdim}; 434259701Sdim 435259701Sdimstatic inline void 436259701SdimsetStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo, 437259701Sdim ConsumedState State) { 438259701Sdim 439259701Sdim assert(PInfo.isVar() || PInfo.isTmp()); 440259701Sdim 441259701Sdim if (PInfo.isVar()) 442259701Sdim StateMap->setState(PInfo.getVar(), State); 443259701Sdim else 444259701Sdim StateMap->setState(PInfo.getTmp(), State); 445259701Sdim} 446259701Sdim 447259701Sdimclass ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> { 448259701Sdim 449259701Sdim typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType; 450259701Sdim typedef std::pair<const Stmt *, PropagationInfo> PairType; 451259701Sdim typedef MapType::iterator InfoEntry; 452259701Sdim typedef MapType::const_iterator ConstInfoEntry; 453259701Sdim 454259701Sdim AnalysisDeclContext &AC; 455259701Sdim ConsumedAnalyzer &Analyzer; 456259701Sdim ConsumedStateMap *StateMap; 457259701Sdim MapType PropagationMap; 458259701Sdim void forwardInfo(const Stmt *From, const Stmt *To); 459259701Sdim bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl); 460259701Sdim void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun, 461259701Sdim QualType ReturnType); 462259701Sdim 463259701Sdimpublic: 464259701Sdim void checkCallability(const PropagationInfo &PInfo, 465259701Sdim const FunctionDecl *FunDecl, 466259701Sdim SourceLocation BlameLoc); 467259701Sdim 468259701Sdim void VisitBinaryOperator(const BinaryOperator *BinOp); 469259701Sdim void VisitCallExpr(const CallExpr *Call); 470259701Sdim void VisitCastExpr(const CastExpr *Cast); 471259701Sdim void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp); 472259701Sdim void VisitCXXConstructExpr(const CXXConstructExpr *Call); 473259701Sdim void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call); 474259701Sdim void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call); 475259701Sdim void VisitDeclRefExpr(const DeclRefExpr *DeclRef); 476259701Sdim void VisitDeclStmt(const DeclStmt *DelcS); 477259701Sdim void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp); 478259701Sdim void VisitMemberExpr(const MemberExpr *MExpr); 479259701Sdim void VisitParmVarDecl(const ParmVarDecl *Param); 480259701Sdim void VisitReturnStmt(const ReturnStmt *Ret); 481259701Sdim void VisitUnaryOperator(const UnaryOperator *UOp); 482259701Sdim void VisitVarDecl(const VarDecl *Var); 483259701Sdim 484259701Sdim ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer, 485259701Sdim ConsumedStateMap *StateMap) 486259701Sdim : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {} 487259701Sdim 488259701Sdim PropagationInfo getInfo(const Stmt *StmtNode) const { 489259701Sdim ConstInfoEntry Entry = PropagationMap.find(StmtNode); 490259701Sdim 491259701Sdim if (Entry != PropagationMap.end()) 492259701Sdim return Entry->second; 493259701Sdim else 494259701Sdim return PropagationInfo(); 495259701Sdim } 496259701Sdim 497259701Sdim void reset(ConsumedStateMap *NewStateMap) { 498259701Sdim StateMap = NewStateMap; 499259701Sdim } 500259701Sdim}; 501259701Sdim 502259701Sdimvoid ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo, 503259701Sdim const FunctionDecl *FunDecl, 504259701Sdim SourceLocation BlameLoc) { 505259701Sdim assert(!PInfo.isTest()); 506259701Sdim 507259701Sdim if (!FunDecl->hasAttr<CallableWhenAttr>()) 508259701Sdim return; 509259701Sdim 510259701Sdim const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>(); 511259701Sdim 512259701Sdim if (PInfo.isVar()) { 513259701Sdim ConsumedState VarState = StateMap->getState(PInfo.getVar()); 514259701Sdim 515259701Sdim if (VarState == CS_None || isCallableInState(CWAttr, VarState)) 516259701Sdim return; 517259701Sdim 518259701Sdim Analyzer.WarningsHandler.warnUseInInvalidState( 519259701Sdim FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(), 520259701Sdim stateToString(VarState), BlameLoc); 521259701Sdim 522259701Sdim } else { 523259701Sdim ConsumedState TmpState = PInfo.getAsState(StateMap); 524259701Sdim 525259701Sdim if (TmpState == CS_None || isCallableInState(CWAttr, TmpState)) 526259701Sdim return; 527259701Sdim 528259701Sdim Analyzer.WarningsHandler.warnUseOfTempInInvalidState( 529259701Sdim FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc); 530259701Sdim } 531259701Sdim} 532259701Sdim 533259701Sdimvoid ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) { 534259701Sdim InfoEntry Entry = PropagationMap.find(From); 535259701Sdim 536259701Sdim if (Entry != PropagationMap.end()) 537259701Sdim PropagationMap.insert(PairType(To, Entry->second)); 538259701Sdim} 539259701Sdim 540259701Sdimbool ConsumedStmtVisitor::isLikeMoveAssignment( 541259701Sdim const CXXMethodDecl *MethodDecl) { 542259701Sdim 543259701Sdim return MethodDecl->isMoveAssignmentOperator() || 544259701Sdim (MethodDecl->getOverloadedOperator() == OO_Equal && 545259701Sdim MethodDecl->getNumParams() == 1 && 546259701Sdim MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType()); 547259701Sdim} 548259701Sdim 549259701Sdimvoid ConsumedStmtVisitor::propagateReturnType(const Stmt *Call, 550259701Sdim const FunctionDecl *Fun, 551259701Sdim QualType ReturnType) { 552259701Sdim if (isConsumableType(ReturnType)) { 553259701Sdim 554259701Sdim ConsumedState ReturnState; 555259701Sdim 556259701Sdim if (Fun->hasAttr<ReturnTypestateAttr>()) 557259701Sdim ReturnState = mapReturnTypestateAttrState( 558259701Sdim Fun->getAttr<ReturnTypestateAttr>()); 559259701Sdim else 560259701Sdim ReturnState = mapConsumableAttrState(ReturnType); 561259701Sdim 562259701Sdim PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState))); 563259701Sdim } 564259701Sdim} 565259701Sdim 566259701Sdimvoid ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) { 567259701Sdim switch (BinOp->getOpcode()) { 568259701Sdim case BO_LAnd: 569259701Sdim case BO_LOr : { 570259701Sdim InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()), 571259701Sdim REntry = PropagationMap.find(BinOp->getRHS()); 572259701Sdim 573259701Sdim VarTestResult LTest, RTest; 574259701Sdim 575259701Sdim if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) { 576259701Sdim LTest = LEntry->second.getVarTest(); 577259701Sdim 578259701Sdim } else { 579259701Sdim LTest.Var = NULL; 580259701Sdim LTest.TestsFor = CS_None; 581259701Sdim } 582259701Sdim 583259701Sdim if (REntry != PropagationMap.end() && REntry->second.isVarTest()) { 584259701Sdim RTest = REntry->second.getVarTest(); 585259701Sdim 586259701Sdim } else { 587259701Sdim RTest.Var = NULL; 588259701Sdim RTest.TestsFor = CS_None; 589259701Sdim } 590259701Sdim 591259701Sdim if (!(LTest.Var == NULL && RTest.Var == NULL)) 592259701Sdim PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp, 593259701Sdim static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest))); 594259701Sdim 595259701Sdim break; 596259701Sdim } 597259701Sdim 598259701Sdim case BO_PtrMemD: 599259701Sdim case BO_PtrMemI: 600259701Sdim forwardInfo(BinOp->getLHS(), BinOp); 601259701Sdim break; 602259701Sdim 603259701Sdim default: 604259701Sdim break; 605259701Sdim } 606259701Sdim} 607259701Sdim 608266715Sdimstatic bool isStdNamespace(const DeclContext *DC) { 609266715Sdim if (!DC->isNamespace()) return false; 610266715Sdim while (DC->getParent()->isNamespace()) 611266715Sdim DC = DC->getParent(); 612266715Sdim const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); 613266715Sdim 614266715Sdim return ND && ND->getName() == "std" && 615266715Sdim ND->getDeclContext()->isTranslationUnit(); 616266715Sdim} 617266715Sdim 618259701Sdimvoid ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) { 619259701Sdim if (const FunctionDecl *FunDecl = 620259701Sdim dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) { 621259701Sdim 622259701Sdim // Special case for the std::move function. 623259701Sdim // TODO: Make this more specific. (Deferred) 624266715Sdim if (Call->getNumArgs() == 1 && 625266715Sdim FunDecl->getNameAsString() == "move" && 626266715Sdim isStdNamespace(FunDecl->getDeclContext())) { 627259701Sdim forwardInfo(Call->getArg(0), Call); 628259701Sdim return; 629259701Sdim } 630259701Sdim 631259701Sdim unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams(); 632259701Sdim 633259701Sdim for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) { 634259701Sdim const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset); 635259701Sdim QualType ParamType = Param->getType(); 636259701Sdim 637259701Sdim InfoEntry Entry = PropagationMap.find(Call->getArg(Index)); 638259701Sdim 639259701Sdim if (Entry == PropagationMap.end() || Entry->second.isTest()) 640259701Sdim continue; 641259701Sdim 642259701Sdim PropagationInfo PInfo = Entry->second; 643259701Sdim 644259701Sdim // Check that the parameter is in the correct state. 645259701Sdim 646259701Sdim if (Param->hasAttr<ParamTypestateAttr>()) { 647259701Sdim ConsumedState ParamState = PInfo.getAsState(StateMap); 648259701Sdim 649259701Sdim ConsumedState ExpectedState = 650259701Sdim mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>()); 651259701Sdim 652259701Sdim if (ParamState != ExpectedState) 653259701Sdim Analyzer.WarningsHandler.warnParamTypestateMismatch( 654259701Sdim Call->getArg(Index - Offset)->getExprLoc(), 655259701Sdim stateToString(ExpectedState), stateToString(ParamState)); 656259701Sdim } 657259701Sdim 658259701Sdim if (!(Entry->second.isVar() || Entry->second.isTmp())) 659259701Sdim continue; 660259701Sdim 661259701Sdim // Adjust state on the caller side. 662259701Sdim 663259701Sdim if (isRValueRefish(ParamType)) { 664259701Sdim setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed); 665259701Sdim 666259701Sdim } else if (Param->hasAttr<ReturnTypestateAttr>()) { 667259701Sdim setStateForVarOrTmp(StateMap, PInfo, 668259701Sdim mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>())); 669259701Sdim 670259701Sdim } else if (!isValueType(ParamType) && 671259701Sdim !ParamType->getPointeeType().isConstQualified()) { 672259701Sdim 673259701Sdim setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown); 674259701Sdim } 675259701Sdim } 676259701Sdim 677259701Sdim QualType RetType = FunDecl->getCallResultType(); 678259701Sdim if (RetType->isReferenceType()) 679259701Sdim RetType = RetType->getPointeeType(); 680259701Sdim 681259701Sdim propagateReturnType(Call, FunDecl, RetType); 682259701Sdim } 683259701Sdim} 684259701Sdim 685259701Sdimvoid ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) { 686259701Sdim forwardInfo(Cast->getSubExpr(), Cast); 687259701Sdim} 688259701Sdim 689259701Sdimvoid ConsumedStmtVisitor::VisitCXXBindTemporaryExpr( 690259701Sdim const CXXBindTemporaryExpr *Temp) { 691259701Sdim 692259701Sdim InfoEntry Entry = PropagationMap.find(Temp->getSubExpr()); 693259701Sdim 694259701Sdim if (Entry != PropagationMap.end() && !Entry->second.isTest()) { 695259701Sdim StateMap->setState(Temp, Entry->second.getAsState(StateMap)); 696259701Sdim PropagationMap.insert(PairType(Temp, PropagationInfo(Temp))); 697259701Sdim } 698259701Sdim} 699259701Sdim 700259701Sdimvoid ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) { 701259701Sdim CXXConstructorDecl *Constructor = Call->getConstructor(); 702259701Sdim 703259701Sdim ASTContext &CurrContext = AC.getASTContext(); 704259701Sdim QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType(); 705259701Sdim 706259701Sdim if (!isConsumableType(ThisType)) 707259701Sdim return; 708259701Sdim 709259701Sdim // FIXME: What should happen if someone annotates the move constructor? 710259701Sdim if (Constructor->hasAttr<ReturnTypestateAttr>()) { 711259701Sdim // TODO: Adjust state of args appropriately. 712259701Sdim 713259701Sdim ReturnTypestateAttr *RTAttr = Constructor->getAttr<ReturnTypestateAttr>(); 714259701Sdim ConsumedState RetState = mapReturnTypestateAttrState(RTAttr); 715259701Sdim PropagationMap.insert(PairType(Call, PropagationInfo(RetState))); 716259701Sdim 717259701Sdim } else if (Constructor->isDefaultConstructor()) { 718259701Sdim 719259701Sdim PropagationMap.insert(PairType(Call, 720259701Sdim PropagationInfo(consumed::CS_Consumed))); 721259701Sdim 722259701Sdim } else if (Constructor->isMoveConstructor()) { 723259701Sdim 724259701Sdim InfoEntry Entry = PropagationMap.find(Call->getArg(0)); 725259701Sdim 726259701Sdim if (Entry != PropagationMap.end()) { 727259701Sdim PropagationInfo PInfo = Entry->second; 728259701Sdim 729259701Sdim if (PInfo.isVar()) { 730259701Sdim const VarDecl* Var = PInfo.getVar(); 731259701Sdim 732259701Sdim PropagationMap.insert(PairType(Call, 733259701Sdim PropagationInfo(StateMap->getState(Var)))); 734259701Sdim 735259701Sdim StateMap->setState(Var, consumed::CS_Consumed); 736259701Sdim 737259701Sdim } else if (PInfo.isTmp()) { 738259701Sdim const CXXBindTemporaryExpr *Tmp = PInfo.getTmp(); 739259701Sdim 740259701Sdim PropagationMap.insert(PairType(Call, 741259701Sdim PropagationInfo(StateMap->getState(Tmp)))); 742259701Sdim 743259701Sdim StateMap->setState(Tmp, consumed::CS_Consumed); 744259701Sdim 745259701Sdim } else { 746259701Sdim PropagationMap.insert(PairType(Call, PInfo)); 747259701Sdim } 748259701Sdim } 749259701Sdim } else if (Constructor->isCopyConstructor()) { 750259701Sdim forwardInfo(Call->getArg(0), Call); 751259701Sdim 752259701Sdim } else { 753259701Sdim // TODO: Adjust state of args appropriately. 754259701Sdim 755259701Sdim ConsumedState RetState = mapConsumableAttrState(ThisType); 756259701Sdim PropagationMap.insert(PairType(Call, PropagationInfo(RetState))); 757259701Sdim } 758259701Sdim} 759259701Sdim 760259701Sdimvoid ConsumedStmtVisitor::VisitCXXMemberCallExpr( 761259701Sdim const CXXMemberCallExpr *Call) { 762259701Sdim 763259701Sdim VisitCallExpr(Call); 764259701Sdim 765259701Sdim InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens()); 766259701Sdim 767259701Sdim if (Entry != PropagationMap.end()) { 768259701Sdim PropagationInfo PInfo = Entry->second; 769259701Sdim const CXXMethodDecl *MethodDecl = Call->getMethodDecl(); 770259701Sdim 771259701Sdim checkCallability(PInfo, MethodDecl, Call->getExprLoc()); 772259701Sdim 773259701Sdim if (PInfo.isVar()) { 774259701Sdim if (isTestingFunction(MethodDecl)) 775259701Sdim PropagationMap.insert(PairType(Call, 776259701Sdim PropagationInfo(PInfo.getVar(), testsFor(MethodDecl)))); 777259701Sdim else if (MethodDecl->hasAttr<SetTypestateAttr>()) 778259701Sdim StateMap->setState(PInfo.getVar(), 779259701Sdim mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>())); 780259701Sdim } else if (PInfo.isTmp() && MethodDecl->hasAttr<SetTypestateAttr>()) { 781259701Sdim StateMap->setState(PInfo.getTmp(), 782259701Sdim mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>())); 783259701Sdim } 784259701Sdim } 785259701Sdim} 786259701Sdim 787259701Sdimvoid ConsumedStmtVisitor::VisitCXXOperatorCallExpr( 788259701Sdim const CXXOperatorCallExpr *Call) { 789259701Sdim 790259701Sdim const FunctionDecl *FunDecl = 791259701Sdim dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee()); 792259701Sdim 793259701Sdim if (!FunDecl) return; 794259701Sdim 795259701Sdim if (isa<CXXMethodDecl>(FunDecl) && 796259701Sdim isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) { 797259701Sdim 798259701Sdim InfoEntry LEntry = PropagationMap.find(Call->getArg(0)); 799259701Sdim InfoEntry REntry = PropagationMap.find(Call->getArg(1)); 800259701Sdim 801259701Sdim PropagationInfo LPInfo, RPInfo; 802259701Sdim 803259701Sdim if (LEntry != PropagationMap.end() && 804259701Sdim REntry != PropagationMap.end()) { 805259701Sdim 806259701Sdim LPInfo = LEntry->second; 807259701Sdim RPInfo = REntry->second; 808259701Sdim 809259701Sdim if (LPInfo.isPointerToValue() && RPInfo.isPointerToValue()) { 810259701Sdim setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getAsState(StateMap)); 811259701Sdim PropagationMap.insert(PairType(Call, LPInfo)); 812259701Sdim setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed); 813259701Sdim 814259701Sdim } else if (RPInfo.isState()) { 815259701Sdim setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getState()); 816259701Sdim PropagationMap.insert(PairType(Call, LPInfo)); 817259701Sdim 818259701Sdim } else { 819259701Sdim setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed); 820259701Sdim } 821259701Sdim 822259701Sdim } else if (LEntry != PropagationMap.end() && 823259701Sdim REntry == PropagationMap.end()) { 824259701Sdim 825259701Sdim LPInfo = LEntry->second; 826259701Sdim 827259701Sdim assert(!LPInfo.isTest()); 828259701Sdim 829259701Sdim if (LPInfo.isPointerToValue()) { 830259701Sdim setStateForVarOrTmp(StateMap, LPInfo, consumed::CS_Unknown); 831259701Sdim PropagationMap.insert(PairType(Call, LPInfo)); 832259701Sdim 833259701Sdim } else { 834259701Sdim PropagationMap.insert(PairType(Call, 835259701Sdim PropagationInfo(consumed::CS_Unknown))); 836259701Sdim } 837259701Sdim 838259701Sdim } else if (LEntry == PropagationMap.end() && 839259701Sdim REntry != PropagationMap.end()) { 840259701Sdim 841259701Sdim RPInfo = REntry->second; 842259701Sdim 843259701Sdim if (RPInfo.isPointerToValue()) 844259701Sdim setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed); 845259701Sdim } 846259701Sdim 847259701Sdim } else { 848259701Sdim 849259701Sdim VisitCallExpr(Call); 850259701Sdim 851259701Sdim InfoEntry Entry = PropagationMap.find(Call->getArg(0)); 852259701Sdim 853259701Sdim if (Entry != PropagationMap.end()) { 854259701Sdim PropagationInfo PInfo = Entry->second; 855259701Sdim 856259701Sdim checkCallability(PInfo, FunDecl, Call->getExprLoc()); 857259701Sdim 858259701Sdim if (PInfo.isVar()) { 859259701Sdim if (isTestingFunction(FunDecl)) 860259701Sdim PropagationMap.insert(PairType(Call, 861259701Sdim PropagationInfo(PInfo.getVar(), testsFor(FunDecl)))); 862259701Sdim else if (FunDecl->hasAttr<SetTypestateAttr>()) 863259701Sdim StateMap->setState(PInfo.getVar(), 864259701Sdim mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>())); 865259701Sdim 866259701Sdim } else if (PInfo.isTmp() && FunDecl->hasAttr<SetTypestateAttr>()) { 867259701Sdim StateMap->setState(PInfo.getTmp(), 868259701Sdim mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>())); 869259701Sdim } 870259701Sdim } 871259701Sdim } 872259701Sdim} 873259701Sdim 874259701Sdimvoid ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) { 875259701Sdim if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) 876259701Sdim if (StateMap->getState(Var) != consumed::CS_None) 877259701Sdim PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var))); 878259701Sdim} 879259701Sdim 880259701Sdimvoid ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) { 881259701Sdim for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(), 882259701Sdim DE = DeclS->decl_end(); DI != DE; ++DI) { 883259701Sdim 884259701Sdim if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI)); 885259701Sdim } 886259701Sdim 887259701Sdim if (DeclS->isSingleDecl()) 888259701Sdim if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl())) 889259701Sdim PropagationMap.insert(PairType(DeclS, PropagationInfo(Var))); 890259701Sdim} 891259701Sdim 892259701Sdimvoid ConsumedStmtVisitor::VisitMaterializeTemporaryExpr( 893259701Sdim const MaterializeTemporaryExpr *Temp) { 894259701Sdim 895259701Sdim forwardInfo(Temp->GetTemporaryExpr(), Temp); 896259701Sdim} 897259701Sdim 898259701Sdimvoid ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) { 899259701Sdim forwardInfo(MExpr->getBase(), MExpr); 900259701Sdim} 901259701Sdim 902259701Sdim 903259701Sdimvoid ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) { 904259701Sdim QualType ParamType = Param->getType(); 905259701Sdim ConsumedState ParamState = consumed::CS_None; 906259701Sdim 907259701Sdim if (Param->hasAttr<ParamTypestateAttr>()) { 908259701Sdim const ParamTypestateAttr *PTAttr = Param->getAttr<ParamTypestateAttr>(); 909259701Sdim ParamState = mapParamTypestateAttrState(PTAttr); 910259701Sdim 911259701Sdim } else if (isConsumableType(ParamType)) { 912259701Sdim ParamState = mapConsumableAttrState(ParamType); 913259701Sdim 914259701Sdim } else if (isRValueRefish(ParamType) && 915259701Sdim isConsumableType(ParamType->getPointeeType())) { 916259701Sdim 917259701Sdim ParamState = mapConsumableAttrState(ParamType->getPointeeType()); 918259701Sdim 919259701Sdim } else if (ParamType->isReferenceType() && 920259701Sdim isConsumableType(ParamType->getPointeeType())) { 921259701Sdim ParamState = consumed::CS_Unknown; 922259701Sdim } 923259701Sdim 924259701Sdim if (ParamState != CS_None) 925259701Sdim StateMap->setState(Param, ParamState); 926259701Sdim} 927259701Sdim 928259701Sdimvoid ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) { 929259701Sdim ConsumedState ExpectedState = Analyzer.getExpectedReturnState(); 930259701Sdim 931259701Sdim if (ExpectedState != CS_None) { 932259701Sdim InfoEntry Entry = PropagationMap.find(Ret->getRetValue()); 933259701Sdim 934259701Sdim if (Entry != PropagationMap.end()) { 935259701Sdim ConsumedState RetState = Entry->second.getAsState(StateMap); 936259701Sdim 937259701Sdim if (RetState != ExpectedState) 938259701Sdim Analyzer.WarningsHandler.warnReturnTypestateMismatch( 939259701Sdim Ret->getReturnLoc(), stateToString(ExpectedState), 940259701Sdim stateToString(RetState)); 941259701Sdim } 942259701Sdim } 943259701Sdim 944259701Sdim StateMap->checkParamsForReturnTypestate(Ret->getLocStart(), 945259701Sdim Analyzer.WarningsHandler); 946259701Sdim} 947259701Sdim 948259701Sdimvoid ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) { 949259701Sdim InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens()); 950259701Sdim if (Entry == PropagationMap.end()) return; 951259701Sdim 952259701Sdim switch (UOp->getOpcode()) { 953259701Sdim case UO_AddrOf: 954259701Sdim PropagationMap.insert(PairType(UOp, Entry->second)); 955259701Sdim break; 956259701Sdim 957259701Sdim case UO_LNot: 958259701Sdim if (Entry->second.isTest()) 959259701Sdim PropagationMap.insert(PairType(UOp, Entry->second.invertTest())); 960259701Sdim break; 961259701Sdim 962259701Sdim default: 963259701Sdim break; 964259701Sdim } 965259701Sdim} 966259701Sdim 967259701Sdim// TODO: See if I need to check for reference types here. 968259701Sdimvoid ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) { 969259701Sdim if (isConsumableType(Var->getType())) { 970259701Sdim if (Var->hasInit()) { 971259701Sdim MapType::iterator VIT = PropagationMap.find( 972259701Sdim Var->getInit()->IgnoreImplicit()); 973259701Sdim if (VIT != PropagationMap.end()) { 974259701Sdim PropagationInfo PInfo = VIT->second; 975259701Sdim ConsumedState St = PInfo.getAsState(StateMap); 976259701Sdim 977259701Sdim if (St != consumed::CS_None) { 978259701Sdim StateMap->setState(Var, St); 979259701Sdim return; 980259701Sdim } 981259701Sdim } 982259701Sdim } 983259701Sdim // Otherwise 984259701Sdim StateMap->setState(Var, consumed::CS_Unknown); 985259701Sdim } 986259701Sdim} 987259701Sdim}} // end clang::consumed::ConsumedStmtVisitor 988259701Sdim 989259701Sdimnamespace clang { 990259701Sdimnamespace consumed { 991259701Sdim 992259701Sdimvoid splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, 993259701Sdim ConsumedStateMap *ThenStates, 994259701Sdim ConsumedStateMap *ElseStates) { 995259701Sdim 996259701Sdim ConsumedState VarState = ThenStates->getState(Test.Var); 997259701Sdim 998259701Sdim if (VarState == CS_Unknown) { 999259701Sdim ThenStates->setState(Test.Var, Test.TestsFor); 1000259701Sdim ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor)); 1001259701Sdim 1002259701Sdim } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) { 1003259701Sdim ThenStates->markUnreachable(); 1004259701Sdim 1005259701Sdim } else if (VarState == Test.TestsFor) { 1006259701Sdim ElseStates->markUnreachable(); 1007259701Sdim } 1008259701Sdim} 1009259701Sdim 1010259701Sdimvoid splitVarStateForIfBinOp(const PropagationInfo &PInfo, 1011259701Sdim ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) { 1012259701Sdim 1013259701Sdim const VarTestResult <est = PInfo.getLTest(), 1014259701Sdim &RTest = PInfo.getRTest(); 1015259701Sdim 1016259701Sdim ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None, 1017259701Sdim RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None; 1018259701Sdim 1019259701Sdim if (LTest.Var) { 1020259701Sdim if (PInfo.testEffectiveOp() == EO_And) { 1021259701Sdim if (LState == CS_Unknown) { 1022259701Sdim ThenStates->setState(LTest.Var, LTest.TestsFor); 1023259701Sdim 1024259701Sdim } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) { 1025259701Sdim ThenStates->markUnreachable(); 1026259701Sdim 1027259701Sdim } else if (LState == LTest.TestsFor && isKnownState(RState)) { 1028259701Sdim if (RState == RTest.TestsFor) 1029259701Sdim ElseStates->markUnreachable(); 1030259701Sdim else 1031259701Sdim ThenStates->markUnreachable(); 1032259701Sdim } 1033259701Sdim 1034259701Sdim } else { 1035259701Sdim if (LState == CS_Unknown) { 1036259701Sdim ElseStates->setState(LTest.Var, 1037259701Sdim invertConsumedUnconsumed(LTest.TestsFor)); 1038259701Sdim 1039259701Sdim } else if (LState == LTest.TestsFor) { 1040259701Sdim ElseStates->markUnreachable(); 1041259701Sdim 1042259701Sdim } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) && 1043259701Sdim isKnownState(RState)) { 1044259701Sdim 1045259701Sdim if (RState == RTest.TestsFor) 1046259701Sdim ElseStates->markUnreachable(); 1047259701Sdim else 1048259701Sdim ThenStates->markUnreachable(); 1049259701Sdim } 1050259701Sdim } 1051259701Sdim } 1052259701Sdim 1053259701Sdim if (RTest.Var) { 1054259701Sdim if (PInfo.testEffectiveOp() == EO_And) { 1055259701Sdim if (RState == CS_Unknown) 1056259701Sdim ThenStates->setState(RTest.Var, RTest.TestsFor); 1057259701Sdim else if (RState == invertConsumedUnconsumed(RTest.TestsFor)) 1058259701Sdim ThenStates->markUnreachable(); 1059259701Sdim 1060259701Sdim } else { 1061259701Sdim if (RState == CS_Unknown) 1062259701Sdim ElseStates->setState(RTest.Var, 1063259701Sdim invertConsumedUnconsumed(RTest.TestsFor)); 1064259701Sdim else if (RState == RTest.TestsFor) 1065259701Sdim ElseStates->markUnreachable(); 1066259701Sdim } 1067259701Sdim } 1068259701Sdim} 1069259701Sdim 1070259701Sdimbool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock, 1071259701Sdim const CFGBlock *TargetBlock) { 1072259701Sdim 1073259701Sdim assert(CurrBlock && "Block pointer must not be NULL"); 1074259701Sdim assert(TargetBlock && "TargetBlock pointer must not be NULL"); 1075259701Sdim 1076259701Sdim unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()]; 1077259701Sdim for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(), 1078259701Sdim PE = TargetBlock->pred_end(); PI != PE; ++PI) { 1079259701Sdim if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] ) 1080259701Sdim return false; 1081259701Sdim } 1082259701Sdim return true; 1083259701Sdim} 1084259701Sdim 1085259701Sdimvoid ConsumedBlockInfo::addInfo(const CFGBlock *Block, 1086259701Sdim ConsumedStateMap *StateMap, 1087259701Sdim bool &AlreadyOwned) { 1088259701Sdim 1089259701Sdim assert(Block && "Block pointer must not be NULL"); 1090259701Sdim 1091259701Sdim ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 1092259701Sdim 1093259701Sdim if (Entry) { 1094259701Sdim Entry->intersect(StateMap); 1095259701Sdim 1096259701Sdim } else if (AlreadyOwned) { 1097259701Sdim StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap); 1098259701Sdim 1099259701Sdim } else { 1100259701Sdim StateMapsArray[Block->getBlockID()] = StateMap; 1101259701Sdim AlreadyOwned = true; 1102259701Sdim } 1103259701Sdim} 1104259701Sdim 1105259701Sdimvoid ConsumedBlockInfo::addInfo(const CFGBlock *Block, 1106259701Sdim ConsumedStateMap *StateMap) { 1107259701Sdim 1108259701Sdim assert(Block != NULL && "Block pointer must not be NULL"); 1109259701Sdim 1110259701Sdim ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 1111259701Sdim 1112259701Sdim if (Entry) { 1113259701Sdim Entry->intersect(StateMap); 1114259701Sdim delete StateMap; 1115259701Sdim 1116259701Sdim } else { 1117259701Sdim StateMapsArray[Block->getBlockID()] = StateMap; 1118259701Sdim } 1119259701Sdim} 1120259701Sdim 1121259701SdimConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) { 1122259701Sdim assert(Block && "Block pointer must not be NULL"); 1123259701Sdim assert(StateMapsArray[Block->getBlockID()] && "Block has no block info"); 1124259701Sdim 1125259701Sdim return StateMapsArray[Block->getBlockID()]; 1126259701Sdim} 1127259701Sdim 1128259701Sdimvoid ConsumedBlockInfo::discardInfo(const CFGBlock *Block) { 1129259701Sdim unsigned int BlockID = Block->getBlockID(); 1130259701Sdim delete StateMapsArray[BlockID]; 1131259701Sdim StateMapsArray[BlockID] = NULL; 1132259701Sdim} 1133259701Sdim 1134259701SdimConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) { 1135259701Sdim assert(Block && "Block pointer must not be NULL"); 1136259701Sdim 1137259701Sdim ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()]; 1138259701Sdim if (isBackEdgeTarget(Block)) { 1139259701Sdim return new ConsumedStateMap(*StateMap); 1140259701Sdim } else { 1141259701Sdim StateMapsArray[Block->getBlockID()] = NULL; 1142259701Sdim return StateMap; 1143259701Sdim } 1144259701Sdim} 1145259701Sdim 1146259701Sdimbool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) { 1147259701Sdim assert(From && "From block must not be NULL"); 1148259701Sdim assert(To && "From block must not be NULL"); 1149259701Sdim 1150259701Sdim return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()]; 1151259701Sdim} 1152259701Sdim 1153259701Sdimbool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) { 1154259701Sdim assert(Block != NULL && "Block pointer must not be NULL"); 1155259701Sdim 1156259701Sdim // Anything with less than two predecessors can't be the target of a back 1157259701Sdim // edge. 1158259701Sdim if (Block->pred_size() < 2) 1159259701Sdim return false; 1160259701Sdim 1161259701Sdim unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()]; 1162259701Sdim for (CFGBlock::const_pred_iterator PI = Block->pred_begin(), 1163259701Sdim PE = Block->pred_end(); PI != PE; ++PI) { 1164259701Sdim if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()]) 1165259701Sdim return true; 1166259701Sdim } 1167259701Sdim return false; 1168259701Sdim} 1169259701Sdim 1170259701Sdimvoid ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc, 1171259701Sdim ConsumedWarningsHandlerBase &WarningsHandler) const { 1172259701Sdim 1173259701Sdim ConsumedState ExpectedState; 1174259701Sdim 1175259701Sdim for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end(); 1176259701Sdim DMI != DME; ++DMI) { 1177259701Sdim 1178259701Sdim if (isa<ParmVarDecl>(DMI->first)) { 1179259701Sdim const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first); 1180259701Sdim 1181259701Sdim if (!Param->hasAttr<ReturnTypestateAttr>()) continue; 1182259701Sdim 1183259701Sdim ExpectedState = 1184259701Sdim mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()); 1185259701Sdim 1186259701Sdim if (DMI->second != ExpectedState) { 1187259701Sdim WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc, 1188259701Sdim Param->getNameAsString(), stateToString(ExpectedState), 1189259701Sdim stateToString(DMI->second)); 1190259701Sdim } 1191259701Sdim } 1192259701Sdim } 1193259701Sdim} 1194259701Sdim 1195259701Sdimvoid ConsumedStateMap::clearTemporaries() { 1196259701Sdim TmpMap.clear(); 1197259701Sdim} 1198259701Sdim 1199259701SdimConsumedState ConsumedStateMap::getState(const VarDecl *Var) const { 1200259701Sdim VarMapType::const_iterator Entry = VarMap.find(Var); 1201259701Sdim 1202259701Sdim if (Entry != VarMap.end()) 1203259701Sdim return Entry->second; 1204259701Sdim 1205259701Sdim return CS_None; 1206259701Sdim} 1207259701Sdim 1208259701SdimConsumedState 1209259701SdimConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const { 1210259701Sdim TmpMapType::const_iterator Entry = TmpMap.find(Tmp); 1211259701Sdim 1212259701Sdim if (Entry != TmpMap.end()) 1213259701Sdim return Entry->second; 1214259701Sdim 1215259701Sdim return CS_None; 1216259701Sdim} 1217259701Sdim 1218259701Sdimvoid ConsumedStateMap::intersect(const ConsumedStateMap *Other) { 1219259701Sdim ConsumedState LocalState; 1220259701Sdim 1221259701Sdim if (this->From && this->From == Other->From && !Other->Reachable) { 1222259701Sdim this->markUnreachable(); 1223259701Sdim return; 1224259701Sdim } 1225259701Sdim 1226259701Sdim for (VarMapType::const_iterator DMI = Other->VarMap.begin(), 1227259701Sdim DME = Other->VarMap.end(); DMI != DME; ++DMI) { 1228259701Sdim 1229259701Sdim LocalState = this->getState(DMI->first); 1230259701Sdim 1231259701Sdim if (LocalState == CS_None) 1232259701Sdim continue; 1233259701Sdim 1234259701Sdim if (LocalState != DMI->second) 1235259701Sdim VarMap[DMI->first] = CS_Unknown; 1236259701Sdim } 1237259701Sdim} 1238259701Sdim 1239259701Sdimvoid ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead, 1240259701Sdim const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates, 1241259701Sdim ConsumedWarningsHandlerBase &WarningsHandler) { 1242259701Sdim 1243259701Sdim ConsumedState LocalState; 1244259701Sdim SourceLocation BlameLoc = getLastStmtLoc(LoopBack); 1245259701Sdim 1246259701Sdim for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(), 1247259701Sdim DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) { 1248259701Sdim 1249259701Sdim LocalState = this->getState(DMI->first); 1250259701Sdim 1251259701Sdim if (LocalState == CS_None) 1252259701Sdim continue; 1253259701Sdim 1254259701Sdim if (LocalState != DMI->second) { 1255259701Sdim VarMap[DMI->first] = CS_Unknown; 1256259701Sdim WarningsHandler.warnLoopStateMismatch( 1257259701Sdim BlameLoc, DMI->first->getNameAsString()); 1258259701Sdim } 1259259701Sdim } 1260259701Sdim} 1261259701Sdim 1262259701Sdimvoid ConsumedStateMap::markUnreachable() { 1263259701Sdim this->Reachable = false; 1264259701Sdim VarMap.clear(); 1265259701Sdim TmpMap.clear(); 1266259701Sdim} 1267259701Sdim 1268259701Sdimvoid ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) { 1269259701Sdim VarMap[Var] = State; 1270259701Sdim} 1271259701Sdim 1272259701Sdimvoid ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp, 1273259701Sdim ConsumedState State) { 1274259701Sdim TmpMap[Tmp] = State; 1275259701Sdim} 1276259701Sdim 1277259701Sdimvoid ConsumedStateMap::remove(const VarDecl *Var) { 1278259701Sdim VarMap.erase(Var); 1279259701Sdim} 1280259701Sdim 1281259701Sdimbool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const { 1282259701Sdim for (VarMapType::const_iterator DMI = Other->VarMap.begin(), 1283259701Sdim DME = Other->VarMap.end(); DMI != DME; ++DMI) { 1284259701Sdim 1285259701Sdim if (this->getState(DMI->first) != DMI->second) 1286259701Sdim return true; 1287259701Sdim } 1288259701Sdim 1289259701Sdim return false; 1290259701Sdim} 1291259701Sdim 1292259701Sdimvoid ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC, 1293259701Sdim const FunctionDecl *D) { 1294259701Sdim QualType ReturnType; 1295259701Sdim if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { 1296259701Sdim ASTContext &CurrContext = AC.getASTContext(); 1297259701Sdim ReturnType = Constructor->getThisType(CurrContext)->getPointeeType(); 1298259701Sdim } else 1299259701Sdim ReturnType = D->getCallResultType(); 1300259701Sdim 1301259701Sdim if (D->hasAttr<ReturnTypestateAttr>()) { 1302259701Sdim const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>(); 1303259701Sdim 1304259701Sdim const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); 1305259701Sdim if (!RD || !RD->hasAttr<ConsumableAttr>()) { 1306259701Sdim // FIXME: This should be removed when template instantiation propagates 1307259701Sdim // attributes at template specialization definition, not 1308259701Sdim // declaration. When it is removed the test needs to be enabled 1309259701Sdim // in SemaDeclAttr.cpp. 1310259701Sdim WarningsHandler.warnReturnTypestateForUnconsumableType( 1311259701Sdim RTSAttr->getLocation(), ReturnType.getAsString()); 1312259701Sdim ExpectedReturnState = CS_None; 1313259701Sdim } else 1314259701Sdim ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr); 1315259701Sdim } else if (isConsumableType(ReturnType)) 1316259701Sdim ExpectedReturnState = mapConsumableAttrState(ReturnType); 1317259701Sdim else 1318259701Sdim ExpectedReturnState = CS_None; 1319259701Sdim} 1320259701Sdim 1321259701Sdimbool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock, 1322259701Sdim const ConsumedStmtVisitor &Visitor) { 1323259701Sdim 1324259701Sdim OwningPtr<ConsumedStateMap> FalseStates(new ConsumedStateMap(*CurrStates)); 1325259701Sdim PropagationInfo PInfo; 1326259701Sdim 1327259701Sdim if (const IfStmt *IfNode = 1328259701Sdim dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) { 1329259701Sdim 1330259701Sdim const Stmt *Cond = IfNode->getCond(); 1331259701Sdim 1332259701Sdim PInfo = Visitor.getInfo(Cond); 1333259701Sdim if (!PInfo.isValid() && isa<BinaryOperator>(Cond)) 1334259701Sdim PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS()); 1335259701Sdim 1336259701Sdim if (PInfo.isVarTest()) { 1337259701Sdim CurrStates->setSource(Cond); 1338259701Sdim FalseStates->setSource(Cond); 1339259701Sdim splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates, 1340259701Sdim FalseStates.get()); 1341259701Sdim 1342259701Sdim } else if (PInfo.isBinTest()) { 1343259701Sdim CurrStates->setSource(PInfo.testSourceNode()); 1344259701Sdim FalseStates->setSource(PInfo.testSourceNode()); 1345259701Sdim splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get()); 1346259701Sdim 1347259701Sdim } else { 1348259701Sdim return false; 1349259701Sdim } 1350259701Sdim 1351259701Sdim } else if (const BinaryOperator *BinOp = 1352259701Sdim dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) { 1353259701Sdim 1354259701Sdim PInfo = Visitor.getInfo(BinOp->getLHS()); 1355259701Sdim if (!PInfo.isVarTest()) { 1356259701Sdim if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) { 1357259701Sdim PInfo = Visitor.getInfo(BinOp->getRHS()); 1358259701Sdim 1359259701Sdim if (!PInfo.isVarTest()) 1360259701Sdim return false; 1361259701Sdim 1362259701Sdim } else { 1363259701Sdim return false; 1364259701Sdim } 1365259701Sdim } 1366259701Sdim 1367259701Sdim CurrStates->setSource(BinOp); 1368259701Sdim FalseStates->setSource(BinOp); 1369259701Sdim 1370259701Sdim const VarTestResult &Test = PInfo.getVarTest(); 1371259701Sdim ConsumedState VarState = CurrStates->getState(Test.Var); 1372259701Sdim 1373259701Sdim if (BinOp->getOpcode() == BO_LAnd) { 1374259701Sdim if (VarState == CS_Unknown) 1375259701Sdim CurrStates->setState(Test.Var, Test.TestsFor); 1376259701Sdim else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) 1377259701Sdim CurrStates->markUnreachable(); 1378259701Sdim 1379259701Sdim } else if (BinOp->getOpcode() == BO_LOr) { 1380259701Sdim if (VarState == CS_Unknown) 1381259701Sdim FalseStates->setState(Test.Var, 1382259701Sdim invertConsumedUnconsumed(Test.TestsFor)); 1383259701Sdim else if (VarState == Test.TestsFor) 1384259701Sdim FalseStates->markUnreachable(); 1385259701Sdim } 1386259701Sdim 1387259701Sdim } else { 1388259701Sdim return false; 1389259701Sdim } 1390259701Sdim 1391259701Sdim CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(); 1392259701Sdim 1393259701Sdim if (*SI) 1394259701Sdim BlockInfo.addInfo(*SI, CurrStates); 1395259701Sdim else 1396259701Sdim delete CurrStates; 1397259701Sdim 1398259701Sdim if (*++SI) 1399259701Sdim BlockInfo.addInfo(*SI, FalseStates.take()); 1400259701Sdim 1401259701Sdim CurrStates = NULL; 1402259701Sdim return true; 1403259701Sdim} 1404259701Sdim 1405259701Sdimvoid ConsumedAnalyzer::run(AnalysisDeclContext &AC) { 1406259701Sdim const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl()); 1407259701Sdim if (!D) 1408259701Sdim return; 1409259701Sdim 1410259701Sdim CFG *CFGraph = AC.getCFG(); 1411259701Sdim if (!CFGraph) 1412259701Sdim return; 1413259701Sdim 1414259701Sdim determineExpectedReturnState(AC, D); 1415259701Sdim 1416259701Sdim PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>(); 1417259701Sdim // AC.getCFG()->viewCFG(LangOptions()); 1418259701Sdim 1419259701Sdim BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph); 1420259701Sdim 1421259701Sdim CurrStates = new ConsumedStateMap(); 1422259701Sdim ConsumedStmtVisitor Visitor(AC, *this, CurrStates); 1423259701Sdim 1424259701Sdim // Add all trackable parameters to the state map. 1425259701Sdim for (FunctionDecl::param_const_iterator PI = D->param_begin(), 1426259701Sdim PE = D->param_end(); PI != PE; ++PI) { 1427259701Sdim Visitor.VisitParmVarDecl(*PI); 1428259701Sdim } 1429259701Sdim 1430259701Sdim // Visit all of the function's basic blocks. 1431259701Sdim for (PostOrderCFGView::iterator I = SortedGraph->begin(), 1432259701Sdim E = SortedGraph->end(); I != E; ++I) { 1433259701Sdim 1434259701Sdim const CFGBlock *CurrBlock = *I; 1435259701Sdim 1436259701Sdim if (CurrStates == NULL) 1437259701Sdim CurrStates = BlockInfo.getInfo(CurrBlock); 1438259701Sdim 1439259701Sdim if (!CurrStates) { 1440259701Sdim continue; 1441259701Sdim 1442259701Sdim } else if (!CurrStates->isReachable()) { 1443259701Sdim delete CurrStates; 1444259701Sdim CurrStates = NULL; 1445259701Sdim continue; 1446259701Sdim } 1447259701Sdim 1448259701Sdim Visitor.reset(CurrStates); 1449259701Sdim 1450259701Sdim // Visit all of the basic block's statements. 1451259701Sdim for (CFGBlock::const_iterator BI = CurrBlock->begin(), 1452259701Sdim BE = CurrBlock->end(); BI != BE; ++BI) { 1453259701Sdim 1454259701Sdim switch (BI->getKind()) { 1455259701Sdim case CFGElement::Statement: 1456259701Sdim Visitor.Visit(BI->castAs<CFGStmt>().getStmt()); 1457259701Sdim break; 1458259701Sdim 1459259701Sdim case CFGElement::TemporaryDtor: { 1460259701Sdim const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>(); 1461259701Sdim const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr(); 1462259701Sdim 1463259701Sdim Visitor.checkCallability(PropagationInfo(BTE), 1464259701Sdim DTor.getDestructorDecl(AC.getASTContext()), 1465259701Sdim BTE->getExprLoc()); 1466259701Sdim break; 1467259701Sdim } 1468259701Sdim 1469259701Sdim case CFGElement::AutomaticObjectDtor: { 1470259701Sdim const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>(); 1471259701Sdim SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd(); 1472259701Sdim const VarDecl *Var = DTor.getVarDecl(); 1473259701Sdim 1474259701Sdim Visitor.checkCallability(PropagationInfo(Var), 1475259701Sdim DTor.getDestructorDecl(AC.getASTContext()), 1476259701Sdim Loc); 1477259701Sdim break; 1478259701Sdim } 1479259701Sdim 1480259701Sdim default: 1481259701Sdim break; 1482259701Sdim } 1483259701Sdim } 1484259701Sdim 1485259701Sdim CurrStates->clearTemporaries(); 1486259701Sdim 1487259701Sdim // TODO: Handle other forms of branching with precision, including while- 1488259701Sdim // and for-loops. (Deferred) 1489259701Sdim if (!splitState(CurrBlock, Visitor)) { 1490259701Sdim CurrStates->setSource(NULL); 1491259701Sdim 1492259701Sdim if (CurrBlock->succ_size() > 1 || 1493259701Sdim (CurrBlock->succ_size() == 1 && 1494259701Sdim (*CurrBlock->succ_begin())->pred_size() > 1)) { 1495259701Sdim 1496259701Sdim bool OwnershipTaken = false; 1497259701Sdim 1498259701Sdim for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), 1499259701Sdim SE = CurrBlock->succ_end(); SI != SE; ++SI) { 1500259701Sdim 1501259701Sdim if (*SI == NULL) continue; 1502259701Sdim 1503259701Sdim if (BlockInfo.isBackEdge(CurrBlock, *SI)) { 1504259701Sdim BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock, 1505259701Sdim CurrStates, 1506259701Sdim WarningsHandler); 1507259701Sdim 1508259701Sdim if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock)) 1509259701Sdim BlockInfo.discardInfo(*SI); 1510259701Sdim } else { 1511259701Sdim BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken); 1512259701Sdim } 1513259701Sdim } 1514259701Sdim 1515259701Sdim if (!OwnershipTaken) 1516259701Sdim delete CurrStates; 1517259701Sdim 1518259701Sdim CurrStates = NULL; 1519259701Sdim } 1520259701Sdim } 1521259701Sdim 1522259701Sdim if (CurrBlock == &AC.getCFG()->getExit() && 1523259701Sdim D->getCallResultType()->isVoidType()) 1524259701Sdim CurrStates->checkParamsForReturnTypestate(D->getLocation(), 1525259701Sdim WarningsHandler); 1526259701Sdim } // End of block iterator. 1527259701Sdim 1528259701Sdim // Delete the last existing state map. 1529259701Sdim delete CurrStates; 1530259701Sdim 1531259701Sdim WarningsHandler.emitDiagnostics(); 1532259701Sdim} 1533259701Sdim}} // end namespace clang::consumed 1534