blob: a0f8ea16390edc2b6af5cb909563fedb4c295873 [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 }
79}
80
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +000081static bool isTestingFunction(const FunctionDecl *FunDecl) {
82 return FunDecl->hasAttr<TestsUnconsumedAttr>();
83}
84
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000085static StringRef stateToString(ConsumedState State) {
86 switch (State) {
87 case consumed::CS_None:
88 return "none";
89
90 case consumed::CS_Unknown:
91 return "unknown";
92
93 case consumed::CS_Unconsumed:
94 return "unconsumed";
95
96 case consumed::CS_Consumed:
97 return "consumed";
98 }
Reid Klecknera72f7202013-08-13 00:11:59 +000099 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000100}
101
102namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000103struct VarTestResult {
104 const VarDecl *Var;
105 ConsumedState TestsFor;
106};
107} // end anonymous::VarTestResult
108
109namespace clang {
110namespace consumed {
111
112enum EffectiveOp {
113 EO_And,
114 EO_Or
115};
116
117class PropagationInfo {
118 enum {
119 IT_None,
120 IT_State,
121 IT_Test,
122 IT_BinTest,
123 IT_Var
124 } InfoType;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000125
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000126 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000127 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000128 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000129 const VarDecl *Var;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000130 struct {
131 const BinaryOperator *Source;
132 EffectiveOp EOp;
133 VarTestResult LTest;
134 VarTestResult RTest;
135 } BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000136 };
137
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000138public:
139 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000140
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000141 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
142 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
143 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000144
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000145 Test.Var = Var;
146 Test.TestsFor = TestsFor;
147 }
148
149 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
150 const VarTestResult &LTest, const VarTestResult &RTest)
151 : InfoType(IT_BinTest) {
152
153 BinTest.Source = Source;
154 BinTest.EOp = EOp;
155 BinTest.LTest = LTest;
156 BinTest.RTest = RTest;
157 }
158
159 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
160 const VarDecl *LVar, ConsumedState LTestsFor,
161 const VarDecl *RVar, ConsumedState RTestsFor)
162 : InfoType(IT_BinTest) {
163
164 BinTest.Source = Source;
165 BinTest.EOp = EOp;
166 BinTest.LTest.Var = LVar;
167 BinTest.LTest.TestsFor = LTestsFor;
168 BinTest.RTest.Var = RVar;
169 BinTest.RTest.TestsFor = RTestsFor;
170 }
171
172 PropagationInfo(ConsumedState State) : InfoType(IT_State), State(State) {}
173 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
174
175 const ConsumedState & getState() const {
176 assert(InfoType == IT_State);
177 return State;
178 }
179
180 const VarTestResult & getTest() const {
181 assert(InfoType == IT_Test);
182 return Test;
183 }
184
185 const VarTestResult & getLTest() const {
186 assert(InfoType == IT_BinTest);
187 return BinTest.LTest;
188 }
189
190 const VarTestResult & getRTest() const {
191 assert(InfoType == IT_BinTest);
192 return BinTest.RTest;
193 }
194
195 const VarDecl * getVar() const {
196 assert(InfoType == IT_Var);
197 return Var;
198 }
199
200 EffectiveOp testEffectiveOp() const {
201 assert(InfoType == IT_BinTest);
202 return BinTest.EOp;
203 }
204
205 const BinaryOperator * testSourceNode() const {
206 assert(InfoType == IT_BinTest);
207 return BinTest.Source;
208 }
209
210 bool isValid() const { return InfoType != IT_None; }
211 bool isState() const { return InfoType == IT_State; }
212 bool isTest() const { return InfoType == IT_Test; }
213 bool isBinTest() const { return InfoType == IT_BinTest; }
214 bool isVar() const { return InfoType == IT_Var; }
215
216 PropagationInfo invertTest() const {
217 assert(InfoType == IT_Test || InfoType == IT_BinTest);
218
219 if (InfoType == IT_Test) {
220 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
221
222 } else if (InfoType == IT_BinTest) {
223 return PropagationInfo(BinTest.Source,
224 BinTest.EOp == EO_And ? EO_Or : EO_And,
225 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
226 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
227 } else {
228 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000229 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000230 }
231};
232
233class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000234
235 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
236 typedef std::pair<const Stmt *, PropagationInfo> PairType;
237 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000238 typedef MapType::const_iterator ConstInfoEntry;
239
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000240 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000241 ConsumedAnalyzer &Analyzer;
242 ConsumedStateMap *StateMap;
243 MapType PropagationMap;
244
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000245 void checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000246 const FunctionDecl *FunDecl,
247 const CallExpr *Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000248 void forwardInfo(const Stmt *From, const Stmt *To);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000249 void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000250 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
251
252public:
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000253
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000254 void Visit(const Stmt *StmtNode);
255
256 void VisitBinaryOperator(const BinaryOperator *BinOp);
257 void VisitCallExpr(const CallExpr *Call);
258 void VisitCastExpr(const CastExpr *Cast);
259 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
260 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
261 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
262 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
263 void VisitDeclStmt(const DeclStmt *DelcS);
264 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
265 void VisitMemberExpr(const MemberExpr *MExpr);
266 void VisitUnaryOperator(const UnaryOperator *UOp);
267 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000268
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000269 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer)
270 : AC(AC), Analyzer(Analyzer), StateMap(NULL) {}
271
272 PropagationInfo getInfo(const Stmt *StmtNode) const {
273 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
274
275 if (Entry != PropagationMap.end())
276 return Entry->second;
277 else
278 return PropagationInfo();
279 }
280
281 void reset(ConsumedStateMap *NewStateMap) {
282 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000283 }
284};
285
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000286// TODO: When we support CallableWhenConsumed this will have to check for
287// the different attributes and change the behavior bellow. (Deferred)
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000288void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000289 const FunctionDecl *FunDecl,
290 const CallExpr *Call) {
291
292 if (!FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) return;
293
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000294 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000295 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000296
297 switch (StateMap->getState(Var)) {
298 case CS_Consumed:
299 Analyzer.WarningsHandler.warnUseWhileConsumed(
300 FunDecl->getNameAsString(), Var->getNameAsString(),
301 Call->getExprLoc());
302 break;
303
304 case CS_Unknown:
305 Analyzer.WarningsHandler.warnUseInUnknownState(
306 FunDecl->getNameAsString(), Var->getNameAsString(),
307 Call->getExprLoc());
308 break;
309
310 case CS_None:
311 case CS_Unconsumed:
312 break;
313 }
314
315 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000316 switch (PInfo.getState()) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000317 case CS_Consumed:
318 Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(
319 FunDecl->getNameAsString(), Call->getExprLoc());
320 break;
321
322 case CS_Unknown:
323 Analyzer.WarningsHandler.warnUseOfTempInUnknownState(
324 FunDecl->getNameAsString(), Call->getExprLoc());
325 break;
326
327 case CS_None:
328 case CS_Unconsumed:
329 break;
330 }
331 }
332}
333
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000334void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
335 InfoEntry Entry = PropagationMap.find(From);
336
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000337 if (Entry != PropagationMap.end())
338 PropagationMap.insert(PairType(To, Entry->second));
339}
340
341void ConsumedStmtVisitor::handleTestingFunctionCall(const CallExpr *Call,
342 const VarDecl *Var) {
343
344 ConsumedState VarState = StateMap->getState(Var);
345
346 if (VarState != CS_Unknown) {
347 SourceLocation CallLoc = Call->getExprLoc();
348
349 if (!CallLoc.isMacroID())
350 Analyzer.WarningsHandler.warnUnnecessaryTest(Var->getNameAsString(),
351 stateToString(VarState), CallLoc);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000352 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000353
354 PropagationMap.insert(PairType(Call, PropagationInfo(Var, CS_Unconsumed)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000355}
356
357bool ConsumedStmtVisitor::isLikeMoveAssignment(
358 const CXXMethodDecl *MethodDecl) {
359
360 return MethodDecl->isMoveAssignmentOperator() ||
361 (MethodDecl->getOverloadedOperator() == OO_Equal &&
362 MethodDecl->getNumParams() == 1 &&
363 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
364}
365
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000366void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
367
368 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
369
370 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
371 CE = StmtNode->child_end(); CI != CE; ++CI) {
372
373 PropagationMap.erase(*CI);
374 }
375}
376
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000377void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
378 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000379 case BO_LAnd:
380 case BO_LOr : {
381 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
382 REntry = PropagationMap.find(BinOp->getRHS());
383
384 VarTestResult LTest, RTest;
385
386 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
387 LTest = LEntry->second.getTest();
388
389 } else {
390 LTest.Var = NULL;
391 LTest.TestsFor = CS_None;
392 }
393
394 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
395 RTest = REntry->second.getTest();
396
397 } else {
398 RTest.Var = NULL;
399 RTest.TestsFor = CS_None;
400 }
401
402 if (!(LTest.Var == NULL && RTest.Var == NULL))
403 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
404 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
405
406 break;
407 }
408
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000409 case BO_PtrMemD:
410 case BO_PtrMemI:
411 forwardInfo(BinOp->getLHS(), BinOp);
412 break;
413
414 default:
415 break;
416 }
417}
418
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000419void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
420 if (const FunctionDecl *FunDecl =
421 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
422
423 // Special case for the std::move function.
424 // TODO: Make this more specific. (Deferred)
425 if (FunDecl->getNameAsString() == "move") {
426 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
427
428 if (Entry != PropagationMap.end()) {
429 PropagationMap.insert(PairType(Call, Entry->second));
430 }
431
432 return;
433 }
434
435 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
436
437 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
438 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
439
440 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
441
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000442 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000443 continue;
444 }
445
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000446 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000447
448 if (ParamType->isRValueReferenceType() ||
449 (ParamType->isLValueReferenceType() &&
450 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
451
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000452 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000453
454 } else if (!(ParamType.isConstQualified() ||
455 ((ParamType->isReferenceType() ||
456 ParamType->isPointerType()) &&
457 ParamType->getPointeeType().isConstQualified()))) {
458
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000459 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000460 }
461 }
462 }
463}
464
465void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000466 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000467}
468
469void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
470 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000471
472 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000473 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
474
475 if (Analyzer.isConsumableType(ThisType)) {
476 if (Constructor->hasAttr<ConsumesAttr>() ||
477 Constructor->isDefaultConstructor()) {
478
479 PropagationMap.insert(PairType(Call,
480 PropagationInfo(consumed::CS_Consumed)));
481
482 } else if (Constructor->isMoveConstructor()) {
483
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000484 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000485 PropagationMap.find(Call->getArg(0))->second;
486
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000487 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000488 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000489
490 PropagationMap.insert(PairType(Call,
491 PropagationInfo(StateMap->getState(Var))));
492
493 StateMap->setState(Var, consumed::CS_Consumed);
494
495 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000496 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000497 }
498
499 } else if (Constructor->isCopyConstructor()) {
500 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
501
502 if (Entry != PropagationMap.end())
503 PropagationMap.insert(PairType(Call, Entry->second));
504
505 } else {
506 PropagationMap.insert(PairType(Call,
507 PropagationInfo(consumed::CS_Unconsumed)));
508 }
509 }
510}
511
512void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
513 const CXXMemberCallExpr *Call) {
514
515 VisitCallExpr(Call);
516
517 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
518
519 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000520 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000521 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000522
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000523 checkCallability(PInfo, MethodDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000524
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000525 if (PInfo.isVar()) {
526 if (isTestingFunction(MethodDecl))
527 handleTestingFunctionCall(Call, PInfo.getVar());
528 else if (MethodDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000529 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000530 else if (!MethodDecl->isConst())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000531 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000532 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000533 }
534}
535
536void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
537 const CXXOperatorCallExpr *Call) {
538
539 const FunctionDecl *FunDecl =
540 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
541
542 if (!FunDecl) return;
543
544 if (isa<CXXMethodDecl>(FunDecl) &&
545 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
546
547 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
548 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
549
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000550 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000551
552 if (LEntry != PropagationMap.end() &&
553 REntry != PropagationMap.end()) {
554
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000555 LPInfo = LEntry->second;
556 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000557
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000558 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000559 StateMap->setState(LPInfo.getVar(),
560 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000561
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000562 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000563
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000564 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000565
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000566 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000567 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000568
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000569 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000570
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000571 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000572 PropagationMap.insert(PairType(Call,
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000573 PropagationInfo(StateMap->getState(RPInfo.getVar()))));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000574
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000575 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000576
577 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000578 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000579 }
580
581 } else if (LEntry != PropagationMap.end() &&
582 REntry == PropagationMap.end()) {
583
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000584 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000585
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000586 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000587 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000588
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000589 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000590
591 } else {
592 PropagationMap.insert(PairType(Call,
593 PropagationInfo(consumed::CS_Unknown)));
594 }
595
596 } else if (LEntry == PropagationMap.end() &&
597 REntry != PropagationMap.end()) {
598
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000599 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000600
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000601 if (RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000602 const VarDecl *Var = RPInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000603
604 PropagationMap.insert(PairType(Call,
605 PropagationInfo(StateMap->getState(Var))));
606
607 StateMap->setState(Var, consumed::CS_Consumed);
608
609 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000610 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000611 }
612 }
613
614 } else {
615
616 VisitCallExpr(Call);
617
618 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
619
620 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000621 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000622
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000623 checkCallability(PInfo, FunDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000624
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000625 if (PInfo.isVar()) {
626 if (isTestingFunction(FunDecl)) {
627 handleTestingFunctionCall(Call, PInfo.getVar());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000628
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000629 } else if (FunDecl->hasAttr<ConsumesAttr>()) {
630 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
631
632 } else if (const CXXMethodDecl *MethodDecl =
633 dyn_cast_or_null<CXXMethodDecl>(FunDecl)) {
634
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000635 if (!MethodDecl->isConst())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000636 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000637 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000638 }
639 }
640 }
641}
642
643void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
644 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
645 if (StateMap->getState(Var) != consumed::CS_None)
646 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
647}
648
649void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
650 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
651 DE = DeclS->decl_end(); DI != DE; ++DI) {
652
653 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
654 }
655
656 if (DeclS->isSingleDecl())
657 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
658 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
659}
660
661void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
662 const MaterializeTemporaryExpr *Temp) {
663
664 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
665
666 if (Entry != PropagationMap.end())
667 PropagationMap.insert(PairType(Temp, Entry->second));
668}
669
670void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
671 forwardInfo(MExpr->getBase(), MExpr);
672}
673
674void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000675 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
676 if (Entry == PropagationMap.end()) return;
677
678 switch (UOp->getOpcode()) {
679 case UO_AddrOf:
680 PropagationMap.insert(PairType(UOp, Entry->second));
681 break;
682
683 case UO_LNot:
684 if (Entry->second.isTest() || Entry->second.isBinTest())
685 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
686 break;
687
688 default:
689 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000690 }
691}
692
693void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
694 if (Analyzer.isConsumableType(Var->getType())) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000695 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000696 PropagationMap.find(Var->getInit())->second;
697
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000698 StateMap->setState(Var, PInfo.isVar() ?
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000699 StateMap->getState(PInfo.getVar()) : PInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000700 }
701}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000702}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000703
704namespace clang {
705namespace consumed {
706
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000707void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
708 ConsumedStateMap *ThenStates,
709 ConsumedStateMap *ElseStates) {
710
711 ConsumedState VarState = ThenStates->getState(Test.Var);
712
713 if (VarState == CS_Unknown) {
714 ThenStates->setState(Test.Var, Test.TestsFor);
715 if (ElseStates)
716 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
717
718 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
719 ThenStates->markUnreachable();
720
721 } else if (VarState == Test.TestsFor && ElseStates) {
722 ElseStates->markUnreachable();
723 }
724}
725
726void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
727 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
728
729 const VarTestResult &LTest = PInfo.getLTest(),
730 &RTest = PInfo.getRTest();
731
732 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
733 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
734
735 if (LTest.Var) {
736 if (PInfo.testEffectiveOp() == EO_And) {
737 if (LState == CS_Unknown) {
738 ThenStates->setState(LTest.Var, LTest.TestsFor);
739
740 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
741 ThenStates->markUnreachable();
742
743 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
744 if (RState == RTest.TestsFor) {
745 if (ElseStates)
746 ElseStates->markUnreachable();
747 } else {
748 ThenStates->markUnreachable();
749 }
750 }
751
752 } else {
753 if (LState == CS_Unknown && ElseStates) {
754 ElseStates->setState(LTest.Var,
755 invertConsumedUnconsumed(LTest.TestsFor));
756
757 } else if (LState == LTest.TestsFor && ElseStates) {
758 ElseStates->markUnreachable();
759
760 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
761 isKnownState(RState)) {
762
763 if (RState == RTest.TestsFor) {
764 if (ElseStates)
765 ElseStates->markUnreachable();
766 } else {
767 ThenStates->markUnreachable();
768 }
769 }
770 }
771 }
772
773 if (RTest.Var) {
774 if (PInfo.testEffectiveOp() == EO_And) {
775 if (RState == CS_Unknown)
776 ThenStates->setState(RTest.Var, RTest.TestsFor);
777 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
778 ThenStates->markUnreachable();
779
780 } else if (ElseStates) {
781 if (RState == CS_Unknown)
782 ElseStates->setState(RTest.Var,
783 invertConsumedUnconsumed(RTest.TestsFor));
784 else if (RState == RTest.TestsFor)
785 ElseStates->markUnreachable();
786 }
787 }
788}
789
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000790void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
791 ConsumedStateMap *StateMap,
792 bool &AlreadyOwned) {
793
794 if (VisitedBlocks.alreadySet(Block)) return;
795
796 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
797
798 if (Entry) {
799 Entry->intersect(StateMap);
800
801 } else if (AlreadyOwned) {
802 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
803
804 } else {
805 StateMapsArray[Block->getBlockID()] = StateMap;
806 AlreadyOwned = true;
807 }
808}
809
810void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
811 ConsumedStateMap *StateMap) {
812
813 if (VisitedBlocks.alreadySet(Block)) {
814 delete StateMap;
815 return;
816 }
817
818 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
819
820 if (Entry) {
821 Entry->intersect(StateMap);
822 delete StateMap;
823
824 } else {
825 StateMapsArray[Block->getBlockID()] = StateMap;
826 }
827}
828
829ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
830 return StateMapsArray[Block->getBlockID()];
831}
832
833void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {
834 VisitedBlocks.insert(Block);
835}
836
837ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {
838 MapType::const_iterator Entry = Map.find(Var);
839
840 if (Entry != Map.end()) {
841 return Entry->second;
842
843 } else {
844 return CS_None;
845 }
846}
847
848void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
849 ConsumedState LocalState;
850
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000851 if (this->From && this->From == Other->From && !Other->Reachable) {
852 this->markUnreachable();
853 return;
854 }
855
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000856 for (MapType::const_iterator DMI = Other->Map.begin(),
857 DME = Other->Map.end(); DMI != DME; ++DMI) {
858
859 LocalState = this->getState(DMI->first);
860
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000861 if (LocalState == CS_None)
862 continue;
863
864 if (LocalState != DMI->second)
865 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000866 }
867}
868
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000869void ConsumedStateMap::markUnreachable() {
870 this->Reachable = false;
871 Map.clear();
872}
873
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000874void ConsumedStateMap::makeUnknown() {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000875 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
876 ++DMI) {
877
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000878 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000879 }
880}
881
882void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
883 Map[Var] = State;
884}
885
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000886void ConsumedStateMap::remove(const VarDecl *Var) {
887 Map.erase(Var);
888}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000889
890bool ConsumedAnalyzer::isConsumableType(QualType Type) {
891 const CXXRecordDecl *RD =
892 dyn_cast_or_null<CXXRecordDecl>(Type->getAsCXXRecordDecl());
893
894 if (!RD) return false;
895
896 std::pair<CacheMapType::iterator, bool> Entry =
897 ConsumableTypeCache.insert(std::make_pair(RD, false));
898
899 if (Entry.second)
900 Entry.first->second = hasConsumableAttributes(RD);
901
902 return Entry.first->second;
903}
904
905// TODO: Walk the base classes to see if any of them are unique types.
906// (Deferred)
907bool ConsumedAnalyzer::hasConsumableAttributes(const CXXRecordDecl *RD) {
908 for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
909 ME = RD->method_end(); MI != ME; ++MI) {
910
911 for (Decl::attr_iterator AI = (*MI)->attr_begin(), AE = (*MI)->attr_end();
912 AI != AE; ++AI) {
913
914 switch ((*AI)->getKind()) {
915 case attr::CallableWhenUnconsumed:
916 case attr::TestsUnconsumed:
917 return true;
918
919 default:
920 break;
921 }
922 }
923 }
924
925 return false;
926}
927
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000928bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
929 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000930
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000931 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
932 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000933
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000934 if (const IfStmt *IfNode =
935 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000936
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000937 bool HasElse = IfNode->getElse() != NULL;
938 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000939
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000940 PInfo = Visitor.getInfo(Cond);
941 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
942 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
943
944 if (PInfo.isTest()) {
945 CurrStates->setSource(Cond);
946 FalseStates->setSource(Cond);
947
948 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates,
949 HasElse ? FalseStates : NULL);
950
951 } else if (PInfo.isBinTest()) {
952 CurrStates->setSource(PInfo.testSourceNode());
953 FalseStates->setSource(PInfo.testSourceNode());
954
955 splitVarStateForIfBinOp(PInfo, CurrStates, HasElse ? FalseStates : NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000956
957 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000958 delete FalseStates;
959 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000960 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000961
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000962 } else if (const BinaryOperator *BinOp =
963 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
964
965 PInfo = Visitor.getInfo(BinOp->getLHS());
966 if (!PInfo.isTest()) {
967 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
968 PInfo = Visitor.getInfo(BinOp->getRHS());
969
970 if (!PInfo.isTest()) {
971 delete FalseStates;
972 return false;
973 }
974
975 } else {
976 delete FalseStates;
977 return false;
978 }
979 }
980
981 CurrStates->setSource(BinOp);
982 FalseStates->setSource(BinOp);
983
984 const VarTestResult &Test = PInfo.getTest();
985 ConsumedState VarState = CurrStates->getState(Test.Var);
986
987 if (BinOp->getOpcode() == BO_LAnd) {
988 if (VarState == CS_Unknown)
989 CurrStates->setState(Test.Var, Test.TestsFor);
990 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
991 CurrStates->markUnreachable();
992
993 } else if (BinOp->getOpcode() == BO_LOr) {
994 if (VarState == CS_Unknown)
995 FalseStates->setState(Test.Var,
996 invertConsumedUnconsumed(Test.TestsFor));
997 else if (VarState == Test.TestsFor)
998 FalseStates->markUnreachable();
999 }
1000
1001 } else {
1002 delete FalseStates;
1003 return false;
1004 }
1005
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001006 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1007
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001008 if (*SI)
1009 BlockInfo.addInfo(*SI, CurrStates);
1010 else
1011 delete CurrStates;
1012
1013 if (*++SI)
1014 BlockInfo.addInfo(*SI, FalseStates);
1015 else
1016 delete FalseStates;
1017
1018 CurrStates = NULL;
1019 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001020}
1021
1022void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1023 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
1024
1025 if (!D) return;
1026
1027 BlockInfo = ConsumedBlockInfo(AC.getCFG());
1028
1029 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1030
1031 CurrStates = new ConsumedStateMap();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001032 ConsumedStmtVisitor Visitor(AC, *this);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001033
1034 // Visit all of the function's basic blocks.
1035 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1036 E = SortedGraph->end(); I != E; ++I) {
1037
1038 const CFGBlock *CurrBlock = *I;
1039 BlockInfo.markVisited(CurrBlock);
1040
1041 if (CurrStates == NULL)
1042 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001043
1044 if (!CurrStates) {
1045 continue;
1046
1047 } else if (!CurrStates->isReachable()) {
1048 delete CurrStates;
1049 CurrStates = NULL;
1050 continue;
1051 }
1052
1053 Visitor.reset(CurrStates);
1054
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001055 // Visit all of the basic block's statements.
1056 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1057 BE = CurrBlock->end(); BI != BE; ++BI) {
1058
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001059 switch (BI->getKind()) {
1060 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001061 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001062 break;
1063 case CFGElement::AutomaticObjectDtor:
1064 CurrStates->remove(BI->castAs<CFGAutomaticObjDtor>().getVarDecl());
1065 default:
1066 break;
1067 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001068 }
1069
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001070 // TODO: Handle other forms of branching with precision, including while-
1071 // and for-loops. (Deferred)
1072 if (!splitState(CurrBlock, Visitor)) {
1073 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001074
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001075 if (CurrBlock->succ_size() > 1) {
1076 CurrStates->makeUnknown();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001077
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001078 bool OwnershipTaken = false;
1079
1080 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1081 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1082
1083 if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1084 }
1085
1086 if (!OwnershipTaken)
1087 delete CurrStates;
1088
1089 CurrStates = NULL;
1090
1091 } else if (CurrBlock->succ_size() == 1 &&
1092 (*CurrBlock->succ_begin())->pred_size() > 1) {
1093
1094 BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);
1095 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001096 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001097 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001098 } // End of block iterator.
1099
1100 // Delete the last existing state map.
1101 delete CurrStates;
1102
1103 WarningsHandler.emitDiagnostics();
1104}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001105}} // end namespace clang::consumed