blob: 8358b6b4e1c7d5714783c00384c32b499726d804 [file] [log] [blame]
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001//===- Consumed.cpp --------------------------------------------*- C++ --*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// A intra-procedural analysis for checking consumed properties. This is based,
11// in part, on research on linear types.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/AST/RecursiveASTVisitor.h"
20#include "clang/AST/StmtVisitor.h"
21#include "clang/AST/StmtCXX.h"
22#include "clang/AST/Type.h"
23#include "clang/Analysis/Analyses/PostOrderCFGView.h"
24#include "clang/Analysis/AnalysisContext.h"
25#include "clang/Analysis/CFG.h"
26#include "clang/Analysis/Analyses/Consumed.h"
27#include "clang/Basic/OperatorKinds.h"
28#include "clang/Basic/SourceLocation.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000029#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/SmallVector.h"
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000031#include "llvm/Support/Compiler.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000032#include "llvm/Support/raw_ostream.h"
33
DeLesley Hutchins73858402013-10-09 18:30:24 +000034// TODO: Use information from tests in while-loop conditional.
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +000035// TODO: Add notes about the actual and expected state for
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000036// TODO: Correctly identify unreachable blocks when chaining boolean operators.
DeLesley Hutchins66540852013-10-04 21:28:06 +000037// TODO: Adjust the parser and AttributesList class to support lists of
38// identifiers.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000039// TODO: Warn about unreachable code.
40// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000041// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
42// if (valid) ...; (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000043// TODO: Take notes on state transitions to provide better warning messages.
44// (Deferred)
45// TODO: Test nested conditionals: A) Checking the same value multiple times,
46// and 2) Checking different values. (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000047
48using namespace clang;
49using namespace consumed;
50
51// Key method definition
52ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
53
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000054static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
55 // Find the source location of the first statement in the block, if the block
56 // is not empty.
57 for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
58 BI != BE; ++BI) {
59 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
60 return CS->getStmt()->getLocStart();
61 }
62
63 // Block is empty.
64 // If we have one successor, return the first statement in that block
65 if (Block->succ_size() == 1 && *Block->succ_begin())
66 return getFirstStmtLoc(*Block->succ_begin());
67
68 return SourceLocation();
69}
70
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000071static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000072 // Find the source location of the last statement in the block, if the block
73 // is not empty.
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000074 if (const Stmt *StmtNode = Block->getTerminator()) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000075 return StmtNode->getLocStart();
76 } else {
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000077 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
78 BE = Block->rend(); BI != BE; ++BI) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000079 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
80 return CS->getStmt()->getLocStart();
81 }
82 }
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000083
84 // If we have one successor, return the first statement in that block
85 SourceLocation Loc;
86 if (Block->succ_size() == 1 && *Block->succ_begin())
87 Loc = getFirstStmtLoc(*Block->succ_begin());
88 if (Loc.isValid())
89 return Loc;
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +000090
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000091 // If we have one predecessor, return the last statement in that block
92 if (Block->pred_size() == 1 && *Block->pred_begin())
93 return getLastStmtLoc(*Block->pred_begin());
94
95 return Loc;
DeLesley Hutchins73858402013-10-09 18:30:24 +000096}
97
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000098static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
99 switch (State) {
100 case CS_Unconsumed:
101 return CS_Consumed;
102 case CS_Consumed:
103 return CS_Unconsumed;
104 case CS_None:
105 return CS_None;
106 case CS_Unknown:
107 return CS_Unknown;
108 }
109 llvm_unreachable("invalid enum");
110}
111
DeLesley Hutchins66540852013-10-04 21:28:06 +0000112static bool isCallableInState(const CallableWhenAttr *CWAttr,
113 ConsumedState State) {
114
115 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
116 E = CWAttr->callableState_end();
117
118 for (; I != E; ++I) {
119
120 ConsumedState MappedAttrState = CS_None;
121
122 switch (*I) {
123 case CallableWhenAttr::Unknown:
124 MappedAttrState = CS_Unknown;
125 break;
126
127 case CallableWhenAttr::Unconsumed:
128 MappedAttrState = CS_Unconsumed;
129 break;
130
131 case CallableWhenAttr::Consumed:
132 MappedAttrState = CS_Consumed;
133 break;
134 }
135
136 if (MappedAttrState == State)
137 return true;
138 }
139
140 return false;
141}
142
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000143static bool isConsumableType(const QualType &QT) {
144 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
145 return RD->hasAttr<ConsumableAttr>();
146 else
147 return false;
148}
149
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000150static bool isKnownState(ConsumedState State) {
151 switch (State) {
152 case CS_Unconsumed:
153 case CS_Consumed:
154 return true;
155 case CS_None:
156 case CS_Unknown:
157 return false;
158 }
Aaron Ballman6b2ec032013-08-29 20:36:09 +0000159 llvm_unreachable("invalid enum");
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000160}
161
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000162static bool isRValueRefish(QualType ParamType) {
163 return ParamType->isRValueReferenceType() ||
164 (ParamType->isLValueReferenceType() &&
165 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue());
166}
167
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000168static bool isTestingFunction(const FunctionDecl *FunDecl) {
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000169 return FunDecl->hasAttr<TestsTypestateAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000170}
171
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000172static bool isValueType(QualType ParamType) {
173 return !(ParamType->isPointerType() || ParamType->isReferenceType());
174}
175
David Blaikiea33ab602013-09-06 01:28:43 +0000176static ConsumedState mapConsumableAttrState(const QualType QT) {
177 assert(isConsumableType(QT));
178
179 const ConsumableAttr *CAttr =
180 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
181
182 switch (CAttr->getDefaultState()) {
183 case ConsumableAttr::Unknown:
184 return CS_Unknown;
185 case ConsumableAttr::Unconsumed:
186 return CS_Unconsumed;
187 case ConsumableAttr::Consumed:
188 return CS_Consumed;
189 }
190 llvm_unreachable("invalid enum");
191}
192
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000193static ConsumedState
194mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
195 switch (PTAttr->getParamState()) {
196 case ParamTypestateAttr::Unknown:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000197 return CS_Unknown;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000198 case ParamTypestateAttr::Unconsumed:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000199 return CS_Unconsumed;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000200 case ParamTypestateAttr::Consumed:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000201 return CS_Consumed;
202 }
203 llvm_unreachable("invalid_enum");
204}
205
Eric Christophere988dc42013-09-03 20:43:00 +0000206static ConsumedState
207mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000208 switch (RTSAttr->getState()) {
209 case ReturnTypestateAttr::Unknown:
210 return CS_Unknown;
211 case ReturnTypestateAttr::Unconsumed:
212 return CS_Unconsumed;
213 case ReturnTypestateAttr::Consumed:
214 return CS_Consumed;
215 }
Eric Christophere988dc42013-09-03 20:43:00 +0000216 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000217}
218
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000219static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
220 switch (STAttr->getNewState()) {
221 case SetTypestateAttr::Unknown:
222 return CS_Unknown;
223 case SetTypestateAttr::Unconsumed:
224 return CS_Unconsumed;
225 case SetTypestateAttr::Consumed:
226 return CS_Consumed;
227 }
228 llvm_unreachable("invalid_enum");
229}
230
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000231static StringRef stateToString(ConsumedState State) {
232 switch (State) {
233 case consumed::CS_None:
234 return "none";
235
236 case consumed::CS_Unknown:
237 return "unknown";
238
239 case consumed::CS_Unconsumed:
240 return "unconsumed";
241
242 case consumed::CS_Consumed:
243 return "consumed";
244 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000245 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000246}
247
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000248static ConsumedState testsFor(const FunctionDecl *FunDecl) {
249 assert(isTestingFunction(FunDecl));
250 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) {
251 case TestsTypestateAttr::Unconsumed:
252 return CS_Unconsumed;
253 case TestsTypestateAttr::Consumed:
254 return CS_Consumed;
255 }
256 llvm_unreachable("invalid enum");
257}
258
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000259namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000260struct VarTestResult {
261 const VarDecl *Var;
262 ConsumedState TestsFor;
263};
264} // end anonymous::VarTestResult
265
266namespace clang {
267namespace consumed {
268
269enum EffectiveOp {
270 EO_And,
271 EO_Or
272};
273
274class PropagationInfo {
275 enum {
276 IT_None,
277 IT_State,
278 IT_Test,
279 IT_BinTest,
280 IT_Var
281 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000282
283 struct BinTestTy {
284 const BinaryOperator *Source;
285 EffectiveOp EOp;
286 VarTestResult LTest;
287 VarTestResult RTest;
288 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000289
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000290 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000291 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000292 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000293 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000294 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000295 };
296
DeLesley Hutchins66540852013-10-04 21:28:06 +0000297 QualType TempType;
298
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000299public:
300 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000301
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000302 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
303 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
304 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000305
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000306 Test.Var = Var;
307 Test.TestsFor = TestsFor;
308 }
309
310 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
311 const VarTestResult &LTest, const VarTestResult &RTest)
312 : InfoType(IT_BinTest) {
313
314 BinTest.Source = Source;
315 BinTest.EOp = EOp;
316 BinTest.LTest = LTest;
317 BinTest.RTest = RTest;
318 }
319
320 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
321 const VarDecl *LVar, ConsumedState LTestsFor,
322 const VarDecl *RVar, ConsumedState RTestsFor)
323 : InfoType(IT_BinTest) {
324
325 BinTest.Source = Source;
326 BinTest.EOp = EOp;
327 BinTest.LTest.Var = LVar;
328 BinTest.LTest.TestsFor = LTestsFor;
329 BinTest.RTest.Var = RVar;
330 BinTest.RTest.TestsFor = RTestsFor;
331 }
332
DeLesley Hutchins66540852013-10-04 21:28:06 +0000333 PropagationInfo(ConsumedState State, QualType TempType)
334 : InfoType(IT_State), State(State), TempType(TempType) {}
335
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000336 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
337
338 const ConsumedState & getState() const {
339 assert(InfoType == IT_State);
340 return State;
341 }
342
DeLesley Hutchins66540852013-10-04 21:28:06 +0000343 const QualType & getTempType() const {
344 assert(InfoType == IT_State);
345 return TempType;
346 }
347
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000348 const VarTestResult & getTest() const {
349 assert(InfoType == IT_Test);
350 return Test;
351 }
352
353 const VarTestResult & getLTest() const {
354 assert(InfoType == IT_BinTest);
355 return BinTest.LTest;
356 }
357
358 const VarTestResult & getRTest() const {
359 assert(InfoType == IT_BinTest);
360 return BinTest.RTest;
361 }
362
363 const VarDecl * getVar() const {
364 assert(InfoType == IT_Var);
365 return Var;
366 }
367
368 EffectiveOp testEffectiveOp() const {
369 assert(InfoType == IT_BinTest);
370 return BinTest.EOp;
371 }
372
373 const BinaryOperator * testSourceNode() const {
374 assert(InfoType == IT_BinTest);
375 return BinTest.Source;
376 }
377
378 bool isValid() const { return InfoType != IT_None; }
379 bool isState() const { return InfoType == IT_State; }
380 bool isTest() const { return InfoType == IT_Test; }
381 bool isBinTest() const { return InfoType == IT_BinTest; }
382 bool isVar() const { return InfoType == IT_Var; }
383
384 PropagationInfo invertTest() const {
385 assert(InfoType == IT_Test || InfoType == IT_BinTest);
386
387 if (InfoType == IT_Test) {
388 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
389
390 } else if (InfoType == IT_BinTest) {
391 return PropagationInfo(BinTest.Source,
392 BinTest.EOp == EO_And ? EO_Or : EO_And,
393 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
394 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
395 } else {
396 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000397 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000398 }
399};
400
401class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000402
403 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
404 typedef std::pair<const Stmt *, PropagationInfo> PairType;
405 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000406 typedef MapType::const_iterator ConstInfoEntry;
407
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000408 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000409 ConsumedAnalyzer &Analyzer;
410 ConsumedStateMap *StateMap;
411 MapType PropagationMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000412 void forwardInfo(const Stmt *From, const Stmt *To);
413 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000414 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
415 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000416
417public:
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000418 void checkCallability(const PropagationInfo &PInfo,
419 const FunctionDecl *FunDecl,
420 SourceLocation BlameLoc);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000421
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000422 void Visit(const Stmt *StmtNode);
423
424 void VisitBinaryOperator(const BinaryOperator *BinOp);
425 void VisitCallExpr(const CallExpr *Call);
426 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000427 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000428 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
429 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
430 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
431 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
432 void VisitDeclStmt(const DeclStmt *DelcS);
433 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
434 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000435 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000436 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000437 void VisitUnaryOperator(const UnaryOperator *UOp);
438 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000439
DeLesley Hutchins42525982013-08-29 22:36:05 +0000440 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
441 ConsumedStateMap *StateMap)
442 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000443
444 PropagationInfo getInfo(const Stmt *StmtNode) const {
445 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
446
447 if (Entry != PropagationMap.end())
448 return Entry->second;
449 else
450 return PropagationInfo();
451 }
452
453 void reset(ConsumedStateMap *NewStateMap) {
454 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000455 }
456};
457
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000458void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000459 const FunctionDecl *FunDecl,
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000460 SourceLocation BlameLoc) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000461
DeLesley Hutchins66540852013-10-04 21:28:06 +0000462 if (!FunDecl->hasAttr<CallableWhenAttr>())
463 return;
464
465 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000466
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000467 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000468 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000469 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000470
DeLesley Hutchins66540852013-10-04 21:28:06 +0000471 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000472
DeLesley Hutchins66540852013-10-04 21:28:06 +0000473 if (isCallableInState(CWAttr, VarState))
474 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000475
DeLesley Hutchins66540852013-10-04 21:28:06 +0000476 Analyzer.WarningsHandler.warnUseInInvalidState(
477 FunDecl->getNameAsString(), Var->getNameAsString(),
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000478 stateToString(VarState), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000479
DeLesley Hutchins66540852013-10-04 21:28:06 +0000480 } else if (PInfo.isState()) {
481
482 assert(PInfo.getState() != CS_None && "Invalid state");
483
484 if (isCallableInState(CWAttr, PInfo.getState()))
485 return;
486
487 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000488 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000489 }
490}
491
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000492void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
493 InfoEntry Entry = PropagationMap.find(From);
494
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000495 if (Entry != PropagationMap.end())
496 PropagationMap.insert(PairType(To, Entry->second));
497}
498
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000499bool ConsumedStmtVisitor::isLikeMoveAssignment(
500 const CXXMethodDecl *MethodDecl) {
501
502 return MethodDecl->isMoveAssignmentOperator() ||
503 (MethodDecl->getOverloadedOperator() == OO_Equal &&
504 MethodDecl->getNumParams() == 1 &&
505 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
506}
507
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000508void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
509 const FunctionDecl *Fun,
510 QualType ReturnType) {
511 if (isConsumableType(ReturnType)) {
512
513 ConsumedState ReturnState;
514
515 if (Fun->hasAttr<ReturnTypestateAttr>())
516 ReturnState = mapReturnTypestateAttrState(
517 Fun->getAttr<ReturnTypestateAttr>());
518 else
David Blaikiea33ab602013-09-06 01:28:43 +0000519 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000520
521 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000522 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000523 }
524}
525
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000526void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
527
528 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
529
530 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
531 CE = StmtNode->child_end(); CI != CE; ++CI) {
532
533 PropagationMap.erase(*CI);
534 }
535}
536
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000537void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
538 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000539 case BO_LAnd:
540 case BO_LOr : {
541 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
542 REntry = PropagationMap.find(BinOp->getRHS());
543
544 VarTestResult LTest, RTest;
545
546 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
547 LTest = LEntry->second.getTest();
548
549 } else {
550 LTest.Var = NULL;
551 LTest.TestsFor = CS_None;
552 }
553
554 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
555 RTest = REntry->second.getTest();
556
557 } else {
558 RTest.Var = NULL;
559 RTest.TestsFor = CS_None;
560 }
561
562 if (!(LTest.Var == NULL && RTest.Var == NULL))
563 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
564 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
565
566 break;
567 }
568
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000569 case BO_PtrMemD:
570 case BO_PtrMemI:
571 forwardInfo(BinOp->getLHS(), BinOp);
572 break;
573
574 default:
575 break;
576 }
577}
578
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000579void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
580 if (const FunctionDecl *FunDecl =
581 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
582
583 // Special case for the std::move function.
584 // TODO: Make this more specific. (Deferred)
585 if (FunDecl->getNameAsString() == "move") {
586 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
587
588 if (Entry != PropagationMap.end()) {
589 PropagationMap.insert(PairType(Call, Entry->second));
590 }
591
592 return;
593 }
594
595 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
596
597 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000598 const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
599 QualType ParamType = Param->getType();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000600
601 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
602
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000603 if (Entry == PropagationMap.end() ||
604 !(Entry->second.isState() || Entry->second.isVar()))
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000605 continue;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000606
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000607 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000608
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000609 // Check that the parameter is in the correct state.
610
611 if (Param->hasAttr<ParamTypestateAttr>()) {
612 ConsumedState ParamState =
613 PInfo.isState() ? PInfo.getState() :
614 StateMap->getState(PInfo.getVar());
615
616 ConsumedState ExpectedState =
617 mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
618
619 if (ParamState != ExpectedState)
620 Analyzer.WarningsHandler.warnParamTypestateMismatch(
621 Call->getArg(Index - Offset)->getExprLoc(),
622 stateToString(ExpectedState), stateToString(ParamState));
623 }
624
625 if (!Entry->second.isVar())
626 continue;
627
628 // Adjust state on the caller side.
629
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000630 if (isRValueRefish(ParamType)) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000631 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000632
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000633 } else if (Param->hasAttr<ReturnTypestateAttr>()) {
634 StateMap->setState(PInfo.getVar(),
635 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
636
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000637 } else if (!isValueType(ParamType) &&
638 !ParamType->getPointeeType().isConstQualified()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000639
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000640 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000641 }
642 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000643
DeLesley Hutchins66540852013-10-04 21:28:06 +0000644 QualType RetType = FunDecl->getCallResultType();
645 if (RetType->isReferenceType())
646 RetType = RetType->getPointeeType();
647
648 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000649 }
650}
651
652void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000653 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000654}
655
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000656void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
657 const CXXBindTemporaryExpr *Temp) {
658
659 forwardInfo(Temp->getSubExpr(), Temp);
660}
661
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000662void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
663 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000664
665 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000666 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
667
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000668 if (!isConsumableType(ThisType))
669 return;
670
671 // FIXME: What should happen if someone annotates the move constructor?
672 if (Constructor->hasAttr<ReturnTypestateAttr>()) {
673 ReturnTypestateAttr *RTAttr = Constructor->getAttr<ReturnTypestateAttr>();
674 ConsumedState RetState = mapReturnTypestateAttrState(RTAttr);
675 PropagationMap.insert(PairType(Call, PropagationInfo(RetState, ThisType)));
676
677 } else if (Constructor->isDefaultConstructor()) {
678
679 PropagationMap.insert(PairType(Call,
680 PropagationInfo(consumed::CS_Consumed, ThisType)));
681
682 } else if (Constructor->isMoveConstructor()) {
683
684 PropagationInfo PInfo =
685 PropagationMap.find(Call->getArg(0))->second;
686
687 if (PInfo.isVar()) {
688 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000689
690 PropagationMap.insert(PairType(Call,
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000691 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000692
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000693 StateMap->setState(Var, consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000694
695 } else {
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000696 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000697 }
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000698
699 } else if (Constructor->isCopyConstructor()) {
700 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
701
702 if (Entry != PropagationMap.end())
703 PropagationMap.insert(PairType(Call, Entry->second));
704
705 } else {
706 ConsumedState RetState = mapConsumableAttrState(ThisType);
707 PropagationMap.insert(PairType(Call, PropagationInfo(RetState, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000708 }
709}
710
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000711
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000712void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
713 const CXXMemberCallExpr *Call) {
714
715 VisitCallExpr(Call);
716
717 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
718
719 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000720 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000721 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000722
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000723 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000724
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000725 if (PInfo.isVar()) {
726 if (isTestingFunction(MethodDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000727 PropagationMap.insert(PairType(Call,
728 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000729 else if (MethodDecl->hasAttr<SetTypestateAttr>())
730 StateMap->setState(PInfo.getVar(),
731 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000732 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000733 }
734}
735
736void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
737 const CXXOperatorCallExpr *Call) {
738
739 const FunctionDecl *FunDecl =
740 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
741
742 if (!FunDecl) return;
743
744 if (isa<CXXMethodDecl>(FunDecl) &&
745 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
746
747 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
748 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
749
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000750 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000751
752 if (LEntry != PropagationMap.end() &&
753 REntry != PropagationMap.end()) {
754
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000755 LPInfo = LEntry->second;
756 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000757
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000758 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000759 StateMap->setState(LPInfo.getVar(),
760 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000761
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000762 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000763
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000764 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000765
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000766 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000767 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000768
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000769 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000770
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000771 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000772 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000773 PropagationInfo(StateMap->getState(RPInfo.getVar()),
774 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000775
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000776 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000777
778 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000779 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000780 }
781
782 } else if (LEntry != PropagationMap.end() &&
783 REntry == PropagationMap.end()) {
784
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000785 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000786
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000787 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000788 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000789
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000790 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000791
DeLesley Hutchins66540852013-10-04 21:28:06 +0000792 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000793 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000794 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000795 }
796
797 } else if (LEntry == PropagationMap.end() &&
798 REntry != PropagationMap.end()) {
799
DeLesley Hutchins66540852013-10-04 21:28:06 +0000800 if (REntry->second.isVar())
801 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000802 }
803
804 } else {
805
806 VisitCallExpr(Call);
807
808 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
809
810 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000811 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000812
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000813 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000814
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000815 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000816 if (isTestingFunction(FunDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000817 PropagationMap.insert(PairType(Call,
818 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000819 else if (FunDecl->hasAttr<SetTypestateAttr>())
820 StateMap->setState(PInfo.getVar(),
821 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000822 }
823 }
824 }
825}
826
827void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
828 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
829 if (StateMap->getState(Var) != consumed::CS_None)
830 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
831}
832
833void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
834 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
835 DE = DeclS->decl_end(); DI != DE; ++DI) {
836
837 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
838 }
839
840 if (DeclS->isSingleDecl())
841 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
842 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
843}
844
845void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
846 const MaterializeTemporaryExpr *Temp) {
847
848 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
849
850 if (Entry != PropagationMap.end())
851 PropagationMap.insert(PairType(Temp, Entry->second));
852}
853
854void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
855 forwardInfo(MExpr->getBase(), MExpr);
856}
857
DeLesley Hutchins42525982013-08-29 22:36:05 +0000858
859void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000860 QualType ParamType = Param->getType();
861 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000862
863 if (Param->hasAttr<ParamTypestateAttr>()) {
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000864 const ParamTypestateAttr *PTAttr = Param->getAttr<ParamTypestateAttr>();
865 ParamState = mapParamTypestateAttrState(PTAttr);
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000866
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000867 } else if (isValueType(ParamType) && isConsumableType(ParamType)) {
David Blaikiea33ab602013-09-06 01:28:43 +0000868 ParamState = mapConsumableAttrState(ParamType);
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000869
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000870 } else if (isRValueRefish(ParamType) &&
871 isConsumableType(ParamType->getPointeeType())) {
872
873 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
874
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000875 } else if (ParamType->isReferenceType() &&
876 isConsumableType(ParamType->getPointeeType())) {
David Blaikiea33ab602013-09-06 01:28:43 +0000877 ParamState = consumed::CS_Unknown;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000878 }
879
880 if (ParamState != CS_None)
David Blaikiea33ab602013-09-06 01:28:43 +0000881 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000882}
883
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000884void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000885 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
886
887 if (ExpectedState != CS_None) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000888 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
889
890 if (Entry != PropagationMap.end()) {
891 assert(Entry->second.isState() || Entry->second.isVar());
892
893 ConsumedState RetState = Entry->second.isState() ?
894 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
895
896 if (RetState != ExpectedState)
897 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
898 Ret->getReturnLoc(), stateToString(ExpectedState),
899 stateToString(RetState));
900 }
901 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000902
903 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
904 Analyzer.WarningsHandler);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000905}
906
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000907void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000908 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
909 if (Entry == PropagationMap.end()) return;
910
911 switch (UOp->getOpcode()) {
912 case UO_AddrOf:
913 PropagationMap.insert(PairType(UOp, Entry->second));
914 break;
915
916 case UO_LNot:
917 if (Entry->second.isTest() || Entry->second.isBinTest())
918 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
919 break;
920
921 default:
922 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000923 }
924}
925
DeLesley Hutchins66540852013-10-04 21:28:06 +0000926// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000927void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000928 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000929 if (Var->hasInit()) {
930 PropagationInfo PInfo =
931 PropagationMap.find(Var->getInit())->second;
932
933 StateMap->setState(Var, PInfo.isVar() ?
934 StateMap->getState(PInfo.getVar()) : PInfo.getState());
935
936 } else {
937 StateMap->setState(Var, consumed::CS_Unknown);
938 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000939 }
940}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000941}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000942
943namespace clang {
944namespace consumed {
945
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000946void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
947 ConsumedStateMap *ThenStates,
948 ConsumedStateMap *ElseStates) {
949
950 ConsumedState VarState = ThenStates->getState(Test.Var);
951
952 if (VarState == CS_Unknown) {
953 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000954 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000955
956 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
957 ThenStates->markUnreachable();
958
DeLesley Hutchins66540852013-10-04 21:28:06 +0000959 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000960 ElseStates->markUnreachable();
961 }
962}
963
964void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
965 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
966
967 const VarTestResult &LTest = PInfo.getLTest(),
968 &RTest = PInfo.getRTest();
969
970 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
971 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
972
973 if (LTest.Var) {
974 if (PInfo.testEffectiveOp() == EO_And) {
975 if (LState == CS_Unknown) {
976 ThenStates->setState(LTest.Var, LTest.TestsFor);
977
978 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
979 ThenStates->markUnreachable();
980
981 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000982 if (RState == RTest.TestsFor)
983 ElseStates->markUnreachable();
984 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000985 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000986 }
987
988 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000989 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000990 ElseStates->setState(LTest.Var,
991 invertConsumedUnconsumed(LTest.TestsFor));
992
DeLesley Hutchins66540852013-10-04 21:28:06 +0000993 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000994 ElseStates->markUnreachable();
995
996 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
997 isKnownState(RState)) {
998
DeLesley Hutchins66540852013-10-04 21:28:06 +0000999 if (RState == RTest.TestsFor)
1000 ElseStates->markUnreachable();
1001 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001002 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001003 }
1004 }
1005 }
1006
1007 if (RTest.Var) {
1008 if (PInfo.testEffectiveOp() == EO_And) {
1009 if (RState == CS_Unknown)
1010 ThenStates->setState(RTest.Var, RTest.TestsFor);
1011 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1012 ThenStates->markUnreachable();
1013
DeLesley Hutchins66540852013-10-04 21:28:06 +00001014 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001015 if (RState == CS_Unknown)
1016 ElseStates->setState(RTest.Var,
1017 invertConsumedUnconsumed(RTest.TestsFor));
1018 else if (RState == RTest.TestsFor)
1019 ElseStates->markUnreachable();
1020 }
1021 }
1022}
1023
DeLesley Hutchins73858402013-10-09 18:30:24 +00001024bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1025 const CFGBlock *TargetBlock) {
1026
1027 assert(CurrBlock && "Block pointer must not be NULL");
1028 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1029
1030 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1031 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1032 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1033 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1034 return false;
1035 }
1036 return true;
1037}
1038
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001039void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1040 ConsumedStateMap *StateMap,
1041 bool &AlreadyOwned) {
1042
DeLesley Hutchins73858402013-10-09 18:30:24 +00001043 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001044
1045 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1046
1047 if (Entry) {
1048 Entry->intersect(StateMap);
1049
1050 } else if (AlreadyOwned) {
1051 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
1052
1053 } else {
1054 StateMapsArray[Block->getBlockID()] = StateMap;
1055 AlreadyOwned = true;
1056 }
1057}
1058
1059void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1060 ConsumedStateMap *StateMap) {
1061
DeLesley Hutchins73858402013-10-09 18:30:24 +00001062 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001063
1064 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1065
1066 if (Entry) {
1067 Entry->intersect(StateMap);
1068 delete StateMap;
1069
1070 } else {
1071 StateMapsArray[Block->getBlockID()] = StateMap;
1072 }
1073}
1074
DeLesley Hutchins73858402013-10-09 18:30:24 +00001075ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1076 assert(Block && "Block pointer must not be NULL");
1077 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1078
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001079 return StateMapsArray[Block->getBlockID()];
1080}
1081
DeLesley Hutchins73858402013-10-09 18:30:24 +00001082void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1083 unsigned int BlockID = Block->getBlockID();
1084 delete StateMapsArray[BlockID];
1085 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001086}
1087
DeLesley Hutchins73858402013-10-09 18:30:24 +00001088ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1089 assert(Block && "Block pointer must not be NULL");
1090
1091 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1092 if (isBackEdgeTarget(Block)) {
1093 return new ConsumedStateMap(*StateMap);
1094 } else {
1095 StateMapsArray[Block->getBlockID()] = NULL;
1096 return StateMap;
1097 }
1098}
1099
1100bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1101 assert(From && "From block must not be NULL");
1102 assert(To && "From block must not be NULL");
1103
1104 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1105}
1106
1107bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1108 assert(Block != NULL && "Block pointer must not be NULL");
1109
1110 // Anything with less than two predecessors can't be the target of a back
1111 // edge.
1112 if (Block->pred_size() < 2)
1113 return false;
1114
1115 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1116 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1117 PE = Block->pred_end(); PI != PE; ++PI) {
1118 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1119 return true;
1120 }
1121 return false;
1122}
1123
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001124void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1125 ConsumedWarningsHandlerBase &WarningsHandler) const {
1126
1127 ConsumedState ExpectedState;
1128
1129 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
1130 ++DMI) {
1131
1132 if (isa<ParmVarDecl>(DMI->first)) {
1133 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
1134
1135 if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
1136
1137 ExpectedState =
1138 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
1139
1140 if (DMI->second != ExpectedState) {
1141 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1142 Param->getNameAsString(), stateToString(ExpectedState),
1143 stateToString(DMI->second));
1144 }
1145 }
1146 }
1147}
1148
DeLesley Hutchins73858402013-10-09 18:30:24 +00001149ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001150 MapType::const_iterator Entry = Map.find(Var);
1151
1152 if (Entry != Map.end()) {
1153 return Entry->second;
1154
1155 } else {
1156 return CS_None;
1157 }
1158}
1159
1160void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1161 ConsumedState LocalState;
1162
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001163 if (this->From && this->From == Other->From && !Other->Reachable) {
1164 this->markUnreachable();
1165 return;
1166 }
1167
DeLesley Hutchins73858402013-10-09 18:30:24 +00001168 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1169 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001170
1171 LocalState = this->getState(DMI->first);
1172
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001173 if (LocalState == CS_None)
1174 continue;
1175
1176 if (LocalState != DMI->second)
1177 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001178 }
1179}
1180
DeLesley Hutchins73858402013-10-09 18:30:24 +00001181void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1182 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1183 ConsumedWarningsHandlerBase &WarningsHandler) {
1184
1185 ConsumedState LocalState;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001186 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001187
1188 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1189 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1190
1191 LocalState = this->getState(DMI->first);
1192
1193 if (LocalState == CS_None)
1194 continue;
1195
1196 if (LocalState != DMI->second) {
1197 Map[DMI->first] = CS_Unknown;
1198 WarningsHandler.warnLoopStateMismatch(
1199 BlameLoc, DMI->first->getNameAsString());
1200 }
1201 }
1202}
1203
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001204void ConsumedStateMap::markUnreachable() {
1205 this->Reachable = false;
1206 Map.clear();
1207}
1208
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001209void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1210 Map[Var] = State;
1211}
1212
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001213void ConsumedStateMap::remove(const VarDecl *Var) {
1214 Map.erase(Var);
1215}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001216
DeLesley Hutchins73858402013-10-09 18:30:24 +00001217bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1218 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1219 DMI != DME; ++DMI) {
1220
1221 if (this->getState(DMI->first) != DMI->second)
1222 return true;
1223 }
1224
1225 return false;
1226}
1227
David Blaikiea33ab602013-09-06 01:28:43 +00001228void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1229 const FunctionDecl *D) {
1230 QualType ReturnType;
1231 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1232 ASTContext &CurrContext = AC.getASTContext();
1233 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1234 } else
1235 ReturnType = D->getCallResultType();
1236
1237 if (D->hasAttr<ReturnTypestateAttr>()) {
1238 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1239
1240 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1241 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1242 // FIXME: This should be removed when template instantiation propagates
1243 // attributes at template specialization definition, not
1244 // declaration. When it is removed the test needs to be enabled
1245 // in SemaDeclAttr.cpp.
1246 WarningsHandler.warnReturnTypestateForUnconsumableType(
1247 RTSAttr->getLocation(), ReturnType.getAsString());
1248 ExpectedReturnState = CS_None;
1249 } else
1250 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1251 } else if (isConsumableType(ReturnType))
1252 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1253 else
1254 ExpectedReturnState = CS_None;
1255}
1256
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001257bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1258 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001259
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001260 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1261 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001262
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001263 if (const IfStmt *IfNode =
1264 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001265
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001266 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001267
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001268 PInfo = Visitor.getInfo(Cond);
1269 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1270 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1271
1272 if (PInfo.isTest()) {
1273 CurrStates->setSource(Cond);
1274 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001275 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001276
1277 } else if (PInfo.isBinTest()) {
1278 CurrStates->setSource(PInfo.testSourceNode());
1279 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001280 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001281
1282 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001283 delete FalseStates;
1284 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001285 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001286
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001287 } else if (const BinaryOperator *BinOp =
1288 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1289
1290 PInfo = Visitor.getInfo(BinOp->getLHS());
1291 if (!PInfo.isTest()) {
1292 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1293 PInfo = Visitor.getInfo(BinOp->getRHS());
1294
1295 if (!PInfo.isTest()) {
1296 delete FalseStates;
1297 return false;
1298 }
1299
1300 } else {
1301 delete FalseStates;
1302 return false;
1303 }
1304 }
1305
1306 CurrStates->setSource(BinOp);
1307 FalseStates->setSource(BinOp);
1308
1309 const VarTestResult &Test = PInfo.getTest();
1310 ConsumedState VarState = CurrStates->getState(Test.Var);
1311
1312 if (BinOp->getOpcode() == BO_LAnd) {
1313 if (VarState == CS_Unknown)
1314 CurrStates->setState(Test.Var, Test.TestsFor);
1315 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1316 CurrStates->markUnreachable();
1317
1318 } else if (BinOp->getOpcode() == BO_LOr) {
1319 if (VarState == CS_Unknown)
1320 FalseStates->setState(Test.Var,
1321 invertConsumedUnconsumed(Test.TestsFor));
1322 else if (VarState == Test.TestsFor)
1323 FalseStates->markUnreachable();
1324 }
1325
1326 } else {
1327 delete FalseStates;
1328 return false;
1329 }
1330
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001331 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1332
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001333 if (*SI)
1334 BlockInfo.addInfo(*SI, CurrStates);
1335 else
1336 delete CurrStates;
1337
1338 if (*++SI)
1339 BlockInfo.addInfo(*SI, FalseStates);
1340 else
1341 delete FalseStates;
1342
1343 CurrStates = NULL;
1344 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001345}
1346
1347void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1348 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001349 if (!D)
1350 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001351
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001352 CFG *CFGraph = AC.getCFG();
1353 if (!CFGraph)
1354 return;
DeLesley Hutchins52f717e2013-10-17 18:19:31 +00001355
David Blaikiea33ab602013-09-06 01:28:43 +00001356 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001357
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001358 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001359 // AC.getCFG()->viewCFG(LangOptions());
1360
1361 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001362
1363 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001364 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1365
1366 // Add all trackable parameters to the state map.
1367 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1368 PE = D->param_end(); PI != PE; ++PI) {
1369 Visitor.VisitParmVarDecl(*PI);
1370 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001371
1372 // Visit all of the function's basic blocks.
1373 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1374 E = SortedGraph->end(); I != E; ++I) {
1375
1376 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001377
1378 if (CurrStates == NULL)
1379 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001380
1381 if (!CurrStates) {
1382 continue;
1383
1384 } else if (!CurrStates->isReachable()) {
1385 delete CurrStates;
1386 CurrStates = NULL;
1387 continue;
1388 }
1389
1390 Visitor.reset(CurrStates);
1391
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001392 // Visit all of the basic block's statements.
1393 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1394 BE = CurrBlock->end(); BI != BE; ++BI) {
1395
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001396 switch (BI->getKind()) {
1397 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001398 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001399 break;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001400
1401 case CFGElement::TemporaryDtor: {
1402 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1403 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1404 PropagationInfo PInfo = Visitor.getInfo(BTE);
1405
1406 if (PInfo.isValid())
1407 Visitor.checkCallability(PInfo,
1408 DTor.getDestructorDecl(AC.getASTContext()),
1409 BTE->getExprLoc());
1410 break;
1411 }
1412
1413 case CFGElement::AutomaticObjectDtor: {
1414 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1415
1416 const VarDecl *Var = DTor.getVarDecl();
1417 ConsumedState VarState = CurrStates->getState(Var);
1418
1419 if (VarState != CS_None) {
1420 PropagationInfo PInfo(Var);
1421
1422 Visitor.checkCallability(PInfo,
1423 DTor.getDestructorDecl(AC.getASTContext()),
1424 getLastStmtLoc(CurrBlock));
1425
1426 CurrStates->remove(Var);
1427 }
1428 break;
1429 }
1430
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001431 default:
1432 break;
1433 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001434 }
1435
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001436 // TODO: Handle other forms of branching with precision, including while-
1437 // and for-loops. (Deferred)
1438 if (!splitState(CurrBlock, Visitor)) {
1439 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001440
DeLesley Hutchins73858402013-10-09 18:30:24 +00001441 if (CurrBlock->succ_size() > 1 ||
1442 (CurrBlock->succ_size() == 1 &&
1443 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001444
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001445 bool OwnershipTaken = false;
1446
1447 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1448 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1449
DeLesley Hutchins73858402013-10-09 18:30:24 +00001450 if (*SI == NULL) continue;
1451
1452 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1453 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1454 CurrStates,
1455 WarningsHandler);
1456
1457 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1458 BlockInfo.discardInfo(*SI);
1459 } else {
1460 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1461 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001462 }
1463
1464 if (!OwnershipTaken)
1465 delete CurrStates;
1466
1467 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001468 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001469 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001470
1471 if (CurrBlock == &AC.getCFG()->getExit() &&
1472 D->getCallResultType()->isVoidType())
1473 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1474 WarningsHandler);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001475 } // End of block iterator.
1476
1477 // Delete the last existing state map.
1478 delete CurrStates;
1479
1480 WarningsHandler.emitDiagnostics();
1481}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001482}} // end namespace clang::consumed