xref: /llvm-project/clang/lib/Analysis/Consumed.cpp (revision 36ea1dd4fc5e193d0eb7f6bf69f15d3779b6da24)
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 
48 using namespace clang;
49 using namespace consumed;
50 
51 // Key method definition
52 ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
53 
54 static 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 
71 static 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 
98 static 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 
112 static 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 
143 static bool isConsumableType(const QualType &QT) {
144   if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
145     return RD->hasAttr<ConsumableAttr>();
146   else
147     return false;
148 }
149 
150 static 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 
162 static bool isTestingFunction(const FunctionDecl *FunDecl) {
163   return FunDecl->hasAttr<TestsTypestateAttr>();
164 }
165 
166 static 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 
183 static 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 
195 static ConsumedState
196 mapReturnTypestateAttrState(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 
208 static 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 
225 static 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 
236 namespace {
237 struct VarTestResult {
238   const VarDecl *Var;
239   ConsumedState TestsFor;
240 };
241 } // end anonymous::VarTestResult
242 
243 namespace clang {
244 namespace consumed {
245 
246 enum EffectiveOp {
247   EO_And,
248   EO_Or
249 };
250 
251 class 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 
276 public:
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 
378 class 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 
394 public:
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 
435 void 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 
469 void 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 
476 bool 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 
485 void 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 
503 void 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 
514 void 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 
556 void 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 
613 void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
614   forwardInfo(Cast->getSubExpr(), Cast);
615 }
616 
617 void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
618   const CXXBindTemporaryExpr *Temp) {
619 
620   forwardInfo(Temp->getSubExpr(), Temp);
621 }
622 
623 void 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 
665 void 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 
689 void 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 
780 void 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 
786 void 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 
798 void 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 
807 void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
808   forwardInfo(MExpr->getBase(), MExpr);
809 }
810 
811 
812 void 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 
827 void 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 
850 void 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.
870 void 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 
886 namespace clang {
887 namespace consumed {
888 
889 void 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 
907 void 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 
967 bool 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 
982 void 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 
1002 void 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 
1018 ConsumedStateMap* 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 
1025 void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1026   unsigned int BlockID = Block->getBlockID();
1027   delete StateMapsArray[BlockID];
1028   StateMapsArray[BlockID] = NULL;
1029 }
1030 
1031 ConsumedStateMap* 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 
1043 bool 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 
1050 bool 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 
1067 void 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 
1092 ConsumedState 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 
1103 void 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 
1124 void 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 
1147 void ConsumedStateMap::markUnreachable() {
1148   this->Reachable = false;
1149   Map.clear();
1150 }
1151 
1152 void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1153   Map[Var] = State;
1154 }
1155 
1156 void ConsumedStateMap::remove(const VarDecl *Var) {
1157   Map.erase(Var);
1158 }
1159 
1160 bool 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 
1171 void 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 
1200 bool 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 
1290 void 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