blob: ee8dd77ff63779e99ce408ebd9613983fc55b54c [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.
DeLesley Hutchins66540852013-10-04 21:28:06 +000036// TODO: Adjust the parser and AttributesList class to support lists of
37// identifiers.
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000038// TODO: Warn about unreachable code.
39// TODO: Switch to using a bitmap to track unreachable blocks.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000040// TODO: Mark variables as Unknown going into while- or for-loops only if they
41// are referenced inside that block. (Deferred)
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000042// TODO: Handle variable definitions, e.g. bool valid = x.isValid();
43// if (valid) ...; (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000044// TODO: Add a method(s) to identify which method calls perform what state
45// transitions. (Deferred)
46// TODO: Take notes on state transitions to provide better warning messages.
47// (Deferred)
48// TODO: Test nested conditionals: A) Checking the same value multiple times,
49// and 2) Checking different values. (Deferred)
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +000050
51using namespace clang;
52using namespace consumed;
53
54// Key method definition
55ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
56
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +000057static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
58 switch (State) {
59 case CS_Unconsumed:
60 return CS_Consumed;
61 case CS_Consumed:
62 return CS_Unconsumed;
63 case CS_None:
64 return CS_None;
65 case CS_Unknown:
66 return CS_Unknown;
67 }
68 llvm_unreachable("invalid enum");
69}
70
DeLesley Hutchins66540852013-10-04 21:28:06 +000071static bool isCallableInState(const CallableWhenAttr *CWAttr,
72 ConsumedState State) {
73
74 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
75 E = CWAttr->callableState_end();
76
77 for (; I != E; ++I) {
78
79 ConsumedState MappedAttrState = CS_None;
80
81 switch (*I) {
82 case CallableWhenAttr::Unknown:
83 MappedAttrState = CS_Unknown;
84 break;
85
86 case CallableWhenAttr::Unconsumed:
87 MappedAttrState = CS_Unconsumed;
88 break;
89
90 case CallableWhenAttr::Consumed:
91 MappedAttrState = CS_Consumed;
92 break;
93 }
94
95 if (MappedAttrState == State)
96 return true;
97 }
98
99 return false;
100}
101
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000102static bool isConsumableType(const QualType &QT) {
103 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
104 return RD->hasAttr<ConsumableAttr>();
105 else
106 return false;
107}
108
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000109static bool isKnownState(ConsumedState State) {
110 switch (State) {
111 case CS_Unconsumed:
112 case CS_Consumed:
113 return true;
114 case CS_None:
115 case CS_Unknown:
116 return false;
117 }
Aaron Ballman6b2ec032013-08-29 20:36:09 +0000118 llvm_unreachable("invalid enum");
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000119}
120
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000121static bool isTestingFunction(const FunctionDecl *FunDecl) {
122 return FunDecl->hasAttr<TestsUnconsumedAttr>();
123}
124
David Blaikiea33ab602013-09-06 01:28:43 +0000125static ConsumedState mapConsumableAttrState(const QualType QT) {
126 assert(isConsumableType(QT));
127
128 const ConsumableAttr *CAttr =
129 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
130
131 switch (CAttr->getDefaultState()) {
132 case ConsumableAttr::Unknown:
133 return CS_Unknown;
134 case ConsumableAttr::Unconsumed:
135 return CS_Unconsumed;
136 case ConsumableAttr::Consumed:
137 return CS_Consumed;
138 }
139 llvm_unreachable("invalid enum");
140}
141
Eric Christophere988dc42013-09-03 20:43:00 +0000142static ConsumedState
143mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000144 switch (RTSAttr->getState()) {
145 case ReturnTypestateAttr::Unknown:
146 return CS_Unknown;
147 case ReturnTypestateAttr::Unconsumed:
148 return CS_Unconsumed;
149 case ReturnTypestateAttr::Consumed:
150 return CS_Consumed;
151 }
Eric Christophere988dc42013-09-03 20:43:00 +0000152 llvm_unreachable("invalid enum");
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000153}
154
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000155static StringRef stateToString(ConsumedState State) {
156 switch (State) {
157 case consumed::CS_None:
158 return "none";
159
160 case consumed::CS_Unknown:
161 return "unknown";
162
163 case consumed::CS_Unconsumed:
164 return "unconsumed";
165
166 case consumed::CS_Consumed:
167 return "consumed";
168 }
Reid Klecknera72f7202013-08-13 00:11:59 +0000169 llvm_unreachable("invalid enum");
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000170}
171
172namespace {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000173struct VarTestResult {
174 const VarDecl *Var;
175 ConsumedState TestsFor;
176};
177} // end anonymous::VarTestResult
178
179namespace clang {
180namespace consumed {
181
182enum EffectiveOp {
183 EO_And,
184 EO_Or
185};
186
187class PropagationInfo {
188 enum {
189 IT_None,
190 IT_State,
191 IT_Test,
192 IT_BinTest,
193 IT_Var
194 } InfoType;
Eric Christophere444ea02013-08-29 18:00:58 +0000195
196 struct BinTestTy {
197 const BinaryOperator *Source;
198 EffectiveOp EOp;
199 VarTestResult LTest;
200 VarTestResult RTest;
201 };
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000202
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000203 union {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000204 ConsumedState State;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000205 VarTestResult Test;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000206 const VarDecl *Var;
Eric Christophere444ea02013-08-29 18:00:58 +0000207 BinTestTy BinTest;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000208 };
209
DeLesley Hutchins66540852013-10-04 21:28:06 +0000210 QualType TempType;
211
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000212public:
213 PropagationInfo() : InfoType(IT_None) {}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000214
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000215 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {}
216 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
217 : InfoType(IT_Test) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000218
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000219 Test.Var = Var;
220 Test.TestsFor = TestsFor;
221 }
222
223 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
224 const VarTestResult &LTest, const VarTestResult &RTest)
225 : InfoType(IT_BinTest) {
226
227 BinTest.Source = Source;
228 BinTest.EOp = EOp;
229 BinTest.LTest = LTest;
230 BinTest.RTest = RTest;
231 }
232
233 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
234 const VarDecl *LVar, ConsumedState LTestsFor,
235 const VarDecl *RVar, ConsumedState RTestsFor)
236 : InfoType(IT_BinTest) {
237
238 BinTest.Source = Source;
239 BinTest.EOp = EOp;
240 BinTest.LTest.Var = LVar;
241 BinTest.LTest.TestsFor = LTestsFor;
242 BinTest.RTest.Var = RVar;
243 BinTest.RTest.TestsFor = RTestsFor;
244 }
245
DeLesley Hutchins66540852013-10-04 21:28:06 +0000246 PropagationInfo(ConsumedState State, QualType TempType)
247 : InfoType(IT_State), State(State), TempType(TempType) {}
248
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000249 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
250
251 const ConsumedState & getState() const {
252 assert(InfoType == IT_State);
253 return State;
254 }
255
DeLesley Hutchins66540852013-10-04 21:28:06 +0000256 const QualType & getTempType() const {
257 assert(InfoType == IT_State);
258 return TempType;
259 }
260
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000261 const VarTestResult & getTest() const {
262 assert(InfoType == IT_Test);
263 return Test;
264 }
265
266 const VarTestResult & getLTest() const {
267 assert(InfoType == IT_BinTest);
268 return BinTest.LTest;
269 }
270
271 const VarTestResult & getRTest() const {
272 assert(InfoType == IT_BinTest);
273 return BinTest.RTest;
274 }
275
276 const VarDecl * getVar() const {
277 assert(InfoType == IT_Var);
278 return Var;
279 }
280
281 EffectiveOp testEffectiveOp() const {
282 assert(InfoType == IT_BinTest);
283 return BinTest.EOp;
284 }
285
286 const BinaryOperator * testSourceNode() const {
287 assert(InfoType == IT_BinTest);
288 return BinTest.Source;
289 }
290
291 bool isValid() const { return InfoType != IT_None; }
292 bool isState() const { return InfoType == IT_State; }
293 bool isTest() const { return InfoType == IT_Test; }
294 bool isBinTest() const { return InfoType == IT_BinTest; }
295 bool isVar() const { return InfoType == IT_Var; }
296
297 PropagationInfo invertTest() const {
298 assert(InfoType == IT_Test || InfoType == IT_BinTest);
299
300 if (InfoType == IT_Test) {
301 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
302
303 } else if (InfoType == IT_BinTest) {
304 return PropagationInfo(BinTest.Source,
305 BinTest.EOp == EO_And ? EO_Or : EO_And,
306 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
307 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
308 } else {
309 return PropagationInfo();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000310 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000311 }
312};
313
314class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000315
316 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
317 typedef std::pair<const Stmt *, PropagationInfo> PairType;
318 typedef MapType::iterator InfoEntry;
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000319 typedef MapType::const_iterator ConstInfoEntry;
320
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000321 AnalysisDeclContext &AC;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000322 ConsumedAnalyzer &Analyzer;
323 ConsumedStateMap *StateMap;
324 MapType PropagationMap;
325
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000326 void checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000327 const FunctionDecl *FunDecl,
328 const CallExpr *Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000329 void forwardInfo(const Stmt *From, const Stmt *To);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000330 void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000331 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000332 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
333 QualType ReturnType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000334
335public:
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000336
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000337 void Visit(const Stmt *StmtNode);
338
339 void VisitBinaryOperator(const BinaryOperator *BinOp);
340 void VisitCallExpr(const CallExpr *Call);
341 void VisitCastExpr(const CastExpr *Cast);
342 void VisitCXXConstructExpr(const CXXConstructExpr *Call);
343 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
344 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
345 void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
346 void VisitDeclStmt(const DeclStmt *DelcS);
347 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
348 void VisitMemberExpr(const MemberExpr *MExpr);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000349 void VisitParmVarDecl(const ParmVarDecl *Param);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000350 void VisitReturnStmt(const ReturnStmt *Ret);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000351 void VisitUnaryOperator(const UnaryOperator *UOp);
352 void VisitVarDecl(const VarDecl *Var);
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000353
DeLesley Hutchins42525982013-08-29 22:36:05 +0000354 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer,
355 ConsumedStateMap *StateMap)
356 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000357
358 PropagationInfo getInfo(const Stmt *StmtNode) const {
359 ConstInfoEntry Entry = PropagationMap.find(StmtNode);
360
361 if (Entry != PropagationMap.end())
362 return Entry->second;
363 else
364 return PropagationInfo();
365 }
366
367 void reset(ConsumedStateMap *NewStateMap) {
368 StateMap = NewStateMap;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000369 }
370};
371
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000372void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000373 const FunctionDecl *FunDecl,
374 const CallExpr *Call) {
375
DeLesley Hutchins66540852013-10-04 21:28:06 +0000376 if (!FunDecl->hasAttr<CallableWhenAttr>())
377 return;
378
379 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000380
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000381 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000382 const VarDecl *Var = PInfo.getVar();
DeLesley Hutchins66540852013-10-04 21:28:06 +0000383 ConsumedState VarState = StateMap->getState(Var);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000384
DeLesley Hutchins66540852013-10-04 21:28:06 +0000385 assert(VarState != CS_None && "Invalid state");
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000386
DeLesley Hutchins66540852013-10-04 21:28:06 +0000387 if (isCallableInState(CWAttr, VarState))
388 return;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000389
DeLesley Hutchins66540852013-10-04 21:28:06 +0000390 Analyzer.WarningsHandler.warnUseInInvalidState(
391 FunDecl->getNameAsString(), Var->getNameAsString(),
392 stateToString(VarState), Call->getExprLoc());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000393
DeLesley Hutchins66540852013-10-04 21:28:06 +0000394 } else if (PInfo.isState()) {
395
396 assert(PInfo.getState() != CS_None && "Invalid state");
397
398 if (isCallableInState(CWAttr, PInfo.getState()))
399 return;
400
401 Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
402 FunDecl->getNameAsString(), stateToString(PInfo.getState()),
403 Call->getExprLoc());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000404 }
405}
406
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000407void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
408 InfoEntry Entry = PropagationMap.find(From);
409
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000410 if (Entry != PropagationMap.end())
411 PropagationMap.insert(PairType(To, Entry->second));
412}
413
414void ConsumedStmtVisitor::handleTestingFunctionCall(const CallExpr *Call,
415 const VarDecl *Var) {
416
417 ConsumedState VarState = StateMap->getState(Var);
418
419 if (VarState != CS_Unknown) {
420 SourceLocation CallLoc = Call->getExprLoc();
421
422 if (!CallLoc.isMacroID())
423 Analyzer.WarningsHandler.warnUnnecessaryTest(Var->getNameAsString(),
424 stateToString(VarState), CallLoc);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000425 }
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000426
427 PropagationMap.insert(PairType(Call, PropagationInfo(Var, CS_Unconsumed)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000428}
429
430bool ConsumedStmtVisitor::isLikeMoveAssignment(
431 const CXXMethodDecl *MethodDecl) {
432
433 return MethodDecl->isMoveAssignmentOperator() ||
434 (MethodDecl->getOverloadedOperator() == OO_Equal &&
435 MethodDecl->getNumParams() == 1 &&
436 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
437}
438
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000439void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
440 const FunctionDecl *Fun,
441 QualType ReturnType) {
442 if (isConsumableType(ReturnType)) {
443
444 ConsumedState ReturnState;
445
446 if (Fun->hasAttr<ReturnTypestateAttr>())
447 ReturnState = mapReturnTypestateAttrState(
448 Fun->getAttr<ReturnTypestateAttr>());
449 else
David Blaikiea33ab602013-09-06 01:28:43 +0000450 ReturnState = mapConsumableAttrState(ReturnType);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000451
452 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000453 PropagationInfo(ReturnState, ReturnType)));
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000454 }
455}
456
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000457void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) {
458
459 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode);
460
461 for (Stmt::const_child_iterator CI = StmtNode->child_begin(),
462 CE = StmtNode->child_end(); CI != CE; ++CI) {
463
464 PropagationMap.erase(*CI);
465 }
466}
467
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000468void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
469 switch (BinOp->getOpcode()) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000470 case BO_LAnd:
471 case BO_LOr : {
472 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
473 REntry = PropagationMap.find(BinOp->getRHS());
474
475 VarTestResult LTest, RTest;
476
477 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) {
478 LTest = LEntry->second.getTest();
479
480 } else {
481 LTest.Var = NULL;
482 LTest.TestsFor = CS_None;
483 }
484
485 if (REntry != PropagationMap.end() && REntry->second.isTest()) {
486 RTest = REntry->second.getTest();
487
488 } else {
489 RTest.Var = NULL;
490 RTest.TestsFor = CS_None;
491 }
492
493 if (!(LTest.Var == NULL && RTest.Var == NULL))
494 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
495 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
496
497 break;
498 }
499
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000500 case BO_PtrMemD:
501 case BO_PtrMemI:
502 forwardInfo(BinOp->getLHS(), BinOp);
503 break;
504
505 default:
506 break;
507 }
508}
509
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000510void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
511 if (const FunctionDecl *FunDecl =
512 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
513
514 // Special case for the std::move function.
515 // TODO: Make this more specific. (Deferred)
516 if (FunDecl->getNameAsString() == "move") {
517 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
518
519 if (Entry != PropagationMap.end()) {
520 PropagationMap.insert(PairType(Call, Entry->second));
521 }
522
523 return;
524 }
525
526 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
527
528 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
529 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType();
530
531 InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
532
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000533 if (Entry == PropagationMap.end() || !Entry->second.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000534 continue;
535 }
536
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000537 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000538
539 if (ParamType->isRValueReferenceType() ||
540 (ParamType->isLValueReferenceType() &&
541 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) {
542
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000543 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000544
545 } else if (!(ParamType.isConstQualified() ||
546 ((ParamType->isReferenceType() ||
547 ParamType->isPointerType()) &&
548 ParamType->getPointeeType().isConstQualified()))) {
549
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000550 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000551 }
552 }
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000553
DeLesley Hutchins66540852013-10-04 21:28:06 +0000554 QualType RetType = FunDecl->getCallResultType();
555 if (RetType->isReferenceType())
556 RetType = RetType->getPointeeType();
557
558 propagateReturnType(Call, FunDecl, RetType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000559 }
560}
561
562void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000563 forwardInfo(Cast->getSubExpr(), Cast);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000564}
565
566void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
567 CXXConstructorDecl *Constructor = Call->getConstructor();
Reid Kleckner2d84f6b2013-08-12 23:49:39 +0000568
569 ASTContext &CurrContext = AC.getASTContext();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000570 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType();
571
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000572 if (isConsumableType(ThisType)) {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000573 if (Constructor->isDefaultConstructor()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000574
575 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000576 PropagationInfo(consumed::CS_Consumed, ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000577
578 } else if (Constructor->isMoveConstructor()) {
579
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000580 PropagationInfo PInfo =
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000581 PropagationMap.find(Call->getArg(0))->second;
582
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000583 if (PInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000584 const VarDecl* Var = PInfo.getVar();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000585
586 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000587 PropagationInfo(StateMap->getState(Var), ThisType)));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000588
589 StateMap->setState(Var, consumed::CS_Consumed);
590
591 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000592 PropagationMap.insert(PairType(Call, PInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000593 }
594
595 } else if (Constructor->isCopyConstructor()) {
596 MapType::iterator Entry = PropagationMap.find(Call->getArg(0));
597
598 if (Entry != PropagationMap.end())
599 PropagationMap.insert(PairType(Call, Entry->second));
600
601 } else {
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000602 propagateReturnType(Call, Constructor, ThisType);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000603 }
604 }
605}
606
607void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
608 const CXXMemberCallExpr *Call) {
609
610 VisitCallExpr(Call);
611
612 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
613
614 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000615 PropagationInfo PInfo = Entry->second;
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000616 const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000617
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000618 checkCallability(PInfo, MethodDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000619
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000620 if (PInfo.isVar()) {
621 if (isTestingFunction(MethodDecl))
622 handleTestingFunctionCall(Call, PInfo.getVar());
623 else if (MethodDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000624 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000625 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000626 }
627}
628
629void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
630 const CXXOperatorCallExpr *Call) {
631
632 const FunctionDecl *FunDecl =
633 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
634
635 if (!FunDecl) return;
636
637 if (isa<CXXMethodDecl>(FunDecl) &&
638 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
639
640 InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
641 InfoEntry REntry = PropagationMap.find(Call->getArg(1));
642
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000643 PropagationInfo LPInfo, RPInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000644
645 if (LEntry != PropagationMap.end() &&
646 REntry != PropagationMap.end()) {
647
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000648 LPInfo = LEntry->second;
649 RPInfo = REntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000650
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000651 if (LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000652 StateMap->setState(LPInfo.getVar(),
653 StateMap->getState(RPInfo.getVar()));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000654
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000655 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000656
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000657 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000658
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000659 } else if (LPInfo.isVar() && !RPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000660 StateMap->setState(LPInfo.getVar(), RPInfo.getState());
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000661
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000662 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000663
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000664 } else if (!LPInfo.isVar() && RPInfo.isVar()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000665 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000666 PropagationInfo(StateMap->getState(RPInfo.getVar()),
667 LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000668
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000669 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000670
671 } else {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000672 PropagationMap.insert(PairType(Call, RPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000673 }
674
675 } else if (LEntry != PropagationMap.end() &&
676 REntry == PropagationMap.end()) {
677
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000678 LPInfo = LEntry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000679
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000680 if (LPInfo.isVar()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000681 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000682
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000683 PropagationMap.insert(PairType(Call, LPInfo));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000684
DeLesley Hutchins66540852013-10-04 21:28:06 +0000685 } else if (LPInfo.isState()) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000686 PropagationMap.insert(PairType(Call,
DeLesley Hutchins66540852013-10-04 21:28:06 +0000687 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType())));
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000688 }
689
690 } else if (LEntry == PropagationMap.end() &&
691 REntry != PropagationMap.end()) {
692
DeLesley Hutchins66540852013-10-04 21:28:06 +0000693 if (REntry->second.isVar())
694 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000695 }
696
697 } else {
698
699 VisitCallExpr(Call);
700
701 InfoEntry Entry = PropagationMap.find(Call->getArg(0));
702
703 if (Entry != PropagationMap.end()) {
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000704 PropagationInfo PInfo = Entry->second;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000705
DeLesley Hutchinsb01e2da2013-08-26 20:34:59 +0000706 checkCallability(PInfo, FunDecl, Call);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000707
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000708 if (PInfo.isVar()) {
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000709 if (isTestingFunction(FunDecl))
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000710 handleTestingFunctionCall(Call, PInfo.getVar());
DeLesley Hutchinsd324a0b2013-08-29 21:17:25 +0000711 else if (FunDecl->hasAttr<ConsumesAttr>())
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000712 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000713 }
714 }
715 }
716}
717
718void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
719 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
720 if (StateMap->getState(Var) != consumed::CS_None)
721 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
722}
723
724void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
725 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
726 DE = DeclS->decl_end(); DI != DE; ++DI) {
727
728 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
729 }
730
731 if (DeclS->isSingleDecl())
732 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
733 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
734}
735
736void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
737 const MaterializeTemporaryExpr *Temp) {
738
739 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr());
740
741 if (Entry != PropagationMap.end())
742 PropagationMap.insert(PairType(Temp, Entry->second));
743}
744
745void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
746 forwardInfo(MExpr->getBase(), MExpr);
747}
748
DeLesley Hutchins42525982013-08-29 22:36:05 +0000749
750void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
David Blaikiea33ab602013-09-06 01:28:43 +0000751 QualType ParamType = Param->getType();
752 ConsumedState ParamState = consumed::CS_None;
753
754 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) &&
755 isConsumableType(ParamType))
756 ParamState = mapConsumableAttrState(ParamType);
757 else if (ParamType->isReferenceType() &&
758 isConsumableType(ParamType->getPointeeType()))
759 ParamState = consumed::CS_Unknown;
760
761 if (ParamState)
762 StateMap->setState(Param, ParamState);
DeLesley Hutchins42525982013-08-29 22:36:05 +0000763}
764
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +0000765void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
766 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) {
767 InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
768
769 if (Entry != PropagationMap.end()) {
770 assert(Entry->second.isState() || Entry->second.isVar());
771
772 ConsumedState RetState = Entry->second.isState() ?
773 Entry->second.getState() : StateMap->getState(Entry->second.getVar());
774
775 if (RetState != ExpectedState)
776 Analyzer.WarningsHandler.warnReturnTypestateMismatch(
777 Ret->getReturnLoc(), stateToString(ExpectedState),
778 stateToString(RetState));
779 }
780 }
781}
782
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000783void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000784 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
785 if (Entry == PropagationMap.end()) return;
786
787 switch (UOp->getOpcode()) {
788 case UO_AddrOf:
789 PropagationMap.insert(PairType(UOp, Entry->second));
790 break;
791
792 case UO_LNot:
793 if (Entry->second.isTest() || Entry->second.isBinTest())
794 PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
795 break;
796
797 default:
798 break;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000799 }
800}
801
DeLesley Hutchins66540852013-10-04 21:28:06 +0000802// TODO: See if I need to check for reference types here.
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000803void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
DeLesley Hutchinsc55bee62013-08-30 22:56:34 +0000804 if (isConsumableType(Var->getType())) {
DeLesley Hutchins42525982013-08-29 22:36:05 +0000805 if (Var->hasInit()) {
806 PropagationInfo PInfo =
807 PropagationMap.find(Var->getInit())->second;
808
809 StateMap->setState(Var, PInfo.isVar() ?
810 StateMap->getState(PInfo.getVar()) : PInfo.getState());
811
812 } else {
813 StateMap->setState(Var, consumed::CS_Unknown);
814 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000815 }
816}
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000817}} // end clang::consumed::ConsumedStmtVisitor
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000818
819namespace clang {
820namespace consumed {
821
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000822void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test,
823 ConsumedStateMap *ThenStates,
824 ConsumedStateMap *ElseStates) {
825
826 ConsumedState VarState = ThenStates->getState(Test.Var);
827
828 if (VarState == CS_Unknown) {
829 ThenStates->setState(Test.Var, Test.TestsFor);
DeLesley Hutchins66540852013-10-04 21:28:06 +0000830 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000831
832 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
833 ThenStates->markUnreachable();
834
DeLesley Hutchins66540852013-10-04 21:28:06 +0000835 } else if (VarState == Test.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000836 ElseStates->markUnreachable();
837 }
838}
839
840void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
841 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) {
842
843 const VarTestResult &LTest = PInfo.getLTest(),
844 &RTest = PInfo.getRTest();
845
846 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
847 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
848
849 if (LTest.Var) {
850 if (PInfo.testEffectiveOp() == EO_And) {
851 if (LState == CS_Unknown) {
852 ThenStates->setState(LTest.Var, LTest.TestsFor);
853
854 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
855 ThenStates->markUnreachable();
856
857 } else if (LState == LTest.TestsFor && isKnownState(RState)) {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000858 if (RState == RTest.TestsFor)
859 ElseStates->markUnreachable();
860 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000861 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000862 }
863
864 } else {
DeLesley Hutchins66540852013-10-04 21:28:06 +0000865 if (LState == CS_Unknown) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000866 ElseStates->setState(LTest.Var,
867 invertConsumedUnconsumed(LTest.TestsFor));
868
DeLesley Hutchins66540852013-10-04 21:28:06 +0000869 } else if (LState == LTest.TestsFor) {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000870 ElseStates->markUnreachable();
871
872 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
873 isKnownState(RState)) {
874
DeLesley Hutchins66540852013-10-04 21:28:06 +0000875 if (RState == RTest.TestsFor)
876 ElseStates->markUnreachable();
877 else
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000878 ThenStates->markUnreachable();
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000879 }
880 }
881 }
882
883 if (RTest.Var) {
884 if (PInfo.testEffectiveOp() == EO_And) {
885 if (RState == CS_Unknown)
886 ThenStates->setState(RTest.Var, RTest.TestsFor);
887 else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
888 ThenStates->markUnreachable();
889
DeLesley Hutchins66540852013-10-04 21:28:06 +0000890 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000891 if (RState == CS_Unknown)
892 ElseStates->setState(RTest.Var,
893 invertConsumedUnconsumed(RTest.TestsFor));
894 else if (RState == RTest.TestsFor)
895 ElseStates->markUnreachable();
896 }
897 }
898}
899
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000900void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
901 ConsumedStateMap *StateMap,
902 bool &AlreadyOwned) {
903
904 if (VisitedBlocks.alreadySet(Block)) return;
905
906 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
907
908 if (Entry) {
909 Entry->intersect(StateMap);
910
911 } else if (AlreadyOwned) {
912 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
913
914 } else {
915 StateMapsArray[Block->getBlockID()] = StateMap;
916 AlreadyOwned = true;
917 }
918}
919
920void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
921 ConsumedStateMap *StateMap) {
922
923 if (VisitedBlocks.alreadySet(Block)) {
924 delete StateMap;
925 return;
926 }
927
928 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
929
930 if (Entry) {
931 Entry->intersect(StateMap);
932 delete StateMap;
933
934 } else {
935 StateMapsArray[Block->getBlockID()] = StateMap;
936 }
937}
938
939ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
940 return StateMapsArray[Block->getBlockID()];
941}
942
943void ConsumedBlockInfo::markVisited(const CFGBlock *Block) {
944 VisitedBlocks.insert(Block);
945}
946
947ConsumedState ConsumedStateMap::getState(const VarDecl *Var) {
948 MapType::const_iterator Entry = Map.find(Var);
949
950 if (Entry != Map.end()) {
951 return Entry->second;
952
953 } else {
954 return CS_None;
955 }
956}
957
958void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
959 ConsumedState LocalState;
960
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000961 if (this->From && this->From == Other->From && !Other->Reachable) {
962 this->markUnreachable();
963 return;
964 }
965
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000966 for (MapType::const_iterator DMI = Other->Map.begin(),
967 DME = Other->Map.end(); DMI != DME; ++DMI) {
968
969 LocalState = this->getState(DMI->first);
970
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000971 if (LocalState == CS_None)
972 continue;
973
974 if (LocalState != DMI->second)
975 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000976 }
977}
978
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000979void ConsumedStateMap::markUnreachable() {
980 this->Reachable = false;
981 Map.clear();
982}
983
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000984void ConsumedStateMap::makeUnknown() {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000985 for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME;
986 ++DMI) {
987
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +0000988 Map[DMI->first] = CS_Unknown;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000989 }
990}
991
992void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
993 Map[Var] = State;
994}
995
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +0000996void ConsumedStateMap::remove(const VarDecl *Var) {
997 Map.erase(Var);
998}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +0000999
David Blaikiea33ab602013-09-06 01:28:43 +00001000void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
1001 const FunctionDecl *D) {
1002 QualType ReturnType;
1003 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1004 ASTContext &CurrContext = AC.getASTContext();
1005 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
1006 } else
1007 ReturnType = D->getCallResultType();
1008
1009 if (D->hasAttr<ReturnTypestateAttr>()) {
1010 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
1011
1012 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
1013 if (!RD || !RD->hasAttr<ConsumableAttr>()) {
1014 // FIXME: This should be removed when template instantiation propagates
1015 // attributes at template specialization definition, not
1016 // declaration. When it is removed the test needs to be enabled
1017 // in SemaDeclAttr.cpp.
1018 WarningsHandler.warnReturnTypestateForUnconsumableType(
1019 RTSAttr->getLocation(), ReturnType.getAsString());
1020 ExpectedReturnState = CS_None;
1021 } else
1022 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
1023 } else if (isConsumableType(ReturnType))
1024 ExpectedReturnState = mapConsumableAttrState(ReturnType);
1025 else
1026 ExpectedReturnState = CS_None;
1027}
1028
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001029bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
1030 const ConsumedStmtVisitor &Visitor) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001031
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001032 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates);
1033 PropagationInfo PInfo;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001034
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001035 if (const IfStmt *IfNode =
1036 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001037
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001038 const Stmt *Cond = IfNode->getCond();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001039
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001040 PInfo = Visitor.getInfo(Cond);
1041 if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
1042 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
1043
1044 if (PInfo.isTest()) {
1045 CurrStates->setSource(Cond);
1046 FalseStates->setSource(Cond);
DeLesley Hutchins66540852013-10-04 21:28:06 +00001047 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001048
1049 } else if (PInfo.isBinTest()) {
1050 CurrStates->setSource(PInfo.testSourceNode());
1051 FalseStates->setSource(PInfo.testSourceNode());
DeLesley Hutchins66540852013-10-04 21:28:06 +00001052 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001053
1054 } else {
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001055 delete FalseStates;
1056 return false;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001057 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001058
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001059 } else if (const BinaryOperator *BinOp =
1060 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
1061
1062 PInfo = Visitor.getInfo(BinOp->getLHS());
1063 if (!PInfo.isTest()) {
1064 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
1065 PInfo = Visitor.getInfo(BinOp->getRHS());
1066
1067 if (!PInfo.isTest()) {
1068 delete FalseStates;
1069 return false;
1070 }
1071
1072 } else {
1073 delete FalseStates;
1074 return false;
1075 }
1076 }
1077
1078 CurrStates->setSource(BinOp);
1079 FalseStates->setSource(BinOp);
1080
1081 const VarTestResult &Test = PInfo.getTest();
1082 ConsumedState VarState = CurrStates->getState(Test.Var);
1083
1084 if (BinOp->getOpcode() == BO_LAnd) {
1085 if (VarState == CS_Unknown)
1086 CurrStates->setState(Test.Var, Test.TestsFor);
1087 else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
1088 CurrStates->markUnreachable();
1089
1090 } else if (BinOp->getOpcode() == BO_LOr) {
1091 if (VarState == CS_Unknown)
1092 FalseStates->setState(Test.Var,
1093 invertConsumedUnconsumed(Test.TestsFor));
1094 else if (VarState == Test.TestsFor)
1095 FalseStates->markUnreachable();
1096 }
1097
1098 } else {
1099 delete FalseStates;
1100 return false;
1101 }
1102
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001103 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
1104
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001105 if (*SI)
1106 BlockInfo.addInfo(*SI, CurrStates);
1107 else
1108 delete CurrStates;
1109
1110 if (*++SI)
1111 BlockInfo.addInfo(*SI, FalseStates);
1112 else
1113 delete FalseStates;
1114
1115 CurrStates = NULL;
1116 return true;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001117}
1118
1119void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
1120 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001121 if (!D)
1122 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001123
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001124 CFG *CFGraph = AC.getCFG();
1125 if (!CFGraph)
1126 return;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001127
David Blaikiea33ab602013-09-06 01:28:43 +00001128 determineExpectedReturnState(AC, D);
DeLesley Hutchins0e8534e2013-09-03 20:11:38 +00001129
DeLesley Hutchins57b781d2013-09-10 23:10:10 +00001130 BlockInfo = ConsumedBlockInfo(CFGraph);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001131
1132 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1133
1134 CurrStates = new ConsumedStateMap();
DeLesley Hutchins42525982013-08-29 22:36:05 +00001135 ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
1136
1137 // Add all trackable parameters to the state map.
1138 for (FunctionDecl::param_const_iterator PI = D->param_begin(),
1139 PE = D->param_end(); PI != PE; ++PI) {
1140 Visitor.VisitParmVarDecl(*PI);
1141 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001142
1143 // Visit all of the function's basic blocks.
1144 for (PostOrderCFGView::iterator I = SortedGraph->begin(),
1145 E = SortedGraph->end(); I != E; ++I) {
1146
1147 const CFGBlock *CurrBlock = *I;
1148 BlockInfo.markVisited(CurrBlock);
1149
1150 if (CurrStates == NULL)
1151 CurrStates = BlockInfo.getInfo(CurrBlock);
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001152
1153 if (!CurrStates) {
1154 continue;
1155
1156 } else if (!CurrStates->isReachable()) {
1157 delete CurrStates;
1158 CurrStates = NULL;
1159 continue;
1160 }
1161
1162 Visitor.reset(CurrStates);
1163
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001164 // Visit all of the basic block's statements.
1165 for (CFGBlock::const_iterator BI = CurrBlock->begin(),
1166 BE = CurrBlock->end(); BI != BE; ++BI) {
1167
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001168 switch (BI->getKind()) {
1169 case CFGElement::Statement:
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001170 Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
DeLesley Hutchins5fdd2072013-08-22 20:44:47 +00001171 break;
1172 case CFGElement::AutomaticObjectDtor:
1173 CurrStates->remove(BI->castAs<CFGAutomaticObjDtor>().getVarDecl());
1174 default:
1175 break;
1176 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001177 }
1178
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001179 // TODO: Handle other forms of branching with precision, including while-
1180 // and for-loops. (Deferred)
1181 if (!splitState(CurrBlock, Visitor)) {
1182 CurrStates->setSource(NULL);
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001183
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001184 if (CurrBlock->succ_size() > 1) {
1185 CurrStates->makeUnknown();
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001186
DeLesley Hutchinsb7dc1f52013-08-29 17:26:57 +00001187 bool OwnershipTaken = false;
1188
1189 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
1190 SE = CurrBlock->succ_end(); SI != SE; ++SI) {
1191
1192 if (*SI) BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
1193 }
1194
1195 if (!OwnershipTaken)
1196 delete CurrStates;
1197
1198 CurrStates = NULL;
1199
1200 } else if (CurrBlock->succ_size() == 1 &&
1201 (*CurrBlock->succ_begin())->pred_size() > 1) {
1202
1203 BlockInfo.addInfo(*CurrBlock->succ_begin(), CurrStates);
1204 CurrStates = NULL;
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001205 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001206 }
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001207 } // End of block iterator.
1208
1209 // Delete the last existing state map.
1210 delete CurrStates;
1211
1212 WarningsHandler.emitDiagnostics();
1213}
DeLesley Hutchinsdf7bef02013-08-12 21:20:55 +00001214}} // end namespace clang::consumed