xref: /llvm-project/clang/lib/Analysis/Consumed.cpp (revision 5a715c4f00acdb54787244be3b857ad716e5d18f)
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: Correctly identify unreachable blocks when chaining boolean operators.
35 // TODO: Warn about unreachable code.
36 // TODO: Switch to using a bitmap to track unreachable blocks.
37 // TODO: Mark variables as Unknown going into while- or for-loops only if they
38 //       are referenced inside that block. (Deferred)
39 // TODO: Handle variable definitions, e.g. bool valid = x.isValid();
40 //       if (valid) ...; (Deferred)
41 // TODO: Add a method(s) to identify which method calls perform what state
42 //       transitions. (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 ConsumedState invertConsumedUnconsumed(ConsumedState State) {
55   switch (State) {
56   case CS_Unconsumed:
57     return CS_Consumed;
58   case CS_Consumed:
59     return CS_Unconsumed;
60   case CS_None:
61     return CS_None;
62   case CS_Unknown:
63     return CS_Unknown;
64   }
65   llvm_unreachable("invalid enum");
66 }
67 
68 static bool isConsumableType(const QualType &QT) {
69   if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
70     return RD->hasAttr<ConsumableAttr>();
71   else
72     return false;
73 }
74 
75 static bool isKnownState(ConsumedState State) {
76   switch (State) {
77   case CS_Unconsumed:
78   case CS_Consumed:
79     return true;
80   case CS_None:
81   case CS_Unknown:
82     return false;
83   }
84   llvm_unreachable("invalid enum");
85 }
86 
87 static bool isTestingFunction(const FunctionDecl *FunDecl) {
88   return FunDecl->hasAttr<TestsUnconsumedAttr>();
89 }
90 
91 static StringRef stateToString(ConsumedState State) {
92   switch (State) {
93   case consumed::CS_None:
94     return "none";
95 
96   case consumed::CS_Unknown:
97     return "unknown";
98 
99   case consumed::CS_Unconsumed:
100     return "unconsumed";
101 
102   case consumed::CS_Consumed:
103     return "consumed";
104   }
105   llvm_unreachable("invalid enum");
106 }
107 
108 namespace {
109 struct VarTestResult {
110   const VarDecl *Var;
111   ConsumedState TestsFor;
112 };
113 } // end anonymous::VarTestResult
114 
115 namespace clang {
116 namespace consumed {
117 
118 enum EffectiveOp {
119   EO_And,
120   EO_Or
121 };
122 
123 class PropagationInfo {
124   enum {
125     IT_None,
126     IT_State,
127     IT_Test,
128     IT_BinTest,
129     IT_Var
130   } InfoType;
131 
132   struct BinTestTy {
133     const BinaryOperator *Source;
134     EffectiveOp EOp;
135     VarTestResult LTest;
136     VarTestResult RTest;
137   };
138 
139   union {
140     ConsumedState State;
141     VarTestResult Test;
142     const VarDecl *Var;
143     BinTestTy BinTest;
144   };
145 
146 public:
147   PropagationInfo() : InfoType(IT_None) {}
148 
149   PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
150   PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
151     : InfoType(IT_Test) {
152 
153     Test.Var      = Var;
154     Test.TestsFor = TestsFor;
155   }
156 
157   PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
158                   const VarTestResult &LTest, const VarTestResult &RTest)
159     : InfoType(IT_BinTest) {
160 
161     BinTest.Source  = Source;
162     BinTest.EOp     = EOp;
163     BinTest.LTest   = LTest;
164     BinTest.RTest   = RTest;
165   }
166 
167   PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
168                   const VarDecl *LVar, ConsumedState LTestsFor,
169                   const VarDecl *RVar, ConsumedState RTestsFor)
170     : InfoType(IT_BinTest) {
171 
172     BinTest.Source         = Source;
173     BinTest.EOp            = EOp;
174     BinTest.LTest.Var      = LVar;
175     BinTest.LTest.TestsFor = LTestsFor;
176     BinTest.RTest.Var      = RVar;
177     BinTest.RTest.TestsFor = RTestsFor;
178   }
179 
180   PropagationInfo(ConsumedState State) : InfoType(IT_State), State(State) {}
181   PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
182 
183   const ConsumedState & getState() const {
184     assert(InfoType == IT_State);
185     return State;
186   }
187 
188   const VarTestResult & getTest() const {
189     assert(InfoType == IT_Test);
190     return Test;
191   }
192 
193   const VarTestResult & getLTest() const {
194     assert(InfoType == IT_BinTest);
195     return BinTest.LTest;
196   }
197 
198   const VarTestResult & getRTest() const {
199     assert(InfoType == IT_BinTest);
200     return BinTest.RTest;
201   }
202 
203   const VarDecl * getVar() const {
204     assert(InfoType == IT_Var);
205     return Var;
206   }
207 
208   EffectiveOp testEffectiveOp() const {
209     assert(InfoType == IT_BinTest);
210     return BinTest.EOp;
211   }
212 
213   const BinaryOperator * testSourceNode() const {
214     assert(InfoType == IT_BinTest);
215     return BinTest.Source;
216   }
217 
218   bool isValid()   const { return InfoType != IT_None;     }
219   bool isState()   const { return InfoType == IT_State;    }
220   bool isTest()    const { return InfoType == IT_Test;     }
221   bool isBinTest() const { return InfoType == IT_BinTest;  }
222   bool isVar()     const { return InfoType == IT_Var;      }
223 
224   PropagationInfo invertTest() const {
225     assert(InfoType == IT_Test || InfoType == IT_BinTest);
226 
227     if (InfoType == IT_Test) {
228       return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
229 
230     } else if (InfoType == IT_BinTest) {
231       return PropagationInfo(BinTest.Source,
232         BinTest.EOp == EO_And ? EO_Or : EO_And,
233         BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
234         BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
235     } else {
236       return PropagationInfo();
237     }
238   }
239 };
240 
241 class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
242 
243   typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
244   typedef std::pair<const Stmt *, PropagationInfo> PairType;
245   typedef MapType::iterator InfoEntry;
246   typedef MapType::const_iterator ConstInfoEntry;
247 
248   AnalysisDeclContext &AC;
249   ConsumedAnalyzer &Analyzer;
250   ConsumedStateMap *StateMap;
251   MapType PropagationMap;
252 
253   void checkCallability(const PropagationInfo &PInfo,
254                         const FunctionDecl *FunDecl,
255                         const CallExpr *Call);
256   void forwardInfo(const Stmt *From, const Stmt *To);
257   void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var);
258   bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
259 
260 public:
261 
262   void Visit(const Stmt *StmtNode);
263 
264   void VisitBinaryOperator(const BinaryOperator *BinOp);
265   void VisitCallExpr(const CallExpr *Call);
266   void VisitCastExpr(const CastExpr *Cast);
267   void VisitCXXConstructExpr(const CXXConstructExpr *Call);
268   void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
269   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
270   void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
271   void VisitDeclStmt(const DeclStmt *DelcS);
272   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
273   void VisitMemberExpr(const MemberExpr *MExpr);
274   void VisitParmVarDecl(const ParmVarDecl *Param);
275   void VisitUnaryOperator(const UnaryOperator *UOp);
276   void VisitVarDecl(const VarDecl *Var);
277 
278   ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
279                       ConsumedStateMap *StateMap)
280       : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
281 
282   PropagationInfo getInfo(const Stmt *StmtNode) const {
283     ConstInfoEntry Entry = PropagationMap.find(StmtNode);
284 
285     if (Entry != PropagationMap.end())
286       return Entry->second;
287     else
288       return PropagationInfo();
289   }
290 
291   void reset(ConsumedStateMap *NewStateMap) {
292     StateMap = NewStateMap;
293   }
294 };
295 
296 // TODO: When we support CallableWhenConsumed this will have to check for
297 //       the different attributes and change the behavior bellow. (Deferred)
298 void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
299                                            const FunctionDecl *FunDecl,
300                                            const CallExpr *Call) {
301 
302   if (!FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) return;
303 
304   if (PInfo.isVar()) {
305     const VarDecl *Var = PInfo.getVar();
306 
307     switch (StateMap->getState(Var)) {
308     case CS_Consumed:
309       Analyzer.WarningsHandler.warnUseWhileConsumed(
310         FunDecl->getNameAsString(), Var->getNameAsString(),
311         Call->getExprLoc());
312       break;
313 
314     case CS_Unknown:
315       Analyzer.WarningsHandler.warnUseInUnknownState(
316         FunDecl->getNameAsString(), Var->getNameAsString(),
317         Call->getExprLoc());
318       break;
319 
320     case CS_None:
321     case CS_Unconsumed:
322       break;
323     }
324 
325   } else {
326     switch (PInfo.getState()) {
327     case CS_Consumed:
328       Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(
329         FunDecl->getNameAsString(), Call->getExprLoc());
330       break;
331 
332     case CS_Unknown:
333       Analyzer.WarningsHandler.warnUseOfTempInUnknownState(
334         FunDecl->getNameAsString(), Call->getExprLoc());
335       break;
336 
337     case CS_None:
338     case CS_Unconsumed:
339       break;
340     }
341   }
342 }
343 
344 void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
345   InfoEntry Entry = PropagationMap.find(From);
346 
347   if (Entry != PropagationMap.end())
348     PropagationMap.insert(PairType(To, Entry->second));
349 }
350 
351 void ConsumedStmtVisitor::handleTestingFunctionCall(const CallExpr *Call,
352                                                     const VarDecl  *Var) {
353 
354   ConsumedState VarState = StateMap->getState(Var);
355 
356   if (VarState != CS_Unknown) {
357     SourceLocation CallLoc = Call->getExprLoc();
358 
359     if (!CallLoc.isMacroID())
360       Analyzer.WarningsHandler.warnUnnecessaryTest(Var->getNameAsString(),
361         stateToString(VarState), CallLoc);
362   }
363 
364   PropagationMap.insert(PairType(Call, PropagationInfo(Var, CS_Unconsumed)));
365 }
366 
367 bool ConsumedStmtVisitor::isLikeMoveAssignment(
368   const CXXMethodDecl *MethodDecl) {
369 
370   return MethodDecl->isMoveAssignmentOperator() ||
371          (MethodDecl->getOverloadedOperator() == OO_Equal &&
372           MethodDecl->getNumParams() == 1 &&
373           MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
374 }
375 
376 void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
377 
378   ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
379 
380   for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
381        CE = StmtNode->child_end(); CI != CE; ++CI) {
382 
383     PropagationMap.erase(*CI);
384   }
385 }
386 
387 void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
388   switch (BinOp->getOpcode()) {
389   case BO_LAnd:
390   case BO_LOr : {
391     InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
392               REntry = PropagationMap.find(BinOp->getRHS());
393 
394     VarTestResult LTest, RTest;
395 
396     if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
397       LTest = LEntry->second.getTest();
398 
399     } else {
400       LTest.Var      = NULL;
401       LTest.TestsFor = CS_None;
402     }
403 
404     if (REntry != PropagationMap.end() && REntry->second.isTest()) {
405       RTest = REntry->second.getTest();
406 
407     } else {
408       RTest.Var      = NULL;
409       RTest.TestsFor = CS_None;
410     }
411 
412     if (!(LTest.Var == NULL && RTest.Var == NULL))
413       PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
414         static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
415 
416     break;
417   }
418 
419   case BO_PtrMemD:
420   case BO_PtrMemI:
421     forwardInfo(BinOp->getLHS(), BinOp);
422     break;
423 
424   default:
425     break;
426   }
427 }
428 
429 void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
430   if (const FunctionDecl *FunDecl =
431     dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
432 
433     // Special case for the std::move function.
434     // TODO: Make this more specific. (Deferred)
435     if (FunDecl->getNameAsString() == "move") {
436       InfoEntry Entry = PropagationMap.find(Call->getArg(0));
437 
438       if (Entry != PropagationMap.end()) {
439         PropagationMap.insert(PairType(Call, Entry->second));
440       }
441 
442       return;
443     }
444 
445     unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
446 
447     for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
448       QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
449 
450       InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
451 
452       if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
453         continue;
454       }
455 
456       PropagationInfo PInfo = Entry->second;
457 
458       if (ParamType->isRValueReferenceType() ||
459           (ParamType->isLValueReferenceType() &&
460            !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
461 
462         StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
463 
464       } else if (!(ParamType.isConstQualified() ||
465                    ((ParamType->isReferenceType() ||
466                      ParamType->isPointerType()) &&
467                     ParamType->getPointeeType().isConstQualified()))) {
468 
469         StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
470       }
471     }
472   }
473 }
474 
475 void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
476   forwardInfo(Cast->getSubExpr(), Cast);
477 }
478 
479 void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
480   CXXConstructorDecl *Constructor = Call->getConstructor();
481 
482   ASTContext &CurrContext = AC.getASTContext();
483   QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
484 
485   if (isConsumableType(ThisType)) {
486     if (Constructor->hasAttr<ConsumesAttr>() ||
487         Constructor->isDefaultConstructor()) {
488 
489       PropagationMap.insert(PairType(Call,
490         PropagationInfo(consumed::CS_Consumed)));
491 
492     } else if (Constructor->isMoveConstructor()) {
493 
494       PropagationInfo PInfo =
495         PropagationMap.find(Call->getArg(0))->second;
496 
497       if (PInfo.isVar()) {
498         const VarDecl* Var = PInfo.getVar();
499 
500         PropagationMap.insert(PairType(Call,
501           PropagationInfo(StateMap->getState(Var))));
502 
503         StateMap->setState(Var, consumed::CS_Consumed);
504 
505       } else {
506         PropagationMap.insert(PairType(Call, PInfo));
507       }
508 
509     } else if (Constructor->isCopyConstructor()) {
510       MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
511 
512       if (Entry != PropagationMap.end())
513         PropagationMap.insert(PairType(Call, Entry->second));
514 
515     } else {
516       PropagationMap.insert(PairType(Call,
517         PropagationInfo(consumed::CS_Unconsumed)));
518     }
519   }
520 }
521 
522 void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
523   const CXXMemberCallExpr *Call) {
524 
525   VisitCallExpr(Call);
526 
527   InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
528 
529   if (Entry != PropagationMap.end()) {
530     PropagationInfo PInfo = Entry->second;
531     const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
532 
533     checkCallability(PInfo, MethodDecl, Call);
534 
535     if (PInfo.isVar()) {
536       if (isTestingFunction(MethodDecl))
537         handleTestingFunctionCall(Call, PInfo.getVar());
538       else if (MethodDecl->hasAttr<ConsumesAttr>())
539         StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
540     }
541   }
542 }
543 
544 void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
545   const CXXOperatorCallExpr *Call) {
546 
547   const FunctionDecl *FunDecl =
548     dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
549 
550   if (!FunDecl) return;
551 
552   if (isa<CXXMethodDecl>(FunDecl) &&
553       isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
554 
555     InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
556     InfoEntry REntry = PropagationMap.find(Call->getArg(1));
557 
558     PropagationInfo LPInfo, RPInfo;
559 
560     if (LEntry != PropagationMap.end() &&
561         REntry != PropagationMap.end()) {
562 
563       LPInfo = LEntry->second;
564       RPInfo = REntry->second;
565 
566       if (LPInfo.isVar() && RPInfo.isVar()) {
567         StateMap->setState(LPInfo.getVar(),
568           StateMap->getState(RPInfo.getVar()));
569 
570         StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
571 
572         PropagationMap.insert(PairType(Call, LPInfo));
573 
574       } else if (LPInfo.isVar() && !RPInfo.isVar()) {
575         StateMap->setState(LPInfo.getVar(), RPInfo.getState());
576 
577         PropagationMap.insert(PairType(Call, LPInfo));
578 
579       } else if (!LPInfo.isVar() && RPInfo.isVar()) {
580         PropagationMap.insert(PairType(Call,
581           PropagationInfo(StateMap->getState(RPInfo.getVar()))));
582 
583         StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
584 
585       } else {
586         PropagationMap.insert(PairType(Call, RPInfo));
587       }
588 
589     } else if (LEntry != PropagationMap.end() &&
590                REntry == PropagationMap.end()) {
591 
592       LPInfo = LEntry->second;
593 
594       if (LPInfo.isVar()) {
595         StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
596 
597         PropagationMap.insert(PairType(Call, LPInfo));
598 
599       } else {
600         PropagationMap.insert(PairType(Call,
601           PropagationInfo(consumed::CS_Unknown)));
602       }
603 
604     } else if (LEntry == PropagationMap.end() &&
605                REntry != PropagationMap.end()) {
606 
607       RPInfo = REntry->second;
608 
609       if (RPInfo.isVar()) {
610         const VarDecl *Var = RPInfo.getVar();
611 
612         PropagationMap.insert(PairType(Call,
613           PropagationInfo(StateMap->getState(Var))));
614 
615         StateMap->setState(Var, consumed::CS_Consumed);
616 
617       } else {
618         PropagationMap.insert(PairType(Call, RPInfo));
619       }
620     }
621 
622   } else {
623 
624     VisitCallExpr(Call);
625 
626     InfoEntry Entry = PropagationMap.find(Call->getArg(0));
627 
628     if (Entry != PropagationMap.end()) {
629       PropagationInfo PInfo = Entry->second;
630 
631       checkCallability(PInfo, FunDecl, Call);
632 
633       if (PInfo.isVar()) {
634         if (isTestingFunction(FunDecl))
635           handleTestingFunctionCall(Call, PInfo.getVar());
636         else if (FunDecl->hasAttr<ConsumesAttr>())
637           StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
638       }
639     }
640   }
641 }
642 
643 void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
644   if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
645     if (StateMap->getState(Var) != consumed::CS_None)
646       PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
647 }
648 
649 void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
650   for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
651        DE = DeclS->decl_end(); DI != DE; ++DI) {
652 
653     if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
654   }
655 
656   if (DeclS->isSingleDecl())
657     if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
658       PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
659 }
660 
661 void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
662   const MaterializeTemporaryExpr *Temp) {
663 
664   InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
665 
666   if (Entry != PropagationMap.end())
667     PropagationMap.insert(PairType(Temp, Entry->second));
668 }
669 
670 void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
671   forwardInfo(MExpr->getBase(), MExpr);
672 }
673 
674 
675 void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
676   if (isConsumableType(Param->getType()))
677     StateMap->setState(Param, consumed::CS_Unknown);
678 }
679 
680 void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
681   InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
682   if (Entry == PropagationMap.end()) return;
683 
684   switch (UOp->getOpcode()) {
685   case UO_AddrOf:
686     PropagationMap.insert(PairType(UOp, Entry->second));
687     break;
688 
689   case UO_LNot:
690     if (Entry->second.isTest() || Entry->second.isBinTest())
691       PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
692     break;
693 
694   default:
695     break;
696   }
697 }
698 
699 void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
700   if (isConsumableType(Var->getType())) {
701     if (Var->hasInit()) {
702       PropagationInfo PInfo =
703         PropagationMap.find(Var->getInit())->second;
704 
705       StateMap->setState(Var, PInfo.isVar() ?
706         StateMap->getState(PInfo.getVar()) : PInfo.getState());
707 
708     } else {
709       StateMap->setState(Var, consumed::CS_Unknown);
710     }
711   }
712 }
713 }} // end clang::consumed::ConsumedStmtVisitor
714 
715 namespace clang {
716 namespace consumed {
717 
718 void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
719                         ConsumedStateMap *ThenStates,
720                         ConsumedStateMap *ElseStates) {
721 
722   ConsumedState VarState = ThenStates->getState(Test.Var);
723 
724   if (VarState == CS_Unknown) {
725     ThenStates->setState(Test.Var, Test.TestsFor);
726     if (ElseStates)
727       ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
728 
729   } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
730     ThenStates->markUnreachable();
731 
732   } else if (VarState == Test.TestsFor && ElseStates) {
733     ElseStates->markUnreachable();
734   }
735 }
736 
737 void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
738   ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
739 
740   const VarTestResult &LTest = PInfo.getLTest(),
741                       &RTest = PInfo.getRTest();
742 
743   ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
744                 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
745 
746   if (LTest.Var) {
747     if (PInfo.testEffectiveOp() == EO_And) {
748       if (LState == CS_Unknown) {
749         ThenStates->setState(LTest.Var, LTest.TestsFor);
750 
751       } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
752         ThenStates->markUnreachable();
753 
754       } else if (LState == LTest.TestsFor && isKnownState(RState)) {
755         if (RState == RTest.TestsFor) {
756           if (ElseStates)
757             ElseStates->markUnreachable();
758         } else {
759           ThenStates->markUnreachable();
760         }
761       }
762 
763     } else {
764       if (LState == CS_Unknown && ElseStates) {
765         ElseStates->setState(LTest.Var,
766                              invertConsumedUnconsumed(LTest.TestsFor));
767 
768       } else if (LState == LTest.TestsFor && ElseStates) {
769         ElseStates->markUnreachable();
770 
771       } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
772                  isKnownState(RState)) {
773 
774         if (RState == RTest.TestsFor) {
775           if (ElseStates)
776             ElseStates->markUnreachable();
777         } else {
778           ThenStates->markUnreachable();
779         }
780       }
781     }
782   }
783 
784   if (RTest.Var) {
785     if (PInfo.testEffectiveOp() == EO_And) {
786       if (RState == CS_Unknown)
787         ThenStates->setState(RTest.Var, RTest.TestsFor);
788       else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
789         ThenStates->markUnreachable();
790 
791     } else if (ElseStates) {
792       if (RState == CS_Unknown)
793         ElseStates->setState(RTest.Var,
794                              invertConsumedUnconsumed(RTest.TestsFor));
795       else if (RState == RTest.TestsFor)
796         ElseStates->markUnreachable();
797     }
798   }
799 }
800 
801 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
802                                 ConsumedStateMap *StateMap,
803                                 bool &AlreadyOwned) {
804 
805   if (VisitedBlocks.alreadySet(Block)) return;
806 
807   ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
808 
809   if (Entry) {
810     Entry->intersect(StateMap);
811 
812   } else if (AlreadyOwned) {
813     StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
814 
815   } else {
816     StateMapsArray[Block->getBlockID()] = StateMap;
817     AlreadyOwned = true;
818   }
819 }
820 
821 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
822                                 ConsumedStateMap *StateMap) {
823 
824   if (VisitedBlocks.alreadySet(Block)) {
825     delete StateMap;
826     return;
827   }
828 
829   ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
830 
831   if (Entry) {
832     Entry->intersect(StateMap);
833     delete StateMap;
834 
835   } else {
836     StateMapsArray[Block->getBlockID()] = StateMap;
837   }
838 }
839 
840 ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
841   return StateMapsArray[Block->getBlockID()];
842 }
843 
844 void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {
845   VisitedBlocks.insert(Block);
846 }
847 
848 ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {
849   MapType::const_iterator Entry = Map.find(Var);
850 
851   if (Entry != Map.end()) {
852     return Entry->second;
853 
854   } else {
855     return CS_None;
856   }
857 }
858 
859 void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
860   ConsumedState LocalState;
861 
862   if (this->From && this->From == Other->From && !Other->Reachable) {
863     this->markUnreachable();
864     return;
865   }
866 
867   for (MapType::const_iterator DMI = Other->Map.begin(),
868        DME = Other->Map.end(); DMI != DME; ++DMI) {
869 
870     LocalState = this->getState(DMI->first);
871 
872     if (LocalState == CS_None)
873       continue;
874 
875     if (LocalState != DMI->second)
876        Map[DMI->first] = CS_Unknown;
877   }
878 }
879 
880 void ConsumedStateMap::markUnreachable() {
881   this->Reachable = false;
882   Map.clear();
883 }
884 
885 void ConsumedStateMap::makeUnknown() {
886   for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
887        ++DMI) {
888 
889     Map[DMI->first] = CS_Unknown;
890   }
891 }
892 
893 void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
894   Map[Var] = State;
895 }
896 
897 void ConsumedStateMap::remove(const VarDecl *Var) {
898   Map.erase(Var);
899 }
900 
901 bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
902                                   const ConsumedStmtVisitor &Visitor) {
903 
904   ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
905   PropagationInfo PInfo;
906 
907   if (const IfStmt *IfNode =
908     dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
909 
910     bool HasElse = IfNode->getElse() != NULL;
911     const Stmt *Cond = IfNode->getCond();
912 
913     PInfo = Visitor.getInfo(Cond);
914     if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
915       PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
916 
917     if (PInfo.isTest()) {
918       CurrStates->setSource(Cond);
919       FalseStates->setSource(Cond);
920 
921       splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates,
922                          HasElse ? FalseStates : NULL);
923 
924     } else if (PInfo.isBinTest()) {
925       CurrStates->setSource(PInfo.testSourceNode());
926       FalseStates->setSource(PInfo.testSourceNode());
927 
928       splitVarStateForIfBinOp(PInfo, CurrStates, HasElse ? FalseStates : NULL);
929 
930     } else {
931       delete FalseStates;
932       return false;
933     }
934 
935   } else if (const BinaryOperator *BinOp =
936     dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
937 
938     PInfo = Visitor.getInfo(BinOp->getLHS());
939     if (!PInfo.isTest()) {
940       if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
941         PInfo = Visitor.getInfo(BinOp->getRHS());
942 
943         if (!PInfo.isTest()) {
944           delete FalseStates;
945           return false;
946         }
947 
948       } else {
949         delete FalseStates;
950         return false;
951       }
952     }
953 
954     CurrStates->setSource(BinOp);
955     FalseStates->setSource(BinOp);
956 
957     const VarTestResult &Test = PInfo.getTest();
958     ConsumedState VarState = CurrStates->getState(Test.Var);
959 
960     if (BinOp->getOpcode() == BO_LAnd) {
961       if (VarState == CS_Unknown)
962         CurrStates->setState(Test.Var, Test.TestsFor);
963       else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
964         CurrStates->markUnreachable();
965 
966     } else if (BinOp->getOpcode() == BO_LOr) {
967       if (VarState == CS_Unknown)
968         FalseStates->setState(Test.Var,
969                               invertConsumedUnconsumed(Test.TestsFor));
970       else if (VarState == Test.TestsFor)
971         FalseStates->markUnreachable();
972     }
973 
974   } else {
975     delete FalseStates;
976     return false;
977   }
978 
979   CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
980 
981   if (*SI)
982     BlockInfo.addInfo(*SI, CurrStates);
983   else
984     delete CurrStates;
985 
986   if (*++SI)
987     BlockInfo.addInfo(*SI, FalseStates);
988   else
989     delete FalseStates;
990 
991   CurrStates = NULL;
992   return true;
993 }
994 
995 void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
996   const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
997 
998   if (!D) return;
999 
1000   BlockInfo = ConsumedBlockInfo(AC.getCFG());
1001 
1002   PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1003 
1004   CurrStates = new ConsumedStateMap();
1005   ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1006 
1007   // Add all trackable parameters to the state map.
1008   for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1009        PE = D->param_end(); PI != PE; ++PI) {
1010     Visitor.VisitParmVarDecl(*PI);
1011   }
1012 
1013   // Visit all of the function's basic blocks.
1014   for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1015        E = SortedGraph->end(); I != E; ++I) {
1016 
1017     const CFGBlock *CurrBlock = *I;
1018     BlockInfo.markVisited(CurrBlock);
1019 
1020     if (CurrStates == NULL)
1021       CurrStates = BlockInfo.getInfo(CurrBlock);
1022 
1023     if (!CurrStates) {
1024       continue;
1025 
1026     } else if (!CurrStates->isReachable()) {
1027       delete CurrStates;
1028       CurrStates = NULL;
1029       continue;
1030     }
1031 
1032     Visitor.reset(CurrStates);
1033 
1034     // Visit all of the basic block's statements.
1035     for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1036          BE = CurrBlock->end(); BI != BE; ++BI) {
1037 
1038       switch (BI->getKind()) {
1039       case CFGElement::Statement:
1040         Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
1041         break;
1042       case CFGElement::AutomaticObjectDtor:
1043         CurrStates->remove(BI->castAs<CFGAutomaticObjDtor>().getVarDecl());
1044       default:
1045         break;
1046       }
1047     }
1048 
1049     // TODO: Handle other forms of branching with precision, including while-
1050     //       and for-loops. (Deferred)
1051     if (!splitState(CurrBlock, Visitor)) {
1052       CurrStates->setSource(NULL);
1053 
1054       if (CurrBlock->succ_size() > 1) {
1055         CurrStates->makeUnknown();
1056 
1057         bool OwnershipTaken = false;
1058 
1059         for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1060              SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1061 
1062           if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1063         }
1064 
1065         if (!OwnershipTaken)
1066           delete CurrStates;
1067 
1068         CurrStates = NULL;
1069 
1070       } else if (CurrBlock->succ_size() == 1 &&
1071                  (*CurrBlock->succ_begin())->pred_size() > 1) {
1072 
1073         BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);
1074         CurrStates = NULL;
1075       }
1076     }
1077   } // End of block iterator.
1078 
1079   // Delete the last existing state map.
1080   delete CurrStates;
1081 
1082   WarningsHandler.emitDiagnostics();
1083 }
1084 }} // end namespace clang::consumed
1085