blob: 5551a21e59fcfdf1c0e4b6ce0d5914b4fa56f1aa [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"
30#include "llvm/ADT/SmallVector.h"
DeLesley Hutchins5533ec52013-08-29 17:26:57 +000031#include "llvm/Support/Compiler.h"
DeLesley Hutchins48a31762013-08-12 21:20:55 +000032#include "llvm/Support/raw_ostream.h"
Ahmed Charlesdfca6f92014-03-09 11:36:40 +000033#include <memory>
DeLesley Hutchins48a31762013-08-12 21:20:55 +000034
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) {
Aaron Ballman535bbcc2014-03-14 17:01:24 +0000854 for (const auto *DI : DeclS->decls())
855 if (isa<VarDecl>(DI))
856 VisitVarDecl(cast<VarDecl>(DI));
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000857
858 if (DeclS->isSingleDecl())
859 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
860 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
861}
862
863void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
864 const MaterializeTemporaryExpr *Temp) {
865
Chris Wailes44930882013-10-24 14:28:17 +0000866 forwardInfo(Temp->GetTemporaryExpr(), Temp);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000867}
868
869void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
870 forwardInfo(MExpr->getBase(), MExpr);
871}
872
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000873
874void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikie16f76d22013-09-06 01:28:43 +0000875 QualType ParamType = Param->getType();
876 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000877
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000878 if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
879 ParamState = mapParamTypestateAttrState(PTA);
880 else if (isConsumableType(ParamType))
881 ParamState = mapConsumableAttrState(ParamType);
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000882 else if (isRValueRef(ParamType) &&
883 isConsumableType(ParamType->getPointeeType()))
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +0000884 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
885 else if (ParamType->isReferenceType() &&
DeLesley Hutchins80a38422014-01-16 23:07:16 +0000886 isConsumableType(ParamType->getPointeeType()))
David Blaikie16f76d22013-09-06 01:28:43 +0000887 ParamState = consumed::CS_Unknown;
DeLesley Hutchins69391772013-10-17 23:23:53 +0000888
889 if (ParamState != CS_None)
David Blaikie16f76d22013-09-06 01:28:43 +0000890 StateMap->setState(Param, ParamState);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000891}
892
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000893void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000894 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
895
896 if (ExpectedState != CS_None) {
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000897 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
898
899 if (Entry != PropagationMap.end()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000900 ConsumedState RetState = Entry->second.getAsState(StateMap);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000901
902 if (RetState != ExpectedState)
903 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
904 Ret->getReturnLoc(), stateToString(ExpectedState),
905 stateToString(RetState));
906 }
907 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +0000908
909 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
910 Analyzer.WarningsHandler);
DeLesley Hutchinsfc368252013-09-03 20:11:38 +0000911}
912
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000913void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000914 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
915 if (Entry == PropagationMap.end()) return;
916
917 switch (UOp->getOpcode()) {
918 case UO_AddrOf:
919 PropagationMap.insert(PairType(UOp, Entry->second));
920 break;
921
922 case UO_LNot:
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000923 if (Entry->second.isTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000924 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
925 break;
926
927 default:
928 break;
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000929 }
930}
931
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000932// TODO: See if I need to check for reference types here.
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000933void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchins5a715c42013-08-30 22:56:34 +0000934 if (isConsumableType(Var->getType())) {
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000935 if (Var->hasInit()) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000936 MapType::iterator VIT = PropagationMap.find(
937 Var->getInit()->IgnoreImplicit());
DeLesley Hutchins81218662013-10-18 23:11:49 +0000938 if (VIT != PropagationMap.end()) {
939 PropagationInfo PInfo = VIT->second;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +0000940 ConsumedState St = PInfo.getAsState(StateMap);
941
DeLesley Hutchins81218662013-10-18 23:11:49 +0000942 if (St != consumed::CS_None) {
943 StateMap->setState(Var, St);
944 return;
945 }
946 }
DeLesley Hutchinsb570c132013-08-29 22:36:05 +0000947 }
DeLesley Hutchins81218662013-10-18 23:11:49 +0000948 // Otherwise
949 StateMap->setState(Var, consumed::CS_Unknown);
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000950 }
951}
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000952}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchins48a31762013-08-12 21:20:55 +0000953
954namespace clang {
955namespace consumed {
956
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000957void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
958 ConsumedStateMap *ThenStates,
959 ConsumedStateMap *ElseStates) {
960
961 ConsumedState VarState = ThenStates->getState(Test.Var);
962
963 if (VarState == CS_Unknown) {
964 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000965 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000966
967 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
968 ThenStates->markUnreachable();
969
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000970 } else if (VarState == Test.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000971 ElseStates->markUnreachable();
972 }
973}
974
975void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
976 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
977
978 const VarTestResult &LTest = PInfo.getLTest(),
979 &RTest = PInfo.getRTest();
980
981 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
982 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
983
984 if (LTest.Var) {
985 if (PInfo.testEffectiveOp() == EO_And) {
986 if (LState == CS_Unknown) {
987 ThenStates->setState(LTest.Var, LTest.TestsFor);
988
989 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
990 ThenStates->markUnreachable();
991
992 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins210791a2013-10-04 21:28:06 +0000993 if (RState == RTest.TestsFor)
994 ElseStates->markUnreachable();
995 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000996 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +0000997 }
998
999 } else {
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001000 if (LState == CS_Unknown) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001001 ElseStates->setState(LTest.Var,
1002 invertConsumedUnconsumed(LTest.TestsFor));
1003
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001004 } else if (LState == LTest.TestsFor) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001005 ElseStates->markUnreachable();
1006
1007 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
1008 isKnownState(RState)) {
1009
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001010 if (RState == RTest.TestsFor)
1011 ElseStates->markUnreachable();
1012 else
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001013 ThenStates->markUnreachable();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001014 }
1015 }
1016 }
1017
1018 if (RTest.Var) {
1019 if (PInfo.testEffectiveOp() == EO_And) {
1020 if (RState == CS_Unknown)
1021 ThenStates->setState(RTest.Var, RTest.TestsFor);
1022 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1023 ThenStates->markUnreachable();
1024
DeLesley Hutchins210791a2013-10-04 21:28:06 +00001025 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001026 if (RState == CS_Unknown)
1027 ElseStates->setState(RTest.Var,
1028 invertConsumedUnconsumed(RTest.TestsFor));
1029 else if (RState == RTest.TestsFor)
1030 ElseStates->markUnreachable();
1031 }
1032 }
1033}
1034
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001035bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1036 const CFGBlock *TargetBlock) {
1037
1038 assert(CurrBlock && "Block pointer must not be NULL");
1039 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1040
1041 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1042 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1043 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1044 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1045 return false;
1046 }
1047 return true;
1048}
1049
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001050void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1051 ConsumedStateMap *StateMap,
1052 bool &AlreadyOwned) {
1053
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001054 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001055
1056 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1057
1058 if (Entry) {
1059 Entry->intersect(StateMap);
1060
1061 } else if (AlreadyOwned) {
1062 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
1063
1064 } else {
1065 StateMapsArray[Block->getBlockID()] = StateMap;
1066 AlreadyOwned = true;
1067 }
1068}
1069
1070void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1071 ConsumedStateMap *StateMap) {
1072
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001073 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001074
1075 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1076
1077 if (Entry) {
1078 Entry->intersect(StateMap);
1079 delete StateMap;
1080
1081 } else {
1082 StateMapsArray[Block->getBlockID()] = StateMap;
1083 }
1084}
1085
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001086ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1087 assert(Block && "Block pointer must not be NULL");
1088 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1089
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001090 return StateMapsArray[Block->getBlockID()];
1091}
1092
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001093void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1094 unsigned int BlockID = Block->getBlockID();
1095 delete StateMapsArray[BlockID];
1096 StateMapsArray[BlockID] = NULL;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001097}
1098
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001099ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1100 assert(Block && "Block pointer must not be NULL");
1101
1102 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1103 if (isBackEdgeTarget(Block)) {
1104 return new ConsumedStateMap(*StateMap);
1105 } else {
1106 StateMapsArray[Block->getBlockID()] = NULL;
1107 return StateMap;
1108 }
1109}
1110
1111bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1112 assert(From && "From block must not be NULL");
1113 assert(To && "From block must not be NULL");
1114
1115 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1116}
1117
1118bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1119 assert(Block != NULL && "Block pointer must not be NULL");
1120
1121 // Anything with less than two predecessors can't be the target of a back
1122 // edge.
1123 if (Block->pred_size() < 2)
1124 return false;
1125
1126 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1127 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1128 PE = Block->pred_end(); PI != PE; ++PI) {
1129 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1130 return true;
1131 }
1132 return false;
1133}
1134
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001135void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1136 ConsumedWarningsHandlerBase &WarningsHandler) const {
1137
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001138 for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
1139 DMI != DME; ++DMI) {
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001140
1141 if (isa<ParmVarDecl>(DMI->first)) {
1142 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001143 const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001144
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001145 if (!RTA)
1146 continue;
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001147
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001148 ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
1149 if (DMI->second != ExpectedState)
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001150 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1151 Param->getNameAsString(), stateToString(ExpectedState),
1152 stateToString(DMI->second));
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001153 }
1154 }
1155}
1156
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001157void ConsumedStateMap::clearTemporaries() {
1158 TmpMap.clear();
1159}
1160
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001161ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001162 VarMapType::const_iterator Entry = VarMap.find(Var);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001163
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001164 if (Entry != VarMap.end())
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001165 return Entry->second;
1166
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001167 return CS_None;
1168}
1169
1170ConsumedState
1171ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
1172 TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
1173
1174 if (Entry != TmpMap.end())
1175 return Entry->second;
1176
1177 return CS_None;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001178}
1179
1180void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1181 ConsumedState LocalState;
1182
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001183 if (this->From && this->From == Other->From && !Other->Reachable) {
1184 this->markUnreachable();
1185 return;
1186 }
1187
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001188 for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
1189 DME = Other->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001190
1191 LocalState = this->getState(DMI->first);
1192
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001193 if (LocalState == CS_None)
1194 continue;
1195
1196 if (LocalState != DMI->second)
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001197 VarMap[DMI->first] = CS_Unknown;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001198 }
1199}
1200
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001201void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1202 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1203 ConsumedWarningsHandlerBase &WarningsHandler) {
1204
1205 ConsumedState LocalState;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001206 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001207
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001208 for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
1209 DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001210
1211 LocalState = this->getState(DMI->first);
1212
1213 if (LocalState == CS_None)
1214 continue;
1215
1216 if (LocalState != DMI->second) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001217 VarMap[DMI->first] = CS_Unknown;
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001218 WarningsHandler.warnLoopStateMismatch(
1219 BlameLoc, DMI->first->getNameAsString());
1220 }
1221 }
1222}
1223
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001224void ConsumedStateMap::markUnreachable() {
1225 this->Reachable = false;
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001226 VarMap.clear();
1227 TmpMap.clear();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001228}
1229
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001230void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001231 VarMap[Var] = State;
1232}
1233
1234void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
1235 ConsumedState State) {
1236 TmpMap[Tmp] = State;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001237}
1238
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001239void ConsumedStateMap::remove(const VarDecl *Var) {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001240 VarMap.erase(Var);
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001241}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001242
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001243bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001244 for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
1245 DME = Other->VarMap.end(); DMI != DME; ++DMI) {
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001246
1247 if (this->getState(DMI->first) != DMI->second)
1248 return true;
1249 }
1250
1251 return false;
1252}
1253
David Blaikie16f76d22013-09-06 01:28:43 +00001254void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1255 const FunctionDecl *D) {
1256 QualType ReturnType;
1257 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1258 ASTContext &CurrContext = AC.getASTContext();
1259 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1260 } else
1261 ReturnType = D->getCallResultType();
1262
Aaron Ballmanb06f2ef2013-12-19 02:58:51 +00001263 if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
David Blaikie16f76d22013-09-06 01:28:43 +00001264 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1265 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1266 // FIXME: This should be removed when template instantiation propagates
1267 // attributes at template specialization definition, not
1268 // declaration. When it is removed the test needs to be enabled
1269 // in SemaDeclAttr.cpp.
1270 WarningsHandler.warnReturnTypestateForUnconsumableType(
1271 RTSAttr->getLocation(), ReturnType.getAsString());
1272 ExpectedReturnState = CS_None;
1273 } else
1274 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
DeLesley Hutchinsf28bbec2014-01-14 00:36:53 +00001275 } else if (isConsumableType(ReturnType)) {
1276 if (isAutoCastType(ReturnType)) // We can auto-cast the state to the
1277 ExpectedReturnState = CS_None; // expected state.
1278 else
1279 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1280 }
David Blaikie16f76d22013-09-06 01:28:43 +00001281 else
1282 ExpectedReturnState = CS_None;
1283}
1284
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001285bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1286 const ConsumedStmtVisitor &Visitor) {
Ahmed Charlesb8984322014-03-07 20:03:18 +00001287
1288 std::unique_ptr<ConsumedStateMap> FalseStates(
1289 new ConsumedStateMap(*CurrStates));
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001290 PropagationInfo PInfo;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001291
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001292 if (const IfStmt *IfNode =
1293 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001294
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001295 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001296
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001297 PInfo = Visitor.getInfo(Cond);
1298 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1299 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1300
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001301 if (PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001302 CurrStates->setSource(Cond);
1303 FalseStates->setSource(Cond);
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001304 splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates,
Chris Wailes2dc8c422013-10-25 15:33:28 +00001305 FalseStates.get());
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001306
1307 } else if (PInfo.isBinTest()) {
1308 CurrStates->setSource(PInfo.testSourceNode());
1309 FalseStates->setSource(PInfo.testSourceNode());
Chris Wailes2dc8c422013-10-25 15:33:28 +00001310 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get());
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001311
1312 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001313 return false;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001314 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001315
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001316 } else if (const BinaryOperator *BinOp =
1317 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1318
1319 PInfo = Visitor.getInfo(BinOp->getLHS());
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001320 if (!PInfo.isVarTest()) {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001321 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1322 PInfo = Visitor.getInfo(BinOp->getRHS());
1323
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001324 if (!PInfo.isVarTest())
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001325 return false;
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001326
1327 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001328 return false;
1329 }
1330 }
1331
1332 CurrStates->setSource(BinOp);
1333 FalseStates->setSource(BinOp);
1334
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001335 const VarTestResult &Test = PInfo.getVarTest();
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001336 ConsumedState VarState = CurrStates->getState(Test.Var);
1337
1338 if (BinOp->getOpcode() == BO_LAnd) {
1339 if (VarState == CS_Unknown)
1340 CurrStates->setState(Test.Var, Test.TestsFor);
1341 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1342 CurrStates->markUnreachable();
1343
1344 } else if (BinOp->getOpcode() == BO_LOr) {
1345 if (VarState == CS_Unknown)
1346 FalseStates->setState(Test.Var,
1347 invertConsumedUnconsumed(Test.TestsFor));
1348 else if (VarState == Test.TestsFor)
1349 FalseStates->markUnreachable();
1350 }
1351
1352 } else {
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001353 return false;
1354 }
1355
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001356 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1357
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001358 if (*SI)
1359 BlockInfo.addInfo(*SI, CurrStates);
1360 else
1361 delete CurrStates;
1362
1363 if (*++SI)
Ahmed Charles9a16beb2014-03-07 19:33:25 +00001364 BlockInfo.addInfo(*SI, FalseStates.release());
1365
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001366 CurrStates = NULL;
1367 return true;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001368}
1369
1370void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1371 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001372 if (!D)
1373 return;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001374
DeLesley Hutchins85c07d92013-09-10 23:10:10 +00001375 CFG *CFGraph = AC.getCFG();
1376 if (!CFGraph)
1377 return;
DeLesley Hutchins65013202013-10-17 18:19:31 +00001378
David Blaikie16f76d22013-09-06 01:28:43 +00001379 determineExpectedReturnState(AC, D);
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001380
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001381 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001382 // AC.getCFG()->viewCFG(LangOptions());
1383
1384 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001385
1386 CurrStates = new ConsumedStateMap();
DeLesley Hutchinsb570c132013-08-29 22:36:05 +00001387 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1388
1389 // Add all trackable parameters to the state map.
Aaron Ballmanf6bf62e2014-03-07 15:12:56 +00001390 for (auto PI : D->params()) {
1391 Visitor.VisitParmVarDecl(PI);
DeLesley Hutchinsb570c132013-08-29 22:36:05 +00001392 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001393
1394 // Visit all of the function's basic blocks.
1395 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1396 E = SortedGraph->end(); I != E; ++I) {
1397
1398 const CFGBlock *CurrBlock = *I;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001399
1400 if (CurrStates == NULL)
1401 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001402
1403 if (!CurrStates) {
1404 continue;
1405
1406 } else if (!CurrStates->isReachable()) {
1407 delete CurrStates;
1408 CurrStates = NULL;
1409 continue;
1410 }
1411
1412 Visitor.reset(CurrStates);
1413
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001414 // Visit all of the basic block's statements.
1415 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1416 BE = CurrBlock->end(); BI != BE; ++BI) {
1417
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001418 switch (BI->getKind()) {
1419 case CFGElement::Statement:
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001420 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001421 break;
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001422
1423 case CFGElement::TemporaryDtor: {
1424 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1425 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001426
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001427 Visitor.checkCallability(PropagationInfo(BTE),
1428 DTor.getDestructorDecl(AC.getASTContext()),
1429 BTE->getExprLoc());
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001430 break;
1431 }
1432
1433 case CFGElement::AutomaticObjectDtor: {
1434 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001435 SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001436 const VarDecl *Var = DTor.getVarDecl();
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001437
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001438 Visitor.checkCallability(PropagationInfo(Var),
1439 DTor.getDestructorDecl(AC.getASTContext()),
1440 Loc);
DeLesley Hutchinsfbdee4e2013-10-11 21:55:33 +00001441 break;
1442 }
1443
DeLesley Hutchinsc2ecf0d2013-08-22 20:44:47 +00001444 default:
1445 break;
1446 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001447 }
1448
DeLesley Hutchins68cc3f12013-11-16 00:22:43 +00001449 CurrStates->clearTemporaries();
1450
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001451 // TODO: Handle other forms of branching with precision, including while-
1452 // and for-loops. (Deferred)
1453 if (!splitState(CurrBlock, Visitor)) {
1454 CurrStates->setSource(NULL);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001455
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001456 if (CurrBlock->succ_size() > 1 ||
1457 (CurrBlock->succ_size() == 1 &&
1458 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001459
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001460 bool OwnershipTaken = false;
1461
1462 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1463 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1464
DeLesley Hutchins3277a612013-10-09 18:30:24 +00001465 if (*SI == NULL) continue;
1466
1467 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1468 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1469 CurrStates,
1470 WarningsHandler);
1471
1472 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1473 BlockInfo.discardInfo(*SI);
1474 } else {
1475 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1476 }
DeLesley Hutchins5533ec52013-08-29 17:26:57 +00001477 }
1478
1479 if (!OwnershipTaken)
1480 delete CurrStates;
1481
1482 CurrStates = NULL;
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001483 }
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001484 }
DeLesley Hutchins36ea1dd2013-10-17 22:53:04 +00001485
1486 if (CurrBlock == &AC.getCFG()->getExit() &&
1487 D->getCallResultType()->isVoidType())
1488 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1489 WarningsHandler);
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001490 } // End of block iterator.
1491
1492 // Delete the last existing state map.
1493 delete CurrStates;
1494
1495 WarningsHandler.emitDiagnostics();
1496}
DeLesley Hutchins48a31762013-08-12 21:20:55 +00001497}} // end namespace clang::consumed