blob: 13306f92a5cff0803589736b0fd145cf53893de7 [file] [log] [blame]
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001//===- Consumed.cpp --------------------------------------------*- C++ --*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// A intra-procedural analysis for checking consumed properties. This is based,
11// in part, on research on linear types.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/AST/RecursiveASTVisitor.h"
20#include "clang/AST/StmtVisitor.h"
21#include "clang/AST/StmtCXX.h"
22#include "clang/AST/Type.h"
23#include "clang/Analysis/Analyses/PostOrderCFGView.h"
24#include "clang/Analysis/AnalysisContext.h"
25#include "clang/Analysis/CFG.h"
26#include "clang/Analysis/Analyses/Consumed.h"
27#include "clang/Basic/OperatorKinds.h"
28#include "clang/Basic/SourceLocation.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000029#include "llvm/ADT/DenseMap.h"
Chris Wailesa0cbcab2013-10-25 15:33:28 +000030#include "llvm/ADT/OwningPtr.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000031#include "llvm/ADT/SmallVector.h"
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000032#include "llvm/Support/Compiler.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000033#include "llvm/Support/raw_ostream.h"
34
DeLesley Hutchins73858402013-10-09 18:30:24 +000035// TODO: Use information from tests in while-loop conditional.
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +000036// TODO: Add notes about the actual and expected state for
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000037// TODO: Correctly identify unreachable blocks when chaining boolean operators.
DeLesley Hutchins66540852013-10-04 21:28:06 +000038// TODO: Adjust the parser and AttributesList class to support lists of
39// identifiers.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000040// TODO: Warn about unreachable code.
41// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000042// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
43// if (valid) ...; (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000044// TODO: Take notes on state transitions to provide better warning messages.
45// (Deferred)
46// TODO: Test nested conditionals: A) Checking the same value multiple times,
47// and 2) Checking different values. (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000048
49using namespace clang;
50using namespace consumed;
51
52// Key method definition
53ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
54
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000055static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
56 // Find the source location of the first statement in the block, if the block
57 // is not empty.
58 for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
59 BI != BE; ++BI) {
60 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
61 return CS->getStmt()->getLocStart();
62 }
63
64 // Block is empty.
65 // If we have one successor, return the first statement in that block
66 if (Block->succ_size() == 1 && *Block->succ_begin())
67 return getFirstStmtLoc(*Block->succ_begin());
68
69 return SourceLocation();
70}
71
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000072static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000073 // Find the source location of the last statement in the block, if the block
74 // is not empty.
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000075 if (const Stmt *StmtNode = Block->getTerminator()) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000076 return StmtNode->getLocStart();
77 } else {
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000078 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
79 BE = Block->rend(); BI != BE; ++BI) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000080 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
81 return CS->getStmt()->getLocStart();
82 }
83 }
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000084
85 // If we have one successor, return the first statement in that block
86 SourceLocation Loc;
87 if (Block->succ_size() == 1 && *Block->succ_begin())
88 Loc = getFirstStmtLoc(*Block->succ_begin());
89 if (Loc.isValid())
90 return Loc;
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +000091
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000092 // If we have one predecessor, return the last statement in that block
93 if (Block->pred_size() == 1 && *Block->pred_begin())
94 return getLastStmtLoc(*Block->pred_begin());
95
96 return Loc;
DeLesley Hutchins73858402013-10-09 18:30:24 +000097}
98
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000099static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
100 switch (State) {
101 case CS_Unconsumed:
102 return CS_Consumed;
103 case CS_Consumed:
104 return CS_Unconsumed;
105 case CS_None:
106 return CS_None;
107 case CS_Unknown:
108 return CS_Unknown;
109 }
110 llvm_unreachable("invalid enum");
111}
112
DeLesley Hutchins66540852013-10-04 21:28:06 +0000113static bool isCallableInState(const CallableWhenAttr *CWAttr,
114 ConsumedState State) {
115
116 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
117 E = CWAttr->callableState_end();
118
119 for (; I != E; ++I) {
120
121 ConsumedState MappedAttrState = CS_None;
122
123 switch (*I) {
124 case CallableWhenAttr::Unknown:
125 MappedAttrState = CS_Unknown;
126 break;
127
128 case CallableWhenAttr::Unconsumed:
129 MappedAttrState = CS_Unconsumed;
130 break;
131
132 case CallableWhenAttr::Consumed:
133 MappedAttrState = CS_Consumed;
134 break;
135 }
136
137 if (MappedAttrState == State)
138 return true;
139 }
140
141 return false;
142}
143
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000144static bool isConsumableType(const QualType &QT) {
Chris Wailes1aa89692013-10-31 15:38:12 +0000145 if (QT->isPointerType() || QT->isReferenceType())
146 return false;
147
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000148 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
149 return RD->hasAttr<ConsumableAttr>();
Chris Wailes1aa89692013-10-31 15:38:12 +0000150
151 return false;
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000152}
153
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000154static bool isKnownState(ConsumedState State) {
155 switch (State) {
156 case CS_Unconsumed:
157 case CS_Consumed:
158 return true;
159 case CS_None:
160 case CS_Unknown:
161 return false;
162 }
Aaron Ballman6b2ec032013-08-29 20:36:09 +0000163 llvm_unreachable("invalid enum");
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000164}
165
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000166static bool isRValueRefish(QualType ParamType) {
167 return ParamType->isRValueReferenceType() ||
168 (ParamType->isLValueReferenceType() &&
Chris Wailes1aa89692013-10-31 15:38:12 +0000169 !cast<LValueReferenceType>(
170 ParamType.getCanonicalType())->isSpelledAsLValue());
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000171}
172
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000173static bool isTestingFunction(const FunctionDecl *FunDecl) {
Chris Wailes0e429f12013-10-29 20:28:41 +0000174 return FunDecl->hasAttr<TestTypestateAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000175}
176
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000177static bool isValueType(QualType ParamType) {
178 return !(ParamType->isPointerType() || ParamType->isReferenceType());
179}
180
David Blaikiea33ab602013-09-06 01:28:43 +0000181static ConsumedState mapConsumableAttrState(const QualType QT) {
182 assert(isConsumableType(QT));
183
184 const ConsumableAttr *CAttr =
185 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
186
187 switch (CAttr->getDefaultState()) {
188 case ConsumableAttr::Unknown:
189 return CS_Unknown;
190 case ConsumableAttr::Unconsumed:
191 return CS_Unconsumed;
192 case ConsumableAttr::Consumed:
193 return CS_Consumed;
194 }
195 llvm_unreachable("invalid enum");
196}
197
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000198static ConsumedState
199mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
200 switch (PTAttr->getParamState()) {
201 case ParamTypestateAttr::Unknown:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000202 return CS_Unknown;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000203 case ParamTypestateAttr::Unconsumed:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000204 return CS_Unconsumed;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000205 case ParamTypestateAttr::Consumed:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000206 return CS_Consumed;
207 }
208 llvm_unreachable("invalid_enum");
209}
210
Eric Christophere988dc42013-09-03 20:43:00 +0000211static ConsumedState
212mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000213 switch (RTSAttr->getState()) {
214 case ReturnTypestateAttr::Unknown:
215 return CS_Unknown;
216 case ReturnTypestateAttr::Unconsumed:
217 return CS_Unconsumed;
218 case ReturnTypestateAttr::Consumed:
219 return CS_Consumed;
220 }
Eric Christophere988dc42013-09-03 20:43:00 +0000221 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000222}
223
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000224static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
225 switch (STAttr->getNewState()) {
226 case SetTypestateAttr::Unknown:
227 return CS_Unknown;
228 case SetTypestateAttr::Unconsumed:
229 return CS_Unconsumed;
230 case SetTypestateAttr::Consumed:
231 return CS_Consumed;
232 }
233 llvm_unreachable("invalid_enum");
234}
235
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000236static StringRef stateToString(ConsumedState State) {
237 switch (State) {
238 case consumed::CS_None:
239 return "none";
240
241 case consumed::CS_Unknown:
242 return "unknown";
243
244 case consumed::CS_Unconsumed:
245 return "unconsumed";
246
247 case consumed::CS_Consumed:
248 return "consumed";
249 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000250 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000251}
252
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000253static ConsumedState testsFor(const FunctionDecl *FunDecl) {
254 assert(isTestingFunction(FunDecl));
Chris Wailes0e429f12013-10-29 20:28:41 +0000255 switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
256 case TestTypestateAttr::Unconsumed:
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000257 return CS_Unconsumed;
Chris Wailes0e429f12013-10-29 20:28:41 +0000258 case TestTypestateAttr::Consumed:
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000259 return CS_Consumed;
260 }
261 llvm_unreachable("invalid enum");
262}
263
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000264namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000265struct VarTestResult {
266 const VarDecl *Var;
267 ConsumedState TestsFor;
268};
269} // end anonymous::VarTestResult
270
271namespace clang {
272namespace consumed {
273
274enum EffectiveOp {
275 EO_And,
276 EO_Or
277};
278
279class PropagationInfo {
280 enum {
281 IT_None,
282 IT_State,
283 IT_Test,
284 IT_BinTest,
285 IT_Var
286 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000287
288 struct BinTestTy {
289 const BinaryOperator *Source;
290 EffectiveOp EOp;
291 VarTestResult LTest;
292 VarTestResult RTest;
293 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000294
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000295 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000296 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000297 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000298 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000299 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000300 };
301
DeLesley Hutchins66540852013-10-04 21:28:06 +0000302 QualType TempType;
303
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000304public:
305 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000306
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000307 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
308 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
309 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000310
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000311 Test.Var = Var;
312 Test.TestsFor = TestsFor;
313 }
314
315 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
316 const VarTestResult &LTest, const VarTestResult &RTest)
317 : InfoType(IT_BinTest) {
318
319 BinTest.Source = Source;
320 BinTest.EOp = EOp;
321 BinTest.LTest = LTest;
322 BinTest.RTest = RTest;
323 }
324
325 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
326 const VarDecl *LVar, ConsumedState LTestsFor,
327 const VarDecl *RVar, ConsumedState RTestsFor)
328 : InfoType(IT_BinTest) {
329
330 BinTest.Source = Source;
331 BinTest.EOp = EOp;
332 BinTest.LTest.Var = LVar;
333 BinTest.LTest.TestsFor = LTestsFor;
334 BinTest.RTest.Var = RVar;
335 BinTest.RTest.TestsFor = RTestsFor;
336 }
337
DeLesley Hutchins66540852013-10-04 21:28:06 +0000338 PropagationInfo(ConsumedState State, QualType TempType)
339 : InfoType(IT_State), State(State), TempType(TempType) {}
340
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000341 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
342
343 const ConsumedState & getState() const {
344 assert(InfoType == IT_State);
345 return State;
346 }
347
DeLesley Hutchins66540852013-10-04 21:28:06 +0000348 const QualType & getTempType() const {
349 assert(InfoType == IT_State);
350 return TempType;
351 }
352
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000353 const VarTestResult & getTest() const {
354 assert(InfoType == IT_Test);
355 return Test;
356 }
357
358 const VarTestResult & getLTest() const {
359 assert(InfoType == IT_BinTest);
360 return BinTest.LTest;
361 }
362
363 const VarTestResult & getRTest() const {
364 assert(InfoType == IT_BinTest);
365 return BinTest.RTest;
366 }
367
368 const VarDecl * getVar() const {
369 assert(InfoType == IT_Var);
370 return Var;
371 }
372
373 EffectiveOp testEffectiveOp() const {
374 assert(InfoType == IT_BinTest);
375 return BinTest.EOp;
376 }
377
378 const BinaryOperator * testSourceNode() const {
379 assert(InfoType == IT_BinTest);
380 return BinTest.Source;
381 }
382
383 bool isValid() const { return InfoType != IT_None; }
384 bool isState() const { return InfoType == IT_State; }
385 bool isTest() const { return InfoType == IT_Test; }
386 bool isBinTest() const { return InfoType == IT_BinTest; }
387 bool isVar() const { return InfoType == IT_Var; }
388
389 PropagationInfo invertTest() const {
390 assert(InfoType == IT_Test || InfoType == IT_BinTest);
391
392 if (InfoType == IT_Test) {
393 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
394
395 } else if (InfoType == IT_BinTest) {
396 return PropagationInfo(BinTest.Source,
397 BinTest.EOp == EO_And ? EO_Or : EO_And,
398 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
399 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
400 } else {
401 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000402 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000403 }
404};
405
406class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000407
408 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
409 typedef std::pair<const Stmt *, PropagationInfo> PairType;
410 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000411 typedef MapType::const_iterator ConstInfoEntry;
412
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000413 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000414 ConsumedAnalyzer &Analyzer;
415 ConsumedStateMap *StateMap;
416 MapType PropagationMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000417 void forwardInfo(const Stmt *From, const Stmt *To);
418 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000419 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
420 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000421
DeLesley Hutchins13be0322013-10-18 23:11:49 +0000422 inline ConsumedState getPInfoState(const PropagationInfo& PInfo) {
423 if (PInfo.isVar())
424 return StateMap->getState(PInfo.getVar());
425 else if (PInfo.isState())
426 return PInfo.getState();
427 else
428 return CS_None;
429 }
430
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000431public:
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000432 void checkCallability(const PropagationInfo &PInfo,
433 const FunctionDecl *FunDecl,
434 SourceLocation BlameLoc);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000435
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000436 void Visit(const Stmt *StmtNode);
437
438 void VisitBinaryOperator(const BinaryOperator *BinOp);
439 void VisitCallExpr(const CallExpr *Call);
440 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000441 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000442 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
443 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
444 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
445 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
446 void VisitDeclStmt(const DeclStmt *DelcS);
447 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
448 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000449 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000450 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000451 void VisitUnaryOperator(const UnaryOperator *UOp);
452 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000453
DeLesley Hutchins42525982013-08-29 22:36:05 +0000454 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
455 ConsumedStateMap *StateMap)
456 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000457
458 PropagationInfo getInfo(const Stmt *StmtNode) const {
459 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
460
461 if (Entry != PropagationMap.end())
462 return Entry->second;
463 else
464 return PropagationInfo();
465 }
466
467 void reset(ConsumedStateMap *NewStateMap) {
468 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000469 }
470};
471
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000472void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000473 const FunctionDecl *FunDecl,
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000474 SourceLocation BlameLoc) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000475
DeLesley Hutchins66540852013-10-04 21:28:06 +0000476 if (!FunDecl->hasAttr<CallableWhenAttr>())
477 return;
478
479 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000480
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000481 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000482 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000483 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000484
DeLesley Hutchins66540852013-10-04 21:28:06 +0000485 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000486
DeLesley Hutchins66540852013-10-04 21:28:06 +0000487 if (isCallableInState(CWAttr, VarState))
488 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000489
DeLesley Hutchins66540852013-10-04 21:28:06 +0000490 Analyzer.WarningsHandler.warnUseInInvalidState(
491 FunDecl->getNameAsString(), Var->getNameAsString(),
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000492 stateToString(VarState), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000493
DeLesley Hutchins66540852013-10-04 21:28:06 +0000494 } else if (PInfo.isState()) {
495
496 assert(PInfo.getState() != CS_None && "Invalid state");
497
498 if (isCallableInState(CWAttr, PInfo.getState()))
499 return;
500
501 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000502 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000503 }
504}
505
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000506void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
507 InfoEntry Entry = PropagationMap.find(From);
508
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000509 if (Entry != PropagationMap.end())
510 PropagationMap.insert(PairType(To, Entry->second));
511}
512
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000513bool ConsumedStmtVisitor::isLikeMoveAssignment(
514 const CXXMethodDecl *MethodDecl) {
515
516 return MethodDecl->isMoveAssignmentOperator() ||
517 (MethodDecl->getOverloadedOperator() == OO_Equal &&
518 MethodDecl->getNumParams() == 1 &&
519 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
520}
521
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000522void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
523 const FunctionDecl *Fun,
524 QualType ReturnType) {
525 if (isConsumableType(ReturnType)) {
526
527 ConsumedState ReturnState;
528
529 if (Fun->hasAttr<ReturnTypestateAttr>())
530 ReturnState = mapReturnTypestateAttrState(
531 Fun->getAttr<ReturnTypestateAttr>());
532 else
David Blaikiea33ab602013-09-06 01:28:43 +0000533 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000534
535 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000536 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000537 }
538}
539
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000540void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
541
542 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
543
544 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
545 CE = StmtNode->child_end(); CI != CE; ++CI) {
546
547 PropagationMap.erase(*CI);
548 }
549}
550
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000551void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
552 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000553 case BO_LAnd:
554 case BO_LOr : {
555 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
556 REntry = PropagationMap.find(BinOp->getRHS());
557
558 VarTestResult LTest, RTest;
559
560 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
561 LTest = LEntry->second.getTest();
562
563 } else {
564 LTest.Var = NULL;
565 LTest.TestsFor = CS_None;
566 }
567
568 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
569 RTest = REntry->second.getTest();
570
571 } else {
572 RTest.Var = NULL;
573 RTest.TestsFor = CS_None;
574 }
575
576 if (!(LTest.Var == NULL && RTest.Var == NULL))
577 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
578 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
579
580 break;
581 }
582
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000583 case BO_PtrMemD:
584 case BO_PtrMemI:
585 forwardInfo(BinOp->getLHS(), BinOp);
586 break;
587
588 default:
589 break;
590 }
591}
592
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000593void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
594 if (const FunctionDecl *FunDecl =
595 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
596
597 // Special case for the std::move function.
598 // TODO: Make this more specific. (Deferred)
599 if (FunDecl->getNameAsString() == "move") {
Chris Wailesde2204b2013-10-24 14:28:17 +0000600 forwardInfo(Call->getArg(0), Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000601 return;
602 }
603
604 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
605
606 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000607 const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
608 QualType ParamType = Param->getType();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000609
610 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
611
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000612 if (Entry == PropagationMap.end() ||
613 !(Entry->second.isState() || Entry->second.isVar()))
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000614 continue;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000615
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000616 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000617
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000618 // Check that the parameter is in the correct state.
619
620 if (Param->hasAttr<ParamTypestateAttr>()) {
621 ConsumedState ParamState =
622 PInfo.isState() ? PInfo.getState() :
623 StateMap->getState(PInfo.getVar());
624
625 ConsumedState ExpectedState =
626 mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
627
628 if (ParamState != ExpectedState)
629 Analyzer.WarningsHandler.warnParamTypestateMismatch(
630 Call->getArg(Index - Offset)->getExprLoc(),
631 stateToString(ExpectedState), stateToString(ParamState));
632 }
633
634 if (!Entry->second.isVar())
635 continue;
636
637 // Adjust state on the caller side.
638
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000639 if (isRValueRefish(ParamType)) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000640 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000641
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000642 } else if (Param->hasAttr<ReturnTypestateAttr>()) {
643 StateMap->setState(PInfo.getVar(),
644 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
645
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000646 } else if (!isValueType(ParamType) &&
647 !ParamType->getPointeeType().isConstQualified()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000648
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000649 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000650 }
651 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000652
DeLesley Hutchins66540852013-10-04 21:28:06 +0000653 QualType RetType = FunDecl->getCallResultType();
654 if (RetType->isReferenceType())
655 RetType = RetType->getPointeeType();
656
657 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000658 }
659}
660
661void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000662 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000663}
664
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000665void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
666 const CXXBindTemporaryExpr *Temp) {
667
668 forwardInfo(Temp->getSubExpr(), Temp);
669}
670
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000671void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
672 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000673
674 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000675 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
676
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000677 if (!isConsumableType(ThisType))
678 return;
679
680 // FIXME: What should happen if someone annotates the move constructor?
681 if (Constructor->hasAttr<ReturnTypestateAttr>()) {
682 ReturnTypestateAttr *RTAttr = Constructor->getAttr<ReturnTypestateAttr>();
683 ConsumedState RetState = mapReturnTypestateAttrState(RTAttr);
684 PropagationMap.insert(PairType(Call, PropagationInfo(RetState, ThisType)));
685
686 } else if (Constructor->isDefaultConstructor()) {
687
688 PropagationMap.insert(PairType(Call,
689 PropagationInfo(consumed::CS_Consumed, ThisType)));
690
691 } else if (Constructor->isMoveConstructor()) {
692
Chris Wailesde2204b2013-10-24 14:28:17 +0000693 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000694
Chris Wailesde2204b2013-10-24 14:28:17 +0000695 if (Entry != PropagationMap.end()) {
696 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000697
Chris Wailesde2204b2013-10-24 14:28:17 +0000698 if (PInfo.isVar()) {
699 const VarDecl* Var = PInfo.getVar();
700
701 PropagationMap.insert(PairType(Call,
702 PropagationInfo(StateMap->getState(Var), ThisType)));
703
704 StateMap->setState(Var, consumed::CS_Consumed);
705
706 } else {
707 PropagationMap.insert(PairType(Call, PInfo));
708 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000709 }
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000710 } else if (Constructor->isCopyConstructor()) {
Chris Wailesde2204b2013-10-24 14:28:17 +0000711 forwardInfo(Call->getArg(0), Call);
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000712
713 } else {
714 ConsumedState RetState = mapConsumableAttrState(ThisType);
715 PropagationMap.insert(PairType(Call, PropagationInfo(RetState, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000716 }
717}
718
719void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
720 const CXXMemberCallExpr *Call) {
721
722 VisitCallExpr(Call);
723
724 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
725
726 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000727 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000728 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000729
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000730 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000731
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000732 if (PInfo.isVar()) {
733 if (isTestingFunction(MethodDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000734 PropagationMap.insert(PairType(Call,
735 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000736 else if (MethodDecl->hasAttr<SetTypestateAttr>())
737 StateMap->setState(PInfo.getVar(),
738 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000739 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000740 }
741}
742
743void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
744 const CXXOperatorCallExpr *Call) {
745
746 const FunctionDecl *FunDecl =
747 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
748
749 if (!FunDecl) return;
750
751 if (isa<CXXMethodDecl>(FunDecl) &&
752 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
753
754 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
755 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
756
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000757 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000758
759 if (LEntry != PropagationMap.end() &&
760 REntry != PropagationMap.end()) {
761
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000762 LPInfo = LEntry->second;
763 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000764
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000765 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000766 StateMap->setState(LPInfo.getVar(),
767 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000768
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000769 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000770
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000771 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000772
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000773 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000774 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000775
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000776 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000777
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000778 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000779 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000780 PropagationInfo(StateMap->getState(RPInfo.getVar()),
781 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000782
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000783 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000784
785 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000786 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000787 }
788
789 } else if (LEntry != PropagationMap.end() &&
790 REntry == PropagationMap.end()) {
791
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000792 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000793
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000794 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000795 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000796
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000797 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000798
DeLesley Hutchins66540852013-10-04 21:28:06 +0000799 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000800 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000801 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000802 }
803
804 } else if (LEntry == PropagationMap.end() &&
805 REntry != PropagationMap.end()) {
806
DeLesley Hutchins66540852013-10-04 21:28:06 +0000807 if (REntry->second.isVar())
808 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000809 }
810
811 } else {
812
813 VisitCallExpr(Call);
814
815 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
816
817 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000818 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000819
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000820 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000821
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000822 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000823 if (isTestingFunction(FunDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000824 PropagationMap.insert(PairType(Call,
825 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000826 else if (FunDecl->hasAttr<SetTypestateAttr>())
827 StateMap->setState(PInfo.getVar(),
828 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000829 }
830 }
831 }
832}
833
834void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
835 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
836 if (StateMap->getState(Var) != consumed::CS_None)
837 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
838}
839
840void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
841 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
842 DE = DeclS->decl_end(); DI != DE; ++DI) {
843
844 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
845 }
846
847 if (DeclS->isSingleDecl())
848 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
849 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
850}
851
852void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
853 const MaterializeTemporaryExpr *Temp) {
854
Chris Wailesde2204b2013-10-24 14:28:17 +0000855 forwardInfo(Temp->GetTemporaryExpr(), Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000856}
857
858void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
859 forwardInfo(MExpr->getBase(), MExpr);
860}
861
DeLesley Hutchins42525982013-08-29 22:36:05 +0000862
863void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000864 QualType ParamType = Param->getType();
865 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000866
867 if (Param->hasAttr<ParamTypestateAttr>()) {
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000868 const ParamTypestateAttr *PTAttr = Param->getAttr<ParamTypestateAttr>();
869 ParamState = mapParamTypestateAttrState(PTAttr);
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000870
Chris Wailes1aa89692013-10-31 15:38:12 +0000871 } else if (isConsumableType(ParamType)) {
David Blaikiea33ab602013-09-06 01:28:43 +0000872 ParamState = mapConsumableAttrState(ParamType);
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000873
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000874 } else if (isRValueRefish(ParamType) &&
875 isConsumableType(ParamType->getPointeeType())) {
876
877 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
878
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000879 } else if (ParamType->isReferenceType() &&
880 isConsumableType(ParamType->getPointeeType())) {
David Blaikiea33ab602013-09-06 01:28:43 +0000881 ParamState = consumed::CS_Unknown;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000882 }
883
884 if (ParamState != CS_None)
David Blaikiea33ab602013-09-06 01:28:43 +0000885 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000886}
887
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000888void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000889 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
890
891 if (ExpectedState != CS_None) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000892 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
893
894 if (Entry != PropagationMap.end()) {
895 assert(Entry->second.isState() || Entry->second.isVar());
896
897 ConsumedState RetState = Entry->second.isState() ?
898 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
899
900 if (RetState != ExpectedState)
901 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
902 Ret->getReturnLoc(), stateToString(ExpectedState),
903 stateToString(RetState));
904 }
905 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000906
907 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
908 Analyzer.WarningsHandler);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000909}
910
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000911void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000912 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
913 if (Entry == PropagationMap.end()) return;
914
915 switch (UOp->getOpcode()) {
916 case UO_AddrOf:
917 PropagationMap.insert(PairType(UOp, Entry->second));
918 break;
919
920 case UO_LNot:
921 if (Entry->second.isTest() || Entry->second.isBinTest())
922 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
923 break;
924
925 default:
926 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000927 }
928}
929
DeLesley Hutchins66540852013-10-04 21:28:06 +0000930// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000931void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000932 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000933 if (Var->hasInit()) {
DeLesley Hutchins13be0322013-10-18 23:11:49 +0000934 MapType::iterator VIT = PropagationMap.find(Var->getInit());
935 if (VIT != PropagationMap.end()) {
936 PropagationInfo PInfo = VIT->second;
937 ConsumedState St = getPInfoState(PInfo);
938 if (St != consumed::CS_None) {
939 StateMap->setState(Var, St);
940 return;
941 }
942 }
DeLesley Hutchins42525982013-08-29 22:36:05 +0000943 }
DeLesley Hutchins13be0322013-10-18 23:11:49 +0000944 // Otherwise
945 StateMap->setState(Var, consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000946 }
947}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000948}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000949
950namespace clang {
951namespace consumed {
952
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000953void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
954 ConsumedStateMap *ThenStates,
955 ConsumedStateMap *ElseStates) {
956
957 ConsumedState VarState = ThenStates->getState(Test.Var);
958
959 if (VarState == CS_Unknown) {
960 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000961 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000962
963 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
964 ThenStates->markUnreachable();
965
DeLesley Hutchins66540852013-10-04 21:28:06 +0000966 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000967 ElseStates->markUnreachable();
968 }
969}
970
971void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
972 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
973
974 const VarTestResult &LTest = PInfo.getLTest(),
975 &RTest = PInfo.getRTest();
976
977 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
978 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
979
980 if (LTest.Var) {
981 if (PInfo.testEffectiveOp() == EO_And) {
982 if (LState == CS_Unknown) {
983 ThenStates->setState(LTest.Var, LTest.TestsFor);
984
985 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
986 ThenStates->markUnreachable();
987
988 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000989 if (RState == RTest.TestsFor)
990 ElseStates->markUnreachable();
991 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000992 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000993 }
994
995 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000996 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000997 ElseStates->setState(LTest.Var,
998 invertConsumedUnconsumed(LTest.TestsFor));
999
DeLesley Hutchins66540852013-10-04 21:28:06 +00001000 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001001 ElseStates->markUnreachable();
1002
1003 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
1004 isKnownState(RState)) {
1005
DeLesley Hutchins66540852013-10-04 21:28:06 +00001006 if (RState == RTest.TestsFor)
1007 ElseStates->markUnreachable();
1008 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001009 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001010 }
1011 }
1012 }
1013
1014 if (RTest.Var) {
1015 if (PInfo.testEffectiveOp() == EO_And) {
1016 if (RState == CS_Unknown)
1017 ThenStates->setState(RTest.Var, RTest.TestsFor);
1018 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1019 ThenStates->markUnreachable();
1020
DeLesley Hutchins66540852013-10-04 21:28:06 +00001021 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001022 if (RState == CS_Unknown)
1023 ElseStates->setState(RTest.Var,
1024 invertConsumedUnconsumed(RTest.TestsFor));
1025 else if (RState == RTest.TestsFor)
1026 ElseStates->markUnreachable();
1027 }
1028 }
1029}
1030
DeLesley Hutchins73858402013-10-09 18:30:24 +00001031bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1032 const CFGBlock *TargetBlock) {
1033
1034 assert(CurrBlock && "Block pointer must not be NULL");
1035 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1036
1037 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1038 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1039 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1040 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1041 return false;
1042 }
1043 return true;
1044}
1045
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001046void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1047 ConsumedStateMap *StateMap,
1048 bool &AlreadyOwned) {
1049
DeLesley Hutchins73858402013-10-09 18:30:24 +00001050 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001051
1052 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1053
1054 if (Entry) {
1055 Entry->intersect(StateMap);
1056
1057 } else if (AlreadyOwned) {
1058 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
1059
1060 } else {
1061 StateMapsArray[Block->getBlockID()] = StateMap;
1062 AlreadyOwned = true;
1063 }
1064}
1065
1066void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1067 ConsumedStateMap *StateMap) {
1068
DeLesley Hutchins73858402013-10-09 18:30:24 +00001069 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001070
1071 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1072
1073 if (Entry) {
1074 Entry->intersect(StateMap);
1075 delete StateMap;
1076
1077 } else {
1078 StateMapsArray[Block->getBlockID()] = StateMap;
1079 }
1080}
1081
DeLesley Hutchins73858402013-10-09 18:30:24 +00001082ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1083 assert(Block && "Block pointer must not be NULL");
1084 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1085
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001086 return StateMapsArray[Block->getBlockID()];
1087}
1088
DeLesley Hutchins73858402013-10-09 18:30:24 +00001089void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1090 unsigned int BlockID = Block->getBlockID();
1091 delete StateMapsArray[BlockID];
1092 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001093}
1094
DeLesley Hutchins73858402013-10-09 18:30:24 +00001095ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1096 assert(Block && "Block pointer must not be NULL");
1097
1098 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1099 if (isBackEdgeTarget(Block)) {
1100 return new ConsumedStateMap(*StateMap);
1101 } else {
1102 StateMapsArray[Block->getBlockID()] = NULL;
1103 return StateMap;
1104 }
1105}
1106
1107bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1108 assert(From && "From block must not be NULL");
1109 assert(To && "From block must not be NULL");
1110
1111 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1112}
1113
1114bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1115 assert(Block != NULL && "Block pointer must not be NULL");
1116
1117 // Anything with less than two predecessors can't be the target of a back
1118 // edge.
1119 if (Block->pred_size() < 2)
1120 return false;
1121
1122 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1123 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1124 PE = Block->pred_end(); PI != PE; ++PI) {
1125 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1126 return true;
1127 }
1128 return false;
1129}
1130
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001131void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1132 ConsumedWarningsHandlerBase &WarningsHandler) const {
1133
1134 ConsumedState ExpectedState;
1135
1136 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
1137 ++DMI) {
1138
1139 if (isa<ParmVarDecl>(DMI->first)) {
1140 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
1141
1142 if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
1143
1144 ExpectedState =
1145 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
1146
1147 if (DMI->second != ExpectedState) {
1148 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1149 Param->getNameAsString(), stateToString(ExpectedState),
1150 stateToString(DMI->second));
1151 }
1152 }
1153 }
1154}
1155
DeLesley Hutchins73858402013-10-09 18:30:24 +00001156ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001157 MapType::const_iterator Entry = Map.find(Var);
1158
1159 if (Entry != Map.end()) {
1160 return Entry->second;
1161
1162 } else {
1163 return CS_None;
1164 }
1165}
1166
1167void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1168 ConsumedState LocalState;
1169
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001170 if (this->From && this->From == Other->From && !Other->Reachable) {
1171 this->markUnreachable();
1172 return;
1173 }
1174
DeLesley Hutchins73858402013-10-09 18:30:24 +00001175 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1176 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001177
1178 LocalState = this->getState(DMI->first);
1179
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001180 if (LocalState == CS_None)
1181 continue;
1182
1183 if (LocalState != DMI->second)
1184 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001185 }
1186}
1187
DeLesley Hutchins73858402013-10-09 18:30:24 +00001188void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1189 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1190 ConsumedWarningsHandlerBase &WarningsHandler) {
1191
1192 ConsumedState LocalState;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001193 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001194
1195 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1196 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1197
1198 LocalState = this->getState(DMI->first);
1199
1200 if (LocalState == CS_None)
1201 continue;
1202
1203 if (LocalState != DMI->second) {
1204 Map[DMI->first] = CS_Unknown;
1205 WarningsHandler.warnLoopStateMismatch(
1206 BlameLoc, DMI->first->getNameAsString());
1207 }
1208 }
1209}
1210
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001211void ConsumedStateMap::markUnreachable() {
1212 this->Reachable = false;
1213 Map.clear();
1214}
1215
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001216void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1217 Map[Var] = State;
1218}
1219
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001220void ConsumedStateMap::remove(const VarDecl *Var) {
1221 Map.erase(Var);
1222}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001223
DeLesley Hutchins73858402013-10-09 18:30:24 +00001224bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1225 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1226 DMI != DME; ++DMI) {
1227
1228 if (this->getState(DMI->first) != DMI->second)
1229 return true;
1230 }
1231
1232 return false;
1233}
1234
David Blaikiea33ab602013-09-06 01:28:43 +00001235void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1236 const FunctionDecl *D) {
1237 QualType ReturnType;
1238 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1239 ASTContext &CurrContext = AC.getASTContext();
1240 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1241 } else
1242 ReturnType = D->getCallResultType();
1243
1244 if (D->hasAttr<ReturnTypestateAttr>()) {
1245 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1246
1247 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1248 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1249 // FIXME: This should be removed when template instantiation propagates
1250 // attributes at template specialization definition, not
1251 // declaration. When it is removed the test needs to be enabled
1252 // in SemaDeclAttr.cpp.
1253 WarningsHandler.warnReturnTypestateForUnconsumableType(
1254 RTSAttr->getLocation(), ReturnType.getAsString());
1255 ExpectedReturnState = CS_None;
1256 } else
1257 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1258 } else if (isConsumableType(ReturnType))
1259 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1260 else
1261 ExpectedReturnState = CS_None;
1262}
1263
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001264bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1265 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001266
Chris Wailesa0cbcab2013-10-25 15:33:28 +00001267 OwningPtr<ConsumedStateMap> FalseStates(new ConsumedStateMap(*CurrStates));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001268 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001269
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001270 if (const IfStmt *IfNode =
1271 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001272
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001273 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001274
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001275 PInfo = Visitor.getInfo(Cond);
1276 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1277 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1278
1279 if (PInfo.isTest()) {
1280 CurrStates->setSource(Cond);
1281 FalseStates->setSource(Cond);
Chris Wailesa0cbcab2013-10-25 15:33:28 +00001282 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates,
1283 FalseStates.get());
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001284
1285 } else if (PInfo.isBinTest()) {
1286 CurrStates->setSource(PInfo.testSourceNode());
1287 FalseStates->setSource(PInfo.testSourceNode());
Chris Wailesa0cbcab2013-10-25 15:33:28 +00001288 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001289
1290 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001291 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001292 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001293
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001294 } else if (const BinaryOperator *BinOp =
1295 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1296
1297 PInfo = Visitor.getInfo(BinOp->getLHS());
1298 if (!PInfo.isTest()) {
1299 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1300 PInfo = Visitor.getInfo(BinOp->getRHS());
1301
Chris Wailesa0cbcab2013-10-25 15:33:28 +00001302 if (!PInfo.isTest())
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001303 return false;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001304
1305 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001306 return false;
1307 }
1308 }
1309
1310 CurrStates->setSource(BinOp);
1311 FalseStates->setSource(BinOp);
1312
1313 const VarTestResult &Test = PInfo.getTest();
1314 ConsumedState VarState = CurrStates->getState(Test.Var);
1315
1316 if (BinOp->getOpcode() == BO_LAnd) {
1317 if (VarState == CS_Unknown)
1318 CurrStates->setState(Test.Var, Test.TestsFor);
1319 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1320 CurrStates->markUnreachable();
1321
1322 } else if (BinOp->getOpcode() == BO_LOr) {
1323 if (VarState == CS_Unknown)
1324 FalseStates->setState(Test.Var,
1325 invertConsumedUnconsumed(Test.TestsFor));
1326 else if (VarState == Test.TestsFor)
1327 FalseStates->markUnreachable();
1328 }
1329
1330 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001331 return false;
1332 }
1333
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001334 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1335
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001336 if (*SI)
1337 BlockInfo.addInfo(*SI, CurrStates);
1338 else
1339 delete CurrStates;
1340
1341 if (*++SI)
Chris Wailesa0cbcab2013-10-25 15:33:28 +00001342 BlockInfo.addInfo(*SI, FalseStates.take());
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001343
1344 CurrStates = NULL;
1345 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001346}
1347
1348void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1349 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001350 if (!D)
1351 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001352
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001353 CFG *CFGraph = AC.getCFG();
1354 if (!CFGraph)
1355 return;
DeLesley Hutchins52f717e2013-10-17 18:19:31 +00001356
David Blaikiea33ab602013-09-06 01:28:43 +00001357 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001358
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001359 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001360 // AC.getCFG()->viewCFG(LangOptions());
1361
1362 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001363
1364 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001365 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1366
1367 // Add all trackable parameters to the state map.
1368 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1369 PE = D->param_end(); PI != PE; ++PI) {
1370 Visitor.VisitParmVarDecl(*PI);
1371 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001372
1373 // Visit all of the function's basic blocks.
1374 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1375 E = SortedGraph->end(); I != E; ++I) {
1376
1377 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001378
1379 if (CurrStates == NULL)
1380 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001381
1382 if (!CurrStates) {
1383 continue;
1384
1385 } else if (!CurrStates->isReachable()) {
1386 delete CurrStates;
1387 CurrStates = NULL;
1388 continue;
1389 }
1390
1391 Visitor.reset(CurrStates);
1392
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001393 // Visit all of the basic block's statements.
1394 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1395 BE = CurrBlock->end(); BI != BE; ++BI) {
1396
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001397 switch (BI->getKind()) {
1398 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001399 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001400 break;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001401
1402 case CFGElement::TemporaryDtor: {
1403 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1404 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1405 PropagationInfo PInfo = Visitor.getInfo(BTE);
1406
1407 if (PInfo.isValid())
1408 Visitor.checkCallability(PInfo,
1409 DTor.getDestructorDecl(AC.getASTContext()),
1410 BTE->getExprLoc());
1411 break;
1412 }
1413
1414 case CFGElement::AutomaticObjectDtor: {
1415 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1416
1417 const VarDecl *Var = DTor.getVarDecl();
1418 ConsumedState VarState = CurrStates->getState(Var);
1419
1420 if (VarState != CS_None) {
1421 PropagationInfo PInfo(Var);
1422
1423 Visitor.checkCallability(PInfo,
1424 DTor.getDestructorDecl(AC.getASTContext()),
1425 getLastStmtLoc(CurrBlock));
1426
1427 CurrStates->remove(Var);
1428 }
1429 break;
1430 }
1431
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001432 default:
1433 break;
1434 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001435 }
1436
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001437 // TODO: Handle other forms of branching with precision, including while-
1438 // and for-loops. (Deferred)
1439 if (!splitState(CurrBlock, Visitor)) {
1440 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001441
DeLesley Hutchins73858402013-10-09 18:30:24 +00001442 if (CurrBlock->succ_size() > 1 ||
1443 (CurrBlock->succ_size() == 1 &&
1444 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001445
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001446 bool OwnershipTaken = false;
1447
1448 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1449 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1450
DeLesley Hutchins73858402013-10-09 18:30:24 +00001451 if (*SI == NULL) continue;
1452
1453 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1454 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1455 CurrStates,
1456 WarningsHandler);
1457
1458 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1459 BlockInfo.discardInfo(*SI);
1460 } else {
1461 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1462 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001463 }
1464
1465 if (!OwnershipTaken)
1466 delete CurrStates;
1467
1468 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001469 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001470 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001471
1472 if (CurrBlock == &AC.getCFG()->getExit() &&
1473 D->getCallResultType()->isVoidType())
1474 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1475 WarningsHandler);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001476 } // End of block iterator.
1477
1478 // Delete the last existing state map.
1479 delete CurrStates;
1480
1481 WarningsHandler.emitDiagnostics();
1482}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001483}} // end namespace clang::consumed