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