blob: 021c26dff2f014241b1c1a4254ea4a69728399ef [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 Hutchinsf30e1942013-10-11 23:03:26 +0000183static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
184 switch (STAttr->getNewState()) {
185 case SetTypestateAttr::Unknown:
186 return CS_Unknown;
187 case SetTypestateAttr::Unconsumed:
188 return CS_Unconsumed;
189 case SetTypestateAttr::Consumed:
190 return CS_Consumed;
191 }
192 llvm_unreachable("invalid_enum");
193}
194
Eric Christophere988dc42013-09-03 20:43:00 +0000195static ConsumedState
196mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000197 switch (RTSAttr->getState()) {
198 case ReturnTypestateAttr::Unknown:
199 return CS_Unknown;
200 case ReturnTypestateAttr::Unconsumed:
201 return CS_Unconsumed;
202 case ReturnTypestateAttr::Consumed:
203 return CS_Consumed;
204 }
Eric Christophere988dc42013-09-03 20:43:00 +0000205 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000206}
207
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000208static StringRef stateToString(ConsumedState State) {
209 switch (State) {
210 case consumed::CS_None:
211 return "none";
212
213 case consumed::CS_Unknown:
214 return "unknown";
215
216 case consumed::CS_Unconsumed:
217 return "unconsumed";
218
219 case consumed::CS_Consumed:
220 return "consumed";
221 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000222 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000223}
224
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000225static ConsumedState testsFor(const FunctionDecl *FunDecl) {
226 assert(isTestingFunction(FunDecl));
227 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) {
228 case TestsTypestateAttr::Unconsumed:
229 return CS_Unconsumed;
230 case TestsTypestateAttr::Consumed:
231 return CS_Consumed;
232 }
233 llvm_unreachable("invalid enum");
234}
235
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000236namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000237struct VarTestResult {
238 const VarDecl *Var;
239 ConsumedState TestsFor;
240};
241} // end anonymous::VarTestResult
242
243namespace clang {
244namespace consumed {
245
246enum EffectiveOp {
247 EO_And,
248 EO_Or
249};
250
251class PropagationInfo {
252 enum {
253 IT_None,
254 IT_State,
255 IT_Test,
256 IT_BinTest,
257 IT_Var
258 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000259
260 struct BinTestTy {
261 const BinaryOperator *Source;
262 EffectiveOp EOp;
263 VarTestResult LTest;
264 VarTestResult RTest;
265 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000266
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000267 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000268 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000269 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000270 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000271 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000272 };
273
DeLesley Hutchins66540852013-10-04 21:28:06 +0000274 QualType TempType;
275
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000276public:
277 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000278
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000279 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
280 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
281 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000282
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000283 Test.Var = Var;
284 Test.TestsFor = TestsFor;
285 }
286
287 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
288 const VarTestResult &LTest, const VarTestResult &RTest)
289 : InfoType(IT_BinTest) {
290
291 BinTest.Source = Source;
292 BinTest.EOp = EOp;
293 BinTest.LTest = LTest;
294 BinTest.RTest = RTest;
295 }
296
297 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
298 const VarDecl *LVar, ConsumedState LTestsFor,
299 const VarDecl *RVar, ConsumedState RTestsFor)
300 : InfoType(IT_BinTest) {
301
302 BinTest.Source = Source;
303 BinTest.EOp = EOp;
304 BinTest.LTest.Var = LVar;
305 BinTest.LTest.TestsFor = LTestsFor;
306 BinTest.RTest.Var = RVar;
307 BinTest.RTest.TestsFor = RTestsFor;
308 }
309
DeLesley Hutchins66540852013-10-04 21:28:06 +0000310 PropagationInfo(ConsumedState State, QualType TempType)
311 : InfoType(IT_State), State(State), TempType(TempType) {}
312
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000313 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
314
315 const ConsumedState & getState() const {
316 assert(InfoType == IT_State);
317 return State;
318 }
319
DeLesley Hutchins66540852013-10-04 21:28:06 +0000320 const QualType & getTempType() const {
321 assert(InfoType == IT_State);
322 return TempType;
323 }
324
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000325 const VarTestResult & getTest() const {
326 assert(InfoType == IT_Test);
327 return Test;
328 }
329
330 const VarTestResult & getLTest() const {
331 assert(InfoType == IT_BinTest);
332 return BinTest.LTest;
333 }
334
335 const VarTestResult & getRTest() const {
336 assert(InfoType == IT_BinTest);
337 return BinTest.RTest;
338 }
339
340 const VarDecl * getVar() const {
341 assert(InfoType == IT_Var);
342 return Var;
343 }
344
345 EffectiveOp testEffectiveOp() const {
346 assert(InfoType == IT_BinTest);
347 return BinTest.EOp;
348 }
349
350 const BinaryOperator * testSourceNode() const {
351 assert(InfoType == IT_BinTest);
352 return BinTest.Source;
353 }
354
355 bool isValid() const { return InfoType != IT_None; }
356 bool isState() const { return InfoType == IT_State; }
357 bool isTest() const { return InfoType == IT_Test; }
358 bool isBinTest() const { return InfoType == IT_BinTest; }
359 bool isVar() const { return InfoType == IT_Var; }
360
361 PropagationInfo invertTest() const {
362 assert(InfoType == IT_Test || InfoType == IT_BinTest);
363
364 if (InfoType == IT_Test) {
365 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
366
367 } else if (InfoType == IT_BinTest) {
368 return PropagationInfo(BinTest.Source,
369 BinTest.EOp == EO_And ? EO_Or : EO_And,
370 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
371 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
372 } else {
373 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000374 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000375 }
376};
377
378class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000379
380 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
381 typedef std::pair<const Stmt *, PropagationInfo> PairType;
382 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000383 typedef MapType::const_iterator ConstInfoEntry;
384
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000385 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000386 ConsumedAnalyzer &Analyzer;
387 ConsumedStateMap *StateMap;
388 MapType PropagationMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000389 void forwardInfo(const Stmt *From, const Stmt *To);
390 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000391 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
392 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000393
394public:
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000395 void checkCallability(const PropagationInfo &PInfo,
396 const FunctionDecl *FunDecl,
397 SourceLocation BlameLoc);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000398
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000399 void Visit(const Stmt *StmtNode);
400
401 void VisitBinaryOperator(const BinaryOperator *BinOp);
402 void VisitCallExpr(const CallExpr *Call);
403 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000404 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000405 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
406 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
407 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
408 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
409 void VisitDeclStmt(const DeclStmt *DelcS);
410 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
411 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000412 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000413 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000414 void VisitUnaryOperator(const UnaryOperator *UOp);
415 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000416
DeLesley Hutchins42525982013-08-29 22:36:05 +0000417 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
418 ConsumedStateMap *StateMap)
419 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000420
421 PropagationInfo getInfo(const Stmt *StmtNode) const {
422 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
423
424 if (Entry != PropagationMap.end())
425 return Entry->second;
426 else
427 return PropagationInfo();
428 }
429
430 void reset(ConsumedStateMap *NewStateMap) {
431 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000432 }
433};
434
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000435void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000436 const FunctionDecl *FunDecl,
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000437 SourceLocation BlameLoc) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000438
DeLesley Hutchins66540852013-10-04 21:28:06 +0000439 if (!FunDecl->hasAttr<CallableWhenAttr>())
440 return;
441
442 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000443
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000444 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000445 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000446 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000447
DeLesley Hutchins66540852013-10-04 21:28:06 +0000448 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000449
DeLesley Hutchins66540852013-10-04 21:28:06 +0000450 if (isCallableInState(CWAttr, VarState))
451 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000452
DeLesley Hutchins66540852013-10-04 21:28:06 +0000453 Analyzer.WarningsHandler.warnUseInInvalidState(
454 FunDecl->getNameAsString(), Var->getNameAsString(),
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000455 stateToString(VarState), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000456
DeLesley Hutchins66540852013-10-04 21:28:06 +0000457 } else if (PInfo.isState()) {
458
459 assert(PInfo.getState() != CS_None && "Invalid state");
460
461 if (isCallableInState(CWAttr, PInfo.getState()))
462 return;
463
464 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000465 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000466 }
467}
468
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000469void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
470 InfoEntry Entry = PropagationMap.find(From);
471
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000472 if (Entry != PropagationMap.end())
473 PropagationMap.insert(PairType(To, Entry->second));
474}
475
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000476bool ConsumedStmtVisitor::isLikeMoveAssignment(
477 const CXXMethodDecl *MethodDecl) {
478
479 return MethodDecl->isMoveAssignmentOperator() ||
480 (MethodDecl->getOverloadedOperator() == OO_Equal &&
481 MethodDecl->getNumParams() == 1 &&
482 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
483}
484
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000485void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
486 const FunctionDecl *Fun,
487 QualType ReturnType) {
488 if (isConsumableType(ReturnType)) {
489
490 ConsumedState ReturnState;
491
492 if (Fun->hasAttr<ReturnTypestateAttr>())
493 ReturnState = mapReturnTypestateAttrState(
494 Fun->getAttr<ReturnTypestateAttr>());
495 else
David Blaikiea33ab602013-09-06 01:28:43 +0000496 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000497
498 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000499 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000500 }
501}
502
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000503void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
504
505 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
506
507 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
508 CE = StmtNode->child_end(); CI != CE; ++CI) {
509
510 PropagationMap.erase(*CI);
511 }
512}
513
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000514void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
515 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000516 case BO_LAnd:
517 case BO_LOr : {
518 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
519 REntry = PropagationMap.find(BinOp->getRHS());
520
521 VarTestResult LTest, RTest;
522
523 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
524 LTest = LEntry->second.getTest();
525
526 } else {
527 LTest.Var = NULL;
528 LTest.TestsFor = CS_None;
529 }
530
531 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
532 RTest = REntry->second.getTest();
533
534 } else {
535 RTest.Var = NULL;
536 RTest.TestsFor = CS_None;
537 }
538
539 if (!(LTest.Var == NULL && RTest.Var == NULL))
540 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
541 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
542
543 break;
544 }
545
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000546 case BO_PtrMemD:
547 case BO_PtrMemI:
548 forwardInfo(BinOp->getLHS(), BinOp);
549 break;
550
551 default:
552 break;
553 }
554}
555
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000556void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
557 if (const FunctionDecl *FunDecl =
558 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
559
560 // Special case for the std::move function.
561 // TODO: Make this more specific. (Deferred)
562 if (FunDecl->getNameAsString() == "move") {
563 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
564
565 if (Entry != PropagationMap.end()) {
566 PropagationMap.insert(PairType(Call, Entry->second));
567 }
568
569 return;
570 }
571
572 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
573
574 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000575 const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
576 QualType ParamType = Param->getType();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000577
578 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
579
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000580 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000581 continue;
582 }
583
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000584 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000585
586 if (ParamType->isRValueReferenceType() ||
587 (ParamType->isLValueReferenceType() &&
588 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
589
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000590 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000591
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000592 } else if (Param->hasAttr<ReturnTypestateAttr>()) {
593 StateMap->setState(PInfo.getVar(),
594 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
595
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000596 } else if (!(ParamType.isConstQualified() ||
597 ((ParamType->isReferenceType() ||
598 ParamType->isPointerType()) &&
599 ParamType->getPointeeType().isConstQualified()))) {
600
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000601 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000602 }
603 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000604
DeLesley Hutchins66540852013-10-04 21:28:06 +0000605 QualType RetType = FunDecl->getCallResultType();
606 if (RetType->isReferenceType())
607 RetType = RetType->getPointeeType();
608
609 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000610 }
611}
612
613void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000614 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000615}
616
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000617void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
618 const CXXBindTemporaryExpr *Temp) {
619
620 forwardInfo(Temp->getSubExpr(), Temp);
621}
622
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000623void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
624 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000625
626 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000627 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
628
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000629 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000630 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000631
632 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000633 PropagationInfo(consumed::CS_Consumed, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000634
635 } else if (Constructor->isMoveConstructor()) {
636
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000637 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000638 PropagationMap.find(Call->getArg(0))->second;
639
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000640 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000641 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000642
643 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000644 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000645
646 StateMap->setState(Var, consumed::CS_Consumed);
647
648 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000649 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000650 }
651
652 } else if (Constructor->isCopyConstructor()) {
653 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
654
655 if (Entry != PropagationMap.end())
656 PropagationMap.insert(PairType(Call, Entry->second));
657
658 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000659 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000660 }
661 }
662}
663
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000664
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000665void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
666 const CXXMemberCallExpr *Call) {
667
668 VisitCallExpr(Call);
669
670 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
671
672 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000673 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000674 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000675
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000676 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000677
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000678 if (PInfo.isVar()) {
679 if (isTestingFunction(MethodDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000680 PropagationMap.insert(PairType(Call,
681 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000682 else if (MethodDecl->hasAttr<SetTypestateAttr>())
683 StateMap->setState(PInfo.getVar(),
684 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000685 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000686 }
687}
688
689void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
690 const CXXOperatorCallExpr *Call) {
691
692 const FunctionDecl *FunDecl =
693 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
694
695 if (!FunDecl) return;
696
697 if (isa<CXXMethodDecl>(FunDecl) &&
698 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
699
700 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
701 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
702
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000703 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000704
705 if (LEntry != PropagationMap.end() &&
706 REntry != PropagationMap.end()) {
707
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000708 LPInfo = LEntry->second;
709 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000710
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000711 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000712 StateMap->setState(LPInfo.getVar(),
713 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000714
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000715 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000716
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000717 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000718
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000719 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000720 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000721
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000722 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000723
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000724 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000725 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000726 PropagationInfo(StateMap->getState(RPInfo.getVar()),
727 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000728
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000729 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000730
731 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000732 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000733 }
734
735 } else if (LEntry != PropagationMap.end() &&
736 REntry == PropagationMap.end()) {
737
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000738 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000739
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000740 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000741 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000742
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000743 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000744
DeLesley Hutchins66540852013-10-04 21:28:06 +0000745 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000746 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000747 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000748 }
749
750 } else if (LEntry == PropagationMap.end() &&
751 REntry != PropagationMap.end()) {
752
DeLesley Hutchins66540852013-10-04 21:28:06 +0000753 if (REntry->second.isVar())
754 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000755 }
756
757 } else {
758
759 VisitCallExpr(Call);
760
761 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
762
763 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000764 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000765
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000766 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000767
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000768 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000769 if (isTestingFunction(FunDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000770 PropagationMap.insert(PairType(Call,
771 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000772 else if (FunDecl->hasAttr<SetTypestateAttr>())
773 StateMap->setState(PInfo.getVar(),
774 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000775 }
776 }
777 }
778}
779
780void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
781 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
782 if (StateMap->getState(Var) != consumed::CS_None)
783 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
784}
785
786void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
787 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
788 DE = DeclS->decl_end(); DI != DE; ++DI) {
789
790 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
791 }
792
793 if (DeclS->isSingleDecl())
794 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
795 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
796}
797
798void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
799 const MaterializeTemporaryExpr *Temp) {
800
801 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
802
803 if (Entry != PropagationMap.end())
804 PropagationMap.insert(PairType(Temp, Entry->second));
805}
806
807void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
808 forwardInfo(MExpr->getBase(), MExpr);
809}
810
DeLesley Hutchins42525982013-08-29 22:36:05 +0000811
812void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000813 QualType ParamType = Param->getType();
814 ConsumedState ParamState = consumed::CS_None;
815
816 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
817 isConsumableType(ParamType))
818 ParamState = mapConsumableAttrState(ParamType);
819 else if (ParamType->isReferenceType() &&
820 isConsumableType(ParamType->getPointeeType()))
821 ParamState = consumed::CS_Unknown;
822
823 if (ParamState)
824 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000825}
826
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000827void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000828 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
829
830 if (ExpectedState != CS_None) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000831 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
832
833 if (Entry != PropagationMap.end()) {
834 assert(Entry->second.isState() || Entry->second.isVar());
835
836 ConsumedState RetState = Entry->second.isState() ?
837 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
838
839 if (RetState != ExpectedState)
840 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
841 Ret->getReturnLoc(), stateToString(ExpectedState),
842 stateToString(RetState));
843 }
844 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000845
846 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
847 Analyzer.WarningsHandler);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000848}
849
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000850void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000851 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
852 if (Entry == PropagationMap.end()) return;
853
854 switch (UOp->getOpcode()) {
855 case UO_AddrOf:
856 PropagationMap.insert(PairType(UOp, Entry->second));
857 break;
858
859 case UO_LNot:
860 if (Entry->second.isTest() || Entry->second.isBinTest())
861 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
862 break;
863
864 default:
865 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000866 }
867}
868
DeLesley Hutchins66540852013-10-04 21:28:06 +0000869// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000870void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000871 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000872 if (Var->hasInit()) {
873 PropagationInfo PInfo =
874 PropagationMap.find(Var->getInit())->second;
875
876 StateMap->setState(Var, PInfo.isVar() ?
877 StateMap->getState(PInfo.getVar()) : PInfo.getState());
878
879 } else {
880 StateMap->setState(Var, consumed::CS_Unknown);
881 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000882 }
883}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000884}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000885
886namespace clang {
887namespace consumed {
888
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000889void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
890 ConsumedStateMap *ThenStates,
891 ConsumedStateMap *ElseStates) {
892
893 ConsumedState VarState = ThenStates->getState(Test.Var);
894
895 if (VarState == CS_Unknown) {
896 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000897 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000898
899 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
900 ThenStates->markUnreachable();
901
DeLesley Hutchins66540852013-10-04 21:28:06 +0000902 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000903 ElseStates->markUnreachable();
904 }
905}
906
907void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
908 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
909
910 const VarTestResult &LTest = PInfo.getLTest(),
911 &RTest = PInfo.getRTest();
912
913 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
914 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
915
916 if (LTest.Var) {
917 if (PInfo.testEffectiveOp() == EO_And) {
918 if (LState == CS_Unknown) {
919 ThenStates->setState(LTest.Var, LTest.TestsFor);
920
921 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
922 ThenStates->markUnreachable();
923
924 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000925 if (RState == RTest.TestsFor)
926 ElseStates->markUnreachable();
927 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000928 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000929 }
930
931 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000932 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000933 ElseStates->setState(LTest.Var,
934 invertConsumedUnconsumed(LTest.TestsFor));
935
DeLesley Hutchins66540852013-10-04 21:28:06 +0000936 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000937 ElseStates->markUnreachable();
938
939 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
940 isKnownState(RState)) {
941
DeLesley Hutchins66540852013-10-04 21:28:06 +0000942 if (RState == RTest.TestsFor)
943 ElseStates->markUnreachable();
944 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000945 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000946 }
947 }
948 }
949
950 if (RTest.Var) {
951 if (PInfo.testEffectiveOp() == EO_And) {
952 if (RState == CS_Unknown)
953 ThenStates->setState(RTest.Var, RTest.TestsFor);
954 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
955 ThenStates->markUnreachable();
956
DeLesley Hutchins66540852013-10-04 21:28:06 +0000957 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000958 if (RState == CS_Unknown)
959 ElseStates->setState(RTest.Var,
960 invertConsumedUnconsumed(RTest.TestsFor));
961 else if (RState == RTest.TestsFor)
962 ElseStates->markUnreachable();
963 }
964 }
965}
966
DeLesley Hutchins73858402013-10-09 18:30:24 +0000967bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
968 const CFGBlock *TargetBlock) {
969
970 assert(CurrBlock && "Block pointer must not be NULL");
971 assert(TargetBlock && "TargetBlock pointer must not be NULL");
972
973 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
974 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
975 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
976 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
977 return false;
978 }
979 return true;
980}
981
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000982void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
983 ConsumedStateMap *StateMap,
984 bool &AlreadyOwned) {
985
DeLesley Hutchins73858402013-10-09 18:30:24 +0000986 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000987
988 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
989
990 if (Entry) {
991 Entry->intersect(StateMap);
992
993 } else if (AlreadyOwned) {
994 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
995
996 } else {
997 StateMapsArray[Block->getBlockID()] = StateMap;
998 AlreadyOwned = true;
999 }
1000}
1001
1002void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1003 ConsumedStateMap *StateMap) {
1004
DeLesley Hutchins73858402013-10-09 18:30:24 +00001005 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001006
1007 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1008
1009 if (Entry) {
1010 Entry->intersect(StateMap);
1011 delete StateMap;
1012
1013 } else {
1014 StateMapsArray[Block->getBlockID()] = StateMap;
1015 }
1016}
1017
DeLesley Hutchins73858402013-10-09 18:30:24 +00001018ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1019 assert(Block && "Block pointer must not be NULL");
1020 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1021
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001022 return StateMapsArray[Block->getBlockID()];
1023}
1024
DeLesley Hutchins73858402013-10-09 18:30:24 +00001025void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1026 unsigned int BlockID = Block->getBlockID();
1027 delete StateMapsArray[BlockID];
1028 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001029}
1030
DeLesley Hutchins73858402013-10-09 18:30:24 +00001031ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1032 assert(Block && "Block pointer must not be NULL");
1033
1034 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1035 if (isBackEdgeTarget(Block)) {
1036 return new ConsumedStateMap(*StateMap);
1037 } else {
1038 StateMapsArray[Block->getBlockID()] = NULL;
1039 return StateMap;
1040 }
1041}
1042
1043bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1044 assert(From && "From block must not be NULL");
1045 assert(To && "From block must not be NULL");
1046
1047 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1048}
1049
1050bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1051 assert(Block != NULL && "Block pointer must not be NULL");
1052
1053 // Anything with less than two predecessors can't be the target of a back
1054 // edge.
1055 if (Block->pred_size() < 2)
1056 return false;
1057
1058 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1059 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1060 PE = Block->pred_end(); PI != PE; ++PI) {
1061 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1062 return true;
1063 }
1064 return false;
1065}
1066
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001067void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1068 ConsumedWarningsHandlerBase &WarningsHandler) const {
1069
1070 ConsumedState ExpectedState;
1071
1072 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
1073 ++DMI) {
1074
1075 if (isa<ParmVarDecl>(DMI->first)) {
1076 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
1077
1078 if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
1079
1080 ExpectedState =
1081 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
1082
1083 if (DMI->second != ExpectedState) {
1084 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1085 Param->getNameAsString(), stateToString(ExpectedState),
1086 stateToString(DMI->second));
1087 }
1088 }
1089 }
1090}
1091
DeLesley Hutchins73858402013-10-09 18:30:24 +00001092ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001093 MapType::const_iterator Entry = Map.find(Var);
1094
1095 if (Entry != Map.end()) {
1096 return Entry->second;
1097
1098 } else {
1099 return CS_None;
1100 }
1101}
1102
1103void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1104 ConsumedState LocalState;
1105
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001106 if (this->From && this->From == Other->From && !Other->Reachable) {
1107 this->markUnreachable();
1108 return;
1109 }
1110
DeLesley Hutchins73858402013-10-09 18:30:24 +00001111 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1112 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001113
1114 LocalState = this->getState(DMI->first);
1115
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001116 if (LocalState == CS_None)
1117 continue;
1118
1119 if (LocalState != DMI->second)
1120 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001121 }
1122}
1123
DeLesley Hutchins73858402013-10-09 18:30:24 +00001124void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1125 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1126 ConsumedWarningsHandlerBase &WarningsHandler) {
1127
1128 ConsumedState LocalState;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001129 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001130
1131 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1132 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1133
1134 LocalState = this->getState(DMI->first);
1135
1136 if (LocalState == CS_None)
1137 continue;
1138
1139 if (LocalState != DMI->second) {
1140 Map[DMI->first] = CS_Unknown;
1141 WarningsHandler.warnLoopStateMismatch(
1142 BlameLoc, DMI->first->getNameAsString());
1143 }
1144 }
1145}
1146
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001147void ConsumedStateMap::markUnreachable() {
1148 this->Reachable = false;
1149 Map.clear();
1150}
1151
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001152void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1153 Map[Var] = State;
1154}
1155
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001156void ConsumedStateMap::remove(const VarDecl *Var) {
1157 Map.erase(Var);
1158}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001159
DeLesley Hutchins73858402013-10-09 18:30:24 +00001160bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1161 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1162 DMI != DME; ++DMI) {
1163
1164 if (this->getState(DMI->first) != DMI->second)
1165 return true;
1166 }
1167
1168 return false;
1169}
1170
David Blaikiea33ab602013-09-06 01:28:43 +00001171void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1172 const FunctionDecl *D) {
1173 QualType ReturnType;
1174 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1175 ASTContext &CurrContext = AC.getASTContext();
1176 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1177 } else
1178 ReturnType = D->getCallResultType();
1179
1180 if (D->hasAttr<ReturnTypestateAttr>()) {
1181 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1182
1183 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1184 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1185 // FIXME: This should be removed when template instantiation propagates
1186 // attributes at template specialization definition, not
1187 // declaration. When it is removed the test needs to be enabled
1188 // in SemaDeclAttr.cpp.
1189 WarningsHandler.warnReturnTypestateForUnconsumableType(
1190 RTSAttr->getLocation(), ReturnType.getAsString());
1191 ExpectedReturnState = CS_None;
1192 } else
1193 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1194 } else if (isConsumableType(ReturnType))
1195 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1196 else
1197 ExpectedReturnState = CS_None;
1198}
1199
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001200bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1201 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001202
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001203 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1204 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001205
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001206 if (const IfStmt *IfNode =
1207 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001208
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001209 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001210
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001211 PInfo = Visitor.getInfo(Cond);
1212 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1213 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1214
1215 if (PInfo.isTest()) {
1216 CurrStates->setSource(Cond);
1217 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001218 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001219
1220 } else if (PInfo.isBinTest()) {
1221 CurrStates->setSource(PInfo.testSourceNode());
1222 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001223 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001224
1225 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001226 delete FalseStates;
1227 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001228 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001229
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001230 } else if (const BinaryOperator *BinOp =
1231 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1232
1233 PInfo = Visitor.getInfo(BinOp->getLHS());
1234 if (!PInfo.isTest()) {
1235 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1236 PInfo = Visitor.getInfo(BinOp->getRHS());
1237
1238 if (!PInfo.isTest()) {
1239 delete FalseStates;
1240 return false;
1241 }
1242
1243 } else {
1244 delete FalseStates;
1245 return false;
1246 }
1247 }
1248
1249 CurrStates->setSource(BinOp);
1250 FalseStates->setSource(BinOp);
1251
1252 const VarTestResult &Test = PInfo.getTest();
1253 ConsumedState VarState = CurrStates->getState(Test.Var);
1254
1255 if (BinOp->getOpcode() == BO_LAnd) {
1256 if (VarState == CS_Unknown)
1257 CurrStates->setState(Test.Var, Test.TestsFor);
1258 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1259 CurrStates->markUnreachable();
1260
1261 } else if (BinOp->getOpcode() == BO_LOr) {
1262 if (VarState == CS_Unknown)
1263 FalseStates->setState(Test.Var,
1264 invertConsumedUnconsumed(Test.TestsFor));
1265 else if (VarState == Test.TestsFor)
1266 FalseStates->markUnreachable();
1267 }
1268
1269 } else {
1270 delete FalseStates;
1271 return false;
1272 }
1273
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001274 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1275
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001276 if (*SI)
1277 BlockInfo.addInfo(*SI, CurrStates);
1278 else
1279 delete CurrStates;
1280
1281 if (*++SI)
1282 BlockInfo.addInfo(*SI, FalseStates);
1283 else
1284 delete FalseStates;
1285
1286 CurrStates = NULL;
1287 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001288}
1289
1290void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1291 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001292 if (!D)
1293 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001294
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001295 CFG *CFGraph = AC.getCFG();
1296 if (!CFGraph)
1297 return;
DeLesley Hutchins52f717e2013-10-17 18:19:31 +00001298
David Blaikiea33ab602013-09-06 01:28:43 +00001299 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001300
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001301 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001302 // AC.getCFG()->viewCFG(LangOptions());
1303
1304 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001305
1306 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001307 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1308
1309 // Add all trackable parameters to the state map.
1310 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1311 PE = D->param_end(); PI != PE; ++PI) {
1312 Visitor.VisitParmVarDecl(*PI);
1313 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001314
1315 // Visit all of the function's basic blocks.
1316 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1317 E = SortedGraph->end(); I != E; ++I) {
1318
1319 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001320
1321 if (CurrStates == NULL)
1322 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001323
1324 if (!CurrStates) {
1325 continue;
1326
1327 } else if (!CurrStates->isReachable()) {
1328 delete CurrStates;
1329 CurrStates = NULL;
1330 continue;
1331 }
1332
1333 Visitor.reset(CurrStates);
1334
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001335 // Visit all of the basic block's statements.
1336 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1337 BE = CurrBlock->end(); BI != BE; ++BI) {
1338
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001339 switch (BI->getKind()) {
1340 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001341 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001342 break;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001343
1344 case CFGElement::TemporaryDtor: {
1345 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1346 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1347 PropagationInfo PInfo = Visitor.getInfo(BTE);
1348
1349 if (PInfo.isValid())
1350 Visitor.checkCallability(PInfo,
1351 DTor.getDestructorDecl(AC.getASTContext()),
1352 BTE->getExprLoc());
1353 break;
1354 }
1355
1356 case CFGElement::AutomaticObjectDtor: {
1357 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1358
1359 const VarDecl *Var = DTor.getVarDecl();
1360 ConsumedState VarState = CurrStates->getState(Var);
1361
1362 if (VarState != CS_None) {
1363 PropagationInfo PInfo(Var);
1364
1365 Visitor.checkCallability(PInfo,
1366 DTor.getDestructorDecl(AC.getASTContext()),
1367 getLastStmtLoc(CurrBlock));
1368
1369 CurrStates->remove(Var);
1370 }
1371 break;
1372 }
1373
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001374 default:
1375 break;
1376 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001377 }
1378
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001379 // TODO: Handle other forms of branching with precision, including while-
1380 // and for-loops. (Deferred)
1381 if (!splitState(CurrBlock, Visitor)) {
1382 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001383
DeLesley Hutchins73858402013-10-09 18:30:24 +00001384 if (CurrBlock->succ_size() > 1 ||
1385 (CurrBlock->succ_size() == 1 &&
1386 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001387
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001388 bool OwnershipTaken = false;
1389
1390 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1391 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1392
DeLesley Hutchins73858402013-10-09 18:30:24 +00001393 if (*SI == NULL) continue;
1394
1395 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1396 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1397 CurrStates,
1398 WarningsHandler);
1399
1400 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1401 BlockInfo.discardInfo(*SI);
1402 } else {
1403 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1404 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001405 }
1406
1407 if (!OwnershipTaken)
1408 delete CurrStates;
1409
1410 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001411 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001412 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001413
1414 if (CurrBlock == &AC.getCFG()->getExit() &&
1415 D->getCallResultType()->isVoidType())
1416 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1417 WarningsHandler);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001418 } // End of block iterator.
1419
1420 // Delete the last existing state map.
1421 delete CurrStates;
1422
1423 WarningsHandler.emitDiagnostics();
1424}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001425}} // end namespace clang::consumed