xref: /llvm-project/clang/lib/Analysis/Consumed.cpp (revision 6501320e723a63bcbadf49c9e9dd4cfde904619e)
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       QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
576 
577       InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
578 
579       if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
580         continue;
581       }
582 
583       PropagationInfo PInfo = Entry->second;
584 
585       if (ParamType->isRValueReferenceType() ||
586           (ParamType->isLValueReferenceType() &&
587            !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
588 
589         StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
590 
591       } else if (!(ParamType.isConstQualified() ||
592                    ((ParamType->isReferenceType() ||
593                      ParamType->isPointerType()) &&
594                     ParamType->getPointeeType().isConstQualified()))) {
595 
596         StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
597       }
598     }
599 
600     QualType RetType = FunDecl->getCallResultType();
601     if (RetType->isReferenceType())
602       RetType = RetType->getPointeeType();
603 
604     propagateReturnType(Call, FunDecl, RetType);
605   }
606 }
607 
608 void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
609   forwardInfo(Cast->getSubExpr(), Cast);
610 }
611 
612 void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
613   const CXXBindTemporaryExpr *Temp) {
614 
615   forwardInfo(Temp->getSubExpr(), Temp);
616 }
617 
618 void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
619   CXXConstructorDecl *Constructor = Call->getConstructor();
620 
621   ASTContext &CurrContext = AC.getASTContext();
622   QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
623 
624   if (isConsumableType(ThisType)) {
625     if (Constructor->isDefaultConstructor()) {
626 
627       PropagationMap.insert(PairType(Call,
628         PropagationInfo(consumed::CS_Consumed, ThisType)));
629 
630     } else if (Constructor->isMoveConstructor()) {
631 
632       PropagationInfo PInfo =
633         PropagationMap.find(Call->getArg(0))->second;
634 
635       if (PInfo.isVar()) {
636         const VarDecl* Var = PInfo.getVar();
637 
638         PropagationMap.insert(PairType(Call,
639           PropagationInfo(StateMap->getState(Var), ThisType)));
640 
641         StateMap->setState(Var, consumed::CS_Consumed);
642 
643       } else {
644         PropagationMap.insert(PairType(Call, PInfo));
645       }
646 
647     } else if (Constructor->isCopyConstructor()) {
648       MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
649 
650       if (Entry != PropagationMap.end())
651         PropagationMap.insert(PairType(Call, Entry->second));
652 
653     } else {
654       propagateReturnType(Call, Constructor, ThisType);
655     }
656   }
657 }
658 
659 
660 void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
661   const CXXMemberCallExpr *Call) {
662 
663   VisitCallExpr(Call);
664 
665   InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
666 
667   if (Entry != PropagationMap.end()) {
668     PropagationInfo PInfo = Entry->second;
669     const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
670 
671     checkCallability(PInfo, MethodDecl, Call->getExprLoc());
672 
673     if (PInfo.isVar()) {
674       if (isTestingFunction(MethodDecl))
675         PropagationMap.insert(PairType(Call,
676           PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
677       else if (MethodDecl->hasAttr<SetTypestateAttr>())
678         StateMap->setState(PInfo.getVar(),
679           mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
680     }
681   }
682 }
683 
684 void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
685   const CXXOperatorCallExpr *Call) {
686 
687   const FunctionDecl *FunDecl =
688     dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
689 
690   if (!FunDecl) return;
691 
692   if (isa<CXXMethodDecl>(FunDecl) &&
693       isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
694 
695     InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
696     InfoEntry REntry = PropagationMap.find(Call->getArg(1));
697 
698     PropagationInfo LPInfo, RPInfo;
699 
700     if (LEntry != PropagationMap.end() &&
701         REntry != PropagationMap.end()) {
702 
703       LPInfo = LEntry->second;
704       RPInfo = REntry->second;
705 
706       if (LPInfo.isVar() && RPInfo.isVar()) {
707         StateMap->setState(LPInfo.getVar(),
708           StateMap->getState(RPInfo.getVar()));
709 
710         StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
711 
712         PropagationMap.insert(PairType(Call, LPInfo));
713 
714       } else if (LPInfo.isVar() && !RPInfo.isVar()) {
715         StateMap->setState(LPInfo.getVar(), RPInfo.getState());
716 
717         PropagationMap.insert(PairType(Call, LPInfo));
718 
719       } else if (!LPInfo.isVar() && RPInfo.isVar()) {
720         PropagationMap.insert(PairType(Call,
721           PropagationInfo(StateMap->getState(RPInfo.getVar()),
722                           LPInfo.getTempType())));
723 
724         StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
725 
726       } else {
727         PropagationMap.insert(PairType(Call, RPInfo));
728       }
729 
730     } else if (LEntry != PropagationMap.end() &&
731                REntry == PropagationMap.end()) {
732 
733       LPInfo = LEntry->second;
734 
735       if (LPInfo.isVar()) {
736         StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
737 
738         PropagationMap.insert(PairType(Call, LPInfo));
739 
740       } else if (LPInfo.isState()) {
741         PropagationMap.insert(PairType(Call,
742           PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
743       }
744 
745     } else if (LEntry == PropagationMap.end() &&
746                REntry != PropagationMap.end()) {
747 
748       if (REntry->second.isVar())
749         StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
750     }
751 
752   } else {
753 
754     VisitCallExpr(Call);
755 
756     InfoEntry Entry = PropagationMap.find(Call->getArg(0));
757 
758     if (Entry != PropagationMap.end()) {
759       PropagationInfo PInfo = Entry->second;
760 
761       checkCallability(PInfo, FunDecl, Call->getExprLoc());
762 
763       if (PInfo.isVar()) {
764         if (isTestingFunction(FunDecl))
765           PropagationMap.insert(PairType(Call,
766             PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
767         else if (FunDecl->hasAttr<SetTypestateAttr>())
768           StateMap->setState(PInfo.getVar(),
769             mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
770       }
771     }
772   }
773 }
774 
775 void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
776   if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
777     if (StateMap->getState(Var) != consumed::CS_None)
778       PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
779 }
780 
781 void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
782   for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
783        DE = DeclS->decl_end(); DI != DE; ++DI) {
784 
785     if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
786   }
787 
788   if (DeclS->isSingleDecl())
789     if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
790       PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
791 }
792 
793 void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
794   const MaterializeTemporaryExpr *Temp) {
795 
796   InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
797 
798   if (Entry != PropagationMap.end())
799     PropagationMap.insert(PairType(Temp, Entry->second));
800 }
801 
802 void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
803   forwardInfo(MExpr->getBase(), MExpr);
804 }
805 
806 
807 void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
808   QualType ParamType = Param->getType();
809   ConsumedState ParamState = consumed::CS_None;
810 
811   if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
812       isConsumableType(ParamType))
813     ParamState = mapConsumableAttrState(ParamType);
814   else if (ParamType->isReferenceType() &&
815            isConsumableType(ParamType->getPointeeType()))
816     ParamState = consumed::CS_Unknown;
817 
818   if (ParamState)
819     StateMap->setState(Param, ParamState);
820 }
821 
822 void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
823   if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
824     InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
825 
826     if (Entry != PropagationMap.end()) {
827       assert(Entry->second.isState() || Entry->second.isVar());
828 
829       ConsumedState RetState = Entry->second.isState() ?
830         Entry->second.getState() : StateMap->getState(Entry->second.getVar());
831 
832       if (RetState != ExpectedState)
833         Analyzer.WarningsHandler.warnReturnTypestateMismatch(
834           Ret->getReturnLoc(), stateToString(ExpectedState),
835           stateToString(RetState));
836     }
837   }
838 }
839 
840 void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
841   InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
842   if (Entry == PropagationMap.end()) return;
843 
844   switch (UOp->getOpcode()) {
845   case UO_AddrOf:
846     PropagationMap.insert(PairType(UOp, Entry->second));
847     break;
848 
849   case UO_LNot:
850     if (Entry->second.isTest() || Entry->second.isBinTest())
851       PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
852     break;
853 
854   default:
855     break;
856   }
857 }
858 
859 // TODO: See if I need to check for reference types here.
860 void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
861   if (isConsumableType(Var->getType())) {
862     if (Var->hasInit()) {
863       PropagationInfo PInfo =
864         PropagationMap.find(Var->getInit())->second;
865 
866       StateMap->setState(Var, PInfo.isVar() ?
867         StateMap->getState(PInfo.getVar()) : PInfo.getState());
868 
869     } else {
870       StateMap->setState(Var, consumed::CS_Unknown);
871     }
872   }
873 }
874 }} // end clang::consumed::ConsumedStmtVisitor
875 
876 namespace clang {
877 namespace consumed {
878 
879 void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
880                         ConsumedStateMap *ThenStates,
881                         ConsumedStateMap *ElseStates) {
882 
883   ConsumedState VarState = ThenStates->getState(Test.Var);
884 
885   if (VarState == CS_Unknown) {
886     ThenStates->setState(Test.Var, Test.TestsFor);
887     ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
888 
889   } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
890     ThenStates->markUnreachable();
891 
892   } else if (VarState == Test.TestsFor) {
893     ElseStates->markUnreachable();
894   }
895 }
896 
897 void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
898   ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
899 
900   const VarTestResult &LTest = PInfo.getLTest(),
901                       &RTest = PInfo.getRTest();
902 
903   ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
904                 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
905 
906   if (LTest.Var) {
907     if (PInfo.testEffectiveOp() == EO_And) {
908       if (LState == CS_Unknown) {
909         ThenStates->setState(LTest.Var, LTest.TestsFor);
910 
911       } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
912         ThenStates->markUnreachable();
913 
914       } else if (LState == LTest.TestsFor && isKnownState(RState)) {
915         if (RState == RTest.TestsFor)
916           ElseStates->markUnreachable();
917         else
918           ThenStates->markUnreachable();
919       }
920 
921     } else {
922       if (LState == CS_Unknown) {
923         ElseStates->setState(LTest.Var,
924                              invertConsumedUnconsumed(LTest.TestsFor));
925 
926       } else if (LState == LTest.TestsFor) {
927         ElseStates->markUnreachable();
928 
929       } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
930                  isKnownState(RState)) {
931 
932         if (RState == RTest.TestsFor)
933           ElseStates->markUnreachable();
934         else
935           ThenStates->markUnreachable();
936       }
937     }
938   }
939 
940   if (RTest.Var) {
941     if (PInfo.testEffectiveOp() == EO_And) {
942       if (RState == CS_Unknown)
943         ThenStates->setState(RTest.Var, RTest.TestsFor);
944       else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
945         ThenStates->markUnreachable();
946 
947     } else {
948       if (RState == CS_Unknown)
949         ElseStates->setState(RTest.Var,
950                              invertConsumedUnconsumed(RTest.TestsFor));
951       else if (RState == RTest.TestsFor)
952         ElseStates->markUnreachable();
953     }
954   }
955 }
956 
957 bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
958                                             const CFGBlock *TargetBlock) {
959 
960   assert(CurrBlock && "Block pointer must not be NULL");
961   assert(TargetBlock && "TargetBlock pointer must not be NULL");
962 
963   unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
964   for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
965        PE = TargetBlock->pred_end(); PI != PE; ++PI) {
966     if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
967       return false;
968   }
969   return true;
970 }
971 
972 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
973                                 ConsumedStateMap *StateMap,
974                                 bool &AlreadyOwned) {
975 
976   assert(Block && "Block pointer must not be NULL");
977 
978   ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
979 
980   if (Entry) {
981     Entry->intersect(StateMap);
982 
983   } else if (AlreadyOwned) {
984     StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
985 
986   } else {
987     StateMapsArray[Block->getBlockID()] = StateMap;
988     AlreadyOwned = true;
989   }
990 }
991 
992 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
993                                 ConsumedStateMap *StateMap) {
994 
995   assert(Block != NULL && "Block pointer must not be NULL");
996 
997   ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
998 
999   if (Entry) {
1000     Entry->intersect(StateMap);
1001     delete StateMap;
1002 
1003   } else {
1004     StateMapsArray[Block->getBlockID()] = StateMap;
1005   }
1006 }
1007 
1008 ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1009   assert(Block && "Block pointer must not be NULL");
1010   assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1011 
1012   return StateMapsArray[Block->getBlockID()];
1013 }
1014 
1015 void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1016   unsigned int BlockID = Block->getBlockID();
1017   delete StateMapsArray[BlockID];
1018   StateMapsArray[BlockID] = NULL;
1019 }
1020 
1021 ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1022   assert(Block && "Block pointer must not be NULL");
1023 
1024   ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1025   if (isBackEdgeTarget(Block)) {
1026     return new ConsumedStateMap(*StateMap);
1027   } else {
1028     StateMapsArray[Block->getBlockID()] = NULL;
1029     return StateMap;
1030   }
1031 }
1032 
1033 bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1034   assert(From && "From block must not be NULL");
1035   assert(To   && "From block must not be NULL");
1036 
1037   return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1038 }
1039 
1040 bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1041   assert(Block != NULL && "Block pointer must not be NULL");
1042 
1043   // Anything with less than two predecessors can't be the target of a back
1044   // edge.
1045   if (Block->pred_size() < 2)
1046     return false;
1047 
1048   unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1049   for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1050        PE = Block->pred_end(); PI != PE; ++PI) {
1051     if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1052       return true;
1053   }
1054   return false;
1055 }
1056 
1057 ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
1058   MapType::const_iterator Entry = Map.find(Var);
1059 
1060   if (Entry != Map.end()) {
1061     return Entry->second;
1062 
1063   } else {
1064     return CS_None;
1065   }
1066 }
1067 
1068 void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1069   ConsumedState LocalState;
1070 
1071   if (this->From && this->From == Other->From && !Other->Reachable) {
1072     this->markUnreachable();
1073     return;
1074   }
1075 
1076   for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1077        DMI != DME; ++DMI) {
1078 
1079     LocalState = this->getState(DMI->first);
1080 
1081     if (LocalState == CS_None)
1082       continue;
1083 
1084     if (LocalState != DMI->second)
1085        Map[DMI->first] = CS_Unknown;
1086   }
1087 }
1088 
1089 void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1090   const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1091   ConsumedWarningsHandlerBase &WarningsHandler) {
1092 
1093   ConsumedState LocalState;
1094   SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
1095 
1096   for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1097        DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1098 
1099     LocalState = this->getState(DMI->first);
1100 
1101     if (LocalState == CS_None)
1102       continue;
1103 
1104     if (LocalState != DMI->second) {
1105       Map[DMI->first] = CS_Unknown;
1106       WarningsHandler.warnLoopStateMismatch(
1107         BlameLoc, DMI->first->getNameAsString());
1108     }
1109   }
1110 }
1111 
1112 void ConsumedStateMap::markUnreachable() {
1113   this->Reachable = false;
1114   Map.clear();
1115 }
1116 
1117 void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1118   Map[Var] = State;
1119 }
1120 
1121 void ConsumedStateMap::remove(const VarDecl *Var) {
1122   Map.erase(Var);
1123 }
1124 
1125 bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1126   for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1127        DMI != DME; ++DMI) {
1128 
1129     if (this->getState(DMI->first) != DMI->second)
1130       return true;
1131   }
1132 
1133   return false;
1134 }
1135 
1136 void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1137                                                     const FunctionDecl *D) {
1138   QualType ReturnType;
1139   if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1140     ASTContext &CurrContext = AC.getASTContext();
1141     ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1142   } else
1143     ReturnType = D->getCallResultType();
1144 
1145   if (D->hasAttr<ReturnTypestateAttr>()) {
1146     const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1147 
1148     const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1149     if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1150       // FIXME: This should be removed when template instantiation propagates
1151       //        attributes at template specialization definition, not
1152       //        declaration. When it is removed the test needs to be enabled
1153       //        in SemaDeclAttr.cpp.
1154       WarningsHandler.warnReturnTypestateForUnconsumableType(
1155           RTSAttr->getLocation(), ReturnType.getAsString());
1156       ExpectedReturnState = CS_None;
1157     } else
1158       ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1159   } else if (isConsumableType(ReturnType))
1160     ExpectedReturnState = mapConsumableAttrState(ReturnType);
1161   else
1162     ExpectedReturnState = CS_None;
1163 }
1164 
1165 bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1166                                   const ConsumedStmtVisitor &Visitor) {
1167 
1168   ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1169   PropagationInfo PInfo;
1170 
1171   if (const IfStmt *IfNode =
1172     dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
1173 
1174     const Stmt *Cond = IfNode->getCond();
1175 
1176     PInfo = Visitor.getInfo(Cond);
1177     if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1178       PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1179 
1180     if (PInfo.isTest()) {
1181       CurrStates->setSource(Cond);
1182       FalseStates->setSource(Cond);
1183       splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
1184 
1185     } else if (PInfo.isBinTest()) {
1186       CurrStates->setSource(PInfo.testSourceNode());
1187       FalseStates->setSource(PInfo.testSourceNode());
1188       splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
1189 
1190     } else {
1191       delete FalseStates;
1192       return false;
1193     }
1194 
1195   } else if (const BinaryOperator *BinOp =
1196     dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1197 
1198     PInfo = Visitor.getInfo(BinOp->getLHS());
1199     if (!PInfo.isTest()) {
1200       if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1201         PInfo = Visitor.getInfo(BinOp->getRHS());
1202 
1203         if (!PInfo.isTest()) {
1204           delete FalseStates;
1205           return false;
1206         }
1207 
1208       } else {
1209         delete FalseStates;
1210         return false;
1211       }
1212     }
1213 
1214     CurrStates->setSource(BinOp);
1215     FalseStates->setSource(BinOp);
1216 
1217     const VarTestResult &Test = PInfo.getTest();
1218     ConsumedState VarState = CurrStates->getState(Test.Var);
1219 
1220     if (BinOp->getOpcode() == BO_LAnd) {
1221       if (VarState == CS_Unknown)
1222         CurrStates->setState(Test.Var, Test.TestsFor);
1223       else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1224         CurrStates->markUnreachable();
1225 
1226     } else if (BinOp->getOpcode() == BO_LOr) {
1227       if (VarState == CS_Unknown)
1228         FalseStates->setState(Test.Var,
1229                               invertConsumedUnconsumed(Test.TestsFor));
1230       else if (VarState == Test.TestsFor)
1231         FalseStates->markUnreachable();
1232     }
1233 
1234   } else {
1235     delete FalseStates;
1236     return false;
1237   }
1238 
1239   CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1240 
1241   if (*SI)
1242     BlockInfo.addInfo(*SI, CurrStates);
1243   else
1244     delete CurrStates;
1245 
1246   if (*++SI)
1247     BlockInfo.addInfo(*SI, FalseStates);
1248   else
1249     delete FalseStates;
1250 
1251   CurrStates = NULL;
1252   return true;
1253 }
1254 
1255 void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1256   const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
1257   if (!D)
1258     return;
1259 
1260   CFG *CFGraph = AC.getCFG();
1261   if (!CFGraph)
1262     return;
1263 
1264   determineExpectedReturnState(AC, D);
1265 
1266   PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1267   // AC.getCFG()->viewCFG(LangOptions());
1268 
1269   BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
1270 
1271   CurrStates = new ConsumedStateMap();
1272   ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1273 
1274   // Add all trackable parameters to the state map.
1275   for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1276        PE = D->param_end(); PI != PE; ++PI) {
1277     Visitor.VisitParmVarDecl(*PI);
1278   }
1279 
1280   // Visit all of the function's basic blocks.
1281   for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1282        E = SortedGraph->end(); I != E; ++I) {
1283 
1284     const CFGBlock *CurrBlock = *I;
1285 
1286     if (CurrStates == NULL)
1287       CurrStates = BlockInfo.getInfo(CurrBlock);
1288 
1289     if (!CurrStates) {
1290       continue;
1291 
1292     } else if (!CurrStates->isReachable()) {
1293       delete CurrStates;
1294       CurrStates = NULL;
1295       continue;
1296     }
1297 
1298     Visitor.reset(CurrStates);
1299 
1300     // Visit all of the basic block's statements.
1301     for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1302          BE = CurrBlock->end(); BI != BE; ++BI) {
1303 
1304       switch (BI->getKind()) {
1305       case CFGElement::Statement:
1306         Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
1307         break;
1308 
1309       case CFGElement::TemporaryDtor: {
1310         const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1311         const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1312         PropagationInfo PInfo = Visitor.getInfo(BTE);
1313 
1314         if (PInfo.isValid())
1315           Visitor.checkCallability(PInfo,
1316                                    DTor.getDestructorDecl(AC.getASTContext()),
1317                                    BTE->getExprLoc());
1318         break;
1319       }
1320 
1321       case CFGElement::AutomaticObjectDtor: {
1322         const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1323 
1324         const VarDecl *Var = DTor.getVarDecl();
1325         ConsumedState VarState = CurrStates->getState(Var);
1326 
1327         if (VarState != CS_None) {
1328           PropagationInfo PInfo(Var);
1329 
1330           Visitor.checkCallability(PInfo,
1331                                    DTor.getDestructorDecl(AC.getASTContext()),
1332                                    getLastStmtLoc(CurrBlock));
1333 
1334           CurrStates->remove(Var);
1335         }
1336         break;
1337       }
1338 
1339       default:
1340         break;
1341       }
1342     }
1343 
1344     // TODO: Handle other forms of branching with precision, including while-
1345     //       and for-loops. (Deferred)
1346     if (!splitState(CurrBlock, Visitor)) {
1347       CurrStates->setSource(NULL);
1348 
1349       if (CurrBlock->succ_size() > 1 ||
1350           (CurrBlock->succ_size() == 1 &&
1351            (*CurrBlock->succ_begin())->pred_size() > 1)) {
1352 
1353         bool OwnershipTaken = false;
1354 
1355         for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1356              SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1357 
1358           if (*SI == NULL) continue;
1359 
1360           if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1361             BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1362                                                            CurrStates,
1363                                                            WarningsHandler);
1364 
1365             if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1366               BlockInfo.discardInfo(*SI);
1367           } else {
1368             BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1369           }
1370         }
1371 
1372         if (!OwnershipTaken)
1373           delete CurrStates;
1374 
1375         CurrStates = NULL;
1376       }
1377     }
1378   } // End of block iterator.
1379 
1380   // Delete the last existing state map.
1381   delete CurrStates;
1382 
1383   WarningsHandler.emitDiagnostics();
1384 }
1385 }} // end namespace clang::consumed
1386