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 <est, 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 <est = 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