blob: ce85796ab411396db996dee94f2c9eddb22cdf0c [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"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000020#include "clang/AST/StmtCXX.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000021#include "clang/AST/StmtVisitor.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000022#include "clang/AST/Type.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000023#include "clang/Analysis/Analyses/Consumed.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000024#include "clang/Analysis/Analyses/PostOrderCFGView.h"
25#include "clang/Analysis/AnalysisContext.h"
26#include "clang/Analysis/CFG.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000027#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 Hutchinsf28bbec2014-01-14 00:36:53 +0000146
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000147static bool isConsumableType(const QualType &QT) {
Chris Wailes93edffa2013-10-31 15:38:12 +0000148 if (QT->isPointerType() || QT->isReferenceType())
149 return false;
150
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000151 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
152 return RD->hasAttr<ConsumableAttr>();
Chris Wailes93edffa2013-10-31 15:38:12 +0000153
154 return false;
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000155}
156
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000157static bool isAutoCastType(const QualType &QT) {
158 if (QT->isPointerType() || QT->isReferenceType())
159 return false;
160
161 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
162 return RD->hasAttr<ConsumableAutoCastAttr>();
163
164 return false;
165}
166
167static bool isSetOnReadPtrType(const QualType &QT) {
168 if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
169 return RD->hasAttr<ConsumableSetOnReadAttr>();
170 return false;
171}
172
173
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000174static bool isKnownState(ConsumedState State) {
175 switch (State) {
176 case CS_Unconsumed:
177 case CS_Consumed:
178 return true;
179 case CS_None:
180 case CS_Unknown:
181 return false;
182 }
Aaron Ballmana21f4b82013-08-29 20:36:09 +0000183 llvm_unreachable("invalid enum");
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000184}
185
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000186static bool isRValueRef(QualType ParamType) {
187 return ParamType->isRValueReferenceType();
DeLesley Hutchins0bd25892013-10-18 19:25:18 +0000188}
189
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000190static bool isTestingFunction(const FunctionDecl *FunDecl) {
Chris Wailes9385f9f2013-10-29 20:28:41 +0000191 return FunDecl->hasAttr<TestTypestateAttr>();
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000192}
193
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000194static bool isPointerOrRef(QualType ParamType) {
195 return ParamType->isPointerType() || ParamType->isReferenceType();
DeLesley Hutchins0bd25892013-10-18 19:25:18 +0000196}
197
David Blaikie16f76d22013-09-06 01:28:43 +0000198static ConsumedState mapConsumableAttrState(const QualType QT) {
199 assert(isConsumableType(QT));
200
201 const ConsumableAttr *CAttr =
202 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
203
204 switch (CAttr->getDefaultState()) {
205 case ConsumableAttr::Unknown:
206 return CS_Unknown;
207 case ConsumableAttr::Unconsumed:
208 return CS_Unconsumed;
209 case ConsumableAttr::Consumed:
210 return CS_Consumed;
211 }
212 llvm_unreachable("invalid enum");
213}
214
DeLesley Hutchins69391772013-10-17 23:23:53 +0000215static ConsumedState
216mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
217 switch (PTAttr->getParamState()) {
218 case ParamTypestateAttr::Unknown:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000219 return CS_Unknown;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000220 case ParamTypestateAttr::Unconsumed:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000221 return CS_Unconsumed;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000222 case ParamTypestateAttr::Consumed:
DeLesley Hutchins33a29342013-10-11 23:03:26 +0000223 return CS_Consumed;
224 }
225 llvm_unreachable("invalid_enum");
226}
227
Eric Christopherde156242013-09-03 20:43:00 +0000228static ConsumedState
229mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000230 switch (RTSAttr->getState()) {
231 case ReturnTypestateAttr::Unknown:
232 return CS_Unknown;
233 case ReturnTypestateAttr::Unconsumed:
234 return CS_Unconsumed;
235 case ReturnTypestateAttr::Consumed:
236 return CS_Consumed;
237 }
Eric Christopherde156242013-09-03 20:43:00 +0000238 llvm_unreachable("invalid enum");
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000239}
240
DeLesley Hutchins69391772013-10-17 23:23:53 +0000241static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
242 switch (STAttr->getNewState()) {
243 case SetTypestateAttr::Unknown:
244 return CS_Unknown;
245 case SetTypestateAttr::Unconsumed:
246 return CS_Unconsumed;
247 case SetTypestateAttr::Consumed:
248 return CS_Consumed;
249 }
250 llvm_unreachable("invalid_enum");
251}
252
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000253static StringRef stateToString(ConsumedState State) {
254 switch (State) {
255 case consumed::CS_None:
256 return "none";
257
258 case consumed::CS_Unknown:
259 return "unknown";
260
261 case consumed::CS_Unconsumed:
262 return "unconsumed";
263
264 case consumed::CS_Consumed:
265 return "consumed";
266 }
Reid Kleckner6454d0a2013-08-13 00:11:59 +0000267 llvm_unreachable("invalid enum");
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000268}
269
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000270static ConsumedState testsFor(const FunctionDecl *FunDecl) {
271 assert(isTestingFunction(FunDecl));
Chris Wailes9385f9f2013-10-29 20:28:41 +0000272 switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
273 case TestTypestateAttr::Unconsumed:
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000274 return CS_Unconsumed;
Chris Wailes9385f9f2013-10-29 20:28:41 +0000275 case TestTypestateAttr::Consumed:
DeLesley Hutchins8d41d992013-10-11 22:30:48 +0000276 return CS_Consumed;
277 }
278 llvm_unreachable("invalid enum");
279}
280
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000281namespace {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000282struct VarTestResult {
283 const VarDecl *Var;
284 ConsumedState TestsFor;
285};
286} // end anonymous::VarTestResult
287
288namespace clang {
289namespace consumed {
290
291enum EffectiveOp {
292 EO_And,
293 EO_Or
294};
295
296class PropagationInfo {
297 enum {
298 IT_None,
299 IT_State,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000300 IT_VarTest,
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000301 IT_BinTest,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000302 IT_Var,
303 IT_Tmp
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000304 } InfoType;
Eric Christopherf8a1baa2013-08-29 18:00:58 +0000305
306 struct BinTestTy {
307 const BinaryOperator *Source;
308 EffectiveOp EOp;
309 VarTestResult LTest;
310 VarTestResult RTest;
311 };
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000312
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000313 union {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000314 ConsumedState State;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000315 VarTestResult VarTest;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000316 const VarDecl *Var;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000317 const CXXBindTemporaryExpr *Tmp;
Eric Christopherf8a1baa2013-08-29 18:00:58 +0000318 BinTestTy BinTest;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000319 };
320
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000321public:
322 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000323
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000324 PropagationInfo(const VarTestResult &VarTest)
325 : InfoType(IT_VarTest), VarTest(VarTest) {}
326
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000327 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000328 : InfoType(IT_VarTest) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000329
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000330 VarTest.Var = Var;
331 VarTest.TestsFor = TestsFor;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000332 }
333
334 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
335 const VarTestResult &LTest, const VarTestResult &RTest)
336 : InfoType(IT_BinTest) {
337
338 BinTest.Source = Source;
339 BinTest.EOp = EOp;
340 BinTest.LTest = LTest;
341 BinTest.RTest = RTest;
342 }
343
344 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
345 const VarDecl *LVar, ConsumedState LTestsFor,
346 const VarDecl *RVar, ConsumedState RTestsFor)
347 : InfoType(IT_BinTest) {
348
349 BinTest.Source = Source;
350 BinTest.EOp = EOp;
351 BinTest.LTest.Var = LVar;
352 BinTest.LTest.TestsFor = LTestsFor;
353 BinTest.RTest.Var = RVar;
354 BinTest.RTest.TestsFor = RTestsFor;
355 }
356
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000357 PropagationInfo(ConsumedState State)
358 : InfoType(IT_State), State(State) {}
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000359
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000360 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000361 PropagationInfo(const CXXBindTemporaryExpr *Tmp)
362 : InfoType(IT_Tmp), Tmp(Tmp) {}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000363
364 const ConsumedState & getState() const {
365 assert(InfoType == IT_State);
366 return State;
367 }
368
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000369 const VarTestResult & getVarTest() const {
370 assert(InfoType == IT_VarTest);
371 return VarTest;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000372 }
373
374 const VarTestResult & getLTest() const {
375 assert(InfoType == IT_BinTest);
376 return BinTest.LTest;
377 }
378
379 const VarTestResult & getRTest() const {
380 assert(InfoType == IT_BinTest);
381 return BinTest.RTest;
382 }
383
384 const VarDecl * getVar() const {
385 assert(InfoType == IT_Var);
386 return Var;
387 }
388
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000389 const CXXBindTemporaryExpr * getTmp() const {
390 assert(InfoType == IT_Tmp);
391 return Tmp;
392 }
393
394 ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
395 assert(isVar() || isTmp() || isState());
396
397 if (isVar())
398 return StateMap->getState(Var);
399 else if (isTmp())
400 return StateMap->getState(Tmp);
401 else if (isState())
402 return State;
403 else
404 return CS_None;
405 }
406
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000407 EffectiveOp testEffectiveOp() const {
408 assert(InfoType == IT_BinTest);
409 return BinTest.EOp;
410 }
411
412 const BinaryOperator * testSourceNode() const {
413 assert(InfoType == IT_BinTest);
414 return BinTest.Source;
415 }
416
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000417 inline bool isValid() const { return InfoType != IT_None; }
418 inline bool isState() const { return InfoType == IT_State; }
419 inline bool isVarTest() const { return InfoType == IT_VarTest; }
420 inline bool isBinTest() const { return InfoType == IT_BinTest; }
421 inline bool isVar() const { return InfoType == IT_Var; }
422 inline bool isTmp() const { return InfoType == IT_Tmp; }
423
424 bool isTest() const {
425 return InfoType == IT_VarTest || InfoType == IT_BinTest;
426 }
427
428 bool isPointerToValue() const {
429 return InfoType == IT_Var || InfoType == IT_Tmp;
430 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000431
432 PropagationInfo invertTest() const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000433 assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000434
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000435 if (InfoType == IT_VarTest) {
436 return PropagationInfo(VarTest.Var,
437 invertConsumedUnconsumed(VarTest.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000438
439 } else if (InfoType == IT_BinTest) {
440 return PropagationInfo(BinTest.Source,
441 BinTest.EOp == EO_And ? EO_Or : EO_And,
442 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
443 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
444 } else {
445 return PropagationInfo();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000446 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000447 }
448};
449
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000450static inline void
451setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
452 ConsumedState State) {
453
454 assert(PInfo.isVar() || PInfo.isTmp());
455
456 if (PInfo.isVar())
457 StateMap->setState(PInfo.getVar(), State);
458 else
459 StateMap->setState(PInfo.getTmp(), State);
460}
461
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000462class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000463
464 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
465 typedef std::pair<const Stmt *, PropagationInfo> PairType;
466 typedef MapType::iterator InfoEntry;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000467 typedef MapType::const_iterator ConstInfoEntry;
468
Reid Klecknere846dea2013-08-12 23:49:39 +0000469 AnalysisDeclContext &AC;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000470 ConsumedAnalyzer &Analyzer;
471 ConsumedStateMap *StateMap;
472 MapType PropagationMap;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000473
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000474 void forwardInfo(const Stmt *From, const Stmt *To);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000475 void copyInfo(const Stmt *From, const Stmt *To, ConsumedState CS);
476 ConsumedState getInfo(const Stmt *From);
477 void setInfo(const Stmt *To, ConsumedState NS);
478 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun);
DeLesley Hutchins81218662013-10-18 23:11:49 +0000479
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000480public:
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000481 void checkCallability(const PropagationInfo &PInfo,
482 const FunctionDecl *FunDecl,
483 SourceLocation BlameLoc);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000484 bool handleCall(const CallExpr *Call, const Expr *ObjArg,
485 const FunctionDecl *FunD);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000486
487 void VisitBinaryOperator(const BinaryOperator *BinOp);
488 void VisitCallExpr(const CallExpr *Call);
489 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000490 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000491 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
492 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
493 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
494 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
495 void VisitDeclStmt(const DeclStmt *DelcS);
496 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
497 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000498 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000499 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000500 void VisitUnaryOperator(const UnaryOperator *UOp);
501 void VisitVarDecl(const VarDecl *Var);
Reid Klecknere846dea2013-08-12 23:49:39 +0000502
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000503 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
504 ConsumedStateMap *StateMap)
505 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000506
507 PropagationInfo getInfo(const Stmt *StmtNode) const {
508 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
509
510 if (Entry != PropagationMap.end())
511 return Entry->second;
512 else
513 return PropagationInfo();
514 }
515
516 void reset(ConsumedStateMap *NewStateMap) {
517 StateMap = NewStateMap;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000518 }
519};
520
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000521
522void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
523 InfoEntry Entry = PropagationMap.find(From);
524 if (Entry != PropagationMap.end())
525 PropagationMap.insert(PairType(To, Entry->second));
526}
527
528
529// Create a new state for To, which is initialized to the state of From.
530// If NS is not CS_None, sets the state of From to NS.
531void ConsumedStmtVisitor::copyInfo(const Stmt *From, const Stmt *To,
532 ConsumedState NS) {
533 InfoEntry Entry = PropagationMap.find(From);
534 if (Entry != PropagationMap.end()) {
535 PropagationInfo& PInfo = Entry->second;
536 ConsumedState CS = PInfo.getAsState(StateMap);
537 if (CS != CS_None)
538 PropagationMap.insert(PairType(To, CS));
539 if (NS != CS_None && PInfo.isPointerToValue())
540 setStateForVarOrTmp(StateMap, PInfo, NS);
541 }
542}
543
544
545// Get the ConsumedState for From
546ConsumedState ConsumedStmtVisitor::getInfo(const Stmt *From) {
547 InfoEntry Entry = PropagationMap.find(From);
548 if (Entry != PropagationMap.end()) {
549 PropagationInfo& PInfo = Entry->second;
550 return PInfo.getAsState(StateMap);
551 }
552 return CS_None;
553}
554
555
556// If we already have info for To then update it, otherwise create a new entry.
557void ConsumedStmtVisitor::setInfo(const Stmt *To, ConsumedState NS) {
558 InfoEntry Entry = PropagationMap.find(To);
559 if (Entry != PropagationMap.end()) {
560 PropagationInfo& PInfo = Entry->second;
561 if (PInfo.isPointerToValue())
562 setStateForVarOrTmp(StateMap, PInfo, NS);
563 } else if (NS != CS_None) {
564 PropagationMap.insert(PairType(To, PropagationInfo(NS)));
565 }
566}
567
568
569
DeLesley Hutchins2445b122013-08-26 20:34:59 +0000570void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000571 const FunctionDecl *FunDecl,
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000572 SourceLocation BlameLoc) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000573 assert(!PInfo.isTest());
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000574
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000575 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000576 if (!CWAttr)
577 return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000578
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000579 if (PInfo.isVar()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000580 ConsumedState VarState = StateMap->getState(PInfo.getVar());
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000581
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000582 if (VarState == CS_None || isCallableInState(CWAttr, VarState))
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000583 return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000584
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000585 Analyzer.WarningsHandler.warnUseInInvalidState(
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000586 FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000587 stateToString(VarState), BlameLoc);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000588
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000589 } else {
590 ConsumedState TmpState = PInfo.getAsState(StateMap);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000591
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000592 if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000593 return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000594
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000595 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000596 FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +0000597 }
598}
599
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000600
601// Factors out common behavior for function, method, and operator calls.
602// Check parameters and set parameter state if necessary.
603// Returns true if the state of ObjArg is set, or false otherwise.
604bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
605 const FunctionDecl *FunD) {
606 unsigned Offset = 0;
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000607 if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
608 Offset = 1; // first argument is 'this'
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000609
610 // check explicit parameters
611 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
612 // Skip variable argument lists.
613 if (Index - Offset >= FunD->getNumParams())
614 break;
615
616 const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
617 QualType ParamType = Param->getType();
618
619 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
620
621 if (Entry == PropagationMap.end() || Entry->second.isTest())
622 continue;
623 PropagationInfo PInfo = Entry->second;
624
625 // Check that the parameter is in the correct state.
626 if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
627 ConsumedState ParamState = PInfo.getAsState(StateMap);
628 ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
629
630 if (ParamState != ExpectedState)
631 Analyzer.WarningsHandler.warnParamTypestateMismatch(
632 Call->getArg(Index)->getExprLoc(),
633 stateToString(ExpectedState), stateToString(ParamState));
634 }
635
636 if (!(Entry->second.isVar() || Entry->second.isTmp()))
637 continue;
638
639 // Adjust state on the caller side.
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000640 if (isRValueRef(ParamType))
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000641 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
642 else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
643 setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000644 else if (isPointerOrRef(ParamType) &&
645 (!ParamType->getPointeeType().isConstQualified() ||
646 isSetOnReadPtrType(ParamType)))
647 setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000648 }
649
650 if (!ObjArg)
651 return false;
652
653 // check implicit 'self' parameter, if present
654 InfoEntry Entry = PropagationMap.find(ObjArg);
655 if (Entry != PropagationMap.end()) {
656 PropagationInfo PInfo = Entry->second;
657 checkCallability(PInfo, FunD, Call->getExprLoc());
658
659 if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
660 if (PInfo.isVar()) {
661 StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
662 return true;
663 }
664 else if (PInfo.isTmp()) {
665 StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
666 return true;
667 }
668 }
669 else if (isTestingFunction(FunD) && PInfo.isVar()) {
670 PropagationMap.insert(PairType(Call,
671 PropagationInfo(PInfo.getVar(), testsFor(FunD))));
672 }
673 }
674 return false;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000675}
676
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000677
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000678void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000679 const FunctionDecl *Fun) {
680 QualType RetType = Fun->getCallResultType();
681 if (RetType->isReferenceType())
682 RetType = RetType->getPointeeType();
683
684 if (isConsumableType(RetType)) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000685 ConsumedState ReturnState;
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000686 if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
687 ReturnState = mapReturnTypestateAttrState(RTA);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000688 else
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000689 ReturnState = mapConsumableAttrState(RetType);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000690
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000691 PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000692 }
693}
694
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000695
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000696void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
697 switch (BinOp->getOpcode()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000698 case BO_LAnd:
699 case BO_LOr : {
700 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
701 REntry = PropagationMap.find(BinOp->getRHS());
702
703 VarTestResult LTest, RTest;
704
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000705 if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
706 LTest = LEntry->second.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000707
708 } else {
709 LTest.Var = NULL;
710 LTest.TestsFor = CS_None;
711 }
712
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000713 if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
714 RTest = REntry->second.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000715
716 } else {
717 RTest.Var = NULL;
718 RTest.TestsFor = CS_None;
719 }
720
721 if (!(LTest.Var == NULL && RTest.Var == NULL))
722 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
723 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
724
725 break;
726 }
727
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000728 case BO_PtrMemD:
729 case BO_PtrMemI:
730 forwardInfo(BinOp->getLHS(), BinOp);
731 break;
732
733 default:
734 break;
735 }
736}
737
Richard Trieuc6896912013-12-17 00:40:40 +0000738static bool isStdNamespace(const DeclContext *DC) {
739 if (!DC->isNamespace()) return false;
740 while (DC->getParent()->isNamespace())
741 DC = DC->getParent();
742 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
743
744 return ND && ND->getName() == "std" &&
745 ND->getDeclContext()->isTranslationUnit();
746}
747
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000748void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000749 const FunctionDecl *FunDecl = Call->getDirectCallee();
750 if (!FunDecl)
751 return;
752
753 // Special case for the std::move function.
754 // TODO: Make this more specific. (Deferred)
755 if (Call->getNumArgs() == 1 &&
756 FunDecl->getNameAsString() == "move" &&
757 isStdNamespace(FunDecl->getDeclContext())) {
758 copyInfo(Call->getArg(0), Call, CS_Consumed);
759 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000760 }
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000761
762 handleCall(Call, 0, FunDecl);
763 propagateReturnType(Call, FunDecl);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000764}
765
766void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000767 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000768}
769
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000770void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
771 const CXXBindTemporaryExpr *Temp) {
772
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000773 InfoEntry Entry = PropagationMap.find(Temp->getSubExpr());
774
775 if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
776 StateMap->setState(Temp, Entry->second.getAsState(StateMap));
777 PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
778 }
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +0000779}
780
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000781void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
782 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Klecknere846dea2013-08-12 23:49:39 +0000783
784 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000785 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
786
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000787 if (!isConsumableType(ThisType))
788 return;
789
790 // FIXME: What should happen if someone annotates the move constructor?
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000791 if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
792 // TODO: Adjust state of args appropriately.
793 ConsumedState RetState = mapReturnTypestateAttrState(RTA);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000794 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
795 } else if (Constructor->isDefaultConstructor()) {
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000796 PropagationMap.insert(PairType(Call,
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000797 PropagationInfo(consumed::CS_Consumed)));
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000798 } else if (Constructor->isMoveConstructor()) {
799 copyInfo(Call->getArg(0), Call, CS_Consumed);
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000800 } else if (Constructor->isCopyConstructor()) {
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000801 // Copy state from arg. If setStateOnRead then set arg to CS_Unknown.
802 ConsumedState NS =
803 isSetOnReadPtrType(Constructor->getThisType(CurrContext)) ?
804 CS_Unknown : CS_None;
805 copyInfo(Call->getArg(0), Call, NS);
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000806 } else {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000807 // TODO: Adjust state of args appropriately.
DeLesley Hutchins11a66c12013-10-18 18:36:21 +0000808 ConsumedState RetState = mapConsumableAttrState(ThisType);
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000809 PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000810 }
811}
812
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000813
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000814void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000815 const CXXMemberCallExpr *Call) {
816 CXXMethodDecl* MD = Call->getMethodDecl();
817 if (!MD)
818 return;
819
820 handleCall(Call, Call->getImplicitObjectArgument(), MD);
821 propagateReturnType(Call, MD);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000822}
823
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000824
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000825void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000826 const CXXOperatorCallExpr *Call) {
827
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000828 const FunctionDecl *FunDecl =
829 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000830 if (!FunDecl) return;
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000831
832 if (Call->getOperator() == OO_Equal) {
833 ConsumedState CS = getInfo(Call->getArg(1));
834 if (!handleCall(Call, Call->getArg(0), FunDecl))
835 setInfo(Call->getArg(0), CS);
836 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000837 }
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +0000838
839 if (const CXXMemberCallExpr *MCall = dyn_cast<CXXMemberCallExpr>(Call))
840 handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
841 else
842 handleCall(Call, Call->getArg(0), FunDecl);
843
844 propagateReturnType(Call, FunDecl);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000845}
846
847void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
848 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
849 if (StateMap->getState(Var) != consumed::CS_None)
850 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
851}
852
853void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
854 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
855 DE = DeclS->decl_end(); DI != DE; ++DI) {
856
857 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
858 }
859
860 if (DeclS->isSingleDecl())
861 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
862 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
863}
864
865void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
866 const MaterializeTemporaryExpr *Temp) {
867
Chris Wailes44930882013-10-24 14:28:17 +0000868 forwardInfo(Temp->GetTemporaryExpr(), Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000869}
870
871void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
872 forwardInfo(MExpr->getBase(), MExpr);
873}
874
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000875
876void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikie16f76d22013-09-06 01:28:43 +0000877 QualType ParamType = Param->getType();
878 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000879
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000880 if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
881 ParamState = mapParamTypestateAttrState(PTA);
882 else if (isConsumableType(ParamType))
883 ParamState = mapConsumableAttrState(ParamType);
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000884 else if (isRValueRef(ParamType) &&
885 isConsumableType(ParamType->getPointeeType()))
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000886 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
887 else if (ParamType->isReferenceType() &&
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000888 isConsumableType(ParamType->getPointeeType()))
David Blaikie16f76d22013-09-06 01:28:43 +0000889 ParamState = consumed::CS_Unknown;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000890
891 if (ParamState != CS_None)
David Blaikie16f76d22013-09-06 01:28:43 +0000892 StateMap->setState(Param, ParamState);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000893}
894
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000895void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000896 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
897
898 if (ExpectedState != CS_None) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000899 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
900
901 if (Entry != PropagationMap.end()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000902 ConsumedState RetState = Entry->second.getAsState(StateMap);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000903
904 if (RetState != ExpectedState)
905 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
906 Ret->getReturnLoc(), stateToString(ExpectedState),
907 stateToString(RetState));
908 }
909 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000910
911 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
912 Analyzer.WarningsHandler);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000913}
914
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000915void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000916 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
917 if (Entry == PropagationMap.end()) return;
918
919 switch (UOp->getOpcode()) {
920 case UO_AddrOf:
921 PropagationMap.insert(PairType(UOp, Entry->second));
922 break;
923
924 case UO_LNot:
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000925 if (Entry->second.isTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000926 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
927 break;
928
929 default:
930 break;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000931 }
932}
933
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000934// TODO: See if I need to check for reference types here.
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000935void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000936 if (isConsumableType(Var->getType())) {
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000937 if (Var->hasInit()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000938 MapType::iterator VIT = PropagationMap.find(
939 Var->getInit()->IgnoreImplicit());
DeLesley Hutchins81218662013-10-18 23:11:49 +0000940 if (VIT != PropagationMap.end()) {
941 PropagationInfo PInfo = VIT->second;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000942 ConsumedState St = PInfo.getAsState(StateMap);
943
DeLesley Hutchins81218662013-10-18 23:11:49 +0000944 if (St != consumed::CS_None) {
945 StateMap->setState(Var, St);
946 return;
947 }
948 }
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000949 }
DeLesley Hutchins81218662013-10-18 23:11:49 +0000950 // Otherwise
951 StateMap->setState(Var, consumed::CS_Unknown);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000952 }
953}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000954}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000955
956namespace clang {
957namespace consumed {
958
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000959void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
960 ConsumedStateMap *ThenStates,
961 ConsumedStateMap *ElseStates) {
962
963 ConsumedState VarState = ThenStates->getState(Test.Var);
964
965 if (VarState == CS_Unknown) {
966 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000967 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000968
969 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
970 ThenStates->markUnreachable();
971
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000972 } else if (VarState == Test.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000973 ElseStates->markUnreachable();
974 }
975}
976
977void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
978 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
979
980 const VarTestResult &LTest = PInfo.getLTest(),
981 &RTest = PInfo.getRTest();
982
983 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
984 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
985
986 if (LTest.Var) {
987 if (PInfo.testEffectiveOp() == EO_And) {
988 if (LState == CS_Unknown) {
989 ThenStates->setState(LTest.Var, LTest.TestsFor);
990
991 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
992 ThenStates->markUnreachable();
993
994 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000995 if (RState == RTest.TestsFor)
996 ElseStates->markUnreachable();
997 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000998 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000999 }
1000
1001 } else {
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001002 if (LState == CS_Unknown) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001003 ElseStates->setState(LTest.Var,
1004 invertConsumedUnconsumed(LTest.TestsFor));
1005
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001006 } else if (LState == LTest.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001007 ElseStates->markUnreachable();
1008
1009 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
1010 isKnownState(RState)) {
1011
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001012 if (RState == RTest.TestsFor)
1013 ElseStates->markUnreachable();
1014 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001015 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001016 }
1017 }
1018 }
1019
1020 if (RTest.Var) {
1021 if (PInfo.testEffectiveOp() == EO_And) {
1022 if (RState == CS_Unknown)
1023 ThenStates->setState(RTest.Var, RTest.TestsFor);
1024 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1025 ThenStates->markUnreachable();
1026
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001027 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001028 if (RState == CS_Unknown)
1029 ElseStates->setState(RTest.Var,
1030 invertConsumedUnconsumed(RTest.TestsFor));
1031 else if (RState == RTest.TestsFor)
1032 ElseStates->markUnreachable();
1033 }
1034 }
1035}
1036
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001037bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1038 const CFGBlock *TargetBlock) {
1039
1040 assert(CurrBlock && "Block pointer must not be NULL");
1041 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1042
1043 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1044 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1045 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1046 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1047 return false;
1048 }
1049 return true;
1050}
1051
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001052void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1053 ConsumedStateMap *StateMap,
1054 bool &AlreadyOwned) {
1055
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001056 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001057
1058 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1059
1060 if (Entry) {
1061 Entry->intersect(StateMap);
1062
1063 } else if (AlreadyOwned) {
1064 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
1065
1066 } else {
1067 StateMapsArray[Block->getBlockID()] = StateMap;
1068 AlreadyOwned = true;
1069 }
1070}
1071
1072void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1073 ConsumedStateMap *StateMap) {
1074
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001075 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001076
1077 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1078
1079 if (Entry) {
1080 Entry->intersect(StateMap);
1081 delete StateMap;
1082
1083 } else {
1084 StateMapsArray[Block->getBlockID()] = StateMap;
1085 }
1086}
1087
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001088ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1089 assert(Block && "Block pointer must not be NULL");
1090 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1091
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001092 return StateMapsArray[Block->getBlockID()];
1093}
1094
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001095void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1096 unsigned int BlockID = Block->getBlockID();
1097 delete StateMapsArray[BlockID];
1098 StateMapsArray[BlockID] = NULL;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001099}
1100
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001101ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1102 assert(Block && "Block pointer must not be NULL");
1103
1104 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1105 if (isBackEdgeTarget(Block)) {
1106 return new ConsumedStateMap(*StateMap);
1107 } else {
1108 StateMapsArray[Block->getBlockID()] = NULL;
1109 return StateMap;
1110 }
1111}
1112
1113bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1114 assert(From && "From block must not be NULL");
1115 assert(To && "From block must not be NULL");
1116
1117 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1118}
1119
1120bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1121 assert(Block != NULL && "Block pointer must not be NULL");
1122
1123 // Anything with less than two predecessors can't be the target of a back
1124 // edge.
1125 if (Block->pred_size() < 2)
1126 return false;
1127
1128 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1129 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1130 PE = Block->pred_end(); PI != PE; ++PI) {
1131 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1132 return true;
1133 }
1134 return false;
1135}
1136
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001137void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1138 ConsumedWarningsHandlerBase &WarningsHandler) const {
1139
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001140 for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
1141 DMI != DME; ++DMI) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001142
1143 if (isa<ParmVarDecl>(DMI->first)) {
1144 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001145 const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001146
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001147 if (!RTA)
1148 continue;
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001149
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001150 ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
1151 if (DMI->second != ExpectedState)
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001152 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1153 Param->getNameAsString(), stateToString(ExpectedState),
1154 stateToString(DMI->second));
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001155 }
1156 }
1157}
1158
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001159void ConsumedStateMap::clearTemporaries() {
1160 TmpMap.clear();
1161}
1162
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001163ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001164 VarMapType::const_iterator Entry = VarMap.find(Var);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001165
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001166 if (Entry != VarMap.end())
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001167 return Entry->second;
1168
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001169 return CS_None;
1170}
1171
1172ConsumedState
1173ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
1174 TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1175
1176 if (Entry != TmpMap.end())
1177 return Entry->second;
1178
1179 return CS_None;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001180}
1181
1182void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1183 ConsumedState LocalState;
1184
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001185 if (this->From && this->From == Other->From && !Other->Reachable) {
1186 this->markUnreachable();
1187 return;
1188 }
1189
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001190 for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
1191 DME = Other->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001192
1193 LocalState = this->getState(DMI->first);
1194
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001195 if (LocalState == CS_None)
1196 continue;
1197
1198 if (LocalState != DMI->second)
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001199 VarMap[DMI->first] = CS_Unknown;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001200 }
1201}
1202
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001203void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1204 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1205 ConsumedWarningsHandlerBase &WarningsHandler) {
1206
1207 ConsumedState LocalState;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001208 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001209
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001210 for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
1211 DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001212
1213 LocalState = this->getState(DMI->first);
1214
1215 if (LocalState == CS_None)
1216 continue;
1217
1218 if (LocalState != DMI->second) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001219 VarMap[DMI->first] = CS_Unknown;
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001220 WarningsHandler.warnLoopStateMismatch(
1221 BlameLoc, DMI->first->getNameAsString());
1222 }
1223 }
1224}
1225
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001226void ConsumedStateMap::markUnreachable() {
1227 this->Reachable = false;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001228 VarMap.clear();
1229 TmpMap.clear();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001230}
1231
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001232void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001233 VarMap[Var] = State;
1234}
1235
1236void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
1237 ConsumedState State) {
1238 TmpMap[Tmp] = State;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001239}
1240
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001241void ConsumedStateMap::remove(const VarDecl *Var) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001242 VarMap.erase(Var);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001243}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001244
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001245bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001246 for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
1247 DME = Other->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001248
1249 if (this->getState(DMI->first) != DMI->second)
1250 return true;
1251 }
1252
1253 return false;
1254}
1255
David Blaikie16f76d22013-09-06 01:28:43 +00001256void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1257 const FunctionDecl *D) {
1258 QualType ReturnType;
1259 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1260 ASTContext &CurrContext = AC.getASTContext();
1261 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1262 } else
1263 ReturnType = D->getCallResultType();
1264
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001265 if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
David Blaikie16f76d22013-09-06 01:28:43 +00001266 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1267 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1268 // FIXME: This should be removed when template instantiation propagates
1269 // attributes at template specialization definition, not
1270 // declaration. When it is removed the test needs to be enabled
1271 // in SemaDeclAttr.cpp.
1272 WarningsHandler.warnReturnTypestateForUnconsumableType(
1273 RTSAttr->getLocation(), ReturnType.getAsString());
1274 ExpectedReturnState = CS_None;
1275 } else
1276 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +00001277 } else if (isConsumableType(ReturnType)) {
1278 if (isAutoCastType(ReturnType)) // We can auto-cast the state to the
1279 ExpectedReturnState = CS_None; // expected state.
1280 else
1281 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1282 }
David Blaikie16f76d22013-09-06 01:28:43 +00001283 else
1284 ExpectedReturnState = CS_None;
1285}
1286
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001287bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1288 const ConsumedStmtVisitor &Visitor) {
Ahmed Charlesb8984322014-03-07 20:03:18 +00001289
1290 std::unique_ptr<ConsumedStateMap> FalseStates(
1291 new ConsumedStateMap(*CurrStates));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001292 PropagationInfo PInfo;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001293
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001294 if (const IfStmt *IfNode =
1295 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001296
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001297 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001298
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001299 PInfo = Visitor.getInfo(Cond);
1300 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1301 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1302
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001303 if (PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001304 CurrStates->setSource(Cond);
1305 FalseStates->setSource(Cond);
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001306 splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates,
Chris Wailes2dc8c422013-10-25 15:33:28 +00001307 FalseStates.get());
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001308
1309 } else if (PInfo.isBinTest()) {
1310 CurrStates->setSource(PInfo.testSourceNode());
1311 FalseStates->setSource(PInfo.testSourceNode());
Chris Wailes2dc8c422013-10-25 15:33:28 +00001312 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get());
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001313
1314 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001315 return false;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001316 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001317
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001318 } else if (const BinaryOperator *BinOp =
1319 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1320
1321 PInfo = Visitor.getInfo(BinOp->getLHS());
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001322 if (!PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001323 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1324 PInfo = Visitor.getInfo(BinOp->getRHS());
1325
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001326 if (!PInfo.isVarTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001327 return false;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001328
1329 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001330 return false;
1331 }
1332 }
1333
1334 CurrStates->setSource(BinOp);
1335 FalseStates->setSource(BinOp);
1336
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001337 const VarTestResult &Test = PInfo.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001338 ConsumedState VarState = CurrStates->getState(Test.Var);
1339
1340 if (BinOp->getOpcode() == BO_LAnd) {
1341 if (VarState == CS_Unknown)
1342 CurrStates->setState(Test.Var, Test.TestsFor);
1343 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1344 CurrStates->markUnreachable();
1345
1346 } else if (BinOp->getOpcode() == BO_LOr) {
1347 if (VarState == CS_Unknown)
1348 FalseStates->setState(Test.Var,
1349 invertConsumedUnconsumed(Test.TestsFor));
1350 else if (VarState == Test.TestsFor)
1351 FalseStates->markUnreachable();
1352 }
1353
1354 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001355 return false;
1356 }
1357
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001358 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1359
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001360 if (*SI)
1361 BlockInfo.addInfo(*SI, CurrStates);
1362 else
1363 delete CurrStates;
1364
1365 if (*++SI)
Ahmed Charles9a16beb2014-03-07 19:33:25 +00001366 BlockInfo.addInfo(*SI, FalseStates.release());
1367
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001368 CurrStates = NULL;
1369 return true;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001370}
1371
1372void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1373 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001374 if (!D)
1375 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001376
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001377 CFG *CFGraph = AC.getCFG();
1378 if (!CFGraph)
1379 return;
DeLesley Hutchins65013202013-10-17 18:19:31 +00001380
David Blaikie16f76d22013-09-06 01:28:43 +00001381 determineExpectedReturnState(AC, D);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001382
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001383 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001384 // AC.getCFG()->viewCFG(LangOptions());
1385
1386 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001387
1388 CurrStates = new ConsumedStateMap();
DeLesley Hutchinsb570c132013-08-29 22:36:05 +00001389 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1390
1391 // Add all trackable parameters to the state map.
Aaron Ballmanf6bf62e2014-03-07 15:12:56 +00001392 for (auto PI : D->params()) {
1393 Visitor.VisitParmVarDecl(PI);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +00001394 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001395
1396 // Visit all of the function's basic blocks.
1397 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1398 E = SortedGraph->end(); I != E; ++I) {
1399
1400 const CFGBlock *CurrBlock = *I;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001401
1402 if (CurrStates == NULL)
1403 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001404
1405 if (!CurrStates) {
1406 continue;
1407
1408 } else if (!CurrStates->isReachable()) {
1409 delete CurrStates;
1410 CurrStates = NULL;
1411 continue;
1412 }
1413
1414 Visitor.reset(CurrStates);
1415
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001416 // Visit all of the basic block's statements.
1417 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1418 BE = CurrBlock->end(); BI != BE; ++BI) {
1419
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001420 switch (BI->getKind()) {
1421 case CFGElement::Statement:
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001422 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001423 break;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001424
1425 case CFGElement::TemporaryDtor: {
1426 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1427 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001428
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001429 Visitor.checkCallability(PropagationInfo(BTE),
1430 DTor.getDestructorDecl(AC.getASTContext()),
1431 BTE->getExprLoc());
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001432 break;
1433 }
1434
1435 case CFGElement::AutomaticObjectDtor: {
1436 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001437 SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001438 const VarDecl *Var = DTor.getVarDecl();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001439
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001440 Visitor.checkCallability(PropagationInfo(Var),
1441 DTor.getDestructorDecl(AC.getASTContext()),
1442 Loc);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001443 break;
1444 }
1445
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001446 default:
1447 break;
1448 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001449 }
1450
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001451 CurrStates->clearTemporaries();
1452
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001453 // TODO: Handle other forms of branching with precision, including while-
1454 // and for-loops. (Deferred)
1455 if (!splitState(CurrBlock, Visitor)) {
1456 CurrStates->setSource(NULL);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001457
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001458 if (CurrBlock->succ_size() > 1 ||
1459 (CurrBlock->succ_size() == 1 &&
1460 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001461
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001462 bool OwnershipTaken = false;
1463
1464 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1465 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1466
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001467 if (*SI == NULL) continue;
1468
1469 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1470 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1471 CurrStates,
1472 WarningsHandler);
1473
1474 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1475 BlockInfo.discardInfo(*SI);
1476 } else {
1477 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1478 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001479 }
1480
1481 if (!OwnershipTaken)
1482 delete CurrStates;
1483
1484 CurrStates = NULL;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001485 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001486 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001487
1488 if (CurrBlock == &AC.getCFG()->getExit() &&
1489 D->getCallResultType()->isVoidType())
1490 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1491 WarningsHandler);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001492 } // End of block iterator.
1493
1494 // Delete the last existing state map.
1495 delete CurrStates;
1496
1497 WarningsHandler.emitDiagnostics();
1498}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001499}} // end namespace clang::consumed