clang API Documentation

Consumed.cpp
Go to the documentation of this file.
00001 //===- Consumed.cpp --------------------------------------------*- C++ --*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // A intra-procedural analysis for checking consumed properties.  This is based,
00011 // in part, on research on linear types.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "clang/AST/ASTContext.h"
00016 #include "clang/AST/Attr.h"
00017 #include "clang/AST/DeclCXX.h"
00018 #include "clang/AST/ExprCXX.h"
00019 #include "clang/AST/RecursiveASTVisitor.h"
00020 #include "clang/AST/StmtCXX.h"
00021 #include "clang/AST/StmtVisitor.h"
00022 #include "clang/AST/Type.h"
00023 #include "clang/Analysis/Analyses/Consumed.h"
00024 #include "clang/Analysis/Analyses/PostOrderCFGView.h"
00025 #include "clang/Analysis/AnalysisContext.h"
00026 #include "clang/Analysis/CFG.h"
00027 #include "clang/Basic/OperatorKinds.h"
00028 #include "clang/Basic/SourceLocation.h"
00029 #include "llvm/ADT/DenseMap.h"
00030 #include "llvm/ADT/SmallVector.h"
00031 #include "llvm/Support/Compiler.h"
00032 #include "llvm/Support/raw_ostream.h"
00033 #include <memory>
00034 
00035 // TODO: Adjust states of args to constructors in the same way that arguments to
00036 //       function calls are handled.
00037 // TODO: Use information from tests in for- and while-loop conditional.
00038 // TODO: Add notes about the actual and expected state for 
00039 // TODO: Correctly identify unreachable blocks when chaining boolean operators.
00040 // TODO: Adjust the parser and AttributesList class to support lists of
00041 //       identifiers.
00042 // TODO: Warn about unreachable code.
00043 // TODO: Switch to using a bitmap to track unreachable blocks.
00044 // TODO: Handle variable definitions, e.g. bool valid = x.isValid();
00045 //       if (valid) ...; (Deferred)
00046 // TODO: Take notes on state transitions to provide better warning messages.
00047 //       (Deferred)
00048 // TODO: Test nested conditionals: A) Checking the same value multiple times,
00049 //       and 2) Checking different values. (Deferred)
00050 
00051 using namespace clang;
00052 using namespace consumed;
00053 
00054 // Key method definition
00055 ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
00056 
00057 static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
00058   // Find the source location of the first statement in the block, if the block
00059   // is not empty.
00060   for (const auto &B : *Block)
00061     if (Optional<CFGStmt> CS = B.getAs<CFGStmt>())
00062       return CS->getStmt()->getLocStart();
00063 
00064   // Block is empty.
00065   // If we have one successor, return the first statement in that block
00066   if (Block->succ_size() == 1 && *Block->succ_begin())
00067     return getFirstStmtLoc(*Block->succ_begin());
00068 
00069   return SourceLocation();
00070 }
00071 
00072 static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
00073   // Find the source location of the last statement in the block, if the block
00074   // is not empty.
00075   if (const Stmt *StmtNode = Block->getTerminator()) {
00076     return StmtNode->getLocStart();
00077   } else {
00078     for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
00079          BE = Block->rend(); BI != BE; ++BI) {
00080       if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
00081         return CS->getStmt()->getLocStart();
00082     }
00083   }
00084 
00085   // If we have one successor, return the first statement in that block
00086   SourceLocation Loc;
00087   if (Block->succ_size() == 1 && *Block->succ_begin())
00088     Loc = getFirstStmtLoc(*Block->succ_begin());
00089   if (Loc.isValid())
00090     return Loc;
00091 
00092   // If we have one predecessor, return the last statement in that block
00093   if (Block->pred_size() == 1 && *Block->pred_begin())
00094     return getLastStmtLoc(*Block->pred_begin());
00095 
00096   return Loc;
00097 }
00098 
00099 static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
00100   switch (State) {
00101   case CS_Unconsumed:
00102     return CS_Consumed;
00103   case CS_Consumed:
00104     return CS_Unconsumed;
00105   case CS_None:
00106     return CS_None;
00107   case CS_Unknown:
00108     return CS_Unknown;
00109   }
00110   llvm_unreachable("invalid enum");
00111 }
00112 
00113 static bool isCallableInState(const CallableWhenAttr *CWAttr,
00114                               ConsumedState State) {
00115   
00116   for (const auto &S : CWAttr->callableStates()) {
00117     ConsumedState MappedAttrState = CS_None;
00118 
00119     switch (S) {
00120     case CallableWhenAttr::Unknown:
00121       MappedAttrState = CS_Unknown;
00122       break;
00123       
00124     case CallableWhenAttr::Unconsumed:
00125       MappedAttrState = CS_Unconsumed;
00126       break;
00127       
00128     case CallableWhenAttr::Consumed:
00129       MappedAttrState = CS_Consumed;
00130       break;
00131     }
00132     
00133     if (MappedAttrState == State)
00134       return true;
00135   }
00136   
00137   return false;
00138 }
00139 
00140 
00141 static bool isConsumableType(const QualType &QT) {
00142   if (QT->isPointerType() || QT->isReferenceType())
00143     return false;
00144   
00145   if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
00146     return RD->hasAttr<ConsumableAttr>();
00147   
00148   return false;
00149 }
00150 
00151 static bool isAutoCastType(const QualType &QT) {
00152   if (QT->isPointerType() || QT->isReferenceType())
00153     return false;
00154 
00155   if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
00156     return RD->hasAttr<ConsumableAutoCastAttr>();
00157 
00158   return false;
00159 }
00160 
00161 static bool isSetOnReadPtrType(const QualType &QT) {
00162   if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
00163     return RD->hasAttr<ConsumableSetOnReadAttr>();
00164   return false;
00165 }
00166 
00167 
00168 static bool isKnownState(ConsumedState State) {
00169   switch (State) {
00170   case CS_Unconsumed:
00171   case CS_Consumed:
00172     return true;
00173   case CS_None:
00174   case CS_Unknown:
00175     return false;
00176   }
00177   llvm_unreachable("invalid enum");
00178 }
00179 
00180 static bool isRValueRef(QualType ParamType) {
00181   return ParamType->isRValueReferenceType();
00182 }
00183 
00184 static bool isTestingFunction(const FunctionDecl *FunDecl) {
00185   return FunDecl->hasAttr<TestTypestateAttr>();
00186 }
00187 
00188 static bool isPointerOrRef(QualType ParamType) {
00189   return ParamType->isPointerType() || ParamType->isReferenceType();
00190 }
00191 
00192 static ConsumedState mapConsumableAttrState(const QualType QT) {
00193   assert(isConsumableType(QT));
00194 
00195   const ConsumableAttr *CAttr =
00196       QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
00197 
00198   switch (CAttr->getDefaultState()) {
00199   case ConsumableAttr::Unknown:
00200     return CS_Unknown;
00201   case ConsumableAttr::Unconsumed:
00202     return CS_Unconsumed;
00203   case ConsumableAttr::Consumed:
00204     return CS_Consumed;
00205   }
00206   llvm_unreachable("invalid enum");
00207 }
00208 
00209 static ConsumedState
00210 mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
00211   switch (PTAttr->getParamState()) {
00212   case ParamTypestateAttr::Unknown:
00213     return CS_Unknown;
00214   case ParamTypestateAttr::Unconsumed:
00215     return CS_Unconsumed;
00216   case ParamTypestateAttr::Consumed:
00217     return CS_Consumed;
00218   }
00219   llvm_unreachable("invalid_enum");
00220 }
00221 
00222 static ConsumedState
00223 mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
00224   switch (RTSAttr->getState()) {
00225   case ReturnTypestateAttr::Unknown:
00226     return CS_Unknown;
00227   case ReturnTypestateAttr::Unconsumed:
00228     return CS_Unconsumed;
00229   case ReturnTypestateAttr::Consumed:
00230     return CS_Consumed;
00231   }
00232   llvm_unreachable("invalid enum");
00233 }
00234 
00235 static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
00236   switch (STAttr->getNewState()) {
00237   case SetTypestateAttr::Unknown:
00238     return CS_Unknown;
00239   case SetTypestateAttr::Unconsumed:
00240     return CS_Unconsumed;
00241   case SetTypestateAttr::Consumed:
00242     return CS_Consumed;
00243   }
00244   llvm_unreachable("invalid_enum");
00245 }
00246 
00247 static StringRef stateToString(ConsumedState State) {
00248   switch (State) {
00249   case consumed::CS_None:
00250     return "none";
00251   
00252   case consumed::CS_Unknown:
00253     return "unknown";
00254   
00255   case consumed::CS_Unconsumed:
00256     return "unconsumed";
00257   
00258   case consumed::CS_Consumed:
00259     return "consumed";
00260   }
00261   llvm_unreachable("invalid enum");
00262 }
00263 
00264 static ConsumedState testsFor(const FunctionDecl *FunDecl) {
00265   assert(isTestingFunction(FunDecl));
00266   switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
00267   case TestTypestateAttr::Unconsumed:
00268     return CS_Unconsumed;
00269   case TestTypestateAttr::Consumed:
00270     return CS_Consumed;
00271   }
00272   llvm_unreachable("invalid enum");
00273 }
00274 
00275 namespace {
00276 struct VarTestResult {
00277   const VarDecl *Var;
00278   ConsumedState TestsFor;
00279 };
00280 } // end anonymous::VarTestResult
00281 
00282 namespace clang {
00283 namespace consumed {
00284 
00285 enum EffectiveOp {
00286   EO_And,
00287   EO_Or
00288 };
00289 
00290 class PropagationInfo {
00291   enum {
00292     IT_None,
00293     IT_State,
00294     IT_VarTest,
00295     IT_BinTest,
00296     IT_Var,
00297     IT_Tmp
00298   } InfoType;
00299 
00300   struct BinTestTy {
00301     const BinaryOperator *Source;
00302     EffectiveOp EOp;
00303     VarTestResult LTest;
00304     VarTestResult RTest;
00305   };
00306   
00307   union {
00308     ConsumedState State;
00309     VarTestResult VarTest;
00310     const VarDecl *Var;
00311     const CXXBindTemporaryExpr *Tmp;
00312     BinTestTy BinTest;
00313   };
00314   
00315 public:
00316   PropagationInfo() : InfoType(IT_None) {}
00317   
00318   PropagationInfo(const VarTestResult &VarTest)
00319     : InfoType(IT_VarTest), VarTest(VarTest) {}
00320   
00321   PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
00322     : InfoType(IT_VarTest) {
00323     
00324     VarTest.Var      = Var;
00325     VarTest.TestsFor = TestsFor;
00326   }
00327   
00328   PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
00329                   const VarTestResult &LTest, const VarTestResult &RTest)
00330     : InfoType(IT_BinTest) {
00331     
00332     BinTest.Source  = Source;
00333     BinTest.EOp     = EOp;
00334     BinTest.LTest   = LTest;
00335     BinTest.RTest   = RTest;
00336   }
00337   
00338   PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
00339                   const VarDecl *LVar, ConsumedState LTestsFor,
00340                   const VarDecl *RVar, ConsumedState RTestsFor)
00341     : InfoType(IT_BinTest) {
00342     
00343     BinTest.Source         = Source;
00344     BinTest.EOp            = EOp;
00345     BinTest.LTest.Var      = LVar;
00346     BinTest.LTest.TestsFor = LTestsFor;
00347     BinTest.RTest.Var      = RVar;
00348     BinTest.RTest.TestsFor = RTestsFor;
00349   }
00350   
00351   PropagationInfo(ConsumedState State)
00352     : InfoType(IT_State), State(State) {}
00353   
00354   PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
00355   PropagationInfo(const CXXBindTemporaryExpr *Tmp)
00356     : InfoType(IT_Tmp), Tmp(Tmp) {}
00357   
00358   const ConsumedState & getState() const {
00359     assert(InfoType == IT_State);
00360     return State;
00361   }
00362   
00363   const VarTestResult & getVarTest() const {
00364     assert(InfoType == IT_VarTest);
00365     return VarTest;
00366   }
00367   
00368   const VarTestResult & getLTest() const {
00369     assert(InfoType == IT_BinTest);
00370     return BinTest.LTest;
00371   }
00372   
00373   const VarTestResult & getRTest() const {
00374     assert(InfoType == IT_BinTest);
00375     return BinTest.RTest;
00376   }
00377   
00378   const VarDecl * getVar() const {
00379     assert(InfoType == IT_Var);
00380     return Var;
00381   }
00382   
00383   const CXXBindTemporaryExpr * getTmp() const {
00384     assert(InfoType == IT_Tmp);
00385     return Tmp;
00386   }
00387   
00388   ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
00389     assert(isVar() || isTmp() || isState());
00390     
00391     if (isVar())
00392       return StateMap->getState(Var);
00393     else if (isTmp())
00394       return StateMap->getState(Tmp);
00395     else if (isState())
00396       return State;
00397     else
00398       return CS_None;
00399   }
00400   
00401   EffectiveOp testEffectiveOp() const {
00402     assert(InfoType == IT_BinTest);
00403     return BinTest.EOp;
00404   }
00405   
00406   const BinaryOperator * testSourceNode() const {
00407     assert(InfoType == IT_BinTest);
00408     return BinTest.Source;
00409   }
00410   
00411   inline bool isValid()   const { return InfoType != IT_None;    }
00412   inline bool isState()   const { return InfoType == IT_State;   }
00413   inline bool isVarTest() const { return InfoType == IT_VarTest; }
00414   inline bool isBinTest() const { return InfoType == IT_BinTest; }
00415   inline bool isVar()     const { return InfoType == IT_Var;     }
00416   inline bool isTmp()     const { return InfoType == IT_Tmp;     }
00417   
00418   bool isTest() const {
00419     return InfoType == IT_VarTest || InfoType == IT_BinTest;
00420   }
00421   
00422   bool isPointerToValue() const {
00423     return InfoType == IT_Var || InfoType == IT_Tmp;
00424   }
00425   
00426   PropagationInfo invertTest() const {
00427     assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
00428     
00429     if (InfoType == IT_VarTest) {
00430       return PropagationInfo(VarTest.Var,
00431                              invertConsumedUnconsumed(VarTest.TestsFor));
00432     
00433     } else if (InfoType == IT_BinTest) {
00434       return PropagationInfo(BinTest.Source,
00435         BinTest.EOp == EO_And ? EO_Or : EO_And,
00436         BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
00437         BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
00438     } else {
00439       return PropagationInfo();
00440     }
00441   }
00442 };
00443 
00444 static inline void
00445 setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
00446                     ConsumedState State) {
00447 
00448   assert(PInfo.isVar() || PInfo.isTmp());
00449   
00450   if (PInfo.isVar())
00451     StateMap->setState(PInfo.getVar(), State);
00452   else
00453     StateMap->setState(PInfo.getTmp(), State);
00454 }
00455 
00456 class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
00457   
00458   typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
00459   typedef std::pair<const Stmt *, PropagationInfo> PairType;
00460   typedef MapType::iterator InfoEntry;
00461   typedef MapType::const_iterator ConstInfoEntry;
00462   
00463   AnalysisDeclContext &AC;
00464   ConsumedAnalyzer &Analyzer;
00465   ConsumedStateMap *StateMap;
00466   MapType PropagationMap;
00467 
00468   InfoEntry findInfo(const Expr *E) {
00469     return PropagationMap.find(E->IgnoreParens());
00470   }
00471   ConstInfoEntry findInfo(const Expr *E) const {
00472     return PropagationMap.find(E->IgnoreParens());
00473   }
00474   void insertInfo(const Expr *E, const PropagationInfo &PI) {
00475     PropagationMap.insert(PairType(E->IgnoreParens(), PI));
00476   }
00477 
00478   void forwardInfo(const Expr *From, const Expr *To);
00479   void copyInfo(const Expr *From, const Expr *To, ConsumedState CS);
00480   ConsumedState getInfo(const Expr *From);
00481   void setInfo(const Expr *To, ConsumedState NS);
00482   void propagateReturnType(const Expr *Call, const FunctionDecl *Fun);
00483 
00484 public:
00485   void checkCallability(const PropagationInfo &PInfo,
00486                         const FunctionDecl *FunDecl,
00487                         SourceLocation BlameLoc);
00488   bool handleCall(const CallExpr *Call, const Expr *ObjArg,
00489                   const FunctionDecl *FunD);
00490   
00491   void VisitBinaryOperator(const BinaryOperator *BinOp);
00492   void VisitCallExpr(const CallExpr *Call);
00493   void VisitCastExpr(const CastExpr *Cast);
00494   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
00495   void VisitCXXConstructExpr(const CXXConstructExpr *Call);
00496   void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
00497   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
00498   void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
00499   void VisitDeclStmt(const DeclStmt *DelcS);
00500   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
00501   void VisitMemberExpr(const MemberExpr *MExpr);
00502   void VisitParmVarDecl(const ParmVarDecl *Param);
00503   void VisitReturnStmt(const ReturnStmt *Ret);
00504   void VisitUnaryOperator(const UnaryOperator *UOp);
00505   void VisitVarDecl(const VarDecl *Var);
00506 
00507   ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
00508                       ConsumedStateMap *StateMap)
00509       : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
00510   
00511   PropagationInfo getInfo(const Expr *StmtNode) const {
00512     ConstInfoEntry Entry = findInfo(StmtNode);
00513     
00514     if (Entry != PropagationMap.end())
00515       return Entry->second;
00516     else
00517       return PropagationInfo();
00518   }
00519   
00520   void reset(ConsumedStateMap *NewStateMap) {
00521     StateMap = NewStateMap;
00522   }
00523 };
00524 
00525 
00526 void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
00527   InfoEntry Entry = findInfo(From);
00528   if (Entry != PropagationMap.end())
00529     insertInfo(To, Entry->second);
00530 }
00531 
00532 
00533 // Create a new state for To, which is initialized to the state of From.
00534 // If NS is not CS_None, sets the state of From to NS.
00535 void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
00536                                    ConsumedState NS) {
00537   InfoEntry Entry = findInfo(From);
00538   if (Entry != PropagationMap.end()) {
00539     PropagationInfo& PInfo = Entry->second;
00540     ConsumedState CS = PInfo.getAsState(StateMap);
00541     if (CS != CS_None)
00542       insertInfo(To, PropagationInfo(CS));
00543     if (NS != CS_None && PInfo.isPointerToValue())
00544       setStateForVarOrTmp(StateMap, PInfo, NS);
00545   }
00546 }
00547 
00548 
00549 // Get the ConsumedState for From
00550 ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
00551   InfoEntry Entry = findInfo(From);
00552   if (Entry != PropagationMap.end()) {
00553     PropagationInfo& PInfo = Entry->second;
00554     return PInfo.getAsState(StateMap);
00555   }
00556   return CS_None;
00557 }
00558 
00559 
00560 // If we already have info for To then update it, otherwise create a new entry.
00561 void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
00562   InfoEntry Entry = findInfo(To);
00563   if (Entry != PropagationMap.end()) {
00564     PropagationInfo& PInfo = Entry->second;
00565     if (PInfo.isPointerToValue())
00566       setStateForVarOrTmp(StateMap, PInfo, NS);
00567   } else if (NS != CS_None) {
00568      insertInfo(To, PropagationInfo(NS));
00569   }
00570 }
00571 
00572 
00573 
00574 void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
00575                                            const FunctionDecl *FunDecl,
00576                                            SourceLocation BlameLoc) {
00577   assert(!PInfo.isTest());
00578 
00579   const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
00580   if (!CWAttr)
00581     return;
00582 
00583   if (PInfo.isVar()) {
00584     ConsumedState VarState = StateMap->getState(PInfo.getVar());
00585 
00586     if (VarState == CS_None || isCallableInState(CWAttr, VarState))
00587       return;
00588 
00589     Analyzer.WarningsHandler.warnUseInInvalidState(
00590       FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
00591       stateToString(VarState), BlameLoc);
00592 
00593   } else {
00594     ConsumedState TmpState = PInfo.getAsState(StateMap);
00595 
00596     if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
00597       return;
00598 
00599     Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
00600       FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
00601   }
00602 }
00603 
00604 
00605 // Factors out common behavior for function, method, and operator calls.
00606 // Check parameters and set parameter state if necessary.
00607 // Returns true if the state of ObjArg is set, or false otherwise.
00608 bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
00609                                      const FunctionDecl *FunD) {
00610   unsigned Offset = 0;
00611   if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
00612     Offset = 1;  // first argument is 'this'
00613 
00614   // check explicit parameters
00615   for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
00616     // Skip variable argument lists.
00617     if (Index - Offset >= FunD->getNumParams())
00618       break;
00619 
00620     const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
00621     QualType ParamType = Param->getType();
00622 
00623     InfoEntry Entry = findInfo(Call->getArg(Index));
00624 
00625     if (Entry == PropagationMap.end() || Entry->second.isTest())
00626       continue;
00627     PropagationInfo PInfo = Entry->second;
00628 
00629     // Check that the parameter is in the correct state.
00630     if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
00631       ConsumedState ParamState = PInfo.getAsState(StateMap);
00632       ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
00633 
00634       if (ParamState != ExpectedState)
00635         Analyzer.WarningsHandler.warnParamTypestateMismatch(
00636           Call->getArg(Index)->getExprLoc(),
00637           stateToString(ExpectedState), stateToString(ParamState));
00638     }
00639 
00640     if (!(Entry->second.isVar() || Entry->second.isTmp()))
00641       continue;
00642 
00643     // Adjust state on the caller side.
00644     if (isRValueRef(ParamType))
00645       setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
00646     else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
00647       setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
00648     else if (isPointerOrRef(ParamType) &&
00649              (!ParamType->getPointeeType().isConstQualified() ||
00650               isSetOnReadPtrType(ParamType)))
00651       setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
00652   }
00653 
00654   if (!ObjArg)
00655     return false;
00656 
00657   // check implicit 'self' parameter, if present
00658   InfoEntry Entry = findInfo(ObjArg);
00659   if (Entry != PropagationMap.end()) {
00660     PropagationInfo PInfo = Entry->second;
00661     checkCallability(PInfo, FunD, Call->getExprLoc());
00662 
00663     if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
00664       if (PInfo.isVar()) {
00665         StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
00666         return true;
00667       }
00668       else if (PInfo.isTmp()) {
00669         StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
00670         return true;
00671       }
00672     }
00673     else if (isTestingFunction(FunD) && PInfo.isVar()) {
00674       PropagationMap.insert(PairType(Call,
00675         PropagationInfo(PInfo.getVar(), testsFor(FunD))));
00676     }
00677   }
00678   return false;
00679 }
00680 
00681 
00682 void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
00683                                               const FunctionDecl *Fun) {
00684   QualType RetType = Fun->getCallResultType();
00685   if (RetType->isReferenceType())
00686     RetType = RetType->getPointeeType();
00687 
00688   if (isConsumableType(RetType)) {
00689     ConsumedState ReturnState;
00690     if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
00691       ReturnState = mapReturnTypestateAttrState(RTA);
00692     else
00693       ReturnState = mapConsumableAttrState(RetType);
00694     
00695     PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
00696   }
00697 }
00698 
00699 
00700 void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
00701   switch (BinOp->getOpcode()) {
00702   case BO_LAnd:
00703   case BO_LOr : {
00704     InfoEntry LEntry = findInfo(BinOp->getLHS()),
00705               REntry = findInfo(BinOp->getRHS());
00706     
00707     VarTestResult LTest, RTest;
00708     
00709     if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
00710       LTest = LEntry->second.getVarTest();
00711       
00712     } else {
00713       LTest.Var      = nullptr;
00714       LTest.TestsFor = CS_None;
00715     }
00716     
00717     if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
00718       RTest = REntry->second.getVarTest();
00719       
00720     } else {
00721       RTest.Var      = nullptr;
00722       RTest.TestsFor = CS_None;
00723     }
00724 
00725     if (!(LTest.Var == nullptr && RTest.Var == nullptr))
00726       PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
00727         static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
00728     
00729     break;
00730   }
00731     
00732   case BO_PtrMemD:
00733   case BO_PtrMemI:
00734     forwardInfo(BinOp->getLHS(), BinOp);
00735     break;
00736     
00737   default:
00738     break;
00739   }
00740 }
00741 
00742 void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
00743   const FunctionDecl *FunDecl = Call->getDirectCallee();
00744   if (!FunDecl)
00745     return;
00746 
00747   // Special case for the std::move function.
00748   // TODO: Make this more specific. (Deferred)
00749   if (Call->getNumArgs() == 1 && FunDecl->getNameAsString() == "move" &&
00750       FunDecl->isInStdNamespace()) {
00751     copyInfo(Call->getArg(0), Call, CS_Consumed);
00752     return;
00753   }
00754 
00755   handleCall(Call, nullptr, FunDecl);
00756   propagateReturnType(Call, FunDecl);
00757 }
00758 
00759 void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
00760   forwardInfo(Cast->getSubExpr(), Cast);
00761 }
00762 
00763 void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
00764   const CXXBindTemporaryExpr *Temp) {
00765   
00766   InfoEntry Entry = findInfo(Temp->getSubExpr());
00767   
00768   if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
00769     StateMap->setState(Temp, Entry->second.getAsState(StateMap));
00770     PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
00771   }
00772 }
00773 
00774 void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
00775   CXXConstructorDecl *Constructor = Call->getConstructor();
00776 
00777   ASTContext &CurrContext = AC.getASTContext();
00778   QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
00779   
00780   if (!isConsumableType(ThisType))
00781     return;
00782   
00783   // FIXME: What should happen if someone annotates the move constructor?
00784   if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
00785     // TODO: Adjust state of args appropriately.    
00786     ConsumedState RetState = mapReturnTypestateAttrState(RTA);
00787     PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
00788   } else if (Constructor->isDefaultConstructor()) {
00789     PropagationMap.insert(PairType(Call,
00790       PropagationInfo(consumed::CS_Consumed)));
00791   } else if (Constructor->isMoveConstructor()) {
00792     copyInfo(Call->getArg(0), Call, CS_Consumed);
00793   } else if (Constructor->isCopyConstructor()) {
00794     // Copy state from arg.  If setStateOnRead then set arg to CS_Unknown.
00795     ConsumedState NS =
00796       isSetOnReadPtrType(Constructor->getThisType(CurrContext)) ?
00797       CS_Unknown : CS_None;
00798     copyInfo(Call->getArg(0), Call, NS);
00799   } else {
00800     // TODO: Adjust state of args appropriately.
00801     ConsumedState RetState = mapConsumableAttrState(ThisType);
00802     PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
00803   }
00804 }
00805 
00806 
00807 void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
00808     const CXXMemberCallExpr *Call) {
00809   CXXMethodDecl* MD = Call->getMethodDecl();
00810   if (!MD)
00811     return;
00812 
00813   handleCall(Call, Call->getImplicitObjectArgument(), MD);
00814   propagateReturnType(Call, MD);
00815 }
00816 
00817 
00818 void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
00819     const CXXOperatorCallExpr *Call) {
00820 
00821   const FunctionDecl *FunDecl =
00822     dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
00823   if (!FunDecl) return;
00824 
00825   if (Call->getOperator() == OO_Equal) {
00826     ConsumedState CS = getInfo(Call->getArg(1));
00827     if (!handleCall(Call, Call->getArg(0), FunDecl))
00828       setInfo(Call->getArg(0), CS);
00829     return;
00830   }
00831 
00832   if (const CXXMemberCallExpr *MCall = dyn_cast<CXXMemberCallExpr>(Call))
00833     handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
00834   else
00835     handleCall(Call, Call->getArg(0), FunDecl);
00836 
00837   propagateReturnType(Call, FunDecl);
00838 }
00839 
00840 void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
00841   if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
00842     if (StateMap->getState(Var) != consumed::CS_None)
00843       PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
00844 }
00845 
00846 void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
00847   for (const auto *DI : DeclS->decls())    
00848     if (isa<VarDecl>(DI))
00849       VisitVarDecl(cast<VarDecl>(DI));
00850   
00851   if (DeclS->isSingleDecl())
00852     if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
00853       PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
00854 }
00855 
00856 void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
00857   const MaterializeTemporaryExpr *Temp) {
00858   
00859   forwardInfo(Temp->GetTemporaryExpr(), Temp);
00860 }
00861 
00862 void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
00863   forwardInfo(MExpr->getBase(), MExpr);
00864 }
00865 
00866 
00867 void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
00868   QualType ParamType = Param->getType();
00869   ConsumedState ParamState = consumed::CS_None;
00870   
00871   if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
00872     ParamState = mapParamTypestateAttrState(PTA);    
00873   else if (isConsumableType(ParamType))
00874     ParamState = mapConsumableAttrState(ParamType);    
00875   else if (isRValueRef(ParamType) &&
00876            isConsumableType(ParamType->getPointeeType()))
00877     ParamState = mapConsumableAttrState(ParamType->getPointeeType());    
00878   else if (ParamType->isReferenceType() &&
00879            isConsumableType(ParamType->getPointeeType()))
00880     ParamState = consumed::CS_Unknown;
00881   
00882   if (ParamState != CS_None)
00883     StateMap->setState(Param, ParamState);
00884 }
00885 
00886 void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
00887   ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
00888   
00889   if (ExpectedState != CS_None) {
00890     InfoEntry Entry = findInfo(Ret->getRetValue());
00891     
00892     if (Entry != PropagationMap.end()) {
00893       ConsumedState RetState = Entry->second.getAsState(StateMap);
00894         
00895       if (RetState != ExpectedState)
00896         Analyzer.WarningsHandler.warnReturnTypestateMismatch(
00897           Ret->getReturnLoc(), stateToString(ExpectedState),
00898           stateToString(RetState));
00899     }
00900   }
00901   
00902   StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
00903                                           Analyzer.WarningsHandler);
00904 }
00905 
00906 void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
00907   InfoEntry Entry = findInfo(UOp->getSubExpr());
00908   if (Entry == PropagationMap.end()) return;
00909   
00910   switch (UOp->getOpcode()) {
00911   case UO_AddrOf:
00912     PropagationMap.insert(PairType(UOp, Entry->second));
00913     break;
00914   
00915   case UO_LNot:
00916     if (Entry->second.isTest())
00917       PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
00918     break;
00919   
00920   default:
00921     break;
00922   }
00923 }
00924 
00925 // TODO: See if I need to check for reference types here.
00926 void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
00927   if (isConsumableType(Var->getType())) {
00928     if (Var->hasInit()) {
00929       MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
00930       if (VIT != PropagationMap.end()) {
00931         PropagationInfo PInfo = VIT->second;
00932         ConsumedState St = PInfo.getAsState(StateMap);
00933         
00934         if (St != consumed::CS_None) {
00935           StateMap->setState(Var, St);
00936           return;
00937         }
00938       }
00939     }
00940     // Otherwise
00941     StateMap->setState(Var, consumed::CS_Unknown);
00942   }
00943 }
00944 }} // end clang::consumed::ConsumedStmtVisitor
00945 
00946 namespace clang {
00947 namespace consumed {
00948 
00949 void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
00950                         ConsumedStateMap *ThenStates,
00951                         ConsumedStateMap *ElseStates) {
00952 
00953   ConsumedState VarState = ThenStates->getState(Test.Var);
00954   
00955   if (VarState == CS_Unknown) {
00956     ThenStates->setState(Test.Var, Test.TestsFor);
00957     ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
00958   
00959   } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
00960     ThenStates->markUnreachable();
00961     
00962   } else if (VarState == Test.TestsFor) {
00963     ElseStates->markUnreachable();
00964   }
00965 }
00966 
00967 void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
00968   ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
00969   
00970   const VarTestResult &LTest = PInfo.getLTest(),
00971                       &RTest = PInfo.getRTest();
00972   
00973   ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
00974                 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
00975   
00976   if (LTest.Var) {
00977     if (PInfo.testEffectiveOp() == EO_And) {
00978       if (LState == CS_Unknown) {
00979         ThenStates->setState(LTest.Var, LTest.TestsFor);
00980         
00981       } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
00982         ThenStates->markUnreachable();
00983         
00984       } else if (LState == LTest.TestsFor && isKnownState(RState)) {
00985         if (RState == RTest.TestsFor)
00986           ElseStates->markUnreachable();
00987         else
00988           ThenStates->markUnreachable();
00989       }
00990       
00991     } else {
00992       if (LState == CS_Unknown) {
00993         ElseStates->setState(LTest.Var,
00994                              invertConsumedUnconsumed(LTest.TestsFor));
00995       
00996       } else if (LState == LTest.TestsFor) {
00997         ElseStates->markUnreachable();
00998         
00999       } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
01000                  isKnownState(RState)) {
01001         
01002         if (RState == RTest.TestsFor)
01003           ElseStates->markUnreachable();
01004         else
01005           ThenStates->markUnreachable();
01006       }
01007     }
01008   }
01009   
01010   if (RTest.Var) {
01011     if (PInfo.testEffectiveOp() == EO_And) {
01012       if (RState == CS_Unknown)
01013         ThenStates->setState(RTest.Var, RTest.TestsFor);
01014       else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
01015         ThenStates->markUnreachable();
01016       
01017     } else {
01018       if (RState == CS_Unknown)
01019         ElseStates->setState(RTest.Var,
01020                              invertConsumedUnconsumed(RTest.TestsFor));
01021       else if (RState == RTest.TestsFor)
01022         ElseStates->markUnreachable();
01023     }
01024   }
01025 }
01026 
01027 bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
01028                                             const CFGBlock *TargetBlock) {
01029   
01030   assert(CurrBlock && "Block pointer must not be NULL");
01031   assert(TargetBlock && "TargetBlock pointer must not be NULL");
01032   
01033   unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
01034   for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
01035        PE = TargetBlock->pred_end(); PI != PE; ++PI) {
01036     if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
01037       return false;
01038   }
01039   return true;
01040 }
01041 
01042 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
01043                                 ConsumedStateMap *StateMap,
01044                                 bool &AlreadyOwned) {
01045   
01046   assert(Block && "Block pointer must not be NULL");
01047   
01048   ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
01049     
01050   if (Entry) {
01051     Entry->intersect(StateMap);
01052     
01053   } else if (AlreadyOwned) {
01054     StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
01055     
01056   } else {
01057     StateMapsArray[Block->getBlockID()] = StateMap;
01058     AlreadyOwned = true;
01059   }
01060 }
01061 
01062 void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
01063                                 ConsumedStateMap *StateMap) {
01064 
01065   assert(Block && "Block pointer must not be NULL");
01066 
01067   ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
01068     
01069   if (Entry) {
01070     Entry->intersect(StateMap);
01071     delete StateMap;
01072     
01073   } else {
01074     StateMapsArray[Block->getBlockID()] = StateMap;
01075   }
01076 }
01077 
01078 ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
01079   assert(Block && "Block pointer must not be NULL");
01080   assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
01081   
01082   return StateMapsArray[Block->getBlockID()];
01083 }
01084 
01085 void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
01086   unsigned int BlockID = Block->getBlockID();
01087   delete StateMapsArray[BlockID];
01088   StateMapsArray[BlockID] = nullptr;
01089 }
01090 
01091 ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
01092   assert(Block && "Block pointer must not be NULL");
01093   
01094   ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
01095   if (isBackEdgeTarget(Block)) {
01096     return new ConsumedStateMap(*StateMap);
01097   } else {
01098     StateMapsArray[Block->getBlockID()] = nullptr;
01099     return StateMap;
01100   }
01101 }
01102 
01103 bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
01104   assert(From && "From block must not be NULL");
01105   assert(To   && "From block must not be NULL");
01106   
01107   return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
01108 }
01109 
01110 bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
01111   assert(Block && "Block pointer must not be NULL");
01112 
01113   // Anything with less than two predecessors can't be the target of a back
01114   // edge.
01115   if (Block->pred_size() < 2)
01116     return false;
01117   
01118   unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
01119   for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
01120        PE = Block->pred_end(); PI != PE; ++PI) {
01121     if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
01122       return true;
01123   }
01124   return false;
01125 }
01126 
01127 void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
01128   ConsumedWarningsHandlerBase &WarningsHandler) const {
01129   
01130   for (const auto &DM : VarMap) {
01131     if (isa<ParmVarDecl>(DM.first)) {
01132       const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first);
01133       const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
01134       
01135       if (!RTA)
01136         continue;
01137       
01138       ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);      
01139       if (DM.second != ExpectedState)
01140         WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
01141           Param->getNameAsString(), stateToString(ExpectedState),
01142           stateToString(DM.second));
01143     }
01144   }
01145 }
01146 
01147 void ConsumedStateMap::clearTemporaries() {
01148   TmpMap.clear();
01149 }
01150 
01151 ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
01152   VarMapType::const_iterator Entry = VarMap.find(Var);
01153   
01154   if (Entry != VarMap.end())
01155     return Entry->second;
01156     
01157   return CS_None;
01158 }
01159 
01160 ConsumedState
01161 ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
01162   TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
01163   
01164   if (Entry != TmpMap.end())
01165     return Entry->second;
01166   
01167   return CS_None;
01168 }
01169 
01170 void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
01171   ConsumedState LocalState;
01172   
01173   if (this->From && this->From == Other->From && !Other->Reachable) {
01174     this->markUnreachable();
01175     return;
01176   }
01177   
01178   for (const auto &DM : Other->VarMap) {
01179     LocalState = this->getState(DM.first);
01180     
01181     if (LocalState == CS_None)
01182       continue;
01183     
01184     if (LocalState != DM.second)
01185      VarMap[DM.first] = CS_Unknown;
01186   }
01187 }
01188 
01189 void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
01190   const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
01191   ConsumedWarningsHandlerBase &WarningsHandler) {
01192   
01193   ConsumedState LocalState;
01194   SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
01195   
01196   for (const auto &DM : LoopBackStates->VarMap) {    
01197     LocalState = this->getState(DM.first);
01198     
01199     if (LocalState == CS_None)
01200       continue;
01201     
01202     if (LocalState != DM.second) {
01203       VarMap[DM.first] = CS_Unknown;
01204       WarningsHandler.warnLoopStateMismatch(BlameLoc,
01205                                             DM.first->getNameAsString());
01206     }
01207   }
01208 }
01209 
01210 void ConsumedStateMap::markUnreachable() {
01211   this->Reachable = false;
01212   VarMap.clear();
01213   TmpMap.clear();
01214 }
01215 
01216 void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
01217   VarMap[Var] = State;
01218 }
01219 
01220 void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
01221                                 ConsumedState State) {
01222   TmpMap[Tmp] = State;
01223 }
01224 
01225 void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
01226   TmpMap.erase(Tmp);
01227 }
01228 
01229 bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
01230   for (const auto &DM : Other->VarMap)
01231     if (this->getState(DM.first) != DM.second)
01232       return true;  
01233   return false;
01234 }
01235 
01236 void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
01237                                                     const FunctionDecl *D) {
01238   QualType ReturnType;
01239   if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
01240     ASTContext &CurrContext = AC.getASTContext();
01241     ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
01242   } else
01243     ReturnType = D->getCallResultType();
01244 
01245   if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
01246     const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
01247     if (!RD || !RD->hasAttr<ConsumableAttr>()) {
01248       // FIXME: This should be removed when template instantiation propagates
01249       //        attributes at template specialization definition, not
01250       //        declaration. When it is removed the test needs to be enabled
01251       //        in SemaDeclAttr.cpp.
01252       WarningsHandler.warnReturnTypestateForUnconsumableType(
01253           RTSAttr->getLocation(), ReturnType.getAsString());
01254       ExpectedReturnState = CS_None;
01255     } else
01256       ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
01257   } else if (isConsumableType(ReturnType)) {
01258     if (isAutoCastType(ReturnType))   // We can auto-cast the state to the
01259       ExpectedReturnState = CS_None;  // expected state.
01260     else
01261       ExpectedReturnState = mapConsumableAttrState(ReturnType);
01262   }
01263   else
01264     ExpectedReturnState = CS_None;
01265 }
01266 
01267 bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
01268                                   const ConsumedStmtVisitor &Visitor) {
01269 
01270   std::unique_ptr<ConsumedStateMap> FalseStates(
01271       new ConsumedStateMap(*CurrStates));
01272   PropagationInfo PInfo;
01273   
01274   if (const IfStmt *IfNode =
01275     dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
01276     
01277     const Expr *Cond = IfNode->getCond();
01278     
01279     PInfo = Visitor.getInfo(Cond);
01280     if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
01281       PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
01282     
01283     if (PInfo.isVarTest()) {
01284       CurrStates->setSource(Cond);
01285       FalseStates->setSource(Cond);
01286       splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates,
01287                          FalseStates.get());
01288       
01289     } else if (PInfo.isBinTest()) {
01290       CurrStates->setSource(PInfo.testSourceNode());
01291       FalseStates->setSource(PInfo.testSourceNode());
01292       splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get());
01293       
01294     } else {
01295       return false;
01296     }
01297     
01298   } else if (const BinaryOperator *BinOp =
01299     dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
01300     
01301     PInfo = Visitor.getInfo(BinOp->getLHS());
01302     if (!PInfo.isVarTest()) {
01303       if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
01304         PInfo = Visitor.getInfo(BinOp->getRHS());
01305         
01306         if (!PInfo.isVarTest())
01307           return false;
01308         
01309       } else {
01310         return false;
01311       }
01312     }
01313     
01314     CurrStates->setSource(BinOp);
01315     FalseStates->setSource(BinOp);
01316     
01317     const VarTestResult &Test = PInfo.getVarTest();
01318     ConsumedState VarState = CurrStates->getState(Test.Var);
01319     
01320     if (BinOp->getOpcode() == BO_LAnd) {
01321       if (VarState == CS_Unknown)
01322         CurrStates->setState(Test.Var, Test.TestsFor);
01323       else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
01324         CurrStates->markUnreachable();
01325       
01326     } else if (BinOp->getOpcode() == BO_LOr) {
01327       if (VarState == CS_Unknown)
01328         FalseStates->setState(Test.Var,
01329                               invertConsumedUnconsumed(Test.TestsFor));
01330       else if (VarState == Test.TestsFor)
01331         FalseStates->markUnreachable();
01332     }
01333     
01334   } else {
01335     return false;
01336   }
01337   
01338   CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
01339   
01340   if (*SI)
01341     BlockInfo.addInfo(*SI, CurrStates);
01342   else
01343     delete CurrStates;
01344     
01345   if (*++SI)
01346     BlockInfo.addInfo(*SI, FalseStates.release());
01347 
01348   CurrStates = nullptr;
01349   return true;
01350 }
01351 
01352 void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
01353   const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
01354   if (!D)
01355     return;
01356   
01357   CFG *CFGraph = AC.getCFG();
01358   if (!CFGraph)
01359     return;
01360 
01361   determineExpectedReturnState(AC, D);
01362 
01363   PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
01364   // AC.getCFG()->viewCFG(LangOptions());
01365   
01366   BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
01367   
01368   CurrStates = new ConsumedStateMap();
01369   ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
01370   
01371   // Add all trackable parameters to the state map.
01372   for (const auto *PI : D->params())
01373     Visitor.VisitParmVarDecl(PI);
01374   
01375   // Visit all of the function's basic blocks.
01376   for (const auto *CurrBlock : *SortedGraph) {
01377     if (!CurrStates)
01378       CurrStates = BlockInfo.getInfo(CurrBlock);
01379     
01380     if (!CurrStates) {
01381       continue;
01382       
01383     } else if (!CurrStates->isReachable()) {
01384       delete CurrStates;
01385       CurrStates = nullptr;
01386       continue;
01387     }
01388     
01389     Visitor.reset(CurrStates);
01390     
01391     // Visit all of the basic block's statements.
01392     for (const auto &B : *CurrBlock) {
01393       switch (B.getKind()) {
01394       case CFGElement::Statement:
01395         Visitor.Visit(B.castAs<CFGStmt>().getStmt());
01396         break;
01397         
01398       case CFGElement::TemporaryDtor: {
01399         const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
01400         const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
01401         
01402         Visitor.checkCallability(PropagationInfo(BTE),
01403                                  DTor.getDestructorDecl(AC.getASTContext()),
01404                                  BTE->getExprLoc());
01405         CurrStates->remove(BTE);
01406         break;
01407       }
01408       
01409       case CFGElement::AutomaticObjectDtor: {
01410         const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
01411         SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
01412         const VarDecl *Var = DTor.getVarDecl();
01413         
01414         Visitor.checkCallability(PropagationInfo(Var),
01415                                  DTor.getDestructorDecl(AC.getASTContext()),
01416                                  Loc);
01417         break;
01418       }
01419       
01420       default:
01421         break;
01422       }
01423     }
01424     
01425     // TODO: Handle other forms of branching with precision, including while-
01426     //       and for-loops. (Deferred)
01427     if (!splitState(CurrBlock, Visitor)) {
01428       CurrStates->setSource(nullptr);
01429 
01430       if (CurrBlock->succ_size() > 1 ||
01431           (CurrBlock->succ_size() == 1 &&
01432            (*CurrBlock->succ_begin())->pred_size() > 1)) {
01433         
01434         bool OwnershipTaken = false;
01435         
01436         for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
01437              SE = CurrBlock->succ_end(); SI != SE; ++SI) {
01438 
01439           if (*SI == nullptr) continue;
01440 
01441           if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
01442             BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
01443                                                            CurrStates,
01444                                                            WarningsHandler);
01445             
01446             if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
01447               BlockInfo.discardInfo(*SI);
01448           } else {
01449             BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
01450           }
01451         }
01452         
01453         if (!OwnershipTaken)
01454           delete CurrStates;
01455 
01456         CurrStates = nullptr;
01457       }
01458     }
01459     
01460     if (CurrBlock == &AC.getCFG()->getExit() &&
01461         D->getCallResultType()->isVoidType())
01462       CurrStates->checkParamsForReturnTypestate(D->getLocation(),
01463                                                 WarningsHandler);
01464   } // End of block iterator.
01465   
01466   // Delete the last existing state map.
01467   delete CurrStates;
01468   
01469   WarningsHandler.emitDiagnostics();
01470 }
01471 }} // end namespace clang::consumed