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