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/raw_ostream.h"
32 
33 // TODO: Add support for methods with CallableWhenUnconsumed.
34 // TODO: Mark variables as Unknown going into while- or for-loops only if they
35 //       are referenced inside that block. (Deferred)
36 // TODO: Add a method(s) to identify which method calls perform what state
37 //       transitions. (Deferred)
38 // TODO: Take notes on state transitions to provide better warning messages.
39 //       (Deferred)
40 // TODO: Test nested conditionals: A) Checking the same value multiple times,
41 //       and 2) Checking different values. (Deferred)
42 // TODO: Test IsFalseVisitor with values in the unknown state. (Deferred)
43 // TODO: Look into combining IsFalseVisitor and TestedVarsVisitor. (Deferred)
44 
45 using namespace clang;
46 using namespace consumed;
47 
48 // Key method definition
49 ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
50 
51 static StringRef stateToString(ConsumedState State) {
52   switch (State) {
53   case consumed::CS_None:
54     return "none";
55 
56   case consumed::CS_Unknown:
57     return "unknown";
58 
59   case consumed::CS_Unconsumed:
60     return "unconsumed";
61 
62   case consumed::CS_Consumed:
63     return "consumed";
64   }
65   llvm_unreachable("invalid enum");
66 }
67 
68 namespace {
69 class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
70 
71   union PropagationUnion {
72     ConsumedState State;
73     const VarDecl *Var;
74   };
75 
76   class PropagationInfo {
77     PropagationUnion StateOrVar;
78 
79   public:
80     bool IsVar;
81 
82     PropagationInfo() : IsVar(false) {
83       StateOrVar.State = consumed::CS_None;
84     }
85 
86     PropagationInfo(ConsumedState State) : IsVar(false) {
87       StateOrVar.State = State;
88     }
89 
90     PropagationInfo(const VarDecl *Var) : IsVar(true) {
91       StateOrVar.Var = Var;
92     }
93 
94     ConsumedState getState() { return StateOrVar.State; };
95 
96     const VarDecl * getVar() { return IsVar ? StateOrVar.Var : NULL; };
97   };
98 
99   typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
100   typedef std::pair<const Stmt *, PropagationInfo> PairType;
101   typedef MapType::iterator InfoEntry;
102 
103   AnalysisDeclContext &AC;
104   ConsumedAnalyzer &Analyzer;
105   ConsumedStateMap *StateMap;
106   MapType PropagationMap;
107 
108   void forwardInfo(const Stmt *From, const Stmt *To);
109   bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
110 
111 public:
112 
113   void Visit(const Stmt *StmtNode);
114 
115   void VisitBinaryOperator(const BinaryOperator *BinOp);
116   void VisitCallExpr(const CallExpr *Call);
117   void VisitCastExpr(const CastExpr *Cast);
118   void VisitCXXConstructExpr(const CXXConstructExpr *Call);
119   void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
120   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
121   void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
122   void VisitDeclStmt(const DeclStmt *DelcS);
123   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
124   void VisitMemberExpr(const MemberExpr *MExpr);
125   void VisitUnaryOperator(const UnaryOperator *UOp);
126   void VisitVarDecl(const VarDecl *Var);
127 
128   ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
129                       ConsumedStateMap *StateMap)
130       : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
131 
132   void reset() {
133     PropagationMap.clear();
134   }
135 };
136 
137 void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
138   InfoEntry Entry = PropagationMap.find(From);
139 
140   if (Entry != PropagationMap.end()) {
141     PropagationMap.insert(PairType(To, PropagationInfo(Entry->second)));
142   }
143 }
144 
145 bool ConsumedStmtVisitor::isLikeMoveAssignment(
146   const CXXMethodDecl *MethodDecl) {
147 
148   return MethodDecl->isMoveAssignmentOperator() ||
149          (MethodDecl->getOverloadedOperator() == OO_Equal &&
150           MethodDecl->getNumParams() == 1 &&
151           MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
152 }
153 
154 void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
155   switch (BinOp->getOpcode()) {
156   case BO_PtrMemD:
157   case BO_PtrMemI:
158     forwardInfo(BinOp->getLHS(), BinOp);
159     break;
160 
161   default:
162     break;
163   }
164 }
165 
166 void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
167   ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
168 
169   for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
170        CE = StmtNode->child_end(); CI != CE; ++CI) {
171 
172     PropagationMap.erase(*CI);
173   }
174 }
175 
176 void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
177   if (const FunctionDecl *FunDecl =
178     dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
179 
180     // Special case for the std::move function.
181     // TODO: Make this more specific. (Deferred)
182     if (FunDecl->getNameAsString() == "move") {
183       InfoEntry Entry = PropagationMap.find(Call->getArg(0));
184 
185       if (Entry != PropagationMap.end()) {
186         PropagationMap.insert(PairType(Call, Entry->second));
187       }
188 
189       return;
190     }
191 
192     unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
193 
194     for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
195       QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
196 
197       InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
198 
199       if (Entry == PropagationMap.end() || !Entry->second.IsVar) {
200         continue;
201       }
202 
203       PropagationInfo PState = Entry->second;
204 
205       if (ParamType->isRValueReferenceType() ||
206           (ParamType->isLValueReferenceType() &&
207            !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
208 
209         StateMap->setState(PState.getVar(), consumed::CS_Consumed);
210 
211       } else if (!(ParamType.isConstQualified() ||
212                    ((ParamType->isReferenceType() ||
213                      ParamType->isPointerType()) &&
214                     ParamType->getPointeeType().isConstQualified()))) {
215 
216         StateMap->setState(PState.getVar(), consumed::CS_Unknown);
217       }
218     }
219   }
220 }
221 
222 void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
223   InfoEntry Entry = PropagationMap.find(Cast->getSubExpr());
224 
225   if (Entry != PropagationMap.end())
226     PropagationMap.insert(PairType(Cast, Entry->second));
227 }
228 
229 void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
230   CXXConstructorDecl *Constructor = Call->getConstructor();
231 
232   ASTContext &CurrContext = AC.getASTContext();
233   QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
234 
235   if (Analyzer.isConsumableType(ThisType)) {
236     if (Constructor->hasAttr<ConsumesAttr>() ||
237         Constructor->isDefaultConstructor()) {
238 
239       PropagationMap.insert(PairType(Call,
240         PropagationInfo(consumed::CS_Consumed)));
241 
242     } else if (Constructor->isMoveConstructor()) {
243 
244       PropagationInfo PState =
245         PropagationMap.find(Call->getArg(0))->second;
246 
247       if (PState.IsVar) {
248         const VarDecl* Var = PState.getVar();
249 
250         PropagationMap.insert(PairType(Call,
251           PropagationInfo(StateMap->getState(Var))));
252 
253         StateMap->setState(Var, consumed::CS_Consumed);
254 
255       } else {
256         PropagationMap.insert(PairType(Call, PState));
257       }
258 
259     } else if (Constructor->isCopyConstructor()) {
260       MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
261 
262       if (Entry != PropagationMap.end())
263         PropagationMap.insert(PairType(Call, Entry->second));
264 
265     } else {
266       PropagationMap.insert(PairType(Call,
267         PropagationInfo(consumed::CS_Unconsumed)));
268     }
269   }
270 }
271 
272 void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
273   const CXXMemberCallExpr *Call) {
274 
275   VisitCallExpr(Call);
276 
277   InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
278 
279   if (Entry != PropagationMap.end()) {
280     PropagationInfo PState = Entry->second;
281     if (!PState.IsVar) return;
282 
283     const CXXMethodDecl *Method = Call->getMethodDecl();
284 
285     if (Method->hasAttr<ConsumesAttr>())
286       StateMap->setState(PState.getVar(), consumed::CS_Consumed);
287     else if (!Method->isConst())
288       StateMap->setState(PState.getVar(), consumed::CS_Unknown);
289   }
290 }
291 
292 void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
293   const CXXOperatorCallExpr *Call) {
294 
295   const FunctionDecl *FunDecl =
296     dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
297 
298   if (!FunDecl) return;
299 
300   if (isa<CXXMethodDecl>(FunDecl) &&
301       isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
302 
303     InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
304     InfoEntry REntry = PropagationMap.find(Call->getArg(1));
305 
306     PropagationInfo LPState, RPState;
307 
308     if (LEntry != PropagationMap.end() &&
309         REntry != PropagationMap.end()) {
310 
311       LPState = LEntry->second;
312       RPState = REntry->second;
313 
314       if (LPState.IsVar && RPState.IsVar) {
315         StateMap->setState(LPState.getVar(),
316           StateMap->getState(RPState.getVar()));
317 
318         StateMap->setState(RPState.getVar(), consumed::CS_Consumed);
319 
320         PropagationMap.insert(PairType(Call, LPState));
321 
322       } else if (LPState.IsVar && !RPState.IsVar) {
323         StateMap->setState(LPState.getVar(), RPState.getState());
324 
325         PropagationMap.insert(PairType(Call, LPState));
326 
327       } else if (!LPState.IsVar && RPState.IsVar) {
328         PropagationMap.insert(PairType(Call,
329           PropagationInfo(StateMap->getState(RPState.getVar()))));
330 
331         StateMap->setState(RPState.getVar(), consumed::CS_Consumed);
332 
333       } else {
334         PropagationMap.insert(PairType(Call, RPState));
335       }
336 
337     } else if (LEntry != PropagationMap.end() &&
338                REntry == PropagationMap.end()) {
339 
340       LPState = LEntry->second;
341 
342       if (LPState.IsVar) {
343         StateMap->setState(LPState.getVar(), consumed::CS_Unknown);
344 
345         PropagationMap.insert(PairType(Call, LPState));
346 
347       } else {
348         PropagationMap.insert(PairType(Call,
349           PropagationInfo(consumed::CS_Unknown)));
350       }
351 
352     } else if (LEntry == PropagationMap.end() &&
353                REntry != PropagationMap.end()) {
354 
355       RPState = REntry->second;
356 
357       if (RPState.IsVar) {
358         const VarDecl *Var = RPState.getVar();
359 
360         PropagationMap.insert(PairType(Call,
361           PropagationInfo(StateMap->getState(Var))));
362 
363         StateMap->setState(Var, consumed::CS_Consumed);
364 
365       } else {
366         PropagationMap.insert(PairType(Call, RPState));
367       }
368     }
369 
370   } else {
371 
372     VisitCallExpr(Call);
373 
374     InfoEntry Entry = PropagationMap.find(Call->getArg(0));
375 
376     if (Entry != PropagationMap.end()) {
377 
378       PropagationInfo PState = Entry->second;
379 
380       // TODO: When we support CallableWhenConsumed this will have to check for
381       //       the different attributes and change the behavior bellow.
382       //       (Deferred)
383       if (FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) {
384         if (PState.IsVar) {
385           const VarDecl *Var = PState.getVar();
386 
387           switch (StateMap->getState(Var)) {
388           case CS_Consumed:
389             Analyzer.WarningsHandler.warnUseWhileConsumed(
390               FunDecl->getNameAsString(), Var->getNameAsString(),
391               Call->getExprLoc());
392             break;
393 
394           case CS_Unknown:
395             Analyzer.WarningsHandler.warnUseInUnknownState(
396               FunDecl->getNameAsString(), Var->getNameAsString(),
397               Call->getExprLoc());
398             break;
399 
400           default:
401             break;
402           }
403 
404         } else {
405           switch (PState.getState()) {
406           case CS_Consumed:
407             Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(
408               FunDecl->getNameAsString(), Call->getExprLoc());
409             break;
410 
411           case CS_Unknown:
412             Analyzer.WarningsHandler.warnUseOfTempInUnknownState(
413               FunDecl->getNameAsString(), Call->getExprLoc());
414             break;
415 
416           default:
417             break;
418           }
419         }
420       }
421 
422       // Handle non-constant member operators.
423       if (const CXXMethodDecl *MethodDecl =
424         dyn_cast_or_null<CXXMethodDecl>(FunDecl)) {
425 
426         if (!MethodDecl->isConst() && PState.IsVar)
427           StateMap->setState(PState.getVar(), consumed::CS_Unknown);
428       }
429     }
430   }
431 }
432 
433 void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
434   if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
435     if (StateMap->getState(Var) != consumed::CS_None)
436       PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
437 }
438 
439 void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
440   for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
441        DE = DeclS->decl_end(); DI != DE; ++DI) {
442 
443     if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
444   }
445 
446   if (DeclS->isSingleDecl())
447     if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
448       PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
449 }
450 
451 void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
452   const MaterializeTemporaryExpr *Temp) {
453 
454   InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
455 
456   if (Entry != PropagationMap.end())
457     PropagationMap.insert(PairType(Temp, Entry->second));
458 }
459 
460 void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
461   forwardInfo(MExpr->getBase(), MExpr);
462 }
463 
464 void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
465   if (UOp->getOpcode() == UO_AddrOf) {
466     InfoEntry Entry = PropagationMap.find(UOp->getSubExpr());
467 
468     if (Entry != PropagationMap.end())
469       PropagationMap.insert(PairType(UOp, Entry->second));
470   }
471 }
472 
473 void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
474   if (Analyzer.isConsumableType(Var->getType())) {
475     PropagationInfo PState =
476       PropagationMap.find(Var->getInit())->second;
477 
478     StateMap->setState(Var, PState.IsVar ?
479       StateMap->getState(PState.getVar()) : PState.getState());
480   }
481 }
482 } // end anonymous::ConsumedStmtVisitor
483 
484 namespace {
485 
486 // TODO: Handle variable definitions, e.g. bool valid = x.isValid();
487 //       if (valid) ...; (Deferred)
488 class TestedVarsVisitor : public RecursiveASTVisitor<TestedVarsVisitor> {
489 
490   bool Invert;
491   SourceLocation CurrTestLoc;
492 
493   ConsumedStateMap *StateMap;
494 
495 public:
496   bool IsUsefulConditional;
497   VarTestResult Test;
498 
499   TestedVarsVisitor(ConsumedStateMap *StateMap) : Invert(false),
500     StateMap(StateMap), IsUsefulConditional(false) {}
501 
502   bool VisitCallExpr(CallExpr *Call);
503   bool VisitDeclRefExpr(DeclRefExpr *DeclRef);
504   bool VisitUnaryOperator(UnaryOperator *UnaryOp);
505 };
506 
507 bool TestedVarsVisitor::VisitCallExpr(CallExpr *Call) {
508   if (const CXXMethodDecl *Method =
509     dyn_cast_or_null<CXXMethodDecl>(Call->getDirectCallee())) {
510 
511     if (isTestingFunction(Method)) {
512       CurrTestLoc = Call->getExprLoc();
513       IsUsefulConditional = true;
514       return true;
515     }
516 
517     IsUsefulConditional = false;
518   }
519 
520   return false;
521 }
522 
523 bool TestedVarsVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {
524   if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) {
525     if (StateMap->getState(Var) != consumed::CS_None) {
526       Test = VarTestResult(Var, CurrTestLoc, !Invert);
527     }
528 
529   } else {
530     IsUsefulConditional = false;
531   }
532 
533   return IsUsefulConditional;
534 }
535 
536 bool TestedVarsVisitor::VisitUnaryOperator(UnaryOperator *UnaryOp) {
537   if (UnaryOp->getOpcode() == UO_LNot) {
538     Invert = true;
539     TraverseStmt(UnaryOp->getSubExpr());
540 
541   } else {
542     IsUsefulConditional = false;
543   }
544 
545   return false;
546 }
547 } // end anonymouse::TestedVarsVisitor
548 
549 namespace clang {
550 namespace consumed {
551 
552 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
553                                 ConsumedStateMap *StateMap,
554                                 bool &AlreadyOwned) {
555 
556   if (VisitedBlocks.alreadySet(Block)) return;
557 
558   ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
559 
560   if (Entry) {
561     Entry->intersect(StateMap);
562 
563   } else if (AlreadyOwned) {
564     StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
565 
566   } else {
567     StateMapsArray[Block->getBlockID()] = StateMap;
568     AlreadyOwned = true;
569   }
570 }
571 
572 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
573                                 ConsumedStateMap *StateMap) {
574 
575   if (VisitedBlocks.alreadySet(Block)) {
576     delete StateMap;
577     return;
578   }
579 
580   ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
581 
582   if (Entry) {
583     Entry->intersect(StateMap);
584     delete StateMap;
585 
586   } else {
587     StateMapsArray[Block->getBlockID()] = StateMap;
588   }
589 }
590 
591 ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
592   return StateMapsArray[Block->getBlockID()];
593 }
594 
595 void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {
596   VisitedBlocks.insert(Block);
597 }
598 
599 ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {
600   MapType::const_iterator Entry = Map.find(Var);
601 
602   if (Entry != Map.end()) {
603     return Entry->second;
604 
605   } else {
606     return CS_None;
607   }
608 }
609 
610 void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
611   ConsumedState LocalState;
612 
613   for (MapType::const_iterator DMI = Other->Map.begin(),
614        DME = Other->Map.end(); DMI != DME; ++DMI) {
615 
616     LocalState = this->getState(DMI->first);
617 
618     if (LocalState != CS_None && LocalState != DMI->second)
619       setState(DMI->first, CS_Unknown);
620   }
621 }
622 
623 void ConsumedStateMap::makeUnknown() {
624   PairType Pair;
625 
626   for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
627        ++DMI) {
628 
629     Pair = *DMI;
630 
631     Map.erase(Pair.first);
632     Map.insert(PairType(Pair.first, CS_Unknown));
633   }
634 }
635 
636 void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
637   Map[Var] = State;
638 }
639 
640 
641 bool ConsumedAnalyzer::isConsumableType(QualType Type) {
642   const CXXRecordDecl *RD =
643     dyn_cast_or_null<CXXRecordDecl>(Type->getAsCXXRecordDecl());
644 
645   if (!RD) return false;
646 
647   std::pair<CacheMapType::iterator, bool> Entry =
648     ConsumableTypeCache.insert(std::make_pair(RD, false));
649 
650   if (Entry.second)
651     Entry.first->second = hasConsumableAttributes(RD);
652 
653   return Entry.first->second;
654 }
655 
656 // TODO: Walk the base classes to see if any of them are unique types.
657 //       (Deferred)
658 bool ConsumedAnalyzer::hasConsumableAttributes(const CXXRecordDecl *RD) {
659   for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
660        ME = RD->method_end(); MI != ME; ++MI) {
661 
662     for (Decl::attr_iterator AI = (*MI)->attr_begin(), AE = (*MI)->attr_end();
663          AI != AE; ++AI) {
664 
665       switch ((*AI)->getKind()) {
666       case attr::CallableWhenUnconsumed:
667       case attr::TestsUnconsumed:
668         return true;
669 
670       default:
671         break;
672       }
673     }
674   }
675 
676   return false;
677 }
678 
679 // TODO: Handle other forms of branching with precision, including while- and
680 //       for-loops. (Deferred)
681 void ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
682                                   const IfStmt *Terminator) {
683 
684   TestedVarsVisitor Visitor(CurrStates);
685   Visitor.TraverseStmt(const_cast<Expr*>(Terminator->getCond()));
686 
687   bool HasElse = Terminator->getElse() != NULL;
688 
689   ConsumedStateMap *ElseOrMergeStates = new ConsumedStateMap(*CurrStates);
690 
691   if (Visitor.IsUsefulConditional) {
692     ConsumedState VarState = CurrStates->getState(Visitor.Test.Var);
693 
694     if (VarState != CS_Unknown) {
695       // FIXME: Make this not warn if the test is from a macro expansion.
696       //        (Deferred)
697       WarningsHandler.warnUnnecessaryTest(Visitor.Test.Var->getNameAsString(),
698         stateToString(VarState), Visitor.Test.Loc);
699     }
700 
701     if (Visitor.Test.UnconsumedInTrueBranch) {
702       CurrStates->setState(Visitor.Test.Var, CS_Unconsumed);
703       if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var, CS_Consumed);
704 
705     } else {
706       CurrStates->setState(Visitor.Test.Var, CS_Consumed);
707       if (HasElse) ElseOrMergeStates->setState(Visitor.Test.Var, CS_Unconsumed);
708     }
709   }
710 
711   CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
712 
713   if (*SI)   BlockInfo.addInfo(*SI,        CurrStates);
714   if (*++SI) BlockInfo.addInfo(*SI, ElseOrMergeStates);
715 }
716 
717 void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
718   const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
719 
720   if (!D) return;
721 
722   BlockInfo = ConsumedBlockInfo(AC.getCFG());
723 
724   PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
725 
726   CurrStates = new ConsumedStateMap();
727 
728   // Visit all of the function's basic blocks.
729   for (PostOrderCFGView::iterator I = SortedGraph->begin(),
730        E = SortedGraph->end(); I != E; ++I) {
731 
732     const CFGBlock *CurrBlock = *I;
733     BlockInfo.markVisited(CurrBlock);
734 
735     if (CurrStates == NULL)
736       CurrStates = BlockInfo.getInfo(CurrBlock);
737 
738     ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
739 
740     // Visit all of the basic block's statements.
741     for (CFGBlock::const_iterator BI = CurrBlock->begin(),
742          BE = CurrBlock->end(); BI != BE; ++BI) {
743 
744       if (BI->getKind() == CFGElement::Statement)
745         Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
746     }
747 
748     // TODO: Remove any variables that have reached the end of their
749     //       lifetimes from the state map. (Deferred)
750 
751     if (const IfStmt *Terminator =
752       dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
753 
754       splitState(CurrBlock, Terminator);
755       CurrStates = NULL;
756 
757     } else if (CurrBlock->succ_size() > 1) {
758       CurrStates->makeUnknown();
759 
760       bool OwnershipTaken = false;
761 
762       for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
763            SE = CurrBlock->succ_end(); SI != SE; ++SI) {
764 
765         if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
766       }
767 
768       if (!OwnershipTaken)
769         delete CurrStates;
770 
771       CurrStates = NULL;
772 
773     } else if (CurrBlock->succ_size() == 1 &&
774                (*CurrBlock->succ_begin())->pred_size() > 1) {
775 
776       BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);
777       CurrStates = NULL;
778     }
779 
780     Visitor.reset();
781   } // End of block iterator.
782 
783   // Delete the last existing state map.
784   delete CurrStates;
785 
786   WarningsHandler.emitDiagnostics();
787 }
788 
789 bool isTestingFunction(const CXXMethodDecl *Method) {
790   return Method->hasAttr<TestsUnconsumedAttr>();
791 }
792 
793 }} // end namespace clang::consumed
794