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