blob: 78153a0a684e5e6be26926dfc95486560b944eb7 [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 Hutchins0e8534e2013-09-03 20:11:38 +000034// TODO: Add notes about the actual and expected state for
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000035// TODO: Correctly identify unreachable blocks when chaining boolean operators.
36// TODO: Warn about unreachable code.
37// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000038// TODO: Mark variables as Unknown going into while- or for-loops only if they
39// are referenced inside that block. (Deferred)
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000040// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
41// if (valid) ...; (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000042// TODO: Add a method(s) to identify which method calls perform what state
43// transitions. (Deferred)
44// TODO: Take notes on state transitions to provide better warning messages.
45// (Deferred)
46// TODO: Test nested conditionals: A) Checking the same value multiple times,
47// and 2) Checking different values. (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000048
49using namespace clang;
50using namespace consumed;
51
52// Key method definition
53ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
54
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000055static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
56 switch (State) {
57 case CS_Unconsumed:
58 return CS_Consumed;
59 case CS_Consumed:
60 return CS_Unconsumed;
61 case CS_None:
62 return CS_None;
63 case CS_Unknown:
64 return CS_Unknown;
65 }
66 llvm_unreachable("invalid enum");
67}
68
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +000069static bool isConsumableType(const QualType &QT) {
70 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
71 return RD->hasAttr<ConsumableAttr>();
72 else
73 return false;
74}
75
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000076static bool isKnownState(ConsumedState State) {
77 switch (State) {
78 case CS_Unconsumed:
79 case CS_Consumed:
80 return true;
81 case CS_None:
82 case CS_Unknown:
83 return false;
84 }
Aaron Ballman6b2ec032013-08-29 20:36:09 +000085 llvm_unreachable("invalid enum");
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000086}
87
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +000088static bool isTestingFunction(const FunctionDecl *FunDecl) {
89 return FunDecl->hasAttr<TestsUnconsumedAttr>();
90}
91
Eric Christophere988dc42013-09-03 20:43:00 +000092static ConsumedState
93mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
94
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +000095 switch (RTSAttr->getState()) {
96 case ReturnTypestateAttr::Unknown:
97 return CS_Unknown;
98 case ReturnTypestateAttr::Unconsumed:
99 return CS_Unconsumed;
100 case ReturnTypestateAttr::Consumed:
101 return CS_Consumed;
102 }
Eric Christophere988dc42013-09-03 20:43:00 +0000103 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000104}
105
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000106static StringRef stateToString(ConsumedState State) {
107 switch (State) {
108 case consumed::CS_None:
109 return "none";
110
111 case consumed::CS_Unknown:
112 return "unknown";
113
114 case consumed::CS_Unconsumed:
115 return "unconsumed";
116
117 case consumed::CS_Consumed:
118 return "consumed";
119 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000120 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000121}
122
123namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000124struct VarTestResult {
125 const VarDecl *Var;
126 ConsumedState TestsFor;
127};
128} // end anonymous::VarTestResult
129
130namespace clang {
131namespace consumed {
132
133enum EffectiveOp {
134 EO_And,
135 EO_Or
136};
137
138class PropagationInfo {
139 enum {
140 IT_None,
141 IT_State,
142 IT_Test,
143 IT_BinTest,
144 IT_Var
145 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000146
147 struct BinTestTy {
148 const BinaryOperator *Source;
149 EffectiveOp EOp;
150 VarTestResult LTest;
151 VarTestResult RTest;
152 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000153
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000154 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000155 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000156 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000157 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000158 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000159 };
160
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000161public:
162 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000163
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000164 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
165 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
166 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000167
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000168 Test.Var = Var;
169 Test.TestsFor = TestsFor;
170 }
171
172 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
173 const VarTestResult &LTest, const VarTestResult &RTest)
174 : InfoType(IT_BinTest) {
175
176 BinTest.Source = Source;
177 BinTest.EOp = EOp;
178 BinTest.LTest = LTest;
179 BinTest.RTest = RTest;
180 }
181
182 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
183 const VarDecl *LVar, ConsumedState LTestsFor,
184 const VarDecl *RVar, ConsumedState RTestsFor)
185 : InfoType(IT_BinTest) {
186
187 BinTest.Source = Source;
188 BinTest.EOp = EOp;
189 BinTest.LTest.Var = LVar;
190 BinTest.LTest.TestsFor = LTestsFor;
191 BinTest.RTest.Var = RVar;
192 BinTest.RTest.TestsFor = RTestsFor;
193 }
194
195 PropagationInfo(ConsumedState State) : InfoType(IT_State), State(State) {}
196 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
197
198 const ConsumedState & getState() const {
199 assert(InfoType == IT_State);
200 return State;
201 }
202
203 const VarTestResult & getTest() const {
204 assert(InfoType == IT_Test);
205 return Test;
206 }
207
208 const VarTestResult & getLTest() const {
209 assert(InfoType == IT_BinTest);
210 return BinTest.LTest;
211 }
212
213 const VarTestResult & getRTest() const {
214 assert(InfoType == IT_BinTest);
215 return BinTest.RTest;
216 }
217
218 const VarDecl * getVar() const {
219 assert(InfoType == IT_Var);
220 return Var;
221 }
222
223 EffectiveOp testEffectiveOp() const {
224 assert(InfoType == IT_BinTest);
225 return BinTest.EOp;
226 }
227
228 const BinaryOperator * testSourceNode() const {
229 assert(InfoType == IT_BinTest);
230 return BinTest.Source;
231 }
232
233 bool isValid() const { return InfoType != IT_None; }
234 bool isState() const { return InfoType == IT_State; }
235 bool isTest() const { return InfoType == IT_Test; }
236 bool isBinTest() const { return InfoType == IT_BinTest; }
237 bool isVar() const { return InfoType == IT_Var; }
238
239 PropagationInfo invertTest() const {
240 assert(InfoType == IT_Test || InfoType == IT_BinTest);
241
242 if (InfoType == IT_Test) {
243 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
244
245 } else if (InfoType == IT_BinTest) {
246 return PropagationInfo(BinTest.Source,
247 BinTest.EOp == EO_And ? EO_Or : EO_And,
248 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
249 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
250 } else {
251 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000252 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000253 }
254};
255
256class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000257
258 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
259 typedef std::pair<const Stmt *, PropagationInfo> PairType;
260 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000261 typedef MapType::const_iterator ConstInfoEntry;
262
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000263 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000264 ConsumedAnalyzer &Analyzer;
265 ConsumedStateMap *StateMap;
266 MapType PropagationMap;
267
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000268 void checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000269 const FunctionDecl *FunDecl,
270 const CallExpr *Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000271 void forwardInfo(const Stmt *From, const Stmt *To);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000272 void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000273 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000274 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
275 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000276
277public:
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000278
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000279 void Visit(const Stmt *StmtNode);
280
281 void VisitBinaryOperator(const BinaryOperator *BinOp);
282 void VisitCallExpr(const CallExpr *Call);
283 void VisitCastExpr(const CastExpr *Cast);
284 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
285 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
286 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
287 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
288 void VisitDeclStmt(const DeclStmt *DelcS);
289 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
290 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000291 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000292 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000293 void VisitUnaryOperator(const UnaryOperator *UOp);
294 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000295
DeLesley Hutchins42525982013-08-29 22:36:05 +0000296 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
297 ConsumedStateMap *StateMap)
298 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000299
300 PropagationInfo getInfo(const Stmt *StmtNode) const {
301 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
302
303 if (Entry != PropagationMap.end())
304 return Entry->second;
305 else
306 return PropagationInfo();
307 }
308
309 void reset(ConsumedStateMap *NewStateMap) {
310 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000311 }
312};
313
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000314// TODO: When we support CallableWhenConsumed this will have to check for
315// the different attributes and change the behavior bellow. (Deferred)
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000316void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000317 const FunctionDecl *FunDecl,
318 const CallExpr *Call) {
319
320 if (!FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) return;
321
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000322 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000323 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000324
325 switch (StateMap->getState(Var)) {
326 case CS_Consumed:
327 Analyzer.WarningsHandler.warnUseWhileConsumed(
328 FunDecl->getNameAsString(), Var->getNameAsString(),
329 Call->getExprLoc());
330 break;
331
332 case CS_Unknown:
333 Analyzer.WarningsHandler.warnUseInUnknownState(
334 FunDecl->getNameAsString(), Var->getNameAsString(),
335 Call->getExprLoc());
336 break;
337
338 case CS_None:
339 case CS_Unconsumed:
340 break;
341 }
342
343 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000344 switch (PInfo.getState()) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000345 case CS_Consumed:
346 Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(
347 FunDecl->getNameAsString(), Call->getExprLoc());
348 break;
349
350 case CS_Unknown:
351 Analyzer.WarningsHandler.warnUseOfTempInUnknownState(
352 FunDecl->getNameAsString(), Call->getExprLoc());
353 break;
354
355 case CS_None:
356 case CS_Unconsumed:
357 break;
358 }
359 }
360}
361
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000362void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
363 InfoEntry Entry = PropagationMap.find(From);
364
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000365 if (Entry != PropagationMap.end())
366 PropagationMap.insert(PairType(To, Entry->second));
367}
368
369void ConsumedStmtVisitor::handleTestingFunctionCall(const CallExpr *Call,
370 const VarDecl *Var) {
371
372 ConsumedState VarState = StateMap->getState(Var);
373
374 if (VarState != CS_Unknown) {
375 SourceLocation CallLoc = Call->getExprLoc();
376
377 if (!CallLoc.isMacroID())
378 Analyzer.WarningsHandler.warnUnnecessaryTest(Var->getNameAsString(),
379 stateToString(VarState), CallLoc);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000380 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000381
382 PropagationMap.insert(PairType(Call, PropagationInfo(Var, CS_Unconsumed)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000383}
384
385bool ConsumedStmtVisitor::isLikeMoveAssignment(
386 const CXXMethodDecl *MethodDecl) {
387
388 return MethodDecl->isMoveAssignmentOperator() ||
389 (MethodDecl->getOverloadedOperator() == OO_Equal &&
390 MethodDecl->getNumParams() == 1 &&
391 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
392}
393
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000394void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
395 const FunctionDecl *Fun,
396 QualType ReturnType) {
397 if (isConsumableType(ReturnType)) {
398
399 ConsumedState ReturnState;
400
401 if (Fun->hasAttr<ReturnTypestateAttr>())
402 ReturnState = mapReturnTypestateAttrState(
403 Fun->getAttr<ReturnTypestateAttr>());
404 else
405 ReturnState = CS_Unknown;
406
407 PropagationMap.insert(PairType(Call,
408 PropagationInfo(ReturnState)));
409 }
410}
411
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000412void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
413
414 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
415
416 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
417 CE = StmtNode->child_end(); CI != CE; ++CI) {
418
419 PropagationMap.erase(*CI);
420 }
421}
422
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000423void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
424 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000425 case BO_LAnd:
426 case BO_LOr : {
427 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
428 REntry = PropagationMap.find(BinOp->getRHS());
429
430 VarTestResult LTest, RTest;
431
432 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
433 LTest = LEntry->second.getTest();
434
435 } else {
436 LTest.Var = NULL;
437 LTest.TestsFor = CS_None;
438 }
439
440 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
441 RTest = REntry->second.getTest();
442
443 } else {
444 RTest.Var = NULL;
445 RTest.TestsFor = CS_None;
446 }
447
448 if (!(LTest.Var == NULL && RTest.Var == NULL))
449 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
450 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
451
452 break;
453 }
454
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000455 case BO_PtrMemD:
456 case BO_PtrMemI:
457 forwardInfo(BinOp->getLHS(), BinOp);
458 break;
459
460 default:
461 break;
462 }
463}
464
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000465void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
466 if (const FunctionDecl *FunDecl =
467 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
468
469 // Special case for the std::move function.
470 // TODO: Make this more specific. (Deferred)
471 if (FunDecl->getNameAsString() == "move") {
472 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
473
474 if (Entry != PropagationMap.end()) {
475 PropagationMap.insert(PairType(Call, Entry->second));
476 }
477
478 return;
479 }
480
481 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
482
483 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
484 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
485
486 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
487
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000488 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000489 continue;
490 }
491
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000492 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000493
494 if (ParamType->isRValueReferenceType() ||
495 (ParamType->isLValueReferenceType() &&
496 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
497
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000498 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000499
500 } else if (!(ParamType.isConstQualified() ||
501 ((ParamType->isReferenceType() ||
502 ParamType->isPointerType()) &&
503 ParamType->getPointeeType().isConstQualified()))) {
504
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000505 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000506 }
507 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000508
509 propagateReturnType(Call, FunDecl, FunDecl->getCallResultType());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000510 }
511}
512
513void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000514 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000515}
516
517void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
518 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000519
520 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000521 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
522
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000523 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000524 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000525
526 PropagationMap.insert(PairType(Call,
527 PropagationInfo(consumed::CS_Consumed)));
528
529 } else if (Constructor->isMoveConstructor()) {
530
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000531 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000532 PropagationMap.find(Call->getArg(0))->second;
533
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000534 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000535 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000536
537 PropagationMap.insert(PairType(Call,
538 PropagationInfo(StateMap->getState(Var))));
539
540 StateMap->setState(Var, consumed::CS_Consumed);
541
542 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000543 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000544 }
545
546 } else if (Constructor->isCopyConstructor()) {
547 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
548
549 if (Entry != PropagationMap.end())
550 PropagationMap.insert(PairType(Call, Entry->second));
551
552 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000553 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000554 }
555 }
556}
557
558void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
559 const CXXMemberCallExpr *Call) {
560
561 VisitCallExpr(Call);
562
563 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
564
565 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000566 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000567 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000568
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000569 checkCallability(PInfo, MethodDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000570
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000571 if (PInfo.isVar()) {
572 if (isTestingFunction(MethodDecl))
573 handleTestingFunctionCall(Call, PInfo.getVar());
574 else if (MethodDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000575 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000576 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000577 }
578}
579
580void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
581 const CXXOperatorCallExpr *Call) {
582
583 const FunctionDecl *FunDecl =
584 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
585
586 if (!FunDecl) return;
587
588 if (isa<CXXMethodDecl>(FunDecl) &&
589 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
590
591 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
592 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
593
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000594 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000595
596 if (LEntry != PropagationMap.end() &&
597 REntry != PropagationMap.end()) {
598
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000599 LPInfo = LEntry->second;
600 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000601
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000602 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000603 StateMap->setState(LPInfo.getVar(),
604 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000605
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000606 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000607
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000608 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000609
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000610 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000611 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000612
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000613 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000614
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000615 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000616 PropagationMap.insert(PairType(Call,
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000617 PropagationInfo(StateMap->getState(RPInfo.getVar()))));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000618
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000619 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000620
621 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000622 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000623 }
624
625 } else if (LEntry != PropagationMap.end() &&
626 REntry == PropagationMap.end()) {
627
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000628 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000629
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000630 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000631 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000632
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000633 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000634
635 } else {
636 PropagationMap.insert(PairType(Call,
637 PropagationInfo(consumed::CS_Unknown)));
638 }
639
640 } else if (LEntry == PropagationMap.end() &&
641 REntry != PropagationMap.end()) {
642
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000643 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000644
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000645 if (RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000646 const VarDecl *Var = RPInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000647
648 PropagationMap.insert(PairType(Call,
649 PropagationInfo(StateMap->getState(Var))));
650
651 StateMap->setState(Var, consumed::CS_Consumed);
652
653 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000654 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000655 }
656 }
657
658 } else {
659
660 VisitCallExpr(Call);
661
662 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
663
664 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000665 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000666
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000667 checkCallability(PInfo, FunDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000668
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000669 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000670 if (isTestingFunction(FunDecl))
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000671 handleTestingFunctionCall(Call, PInfo.getVar());
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000672 else if (FunDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000673 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000674 }
675 }
676 }
677}
678
679void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
680 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
681 if (StateMap->getState(Var) != consumed::CS_None)
682 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
683}
684
685void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
686 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
687 DE = DeclS->decl_end(); DI != DE; ++DI) {
688
689 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
690 }
691
692 if (DeclS->isSingleDecl())
693 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
694 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
695}
696
697void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
698 const MaterializeTemporaryExpr *Temp) {
699
700 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
701
702 if (Entry != PropagationMap.end())
703 PropagationMap.insert(PairType(Temp, Entry->second));
704}
705
706void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
707 forwardInfo(MExpr->getBase(), MExpr);
708}
709
DeLesley Hutchins42525982013-08-29 22:36:05 +0000710
711void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000712 if (isConsumableType(Param->getType()))
DeLesley Hutchins42525982013-08-29 22:36:05 +0000713 StateMap->setState(Param, consumed::CS_Unknown);
714}
715
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000716void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
717 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
718 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
719
720 if (Entry != PropagationMap.end()) {
721 assert(Entry->second.isState() || Entry->second.isVar());
722
723 ConsumedState RetState = Entry->second.isState() ?
724 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
725
726 if (RetState != ExpectedState)
727 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
728 Ret->getReturnLoc(), stateToString(ExpectedState),
729 stateToString(RetState));
730 }
731 }
732}
733
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000734void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000735 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
736 if (Entry == PropagationMap.end()) return;
737
738 switch (UOp->getOpcode()) {
739 case UO_AddrOf:
740 PropagationMap.insert(PairType(UOp, Entry->second));
741 break;
742
743 case UO_LNot:
744 if (Entry->second.isTest() || Entry->second.isBinTest())
745 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
746 break;
747
748 default:
749 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000750 }
751}
752
753void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000754 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000755 if (Var->hasInit()) {
756 PropagationInfo PInfo =
757 PropagationMap.find(Var->getInit())->second;
758
759 StateMap->setState(Var, PInfo.isVar() ?
760 StateMap->getState(PInfo.getVar()) : PInfo.getState());
761
762 } else {
763 StateMap->setState(Var, consumed::CS_Unknown);
764 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000765 }
766}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000767}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000768
769namespace clang {
770namespace consumed {
771
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000772void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
773 ConsumedStateMap *ThenStates,
774 ConsumedStateMap *ElseStates) {
775
776 ConsumedState VarState = ThenStates->getState(Test.Var);
777
778 if (VarState == CS_Unknown) {
779 ThenStates->setState(Test.Var, Test.TestsFor);
780 if (ElseStates)
781 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
782
783 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
784 ThenStates->markUnreachable();
785
786 } else if (VarState == Test.TestsFor && ElseStates) {
787 ElseStates->markUnreachable();
788 }
789}
790
791void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
792 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
793
794 const VarTestResult &LTest = PInfo.getLTest(),
795 &RTest = PInfo.getRTest();
796
797 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
798 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
799
800 if (LTest.Var) {
801 if (PInfo.testEffectiveOp() == EO_And) {
802 if (LState == CS_Unknown) {
803 ThenStates->setState(LTest.Var, LTest.TestsFor);
804
805 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
806 ThenStates->markUnreachable();
807
808 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
809 if (RState == RTest.TestsFor) {
810 if (ElseStates)
811 ElseStates->markUnreachable();
812 } else {
813 ThenStates->markUnreachable();
814 }
815 }
816
817 } else {
818 if (LState == CS_Unknown && ElseStates) {
819 ElseStates->setState(LTest.Var,
820 invertConsumedUnconsumed(LTest.TestsFor));
821
822 } else if (LState == LTest.TestsFor && ElseStates) {
823 ElseStates->markUnreachable();
824
825 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
826 isKnownState(RState)) {
827
828 if (RState == RTest.TestsFor) {
829 if (ElseStates)
830 ElseStates->markUnreachable();
831 } else {
832 ThenStates->markUnreachable();
833 }
834 }
835 }
836 }
837
838 if (RTest.Var) {
839 if (PInfo.testEffectiveOp() == EO_And) {
840 if (RState == CS_Unknown)
841 ThenStates->setState(RTest.Var, RTest.TestsFor);
842 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
843 ThenStates->markUnreachable();
844
845 } else if (ElseStates) {
846 if (RState == CS_Unknown)
847 ElseStates->setState(RTest.Var,
848 invertConsumedUnconsumed(RTest.TestsFor));
849 else if (RState == RTest.TestsFor)
850 ElseStates->markUnreachable();
851 }
852 }
853}
854
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000855void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
856 ConsumedStateMap *StateMap,
857 bool &AlreadyOwned) {
858
859 if (VisitedBlocks.alreadySet(Block)) return;
860
861 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
862
863 if (Entry) {
864 Entry->intersect(StateMap);
865
866 } else if (AlreadyOwned) {
867 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
868
869 } else {
870 StateMapsArray[Block->getBlockID()] = StateMap;
871 AlreadyOwned = true;
872 }
873}
874
875void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
876 ConsumedStateMap *StateMap) {
877
878 if (VisitedBlocks.alreadySet(Block)) {
879 delete StateMap;
880 return;
881 }
882
883 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
884
885 if (Entry) {
886 Entry->intersect(StateMap);
887 delete StateMap;
888
889 } else {
890 StateMapsArray[Block->getBlockID()] = StateMap;
891 }
892}
893
894ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
895 return StateMapsArray[Block->getBlockID()];
896}
897
898void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {
899 VisitedBlocks.insert(Block);
900}
901
902ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {
903 MapType::const_iterator Entry = Map.find(Var);
904
905 if (Entry != Map.end()) {
906 return Entry->second;
907
908 } else {
909 return CS_None;
910 }
911}
912
913void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
914 ConsumedState LocalState;
915
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000916 if (this->From && this->From == Other->From && !Other->Reachable) {
917 this->markUnreachable();
918 return;
919 }
920
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000921 for (MapType::const_iterator DMI = Other->Map.begin(),
922 DME = Other->Map.end(); DMI != DME; ++DMI) {
923
924 LocalState = this->getState(DMI->first);
925
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000926 if (LocalState == CS_None)
927 continue;
928
929 if (LocalState != DMI->second)
930 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000931 }
932}
933
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000934void ConsumedStateMap::markUnreachable() {
935 this->Reachable = false;
936 Map.clear();
937}
938
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000939void ConsumedStateMap::makeUnknown() {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000940 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
941 ++DMI) {
942
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000943 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000944 }
945}
946
947void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
948 Map[Var] = State;
949}
950
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000951void ConsumedStateMap::remove(const VarDecl *Var) {
952 Map.erase(Var);
953}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000954
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000955bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
956 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000957
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000958 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
959 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000960
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000961 if (const IfStmt *IfNode =
962 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000963
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000964 bool HasElse = IfNode->getElse() != NULL;
965 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000966
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000967 PInfo = Visitor.getInfo(Cond);
968 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
969 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
970
971 if (PInfo.isTest()) {
972 CurrStates->setSource(Cond);
973 FalseStates->setSource(Cond);
974
975 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates,
976 HasElse ? FalseStates : NULL);
977
978 } else if (PInfo.isBinTest()) {
979 CurrStates->setSource(PInfo.testSourceNode());
980 FalseStates->setSource(PInfo.testSourceNode());
981
982 splitVarStateForIfBinOp(PInfo, CurrStates, HasElse ? FalseStates : NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000983
984 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000985 delete FalseStates;
986 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000987 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000988
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000989 } else if (const BinaryOperator *BinOp =
990 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
991
992 PInfo = Visitor.getInfo(BinOp->getLHS());
993 if (!PInfo.isTest()) {
994 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
995 PInfo = Visitor.getInfo(BinOp->getRHS());
996
997 if (!PInfo.isTest()) {
998 delete FalseStates;
999 return false;
1000 }
1001
1002 } else {
1003 delete FalseStates;
1004 return false;
1005 }
1006 }
1007
1008 CurrStates->setSource(BinOp);
1009 FalseStates->setSource(BinOp);
1010
1011 const VarTestResult &Test = PInfo.getTest();
1012 ConsumedState VarState = CurrStates->getState(Test.Var);
1013
1014 if (BinOp->getOpcode() == BO_LAnd) {
1015 if (VarState == CS_Unknown)
1016 CurrStates->setState(Test.Var, Test.TestsFor);
1017 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1018 CurrStates->markUnreachable();
1019
1020 } else if (BinOp->getOpcode() == BO_LOr) {
1021 if (VarState == CS_Unknown)
1022 FalseStates->setState(Test.Var,
1023 invertConsumedUnconsumed(Test.TestsFor));
1024 else if (VarState == Test.TestsFor)
1025 FalseStates->markUnreachable();
1026 }
1027
1028 } else {
1029 delete FalseStates;
1030 return false;
1031 }
1032
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001033 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1034
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001035 if (*SI)
1036 BlockInfo.addInfo(*SI, CurrStates);
1037 else
1038 delete CurrStates;
1039
1040 if (*++SI)
1041 BlockInfo.addInfo(*SI, FalseStates);
1042 else
1043 delete FalseStates;
1044
1045 CurrStates = NULL;
1046 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001047}
1048
1049void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1050 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
1051
1052 if (!D) return;
1053
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +00001054 // FIXME: This should be removed when template instantiation propagates
1055 // attributes at template specialization definition, not declaration.
1056 // When it is removed the test needs to be enabled in SemaDeclAttr.cpp.
1057 QualType ReturnType;
1058 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1059 ASTContext &CurrContext = AC.getASTContext();
1060 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1061
1062 } else {
1063 ReturnType = D->getCallResultType();
1064 }
1065
1066 // Determine the expected return value.
1067 if (D->hasAttr<ReturnTypestateAttr>()) {
1068
1069 ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1070
1071 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1072 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1073 // FIXME: This branch can be removed with the code above.
1074 WarningsHandler.warnReturnTypestateForUnconsumableType(
1075 RTSAttr->getLocation(), ReturnType.getAsString());
1076 ExpectedReturnState = CS_None;
1077
1078 } else {
1079 switch (RTSAttr->getState()) {
1080 case ReturnTypestateAttr::Unknown:
1081 ExpectedReturnState = CS_Unknown;
1082 break;
1083
1084 case ReturnTypestateAttr::Unconsumed:
1085 ExpectedReturnState = CS_Unconsumed;
1086 break;
1087
1088 case ReturnTypestateAttr::Consumed:
1089 ExpectedReturnState = CS_Consumed;
1090 break;
1091 }
1092 }
1093
1094 } else if (isConsumableType(ReturnType)) {
1095 ExpectedReturnState = CS_Unknown;
1096
1097 } else {
1098 ExpectedReturnState = CS_None;
1099 }
1100
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001101 BlockInfo = ConsumedBlockInfo(AC.getCFG());
1102
1103 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1104
1105 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001106 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1107
1108 // Add all trackable parameters to the state map.
1109 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1110 PE = D->param_end(); PI != PE; ++PI) {
1111 Visitor.VisitParmVarDecl(*PI);
1112 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001113
1114 // Visit all of the function's basic blocks.
1115 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1116 E = SortedGraph->end(); I != E; ++I) {
1117
1118 const CFGBlock *CurrBlock = *I;
1119 BlockInfo.markVisited(CurrBlock);
1120
1121 if (CurrStates == NULL)
1122 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001123
1124 if (!CurrStates) {
1125 continue;
1126
1127 } else if (!CurrStates->isReachable()) {
1128 delete CurrStates;
1129 CurrStates = NULL;
1130 continue;
1131 }
1132
1133 Visitor.reset(CurrStates);
1134
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001135 // Visit all of the basic block's statements.
1136 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1137 BE = CurrBlock->end(); BI != BE; ++BI) {
1138
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001139 switch (BI->getKind()) {
1140 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001141 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001142 break;
1143 case CFGElement::AutomaticObjectDtor:
1144 CurrStates->remove(BI->castAs<CFGAutomaticObjDtor>().getVarDecl());
1145 default:
1146 break;
1147 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001148 }
1149
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001150 // TODO: Handle other forms of branching with precision, including while-
1151 // and for-loops. (Deferred)
1152 if (!splitState(CurrBlock, Visitor)) {
1153 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001154
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001155 if (CurrBlock->succ_size() > 1) {
1156 CurrStates->makeUnknown();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001157
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001158 bool OwnershipTaken = false;
1159
1160 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1161 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1162
1163 if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1164 }
1165
1166 if (!OwnershipTaken)
1167 delete CurrStates;
1168
1169 CurrStates = NULL;
1170
1171 } else if (CurrBlock->succ_size() == 1 &&
1172 (*CurrBlock->succ_begin())->pred_size() > 1) {
1173
1174 BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);
1175 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001176 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001177 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001178 } // End of block iterator.
1179
1180 // Delete the last existing state map.
1181 delete CurrStates;
1182
1183 WarningsHandler.emitDiagnostics();
1184}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001185}} // end namespace clang::consumed