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