blob: d1c03d091bb7717dd9c1633e95d6c1e455f8d384 [file] [log] [blame]
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001//===- Consumed.cpp --------------------------------------------*- C++ --*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// A intra-procedural analysis for checking consumed properties. This is based,
11// in part, on research on linear types.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/AST/RecursiveASTVisitor.h"
20#include "clang/AST/StmtVisitor.h"
21#include "clang/AST/StmtCXX.h"
22#include "clang/AST/Type.h"
23#include "clang/Analysis/Analyses/PostOrderCFGView.h"
24#include "clang/Analysis/AnalysisContext.h"
25#include "clang/Analysis/CFG.h"
26#include "clang/Analysis/Analyses/Consumed.h"
27#include "clang/Basic/OperatorKinds.h"
28#include "clang/Basic/SourceLocation.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000029#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/SmallVector.h"
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000031#include "llvm/Support/Compiler.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000032#include "llvm/Support/raw_ostream.h"
33
DeLesley Hutchins73858402013-10-09 18:30:24 +000034// TODO: Use information from tests in while-loop conditional.
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +000035// TODO: Add notes about the actual and expected state for
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000036// TODO: Correctly identify unreachable blocks when chaining boolean operators.
DeLesley Hutchins66540852013-10-04 21:28:06 +000037// TODO: Adjust the parser and AttributesList class to support lists of
38// identifiers.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000039// TODO: Warn about unreachable code.
40// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000041// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
42// if (valid) ...; (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000043// TODO: Take notes on state transitions to provide better warning messages.
44// (Deferred)
45// TODO: Test nested conditionals: A) Checking the same value multiple times,
46// and 2) Checking different values. (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000047
48using namespace clang;
49using namespace consumed;
50
51// Key method definition
52ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
53
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000054static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000055 // Find the source location of the last statement in the block, if the block
56 // is not empty.
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000057 if (const Stmt *StmtNode = Block->getTerminator()) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000058 return StmtNode->getLocStart();
59 } else {
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000060 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
61 BE = Block->rend(); BI != BE; ++BI) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000062 // FIXME: Handle other CFGElement kinds.
63 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
64 return CS->getStmt()->getLocStart();
65 }
66 }
67
68 // The block is empty, and has a single predecessor. Use its exit location.
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000069 assert(Block->pred_size() == 1 && *Block->pred_begin() &&
70 Block->succ_size() != 0);
DeLesley Hutchins73858402013-10-09 18:30:24 +000071
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000072 return getLastStmtLoc(*Block->pred_begin());
DeLesley Hutchins73858402013-10-09 18:30:24 +000073}
74
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000075static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
76 switch (State) {
77 case CS_Unconsumed:
78 return CS_Consumed;
79 case CS_Consumed:
80 return CS_Unconsumed;
81 case CS_None:
82 return CS_None;
83 case CS_Unknown:
84 return CS_Unknown;
85 }
86 llvm_unreachable("invalid enum");
87}
88
DeLesley Hutchins66540852013-10-04 21:28:06 +000089static bool isCallableInState(const CallableWhenAttr *CWAttr,
90 ConsumedState State) {
91
92 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
93 E = CWAttr->callableState_end();
94
95 for (; I != E; ++I) {
96
97 ConsumedState MappedAttrState = CS_None;
98
99 switch (*I) {
100 case CallableWhenAttr::Unknown:
101 MappedAttrState = CS_Unknown;
102 break;
103
104 case CallableWhenAttr::Unconsumed:
105 MappedAttrState = CS_Unconsumed;
106 break;
107
108 case CallableWhenAttr::Consumed:
109 MappedAttrState = CS_Consumed;
110 break;
111 }
112
113 if (MappedAttrState == State)
114 return true;
115 }
116
117 return false;
118}
119
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000120static bool isConsumableType(const QualType &QT) {
121 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
122 return RD->hasAttr<ConsumableAttr>();
123 else
124 return false;
125}
126
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000127static bool isKnownState(ConsumedState State) {
128 switch (State) {
129 case CS_Unconsumed:
130 case CS_Consumed:
131 return true;
132 case CS_None:
133 case CS_Unknown:
134 return false;
135 }
Aaron Ballman6b2ec032013-08-29 20:36:09 +0000136 llvm_unreachable("invalid enum");
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000137}
138
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000139static bool isTestingFunction(const FunctionDecl *FunDecl) {
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000140 return FunDecl->hasAttr<TestsTypestateAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000141}
142
David Blaikiea33ab602013-09-06 01:28:43 +0000143static ConsumedState mapConsumableAttrState(const QualType QT) {
144 assert(isConsumableType(QT));
145
146 const ConsumableAttr *CAttr =
147 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
148
149 switch (CAttr->getDefaultState()) {
150 case ConsumableAttr::Unknown:
151 return CS_Unknown;
152 case ConsumableAttr::Unconsumed:
153 return CS_Unconsumed;
154 case ConsumableAttr::Consumed:
155 return CS_Consumed;
156 }
157 llvm_unreachable("invalid enum");
158}
159
Eric Christophere988dc42013-09-03 20:43:00 +0000160static ConsumedState
161mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000162 switch (RTSAttr->getState()) {
163 case ReturnTypestateAttr::Unknown:
164 return CS_Unknown;
165 case ReturnTypestateAttr::Unconsumed:
166 return CS_Unconsumed;
167 case ReturnTypestateAttr::Consumed:
168 return CS_Consumed;
169 }
Eric Christophere988dc42013-09-03 20:43:00 +0000170 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000171}
172
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000173static StringRef stateToString(ConsumedState State) {
174 switch (State) {
175 case consumed::CS_None:
176 return "none";
177
178 case consumed::CS_Unknown:
179 return "unknown";
180
181 case consumed::CS_Unconsumed:
182 return "unconsumed";
183
184 case consumed::CS_Consumed:
185 return "consumed";
186 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000187 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000188}
189
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000190static ConsumedState testsFor(const FunctionDecl *FunDecl) {
191 assert(isTestingFunction(FunDecl));
192 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) {
193 case TestsTypestateAttr::Unconsumed:
194 return CS_Unconsumed;
195 case TestsTypestateAttr::Consumed:
196 return CS_Consumed;
197 }
198 llvm_unreachable("invalid enum");
199}
200
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000201namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000202struct VarTestResult {
203 const VarDecl *Var;
204 ConsumedState TestsFor;
205};
206} // end anonymous::VarTestResult
207
208namespace clang {
209namespace consumed {
210
211enum EffectiveOp {
212 EO_And,
213 EO_Or
214};
215
216class PropagationInfo {
217 enum {
218 IT_None,
219 IT_State,
220 IT_Test,
221 IT_BinTest,
222 IT_Var
223 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000224
225 struct BinTestTy {
226 const BinaryOperator *Source;
227 EffectiveOp EOp;
228 VarTestResult LTest;
229 VarTestResult RTest;
230 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000231
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000232 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000233 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000234 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000235 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000236 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000237 };
238
DeLesley Hutchins66540852013-10-04 21:28:06 +0000239 QualType TempType;
240
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000241public:
242 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000243
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000244 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
245 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
246 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000247
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000248 Test.Var = Var;
249 Test.TestsFor = TestsFor;
250 }
251
252 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
253 const VarTestResult &LTest, const VarTestResult &RTest)
254 : InfoType(IT_BinTest) {
255
256 BinTest.Source = Source;
257 BinTest.EOp = EOp;
258 BinTest.LTest = LTest;
259 BinTest.RTest = RTest;
260 }
261
262 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
263 const VarDecl *LVar, ConsumedState LTestsFor,
264 const VarDecl *RVar, ConsumedState RTestsFor)
265 : InfoType(IT_BinTest) {
266
267 BinTest.Source = Source;
268 BinTest.EOp = EOp;
269 BinTest.LTest.Var = LVar;
270 BinTest.LTest.TestsFor = LTestsFor;
271 BinTest.RTest.Var = RVar;
272 BinTest.RTest.TestsFor = RTestsFor;
273 }
274
DeLesley Hutchins66540852013-10-04 21:28:06 +0000275 PropagationInfo(ConsumedState State, QualType TempType)
276 : InfoType(IT_State), State(State), TempType(TempType) {}
277
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000278 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
279
280 const ConsumedState & getState() const {
281 assert(InfoType == IT_State);
282 return State;
283 }
284
DeLesley Hutchins66540852013-10-04 21:28:06 +0000285 const QualType & getTempType() const {
286 assert(InfoType == IT_State);
287 return TempType;
288 }
289
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000290 const VarTestResult & getTest() const {
291 assert(InfoType == IT_Test);
292 return Test;
293 }
294
295 const VarTestResult & getLTest() const {
296 assert(InfoType == IT_BinTest);
297 return BinTest.LTest;
298 }
299
300 const VarTestResult & getRTest() const {
301 assert(InfoType == IT_BinTest);
302 return BinTest.RTest;
303 }
304
305 const VarDecl * getVar() const {
306 assert(InfoType == IT_Var);
307 return Var;
308 }
309
310 EffectiveOp testEffectiveOp() const {
311 assert(InfoType == IT_BinTest);
312 return BinTest.EOp;
313 }
314
315 const BinaryOperator * testSourceNode() const {
316 assert(InfoType == IT_BinTest);
317 return BinTest.Source;
318 }
319
320 bool isValid() const { return InfoType != IT_None; }
321 bool isState() const { return InfoType == IT_State; }
322 bool isTest() const { return InfoType == IT_Test; }
323 bool isBinTest() const { return InfoType == IT_BinTest; }
324 bool isVar() const { return InfoType == IT_Var; }
325
326 PropagationInfo invertTest() const {
327 assert(InfoType == IT_Test || InfoType == IT_BinTest);
328
329 if (InfoType == IT_Test) {
330 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
331
332 } else if (InfoType == IT_BinTest) {
333 return PropagationInfo(BinTest.Source,
334 BinTest.EOp == EO_And ? EO_Or : EO_And,
335 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
336 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
337 } else {
338 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000339 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000340 }
341};
342
343class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000344
345 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
346 typedef std::pair<const Stmt *, PropagationInfo> PairType;
347 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000348 typedef MapType::const_iterator ConstInfoEntry;
349
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000350 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000351 ConsumedAnalyzer &Analyzer;
352 ConsumedStateMap *StateMap;
353 MapType PropagationMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000354 void forwardInfo(const Stmt *From, const Stmt *To);
355 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000356 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
357 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000358
359public:
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000360 void checkCallability(const PropagationInfo &PInfo,
361 const FunctionDecl *FunDecl,
362 SourceLocation BlameLoc);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000363
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000364 void Visit(const Stmt *StmtNode);
365
366 void VisitBinaryOperator(const BinaryOperator *BinOp);
367 void VisitCallExpr(const CallExpr *Call);
368 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000369 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000370 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
371 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
372 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
373 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
374 void VisitDeclStmt(const DeclStmt *DelcS);
375 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
376 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000377 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000378 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000379 void VisitUnaryOperator(const UnaryOperator *UOp);
380 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000381
DeLesley Hutchins42525982013-08-29 22:36:05 +0000382 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
383 ConsumedStateMap *StateMap)
384 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000385
386 PropagationInfo getInfo(const Stmt *StmtNode) const {
387 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
388
389 if (Entry != PropagationMap.end())
390 return Entry->second;
391 else
392 return PropagationInfo();
393 }
394
395 void reset(ConsumedStateMap *NewStateMap) {
396 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000397 }
398};
399
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000400void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000401 const FunctionDecl *FunDecl,
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000402 SourceLocation BlameLoc) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000403
DeLesley Hutchins66540852013-10-04 21:28:06 +0000404 if (!FunDecl->hasAttr<CallableWhenAttr>())
405 return;
406
407 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000408
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000409 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000410 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000411 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000412
DeLesley Hutchins66540852013-10-04 21:28:06 +0000413 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000414
DeLesley Hutchins66540852013-10-04 21:28:06 +0000415 if (isCallableInState(CWAttr, VarState))
416 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000417
DeLesley Hutchins66540852013-10-04 21:28:06 +0000418 Analyzer.WarningsHandler.warnUseInInvalidState(
419 FunDecl->getNameAsString(), Var->getNameAsString(),
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000420 stateToString(VarState), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000421
DeLesley Hutchins66540852013-10-04 21:28:06 +0000422 } else if (PInfo.isState()) {
423
424 assert(PInfo.getState() != CS_None && "Invalid state");
425
426 if (isCallableInState(CWAttr, PInfo.getState()))
427 return;
428
429 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000430 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000431 }
432}
433
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000434void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
435 InfoEntry Entry = PropagationMap.find(From);
436
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000437 if (Entry != PropagationMap.end())
438 PropagationMap.insert(PairType(To, Entry->second));
439}
440
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000441bool ConsumedStmtVisitor::isLikeMoveAssignment(
442 const CXXMethodDecl *MethodDecl) {
443
444 return MethodDecl->isMoveAssignmentOperator() ||
445 (MethodDecl->getOverloadedOperator() == OO_Equal &&
446 MethodDecl->getNumParams() == 1 &&
447 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
448}
449
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000450void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
451 const FunctionDecl *Fun,
452 QualType ReturnType) {
453 if (isConsumableType(ReturnType)) {
454
455 ConsumedState ReturnState;
456
457 if (Fun->hasAttr<ReturnTypestateAttr>())
458 ReturnState = mapReturnTypestateAttrState(
459 Fun->getAttr<ReturnTypestateAttr>());
460 else
David Blaikiea33ab602013-09-06 01:28:43 +0000461 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000462
463 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000464 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000465 }
466}
467
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000468void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
469
470 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
471
472 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
473 CE = StmtNode->child_end(); CI != CE; ++CI) {
474
475 PropagationMap.erase(*CI);
476 }
477}
478
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000479void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
480 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000481 case BO_LAnd:
482 case BO_LOr : {
483 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
484 REntry = PropagationMap.find(BinOp->getRHS());
485
486 VarTestResult LTest, RTest;
487
488 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
489 LTest = LEntry->second.getTest();
490
491 } else {
492 LTest.Var = NULL;
493 LTest.TestsFor = CS_None;
494 }
495
496 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
497 RTest = REntry->second.getTest();
498
499 } else {
500 RTest.Var = NULL;
501 RTest.TestsFor = CS_None;
502 }
503
504 if (!(LTest.Var == NULL && RTest.Var == NULL))
505 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
506 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
507
508 break;
509 }
510
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000511 case BO_PtrMemD:
512 case BO_PtrMemI:
513 forwardInfo(BinOp->getLHS(), BinOp);
514 break;
515
516 default:
517 break;
518 }
519}
520
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000521void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
522 if (const FunctionDecl *FunDecl =
523 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
524
525 // Special case for the std::move function.
526 // TODO: Make this more specific. (Deferred)
527 if (FunDecl->getNameAsString() == "move") {
528 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
529
530 if (Entry != PropagationMap.end()) {
531 PropagationMap.insert(PairType(Call, Entry->second));
532 }
533
534 return;
535 }
536
537 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
538
539 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
540 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
541
542 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
543
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000544 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000545 continue;
546 }
547
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000548 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000549
550 if (ParamType->isRValueReferenceType() ||
551 (ParamType->isLValueReferenceType() &&
552 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
553
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000554 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000555
556 } else if (!(ParamType.isConstQualified() ||
557 ((ParamType->isReferenceType() ||
558 ParamType->isPointerType()) &&
559 ParamType->getPointeeType().isConstQualified()))) {
560
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000561 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000562 }
563 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000564
DeLesley Hutchins66540852013-10-04 21:28:06 +0000565 QualType RetType = FunDecl->getCallResultType();
566 if (RetType->isReferenceType())
567 RetType = RetType->getPointeeType();
568
569 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000570 }
571}
572
573void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000574 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000575}
576
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000577void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
578 const CXXBindTemporaryExpr *Temp) {
579
580 forwardInfo(Temp->getSubExpr(), Temp);
581}
582
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000583void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
584 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000585
586 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000587 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
588
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000589 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000590 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000591
592 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000593 PropagationInfo(consumed::CS_Consumed, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000594
595 } else if (Constructor->isMoveConstructor()) {
596
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000597 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000598 PropagationMap.find(Call->getArg(0))->second;
599
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000600 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000601 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000602
603 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000604 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000605
606 StateMap->setState(Var, consumed::CS_Consumed);
607
608 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000609 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000610 }
611
612 } else if (Constructor->isCopyConstructor()) {
613 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
614
615 if (Entry != PropagationMap.end())
616 PropagationMap.insert(PairType(Call, Entry->second));
617
618 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000619 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000620 }
621 }
622}
623
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000624
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000625void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
626 const CXXMemberCallExpr *Call) {
627
628 VisitCallExpr(Call);
629
630 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
631
632 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000633 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000634 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000635
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000636 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000637
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000638 if (PInfo.isVar()) {
639 if (isTestingFunction(MethodDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000640 PropagationMap.insert(PairType(Call,
641 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000642 else if (MethodDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000643 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000644 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000645 }
646}
647
648void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
649 const CXXOperatorCallExpr *Call) {
650
651 const FunctionDecl *FunDecl =
652 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
653
654 if (!FunDecl) return;
655
656 if (isa<CXXMethodDecl>(FunDecl) &&
657 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
658
659 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
660 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
661
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000662 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000663
664 if (LEntry != PropagationMap.end() &&
665 REntry != PropagationMap.end()) {
666
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000667 LPInfo = LEntry->second;
668 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000669
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000670 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000671 StateMap->setState(LPInfo.getVar(),
672 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000673
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000674 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000675
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000676 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000677
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000678 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000679 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000680
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000681 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000682
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000683 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000684 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000685 PropagationInfo(StateMap->getState(RPInfo.getVar()),
686 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000687
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000688 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000689
690 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000691 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000692 }
693
694 } else if (LEntry != PropagationMap.end() &&
695 REntry == PropagationMap.end()) {
696
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000697 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000698
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000699 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000700 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000701
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000702 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000703
DeLesley Hutchins66540852013-10-04 21:28:06 +0000704 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000705 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000706 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000707 }
708
709 } else if (LEntry == PropagationMap.end() &&
710 REntry != PropagationMap.end()) {
711
DeLesley Hutchins66540852013-10-04 21:28:06 +0000712 if (REntry->second.isVar())
713 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000714 }
715
716 } else {
717
718 VisitCallExpr(Call);
719
720 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
721
722 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000723 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000724
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000725 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000726
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000727 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000728 if (isTestingFunction(FunDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000729 PropagationMap.insert(PairType(Call,
730 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000731 else if (FunDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000732 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000733 }
734 }
735 }
736}
737
738void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
739 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
740 if (StateMap->getState(Var) != consumed::CS_None)
741 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
742}
743
744void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
745 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
746 DE = DeclS->decl_end(); DI != DE; ++DI) {
747
748 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
749 }
750
751 if (DeclS->isSingleDecl())
752 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
753 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
754}
755
756void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
757 const MaterializeTemporaryExpr *Temp) {
758
759 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
760
761 if (Entry != PropagationMap.end())
762 PropagationMap.insert(PairType(Temp, Entry->second));
763}
764
765void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
766 forwardInfo(MExpr->getBase(), MExpr);
767}
768
DeLesley Hutchins42525982013-08-29 22:36:05 +0000769
770void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000771 QualType ParamType = Param->getType();
772 ConsumedState ParamState = consumed::CS_None;
773
774 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
775 isConsumableType(ParamType))
776 ParamState = mapConsumableAttrState(ParamType);
777 else if (ParamType->isReferenceType() &&
778 isConsumableType(ParamType->getPointeeType()))
779 ParamState = consumed::CS_Unknown;
780
781 if (ParamState)
782 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000783}
784
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000785void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
786 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
787 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
788
789 if (Entry != PropagationMap.end()) {
790 assert(Entry->second.isState() || Entry->second.isVar());
791
792 ConsumedState RetState = Entry->second.isState() ?
793 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
794
795 if (RetState != ExpectedState)
796 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
797 Ret->getReturnLoc(), stateToString(ExpectedState),
798 stateToString(RetState));
799 }
800 }
801}
802
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000803void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000804 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
805 if (Entry == PropagationMap.end()) return;
806
807 switch (UOp->getOpcode()) {
808 case UO_AddrOf:
809 PropagationMap.insert(PairType(UOp, Entry->second));
810 break;
811
812 case UO_LNot:
813 if (Entry->second.isTest() || Entry->second.isBinTest())
814 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
815 break;
816
817 default:
818 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000819 }
820}
821
DeLesley Hutchins66540852013-10-04 21:28:06 +0000822// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000823void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000824 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000825 if (Var->hasInit()) {
826 PropagationInfo PInfo =
827 PropagationMap.find(Var->getInit())->second;
828
829 StateMap->setState(Var, PInfo.isVar() ?
830 StateMap->getState(PInfo.getVar()) : PInfo.getState());
831
832 } else {
833 StateMap->setState(Var, consumed::CS_Unknown);
834 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000835 }
836}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000837}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000838
839namespace clang {
840namespace consumed {
841
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000842void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
843 ConsumedStateMap *ThenStates,
844 ConsumedStateMap *ElseStates) {
845
846 ConsumedState VarState = ThenStates->getState(Test.Var);
847
848 if (VarState == CS_Unknown) {
849 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000850 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000851
852 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
853 ThenStates->markUnreachable();
854
DeLesley Hutchins66540852013-10-04 21:28:06 +0000855 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000856 ElseStates->markUnreachable();
857 }
858}
859
860void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
861 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
862
863 const VarTestResult &LTest = PInfo.getLTest(),
864 &RTest = PInfo.getRTest();
865
866 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
867 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
868
869 if (LTest.Var) {
870 if (PInfo.testEffectiveOp() == EO_And) {
871 if (LState == CS_Unknown) {
872 ThenStates->setState(LTest.Var, LTest.TestsFor);
873
874 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
875 ThenStates->markUnreachable();
876
877 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000878 if (RState == RTest.TestsFor)
879 ElseStates->markUnreachable();
880 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000881 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000882 }
883
884 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000885 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000886 ElseStates->setState(LTest.Var,
887 invertConsumedUnconsumed(LTest.TestsFor));
888
DeLesley Hutchins66540852013-10-04 21:28:06 +0000889 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000890 ElseStates->markUnreachable();
891
892 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
893 isKnownState(RState)) {
894
DeLesley Hutchins66540852013-10-04 21:28:06 +0000895 if (RState == RTest.TestsFor)
896 ElseStates->markUnreachable();
897 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000898 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000899 }
900 }
901 }
902
903 if (RTest.Var) {
904 if (PInfo.testEffectiveOp() == EO_And) {
905 if (RState == CS_Unknown)
906 ThenStates->setState(RTest.Var, RTest.TestsFor);
907 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
908 ThenStates->markUnreachable();
909
DeLesley Hutchins66540852013-10-04 21:28:06 +0000910 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000911 if (RState == CS_Unknown)
912 ElseStates->setState(RTest.Var,
913 invertConsumedUnconsumed(RTest.TestsFor));
914 else if (RState == RTest.TestsFor)
915 ElseStates->markUnreachable();
916 }
917 }
918}
919
DeLesley Hutchins73858402013-10-09 18:30:24 +0000920bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
921 const CFGBlock *TargetBlock) {
922
923 assert(CurrBlock && "Block pointer must not be NULL");
924 assert(TargetBlock && "TargetBlock pointer must not be NULL");
925
926 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
927 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
928 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
929 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
930 return false;
931 }
932 return true;
933}
934
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000935void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
936 ConsumedStateMap *StateMap,
937 bool &AlreadyOwned) {
938
DeLesley Hutchins73858402013-10-09 18:30:24 +0000939 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000940
941 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
942
943 if (Entry) {
944 Entry->intersect(StateMap);
945
946 } else if (AlreadyOwned) {
947 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
948
949 } else {
950 StateMapsArray[Block->getBlockID()] = StateMap;
951 AlreadyOwned = true;
952 }
953}
954
955void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
956 ConsumedStateMap *StateMap) {
957
DeLesley Hutchins73858402013-10-09 18:30:24 +0000958 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000959
960 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
961
962 if (Entry) {
963 Entry->intersect(StateMap);
964 delete StateMap;
965
966 } else {
967 StateMapsArray[Block->getBlockID()] = StateMap;
968 }
969}
970
DeLesley Hutchins73858402013-10-09 18:30:24 +0000971ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
972 assert(Block && "Block pointer must not be NULL");
973 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
974
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000975 return StateMapsArray[Block->getBlockID()];
976}
977
DeLesley Hutchins73858402013-10-09 18:30:24 +0000978void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
979 unsigned int BlockID = Block->getBlockID();
980 delete StateMapsArray[BlockID];
981 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000982}
983
DeLesley Hutchins73858402013-10-09 18:30:24 +0000984ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
985 assert(Block && "Block pointer must not be NULL");
986
987 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
988 if (isBackEdgeTarget(Block)) {
989 return new ConsumedStateMap(*StateMap);
990 } else {
991 StateMapsArray[Block->getBlockID()] = NULL;
992 return StateMap;
993 }
994}
995
996bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
997 assert(From && "From block must not be NULL");
998 assert(To && "From block must not be NULL");
999
1000 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1001}
1002
1003bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1004 assert(Block != NULL && "Block pointer must not be NULL");
1005
1006 // Anything with less than two predecessors can't be the target of a back
1007 // edge.
1008 if (Block->pred_size() < 2)
1009 return false;
1010
1011 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1012 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1013 PE = Block->pred_end(); PI != PE; ++PI) {
1014 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1015 return true;
1016 }
1017 return false;
1018}
1019
1020ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001021 MapType::const_iterator Entry = Map.find(Var);
1022
1023 if (Entry != Map.end()) {
1024 return Entry->second;
1025
1026 } else {
1027 return CS_None;
1028 }
1029}
1030
1031void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1032 ConsumedState LocalState;
1033
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001034 if (this->From && this->From == Other->From && !Other->Reachable) {
1035 this->markUnreachable();
1036 return;
1037 }
1038
DeLesley Hutchins73858402013-10-09 18:30:24 +00001039 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1040 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001041
1042 LocalState = this->getState(DMI->first);
1043
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001044 if (LocalState == CS_None)
1045 continue;
1046
1047 if (LocalState != DMI->second)
1048 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001049 }
1050}
1051
DeLesley Hutchins73858402013-10-09 18:30:24 +00001052void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1053 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1054 ConsumedWarningsHandlerBase &WarningsHandler) {
1055
1056 ConsumedState LocalState;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001057 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001058
1059 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1060 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1061
1062 LocalState = this->getState(DMI->first);
1063
1064 if (LocalState == CS_None)
1065 continue;
1066
1067 if (LocalState != DMI->second) {
1068 Map[DMI->first] = CS_Unknown;
1069 WarningsHandler.warnLoopStateMismatch(
1070 BlameLoc, DMI->first->getNameAsString());
1071 }
1072 }
1073}
1074
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001075void ConsumedStateMap::markUnreachable() {
1076 this->Reachable = false;
1077 Map.clear();
1078}
1079
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001080void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1081 Map[Var] = State;
1082}
1083
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001084void ConsumedStateMap::remove(const VarDecl *Var) {
1085 Map.erase(Var);
1086}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001087
DeLesley Hutchins73858402013-10-09 18:30:24 +00001088bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1089 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1090 DMI != DME; ++DMI) {
1091
1092 if (this->getState(DMI->first) != DMI->second)
1093 return true;
1094 }
1095
1096 return false;
1097}
1098
David Blaikiea33ab602013-09-06 01:28:43 +00001099void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1100 const FunctionDecl *D) {
1101 QualType ReturnType;
1102 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1103 ASTContext &CurrContext = AC.getASTContext();
1104 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1105 } else
1106 ReturnType = D->getCallResultType();
1107
1108 if (D->hasAttr<ReturnTypestateAttr>()) {
1109 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1110
1111 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1112 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1113 // FIXME: This should be removed when template instantiation propagates
1114 // attributes at template specialization definition, not
1115 // declaration. When it is removed the test needs to be enabled
1116 // in SemaDeclAttr.cpp.
1117 WarningsHandler.warnReturnTypestateForUnconsumableType(
1118 RTSAttr->getLocation(), ReturnType.getAsString());
1119 ExpectedReturnState = CS_None;
1120 } else
1121 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1122 } else if (isConsumableType(ReturnType))
1123 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1124 else
1125 ExpectedReturnState = CS_None;
1126}
1127
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001128bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1129 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001130
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001131 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1132 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001133
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001134 if (const IfStmt *IfNode =
1135 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001136
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001137 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001138
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001139 PInfo = Visitor.getInfo(Cond);
1140 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1141 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1142
1143 if (PInfo.isTest()) {
1144 CurrStates->setSource(Cond);
1145 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001146 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001147
1148 } else if (PInfo.isBinTest()) {
1149 CurrStates->setSource(PInfo.testSourceNode());
1150 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001151 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001152
1153 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001154 delete FalseStates;
1155 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001156 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001157
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001158 } else if (const BinaryOperator *BinOp =
1159 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1160
1161 PInfo = Visitor.getInfo(BinOp->getLHS());
1162 if (!PInfo.isTest()) {
1163 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1164 PInfo = Visitor.getInfo(BinOp->getRHS());
1165
1166 if (!PInfo.isTest()) {
1167 delete FalseStates;
1168 return false;
1169 }
1170
1171 } else {
1172 delete FalseStates;
1173 return false;
1174 }
1175 }
1176
1177 CurrStates->setSource(BinOp);
1178 FalseStates->setSource(BinOp);
1179
1180 const VarTestResult &Test = PInfo.getTest();
1181 ConsumedState VarState = CurrStates->getState(Test.Var);
1182
1183 if (BinOp->getOpcode() == BO_LAnd) {
1184 if (VarState == CS_Unknown)
1185 CurrStates->setState(Test.Var, Test.TestsFor);
1186 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1187 CurrStates->markUnreachable();
1188
1189 } else if (BinOp->getOpcode() == BO_LOr) {
1190 if (VarState == CS_Unknown)
1191 FalseStates->setState(Test.Var,
1192 invertConsumedUnconsumed(Test.TestsFor));
1193 else if (VarState == Test.TestsFor)
1194 FalseStates->markUnreachable();
1195 }
1196
1197 } else {
1198 delete FalseStates;
1199 return false;
1200 }
1201
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001202 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1203
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001204 if (*SI)
1205 BlockInfo.addInfo(*SI, CurrStates);
1206 else
1207 delete CurrStates;
1208
1209 if (*++SI)
1210 BlockInfo.addInfo(*SI, FalseStates);
1211 else
1212 delete FalseStates;
1213
1214 CurrStates = NULL;
1215 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001216}
1217
1218void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1219 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001220 if (!D)
1221 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001222
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001223 CFG *CFGraph = AC.getCFG();
1224 if (!CFGraph)
1225 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001226
David Blaikiea33ab602013-09-06 01:28:43 +00001227 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001228
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001229 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001230 // AC.getCFG()->viewCFG(LangOptions());
1231
1232 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001233
1234 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001235 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1236
1237 // Add all trackable parameters to the state map.
1238 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1239 PE = D->param_end(); PI != PE; ++PI) {
1240 Visitor.VisitParmVarDecl(*PI);
1241 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001242
1243 // Visit all of the function's basic blocks.
1244 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1245 E = SortedGraph->end(); I != E; ++I) {
1246
1247 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001248
1249 if (CurrStates == NULL)
1250 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001251
1252 if (!CurrStates) {
1253 continue;
1254
1255 } else if (!CurrStates->isReachable()) {
1256 delete CurrStates;
1257 CurrStates = NULL;
1258 continue;
1259 }
1260
1261 Visitor.reset(CurrStates);
1262
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001263 // Visit all of the basic block's statements.
1264 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1265 BE = CurrBlock->end(); BI != BE; ++BI) {
1266
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001267 switch (BI->getKind()) {
1268 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001269 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001270 break;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001271
1272 case CFGElement::TemporaryDtor: {
1273 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1274 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1275 PropagationInfo PInfo = Visitor.getInfo(BTE);
1276
1277 if (PInfo.isValid())
1278 Visitor.checkCallability(PInfo,
1279 DTor.getDestructorDecl(AC.getASTContext()),
1280 BTE->getExprLoc());
1281 break;
1282 }
1283
1284 case CFGElement::AutomaticObjectDtor: {
1285 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1286
1287 const VarDecl *Var = DTor.getVarDecl();
1288 ConsumedState VarState = CurrStates->getState(Var);
1289
1290 if (VarState != CS_None) {
1291 PropagationInfo PInfo(Var);
1292
1293 Visitor.checkCallability(PInfo,
1294 DTor.getDestructorDecl(AC.getASTContext()),
1295 getLastStmtLoc(CurrBlock));
1296
1297 CurrStates->remove(Var);
1298 }
1299 break;
1300 }
1301
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001302 default:
1303 break;
1304 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001305 }
1306
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001307 // TODO: Handle other forms of branching with precision, including while-
1308 // and for-loops. (Deferred)
1309 if (!splitState(CurrBlock, Visitor)) {
1310 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001311
DeLesley Hutchins73858402013-10-09 18:30:24 +00001312 if (CurrBlock->succ_size() > 1 ||
1313 (CurrBlock->succ_size() == 1 &&
1314 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001315
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001316 bool OwnershipTaken = false;
1317
1318 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1319 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1320
DeLesley Hutchins73858402013-10-09 18:30:24 +00001321 if (*SI == NULL) continue;
1322
1323 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1324 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1325 CurrStates,
1326 WarningsHandler);
1327
1328 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1329 BlockInfo.discardInfo(*SI);
1330 } else {
1331 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1332 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001333 }
1334
1335 if (!OwnershipTaken)
1336 delete CurrStates;
1337
1338 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001339 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001340 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001341 } // End of block iterator.
1342
1343 // Delete the last existing state map.
1344 delete CurrStates;
1345
1346 WarningsHandler.emitDiagnostics();
1347}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001348}} // end namespace clang::consumed