blob: c1902718a8f7b6e427cfa6a8c410e6038e965abc [file] [log] [blame]
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001//===- Consumed.cpp --------------------------------------------*- C++ --*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// A intra-procedural analysis for checking consumed properties. This is based,
11// in part, on research on linear types.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/AST/RecursiveASTVisitor.h"
20#include "clang/AST/StmtVisitor.h"
21#include "clang/AST/StmtCXX.h"
22#include "clang/AST/Type.h"
23#include "clang/Analysis/Analyses/PostOrderCFGView.h"
24#include "clang/Analysis/AnalysisContext.h"
25#include "clang/Analysis/CFG.h"
26#include "clang/Analysis/Analyses/Consumed.h"
27#include "clang/Basic/OperatorKinds.h"
28#include "clang/Basic/SourceLocation.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000029#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/SmallVector.h"
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000031#include "llvm/Support/Compiler.h"
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000032#include "llvm/Support/raw_ostream.h"
33
DeLesley Hutchins73858402013-10-09 18:30:24 +000034// TODO: Use information from tests in while-loop conditional.
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +000035// TODO: Add notes about the actual and expected state for
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000036// TODO: Correctly identify unreachable blocks when chaining boolean operators.
DeLesley Hutchins66540852013-10-04 21:28:06 +000037// TODO: Adjust the parser and AttributesList class to support lists of
38// identifiers.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000039// TODO: Warn about unreachable code.
40// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000041// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
42// if (valid) ...; (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000043// TODO: Take notes on state transitions to provide better warning messages.
44// (Deferred)
45// TODO: Test nested conditionals: A) Checking the same value multiple times,
46// and 2) Checking different values. (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000047
48using namespace clang;
49using namespace consumed;
50
51// Key method definition
52ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
53
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000054static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
55 // Find the source location of the first statement in the block, if the block
56 // is not empty.
57 for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
58 BI != BE; ++BI) {
59 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
60 return CS->getStmt()->getLocStart();
61 }
62
63 // Block is empty.
64 // If we have one successor, return the first statement in that block
65 if (Block->succ_size() == 1 && *Block->succ_begin())
66 return getFirstStmtLoc(*Block->succ_begin());
67
68 return SourceLocation();
69}
70
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000071static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000072 // Find the source location of the last statement in the block, if the block
73 // is not empty.
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000074 if (const Stmt *StmtNode = Block->getTerminator()) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000075 return StmtNode->getLocStart();
76 } else {
DeLesley Hutchins627c7f92013-10-11 21:55:33 +000077 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
78 BE = Block->rend(); BI != BE; ++BI) {
DeLesley Hutchins73858402013-10-09 18:30:24 +000079 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
80 return CS->getStmt()->getLocStart();
81 }
82 }
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000083
84 // If we have one successor, return the first statement in that block
85 SourceLocation Loc;
86 if (Block->succ_size() == 1 && *Block->succ_begin())
87 Loc = getFirstStmtLoc(*Block->succ_begin());
88 if (Loc.isValid())
89 return Loc;
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +000090
DeLesley Hutchins52f717e2013-10-17 18:19:31 +000091 // If we have one predecessor, return the last statement in that block
92 if (Block->pred_size() == 1 && *Block->pred_begin())
93 return getLastStmtLoc(*Block->pred_begin());
94
95 return Loc;
DeLesley Hutchins73858402013-10-09 18:30:24 +000096}
97
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000098static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
99 switch (State) {
100 case CS_Unconsumed:
101 return CS_Consumed;
102 case CS_Consumed:
103 return CS_Unconsumed;
104 case CS_None:
105 return CS_None;
106 case CS_Unknown:
107 return CS_Unknown;
108 }
109 llvm_unreachable("invalid enum");
110}
111
DeLesley Hutchins66540852013-10-04 21:28:06 +0000112static bool isCallableInState(const CallableWhenAttr *CWAttr,
113 ConsumedState State) {
114
115 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
116 E = CWAttr->callableState_end();
117
118 for (; I != E; ++I) {
119
120 ConsumedState MappedAttrState = CS_None;
121
122 switch (*I) {
123 case CallableWhenAttr::Unknown:
124 MappedAttrState = CS_Unknown;
125 break;
126
127 case CallableWhenAttr::Unconsumed:
128 MappedAttrState = CS_Unconsumed;
129 break;
130
131 case CallableWhenAttr::Consumed:
132 MappedAttrState = CS_Consumed;
133 break;
134 }
135
136 if (MappedAttrState == State)
137 return true;
138 }
139
140 return false;
141}
142
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000143static bool isConsumableType(const QualType &QT) {
144 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
145 return RD->hasAttr<ConsumableAttr>();
146 else
147 return false;
148}
149
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000150static bool isKnownState(ConsumedState State) {
151 switch (State) {
152 case CS_Unconsumed:
153 case CS_Consumed:
154 return true;
155 case CS_None:
156 case CS_Unknown:
157 return false;
158 }
Aaron Ballman6b2ec032013-08-29 20:36:09 +0000159 llvm_unreachable("invalid enum");
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000160}
161
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000162static bool isRValueRefish(QualType ParamType) {
163 return ParamType->isRValueReferenceType() ||
164 (ParamType->isLValueReferenceType() &&
165 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue());
166}
167
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000168static bool isTestingFunction(const FunctionDecl *FunDecl) {
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000169 return FunDecl->hasAttr<TestsTypestateAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000170}
171
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000172static bool isValueType(QualType ParamType) {
173 return !(ParamType->isPointerType() || ParamType->isReferenceType());
174}
175
David Blaikiea33ab602013-09-06 01:28:43 +0000176static ConsumedState mapConsumableAttrState(const QualType QT) {
177 assert(isConsumableType(QT));
178
179 const ConsumableAttr *CAttr =
180 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
181
182 switch (CAttr->getDefaultState()) {
183 case ConsumableAttr::Unknown:
184 return CS_Unknown;
185 case ConsumableAttr::Unconsumed:
186 return CS_Unconsumed;
187 case ConsumableAttr::Consumed:
188 return CS_Consumed;
189 }
190 llvm_unreachable("invalid enum");
191}
192
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000193static ConsumedState
194mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
195 switch (PTAttr->getParamState()) {
196 case ParamTypestateAttr::Unknown:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000197 return CS_Unknown;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000198 case ParamTypestateAttr::Unconsumed:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000199 return CS_Unconsumed;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000200 case ParamTypestateAttr::Consumed:
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000201 return CS_Consumed;
202 }
203 llvm_unreachable("invalid_enum");
204}
205
Eric Christophere988dc42013-09-03 20:43:00 +0000206static ConsumedState
207mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000208 switch (RTSAttr->getState()) {
209 case ReturnTypestateAttr::Unknown:
210 return CS_Unknown;
211 case ReturnTypestateAttr::Unconsumed:
212 return CS_Unconsumed;
213 case ReturnTypestateAttr::Consumed:
214 return CS_Consumed;
215 }
Eric Christophere988dc42013-09-03 20:43:00 +0000216 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000217}
218
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000219static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
220 switch (STAttr->getNewState()) {
221 case SetTypestateAttr::Unknown:
222 return CS_Unknown;
223 case SetTypestateAttr::Unconsumed:
224 return CS_Unconsumed;
225 case SetTypestateAttr::Consumed:
226 return CS_Consumed;
227 }
228 llvm_unreachable("invalid_enum");
229}
230
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000231static StringRef stateToString(ConsumedState State) {
232 switch (State) {
233 case consumed::CS_None:
234 return "none";
235
236 case consumed::CS_Unknown:
237 return "unknown";
238
239 case consumed::CS_Unconsumed:
240 return "unconsumed";
241
242 case consumed::CS_Consumed:
243 return "consumed";
244 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000245 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000246}
247
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000248static ConsumedState testsFor(const FunctionDecl *FunDecl) {
249 assert(isTestingFunction(FunDecl));
250 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) {
251 case TestsTypestateAttr::Unconsumed:
252 return CS_Unconsumed;
253 case TestsTypestateAttr::Consumed:
254 return CS_Consumed;
255 }
256 llvm_unreachable("invalid enum");
257}
258
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000259namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000260struct VarTestResult {
261 const VarDecl *Var;
262 ConsumedState TestsFor;
263};
264} // end anonymous::VarTestResult
265
266namespace clang {
267namespace consumed {
268
269enum EffectiveOp {
270 EO_And,
271 EO_Or
272};
273
274class PropagationInfo {
275 enum {
276 IT_None,
277 IT_State,
278 IT_Test,
279 IT_BinTest,
280 IT_Var
281 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000282
283 struct BinTestTy {
284 const BinaryOperator *Source;
285 EffectiveOp EOp;
286 VarTestResult LTest;
287 VarTestResult RTest;
288 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000289
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000290 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000291 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000292 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000293 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000294 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000295 };
296
DeLesley Hutchins66540852013-10-04 21:28:06 +0000297 QualType TempType;
298
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000299public:
300 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000301
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000302 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
303 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
304 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000305
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000306 Test.Var = Var;
307 Test.TestsFor = TestsFor;
308 }
309
310 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
311 const VarTestResult &LTest, const VarTestResult &RTest)
312 : InfoType(IT_BinTest) {
313
314 BinTest.Source = Source;
315 BinTest.EOp = EOp;
316 BinTest.LTest = LTest;
317 BinTest.RTest = RTest;
318 }
319
320 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
321 const VarDecl *LVar, ConsumedState LTestsFor,
322 const VarDecl *RVar, ConsumedState RTestsFor)
323 : InfoType(IT_BinTest) {
324
325 BinTest.Source = Source;
326 BinTest.EOp = EOp;
327 BinTest.LTest.Var = LVar;
328 BinTest.LTest.TestsFor = LTestsFor;
329 BinTest.RTest.Var = RVar;
330 BinTest.RTest.TestsFor = RTestsFor;
331 }
332
DeLesley Hutchins66540852013-10-04 21:28:06 +0000333 PropagationInfo(ConsumedState State, QualType TempType)
334 : InfoType(IT_State), State(State), TempType(TempType) {}
335
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000336 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
337
338 const ConsumedState & getState() const {
339 assert(InfoType == IT_State);
340 return State;
341 }
342
DeLesley Hutchins66540852013-10-04 21:28:06 +0000343 const QualType & getTempType() const {
344 assert(InfoType == IT_State);
345 return TempType;
346 }
347
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000348 const VarTestResult & getTest() const {
349 assert(InfoType == IT_Test);
350 return Test;
351 }
352
353 const VarTestResult & getLTest() const {
354 assert(InfoType == IT_BinTest);
355 return BinTest.LTest;
356 }
357
358 const VarTestResult & getRTest() const {
359 assert(InfoType == IT_BinTest);
360 return BinTest.RTest;
361 }
362
363 const VarDecl * getVar() const {
364 assert(InfoType == IT_Var);
365 return Var;
366 }
367
368 EffectiveOp testEffectiveOp() const {
369 assert(InfoType == IT_BinTest);
370 return BinTest.EOp;
371 }
372
373 const BinaryOperator * testSourceNode() const {
374 assert(InfoType == IT_BinTest);
375 return BinTest.Source;
376 }
377
378 bool isValid() const { return InfoType != IT_None; }
379 bool isState() const { return InfoType == IT_State; }
380 bool isTest() const { return InfoType == IT_Test; }
381 bool isBinTest() const { return InfoType == IT_BinTest; }
382 bool isVar() const { return InfoType == IT_Var; }
383
384 PropagationInfo invertTest() const {
385 assert(InfoType == IT_Test || InfoType == IT_BinTest);
386
387 if (InfoType == IT_Test) {
388 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
389
390 } else if (InfoType == IT_BinTest) {
391 return PropagationInfo(BinTest.Source,
392 BinTest.EOp == EO_And ? EO_Or : EO_And,
393 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
394 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
395 } else {
396 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000397 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000398 }
399};
400
401class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000402
403 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
404 typedef std::pair<const Stmt *, PropagationInfo> PairType;
405 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000406 typedef MapType::const_iterator ConstInfoEntry;
407
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000408 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000409 ConsumedAnalyzer &Analyzer;
410 ConsumedStateMap *StateMap;
411 MapType PropagationMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000412 void forwardInfo(const Stmt *From, const Stmt *To);
413 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000414 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
415 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000416
DeLesley Hutchins13be0322013-10-18 23:11:49 +0000417 inline ConsumedState getPInfoState(const PropagationInfo& PInfo) {
418 if (PInfo.isVar())
419 return StateMap->getState(PInfo.getVar());
420 else if (PInfo.isState())
421 return PInfo.getState();
422 else
423 return CS_None;
424 }
425
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000426public:
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000427 void checkCallability(const PropagationInfo &PInfo,
428 const FunctionDecl *FunDecl,
429 SourceLocation BlameLoc);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000430
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000431 void Visit(const Stmt *StmtNode);
432
433 void VisitBinaryOperator(const BinaryOperator *BinOp);
434 void VisitCallExpr(const CallExpr *Call);
435 void VisitCastExpr(const CastExpr *Cast);
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000436 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000437 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
438 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
439 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
440 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
441 void VisitDeclStmt(const DeclStmt *DelcS);
442 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
443 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000444 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000445 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000446 void VisitUnaryOperator(const UnaryOperator *UOp);
447 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000448
DeLesley Hutchins42525982013-08-29 22:36:05 +0000449 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
450 ConsumedStateMap *StateMap)
451 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000452
453 PropagationInfo getInfo(const Stmt *StmtNode) const {
454 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
455
456 if (Entry != PropagationMap.end())
457 return Entry->second;
458 else
459 return PropagationInfo();
460 }
461
462 void reset(ConsumedStateMap *NewStateMap) {
463 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000464 }
465};
466
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000467void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000468 const FunctionDecl *FunDecl,
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000469 SourceLocation BlameLoc) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000470
DeLesley Hutchins66540852013-10-04 21:28:06 +0000471 if (!FunDecl->hasAttr<CallableWhenAttr>())
472 return;
473
474 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000475
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000476 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000477 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000478 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000479
DeLesley Hutchins66540852013-10-04 21:28:06 +0000480 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000481
DeLesley Hutchins66540852013-10-04 21:28:06 +0000482 if (isCallableInState(CWAttr, VarState))
483 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000484
DeLesley Hutchins66540852013-10-04 21:28:06 +0000485 Analyzer.WarningsHandler.warnUseInInvalidState(
486 FunDecl->getNameAsString(), Var->getNameAsString(),
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000487 stateToString(VarState), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000488
DeLesley Hutchins66540852013-10-04 21:28:06 +0000489 } else if (PInfo.isState()) {
490
491 assert(PInfo.getState() != CS_None && "Invalid state");
492
493 if (isCallableInState(CWAttr, PInfo.getState()))
494 return;
495
496 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000497 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000498 }
499}
500
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000501void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
502 InfoEntry Entry = PropagationMap.find(From);
503
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000504 if (Entry != PropagationMap.end())
505 PropagationMap.insert(PairType(To, Entry->second));
506}
507
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000508bool ConsumedStmtVisitor::isLikeMoveAssignment(
509 const CXXMethodDecl *MethodDecl) {
510
511 return MethodDecl->isMoveAssignmentOperator() ||
512 (MethodDecl->getOverloadedOperator() == OO_Equal &&
513 MethodDecl->getNumParams() == 1 &&
514 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
515}
516
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000517void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
518 const FunctionDecl *Fun,
519 QualType ReturnType) {
520 if (isConsumableType(ReturnType)) {
521
522 ConsumedState ReturnState;
523
524 if (Fun->hasAttr<ReturnTypestateAttr>())
525 ReturnState = mapReturnTypestateAttrState(
526 Fun->getAttr<ReturnTypestateAttr>());
527 else
David Blaikiea33ab602013-09-06 01:28:43 +0000528 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000529
530 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000531 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000532 }
533}
534
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000535void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
536
537 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
538
539 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
540 CE = StmtNode->child_end(); CI != CE; ++CI) {
541
542 PropagationMap.erase(*CI);
543 }
544}
545
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000546void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
547 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000548 case BO_LAnd:
549 case BO_LOr : {
550 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
551 REntry = PropagationMap.find(BinOp->getRHS());
552
553 VarTestResult LTest, RTest;
554
555 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
556 LTest = LEntry->second.getTest();
557
558 } else {
559 LTest.Var = NULL;
560 LTest.TestsFor = CS_None;
561 }
562
563 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
564 RTest = REntry->second.getTest();
565
566 } else {
567 RTest.Var = NULL;
568 RTest.TestsFor = CS_None;
569 }
570
571 if (!(LTest.Var == NULL && RTest.Var == NULL))
572 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
573 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
574
575 break;
576 }
577
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000578 case BO_PtrMemD:
579 case BO_PtrMemI:
580 forwardInfo(BinOp->getLHS(), BinOp);
581 break;
582
583 default:
584 break;
585 }
586}
587
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000588void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
589 if (const FunctionDecl *FunDecl =
590 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
591
592 // Special case for the std::move function.
593 // TODO: Make this more specific. (Deferred)
594 if (FunDecl->getNameAsString() == "move") {
Chris Wailesde2204b2013-10-24 14:28:17 +0000595 forwardInfo(Call->getArg(0), Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000596 return;
597 }
598
599 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
600
601 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000602 const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
603 QualType ParamType = Param->getType();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000604
605 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
606
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000607 if (Entry == PropagationMap.end() ||
608 !(Entry->second.isState() || Entry->second.isVar()))
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000609 continue;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000610
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000611 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000612
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000613 // Check that the parameter is in the correct state.
614
615 if (Param->hasAttr<ParamTypestateAttr>()) {
616 ConsumedState ParamState =
617 PInfo.isState() ? PInfo.getState() :
618 StateMap->getState(PInfo.getVar());
619
620 ConsumedState ExpectedState =
621 mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
622
623 if (ParamState != ExpectedState)
624 Analyzer.WarningsHandler.warnParamTypestateMismatch(
625 Call->getArg(Index - Offset)->getExprLoc(),
626 stateToString(ExpectedState), stateToString(ParamState));
627 }
628
629 if (!Entry->second.isVar())
630 continue;
631
632 // Adjust state on the caller side.
633
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000634 if (isRValueRefish(ParamType)) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000635 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000636
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000637 } else if (Param->hasAttr<ReturnTypestateAttr>()) {
638 StateMap->setState(PInfo.getVar(),
639 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
640
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000641 } else if (!isValueType(ParamType) &&
642 !ParamType->getPointeeType().isConstQualified()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000643
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000644 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000645 }
646 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000647
DeLesley Hutchins66540852013-10-04 21:28:06 +0000648 QualType RetType = FunDecl->getCallResultType();
649 if (RetType->isReferenceType())
650 RetType = RetType->getPointeeType();
651
652 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000653 }
654}
655
656void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000657 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000658}
659
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000660void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
661 const CXXBindTemporaryExpr *Temp) {
662
663 forwardInfo(Temp->getSubExpr(), Temp);
664}
665
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000666void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
667 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000668
669 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000670 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
671
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000672 if (!isConsumableType(ThisType))
673 return;
674
675 // FIXME: What should happen if someone annotates the move constructor?
676 if (Constructor->hasAttr<ReturnTypestateAttr>()) {
677 ReturnTypestateAttr *RTAttr = Constructor->getAttr<ReturnTypestateAttr>();
678 ConsumedState RetState = mapReturnTypestateAttrState(RTAttr);
679 PropagationMap.insert(PairType(Call, PropagationInfo(RetState, ThisType)));
680
681 } else if (Constructor->isDefaultConstructor()) {
682
683 PropagationMap.insert(PairType(Call,
684 PropagationInfo(consumed::CS_Consumed, ThisType)));
685
686 } else if (Constructor->isMoveConstructor()) {
687
Chris Wailesde2204b2013-10-24 14:28:17 +0000688 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000689
Chris Wailesde2204b2013-10-24 14:28:17 +0000690 if (Entry != PropagationMap.end()) {
691 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000692
Chris Wailesde2204b2013-10-24 14:28:17 +0000693 if (PInfo.isVar()) {
694 const VarDecl* Var = PInfo.getVar();
695
696 PropagationMap.insert(PairType(Call,
697 PropagationInfo(StateMap->getState(Var), ThisType)));
698
699 StateMap->setState(Var, consumed::CS_Consumed);
700
701 } else {
702 PropagationMap.insert(PairType(Call, PInfo));
703 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000704 }
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000705 } else if (Constructor->isCopyConstructor()) {
Chris Wailesde2204b2013-10-24 14:28:17 +0000706 forwardInfo(Call->getArg(0), Call);
DeLesley Hutchinsc5cdafc2013-10-18 18:36:21 +0000707
708 } else {
709 ConsumedState RetState = mapConsumableAttrState(ThisType);
710 PropagationMap.insert(PairType(Call, PropagationInfo(RetState, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000711 }
712}
713
714void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
715 const CXXMemberCallExpr *Call) {
716
717 VisitCallExpr(Call);
718
719 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
720
721 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000722 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000723 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000724
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000725 checkCallability(PInfo, MethodDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000726
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000727 if (PInfo.isVar()) {
728 if (isTestingFunction(MethodDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000729 PropagationMap.insert(PairType(Call,
730 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000731 else if (MethodDecl->hasAttr<SetTypestateAttr>())
732 StateMap->setState(PInfo.getVar(),
733 mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000734 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000735 }
736}
737
738void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
739 const CXXOperatorCallExpr *Call) {
740
741 const FunctionDecl *FunDecl =
742 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
743
744 if (!FunDecl) return;
745
746 if (isa<CXXMethodDecl>(FunDecl) &&
747 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
748
749 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
750 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
751
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000752 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000753
754 if (LEntry != PropagationMap.end() &&
755 REntry != PropagationMap.end()) {
756
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000757 LPInfo = LEntry->second;
758 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000759
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000760 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000761 StateMap->setState(LPInfo.getVar(),
762 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000763
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000764 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000765
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000766 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000767
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000768 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000769 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000770
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000771 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000772
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000773 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000774 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000775 PropagationInfo(StateMap->getState(RPInfo.getVar()),
776 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000777
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000778 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000779
780 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000781 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000782 }
783
784 } else if (LEntry != PropagationMap.end() &&
785 REntry == PropagationMap.end()) {
786
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000787 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000788
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000789 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000790 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000791
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000792 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000793
DeLesley Hutchins66540852013-10-04 21:28:06 +0000794 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000795 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000796 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000797 }
798
799 } else if (LEntry == PropagationMap.end() &&
800 REntry != PropagationMap.end()) {
801
DeLesley Hutchins66540852013-10-04 21:28:06 +0000802 if (REntry->second.isVar())
803 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000804 }
805
806 } else {
807
808 VisitCallExpr(Call);
809
810 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
811
812 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000813 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000814
DeLesley Hutchins627c7f92013-10-11 21:55:33 +0000815 checkCallability(PInfo, FunDecl, Call->getExprLoc());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000816
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000817 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000818 if (isTestingFunction(FunDecl))
DeLesley Hutchins1bf63432013-10-11 22:30:48 +0000819 PropagationMap.insert(PairType(Call,
820 PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
DeLesley Hutchinsf30e1942013-10-11 23:03:26 +0000821 else if (FunDecl->hasAttr<SetTypestateAttr>())
822 StateMap->setState(PInfo.getVar(),
823 mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000824 }
825 }
826 }
827}
828
829void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
830 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
831 if (StateMap->getState(Var) != consumed::CS_None)
832 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
833}
834
835void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
836 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
837 DE = DeclS->decl_end(); DI != DE; ++DI) {
838
839 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
840 }
841
842 if (DeclS->isSingleDecl())
843 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
844 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
845}
846
847void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
848 const MaterializeTemporaryExpr *Temp) {
849
Chris Wailesde2204b2013-10-24 14:28:17 +0000850 forwardInfo(Temp->GetTemporaryExpr(), Temp);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000851}
852
853void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
854 forwardInfo(MExpr->getBase(), MExpr);
855}
856
DeLesley Hutchins42525982013-08-29 22:36:05 +0000857
858void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000859 QualType ParamType = Param->getType();
860 ConsumedState ParamState = consumed::CS_None;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000861
862 if (Param->hasAttr<ParamTypestateAttr>()) {
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000863 const ParamTypestateAttr *PTAttr = Param->getAttr<ParamTypestateAttr>();
864 ParamState = mapParamTypestateAttrState(PTAttr);
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000865
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000866 } else if (isValueType(ParamType) && isConsumableType(ParamType)) {
David Blaikiea33ab602013-09-06 01:28:43 +0000867 ParamState = mapConsumableAttrState(ParamType);
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000868
DeLesley Hutchinsbe63ab62013-10-18 19:25:18 +0000869 } else if (isRValueRefish(ParamType) &&
870 isConsumableType(ParamType->getPointeeType())) {
871
872 ParamState = mapConsumableAttrState(ParamType->getPointeeType());
873
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000874 } else if (ParamType->isReferenceType() &&
875 isConsumableType(ParamType->getPointeeType())) {
David Blaikiea33ab602013-09-06 01:28:43 +0000876 ParamState = consumed::CS_Unknown;
DeLesley Hutchinsd4f0e192013-10-17 23:23:53 +0000877 }
878
879 if (ParamState != CS_None)
David Blaikiea33ab602013-09-06 01:28:43 +0000880 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000881}
882
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000883void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000884 ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
885
886 if (ExpectedState != CS_None) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000887 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
888
889 if (Entry != PropagationMap.end()) {
890 assert(Entry->second.isState() || Entry->second.isVar());
891
892 ConsumedState RetState = Entry->second.isState() ?
893 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
894
895 if (RetState != ExpectedState)
896 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
897 Ret->getReturnLoc(), stateToString(ExpectedState),
898 stateToString(RetState));
899 }
900 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +0000901
902 StateMap->checkParamsForReturnTypestate(Ret->getLocStart(),
903 Analyzer.WarningsHandler);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000904}
905
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000906void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000907 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
908 if (Entry == PropagationMap.end()) return;
909
910 switch (UOp->getOpcode()) {
911 case UO_AddrOf:
912 PropagationMap.insert(PairType(UOp, Entry->second));
913 break;
914
915 case UO_LNot:
916 if (Entry->second.isTest() || Entry->second.isBinTest())
917 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
918 break;
919
920 default:
921 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000922 }
923}
924
DeLesley Hutchins66540852013-10-04 21:28:06 +0000925// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000926void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000927 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000928 if (Var->hasInit()) {
DeLesley Hutchins13be0322013-10-18 23:11:49 +0000929 MapType::iterator VIT = PropagationMap.find(Var->getInit());
930 if (VIT != PropagationMap.end()) {
931 PropagationInfo PInfo = VIT->second;
932 ConsumedState St = getPInfoState(PInfo);
933 if (St != consumed::CS_None) {
934 StateMap->setState(Var, St);
935 return;
936 }
937 }
DeLesley Hutchins42525982013-08-29 22:36:05 +0000938 }
DeLesley Hutchins13be0322013-10-18 23:11:49 +0000939 // Otherwise
940 StateMap->setState(Var, consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000941 }
942}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000943}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000944
945namespace clang {
946namespace consumed {
947
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000948void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
949 ConsumedStateMap *ThenStates,
950 ConsumedStateMap *ElseStates) {
951
952 ConsumedState VarState = ThenStates->getState(Test.Var);
953
954 if (VarState == CS_Unknown) {
955 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000956 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000957
958 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
959 ThenStates->markUnreachable();
960
DeLesley Hutchins66540852013-10-04 21:28:06 +0000961 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000962 ElseStates->markUnreachable();
963 }
964}
965
966void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
967 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
968
969 const VarTestResult &LTest = PInfo.getLTest(),
970 &RTest = PInfo.getRTest();
971
972 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
973 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
974
975 if (LTest.Var) {
976 if (PInfo.testEffectiveOp() == EO_And) {
977 if (LState == CS_Unknown) {
978 ThenStates->setState(LTest.Var, LTest.TestsFor);
979
980 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
981 ThenStates->markUnreachable();
982
983 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000984 if (RState == RTest.TestsFor)
985 ElseStates->markUnreachable();
986 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000987 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000988 }
989
990 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000991 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000992 ElseStates->setState(LTest.Var,
993 invertConsumedUnconsumed(LTest.TestsFor));
994
DeLesley Hutchins66540852013-10-04 21:28:06 +0000995 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000996 ElseStates->markUnreachable();
997
998 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
999 isKnownState(RState)) {
1000
DeLesley Hutchins66540852013-10-04 21:28:06 +00001001 if (RState == RTest.TestsFor)
1002 ElseStates->markUnreachable();
1003 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001004 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001005 }
1006 }
1007 }
1008
1009 if (RTest.Var) {
1010 if (PInfo.testEffectiveOp() == EO_And) {
1011 if (RState == CS_Unknown)
1012 ThenStates->setState(RTest.Var, RTest.TestsFor);
1013 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
1014 ThenStates->markUnreachable();
1015
DeLesley Hutchins66540852013-10-04 21:28:06 +00001016 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001017 if (RState == CS_Unknown)
1018 ElseStates->setState(RTest.Var,
1019 invertConsumedUnconsumed(RTest.TestsFor));
1020 else if (RState == RTest.TestsFor)
1021 ElseStates->markUnreachable();
1022 }
1023 }
1024}
1025
DeLesley Hutchins73858402013-10-09 18:30:24 +00001026bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
1027 const CFGBlock *TargetBlock) {
1028
1029 assert(CurrBlock && "Block pointer must not be NULL");
1030 assert(TargetBlock && "TargetBlock pointer must not be NULL");
1031
1032 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
1033 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
1034 PE = TargetBlock->pred_end(); PI != PE; ++PI) {
1035 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
1036 return false;
1037 }
1038 return true;
1039}
1040
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001041void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1042 ConsumedStateMap *StateMap,
1043 bool &AlreadyOwned) {
1044
DeLesley Hutchins73858402013-10-09 18:30:24 +00001045 assert(Block && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001046
1047 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1048
1049 if (Entry) {
1050 Entry->intersect(StateMap);
1051
1052 } else if (AlreadyOwned) {
1053 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
1054
1055 } else {
1056 StateMapsArray[Block->getBlockID()] = StateMap;
1057 AlreadyOwned = true;
1058 }
1059}
1060
1061void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
1062 ConsumedStateMap *StateMap) {
1063
DeLesley Hutchins73858402013-10-09 18:30:24 +00001064 assert(Block != NULL && "Block pointer must not be NULL");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001065
1066 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
1067
1068 if (Entry) {
1069 Entry->intersect(StateMap);
1070 delete StateMap;
1071
1072 } else {
1073 StateMapsArray[Block->getBlockID()] = StateMap;
1074 }
1075}
1076
DeLesley Hutchins73858402013-10-09 18:30:24 +00001077ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
1078 assert(Block && "Block pointer must not be NULL");
1079 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
1080
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001081 return StateMapsArray[Block->getBlockID()];
1082}
1083
DeLesley Hutchins73858402013-10-09 18:30:24 +00001084void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
1085 unsigned int BlockID = Block->getBlockID();
1086 delete StateMapsArray[BlockID];
1087 StateMapsArray[BlockID] = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001088}
1089
DeLesley Hutchins73858402013-10-09 18:30:24 +00001090ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
1091 assert(Block && "Block pointer must not be NULL");
1092
1093 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
1094 if (isBackEdgeTarget(Block)) {
1095 return new ConsumedStateMap(*StateMap);
1096 } else {
1097 StateMapsArray[Block->getBlockID()] = NULL;
1098 return StateMap;
1099 }
1100}
1101
1102bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
1103 assert(From && "From block must not be NULL");
1104 assert(To && "From block must not be NULL");
1105
1106 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
1107}
1108
1109bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
1110 assert(Block != NULL && "Block pointer must not be NULL");
1111
1112 // Anything with less than two predecessors can't be the target of a back
1113 // edge.
1114 if (Block->pred_size() < 2)
1115 return false;
1116
1117 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
1118 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
1119 PE = Block->pred_end(); PI != PE; ++PI) {
1120 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
1121 return true;
1122 }
1123 return false;
1124}
1125
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001126void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
1127 ConsumedWarningsHandlerBase &WarningsHandler) const {
1128
1129 ConsumedState ExpectedState;
1130
1131 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
1132 ++DMI) {
1133
1134 if (isa<ParmVarDecl>(DMI->first)) {
1135 const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
1136
1137 if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
1138
1139 ExpectedState =
1140 mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
1141
1142 if (DMI->second != ExpectedState) {
1143 WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
1144 Param->getNameAsString(), stateToString(ExpectedState),
1145 stateToString(DMI->second));
1146 }
1147 }
1148 }
1149}
1150
DeLesley Hutchins73858402013-10-09 18:30:24 +00001151ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001152 MapType::const_iterator Entry = Map.find(Var);
1153
1154 if (Entry != Map.end()) {
1155 return Entry->second;
1156
1157 } else {
1158 return CS_None;
1159 }
1160}
1161
1162void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
1163 ConsumedState LocalState;
1164
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001165 if (this->From && this->From == Other->From && !Other->Reachable) {
1166 this->markUnreachable();
1167 return;
1168 }
1169
DeLesley Hutchins73858402013-10-09 18:30:24 +00001170 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1171 DMI != DME; ++DMI) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001172
1173 LocalState = this->getState(DMI->first);
1174
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001175 if (LocalState == CS_None)
1176 continue;
1177
1178 if (LocalState != DMI->second)
1179 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001180 }
1181}
1182
DeLesley Hutchins73858402013-10-09 18:30:24 +00001183void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
1184 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
1185 ConsumedWarningsHandlerBase &WarningsHandler) {
1186
1187 ConsumedState LocalState;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001188 SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001189
1190 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(),
1191 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) {
1192
1193 LocalState = this->getState(DMI->first);
1194
1195 if (LocalState == CS_None)
1196 continue;
1197
1198 if (LocalState != DMI->second) {
1199 Map[DMI->first] = CS_Unknown;
1200 WarningsHandler.warnLoopStateMismatch(
1201 BlameLoc, DMI->first->getNameAsString());
1202 }
1203 }
1204}
1205
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001206void ConsumedStateMap::markUnreachable() {
1207 this->Reachable = false;
1208 Map.clear();
1209}
1210
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001211void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
1212 Map[Var] = State;
1213}
1214
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001215void ConsumedStateMap::remove(const VarDecl *Var) {
1216 Map.erase(Var);
1217}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001218
DeLesley Hutchins73858402013-10-09 18:30:24 +00001219bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
1220 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end();
1221 DMI != DME; ++DMI) {
1222
1223 if (this->getState(DMI->first) != DMI->second)
1224 return true;
1225 }
1226
1227 return false;
1228}
1229
David Blaikiea33ab602013-09-06 01:28:43 +00001230void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1231 const FunctionDecl *D) {
1232 QualType ReturnType;
1233 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1234 ASTContext &CurrContext = AC.getASTContext();
1235 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1236 } else
1237 ReturnType = D->getCallResultType();
1238
1239 if (D->hasAttr<ReturnTypestateAttr>()) {
1240 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1241
1242 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1243 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1244 // FIXME: This should be removed when template instantiation propagates
1245 // attributes at template specialization definition, not
1246 // declaration. When it is removed the test needs to be enabled
1247 // in SemaDeclAttr.cpp.
1248 WarningsHandler.warnReturnTypestateForUnconsumableType(
1249 RTSAttr->getLocation(), ReturnType.getAsString());
1250 ExpectedReturnState = CS_None;
1251 } else
1252 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1253 } else if (isConsumableType(ReturnType))
1254 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1255 else
1256 ExpectedReturnState = CS_None;
1257}
1258
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001259bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1260 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001261
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001262 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1263 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001264
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001265 if (const IfStmt *IfNode =
1266 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001267
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001268 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001269
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001270 PInfo = Visitor.getInfo(Cond);
1271 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1272 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1273
1274 if (PInfo.isTest()) {
1275 CurrStates->setSource(Cond);
1276 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001277 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001278
1279 } else if (PInfo.isBinTest()) {
1280 CurrStates->setSource(PInfo.testSourceNode());
1281 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001282 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001283
1284 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001285 delete FalseStates;
1286 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001287 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001288
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001289 } else if (const BinaryOperator *BinOp =
1290 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1291
1292 PInfo = Visitor.getInfo(BinOp->getLHS());
1293 if (!PInfo.isTest()) {
1294 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1295 PInfo = Visitor.getInfo(BinOp->getRHS());
1296
1297 if (!PInfo.isTest()) {
1298 delete FalseStates;
1299 return false;
1300 }
1301
1302 } else {
1303 delete FalseStates;
1304 return false;
1305 }
1306 }
1307
1308 CurrStates->setSource(BinOp);
1309 FalseStates->setSource(BinOp);
1310
1311 const VarTestResult &Test = PInfo.getTest();
1312 ConsumedState VarState = CurrStates->getState(Test.Var);
1313
1314 if (BinOp->getOpcode() == BO_LAnd) {
1315 if (VarState == CS_Unknown)
1316 CurrStates->setState(Test.Var, Test.TestsFor);
1317 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1318 CurrStates->markUnreachable();
1319
1320 } else if (BinOp->getOpcode() == BO_LOr) {
1321 if (VarState == CS_Unknown)
1322 FalseStates->setState(Test.Var,
1323 invertConsumedUnconsumed(Test.TestsFor));
1324 else if (VarState == Test.TestsFor)
1325 FalseStates->markUnreachable();
1326 }
1327
1328 } else {
1329 delete FalseStates;
1330 return false;
1331 }
1332
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001333 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1334
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001335 if (*SI)
1336 BlockInfo.addInfo(*SI, CurrStates);
1337 else
1338 delete CurrStates;
1339
1340 if (*++SI)
1341 BlockInfo.addInfo(*SI, FalseStates);
1342 else
1343 delete FalseStates;
1344
1345 CurrStates = NULL;
1346 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001347}
1348
1349void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1350 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001351 if (!D)
1352 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001353
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001354 CFG *CFGraph = AC.getCFG();
1355 if (!CFGraph)
1356 return;
DeLesley Hutchins52f717e2013-10-17 18:19:31 +00001357
David Blaikiea33ab602013-09-06 01:28:43 +00001358 determineExpectedReturnState(AC, D);
DeLesley Hutchins73858402013-10-09 18:30:24 +00001359
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001360 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
DeLesley Hutchins73858402013-10-09 18:30:24 +00001361 // AC.getCFG()->viewCFG(LangOptions());
1362
1363 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001364
1365 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001366 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1367
1368 // Add all trackable parameters to the state map.
1369 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1370 PE = D->param_end(); PI != PE; ++PI) {
1371 Visitor.VisitParmVarDecl(*PI);
1372 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001373
1374 // Visit all of the function's basic blocks.
1375 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1376 E = SortedGraph->end(); I != E; ++I) {
1377
1378 const CFGBlock *CurrBlock = *I;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001379
1380 if (CurrStates == NULL)
1381 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001382
1383 if (!CurrStates) {
1384 continue;
1385
1386 } else if (!CurrStates->isReachable()) {
1387 delete CurrStates;
1388 CurrStates = NULL;
1389 continue;
1390 }
1391
1392 Visitor.reset(CurrStates);
1393
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001394 // Visit all of the basic block's statements.
1395 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1396 BE = CurrBlock->end(); BI != BE; ++BI) {
1397
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001398 switch (BI->getKind()) {
1399 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001400 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001401 break;
DeLesley Hutchins627c7f92013-10-11 21:55:33 +00001402
1403 case CFGElement::TemporaryDtor: {
1404 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
1405 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
1406 PropagationInfo PInfo = Visitor.getInfo(BTE);
1407
1408 if (PInfo.isValid())
1409 Visitor.checkCallability(PInfo,
1410 DTor.getDestructorDecl(AC.getASTContext()),
1411 BTE->getExprLoc());
1412 break;
1413 }
1414
1415 case CFGElement::AutomaticObjectDtor: {
1416 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
1417
1418 const VarDecl *Var = DTor.getVarDecl();
1419 ConsumedState VarState = CurrStates->getState(Var);
1420
1421 if (VarState != CS_None) {
1422 PropagationInfo PInfo(Var);
1423
1424 Visitor.checkCallability(PInfo,
1425 DTor.getDestructorDecl(AC.getASTContext()),
1426 getLastStmtLoc(CurrBlock));
1427
1428 CurrStates->remove(Var);
1429 }
1430 break;
1431 }
1432
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001433 default:
1434 break;
1435 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001436 }
1437
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001438 // TODO: Handle other forms of branching with precision, including while-
1439 // and for-loops. (Deferred)
1440 if (!splitState(CurrBlock, Visitor)) {
1441 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001442
DeLesley Hutchins73858402013-10-09 18:30:24 +00001443 if (CurrBlock->succ_size() > 1 ||
1444 (CurrBlock->succ_size() == 1 &&
1445 (*CurrBlock->succ_begin())->pred_size() > 1)) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001446
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001447 bool OwnershipTaken = false;
1448
1449 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1450 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1451
DeLesley Hutchins73858402013-10-09 18:30:24 +00001452 if (*SI == NULL) continue;
1453
1454 if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
1455 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
1456 CurrStates,
1457 WarningsHandler);
1458
1459 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock))
1460 BlockInfo.discardInfo(*SI);
1461 } else {
1462 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1463 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001464 }
1465
1466 if (!OwnershipTaken)
1467 delete CurrStates;
1468
1469 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001470 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001471 }
DeLesley Hutchinscd0f6d72013-10-17 22:53:04 +00001472
1473 if (CurrBlock == &AC.getCFG()->getExit() &&
1474 D->getCallResultType()->isVoidType())
1475 CurrStates->checkParamsForReturnTypestate(D->getLocation(),
1476 WarningsHandler);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001477 } // End of block iterator.
1478
1479 // Delete the last existing state map.
1480 delete CurrStates;
1481
1482 WarningsHandler.emitDiagnostics();
1483}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001484}} // end namespace clang::consumed