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