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