blob: e5231e07c284e81d7ba0329a6df5ef2466400eb1 [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 Hutchinsb7dc1f52013-08-29 17:26:57 +000034// TODO: Correctly identify unreachable blocks when chaining boolean operators.
35// TODO: Warn about unreachable code.
36// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000037// TODO: Mark variables as Unknown going into while- or for-loops only if they
38// are referenced inside that block. (Deferred)
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000039// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
40// if (valid) ...; (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000041// TODO: Add a method(s) to identify which method calls perform what state
42// transitions. (Deferred)
43// 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)
47// TODO: Test IsFalseVisitor with values in the unknown state. (Deferred)
48// TODO: Look into combining IsFalseVisitor and TestedVarsVisitor. (Deferred)
49
50using namespace clang;
51using namespace consumed;
52
53// Key method definition
54ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
55
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000056static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
57 switch (State) {
58 case CS_Unconsumed:
59 return CS_Consumed;
60 case CS_Consumed:
61 return CS_Unconsumed;
62 case CS_None:
63 return CS_None;
64 case CS_Unknown:
65 return CS_Unknown;
66 }
67 llvm_unreachable("invalid enum");
68}
69
70static bool isKnownState(ConsumedState State) {
71 switch (State) {
72 case CS_Unconsumed:
73 case CS_Consumed:
74 return true;
75 case CS_None:
76 case CS_Unknown:
77 return false;
78 }
Aaron Ballman6b2ec032013-08-29 20:36:09 +000079 llvm_unreachable("invalid enum");
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000080}
81
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +000082static bool isTestingFunction(const FunctionDecl *FunDecl) {
83 return FunDecl->hasAttr<TestsUnconsumedAttr>();
84}
85
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000086static StringRef stateToString(ConsumedState State) {
87 switch (State) {
88 case consumed::CS_None:
89 return "none";
90
91 case consumed::CS_Unknown:
92 return "unknown";
93
94 case consumed::CS_Unconsumed:
95 return "unconsumed";
96
97 case consumed::CS_Consumed:
98 return "consumed";
99 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000100 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000101}
102
103namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000104struct VarTestResult {
105 const VarDecl *Var;
106 ConsumedState TestsFor;
107};
108} // end anonymous::VarTestResult
109
110namespace clang {
111namespace consumed {
112
113enum EffectiveOp {
114 EO_And,
115 EO_Or
116};
117
118class PropagationInfo {
119 enum {
120 IT_None,
121 IT_State,
122 IT_Test,
123 IT_BinTest,
124 IT_Var
125 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000126
127 struct BinTestTy {
128 const BinaryOperator *Source;
129 EffectiveOp EOp;
130 VarTestResult LTest;
131 VarTestResult RTest;
132 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000133
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000134 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000135 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000136 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000137 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000138 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000139 };
140
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000141public:
142 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000143
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000144 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
145 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
146 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000147
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000148 Test.Var = Var;
149 Test.TestsFor = TestsFor;
150 }
151
152 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
153 const VarTestResult &LTest, const VarTestResult &RTest)
154 : InfoType(IT_BinTest) {
155
156 BinTest.Source = Source;
157 BinTest.EOp = EOp;
158 BinTest.LTest = LTest;
159 BinTest.RTest = RTest;
160 }
161
162 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
163 const VarDecl *LVar, ConsumedState LTestsFor,
164 const VarDecl *RVar, ConsumedState RTestsFor)
165 : InfoType(IT_BinTest) {
166
167 BinTest.Source = Source;
168 BinTest.EOp = EOp;
169 BinTest.LTest.Var = LVar;
170 BinTest.LTest.TestsFor = LTestsFor;
171 BinTest.RTest.Var = RVar;
172 BinTest.RTest.TestsFor = RTestsFor;
173 }
174
175 PropagationInfo(ConsumedState State) : InfoType(IT_State), State(State) {}
176 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
177
178 const ConsumedState & getState() const {
179 assert(InfoType == IT_State);
180 return State;
181 }
182
183 const VarTestResult & getTest() const {
184 assert(InfoType == IT_Test);
185 return Test;
186 }
187
188 const VarTestResult & getLTest() const {
189 assert(InfoType == IT_BinTest);
190 return BinTest.LTest;
191 }
192
193 const VarTestResult & getRTest() const {
194 assert(InfoType == IT_BinTest);
195 return BinTest.RTest;
196 }
197
198 const VarDecl * getVar() const {
199 assert(InfoType == IT_Var);
200 return Var;
201 }
202
203 EffectiveOp testEffectiveOp() const {
204 assert(InfoType == IT_BinTest);
205 return BinTest.EOp;
206 }
207
208 const BinaryOperator * testSourceNode() const {
209 assert(InfoType == IT_BinTest);
210 return BinTest.Source;
211 }
212
213 bool isValid() const { return InfoType != IT_None; }
214 bool isState() const { return InfoType == IT_State; }
215 bool isTest() const { return InfoType == IT_Test; }
216 bool isBinTest() const { return InfoType == IT_BinTest; }
217 bool isVar() const { return InfoType == IT_Var; }
218
219 PropagationInfo invertTest() const {
220 assert(InfoType == IT_Test || InfoType == IT_BinTest);
221
222 if (InfoType == IT_Test) {
223 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
224
225 } else if (InfoType == IT_BinTest) {
226 return PropagationInfo(BinTest.Source,
227 BinTest.EOp == EO_And ? EO_Or : EO_And,
228 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
229 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
230 } else {
231 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000232 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000233 }
234};
235
236class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000237
238 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
239 typedef std::pair<const Stmt *, PropagationInfo> PairType;
240 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000241 typedef MapType::const_iterator ConstInfoEntry;
242
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000243 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000244 ConsumedAnalyzer &Analyzer;
245 ConsumedStateMap *StateMap;
246 MapType PropagationMap;
247
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000248 void checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000249 const FunctionDecl *FunDecl,
250 const CallExpr *Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000251 void forwardInfo(const Stmt *From, const Stmt *To);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000252 void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000253 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
254
255public:
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000256
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000257 void Visit(const Stmt *StmtNode);
258
259 void VisitBinaryOperator(const BinaryOperator *BinOp);
260 void VisitCallExpr(const CallExpr *Call);
261 void VisitCastExpr(const CastExpr *Cast);
262 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
263 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
264 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
265 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
266 void VisitDeclStmt(const DeclStmt *DelcS);
267 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
268 void VisitMemberExpr(const MemberExpr *MExpr);
269 void VisitUnaryOperator(const UnaryOperator *UOp);
270 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000271
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000272 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer)
273 : AC(AC), Analyzer(Analyzer), StateMap(NULL) {}
274
275 PropagationInfo getInfo(const Stmt *StmtNode) const {
276 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
277
278 if (Entry != PropagationMap.end())
279 return Entry->second;
280 else
281 return PropagationInfo();
282 }
283
284 void reset(ConsumedStateMap *NewStateMap) {
285 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000286 }
287};
288
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000289// TODO: When we support CallableWhenConsumed this will have to check for
290// the different attributes and change the behavior bellow. (Deferred)
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000291void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000292 const FunctionDecl *FunDecl,
293 const CallExpr *Call) {
294
295 if (!FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) return;
296
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000297 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000298 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000299
300 switch (StateMap->getState(Var)) {
301 case CS_Consumed:
302 Analyzer.WarningsHandler.warnUseWhileConsumed(
303 FunDecl->getNameAsString(), Var->getNameAsString(),
304 Call->getExprLoc());
305 break;
306
307 case CS_Unknown:
308 Analyzer.WarningsHandler.warnUseInUnknownState(
309 FunDecl->getNameAsString(), Var->getNameAsString(),
310 Call->getExprLoc());
311 break;
312
313 case CS_None:
314 case CS_Unconsumed:
315 break;
316 }
317
318 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000319 switch (PInfo.getState()) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000320 case CS_Consumed:
321 Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(
322 FunDecl->getNameAsString(), Call->getExprLoc());
323 break;
324
325 case CS_Unknown:
326 Analyzer.WarningsHandler.warnUseOfTempInUnknownState(
327 FunDecl->getNameAsString(), Call->getExprLoc());
328 break;
329
330 case CS_None:
331 case CS_Unconsumed:
332 break;
333 }
334 }
335}
336
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000337void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
338 InfoEntry Entry = PropagationMap.find(From);
339
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000340 if (Entry != PropagationMap.end())
341 PropagationMap.insert(PairType(To, Entry->second));
342}
343
344void ConsumedStmtVisitor::handleTestingFunctionCall(const CallExpr *Call,
345 const VarDecl *Var) {
346
347 ConsumedState VarState = StateMap->getState(Var);
348
349 if (VarState != CS_Unknown) {
350 SourceLocation CallLoc = Call->getExprLoc();
351
352 if (!CallLoc.isMacroID())
353 Analyzer.WarningsHandler.warnUnnecessaryTest(Var->getNameAsString(),
354 stateToString(VarState), CallLoc);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000355 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000356
357 PropagationMap.insert(PairType(Call, PropagationInfo(Var, CS_Unconsumed)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000358}
359
360bool ConsumedStmtVisitor::isLikeMoveAssignment(
361 const CXXMethodDecl *MethodDecl) {
362
363 return MethodDecl->isMoveAssignmentOperator() ||
364 (MethodDecl->getOverloadedOperator() == OO_Equal &&
365 MethodDecl->getNumParams() == 1 &&
366 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
367}
368
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000369void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
370
371 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
372
373 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
374 CE = StmtNode->child_end(); CI != CE; ++CI) {
375
376 PropagationMap.erase(*CI);
377 }
378}
379
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000380void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
381 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000382 case BO_LAnd:
383 case BO_LOr : {
384 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
385 REntry = PropagationMap.find(BinOp->getRHS());
386
387 VarTestResult LTest, RTest;
388
389 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
390 LTest = LEntry->second.getTest();
391
392 } else {
393 LTest.Var = NULL;
394 LTest.TestsFor = CS_None;
395 }
396
397 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
398 RTest = REntry->second.getTest();
399
400 } else {
401 RTest.Var = NULL;
402 RTest.TestsFor = CS_None;
403 }
404
405 if (!(LTest.Var == NULL && RTest.Var == NULL))
406 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
407 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
408
409 break;
410 }
411
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000412 case BO_PtrMemD:
413 case BO_PtrMemI:
414 forwardInfo(BinOp->getLHS(), BinOp);
415 break;
416
417 default:
418 break;
419 }
420}
421
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000422void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
423 if (const FunctionDecl *FunDecl =
424 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
425
426 // Special case for the std::move function.
427 // TODO: Make this more specific. (Deferred)
428 if (FunDecl->getNameAsString() == "move") {
429 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
430
431 if (Entry != PropagationMap.end()) {
432 PropagationMap.insert(PairType(Call, Entry->second));
433 }
434
435 return;
436 }
437
438 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
439
440 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
441 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
442
443 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
444
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000445 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000446 continue;
447 }
448
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000449 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000450
451 if (ParamType->isRValueReferenceType() ||
452 (ParamType->isLValueReferenceType() &&
453 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
454
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000455 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000456
457 } else if (!(ParamType.isConstQualified() ||
458 ((ParamType->isReferenceType() ||
459 ParamType->isPointerType()) &&
460 ParamType->getPointeeType().isConstQualified()))) {
461
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000462 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000463 }
464 }
465 }
466}
467
468void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000469 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000470}
471
472void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
473 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000474
475 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000476 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
477
478 if (Analyzer.isConsumableType(ThisType)) {
479 if (Constructor->hasAttr<ConsumesAttr>() ||
480 Constructor->isDefaultConstructor()) {
481
482 PropagationMap.insert(PairType(Call,
483 PropagationInfo(consumed::CS_Consumed)));
484
485 } else if (Constructor->isMoveConstructor()) {
486
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000487 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000488 PropagationMap.find(Call->getArg(0))->second;
489
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000490 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000491 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000492
493 PropagationMap.insert(PairType(Call,
494 PropagationInfo(StateMap->getState(Var))));
495
496 StateMap->setState(Var, consumed::CS_Consumed);
497
498 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000499 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000500 }
501
502 } else if (Constructor->isCopyConstructor()) {
503 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
504
505 if (Entry != PropagationMap.end())
506 PropagationMap.insert(PairType(Call, Entry->second));
507
508 } else {
509 PropagationMap.insert(PairType(Call,
510 PropagationInfo(consumed::CS_Unconsumed)));
511 }
512 }
513}
514
515void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
516 const CXXMemberCallExpr *Call) {
517
518 VisitCallExpr(Call);
519
520 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
521
522 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000523 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000524 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000525
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000526 checkCallability(PInfo, MethodDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000527
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000528 if (PInfo.isVar()) {
529 if (isTestingFunction(MethodDecl))
530 handleTestingFunctionCall(Call, PInfo.getVar());
531 else if (MethodDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000532 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000533 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000534 }
535}
536
537void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
538 const CXXOperatorCallExpr *Call) {
539
540 const FunctionDecl *FunDecl =
541 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
542
543 if (!FunDecl) return;
544
545 if (isa<CXXMethodDecl>(FunDecl) &&
546 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
547
548 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
549 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
550
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000551 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000552
553 if (LEntry != PropagationMap.end() &&
554 REntry != PropagationMap.end()) {
555
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000556 LPInfo = LEntry->second;
557 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000558
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000559 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000560 StateMap->setState(LPInfo.getVar(),
561 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000562
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000563 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000564
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000565 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000566
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000567 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000568 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000569
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000570 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000571
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000572 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000573 PropagationMap.insert(PairType(Call,
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000574 PropagationInfo(StateMap->getState(RPInfo.getVar()))));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000575
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000576 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000577
578 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000579 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000580 }
581
582 } else if (LEntry != PropagationMap.end() &&
583 REntry == PropagationMap.end()) {
584
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000585 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000586
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000587 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000588 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000589
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000590 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000591
592 } else {
593 PropagationMap.insert(PairType(Call,
594 PropagationInfo(consumed::CS_Unknown)));
595 }
596
597 } else if (LEntry == PropagationMap.end() &&
598 REntry != PropagationMap.end()) {
599
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000600 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000601
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000602 if (RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000603 const VarDecl *Var = RPInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000604
605 PropagationMap.insert(PairType(Call,
606 PropagationInfo(StateMap->getState(Var))));
607
608 StateMap->setState(Var, consumed::CS_Consumed);
609
610 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000611 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000612 }
613 }
614
615 } else {
616
617 VisitCallExpr(Call);
618
619 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
620
621 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000622 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000623
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000624 checkCallability(PInfo, FunDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000625
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000626 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000627 if (isTestingFunction(FunDecl))
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000628 handleTestingFunctionCall(Call, PInfo.getVar());
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000629 else if (FunDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000630 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000631 }
632 }
633 }
634}
635
636void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
637 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
638 if (StateMap->getState(Var) != consumed::CS_None)
639 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
640}
641
642void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
643 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
644 DE = DeclS->decl_end(); DI != DE; ++DI) {
645
646 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
647 }
648
649 if (DeclS->isSingleDecl())
650 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
651 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
652}
653
654void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
655 const MaterializeTemporaryExpr *Temp) {
656
657 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
658
659 if (Entry != PropagationMap.end())
660 PropagationMap.insert(PairType(Temp, Entry->second));
661}
662
663void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
664 forwardInfo(MExpr->getBase(), MExpr);
665}
666
667void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000668 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
669 if (Entry == PropagationMap.end()) return;
670
671 switch (UOp->getOpcode()) {
672 case UO_AddrOf:
673 PropagationMap.insert(PairType(UOp, Entry->second));
674 break;
675
676 case UO_LNot:
677 if (Entry->second.isTest() || Entry->second.isBinTest())
678 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
679 break;
680
681 default:
682 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000683 }
684}
685
686void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
687 if (Analyzer.isConsumableType(Var->getType())) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000688 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000689 PropagationMap.find(Var->getInit())->second;
690
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000691 StateMap->setState(Var, PInfo.isVar() ?
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000692 StateMap->getState(PInfo.getVar()) : PInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000693 }
694}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000695}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000696
697namespace clang {
698namespace consumed {
699
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000700void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
701 ConsumedStateMap *ThenStates,
702 ConsumedStateMap *ElseStates) {
703
704 ConsumedState VarState = ThenStates->getState(Test.Var);
705
706 if (VarState == CS_Unknown) {
707 ThenStates->setState(Test.Var, Test.TestsFor);
708 if (ElseStates)
709 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
710
711 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
712 ThenStates->markUnreachable();
713
714 } else if (VarState == Test.TestsFor && ElseStates) {
715 ElseStates->markUnreachable();
716 }
717}
718
719void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
720 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
721
722 const VarTestResult &LTest = PInfo.getLTest(),
723 &RTest = PInfo.getRTest();
724
725 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
726 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
727
728 if (LTest.Var) {
729 if (PInfo.testEffectiveOp() == EO_And) {
730 if (LState == CS_Unknown) {
731 ThenStates->setState(LTest.Var, LTest.TestsFor);
732
733 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
734 ThenStates->markUnreachable();
735
736 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
737 if (RState == RTest.TestsFor) {
738 if (ElseStates)
739 ElseStates->markUnreachable();
740 } else {
741 ThenStates->markUnreachable();
742 }
743 }
744
745 } else {
746 if (LState == CS_Unknown && ElseStates) {
747 ElseStates->setState(LTest.Var,
748 invertConsumedUnconsumed(LTest.TestsFor));
749
750 } else if (LState == LTest.TestsFor && ElseStates) {
751 ElseStates->markUnreachable();
752
753 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
754 isKnownState(RState)) {
755
756 if (RState == RTest.TestsFor) {
757 if (ElseStates)
758 ElseStates->markUnreachable();
759 } else {
760 ThenStates->markUnreachable();
761 }
762 }
763 }
764 }
765
766 if (RTest.Var) {
767 if (PInfo.testEffectiveOp() == EO_And) {
768 if (RState == CS_Unknown)
769 ThenStates->setState(RTest.Var, RTest.TestsFor);
770 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
771 ThenStates->markUnreachable();
772
773 } else if (ElseStates) {
774 if (RState == CS_Unknown)
775 ElseStates->setState(RTest.Var,
776 invertConsumedUnconsumed(RTest.TestsFor));
777 else if (RState == RTest.TestsFor)
778 ElseStates->markUnreachable();
779 }
780 }
781}
782
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000783void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
784 ConsumedStateMap *StateMap,
785 bool &AlreadyOwned) {
786
787 if (VisitedBlocks.alreadySet(Block)) return;
788
789 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
790
791 if (Entry) {
792 Entry->intersect(StateMap);
793
794 } else if (AlreadyOwned) {
795 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
796
797 } else {
798 StateMapsArray[Block->getBlockID()] = StateMap;
799 AlreadyOwned = true;
800 }
801}
802
803void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
804 ConsumedStateMap *StateMap) {
805
806 if (VisitedBlocks.alreadySet(Block)) {
807 delete StateMap;
808 return;
809 }
810
811 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
812
813 if (Entry) {
814 Entry->intersect(StateMap);
815 delete StateMap;
816
817 } else {
818 StateMapsArray[Block->getBlockID()] = StateMap;
819 }
820}
821
822ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
823 return StateMapsArray[Block->getBlockID()];
824}
825
826void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {
827 VisitedBlocks.insert(Block);
828}
829
830ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {
831 MapType::const_iterator Entry = Map.find(Var);
832
833 if (Entry != Map.end()) {
834 return Entry->second;
835
836 } else {
837 return CS_None;
838 }
839}
840
841void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
842 ConsumedState LocalState;
843
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000844 if (this->From && this->From == Other->From && !Other->Reachable) {
845 this->markUnreachable();
846 return;
847 }
848
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000849 for (MapType::const_iterator DMI = Other->Map.begin(),
850 DME = Other->Map.end(); DMI != DME; ++DMI) {
851
852 LocalState = this->getState(DMI->first);
853
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000854 if (LocalState == CS_None)
855 continue;
856
857 if (LocalState != DMI->second)
858 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000859 }
860}
861
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000862void ConsumedStateMap::markUnreachable() {
863 this->Reachable = false;
864 Map.clear();
865}
866
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000867void ConsumedStateMap::makeUnknown() {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000868 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
869 ++DMI) {
870
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000871 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000872 }
873}
874
875void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
876 Map[Var] = State;
877}
878
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000879void ConsumedStateMap::remove(const VarDecl *Var) {
880 Map.erase(Var);
881}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000882
883bool ConsumedAnalyzer::isConsumableType(QualType Type) {
884 const CXXRecordDecl *RD =
885 dyn_cast_or_null<CXXRecordDecl>(Type->getAsCXXRecordDecl());
886
887 if (!RD) return false;
888
889 std::pair<CacheMapType::iterator, bool> Entry =
890 ConsumableTypeCache.insert(std::make_pair(RD, false));
891
892 if (Entry.second)
893 Entry.first->second = hasConsumableAttributes(RD);
894
895 return Entry.first->second;
896}
897
898// TODO: Walk the base classes to see if any of them are unique types.
899// (Deferred)
900bool ConsumedAnalyzer::hasConsumableAttributes(const CXXRecordDecl *RD) {
901 for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
902 ME = RD->method_end(); MI != ME; ++MI) {
903
904 for (Decl::attr_iterator AI = (*MI)->attr_begin(), AE = (*MI)->attr_end();
905 AI != AE; ++AI) {
906
907 switch ((*AI)->getKind()) {
908 case attr::CallableWhenUnconsumed:
909 case attr::TestsUnconsumed:
910 return true;
911
912 default:
913 break;
914 }
915 }
916 }
917
918 return false;
919}
920
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000921bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
922 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000923
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000924 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
925 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000926
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000927 if (const IfStmt *IfNode =
928 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000929
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000930 bool HasElse = IfNode->getElse() != NULL;
931 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000932
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000933 PInfo = Visitor.getInfo(Cond);
934 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
935 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
936
937 if (PInfo.isTest()) {
938 CurrStates->setSource(Cond);
939 FalseStates->setSource(Cond);
940
941 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates,
942 HasElse ? FalseStates : NULL);
943
944 } else if (PInfo.isBinTest()) {
945 CurrStates->setSource(PInfo.testSourceNode());
946 FalseStates->setSource(PInfo.testSourceNode());
947
948 splitVarStateForIfBinOp(PInfo, CurrStates, HasElse ? FalseStates : NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000949
950 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000951 delete FalseStates;
952 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000953 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000954
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000955 } else if (const BinaryOperator *BinOp =
956 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
957
958 PInfo = Visitor.getInfo(BinOp->getLHS());
959 if (!PInfo.isTest()) {
960 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
961 PInfo = Visitor.getInfo(BinOp->getRHS());
962
963 if (!PInfo.isTest()) {
964 delete FalseStates;
965 return false;
966 }
967
968 } else {
969 delete FalseStates;
970 return false;
971 }
972 }
973
974 CurrStates->setSource(BinOp);
975 FalseStates->setSource(BinOp);
976
977 const VarTestResult &Test = PInfo.getTest();
978 ConsumedState VarState = CurrStates->getState(Test.Var);
979
980 if (BinOp->getOpcode() == BO_LAnd) {
981 if (VarState == CS_Unknown)
982 CurrStates->setState(Test.Var, Test.TestsFor);
983 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
984 CurrStates->markUnreachable();
985
986 } else if (BinOp->getOpcode() == BO_LOr) {
987 if (VarState == CS_Unknown)
988 FalseStates->setState(Test.Var,
989 invertConsumedUnconsumed(Test.TestsFor));
990 else if (VarState == Test.TestsFor)
991 FalseStates->markUnreachable();
992 }
993
994 } else {
995 delete FalseStates;
996 return false;
997 }
998
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000999 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1000
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001001 if (*SI)
1002 BlockInfo.addInfo(*SI, CurrStates);
1003 else
1004 delete CurrStates;
1005
1006 if (*++SI)
1007 BlockInfo.addInfo(*SI, FalseStates);
1008 else
1009 delete FalseStates;
1010
1011 CurrStates = NULL;
1012 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001013}
1014
1015void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1016 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
1017
1018 if (!D) return;
1019
1020 BlockInfo = ConsumedBlockInfo(AC.getCFG());
1021
1022 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1023
1024 CurrStates = new ConsumedStateMap();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001025 ConsumedStmtVisitor Visitor(AC, *this);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001026
1027 // Visit all of the function's basic blocks.
1028 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1029 E = SortedGraph->end(); I != E; ++I) {
1030
1031 const CFGBlock *CurrBlock = *I;
1032 BlockInfo.markVisited(CurrBlock);
1033
1034 if (CurrStates == NULL)
1035 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001036
1037 if (!CurrStates) {
1038 continue;
1039
1040 } else if (!CurrStates->isReachable()) {
1041 delete CurrStates;
1042 CurrStates = NULL;
1043 continue;
1044 }
1045
1046 Visitor.reset(CurrStates);
1047
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001048 // Visit all of the basic block's statements.
1049 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1050 BE = CurrBlock->end(); BI != BE; ++BI) {
1051
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001052 switch (BI->getKind()) {
1053 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001054 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001055 break;
1056 case CFGElement::AutomaticObjectDtor:
1057 CurrStates->remove(BI->castAs<CFGAutomaticObjDtor>().getVarDecl());
1058 default:
1059 break;
1060 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001061 }
1062
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001063 // TODO: Handle other forms of branching with precision, including while-
1064 // and for-loops. (Deferred)
1065 if (!splitState(CurrBlock, Visitor)) {
1066 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001067
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001068 if (CurrBlock->succ_size() > 1) {
1069 CurrStates->makeUnknown();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001070
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001071 bool OwnershipTaken = false;
1072
1073 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1074 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1075
1076 if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1077 }
1078
1079 if (!OwnershipTaken)
1080 delete CurrStates;
1081
1082 CurrStates = NULL;
1083
1084 } else if (CurrBlock->succ_size() == 1 &&
1085 (*CurrBlock->succ_begin())->pred_size() > 1) {
1086
1087 BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);
1088 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001089 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001090 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001091 } // End of block iterator.
1092
1093 // Delete the last existing state map.
1094 delete CurrStates;
1095
1096 WarningsHandler.emitDiagnostics();
1097}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001098}} // end namespace clang::consumed