blob: a7d747f705b2da5174770dbd004acd16906390a5 [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 Hutchins5fdd2072013-08-22 20:44:47 +0000162static bool isTestingFunction(const FunctionDecl *FunDecl) {
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000163 return FunDecl->hasAttr<TestsTypestateAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000164}
165
David Blaikiea33ab602013-09-06 01:28:43 +0000166static ConsumedState mapConsumableAttrState(const QualType QT) {
167 assert(isConsumableType(QT));
168
169 const ConsumableAttr *CAttr =
170 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
171
172 switch (CAttr->getDefaultState()) {
173 case ConsumableAttr::Unknown:
174 return CS_Unknown;
175 case ConsumableAttr::Unconsumed:
176 return CS_Unconsumed;
177 case ConsumableAttr::Consumed:
178 return CS_Consumed;
179 }
180 llvm_unreachable("invalid enum");
181}
182
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000183static ConsumedState
184mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
185 switch (PTAttr->getParamState()) {
186 case ParamTypestateAttr::Unknown:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000187 return CS_Unknown;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000188 case ParamTypestateAttr::Unconsumed:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000189 return CS_Unconsumed;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000190 case ParamTypestateAttr::Consumed:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000191 return CS_Consumed;
192 }
193 llvm_unreachable("invalid_enum");
194}
195
Eric Christophere988dc42013-09-03 20:43:00 +0000196static ConsumedState
197mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000198 switch (RTSAttr->getState()) {
199 case ReturnTypestateAttr::Unknown:
200 return CS_Unknown;
201 case ReturnTypestateAttr::Unconsumed:
202 return CS_Unconsumed;
203 case ReturnTypestateAttr::Consumed:
204 return CS_Consumed;
205 }
Eric Christophere988dc42013-09-03 20:43:00 +0000206 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000207}
208
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000209static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
210 switch (STAttr->getNewState()) {
211 case SetTypestateAttr::Unknown:
212 return CS_Unknown;
213 case SetTypestateAttr::Unconsumed:
214 return CS_Unconsumed;
215 case SetTypestateAttr::Consumed:
216 return CS_Consumed;
217 }
218 llvm_unreachable("invalid_enum");
219}
220
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000221static StringRef stateToString(ConsumedState State) {
222 switch (State) {
223 case consumed::CS_None:
224 return "none";
225
226 case consumed::CS_Unknown:
227 return "unknown";
228
229 case consumed::CS_Unconsumed:
230 return "unconsumed";
231
232 case consumed::CS_Consumed:
233 return "consumed";
234 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000235 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000236}
237
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000238static ConsumedState testsFor(const FunctionDecl *FunDecl) {
239 assert(isTestingFunction(FunDecl));
240 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) {
241 case TestsTypestateAttr::Unconsumed:
242 return CS_Unconsumed;
243 case TestsTypestateAttr::Consumed:
244 return CS_Consumed;
245 }
246 llvm_unreachable("invalid enum");
247}
248
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000249namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000250struct VarTestResult {
251 const VarDecl *Var;
252 ConsumedState TestsFor;
253};
254} // end anonymous::VarTestResult
255
256namespace clang {
257namespace consumed {
258
259enum EffectiveOp {
260 EO_And,
261 EO_Or
262};
263
264class PropagationInfo {
265 enum {
266 IT_None,
267 IT_State,
268 IT_Test,
269 IT_BinTest,
270 IT_Var
271 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000272
273 struct BinTestTy {
274 const BinaryOperator *Source;
275 EffectiveOp EOp;
276 VarTestResult LTest;
277 VarTestResult RTest;
278 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000279
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000280 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000281 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000282 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000283 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000284 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000285 };
286
DeLesley Hutchins66540852013-10-04 21:28:06 +0000287 QualType TempType;
288
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000289public:
290 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000291
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000292 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
293 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
294 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000295
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000296 Test.Var = Var;
297 Test.TestsFor = TestsFor;
298 }
299
300 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
301 const VarTestResult &LTest, const VarTestResult &RTest)
302 : InfoType(IT_BinTest) {
303
304 BinTest.Source = Source;
305 BinTest.EOp = EOp;
306 BinTest.LTest = LTest;
307 BinTest.RTest = RTest;
308 }
309
310 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
311 const VarDecl *LVar, ConsumedState LTestsFor,
312 const VarDecl *RVar, ConsumedState RTestsFor)
313 : InfoType(IT_BinTest) {
314
315 BinTest.Source = Source;
316 BinTest.EOp = EOp;
317 BinTest.LTest.Var = LVar;
318 BinTest.LTest.TestsFor = LTestsFor;
319 BinTest.RTest.Var = RVar;
320 BinTest.RTest.TestsFor = RTestsFor;
321 }
322
DeLesley Hutchins66540852013-10-04 21:28:06 +0000323 PropagationInfo(ConsumedState State, QualType TempType)
324 : InfoType(IT_State), State(State), TempType(TempType) {}
325
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000326 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
327
328 const ConsumedState & getState() const {
329 assert(InfoType == IT_State);
330 return State;
331 }
332
DeLesley Hutchins66540852013-10-04 21:28:06 +0000333 const QualType & getTempType() const {
334 assert(InfoType == IT_State);
335 return TempType;
336 }
337
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000338 const VarTestResult & getTest() const {
339 assert(InfoType == IT_Test);
340 return Test;
341 }
342
343 const VarTestResult & getLTest() const {
344 assert(InfoType == IT_BinTest);
345 return BinTest.LTest;
346 }
347
348 const VarTestResult & getRTest() const {
349 assert(InfoType == IT_BinTest);
350 return BinTest.RTest;
351 }
352
353 const VarDecl * getVar() const {
354 assert(InfoType == IT_Var);
355 return Var;
356 }
357
358 EffectiveOp testEffectiveOp() const {
359 assert(InfoType == IT_BinTest);
360 return BinTest.EOp;
361 }
362
363 const BinaryOperator * testSourceNode() const {
364 assert(InfoType == IT_BinTest);
365 return BinTest.Source;
366 }
367
368 bool isValid() const { return InfoType != IT_None; }
369 bool isState() const { return InfoType == IT_State; }
370 bool isTest() const { return InfoType == IT_Test; }
371 bool isBinTest() const { return InfoType == IT_BinTest; }
372 bool isVar() const { return InfoType == IT_Var; }
373
374 PropagationInfo invertTest() const {
375 assert(InfoType == IT_Test || InfoType == IT_BinTest);
376
377 if (InfoType == IT_Test) {
378 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
379
380 } else if (InfoType == IT_BinTest) {
381 return PropagationInfo(BinTest.Source,
382 BinTest.EOp == EO_And ? EO_Or : EO_And,
383 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
384 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
385 } else {
386 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000387 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000388 }
389};
390
391class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000392
393 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
394 typedef std::pair<const Stmt *, PropagationInfo> PairType;
395 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000396 typedef MapType::const_iterator ConstInfoEntry;
397
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000398 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000399 ConsumedAnalyzer &Analyzer;
400 ConsumedStateMap *StateMap;
401 MapType PropagationMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000402 void forwardInfo(const Stmt *From, const Stmt *To);
403 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000404 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
405 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000406
407public:
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000408 void checkCallability(const PropagationInfo &PInfo,
409 const FunctionDecl *FunDecl,
410 SourceLocation BlameLoc);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000411
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000412 void Visit(const Stmt *StmtNode);
413
414 void VisitBinaryOperator(const BinaryOperator *BinOp);
415 void VisitCallExpr(const CallExpr *Call);
416 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000417 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000418 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
419 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
420 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
421 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
422 void VisitDeclStmt(const DeclStmt *DelcS);
423 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
424 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000425 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000426 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000427 void VisitUnaryOperator(const UnaryOperator *UOp);
428 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000429
DeLesley Hutchins42525982013-08-29 22:36:05 +0000430 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
431 ConsumedStateMap *StateMap)
432 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000433
434 PropagationInfo getInfo(const Stmt *StmtNode) const {
435 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
436
437 if (Entry != PropagationMap.end())
438 return Entry->second;
439 else
440 return PropagationInfo();
441 }
442
443 void reset(ConsumedStateMap *NewStateMap) {
444 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000445 }
446};
447
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000448void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000449 const FunctionDecl *FunDecl,
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000450 SourceLocation BlameLoc) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000451
DeLesley Hutchins66540852013-10-04 21:28:06 +0000452 if (!FunDecl->hasAttr<CallableWhenAttr>())
453 return;
454
455 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000456
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000457 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000458 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000459 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000460
DeLesley Hutchins66540852013-10-04 21:28:06 +0000461 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000462
DeLesley Hutchins66540852013-10-04 21:28:06 +0000463 if (isCallableInState(CWAttr, VarState))
464 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000465
DeLesley Hutchins66540852013-10-04 21:28:06 +0000466 Analyzer.WarningsHandler.warnUseInInvalidState(
467 FunDecl->getNameAsString(), Var->getNameAsString(),
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000468 stateToString(VarState), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000469
DeLesley Hutchins66540852013-10-04 21:28:06 +0000470 } else if (PInfo.isState()) {
471
472 assert(PInfo.getState() != CS_None && "Invalid state");
473
474 if (isCallableInState(CWAttr, PInfo.getState()))
475 return;
476
477 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000478 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000479 }
480}
481
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000482void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
483 InfoEntry Entry = PropagationMap.find(From);
484
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000485 if (Entry != PropagationMap.end())
486 PropagationMap.insert(PairType(To, Entry->second));
487}
488
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000489bool ConsumedStmtVisitor::isLikeMoveAssignment(
490 const CXXMethodDecl *MethodDecl) {
491
492 return MethodDecl->isMoveAssignmentOperator() ||
493 (MethodDecl->getOverloadedOperator() == OO_Equal &&
494 MethodDecl->getNumParams() == 1 &&
495 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
496}
497
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000498void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
499 const FunctionDecl *Fun,
500 QualType ReturnType) {
501 if (isConsumableType(ReturnType)) {
502
503 ConsumedState ReturnState;
504
505 if (Fun->hasAttr<ReturnTypestateAttr>())
506 ReturnState = mapReturnTypestateAttrState(
507 Fun->getAttr<ReturnTypestateAttr>());
508 else
David Blaikiea33ab602013-09-06 01:28:43 +0000509 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000510
511 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000512 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000513 }
514}
515
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000516void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
517
518 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
519
520 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
521 CE = StmtNode->child_end(); CI != CE; ++CI) {
522
523 PropagationMap.erase(*CI);
524 }
525}
526
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000527void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
528 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000529 case BO_LAnd:
530 case BO_LOr : {
531 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
532 REntry = PropagationMap.find(BinOp->getRHS());
533
534 VarTestResult LTest, RTest;
535
536 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
537 LTest = LEntry->second.getTest();
538
539 } else {
540 LTest.Var = NULL;
541 LTest.TestsFor = CS_None;
542 }
543
544 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
545 RTest = REntry->second.getTest();
546
547 } else {
548 RTest.Var = NULL;
549 RTest.TestsFor = CS_None;
550 }
551
552 if (!(LTest.Var == NULL && RTest.Var == NULL))
553 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
554 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
555
556 break;
557 }
558
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000559 case BO_PtrMemD:
560 case BO_PtrMemI:
561 forwardInfo(BinOp->getLHS(), BinOp);
562 break;
563
564 default:
565 break;
566 }
567}
568
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000569void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
570 if (const FunctionDecl *FunDecl =
571 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
572
573 // Special case for the std::move function.
574 // TODO: Make this more specific. (Deferred)
575 if (FunDecl->getNameAsString() == "move") {
576 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
577
578 if (Entry != PropagationMap.end()) {
579 PropagationMap.insert(PairType(Call, Entry->second));
580 }
581
582 return;
583 }
584
585 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
586
587 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000588 const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
589 QualType ParamType = Param->getType();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000590
591 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
592
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000593 if (Entry == PropagationMap.end() ||
594 !(Entry->second.isState() || Entry->second.isVar()))
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000595 continue;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000596
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000597 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000598
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000599 // Check that the parameter is in the correct state.
600
601 if (Param->hasAttr<ParamTypestateAttr>()) {
602 ConsumedState ParamState =
603 PInfo.isState() ? PInfo.getState() :
604 StateMap->getState(PInfo.getVar());
605
606 ConsumedState ExpectedState =
607 mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
608
609 if (ParamState != ExpectedState)
610 Analyzer.WarningsHandler.warnParamTypestateMismatch(
611 Call->getArg(Index - Offset)->getExprLoc(),
612 stateToString(ExpectedState), stateToString(ParamState));
613 }
614
615 if (!Entry->second.isVar())
616 continue;
617
618 // Adjust state on the caller side.
619
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000620 if (ParamType->isRValueReferenceType() ||
621 (ParamType->isLValueReferenceType() &&
622 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
623
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000624 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000625
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000626 } else if (Param->hasAttr<ReturnTypestateAttr>()) {
627 StateMap->setState(PInfo.getVar(),
628 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
629
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000630 } else if (!(ParamType.isConstQualified() ||
631 ((ParamType->isReferenceType() ||
632 ParamType->isPointerType()) &&
633 ParamType->getPointeeType().isConstQualified()))) {
634
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000635 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000636 }
637 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000638
DeLesley Hutchins66540852013-10-04 21:28:06 +0000639 QualType RetType = FunDecl->getCallResultType();
640 if (RetType->isReferenceType())
641 RetType = RetType->getPointeeType();
642
643 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000644 }
645}
646
647void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000648 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000649}
650
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000651void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
652 const CXXBindTemporaryExpr *Temp) {
653
654 forwardInfo(Temp->getSubExpr(), Temp);
655}
656
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000657void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
658 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000659
660 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000661 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
662
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000663 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000664 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000665
666 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000667 PropagationInfo(consumed::CS_Consumed, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000668
669 } else if (Constructor->isMoveConstructor()) {
670
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000671 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000672 PropagationMap.find(Call->getArg(0))->second;
673
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000674 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000675 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000676
677 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000678 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000679
680 StateMap->setState(Var, consumed::CS_Consumed);
681
682 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000683 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000684 }
685
686 } else if (Constructor->isCopyConstructor()) {
687 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
688
689 if (Entry != PropagationMap.end())
690 PropagationMap.insert(PairType(Call, Entry->second));
691
692 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000693 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000694 }
695 }
696}
697
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000698
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000699void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
700 const CXXMemberCallExpr *Call) {
701
702 VisitCallExpr(Call);
703
704 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
705
706 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000707 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000708 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000709
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000710 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000711
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000712 if (PInfo.isVar()) {
713 if (isTestingFunction(MethodDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000714 PropagationMap.insert(PairType(Call,
715 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000716 else if (MethodDecl->hasAttr<SetTypestateAttr>())
717 StateMap->setState(PInfo.getVar(),
718 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000719 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000720 }
721}
722
723void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
724 const CXXOperatorCallExpr *Call) {
725
726 const FunctionDecl *FunDecl =
727 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
728
729 if (!FunDecl) return;
730
731 if (isa<CXXMethodDecl>(FunDecl) &&
732 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
733
734 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
735 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
736
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000737 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000738
739 if (LEntry != PropagationMap.end() &&
740 REntry != PropagationMap.end()) {
741
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000742 LPInfo = LEntry->second;
743 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000744
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000745 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000746 StateMap->setState(LPInfo.getVar(),
747 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000748
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000749 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000750
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000751 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000752
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000753 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000754 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000755
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000756 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000757
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000758 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000759 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000760 PropagationInfo(StateMap->getState(RPInfo.getVar()),
761 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000762
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000763 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000764
765 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000766 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000767 }
768
769 } else if (LEntry != PropagationMap.end() &&
770 REntry == PropagationMap.end()) {
771
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000772 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000773
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000774 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000775 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000776
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000777 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000778
DeLesley Hutchins66540852013-10-04 21:28:06 +0000779 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000780 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000781 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000782 }
783
784 } else if (LEntry == PropagationMap.end() &&
785 REntry != PropagationMap.end()) {
786
DeLesley Hutchins66540852013-10-04 21:28:06 +0000787 if (REntry->second.isVar())
788 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000789 }
790
791 } else {
792
793 VisitCallExpr(Call);
794
795 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
796
797 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000798 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000799
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000800 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000801
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000802 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000803 if (isTestingFunction(FunDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000804 PropagationMap.insert(PairType(Call,
805 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000806 else if (FunDecl->hasAttr<SetTypestateAttr>())
807 StateMap->setState(PInfo.getVar(),
808 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000809 }
810 }
811 }
812}
813
814void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
815 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
816 if (StateMap->getState(Var) != consumed::CS_None)
817 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
818}
819
820void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
821 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
822 DE = DeclS->decl_end(); DI != DE; ++DI) {
823
824 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
825 }
826
827 if (DeclS->isSingleDecl())
828 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
829 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
830}
831
832void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
833 const MaterializeTemporaryExpr *Temp) {
834
835 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
836
837 if (Entry != PropagationMap.end())
838 PropagationMap.insert(PairType(Temp, Entry->second));
839}
840
841void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
842 forwardInfo(MExpr->getBase(), MExpr);
843}
844
DeLesley Hutchins42525982013-08-29 22:36:05 +0000845
846void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000847 QualType ParamType = Param->getType();
848 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000849
850 if (Param->hasAttr<ParamTypestateAttr>()) {
851 ParamState =
852 mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
853
854 } else if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
855 isConsumableType(ParamType)) {
856
David Blaikiea33ab602013-09-06 01:28:43 +0000857 ParamState = mapConsumableAttrState(ParamType);
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000858
859 } else if (ParamType->isReferenceType() &&
860 isConsumableType(ParamType->getPointeeType())) {
David Blaikiea33ab602013-09-06 01:28:43 +0000861 ParamState = consumed::CS_Unknown;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000862 }
863
864 if (ParamState != CS_None)
David Blaikiea33ab602013-09-06 01:28:43 +0000865 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000866}
867
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000868void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000869 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
870
871 if (ExpectedState != CS_None) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000872 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
873
874 if (Entry != PropagationMap.end()) {
875 assert(Entry->second.isState() || Entry->second.isVar());
876
877 ConsumedState RetState = Entry->second.isState() ?
878 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
879
880 if (RetState != ExpectedState)
881 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
882 Ret->getReturnLoc(), stateToString(ExpectedState),
883 stateToString(RetState));
884 }
885 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000886
887 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
888 Analyzer.WarningsHandler);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000889}
890
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000891void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000892 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
893 if (Entry == PropagationMap.end()) return;
894
895 switch (UOp->getOpcode()) {
896 case UO_AddrOf:
897 PropagationMap.insert(PairType(UOp, Entry->second));
898 break;
899
900 case UO_LNot:
901 if (Entry->second.isTest() || Entry->second.isBinTest())
902 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
903 break;
904
905 default:
906 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000907 }
908}
909
DeLesley Hutchins66540852013-10-04 21:28:06 +0000910// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000911void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000912 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000913 if (Var->hasInit()) {
914 PropagationInfo PInfo =
915 PropagationMap.find(Var->getInit())->second;
916
917 StateMap->setState(Var, PInfo.isVar() ?
918 StateMap->getState(PInfo.getVar()) : PInfo.getState());
919
920 } else {
921 StateMap->setState(Var, consumed::CS_Unknown);
922 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000923 }
924}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000925}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000926
927namespace clang {
928namespace consumed {
929
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000930void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
931 ConsumedStateMap *ThenStates,
932 ConsumedStateMap *ElseStates) {
933
934 ConsumedState VarState = ThenStates->getState(Test.Var);
935
936 if (VarState == CS_Unknown) {
937 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000938 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000939
940 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
941 ThenStates->markUnreachable();
942
DeLesley Hutchins66540852013-10-04 21:28:06 +0000943 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000944 ElseStates->markUnreachable();
945 }
946}
947
948void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
949 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
950
951 const VarTestResult &LTest = PInfo.getLTest(),
952 &RTest = PInfo.getRTest();
953
954 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
955 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
956
957 if (LTest.Var) {
958 if (PInfo.testEffectiveOp() == EO_And) {
959 if (LState == CS_Unknown) {
960 ThenStates->setState(LTest.Var, LTest.TestsFor);
961
962 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
963 ThenStates->markUnreachable();
964
965 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000966 if (RState == RTest.TestsFor)
967 ElseStates->markUnreachable();
968 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000969 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000970 }
971
972 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000973 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000974 ElseStates->setState(LTest.Var,
975 invertConsumedUnconsumed(LTest.TestsFor));
976
DeLesley Hutchins66540852013-10-04 21:28:06 +0000977 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000978 ElseStates->markUnreachable();
979
980 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
981 isKnownState(RState)) {
982
DeLesley Hutchins66540852013-10-04 21:28:06 +0000983 if (RState == RTest.TestsFor)
984 ElseStates->markUnreachable();
985 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000986 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000987 }
988 }
989 }
990
991 if (RTest.Var) {
992 if (PInfo.testEffectiveOp() == EO_And) {
993 if (RState == CS_Unknown)
994 ThenStates->setState(RTest.Var, RTest.TestsFor);
995 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
996 ThenStates->markUnreachable();
997
DeLesley Hutchins66540852013-10-04 21:28:06 +0000998 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000999 if (RState == CS_Unknown)
1000 ElseStates->setState(RTest.Var,
1001 invertConsumedUnconsumed(RTest.TestsFor));
1002 else if (RState == RTest.TestsFor)
1003 ElseStates->markUnreachable();
1004 }
1005 }
1006}
1007
DeLesley Hutchins73858402013-10-09 18:30:24 +00001008bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1009 const CFGBlock *TargetBlock) {
1010
1011 assert(CurrBlock && "Block pointer must not be NULL");
1012 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1013
1014 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1015 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1016 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1017 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1018 return false;
1019 }
1020 return true;
1021}
1022
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001023void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1024 ConsumedStateMap *StateMap,
1025 bool &AlreadyOwned) {
1026
DeLesley Hutchins73858402013-10-09 18:30:24 +00001027 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001028
1029 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1030
1031 if (Entry) {
1032 Entry->intersect(StateMap);
1033
1034 } else if (AlreadyOwned) {
1035 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
1036
1037 } else {
1038 StateMapsArray[Block->getBlockID()] = StateMap;
1039 AlreadyOwned = true;
1040 }
1041}
1042
1043void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1044 ConsumedStateMap *StateMap) {
1045
DeLesley Hutchins73858402013-10-09 18:30:24 +00001046 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001047
1048 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1049
1050 if (Entry) {
1051 Entry->intersect(StateMap);
1052 delete StateMap;
1053
1054 } else {
1055 StateMapsArray[Block->getBlockID()] = StateMap;
1056 }
1057}
1058
DeLesley Hutchins73858402013-10-09 18:30:24 +00001059ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1060 assert(Block && "Block pointer must not be NULL");
1061 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1062
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001063 return StateMapsArray[Block->getBlockID()];
1064}
1065
DeLesley Hutchins73858402013-10-09 18:30:24 +00001066void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1067 unsigned int BlockID = Block->getBlockID();
1068 delete StateMapsArray[BlockID];
1069 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001070}
1071
DeLesley Hutchins73858402013-10-09 18:30:24 +00001072ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1073 assert(Block && "Block pointer must not be NULL");
1074
1075 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1076 if (isBackEdgeTarget(Block)) {
1077 return new ConsumedStateMap(*StateMap);
1078 } else {
1079 StateMapsArray[Block->getBlockID()] = NULL;
1080 return StateMap;
1081 }
1082}
1083
1084bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1085 assert(From && "From block must not be NULL");
1086 assert(To && "From block must not be NULL");
1087
1088 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1089}
1090
1091bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1092 assert(Block != NULL && "Block pointer must not be NULL");
1093
1094 // Anything with less than two predecessors can't be the target of a back
1095 // edge.
1096 if (Block->pred_size() < 2)
1097 return false;
1098
1099 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1100 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1101 PE = Block->pred_end(); PI != PE; ++PI) {
1102 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1103 return true;
1104 }
1105 return false;
1106}
1107
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001108void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1109 ConsumedWarningsHandlerBase &WarningsHandler) const {
1110
1111 ConsumedState ExpectedState;
1112
1113 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
1114 ++DMI) {
1115
1116 if (isa<ParmVarDecl>(DMI->first)) {
1117 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
1118
1119 if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
1120
1121 ExpectedState =
1122 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
1123
1124 if (DMI->second != ExpectedState) {
1125 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1126 Param->getNameAsString(), stateToString(ExpectedState),
1127 stateToString(DMI->second));
1128 }
1129 }
1130 }
1131}
1132
DeLesley Hutchins73858402013-10-09 18:30:24 +00001133ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001134 MapType::const_iterator Entry = Map.find(Var);
1135
1136 if (Entry != Map.end()) {
1137 return Entry->second;
1138
1139 } else {
1140 return CS_None;
1141 }
1142}
1143
1144void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1145 ConsumedState LocalState;
1146
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001147 if (this->From && this->From == Other->From && !Other->Reachable) {
1148 this->markUnreachable();
1149 return;
1150 }
1151
DeLesley Hutchins73858402013-10-09 18:30:24 +00001152 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1153 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001154
1155 LocalState = this->getState(DMI->first);
1156
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001157 if (LocalState == CS_None)
1158 continue;
1159
1160 if (LocalState != DMI->second)
1161 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001162 }
1163}
1164
DeLesley Hutchins73858402013-10-09 18:30:24 +00001165void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1166 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1167 ConsumedWarningsHandlerBase &WarningsHandler) {
1168
1169 ConsumedState LocalState;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001170 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001171
1172 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1173 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1174
1175 LocalState = this->getState(DMI->first);
1176
1177 if (LocalState == CS_None)
1178 continue;
1179
1180 if (LocalState != DMI->second) {
1181 Map[DMI->first] = CS_Unknown;
1182 WarningsHandler.warnLoopStateMismatch(
1183 BlameLoc, DMI->first->getNameAsString());
1184 }
1185 }
1186}
1187
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001188void ConsumedStateMap::markUnreachable() {
1189 this->Reachable = false;
1190 Map.clear();
1191}
1192
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001193void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1194 Map[Var] = State;
1195}
1196
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001197void ConsumedStateMap::remove(const VarDecl *Var) {
1198 Map.erase(Var);
1199}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001200
DeLesley Hutchins73858402013-10-09 18:30:24 +00001201bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1202 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1203 DMI != DME; ++DMI) {
1204
1205 if (this->getState(DMI->first) != DMI->second)
1206 return true;
1207 }
1208
1209 return false;
1210}
1211
David Blaikiea33ab602013-09-06 01:28:43 +00001212void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1213 const FunctionDecl *D) {
1214 QualType ReturnType;
1215 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1216 ASTContext &CurrContext = AC.getASTContext();
1217 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1218 } else
1219 ReturnType = D->getCallResultType();
1220
1221 if (D->hasAttr<ReturnTypestateAttr>()) {
1222 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1223
1224 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1225 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1226 // FIXME: This should be removed when template instantiation propagates
1227 // attributes at template specialization definition, not
1228 // declaration. When it is removed the test needs to be enabled
1229 // in SemaDeclAttr.cpp.
1230 WarningsHandler.warnReturnTypestateForUnconsumableType(
1231 RTSAttr->getLocation(), ReturnType.getAsString());
1232 ExpectedReturnState = CS_None;
1233 } else
1234 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1235 } else if (isConsumableType(ReturnType))
1236 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1237 else
1238 ExpectedReturnState = CS_None;
1239}
1240
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001241bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1242 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001243
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001244 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1245 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001246
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001247 if (const IfStmt *IfNode =
1248 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001249
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001250 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001251
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001252 PInfo = Visitor.getInfo(Cond);
1253 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1254 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1255
1256 if (PInfo.isTest()) {
1257 CurrStates->setSource(Cond);
1258 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001259 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001260
1261 } else if (PInfo.isBinTest()) {
1262 CurrStates->setSource(PInfo.testSourceNode());
1263 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001264 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001265
1266 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001267 delete FalseStates;
1268 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001269 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001270
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001271 } else if (const BinaryOperator *BinOp =
1272 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1273
1274 PInfo = Visitor.getInfo(BinOp->getLHS());
1275 if (!PInfo.isTest()) {
1276 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1277 PInfo = Visitor.getInfo(BinOp->getRHS());
1278
1279 if (!PInfo.isTest()) {
1280 delete FalseStates;
1281 return false;
1282 }
1283
1284 } else {
1285 delete FalseStates;
1286 return false;
1287 }
1288 }
1289
1290 CurrStates->setSource(BinOp);
1291 FalseStates->setSource(BinOp);
1292
1293 const VarTestResult &Test = PInfo.getTest();
1294 ConsumedState VarState = CurrStates->getState(Test.Var);
1295
1296 if (BinOp->getOpcode() == BO_LAnd) {
1297 if (VarState == CS_Unknown)
1298 CurrStates->setState(Test.Var, Test.TestsFor);
1299 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1300 CurrStates->markUnreachable();
1301
1302 } else if (BinOp->getOpcode() == BO_LOr) {
1303 if (VarState == CS_Unknown)
1304 FalseStates->setState(Test.Var,
1305 invertConsumedUnconsumed(Test.TestsFor));
1306 else if (VarState == Test.TestsFor)
1307 FalseStates->markUnreachable();
1308 }
1309
1310 } else {
1311 delete FalseStates;
1312 return false;
1313 }
1314
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001315 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1316
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001317 if (*SI)
1318 BlockInfo.addInfo(*SI, CurrStates);
1319 else
1320 delete CurrStates;
1321
1322 if (*++SI)
1323 BlockInfo.addInfo(*SI, FalseStates);
1324 else
1325 delete FalseStates;
1326
1327 CurrStates = NULL;
1328 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001329}
1330
1331void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1332 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001333 if (!D)
1334 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001335
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001336 CFG *CFGraph = AC.getCFG();
1337 if (!CFGraph)
1338 return;
DeLesley Hutchins52f717e2013-10-17 18:19:31 +00001339
David Blaikiea33ab602013-09-06 01:28:43 +00001340 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001341
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001342 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001343 // AC.getCFG()->viewCFG(LangOptions());
1344
1345 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001346
1347 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001348 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1349
1350 // Add all trackable parameters to the state map.
1351 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1352 PE = D->param_end(); PI != PE; ++PI) {
1353 Visitor.VisitParmVarDecl(*PI);
1354 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001355
1356 // Visit all of the function's basic blocks.
1357 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1358 E = SortedGraph->end(); I != E; ++I) {
1359
1360 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001361
1362 if (CurrStates == NULL)
1363 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001364
1365 if (!CurrStates) {
1366 continue;
1367
1368 } else if (!CurrStates->isReachable()) {
1369 delete CurrStates;
1370 CurrStates = NULL;
1371 continue;
1372 }
1373
1374 Visitor.reset(CurrStates);
1375
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001376 // Visit all of the basic block's statements.
1377 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1378 BE = CurrBlock->end(); BI != BE; ++BI) {
1379
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001380 switch (BI->getKind()) {
1381 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001382 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001383 break;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001384
1385 case CFGElement::TemporaryDtor: {
1386 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1387 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1388 PropagationInfo PInfo = Visitor.getInfo(BTE);
1389
1390 if (PInfo.isValid())
1391 Visitor.checkCallability(PInfo,
1392 DTor.getDestructorDecl(AC.getASTContext()),
1393 BTE->getExprLoc());
1394 break;
1395 }
1396
1397 case CFGElement::AutomaticObjectDtor: {
1398 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1399
1400 const VarDecl *Var = DTor.getVarDecl();
1401 ConsumedState VarState = CurrStates->getState(Var);
1402
1403 if (VarState != CS_None) {
1404 PropagationInfo PInfo(Var);
1405
1406 Visitor.checkCallability(PInfo,
1407 DTor.getDestructorDecl(AC.getASTContext()),
1408 getLastStmtLoc(CurrBlock));
1409
1410 CurrStates->remove(Var);
1411 }
1412 break;
1413 }
1414
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001415 default:
1416 break;
1417 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001418 }
1419
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001420 // TODO: Handle other forms of branching with precision, including while-
1421 // and for-loops. (Deferred)
1422 if (!splitState(CurrBlock, Visitor)) {
1423 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001424
DeLesley Hutchins73858402013-10-09 18:30:24 +00001425 if (CurrBlock->succ_size() > 1 ||
1426 (CurrBlock->succ_size() == 1 &&
1427 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001428
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001429 bool OwnershipTaken = false;
1430
1431 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1432 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1433
DeLesley Hutchins73858402013-10-09 18:30:24 +00001434 if (*SI == NULL) continue;
1435
1436 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1437 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1438 CurrStates,
1439 WarningsHandler);
1440
1441 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1442 BlockInfo.discardInfo(*SI);
1443 } else {
1444 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1445 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001446 }
1447
1448 if (!OwnershipTaken)
1449 delete CurrStates;
1450
1451 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001452 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001453 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001454
1455 if (CurrBlock == &AC.getCFG()->getExit() &&
1456 D->getCallResultType()->isVoidType())
1457 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1458 WarningsHandler);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001459 } // End of block iterator.
1460
1461 // Delete the last existing state map.
1462 delete CurrStates;
1463
1464 WarningsHandler.emitDiagnostics();
1465}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001466}} // end namespace clang::consumed