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