blob: 6e692be60948b1159cde53af6a7d6c2534e8c21b [file] [log] [blame]
DeLesley Hutchins48a31762013-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 Hutchins48a31762013-08-12 21:20:55 +000029#include "llvm/ADT/DenseMap.h"
Chris Wailes2dc8c422013-10-25 15:33:28 +000030#include "llvm/ADT/OwningPtr.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000031#include "llvm/ADT/SmallVector.h"
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000032#include "llvm/Support/Compiler.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000033#include "llvm/Support/raw_ostream.h"
34
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +000035// TODO: Adjust states of args to constructors in the same way that arguments to
36// function calls are handled.
37// TODO: Use information from tests in for- and while-loop conditional.
DeLesley Hutchinsfc368252013-09-03 20:11:38 +000038// TODO: Add notes about the actual and expected state for
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000039// TODO: Correctly identify unreachable blocks when chaining boolean operators.
DeLesley Hutchins210791a2013-10-04 21:28:06 +000040// TODO: Adjust the parser and AttributesList class to support lists of
41// identifiers.
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000042// TODO: Warn about unreachable code.
43// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000044// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
45// if (valid) ...; (Deferred)
DeLesley Hutchins48a31762013-08-12 21:20:55 +000046// TODO: Take notes on state transitions to provide better warning messages.
47// (Deferred)
48// TODO: Test nested conditionals: A) Checking the same value multiple times,
49// and 2) Checking different values. (Deferred)
DeLesley Hutchins48a31762013-08-12 21:20:55 +000050
51using namespace clang;
52using namespace consumed;
53
54// Key method definition
55ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
56
DeLesley Hutchins65013202013-10-17 18:19:31 +000057static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
58 // Find the source location of the first statement in the block, if the block
59 // is not empty.
60 for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
61 BI != BE; ++BI) {
62 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
63 return CS->getStmt()->getLocStart();
64 }
65
66 // Block is empty.
67 // If we have one successor, return the first statement in that block
68 if (Block->succ_size() == 1 && *Block->succ_begin())
69 return getFirstStmtLoc(*Block->succ_begin());
70
71 return SourceLocation();
72}
73
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000074static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000075 // Find the source location of the last statement in the block, if the block
76 // is not empty.
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000077 if (const Stmt *StmtNode = Block->getTerminator()) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000078 return StmtNode->getLocStart();
79 } else {
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +000080 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
81 BE = Block->rend(); BI != BE; ++BI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +000082 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
83 return CS->getStmt()->getLocStart();
84 }
85 }
DeLesley Hutchins65013202013-10-17 18:19:31 +000086
87 // If we have one successor, return the first statement in that block
88 SourceLocation Loc;
89 if (Block->succ_size() == 1 && *Block->succ_begin())
90 Loc = getFirstStmtLoc(*Block->succ_begin());
91 if (Loc.isValid())
92 return Loc;
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +000093
DeLesley Hutchins65013202013-10-17 18:19:31 +000094 // If we have one predecessor, return the last statement in that block
95 if (Block->pred_size() == 1 && *Block->pred_begin())
96 return getLastStmtLoc(*Block->pred_begin());
97
98 return Loc;
DeLesley Hutchins3277a612013-10-09 18:30:24 +000099}
100
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000101static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
102 switch (State) {
103 case CS_Unconsumed:
104 return CS_Consumed;
105 case CS_Consumed:
106 return CS_Unconsumed;
107 case CS_None:
108 return CS_None;
109 case CS_Unknown:
110 return CS_Unknown;
111 }
112 llvm_unreachable("invalid enum");
113}
114
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000115static bool isCallableInState(const CallableWhenAttr *CWAttr,
116 ConsumedState State) {
117
118 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
119 E = CWAttr->callableState_end();
120
121 for (; I != E; ++I) {
122
123 ConsumedState MappedAttrState = CS_None;
124
125 switch (*I) {
126 case CallableWhenAttr::Unknown:
127 MappedAttrState = CS_Unknown;
128 break;
129
130 case CallableWhenAttr::Unconsumed:
131 MappedAttrState = CS_Unconsumed;
132 break;
133
134 case CallableWhenAttr::Consumed:
135 MappedAttrState = CS_Consumed;
136 break;
137 }
138
139 if (MappedAttrState == State)
140 return true;
141 }
142
143 return false;
144}
145
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000146static bool isConsumableType(const QualType &QT) {
Chris Wailes93edffa2013-10-31 15:38:12 +0000147 if (QT->isPointerType() || QT->isReferenceType())
148 return false;
149
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000150 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
151 return RD->hasAttr<ConsumableAttr>();
Chris Wailes93edffa2013-10-31 15:38:12 +0000152
153 return false;
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000154}
155
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000156static bool isKnownState(ConsumedState State) {
157 switch (State) {
158 case CS_Unconsumed:
159 case CS_Consumed:
160 return true;
161 case CS_None:
162 case CS_Unknown:
163 return false;
164 }
Aaron Ballmana21f4b82013-08-29 20:36:09 +0000165 llvm_unreachable("invalid enum");
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000166}
167
DeLesley Hutchins0bd25892013-10-18 19:25:18 +0000168static bool isRValueRefish(QualType ParamType) {
169 return ParamType->isRValueReferenceType() ||
170 (ParamType->isLValueReferenceType() &&
Chris Wailes93edffa2013-10-31 15:38:12 +0000171 !cast<LValueReferenceType>(
172 ParamType.getCanonicalType())->isSpelledAsLValue());
DeLesley Hutchins0bd25892013-10-18 19:25:18 +0000173}
174
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000175static bool isTestingFunction(const FunctionDecl *FunDecl) {
Chris Wailes9385f9f2013-10-29 20:28:41 +0000176 return FunDecl->hasAttr<TestTypestateAttr>();
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000177}
178
DeLesley Hutchins0bd25892013-10-18 19:25:18 +0000179static bool isValueType(QualType ParamType) {
180 return !(ParamType->isPointerType() || ParamType->isReferenceType());
181}
182
David Blaikie16f76d22013-09-06 01:28:43 +0000183static ConsumedState mapConsumableAttrState(const QualType QT) {
184 assert(isConsumableType(QT));
185
186 const ConsumableAttr *CAttr =
187 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
188
189 switch (CAttr->getDefaultState()) {
190 case ConsumableAttr::Unknown:
191 return CS_Unknown;
192 case ConsumableAttr::Unconsumed:
193 return CS_Unconsumed;
194 case ConsumableAttr::Consumed:
195 return CS_Consumed;
196 }
197 llvm_unreachable("invalid enum");
198}
199
DeLesley Hutchins69391772013-10-17 23:23:53 +0000200static ConsumedState
201mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
202 switch (PTAttr->getParamState()) {
203 case ParamTypestateAttr::Unknown:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000204 return CS_Unknown;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000205 case ParamTypestateAttr::Unconsumed:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000206 return CS_Unconsumed;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000207 case ParamTypestateAttr::Consumed:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000208 return CS_Consumed;
209 }
210 llvm_unreachable("invalid_enum");
211}
212
Eric Christopherde156242013-09-03 20:43:00 +0000213static ConsumedState
214mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000215 switch (RTSAttr->getState()) {
216 case ReturnTypestateAttr::Unknown:
217 return CS_Unknown;
218 case ReturnTypestateAttr::Unconsumed:
219 return CS_Unconsumed;
220 case ReturnTypestateAttr::Consumed:
221 return CS_Consumed;
222 }
Eric Christopherde156242013-09-03 20:43:00 +0000223 llvm_unreachable("invalid enum");
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000224}
225
DeLesley Hutchins69391772013-10-17 23:23:53 +0000226static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
227 switch (STAttr->getNewState()) {
228 case SetTypestateAttr::Unknown:
229 return CS_Unknown;
230 case SetTypestateAttr::Unconsumed:
231 return CS_Unconsumed;
232 case SetTypestateAttr::Consumed:
233 return CS_Consumed;
234 }
235 llvm_unreachable("invalid_enum");
236}
237
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000238static StringRef stateToString(ConsumedState State) {
239 switch (State) {
240 case consumed::CS_None:
241 return "none";
242
243 case consumed::CS_Unknown:
244 return "unknown";
245
246 case consumed::CS_Unconsumed:
247 return "unconsumed";
248
249 case consumed::CS_Consumed:
250 return "consumed";
251 }
Reid Kleckner6454d0a2013-08-13 00:11:59 +0000252 llvm_unreachable("invalid enum");
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000253}
254
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000255static ConsumedState testsFor(const FunctionDecl *FunDecl) {
256 assert(isTestingFunction(FunDecl));
Chris Wailes9385f9f2013-10-29 20:28:41 +0000257 switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
258 case TestTypestateAttr::Unconsumed:
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000259 return CS_Unconsumed;
Chris Wailes9385f9f2013-10-29 20:28:41 +0000260 case TestTypestateAttr::Consumed:
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000261 return CS_Consumed;
262 }
263 llvm_unreachable("invalid enum");
264}
265
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000266namespace {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000267struct VarTestResult {
268 const VarDecl *Var;
269 ConsumedState TestsFor;
270};
271} // end anonymous::VarTestResult
272
273namespace clang {
274namespace consumed {
275
276enum EffectiveOp {
277 EO_And,
278 EO_Or
279};
280
281class PropagationInfo {
282 enum {
283 IT_None,
284 IT_State,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000285 IT_VarTest,
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000286 IT_BinTest,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000287 IT_Var,
288 IT_Tmp
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000289 } InfoType;
Eric Christopherf8a1baa2013-08-29 18:00:58 +0000290
291 struct BinTestTy {
292 const BinaryOperator *Source;
293 EffectiveOp EOp;
294 VarTestResult LTest;
295 VarTestResult RTest;
296 };
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000297
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000298 union {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000299 ConsumedState State;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000300 VarTestResult VarTest;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000301 const VarDecl *Var;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000302 const CXXBindTemporaryExpr *Tmp;
Eric Christopherf8a1baa2013-08-29 18:00:58 +0000303 BinTestTy BinTest;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000304 };
305
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000306public:
307 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000308
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000309 PropagationInfo(const VarTestResult &VarTest)
310 : InfoType(IT_VarTest), VarTest(VarTest) {}
311
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000312 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000313 : InfoType(IT_VarTest) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000314
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000315 VarTest.Var = Var;
316 VarTest.TestsFor = TestsFor;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000317 }
318
319 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
320 const VarTestResult &LTest, const VarTestResult &RTest)
321 : InfoType(IT_BinTest) {
322
323 BinTest.Source = Source;
324 BinTest.EOp = EOp;
325 BinTest.LTest = LTest;
326 BinTest.RTest = RTest;
327 }
328
329 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
330 const VarDecl *LVar, ConsumedState LTestsFor,
331 const VarDecl *RVar, ConsumedState RTestsFor)
332 : InfoType(IT_BinTest) {
333
334 BinTest.Source = Source;
335 BinTest.EOp = EOp;
336 BinTest.LTest.Var = LVar;
337 BinTest.LTest.TestsFor = LTestsFor;
338 BinTest.RTest.Var = RVar;
339 BinTest.RTest.TestsFor = RTestsFor;
340 }
341
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000342 PropagationInfo(ConsumedState State)
343 : InfoType(IT_State), State(State) {}
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000344
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000345 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000346 PropagationInfo(const CXXBindTemporaryExpr *Tmp)
347 : InfoType(IT_Tmp), Tmp(Tmp) {}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000348
349 const ConsumedState & getState() const {
350 assert(InfoType == IT_State);
351 return State;
352 }
353
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000354 const VarTestResult & getVarTest() const {
355 assert(InfoType == IT_VarTest);
356 return VarTest;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000357 }
358
359 const VarTestResult & getLTest() const {
360 assert(InfoType == IT_BinTest);
361 return BinTest.LTest;
362 }
363
364 const VarTestResult & getRTest() const {
365 assert(InfoType == IT_BinTest);
366 return BinTest.RTest;
367 }
368
369 const VarDecl * getVar() const {
370 assert(InfoType == IT_Var);
371 return Var;
372 }
373
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000374 const CXXBindTemporaryExpr * getTmp() const {
375 assert(InfoType == IT_Tmp);
376 return Tmp;
377 }
378
379 ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
380 assert(isVar() || isTmp() || isState());
381
382 if (isVar())
383 return StateMap->getState(Var);
384 else if (isTmp())
385 return StateMap->getState(Tmp);
386 else if (isState())
387 return State;
388 else
389 return CS_None;
390 }
391
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000392 EffectiveOp testEffectiveOp() const {
393 assert(InfoType == IT_BinTest);
394 return BinTest.EOp;
395 }
396
397 const BinaryOperator * testSourceNode() const {
398 assert(InfoType == IT_BinTest);
399 return BinTest.Source;
400 }
401
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000402 inline bool isValid() const { return InfoType != IT_None; }
403 inline bool isState() const { return InfoType == IT_State; }
404 inline bool isVarTest() const { return InfoType == IT_VarTest; }
405 inline bool isBinTest() const { return InfoType == IT_BinTest; }
406 inline bool isVar() const { return InfoType == IT_Var; }
407 inline bool isTmp() const { return InfoType == IT_Tmp; }
408
409 bool isTest() const {
410 return InfoType == IT_VarTest || InfoType == IT_BinTest;
411 }
412
413 bool isPointerToValue() const {
414 return InfoType == IT_Var || InfoType == IT_Tmp;
415 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000416
417 PropagationInfo invertTest() const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000418 assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000419
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000420 if (InfoType == IT_VarTest) {
421 return PropagationInfo(VarTest.Var,
422 invertConsumedUnconsumed(VarTest.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000423
424 } else if (InfoType == IT_BinTest) {
425 return PropagationInfo(BinTest.Source,
426 BinTest.EOp == EO_And ? EO_Or : EO_And,
427 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
428 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
429 } else {
430 return PropagationInfo();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000431 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000432 }
433};
434
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000435static inline void
436setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
437 ConsumedState State) {
438
439 assert(PInfo.isVar() || PInfo.isTmp());
440
441 if (PInfo.isVar())
442 StateMap->setState(PInfo.getVar(), State);
443 else
444 StateMap->setState(PInfo.getTmp(), State);
445}
446
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000447class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000448
449 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
450 typedef std::pair<const Stmt *, PropagationInfo> PairType;
451 typedef MapType::iterator InfoEntry;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000452 typedef MapType::const_iterator ConstInfoEntry;
453
Reid Klecknere846dea2013-08-12 23:49:39 +0000454 AnalysisDeclContext &AC;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000455 ConsumedAnalyzer &Analyzer;
456 ConsumedStateMap *StateMap;
457 MapType PropagationMap;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000458 void forwardInfo(const Stmt *From, const Stmt *To);
459 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000460 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
461 QualType ReturnType);
DeLesley Hutchins81218662013-10-18 23:11:49 +0000462
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000463public:
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000464 void checkCallability(const PropagationInfo &PInfo,
465 const FunctionDecl *FunDecl,
466 SourceLocation BlameLoc);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000467
468 void VisitBinaryOperator(const BinaryOperator *BinOp);
469 void VisitCallExpr(const CallExpr *Call);
470 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000471 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000472 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
473 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
474 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
475 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
476 void VisitDeclStmt(const DeclStmt *DelcS);
477 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
478 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000479 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000480 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000481 void VisitUnaryOperator(const UnaryOperator *UOp);
482 void VisitVarDecl(const VarDecl *Var);
Reid Klecknere846dea2013-08-12 23:49:39 +0000483
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000484 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
485 ConsumedStateMap *StateMap)
486 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000487
488 PropagationInfo getInfo(const Stmt *StmtNode) const {
489 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
490
491 if (Entry != PropagationMap.end())
492 return Entry->second;
493 else
494 return PropagationInfo();
495 }
496
497 void reset(ConsumedStateMap *NewStateMap) {
498 StateMap = NewStateMap;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000499 }
500};
501
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000502void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000503 const FunctionDecl *FunDecl,
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000504 SourceLocation BlameLoc) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000505 assert(!PInfo.isTest());
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000506
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000507 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000508 if (!CWAttr)
509 return;
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000510
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000511 if (PInfo.isVar()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000512 ConsumedState VarState = StateMap->getState(PInfo.getVar());
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000513
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000514 if (VarState == CS_None || isCallableInState(CWAttr, VarState))
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000515 return;
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000516
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000517 Analyzer.WarningsHandler.warnUseInInvalidState(
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000518 FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000519 stateToString(VarState), BlameLoc);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000520
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000521 } else {
522 ConsumedState TmpState = PInfo.getAsState(StateMap);
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000523
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000524 if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000525 return;
526
527 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000528 FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000529 }
530}
531
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000532void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
533 InfoEntry Entry = PropagationMap.find(From);
534
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000535 if (Entry != PropagationMap.end())
536 PropagationMap.insert(PairType(To, Entry->second));
537}
538
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000539bool ConsumedStmtVisitor::isLikeMoveAssignment(
540 const CXXMethodDecl *MethodDecl) {
541
542 return MethodDecl->isMoveAssignmentOperator() ||
543 (MethodDecl->getOverloadedOperator() == OO_Equal &&
544 MethodDecl->getNumParams() == 1 &&
545 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
546}
547
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000548void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
549 const FunctionDecl *Fun,
550 QualType ReturnType) {
551 if (isConsumableType(ReturnType)) {
552
553 ConsumedState ReturnState;
554
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000555 if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
556 ReturnState = mapReturnTypestateAttrState(RTA);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000557 else
David Blaikie16f76d22013-09-06 01:28:43 +0000558 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000559
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000560 PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000561 }
562}
563
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000564void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
565 switch (BinOp->getOpcode()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000566 case BO_LAnd:
567 case BO_LOr : {
568 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
569 REntry = PropagationMap.find(BinOp->getRHS());
570
571 VarTestResult LTest, RTest;
572
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000573 if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
574 LTest = LEntry->second.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000575
576 } else {
577 LTest.Var = NULL;
578 LTest.TestsFor = CS_None;
579 }
580
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000581 if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
582 RTest = REntry->second.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000583
584 } else {
585 RTest.Var = NULL;
586 RTest.TestsFor = CS_None;
587 }
588
589 if (!(LTest.Var == NULL && RTest.Var == NULL))
590 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
591 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
592
593 break;
594 }
595
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000596 case BO_PtrMemD:
597 case BO_PtrMemI:
598 forwardInfo(BinOp->getLHS(), BinOp);
599 break;
600
601 default:
602 break;
603 }
604}
605
Richard Trieuc6896912013-12-17 00:40:40 +0000606static bool isStdNamespace(const DeclContext *DC) {
607 if (!DC->isNamespace()) return false;
608 while (DC->getParent()->isNamespace())
609 DC = DC->getParent();
610 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
611
612 return ND && ND->getName() == "std" &&
613 ND->getDeclContext()->isTranslationUnit();
614}
615
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000616void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
617 if (const FunctionDecl *FunDecl =
618 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
619
620 // Special case for the std::move function.
621 // TODO: Make this more specific. (Deferred)
Richard Trieuc6896912013-12-17 00:40:40 +0000622 if (Call->getNumArgs() == 1 &&
623 FunDecl->getNameAsString() == "move" &&
624 isStdNamespace(FunDecl->getDeclContext())) {
Chris Wailes44930882013-10-24 14:28:17 +0000625 forwardInfo(Call->getArg(0), Call);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000626 return;
627 }
628
629 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
630
631 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000632 const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
633 QualType ParamType = Param->getType();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000634
635 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
636
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000637 if (Entry == PropagationMap.end() || Entry->second.isTest())
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000638 continue;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000639
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000640 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000641
DeLesley Hutchins69391772013-10-17 23:23:53 +0000642 // Check that the parameter is in the correct state.
643
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000644 if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
645 ConsumedState ParamState = PInfo.getAsState(StateMap);
646 ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
DeLesley Hutchins69391772013-10-17 23:23:53 +0000647
648 if (ParamState != ExpectedState)
649 Analyzer.WarningsHandler.warnParamTypestateMismatch(
650 Call->getArg(Index - Offset)->getExprLoc(),
651 stateToString(ExpectedState), stateToString(ParamState));
652 }
653
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000654 if (!(Entry->second.isVar() || Entry->second.isTmp()))
DeLesley Hutchins69391772013-10-17 23:23:53 +0000655 continue;
656
657 // Adjust state on the caller side.
658
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000659 if (isRValueRefish(ParamType))
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000660 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000661 else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
662 setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
663 else if (!isValueType(ParamType) &&
664 !ParamType->getPointeeType().isConstQualified())
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000665 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000666 }
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000667
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000668 QualType RetType = FunDecl->getCallResultType();
669 if (RetType->isReferenceType())
670 RetType = RetType->getPointeeType();
671
672 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000673 }
674}
675
676void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000677 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000678}
679
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000680void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
681 const CXXBindTemporaryExpr *Temp) {
682
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000683 InfoEntry Entry = PropagationMap.find(Temp->getSubExpr());
684
685 if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
686 StateMap->setState(Temp, Entry->second.getAsState(StateMap));
687 PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
688 }
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000689}
690
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000691void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
692 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Klecknere846dea2013-08-12 23:49:39 +0000693
694 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000695 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
696
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000697 if (!isConsumableType(ThisType))
698 return;
699
700 // FIXME: What should happen if someone annotates the move constructor?
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000701 if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
702 // TODO: Adjust state of args appropriately.
703 ConsumedState RetState = mapReturnTypestateAttrState(RTA);
704 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
705 } else if (Constructor->isDefaultConstructor()) {
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000706 PropagationMap.insert(PairType(Call,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000707 PropagationInfo(consumed::CS_Consumed)));
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000708 } else if (Constructor->isMoveConstructor()) {
Chris Wailes44930882013-10-24 14:28:17 +0000709 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000710
Chris Wailes44930882013-10-24 14:28:17 +0000711 if (Entry != PropagationMap.end()) {
712 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000713
Chris Wailes44930882013-10-24 14:28:17 +0000714 if (PInfo.isVar()) {
715 const VarDecl* Var = PInfo.getVar();
716
717 PropagationMap.insert(PairType(Call,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000718 PropagationInfo(StateMap->getState(Var))));
Chris Wailes44930882013-10-24 14:28:17 +0000719
720 StateMap->setState(Var, consumed::CS_Consumed);
721
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000722 } else if (PInfo.isTmp()) {
723 const CXXBindTemporaryExpr *Tmp = PInfo.getTmp();
724
725 PropagationMap.insert(PairType(Call,
726 PropagationInfo(StateMap->getState(Tmp))));
727
728 StateMap->setState(Tmp, consumed::CS_Consumed);
729
Chris Wailes44930882013-10-24 14:28:17 +0000730 } else {
731 PropagationMap.insert(PairType(Call, PInfo));
732 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000733 }
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000734 } else if (Constructor->isCopyConstructor()) {
Chris Wailes44930882013-10-24 14:28:17 +0000735 forwardInfo(Call->getArg(0), Call);
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000736
737 } else {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000738 // TODO: Adjust state of args appropriately.
739
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000740 ConsumedState RetState = mapConsumableAttrState(ThisType);
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000741 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000742 }
743}
744
745void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
746 const CXXMemberCallExpr *Call) {
747
748 VisitCallExpr(Call);
749
750 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
751
752 if (Entry != PropagationMap.end()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000753 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000754 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000755
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000756 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000757
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000758 SetTypestateAttr *STA = MethodDecl->getAttr<SetTypestateAttr>();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000759 if (PInfo.isVar()) {
760 if (isTestingFunction(MethodDecl))
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000761 PropagationMap.insert(PairType(Call,
762 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000763 else if (STA)
764 StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
765 } else if (STA && PInfo.isTmp())
766 StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000767 }
768}
769
770void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
771 const CXXOperatorCallExpr *Call) {
772
773 const FunctionDecl *FunDecl =
774 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
775
776 if (!FunDecl) return;
777
778 if (isa<CXXMethodDecl>(FunDecl) &&
779 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
780
781 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
782 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
783
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000784 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000785
786 if (LEntry != PropagationMap.end() &&
787 REntry != PropagationMap.end()) {
788
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000789 LPInfo = LEntry->second;
790 RPInfo = REntry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000791
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000792 if (LPInfo.isPointerToValue() && RPInfo.isPointerToValue()) {
793 setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getAsState(StateMap));
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000794 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000795 setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000796
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000797 } else if (RPInfo.isState()) {
798 setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getState());
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000799 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000800
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000801 } else {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000802 setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000803 }
804
805 } else if (LEntry != PropagationMap.end() &&
806 REntry == PropagationMap.end()) {
807
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000808 LPInfo = LEntry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000809
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000810 assert(!LPInfo.isTest());
811
812 if (LPInfo.isPointerToValue()) {
813 setStateForVarOrTmp(StateMap, LPInfo, consumed::CS_Unknown);
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000814 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000815
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000816 } else {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000817 PropagationMap.insert(PairType(Call,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000818 PropagationInfo(consumed::CS_Unknown)));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000819 }
820
821 } else if (LEntry == PropagationMap.end() &&
822 REntry != PropagationMap.end()) {
823
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000824 RPInfo = REntry->second;
825
826 if (RPInfo.isPointerToValue())
827 setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000828 }
829
830 } else {
831
832 VisitCallExpr(Call);
833
834 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
835
836 if (Entry != PropagationMap.end()) {
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000837 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000838
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000839 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000840
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000841 SetTypestateAttr *STA = FunDecl->getAttr<SetTypestateAttr>();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000842 if (PInfo.isVar()) {
DeLesley Hutchins7fa60ed2013-08-29 21:17:25 +0000843 if (isTestingFunction(FunDecl))
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000844 PropagationMap.insert(PairType(Call,
845 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000846 else if (STA)
847 StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
848 } else if (STA && PInfo.isTmp())
849 StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000850 }
851 }
852}
853
854void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
855 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
856 if (StateMap->getState(Var) != consumed::CS_None)
857 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
858}
859
860void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
861 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
862 DE = DeclS->decl_end(); DI != DE; ++DI) {
863
864 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
865 }
866
867 if (DeclS->isSingleDecl())
868 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
869 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
870}
871
872void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
873 const MaterializeTemporaryExpr *Temp) {
874
Chris Wailes44930882013-10-24 14:28:17 +0000875 forwardInfo(Temp->GetTemporaryExpr(), Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000876}
877
878void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
879 forwardInfo(MExpr->getBase(), MExpr);
880}
881
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000882
883void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikie16f76d22013-09-06 01:28:43 +0000884 QualType ParamType = Param->getType();
885 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000886
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000887 if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
888 ParamState = mapParamTypestateAttrState(PTA);
889 else if (isConsumableType(ParamType))
890 ParamState = mapConsumableAttrState(ParamType);
891 else if (isRValueRefish(ParamType) &&
892 isConsumableType(ParamType->getPointeeType()))
893 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
894 else if (ParamType->isReferenceType() &&
895 isConsumableType(ParamType->getPointeeType()))
David Blaikie16f76d22013-09-06 01:28:43 +0000896 ParamState = consumed::CS_Unknown;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000897
898 if (ParamState != CS_None)
David Blaikie16f76d22013-09-06 01:28:43 +0000899 StateMap->setState(Param, ParamState);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000900}
901
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000902void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000903 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
904
905 if (ExpectedState != CS_None) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000906 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
907
908 if (Entry != PropagationMap.end()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000909 ConsumedState RetState = Entry->second.getAsState(StateMap);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000910
911 if (RetState != ExpectedState)
912 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
913 Ret->getReturnLoc(), stateToString(ExpectedState),
914 stateToString(RetState));
915 }
916 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000917
918 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
919 Analyzer.WarningsHandler);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000920}
921
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000922void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000923 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
924 if (Entry == PropagationMap.end()) return;
925
926 switch (UOp->getOpcode()) {
927 case UO_AddrOf:
928 PropagationMap.insert(PairType(UOp, Entry->second));
929 break;
930
931 case UO_LNot:
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000932 if (Entry->second.isTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000933 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
934 break;
935
936 default:
937 break;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000938 }
939}
940
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000941// TODO: See if I need to check for reference types here.
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000942void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000943 if (isConsumableType(Var->getType())) {
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000944 if (Var->hasInit()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000945 MapType::iterator VIT = PropagationMap.find(
946 Var->getInit()->IgnoreImplicit());
DeLesley Hutchins81218662013-10-18 23:11:49 +0000947 if (VIT != PropagationMap.end()) {
948 PropagationInfo PInfo = VIT->second;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000949 ConsumedState St = PInfo.getAsState(StateMap);
950
DeLesley Hutchins81218662013-10-18 23:11:49 +0000951 if (St != consumed::CS_None) {
952 StateMap->setState(Var, St);
953 return;
954 }
955 }
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000956 }
DeLesley Hutchins81218662013-10-18 23:11:49 +0000957 // Otherwise
958 StateMap->setState(Var, consumed::CS_Unknown);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000959 }
960}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000961}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000962
963namespace clang {
964namespace consumed {
965
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000966void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
967 ConsumedStateMap *ThenStates,
968 ConsumedStateMap *ElseStates) {
969
970 ConsumedState VarState = ThenStates->getState(Test.Var);
971
972 if (VarState == CS_Unknown) {
973 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000974 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000975
976 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
977 ThenStates->markUnreachable();
978
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000979 } else if (VarState == Test.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000980 ElseStates->markUnreachable();
981 }
982}
983
984void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
985 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
986
987 const VarTestResult &LTest = PInfo.getLTest(),
988 &RTest = PInfo.getRTest();
989
990 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
991 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
992
993 if (LTest.Var) {
994 if (PInfo.testEffectiveOp() == EO_And) {
995 if (LState == CS_Unknown) {
996 ThenStates->setState(LTest.Var, LTest.TestsFor);
997
998 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
999 ThenStates->markUnreachable();
1000
1001 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001002 if (RState == RTest.TestsFor)
1003 ElseStates->markUnreachable();
1004 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001005 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001006 }
1007
1008 } else {
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001009 if (LState == CS_Unknown) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001010 ElseStates->setState(LTest.Var,
1011 invertConsumedUnconsumed(LTest.TestsFor));
1012
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001013 } else if (LState == LTest.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001014 ElseStates->markUnreachable();
1015
1016 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
1017 isKnownState(RState)) {
1018
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001019 if (RState == RTest.TestsFor)
1020 ElseStates->markUnreachable();
1021 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001022 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001023 }
1024 }
1025 }
1026
1027 if (RTest.Var) {
1028 if (PInfo.testEffectiveOp() == EO_And) {
1029 if (RState == CS_Unknown)
1030 ThenStates->setState(RTest.Var, RTest.TestsFor);
1031 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1032 ThenStates->markUnreachable();
1033
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001034 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001035 if (RState == CS_Unknown)
1036 ElseStates->setState(RTest.Var,
1037 invertConsumedUnconsumed(RTest.TestsFor));
1038 else if (RState == RTest.TestsFor)
1039 ElseStates->markUnreachable();
1040 }
1041 }
1042}
1043
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001044bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1045 const CFGBlock *TargetBlock) {
1046
1047 assert(CurrBlock && "Block pointer must not be NULL");
1048 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1049
1050 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1051 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1052 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1053 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1054 return false;
1055 }
1056 return true;
1057}
1058
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001059void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1060 ConsumedStateMap *StateMap,
1061 bool &AlreadyOwned) {
1062
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001063 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001064
1065 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1066
1067 if (Entry) {
1068 Entry->intersect(StateMap);
1069
1070 } else if (AlreadyOwned) {
1071 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
1072
1073 } else {
1074 StateMapsArray[Block->getBlockID()] = StateMap;
1075 AlreadyOwned = true;
1076 }
1077}
1078
1079void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1080 ConsumedStateMap *StateMap) {
1081
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001082 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001083
1084 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1085
1086 if (Entry) {
1087 Entry->intersect(StateMap);
1088 delete StateMap;
1089
1090 } else {
1091 StateMapsArray[Block->getBlockID()] = StateMap;
1092 }
1093}
1094
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001095ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1096 assert(Block && "Block pointer must not be NULL");
1097 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1098
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001099 return StateMapsArray[Block->getBlockID()];
1100}
1101
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001102void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1103 unsigned int BlockID = Block->getBlockID();
1104 delete StateMapsArray[BlockID];
1105 StateMapsArray[BlockID] = NULL;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001106}
1107
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001108ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1109 assert(Block && "Block pointer must not be NULL");
1110
1111 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1112 if (isBackEdgeTarget(Block)) {
1113 return new ConsumedStateMap(*StateMap);
1114 } else {
1115 StateMapsArray[Block->getBlockID()] = NULL;
1116 return StateMap;
1117 }
1118}
1119
1120bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1121 assert(From && "From block must not be NULL");
1122 assert(To && "From block must not be NULL");
1123
1124 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1125}
1126
1127bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1128 assert(Block != NULL && "Block pointer must not be NULL");
1129
1130 // Anything with less than two predecessors can't be the target of a back
1131 // edge.
1132 if (Block->pred_size() < 2)
1133 return false;
1134
1135 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1136 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1137 PE = Block->pred_end(); PI != PE; ++PI) {
1138 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1139 return true;
1140 }
1141 return false;
1142}
1143
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001144void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1145 ConsumedWarningsHandlerBase &WarningsHandler) const {
1146
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001147 for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
1148 DMI != DME; ++DMI) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001149
1150 if (isa<ParmVarDecl>(DMI->first)) {
1151 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001152 const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001153
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001154 if (!RTA)
1155 continue;
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001156
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001157 ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
1158 if (DMI->second != ExpectedState)
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001159 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1160 Param->getNameAsString(), stateToString(ExpectedState),
1161 stateToString(DMI->second));
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001162 }
1163 }
1164}
1165
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001166void ConsumedStateMap::clearTemporaries() {
1167 TmpMap.clear();
1168}
1169
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001170ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001171 VarMapType::const_iterator Entry = VarMap.find(Var);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001172
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001173 if (Entry != VarMap.end())
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001174 return Entry->second;
1175
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001176 return CS_None;
1177}
1178
1179ConsumedState
1180ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
1181 TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1182
1183 if (Entry != TmpMap.end())
1184 return Entry->second;
1185
1186 return CS_None;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001187}
1188
1189void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1190 ConsumedState LocalState;
1191
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001192 if (this->From && this->From == Other->From && !Other->Reachable) {
1193 this->markUnreachable();
1194 return;
1195 }
1196
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001197 for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
1198 DME = Other->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001199
1200 LocalState = this->getState(DMI->first);
1201
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001202 if (LocalState == CS_None)
1203 continue;
1204
1205 if (LocalState != DMI->second)
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001206 VarMap[DMI->first] = CS_Unknown;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001207 }
1208}
1209
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001210void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1211 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1212 ConsumedWarningsHandlerBase &WarningsHandler) {
1213
1214 ConsumedState LocalState;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001215 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001216
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001217 for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
1218 DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001219
1220 LocalState = this->getState(DMI->first);
1221
1222 if (LocalState == CS_None)
1223 continue;
1224
1225 if (LocalState != DMI->second) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001226 VarMap[DMI->first] = CS_Unknown;
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001227 WarningsHandler.warnLoopStateMismatch(
1228 BlameLoc, DMI->first->getNameAsString());
1229 }
1230 }
1231}
1232
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001233void ConsumedStateMap::markUnreachable() {
1234 this->Reachable = false;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001235 VarMap.clear();
1236 TmpMap.clear();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001237}
1238
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001239void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001240 VarMap[Var] = State;
1241}
1242
1243void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
1244 ConsumedState State) {
1245 TmpMap[Tmp] = State;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001246}
1247
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001248void ConsumedStateMap::remove(const VarDecl *Var) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001249 VarMap.erase(Var);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001250}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001251
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001252bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001253 for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
1254 DME = Other->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001255
1256 if (this->getState(DMI->first) != DMI->second)
1257 return true;
1258 }
1259
1260 return false;
1261}
1262
David Blaikie16f76d22013-09-06 01:28:43 +00001263void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1264 const FunctionDecl *D) {
1265 QualType ReturnType;
1266 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1267 ASTContext &CurrContext = AC.getASTContext();
1268 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1269 } else
1270 ReturnType = D->getCallResultType();
1271
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001272 if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
David Blaikie16f76d22013-09-06 01:28:43 +00001273 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1274 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1275 // FIXME: This should be removed when template instantiation propagates
1276 // attributes at template specialization definition, not
1277 // declaration. When it is removed the test needs to be enabled
1278 // in SemaDeclAttr.cpp.
1279 WarningsHandler.warnReturnTypestateForUnconsumableType(
1280 RTSAttr->getLocation(), ReturnType.getAsString());
1281 ExpectedReturnState = CS_None;
1282 } else
1283 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1284 } else if (isConsumableType(ReturnType))
1285 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1286 else
1287 ExpectedReturnState = CS_None;
1288}
1289
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001290bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1291 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001292
Chris Wailes2dc8c422013-10-25 15:33:28 +00001293 OwningPtr<ConsumedStateMap> FalseStates(new ConsumedStateMap(*CurrStates));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001294 PropagationInfo PInfo;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001295
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001296 if (const IfStmt *IfNode =
1297 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001298
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001299 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001300
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001301 PInfo = Visitor.getInfo(Cond);
1302 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1303 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1304
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001305 if (PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001306 CurrStates->setSource(Cond);
1307 FalseStates->setSource(Cond);
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001308 splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates,
Chris Wailes2dc8c422013-10-25 15:33:28 +00001309 FalseStates.get());
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001310
1311 } else if (PInfo.isBinTest()) {
1312 CurrStates->setSource(PInfo.testSourceNode());
1313 FalseStates->setSource(PInfo.testSourceNode());
Chris Wailes2dc8c422013-10-25 15:33:28 +00001314 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get());
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001315
1316 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001317 return false;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001318 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001319
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001320 } else if (const BinaryOperator *BinOp =
1321 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1322
1323 PInfo = Visitor.getInfo(BinOp->getLHS());
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001324 if (!PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001325 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1326 PInfo = Visitor.getInfo(BinOp->getRHS());
1327
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001328 if (!PInfo.isVarTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001329 return false;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001330
1331 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001332 return false;
1333 }
1334 }
1335
1336 CurrStates->setSource(BinOp);
1337 FalseStates->setSource(BinOp);
1338
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001339 const VarTestResult &Test = PInfo.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001340 ConsumedState VarState = CurrStates->getState(Test.Var);
1341
1342 if (BinOp->getOpcode() == BO_LAnd) {
1343 if (VarState == CS_Unknown)
1344 CurrStates->setState(Test.Var, Test.TestsFor);
1345 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1346 CurrStates->markUnreachable();
1347
1348 } else if (BinOp->getOpcode() == BO_LOr) {
1349 if (VarState == CS_Unknown)
1350 FalseStates->setState(Test.Var,
1351 invertConsumedUnconsumed(Test.TestsFor));
1352 else if (VarState == Test.TestsFor)
1353 FalseStates->markUnreachable();
1354 }
1355
1356 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001357 return false;
1358 }
1359
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001360 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1361
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001362 if (*SI)
1363 BlockInfo.addInfo(*SI, CurrStates);
1364 else
1365 delete CurrStates;
1366
1367 if (*++SI)
Chris Wailes2dc8c422013-10-25 15:33:28 +00001368 BlockInfo.addInfo(*SI, FalseStates.take());
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001369
1370 CurrStates = NULL;
1371 return true;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001372}
1373
1374void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1375 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001376 if (!D)
1377 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001378
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001379 CFG *CFGraph = AC.getCFG();
1380 if (!CFGraph)
1381 return;
DeLesley Hutchins65013202013-10-17 18:19:31 +00001382
David Blaikie16f76d22013-09-06 01:28:43 +00001383 determineExpectedReturnState(AC, D);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001384
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001385 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001386 // AC.getCFG()->viewCFG(LangOptions());
1387
1388 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001389
1390 CurrStates = new ConsumedStateMap();
DeLesley Hutchinsb570c132013-08-29 22:36:05 +00001391 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1392
1393 // Add all trackable parameters to the state map.
1394 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1395 PE = D->param_end(); PI != PE; ++PI) {
1396 Visitor.VisitParmVarDecl(*PI);
1397 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001398
1399 // Visit all of the function's basic blocks.
1400 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1401 E = SortedGraph->end(); I != E; ++I) {
1402
1403 const CFGBlock *CurrBlock = *I;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001404
1405 if (CurrStates == NULL)
1406 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001407
1408 if (!CurrStates) {
1409 continue;
1410
1411 } else if (!CurrStates->isReachable()) {
1412 delete CurrStates;
1413 CurrStates = NULL;
1414 continue;
1415 }
1416
1417 Visitor.reset(CurrStates);
1418
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001419 // Visit all of the basic block's statements.
1420 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1421 BE = CurrBlock->end(); BI != BE; ++BI) {
1422
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001423 switch (BI->getKind()) {
1424 case CFGElement::Statement:
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001425 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001426 break;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001427
1428 case CFGElement::TemporaryDtor: {
1429 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1430 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001431
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001432 Visitor.checkCallability(PropagationInfo(BTE),
1433 DTor.getDestructorDecl(AC.getASTContext()),
1434 BTE->getExprLoc());
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001435 break;
1436 }
1437
1438 case CFGElement::AutomaticObjectDtor: {
1439 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001440 SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001441 const VarDecl *Var = DTor.getVarDecl();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001442
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001443 Visitor.checkCallability(PropagationInfo(Var),
1444 DTor.getDestructorDecl(AC.getASTContext()),
1445 Loc);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001446 break;
1447 }
1448
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001449 default:
1450 break;
1451 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001452 }
1453
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001454 CurrStates->clearTemporaries();
1455
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001456 // TODO: Handle other forms of branching with precision, including while-
1457 // and for-loops. (Deferred)
1458 if (!splitState(CurrBlock, Visitor)) {
1459 CurrStates->setSource(NULL);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001460
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001461 if (CurrBlock->succ_size() > 1 ||
1462 (CurrBlock->succ_size() == 1 &&
1463 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001464
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001465 bool OwnershipTaken = false;
1466
1467 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1468 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1469
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001470 if (*SI == NULL) continue;
1471
1472 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1473 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1474 CurrStates,
1475 WarningsHandler);
1476
1477 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1478 BlockInfo.discardInfo(*SI);
1479 } else {
1480 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1481 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001482 }
1483
1484 if (!OwnershipTaken)
1485 delete CurrStates;
1486
1487 CurrStates = NULL;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001488 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001489 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001490
1491 if (CurrBlock == &AC.getCFG()->getExit() &&
1492 D->getCallResultType()->isVoidType())
1493 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1494 WarningsHandler);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001495 } // End of block iterator.
1496
1497 // Delete the last existing state map.
1498 delete CurrStates;
1499
1500 WarningsHandler.emitDiagnostics();
1501}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001502}} // end namespace clang::consumed