blob: 7cd029020a2a3db83113f290e2937d916dcaed08 [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
David Blaikiea33ab602013-09-06 01:28:43 +000092static ConsumedState mapConsumableAttrState(const QualType QT) {
93 assert(isConsumableType(QT));
94
95 const ConsumableAttr *CAttr =
96 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
97
98 switch (CAttr->getDefaultState()) {
99 case ConsumableAttr::Unknown:
100 return CS_Unknown;
101 case ConsumableAttr::Unconsumed:
102 return CS_Unconsumed;
103 case ConsumableAttr::Consumed:
104 return CS_Consumed;
105 }
106 llvm_unreachable("invalid enum");
107}
108
Eric Christophere988dc42013-09-03 20:43:00 +0000109static ConsumedState
110mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000111 switch (RTSAttr->getState()) {
112 case ReturnTypestateAttr::Unknown:
113 return CS_Unknown;
114 case ReturnTypestateAttr::Unconsumed:
115 return CS_Unconsumed;
116 case ReturnTypestateAttr::Consumed:
117 return CS_Consumed;
118 }
Eric Christophere988dc42013-09-03 20:43:00 +0000119 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000120}
121
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000122static StringRef stateToString(ConsumedState State) {
123 switch (State) {
124 case consumed::CS_None:
125 return "none";
126
127 case consumed::CS_Unknown:
128 return "unknown";
129
130 case consumed::CS_Unconsumed:
131 return "unconsumed";
132
133 case consumed::CS_Consumed:
134 return "consumed";
135 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000136 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000137}
138
139namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000140struct VarTestResult {
141 const VarDecl *Var;
142 ConsumedState TestsFor;
143};
144} // end anonymous::VarTestResult
145
146namespace clang {
147namespace consumed {
148
149enum EffectiveOp {
150 EO_And,
151 EO_Or
152};
153
154class PropagationInfo {
155 enum {
156 IT_None,
157 IT_State,
158 IT_Test,
159 IT_BinTest,
160 IT_Var
161 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000162
163 struct BinTestTy {
164 const BinaryOperator *Source;
165 EffectiveOp EOp;
166 VarTestResult LTest;
167 VarTestResult RTest;
168 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000169
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000170 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000171 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000172 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000173 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000174 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000175 };
176
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000177public:
178 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000179
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000180 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
181 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
182 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000183
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000184 Test.Var = Var;
185 Test.TestsFor = TestsFor;
186 }
187
188 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
189 const VarTestResult &LTest, const VarTestResult &RTest)
190 : InfoType(IT_BinTest) {
191
192 BinTest.Source = Source;
193 BinTest.EOp = EOp;
194 BinTest.LTest = LTest;
195 BinTest.RTest = RTest;
196 }
197
198 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
199 const VarDecl *LVar, ConsumedState LTestsFor,
200 const VarDecl *RVar, ConsumedState RTestsFor)
201 : InfoType(IT_BinTest) {
202
203 BinTest.Source = Source;
204 BinTest.EOp = EOp;
205 BinTest.LTest.Var = LVar;
206 BinTest.LTest.TestsFor = LTestsFor;
207 BinTest.RTest.Var = RVar;
208 BinTest.RTest.TestsFor = RTestsFor;
209 }
210
211 PropagationInfo(ConsumedState State) : InfoType(IT_State), State(State) {}
212 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
213
214 const ConsumedState & getState() const {
215 assert(InfoType == IT_State);
216 return State;
217 }
218
219 const VarTestResult & getTest() const {
220 assert(InfoType == IT_Test);
221 return Test;
222 }
223
224 const VarTestResult & getLTest() const {
225 assert(InfoType == IT_BinTest);
226 return BinTest.LTest;
227 }
228
229 const VarTestResult & getRTest() const {
230 assert(InfoType == IT_BinTest);
231 return BinTest.RTest;
232 }
233
234 const VarDecl * getVar() const {
235 assert(InfoType == IT_Var);
236 return Var;
237 }
238
239 EffectiveOp testEffectiveOp() const {
240 assert(InfoType == IT_BinTest);
241 return BinTest.EOp;
242 }
243
244 const BinaryOperator * testSourceNode() const {
245 assert(InfoType == IT_BinTest);
246 return BinTest.Source;
247 }
248
249 bool isValid() const { return InfoType != IT_None; }
250 bool isState() const { return InfoType == IT_State; }
251 bool isTest() const { return InfoType == IT_Test; }
252 bool isBinTest() const { return InfoType == IT_BinTest; }
253 bool isVar() const { return InfoType == IT_Var; }
254
255 PropagationInfo invertTest() const {
256 assert(InfoType == IT_Test || InfoType == IT_BinTest);
257
258 if (InfoType == IT_Test) {
259 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
260
261 } else if (InfoType == IT_BinTest) {
262 return PropagationInfo(BinTest.Source,
263 BinTest.EOp == EO_And ? EO_Or : EO_And,
264 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
265 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
266 } else {
267 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000268 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000269 }
270};
271
272class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000273
274 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
275 typedef std::pair<const Stmt *, PropagationInfo> PairType;
276 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000277 typedef MapType::const_iterator ConstInfoEntry;
278
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000279 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000280 ConsumedAnalyzer &Analyzer;
281 ConsumedStateMap *StateMap;
282 MapType PropagationMap;
283
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000284 void checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000285 const FunctionDecl *FunDecl,
286 const CallExpr *Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000287 void forwardInfo(const Stmt *From, const Stmt *To);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000288 void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000289 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000290 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
291 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000292
293public:
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000294
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000295 void Visit(const Stmt *StmtNode);
296
297 void VisitBinaryOperator(const BinaryOperator *BinOp);
298 void VisitCallExpr(const CallExpr *Call);
299 void VisitCastExpr(const CastExpr *Cast);
300 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
301 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
302 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
303 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
304 void VisitDeclStmt(const DeclStmt *DelcS);
305 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
306 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000307 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000308 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000309 void VisitUnaryOperator(const UnaryOperator *UOp);
310 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000311
DeLesley Hutchins42525982013-08-29 22:36:05 +0000312 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
313 ConsumedStateMap *StateMap)
314 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000315
316 PropagationInfo getInfo(const Stmt *StmtNode) const {
317 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
318
319 if (Entry != PropagationMap.end())
320 return Entry->second;
321 else
322 return PropagationInfo();
323 }
324
325 void reset(ConsumedStateMap *NewStateMap) {
326 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000327 }
328};
329
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000330// TODO: When we support CallableWhenConsumed this will have to check for
331// the different attributes and change the behavior bellow. (Deferred)
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000332void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000333 const FunctionDecl *FunDecl,
334 const CallExpr *Call) {
335
336 if (!FunDecl->hasAttr<CallableWhenUnconsumedAttr>()) return;
337
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000338 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000339 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000340
341 switch (StateMap->getState(Var)) {
342 case CS_Consumed:
343 Analyzer.WarningsHandler.warnUseWhileConsumed(
344 FunDecl->getNameAsString(), Var->getNameAsString(),
345 Call->getExprLoc());
346 break;
347
348 case CS_Unknown:
349 Analyzer.WarningsHandler.warnUseInUnknownState(
350 FunDecl->getNameAsString(), Var->getNameAsString(),
351 Call->getExprLoc());
352 break;
353
354 case CS_None:
355 case CS_Unconsumed:
356 break;
357 }
358
359 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000360 switch (PInfo.getState()) {
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000361 case CS_Consumed:
362 Analyzer.WarningsHandler.warnUseOfTempWhileConsumed(
363 FunDecl->getNameAsString(), Call->getExprLoc());
364 break;
365
366 case CS_Unknown:
367 Analyzer.WarningsHandler.warnUseOfTempInUnknownState(
368 FunDecl->getNameAsString(), Call->getExprLoc());
369 break;
370
371 case CS_None:
372 case CS_Unconsumed:
373 break;
374 }
375 }
376}
377
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000378void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
379 InfoEntry Entry = PropagationMap.find(From);
380
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000381 if (Entry != PropagationMap.end())
382 PropagationMap.insert(PairType(To, Entry->second));
383}
384
385void ConsumedStmtVisitor::handleTestingFunctionCall(const CallExpr *Call,
386 const VarDecl *Var) {
387
388 ConsumedState VarState = StateMap->getState(Var);
389
390 if (VarState != CS_Unknown) {
391 SourceLocation CallLoc = Call->getExprLoc();
392
393 if (!CallLoc.isMacroID())
394 Analyzer.WarningsHandler.warnUnnecessaryTest(Var->getNameAsString(),
395 stateToString(VarState), CallLoc);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000396 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000397
398 PropagationMap.insert(PairType(Call, PropagationInfo(Var, CS_Unconsumed)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000399}
400
401bool ConsumedStmtVisitor::isLikeMoveAssignment(
402 const CXXMethodDecl *MethodDecl) {
403
404 return MethodDecl->isMoveAssignmentOperator() ||
405 (MethodDecl->getOverloadedOperator() == OO_Equal &&
406 MethodDecl->getNumParams() == 1 &&
407 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
408}
409
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000410void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
411 const FunctionDecl *Fun,
412 QualType ReturnType) {
413 if (isConsumableType(ReturnType)) {
414
415 ConsumedState ReturnState;
416
417 if (Fun->hasAttr<ReturnTypestateAttr>())
418 ReturnState = mapReturnTypestateAttrState(
419 Fun->getAttr<ReturnTypestateAttr>());
420 else
David Blaikiea33ab602013-09-06 01:28:43 +0000421 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000422
423 PropagationMap.insert(PairType(Call,
424 PropagationInfo(ReturnState)));
425 }
426}
427
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000428void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
429
430 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
431
432 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
433 CE = StmtNode->child_end(); CI != CE; ++CI) {
434
435 PropagationMap.erase(*CI);
436 }
437}
438
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000439void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
440 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000441 case BO_LAnd:
442 case BO_LOr : {
443 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
444 REntry = PropagationMap.find(BinOp->getRHS());
445
446 VarTestResult LTest, RTest;
447
448 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
449 LTest = LEntry->second.getTest();
450
451 } else {
452 LTest.Var = NULL;
453 LTest.TestsFor = CS_None;
454 }
455
456 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
457 RTest = REntry->second.getTest();
458
459 } else {
460 RTest.Var = NULL;
461 RTest.TestsFor = CS_None;
462 }
463
464 if (!(LTest.Var == NULL && RTest.Var == NULL))
465 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
466 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
467
468 break;
469 }
470
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000471 case BO_PtrMemD:
472 case BO_PtrMemI:
473 forwardInfo(BinOp->getLHS(), BinOp);
474 break;
475
476 default:
477 break;
478 }
479}
480
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000481void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
482 if (const FunctionDecl *FunDecl =
483 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
484
485 // Special case for the std::move function.
486 // TODO: Make this more specific. (Deferred)
487 if (FunDecl->getNameAsString() == "move") {
488 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
489
490 if (Entry != PropagationMap.end()) {
491 PropagationMap.insert(PairType(Call, Entry->second));
492 }
493
494 return;
495 }
496
497 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
498
499 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
500 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
501
502 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
503
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000504 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000505 continue;
506 }
507
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000508 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000509
510 if (ParamType->isRValueReferenceType() ||
511 (ParamType->isLValueReferenceType() &&
512 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
513
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000514 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000515
516 } else if (!(ParamType.isConstQualified() ||
517 ((ParamType->isReferenceType() ||
518 ParamType->isPointerType()) &&
519 ParamType->getPointeeType().isConstQualified()))) {
520
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000521 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000522 }
523 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000524
525 propagateReturnType(Call, FunDecl, FunDecl->getCallResultType());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000526 }
527}
528
529void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000530 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000531}
532
533void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
534 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000535
536 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000537 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
538
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000539 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000540 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000541
542 PropagationMap.insert(PairType(Call,
543 PropagationInfo(consumed::CS_Consumed)));
544
545 } else if (Constructor->isMoveConstructor()) {
546
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000547 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000548 PropagationMap.find(Call->getArg(0))->second;
549
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000550 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000551 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000552
553 PropagationMap.insert(PairType(Call,
554 PropagationInfo(StateMap->getState(Var))));
555
556 StateMap->setState(Var, consumed::CS_Consumed);
557
558 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000559 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000560 }
561
562 } else if (Constructor->isCopyConstructor()) {
563 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
564
565 if (Entry != PropagationMap.end())
566 PropagationMap.insert(PairType(Call, Entry->second));
567
568 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000569 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000570 }
571 }
572}
573
574void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
575 const CXXMemberCallExpr *Call) {
576
577 VisitCallExpr(Call);
578
579 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
580
581 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000582 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000583 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000584
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000585 checkCallability(PInfo, MethodDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000586
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000587 if (PInfo.isVar()) {
588 if (isTestingFunction(MethodDecl))
589 handleTestingFunctionCall(Call, PInfo.getVar());
590 else if (MethodDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000591 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000592 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000593 }
594}
595
596void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
597 const CXXOperatorCallExpr *Call) {
598
599 const FunctionDecl *FunDecl =
600 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
601
602 if (!FunDecl) return;
603
604 if (isa<CXXMethodDecl>(FunDecl) &&
605 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
606
607 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
608 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
609
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000610 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000611
612 if (LEntry != PropagationMap.end() &&
613 REntry != PropagationMap.end()) {
614
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000615 LPInfo = LEntry->second;
616 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000617
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000618 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000619 StateMap->setState(LPInfo.getVar(),
620 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000621
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000622 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000623
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000624 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000625
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000626 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000627 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000628
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000629 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000630
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000631 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000632 PropagationMap.insert(PairType(Call,
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000633 PropagationInfo(StateMap->getState(RPInfo.getVar()))));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000634
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000635 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000636
637 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000638 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000639 }
640
641 } else if (LEntry != PropagationMap.end() &&
642 REntry == PropagationMap.end()) {
643
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000644 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000645
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000646 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000647 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000648
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000649 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000650
651 } else {
652 PropagationMap.insert(PairType(Call,
653 PropagationInfo(consumed::CS_Unknown)));
654 }
655
656 } else if (LEntry == PropagationMap.end() &&
657 REntry != PropagationMap.end()) {
658
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000659 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000660
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000661 if (RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000662 const VarDecl *Var = RPInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000663
664 PropagationMap.insert(PairType(Call,
665 PropagationInfo(StateMap->getState(Var))));
666
667 StateMap->setState(Var, consumed::CS_Consumed);
668
669 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000670 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000671 }
672 }
673
674 } else {
675
676 VisitCallExpr(Call);
677
678 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
679
680 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000681 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000682
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000683 checkCallability(PInfo, FunDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000684
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000685 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000686 if (isTestingFunction(FunDecl))
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000687 handleTestingFunctionCall(Call, PInfo.getVar());
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000688 else if (FunDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000689 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000690 }
691 }
692 }
693}
694
695void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
696 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
697 if (StateMap->getState(Var) != consumed::CS_None)
698 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
699}
700
701void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
702 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
703 DE = DeclS->decl_end(); DI != DE; ++DI) {
704
705 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
706 }
707
708 if (DeclS->isSingleDecl())
709 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
710 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
711}
712
713void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
714 const MaterializeTemporaryExpr *Temp) {
715
716 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
717
718 if (Entry != PropagationMap.end())
719 PropagationMap.insert(PairType(Temp, Entry->second));
720}
721
722void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
723 forwardInfo(MExpr->getBase(), MExpr);
724}
725
DeLesley Hutchins42525982013-08-29 22:36:05 +0000726
727void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000728 QualType ParamType = Param->getType();
729 ConsumedState ParamState = consumed::CS_None;
730
731 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
732 isConsumableType(ParamType))
733 ParamState = mapConsumableAttrState(ParamType);
734 else if (ParamType->isReferenceType() &&
735 isConsumableType(ParamType->getPointeeType()))
736 ParamState = consumed::CS_Unknown;
737
738 if (ParamState)
739 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000740}
741
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000742void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
743 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
744 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
745
746 if (Entry != PropagationMap.end()) {
747 assert(Entry->second.isState() || Entry->second.isVar());
748
749 ConsumedState RetState = Entry->second.isState() ?
750 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
751
752 if (RetState != ExpectedState)
753 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
754 Ret->getReturnLoc(), stateToString(ExpectedState),
755 stateToString(RetState));
756 }
757 }
758}
759
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000760void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000761 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
762 if (Entry == PropagationMap.end()) return;
763
764 switch (UOp->getOpcode()) {
765 case UO_AddrOf:
766 PropagationMap.insert(PairType(UOp, Entry->second));
767 break;
768
769 case UO_LNot:
770 if (Entry->second.isTest() || Entry->second.isBinTest())
771 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
772 break;
773
774 default:
775 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000776 }
777}
778
779void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000780 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000781 if (Var->hasInit()) {
782 PropagationInfo PInfo =
783 PropagationMap.find(Var->getInit())->second;
784
785 StateMap->setState(Var, PInfo.isVar() ?
786 StateMap->getState(PInfo.getVar()) : PInfo.getState());
787
788 } else {
789 StateMap->setState(Var, consumed::CS_Unknown);
790 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000791 }
792}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000793}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000794
795namespace clang {
796namespace consumed {
797
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000798void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
799 ConsumedStateMap *ThenStates,
800 ConsumedStateMap *ElseStates) {
801
802 ConsumedState VarState = ThenStates->getState(Test.Var);
803
804 if (VarState == CS_Unknown) {
805 ThenStates->setState(Test.Var, Test.TestsFor);
806 if (ElseStates)
807 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
808
809 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
810 ThenStates->markUnreachable();
811
812 } else if (VarState == Test.TestsFor && ElseStates) {
813 ElseStates->markUnreachable();
814 }
815}
816
817void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
818 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
819
820 const VarTestResult &LTest = PInfo.getLTest(),
821 &RTest = PInfo.getRTest();
822
823 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
824 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
825
826 if (LTest.Var) {
827 if (PInfo.testEffectiveOp() == EO_And) {
828 if (LState == CS_Unknown) {
829 ThenStates->setState(LTest.Var, LTest.TestsFor);
830
831 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
832 ThenStates->markUnreachable();
833
834 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
835 if (RState == RTest.TestsFor) {
836 if (ElseStates)
837 ElseStates->markUnreachable();
838 } else {
839 ThenStates->markUnreachable();
840 }
841 }
842
843 } else {
844 if (LState == CS_Unknown && ElseStates) {
845 ElseStates->setState(LTest.Var,
846 invertConsumedUnconsumed(LTest.TestsFor));
847
848 } else if (LState == LTest.TestsFor && ElseStates) {
849 ElseStates->markUnreachable();
850
851 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
852 isKnownState(RState)) {
853
854 if (RState == RTest.TestsFor) {
855 if (ElseStates)
856 ElseStates->markUnreachable();
857 } else {
858 ThenStates->markUnreachable();
859 }
860 }
861 }
862 }
863
864 if (RTest.Var) {
865 if (PInfo.testEffectiveOp() == EO_And) {
866 if (RState == CS_Unknown)
867 ThenStates->setState(RTest.Var, RTest.TestsFor);
868 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
869 ThenStates->markUnreachable();
870
871 } else if (ElseStates) {
872 if (RState == CS_Unknown)
873 ElseStates->setState(RTest.Var,
874 invertConsumedUnconsumed(RTest.TestsFor));
875 else if (RState == RTest.TestsFor)
876 ElseStates->markUnreachable();
877 }
878 }
879}
880
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000881void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
882 ConsumedStateMap *StateMap,
883 bool &AlreadyOwned) {
884
885 if (VisitedBlocks.alreadySet(Block)) return;
886
887 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
888
889 if (Entry) {
890 Entry->intersect(StateMap);
891
892 } else if (AlreadyOwned) {
893 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
894
895 } else {
896 StateMapsArray[Block->getBlockID()] = StateMap;
897 AlreadyOwned = true;
898 }
899}
900
901void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
902 ConsumedStateMap *StateMap) {
903
904 if (VisitedBlocks.alreadySet(Block)) {
905 delete StateMap;
906 return;
907 }
908
909 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
910
911 if (Entry) {
912 Entry->intersect(StateMap);
913 delete StateMap;
914
915 } else {
916 StateMapsArray[Block->getBlockID()] = StateMap;
917 }
918}
919
920ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
921 return StateMapsArray[Block->getBlockID()];
922}
923
924void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {
925 VisitedBlocks.insert(Block);
926}
927
928ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {
929 MapType::const_iterator Entry = Map.find(Var);
930
931 if (Entry != Map.end()) {
932 return Entry->second;
933
934 } else {
935 return CS_None;
936 }
937}
938
939void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
940 ConsumedState LocalState;
941
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000942 if (this->From && this->From == Other->From && !Other->Reachable) {
943 this->markUnreachable();
944 return;
945 }
946
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000947 for (MapType::const_iterator DMI = Other->Map.begin(),
948 DME = Other->Map.end(); DMI != DME; ++DMI) {
949
950 LocalState = this->getState(DMI->first);
951
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000952 if (LocalState == CS_None)
953 continue;
954
955 if (LocalState != DMI->second)
956 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000957 }
958}
959
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000960void ConsumedStateMap::markUnreachable() {
961 this->Reachable = false;
962 Map.clear();
963}
964
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000965void ConsumedStateMap::makeUnknown() {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000966 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
967 ++DMI) {
968
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000969 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000970 }
971}
972
973void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
974 Map[Var] = State;
975}
976
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000977void ConsumedStateMap::remove(const VarDecl *Var) {
978 Map.erase(Var);
979}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000980
David Blaikiea33ab602013-09-06 01:28:43 +0000981void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
982 const FunctionDecl *D) {
983 QualType ReturnType;
984 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
985 ASTContext &CurrContext = AC.getASTContext();
986 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
987 } else
988 ReturnType = D->getCallResultType();
989
990 if (D->hasAttr<ReturnTypestateAttr>()) {
991 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
992
993 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
994 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
995 // FIXME: This should be removed when template instantiation propagates
996 // attributes at template specialization definition, not
997 // declaration. When it is removed the test needs to be enabled
998 // in SemaDeclAttr.cpp.
999 WarningsHandler.warnReturnTypestateForUnconsumableType(
1000 RTSAttr->getLocation(), ReturnType.getAsString());
1001 ExpectedReturnState = CS_None;
1002 } else
1003 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1004 } else if (isConsumableType(ReturnType))
1005 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1006 else
1007 ExpectedReturnState = CS_None;
1008}
1009
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001010bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1011 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001012
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001013 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1014 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001015
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001016 if (const IfStmt *IfNode =
1017 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001018
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001019 bool HasElse = IfNode->getElse() != NULL;
1020 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001021
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001022 PInfo = Visitor.getInfo(Cond);
1023 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1024 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1025
1026 if (PInfo.isTest()) {
1027 CurrStates->setSource(Cond);
1028 FalseStates->setSource(Cond);
1029
1030 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates,
1031 HasElse ? FalseStates : NULL);
1032
1033 } else if (PInfo.isBinTest()) {
1034 CurrStates->setSource(PInfo.testSourceNode());
1035 FalseStates->setSource(PInfo.testSourceNode());
1036
1037 splitVarStateForIfBinOp(PInfo, CurrStates, HasElse ? FalseStates : NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001038
1039 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001040 delete FalseStates;
1041 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001042 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001043
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001044 } else if (const BinaryOperator *BinOp =
1045 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1046
1047 PInfo = Visitor.getInfo(BinOp->getLHS());
1048 if (!PInfo.isTest()) {
1049 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1050 PInfo = Visitor.getInfo(BinOp->getRHS());
1051
1052 if (!PInfo.isTest()) {
1053 delete FalseStates;
1054 return false;
1055 }
1056
1057 } else {
1058 delete FalseStates;
1059 return false;
1060 }
1061 }
1062
1063 CurrStates->setSource(BinOp);
1064 FalseStates->setSource(BinOp);
1065
1066 const VarTestResult &Test = PInfo.getTest();
1067 ConsumedState VarState = CurrStates->getState(Test.Var);
1068
1069 if (BinOp->getOpcode() == BO_LAnd) {
1070 if (VarState == CS_Unknown)
1071 CurrStates->setState(Test.Var, Test.TestsFor);
1072 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1073 CurrStates->markUnreachable();
1074
1075 } else if (BinOp->getOpcode() == BO_LOr) {
1076 if (VarState == CS_Unknown)
1077 FalseStates->setState(Test.Var,
1078 invertConsumedUnconsumed(Test.TestsFor));
1079 else if (VarState == Test.TestsFor)
1080 FalseStates->markUnreachable();
1081 }
1082
1083 } else {
1084 delete FalseStates;
1085 return false;
1086 }
1087
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001088 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1089
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001090 if (*SI)
1091 BlockInfo.addInfo(*SI, CurrStates);
1092 else
1093 delete CurrStates;
1094
1095 if (*++SI)
1096 BlockInfo.addInfo(*SI, FalseStates);
1097 else
1098 delete FalseStates;
1099
1100 CurrStates = NULL;
1101 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001102}
1103
1104void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1105 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001106 if (!D)
1107 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001108
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001109 CFG *CFGraph = AC.getCFG();
1110 if (!CFGraph)
1111 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001112
David Blaikiea33ab602013-09-06 01:28:43 +00001113 determineExpectedReturnState(AC, D);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +00001114
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001115 BlockInfo = ConsumedBlockInfo(CFGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001116
1117 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1118
1119 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001120 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1121
1122 // Add all trackable parameters to the state map.
1123 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1124 PE = D->param_end(); PI != PE; ++PI) {
1125 Visitor.VisitParmVarDecl(*PI);
1126 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001127
1128 // Visit all of the function's basic blocks.
1129 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1130 E = SortedGraph->end(); I != E; ++I) {
1131
1132 const CFGBlock *CurrBlock = *I;
1133 BlockInfo.markVisited(CurrBlock);
1134
1135 if (CurrStates == NULL)
1136 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001137
1138 if (!CurrStates) {
1139 continue;
1140
1141 } else if (!CurrStates->isReachable()) {
1142 delete CurrStates;
1143 CurrStates = NULL;
1144 continue;
1145 }
1146
1147 Visitor.reset(CurrStates);
1148
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001149 // Visit all of the basic block's statements.
1150 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1151 BE = CurrBlock->end(); BI != BE; ++BI) {
1152
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001153 switch (BI->getKind()) {
1154 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001155 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001156 break;
1157 case CFGElement::AutomaticObjectDtor:
1158 CurrStates->remove(BI->castAs<CFGAutomaticObjDtor>().getVarDecl());
1159 default:
1160 break;
1161 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001162 }
1163
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001164 // TODO: Handle other forms of branching with precision, including while-
1165 // and for-loops. (Deferred)
1166 if (!splitState(CurrBlock, Visitor)) {
1167 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001168
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001169 if (CurrBlock->succ_size() > 1) {
1170 CurrStates->makeUnknown();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001171
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001172 bool OwnershipTaken = false;
1173
1174 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1175 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1176
1177 if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1178 }
1179
1180 if (!OwnershipTaken)
1181 delete CurrStates;
1182
1183 CurrStates = NULL;
1184
1185 } else if (CurrBlock->succ_size() == 1 &&
1186 (*CurrBlock->succ_begin())->pred_size() > 1) {
1187
1188 BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);
1189 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001190 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001191 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001192 } // End of block iterator.
1193
1194 // Delete the last existing state map.
1195 delete CurrStates;
1196
1197 WarningsHandler.emitDiagnostics();
1198}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001199}} // end namespace clang::consumed