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